From 22a5f857133d85ea743627a8d8895dd1752dafff Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 10:33:44 +0200 Subject: [PATCH 01/28] Initial work on wifi for the zephyr platform --- platforms/Zephyr/main.cpp | 209 ++++++++++++++++++++++---------------- platforms/Zephyr/prj.conf | 33 ++++++ 2 files changed, 153 insertions(+), 89 deletions(-) diff --git a/platforms/Zephyr/main.cpp b/platforms/Zephyr/main.cpp index b2bb39f3..af99e896 100644 --- a/platforms/Zephyr/main.cpp +++ b/platforms/Zephyr/main.cpp @@ -1,122 +1,153 @@ -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include "../../src/WARDuino.h" -#include "upload.h" +#include +#include +#include + +#include +#include -#define DEBUGGER_STACK_SIZE 2048 -#define DEBUGGER_PRIORITY 0 +LOG_MODULE_REGISTER(WARDuinoWifiTest, LOG_LEVEL_INF); -/*BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), - zephyr_cdc_acm_uart), "Console device is not ACM CDC UART device");*/ +#define EVENT_MASK (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) -static struct tty_serial console_serial; +static struct net_mgmt_event_callback mgmt_cb; +static struct net_mgmt_event_callback ipv4_cb; -static uint8_t console_rxbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE]; -static uint8_t console_txbuf[CONFIG_CONSOLE_PUTCHAR_BUFSIZE]; +static bool connected; +static K_SEM_DEFINE(run_app, 0, 1); +static K_SEM_DEFINE(ip_sem, 0, 1); -struct ModuleInfo { - unsigned char *wasm; - unsigned int wasm_len; - const char *name; -}; +void wifi_args_to_params(struct wifi_connect_req_params *params, const char *ssid, const char *passwd) { + params->ssid = (const uint8_t*) ssid; + params->ssid_length = strlen((const char*) params->ssid); -ModuleInfo modules[] = { - {upload_wasm, upload_wasm_len, "main"}, -}; -const size_t module_count = sizeof(modules) / sizeof(modules[0]); + params->psk = (const uint8_t*) passwd; + params->psk_length = strlen((const char*) params->psk); -ssize_t war_console_read(void *dummy, void *buf, size_t size) { - ARG_UNUSED(dummy); - return tty_read(&console_serial, buf, size); + 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)); } -int war_console_init(void) { - const struct device *uart_dev; - int ret; +int send_conn_request(const char *ssid, const char *passwd) { + struct wifi_connect_req_params cnx_params; - uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); - if (!device_is_ready(uart_dev)) { - return -ENODEV; + struct net_if *iface = net_if_get_first_wifi(); + if (iface == NULL) { + printf("Returned network interface is NULL\n"); + return -1; } - ret = tty_init(&console_serial, uart_dev); + wifi_args_to_params(&cnx_params, ssid, passwd); - if (ret) { - return ret; + printf("Connecting to Wi-Fi\n"); + net_if_up(iface); + net_dhcpv4_start(iface); + int err = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); + if (err) { + printf("Connecting to Wi-Fi failed, err: %d\n", err); + return ENOEXEC; } + return 0; +} - /* Checks device driver supports for interrupt driven data transfers. */ - if (CONFIG_CONSOLE_GETCHAR_BUFSIZE + CONFIG_CONSOLE_PUTCHAR_BUFSIZE) { - const struct uart_driver_api *api = - (const struct uart_driver_api *)uart_dev->api; - if (!api->irq_callback_set) { - return -ENOTSUP; +static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, + uint64_t mgmt_event, struct net_if *iface) { + printf("Event %d\n", mgmt_event); + if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { + printf("Network connected\n"); + connected = true; + k_sem_give(&run_app); + return; + } + if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { + if (connected == false) { + printf("Disconnected, waiting for network to be connected\n"); + } else { + printf("Network disconnected\n"); + connected = false; } + k_sem_reset(&run_app); + return; + } + if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { + printf("Got IP addr\n"); + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; + + if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != NET_ADDR_DHCP) { + continue; + } + + printk("IPv4 address: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, + buf, sizeof(buf))); + printk("Subnet: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].netmask, + buf, sizeof(buf))); + printk("Router: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->gw, + buf, sizeof(buf))); + } + k_sem_give(&ip_sem); + return; } - - tty_set_tx_buf(&console_serial, console_txbuf, sizeof(console_txbuf)); - tty_set_rx_buf(&console_serial, console_rxbuf, sizeof(console_rxbuf)); - - console_serial.rx_timeout = K_MSEC(200); - - return 0; } -WARDuino *wac = WARDuino::instance(); -std::vector loaded_modules; +int wifi_connect(const char *ssid, const char *passwd) { + printf("Initializing Wi-Fi driver\n"); + // Sleep to allow initialization of Wi-Fi driver. + k_sleep(K_SECONDS(1)); -void startDebuggerStd() { - Channel *duplex = new Duplex(stdin, stdout); - wac->debugger->setChannel(duplex); - duplex->open(); + net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK); + net_mgmt_add_event_callback(&mgmt_cb); - war_console_init(); - int valread; - uint8_t buffer[1024] = {0}; - while (true) { - k_msleep(500); + net_mgmt_init_event_callback(&ipv4_cb, net_mgmt_event_handler, NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&ipv4_cb); - while ((valread = war_console_read(NULL, buffer, 1024)) > 0) { - wac->handleInterrupt(valread, buffer); + // Keep trying to connect until we are connected. + while (!connected) { + printf("Trying to connect...\n"); + if (send_conn_request(ssid, passwd)) { + return -1; } - } -} - -K_THREAD_DEFINE(debugger_tid, DEBUGGER_STACK_SIZE, startDebuggerStd, NULL, NULL, - NULL, DEBUGGER_PRIORITY, 0, 0); - -int main(void) { - // Load all modules - for (size_t i = 0; i < module_count; i++) { - Module *mod = wac->load_module(modules[i].wasm, modules[i].wasm_len, - modules[i].name, - {.disable_memory_bounds = false, - .mangle_table_index = false, - .dlsym_trim_underscore = false, - .return_exception = true}); - - if (mod) { - loaded_modules.push_back(mod); - printk(" ✓ Loaded %s (%u bytes)\n", modules[i].name, - modules[i].wasm_len); - } else { - printk(" ✗ Failed to load %s\n", modules[i].name); + k_sem_take(&run_app, K_FOREVER); + if (!connected) { + k_msleep(2000); } } - if (!loaded_modules.empty()) { - Module *m = loaded_modules.back(); - wac->run_module(m); - } + printf("Connected sem finished! Waiting for IP...\n"); - for (auto mod : loaded_modules) { - wac->unload_module(mod); - } - loaded_modules.clear(); + k_sem_take(&ip_sem, K_FOREVER); return 0; -} \ No newline at end of file +} + +/*#include "../../src/WARDuino.h" +#include "upload.h" + +WARDuino *wac = WARDuino::instance();*/ + +int main() { + wifi_connect("Oneplus 7", "supertux"); + + /*Module *m = wac->load_module(upload_wasm, upload_wasm_len, {}); + wac->run_module(m); + wac->unload_module(m);*/ +} diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 3073cb76..f5b04779 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -49,3 +49,36 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=y CONFIG_USB_DEVICE_PRODUCT="WARDuino Microcontroller" CONFIG_USB_DEVICE_MANUFACTURER="TOPLLab" + +# Wifi +CONFIG_NETWORKING=y +CONFIG_NET_MGMT=y +# Optional but useful +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +#CONFIG_WIFI_SHELL=n +#CONFIG_NET_L2_WIFI=y + +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n + +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=20 +CONFIG_NET_BUF_TX_COUNT=20 +CONFIG_NET_MAX_CONTEXTS=10 + +CONFIG_NET_DHCPV4=y +CONFIG_NET_DHCPV4_LOG_LEVEL_INF=y +CONFIG_NET_IPV4_LOG_LEVEL_DBG=y +CONFIG_NET_DHCPV4_LOG_LEVEL_DBG=y + +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="Oneplus 7" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="supertux" + +CONFIG_LOG=y From 0dbe085cdbdc455a854f305d3b9418b8fb95fac1 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 17 Dec 2025 15:09:39 +0100 Subject: [PATCH 02/28] Disable display driver for now Seems to cause a connection to return -22? --- platforms/Zephyr/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index f5b04779..5e17d6e9 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -39,7 +39,7 @@ CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP=y #CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y # Display drivers -CONFIG_DISPLAY=y +CONFIG_DISPLAY=n # Needed for random number generation primitives CONFIG_ENTROPY_GENERATOR=y From d867e71d714a3da0eca22bb533d7e6f3e08fc441 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 17 Dec 2025 15:23:44 +0100 Subject: [PATCH 03/28] Disable wifi credentials library Credentials will be part of the wasm module in WARDuino --- platforms/Zephyr/main.cpp | 1 - platforms/Zephyr/prj.conf | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/platforms/Zephyr/main.cpp b/platforms/Zephyr/main.cpp index af99e896..7959de89 100644 --- a/platforms/Zephyr/main.cpp +++ b/platforms/Zephyr/main.cpp @@ -9,7 +9,6 @@ #include "../../src/WARDuino.h" #include -#include #include #include diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 5e17d6e9..0cb71aa6 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -76,9 +76,6 @@ CONFIG_NET_DHCPV4_LOG_LEVEL_INF=y CONFIG_NET_IPV4_LOG_LEVEL_DBG=y CONFIG_NET_DHCPV4_LOG_LEVEL_DBG=y -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="Oneplus 7" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="supertux" +CONFIG_WIFI_CREDENTIALS=n CONFIG_LOG=y From 491c94f24587be9bc4e63e99372cbfcf34cc0054 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 10:34:36 +0200 Subject: [PATCH 04/28] Optimize prj.conf --- platforms/Zephyr/main.cpp | 3 --- platforms/Zephyr/prj.conf | 13 +++++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/platforms/Zephyr/main.cpp b/platforms/Zephyr/main.cpp index 7959de89..dd731c4c 100644 --- a/platforms/Zephyr/main.cpp +++ b/platforms/Zephyr/main.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include @@ -14,8 +13,6 @@ #include #include -LOG_MODULE_REGISTER(WARDuinoWifiTest, LOG_LEVEL_INF); - #define EVENT_MASK (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) static struct net_mgmt_event_callback mgmt_cb; diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 0cb71aa6..19860d6e 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -39,7 +39,7 @@ CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP=y #CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y # Display drivers -CONFIG_DISPLAY=n +CONFIG_DISPLAY=y # Needed for random number generation primitives CONFIG_ENTROPY_GENERATOR=y @@ -55,12 +55,12 @@ CONFIG_NETWORKING=y CONFIG_NET_MGMT=y # Optional but useful CONFIG_NET_MGMT_EVENT=y -CONFIG_NET_MGMT_EVENT_INFO=y +# Optional for cb->info +CONFIG_NET_MGMT_EVENT_INFO=n CONFIG_WIFI=y CONFIG_NET_L2_WIFI_MGMT=y -#CONFIG_WIFI_SHELL=n -#CONFIG_NET_L2_WIFI=y +CONFIG_NET_SHELL=n CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n @@ -72,10 +72,7 @@ CONFIG_NET_BUF_TX_COUNT=20 CONFIG_NET_MAX_CONTEXTS=10 CONFIG_NET_DHCPV4=y -CONFIG_NET_DHCPV4_LOG_LEVEL_INF=y -CONFIG_NET_IPV4_LOG_LEVEL_DBG=y -CONFIG_NET_DHCPV4_LOG_LEVEL_DBG=y CONFIG_WIFI_CREDENTIALS=n -CONFIG_LOG=y +CONFIG_LOG=n From 0b57aea50ce6227169244533f9d563649e1fa966 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 10:55:24 +0200 Subject: [PATCH 05/28] Move wifi connection code into a wifi_connect primitive --- platforms/Zephyr/main.cpp | 203 +++++++++++++++-------------------- src/Primitives/Zephyr/wifi.h | 138 ++++++++++++++++++++++++ src/Primitives/zephyr.cpp | 31 ++++++ 3 files changed, 257 insertions(+), 115 deletions(-) create mode 100644 src/Primitives/Zephyr/wifi.h diff --git a/platforms/Zephyr/main.cpp b/platforms/Zephyr/main.cpp index dd731c4c..5e43ed0d 100644 --- a/platforms/Zephyr/main.cpp +++ b/platforms/Zephyr/main.cpp @@ -1,149 +1,122 @@ -#include -#include -#include -#include -#include +#include +#include +#include #include #include "../../src/WARDuino.h" -#include -#include +#include "upload.h" -#include -#include +#define DEBUGGER_STACK_SIZE 2048 +#define DEBUGGER_PRIORITY 0 -#define EVENT_MASK (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) +/*BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), + zephyr_cdc_acm_uart), "Console device is not ACM CDC UART device");*/ -static struct net_mgmt_event_callback mgmt_cb; -static struct net_mgmt_event_callback ipv4_cb; +static struct tty_serial console_serial; -static bool connected; -static K_SEM_DEFINE(run_app, 0, 1); -static K_SEM_DEFINE(ip_sem, 0, 1); +static uint8_t console_rxbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE]; +static uint8_t console_txbuf[CONFIG_CONSOLE_PUTCHAR_BUFSIZE]; -void wifi_args_to_params(struct wifi_connect_req_params *params, const char *ssid, const char *passwd) { - params->ssid = (const uint8_t*) ssid; - params->ssid_length = strlen((const char*) params->ssid); +struct ModuleInfo { + unsigned char *wasm; + unsigned int wasm_len; + const char *name; +}; - params->psk = (const uint8_t*) passwd; - params->psk_length = strlen((const char*) params->psk); +ModuleInfo modules[] = { + {upload_wasm, upload_wasm_len, "main"}, +}; +const size_t module_count = sizeof(modules) / sizeof(modules[0]); - 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)); +ssize_t war_console_read(void *dummy, void *buf, size_t size) { + ARG_UNUSED(dummy); + return tty_read(&console_serial, buf, size); } -int send_conn_request(const char *ssid, const char *passwd) { - struct wifi_connect_req_params cnx_params; +int war_console_init(void) { + const struct device *uart_dev; + int ret; - struct net_if *iface = net_if_get_first_wifi(); - if (iface == NULL) { - printf("Returned network interface is NULL\n"); - return -1; + uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + if (!device_is_ready(uart_dev)) { + return -ENODEV; } - wifi_args_to_params(&cnx_params, ssid, passwd); + ret = tty_init(&console_serial, uart_dev); - printf("Connecting to Wi-Fi\n"); - net_if_up(iface); - net_dhcpv4_start(iface); - int err = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); - if (err) { - printf("Connecting to Wi-Fi failed, err: %d\n", err); - return ENOEXEC; + if (ret) { + return ret; } - return 0; -} -static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, - uint64_t mgmt_event, struct net_if *iface) { - printf("Event %d\n", mgmt_event); - if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { - printf("Network connected\n"); - connected = true; - k_sem_give(&run_app); - return; - } - if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { - if (connected == false) { - printf("Disconnected, waiting for network to be connected\n"); - } else { - printf("Network disconnected\n"); - connected = false; - } - k_sem_reset(&run_app); - return; - } - if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { - printf("Got IP addr\n"); - for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - char buf[NET_IPV4_ADDR_LEN]; - - if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != NET_ADDR_DHCP) { - continue; - } - - printk("IPv4 address: %s\n", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, - buf, sizeof(buf))); - printk("Subnet: %s\n", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->unicast[i].netmask, - buf, sizeof(buf))); - printk("Router: %s\n", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->gw, - buf, sizeof(buf))); + /* Checks device driver supports for interrupt driven data transfers. */ + if (CONFIG_CONSOLE_GETCHAR_BUFSIZE + CONFIG_CONSOLE_PUTCHAR_BUFSIZE) { + const struct uart_driver_api *api = + (const struct uart_driver_api *)uart_dev->api; + if (!api->irq_callback_set) { + return -ENOTSUP; } - k_sem_give(&ip_sem); - return; } -} -int wifi_connect(const char *ssid, const char *passwd) { - printf("Initializing Wi-Fi driver\n"); - // Sleep to allow initialization of Wi-Fi driver. - k_sleep(K_SECONDS(1)); + tty_set_tx_buf(&console_serial, console_txbuf, sizeof(console_txbuf)); + tty_set_rx_buf(&console_serial, console_rxbuf, sizeof(console_rxbuf)); - net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK); - net_mgmt_add_event_callback(&mgmt_cb); + console_serial.rx_timeout = K_MSEC(200); - net_mgmt_init_event_callback(&ipv4_cb, net_mgmt_event_handler, NET_EVENT_IPV4_ADDR_ADD); - net_mgmt_add_event_callback(&ipv4_cb); + return 0; +} - // Keep trying to connect until we are connected. - while (!connected) { - printf("Trying to connect...\n"); - if (send_conn_request(ssid, passwd)) { - return -1; - } - k_sem_take(&run_app, K_FOREVER); - if (!connected) { - k_msleep(2000); - } - } +WARDuino *wac = WARDuino::instance(); +std::vector loaded_modules; - printf("Connected sem finished! Waiting for IP...\n"); +void startDebuggerStd() { + Channel *duplex = new Duplex(stdin, stdout); + wac->debugger->setChannel(duplex); + duplex->open(); - k_sem_take(&ip_sem, K_FOREVER); + war_console_init(); + int valread; + uint8_t buffer[1024] = {0}; + while (true) { + k_msleep(500); - return 0; + while ((valread = war_console_read(NULL, buffer, 1024)) > 0) { + wac->handleInterrupt(valread, buffer); + } + } } -/*#include "../../src/WARDuino.h" -#include "upload.h" +K_THREAD_DEFINE(debugger_tid, DEBUGGER_STACK_SIZE, startDebuggerStd, NULL, NULL, + NULL, DEBUGGER_PRIORITY, 0, 0); + +int main(void) { + // Load all modules + for (size_t i = 0; i < module_count; i++) { + Module *mod = wac->load_module(modules[i].wasm, modules[i].wasm_len, + modules[i].name, + {.disable_memory_bounds = false, + .mangle_table_index = false, + .dlsym_trim_underscore = false, + .return_exception = true}); + + if (mod) { + loaded_modules.push_back(mod); + printk(" ✓ Loaded %s (%u bytes)\n", modules[i].name, + modules[i].wasm_len); + } else { + printk(" ✗ Failed to load %s\n", modules[i].name); + } + } -WARDuino *wac = WARDuino::instance();*/ + if (!loaded_modules.empty()) { + Module *m = loaded_modules.back(); + wac->run_module(m); + } -int main() { - wifi_connect("Oneplus 7", "supertux"); + for (auto mod : loaded_modules) { + wac->unload_module(mod); + } + loaded_modules.clear(); - /*Module *m = wac->load_module(upload_wasm, upload_wasm_len, {}); - wac->run_module(m); - wac->unload_module(m);*/ + return 0; } diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h new file mode 100644 index 00000000..0238a9b0 --- /dev/null +++ b/src/Primitives/Zephyr/wifi.h @@ -0,0 +1,138 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define EVENT_MASK \ + (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) + +static struct net_mgmt_event_callback mgmt_cb; +static struct net_mgmt_event_callback ipv4_cb; + +static bool connected; +static K_SEM_DEFINE(run_app, 0, 1); +static K_SEM_DEFINE(ip_sem, 0, 1); + +void wifi_args_to_params(struct wifi_connect_req_params *params, + const char *ssid, const char *passwd) { + params->ssid = (const uint8_t *)ssid; + params->ssid_length = strlen((const char *)params->ssid); + + params->psk = (const uint8_t *)passwd; + params->psk_length = strlen((const char *)params->psk); + + 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)); +} + +int send_conn_request(const char *ssid, const char *passwd) { + struct wifi_connect_req_params cnx_params; + + struct net_if *iface = net_if_get_first_wifi(); + if (iface == NULL) { + printf("Returned network interface is NULL\n"); + return -1; + } + + wifi_args_to_params(&cnx_params, ssid, passwd); + + printf("Connecting to Wi-Fi\n"); + net_if_up(iface); + net_dhcpv4_start(iface); + int err = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, + sizeof(struct wifi_connect_req_params)); + if (err) { + printf("Connecting to Wi-Fi failed, err: %d\n", err); + return ENOEXEC; + } + return 0; +} + +static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, + uint64_t mgmt_event, struct net_if *iface) { + printf("Event %d\n", mgmt_event); + if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { + printf("Network connected\n"); + connected = true; + k_sem_give(&run_app); + return; + } + if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { + if (connected == false) { + printf("Disconnected, waiting for network to be connected\n"); + } else { + printf("Network disconnected\n"); + connected = false; + } + k_sem_reset(&run_app); + return; + } + if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { + printf("Got IP addr\n"); + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; + + if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != + NET_ADDR_DHCP) { + continue; + } + + printk("IPv4 address: %s\n", + net_addr_ntop( + AF_INET, + &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, + buf, sizeof(buf))); + printk("Subnet: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].netmask, + buf, sizeof(buf))); + printk("Router: %s\n", + net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, + sizeof(buf))); + } + k_sem_give(&ip_sem); + return; + } +} + +int network_connect(const char *ssid, const char *passwd) { + printf("Initializing Wi-Fi driver\n"); + // Sleep to allow initialization of Wi-Fi driver. + k_sleep(K_SECONDS(1)); + + net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK); + net_mgmt_add_event_callback(&mgmt_cb); + + net_mgmt_init_event_callback(&ipv4_cb, net_mgmt_event_handler, + NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&ipv4_cb); + + // Keep trying to connect until we are connected. + while (!connected) { + printf("Trying to connect...\n"); + if (send_conn_request(ssid, passwd)) { + return -1; + } + k_sem_take(&run_app, K_FOREVER); + if (!connected) { + k_msleep(2000); + } + } + + printf("Connected sem finished! Waiting for IP...\n"); + + k_sem_take(&ip_sem, K_FOREVER); + + return 0; +} diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index c250f231..c1d5b8e5 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -22,6 +22,11 @@ #include #include +#if IS_ENABLED(CONFIG_WIFI) +#include +#include +#endif + #include #include #include @@ -543,6 +548,27 @@ def_prim(display_draw_string, sevenToNoneU32) { } #endif +#if IS_ENABLED(CONFIG_WIFI) +#include "Zephyr/wifi.h" + +def_prim(wifi_connect, fourToNoneU32) { + uint32_t ssid = arg3.uint32; + uint32_t len0 = arg2.uint32; + uint32_t pass = arg1.uint32; + uint32_t len1 = arg0.uint32; + + std::string ssid_str = + parse_utf8_string(m->memory.bytes, len0, ssid).c_str(); + std::string pass_str = + parse_utf8_string(m->memory.bytes, len1, pass).c_str(); + + network_connect(ssid_str.c_str(), pass_str.c_str()); + + pop_args(4); + return true; +} +#endif + //------------------------------------------------------ // Installing all the primitives //------------------------------------------------------ @@ -583,10 +609,15 @@ void install_primitives(Interpreter *interpreter) { install_primitive(display_draw_string); #endif + #if DT_PROP_HAS_NAME(DT_PATH(zephyr_user), pwms, builtin_buzzer) install_primitive(tone); install_primitive(noTone); #endif + +#if IS_ENABLED(CONFIG_WIFI) + install_primitive(wifi_connect); +#endif } Memory external_mem = {0, 0, 0, nullptr}; From 1042729aa5804cfae954547ef794e5e79ec33ecd Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 11:27:39 +0200 Subject: [PATCH 06/28] Add overlay for rpi_pico w --- .../Zephyr/boards/rpi_pico_rp2040_w.conf | 2 + .../Zephyr/boards/rpi_pico_rp2040_w.overlay | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 platforms/Zephyr/boards/rpi_pico_rp2040_w.conf create mode 100644 platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay diff --git a/platforms/Zephyr/boards/rpi_pico_rp2040_w.conf b/platforms/Zephyr/boards/rpi_pico_rp2040_w.conf new file mode 100644 index 00000000..dfa1050d --- /dev/null +++ b/platforms/Zephyr/boards/rpi_pico_rp2040_w.conf @@ -0,0 +1,2 @@ +CONFIG_ENTROPY_GENERATOR=n +CONFIG_TEST_RANDOM_GENERATOR=y \ No newline at end of file diff --git a/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay b/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay new file mode 100644 index 00000000..aa559e3f --- /dev/null +++ b/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay @@ -0,0 +1,77 @@ +#include + +#include "../app.overlay" + +/ { + chosen { + zephyr,console = &cdc_acm_uart0; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +/ { + zephyr,user { + warduino-gpios = + <&gpio0 0 0>, + <&gpio0 1 0>, + <&gpio0 2 0>, + <&gpio0 3 0>, + <&gpio0 4 0>, + <&gpio0 5 0>, + <&gpio0 6 0>, + <&gpio0 7 0>, + <&gpio0 8 0>, + <&gpio0 9 0>, + <&gpio0 10 0>, + <&gpio0 11 0>, + <&gpio0 12 0>, + <&gpio0 13 0>, + <&gpio0 14 0>, + <&gpio0 15 0>, + <&gpio0 16 0>, + <&gpio0 17 0>, + <&gpio0 18 0>, + <&gpio0 19 0>, + <&gpio0 20 0>, + <&gpio0 21 0>, + <&gpio0 22 0>, + <&gpio0 23 0>, + <&gpio0 24 0>, + <&gpio0 25 0>, + <&gpio0 26 0>, + <&gpio0 27 0>, + <&gpio0 28 0>, + <&gpio0 29 0>; + }; +}; + +/ { + chosen { + zephyr,display = &ili9341; + }; + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&spi0>; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + reg = <0>; + mipi-max-frequency = <20000000>; + mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE"; + width = <240>; + height = <320>; + pixel-format = ; + rotation = <0>; + status = "okay"; + h-mirror; + }; + }; +}; From 3890b45ebe992dbe111a08c9507df5629318b96a Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 14:48:48 +0200 Subject: [PATCH 07/28] Try to make wifi connect a bit more stable + show list of networks in the area --- platforms/Zephyr/prj.conf | 6 +- src/Primitives/Zephyr/wifi.h | 105 +++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 19860d6e..c3c6792b 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -39,7 +39,7 @@ CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP=y #CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y # Display drivers -CONFIG_DISPLAY=y +CONFIG_DISPLAY=n # Needed for random number generation primitives CONFIG_ENTROPY_GENERATOR=y @@ -56,9 +56,11 @@ CONFIG_NET_MGMT=y # Optional but useful CONFIG_NET_MGMT_EVENT=y # Optional for cb->info -CONFIG_NET_MGMT_EVENT_INFO=n +CONFIG_NET_MGMT_EVENT_INFO=y CONFIG_WIFI=y +CONFIG_WIFI_LOG_LEVEL_DBG=y +CONFIG_NET_LOG=y CONFIG_NET_L2_WIFI_MGMT=y CONFIG_NET_SHELL=n diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 0238a9b0..3e2aa015 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -13,14 +13,16 @@ #define EVENT_MASK \ (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) -static struct net_mgmt_event_callback mgmt_cb; -static struct net_mgmt_event_callback ipv4_cb; +static net_mgmt_event_callback mgmt_cb; +static net_mgmt_event_callback ipv4_cb; +static net_mgmt_event_callback scan_cb; -static bool connected; +static volatile bool connected; static K_SEM_DEFINE(run_app, 0, 1); static K_SEM_DEFINE(ip_sem, 0, 1); +static K_SEM_DEFINE(scan_done_sem, 0, 1); -void wifi_args_to_params(struct wifi_connect_req_params *params, +void wifi_args_to_params(wifi_connect_req_params *params, const char *ssid, const char *passwd) { params->ssid = (const uint8_t *)ssid; params->ssid_length = strlen((const char *)params->ssid); @@ -30,52 +32,71 @@ void wifi_args_to_params(struct wifi_connect_req_params *params, params->channel = WIFI_CHANNEL_ANY; params->security = WIFI_SECURITY_TYPE_PSK; - params->mfp = WIFI_MFP_OPTIONAL; + params->mfp = WIFI_MFP_DISABLE; params->timeout = SYS_FOREVER_MS; - params->band = WIFI_FREQ_BAND_UNKNOWN; + params->band = WIFI_FREQ_BAND_2_4_GHZ; memset(params->bssid, 0, sizeof(params->bssid)); } int send_conn_request(const char *ssid, const char *passwd) { - struct wifi_connect_req_params cnx_params; + wifi_connect_req_params cnx_params; - struct net_if *iface = net_if_get_first_wifi(); + net_if *iface = net_if_get_first_wifi(); if (iface == NULL) { - printf("Returned network interface is NULL\n"); + printf("No Wi-Fi interface found\n"); return -1; } wifi_args_to_params(&cnx_params, ssid, passwd); - printf("Connecting to Wi-Fi\n"); - net_if_up(iface); - net_dhcpv4_start(iface); + printf("Connecting to %s\n", ssid); int err = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); if (err) { - printf("Connecting to Wi-Fi failed, err: %d\n", err); - return ENOEXEC; + printf("Connection request failed, err: %d\n", err); + return err; } return 0; } -static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, - uint64_t mgmt_event, struct net_if *iface) { - printf("Event %d\n", mgmt_event); +static void scan_result_handler(net_mgmt_event_callback *cb, + uint64_t mgmt_event, net_if *iface) { + if (mgmt_event == NET_EVENT_WIFI_SCAN_RESULT) { + const wifi_scan_result *entry = + (const struct wifi_scan_result *)cb->info; + if (entry) { + printf(" AP: %-32s ch=%-3d rssi=%-4d security=%d\n", + entry->ssid, entry->channel, entry->rssi, entry->security); + } + } + if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { + k_sem_give(&scan_done_sem); + } +} + +static void net_mgmt_event_handler(net_mgmt_event_callback *cb, + uint64_t mgmt_event, net_if *iface) { if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { - printf("Network connected\n"); - connected = true; + const wifi_status *status = + (const wifi_status *)cb->info; + if (status && status->conn_status == WIFI_STATUS_CONN_SUCCESS) { + printf("Network connected\n"); + connected = true; + } else { + printf("Connection failed (conn_status=%d), retrying\n", + status ? status->conn_status : -1); + } k_sem_give(&run_app); return; } if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { if (connected == false) { - printf("Disconnected, waiting for network to be connected\n"); + printf("Connection failed, retrying\n"); + k_sem_give(&run_app); } else { printf("Network disconnected\n"); connected = false; } - k_sem_reset(&run_app); return; } if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { @@ -108,8 +129,7 @@ static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); - // Sleep to allow initialization of Wi-Fi driver. - k_sleep(K_SECONDS(1)); + k_sleep(K_SECONDS(5)); net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK); net_mgmt_add_event_callback(&mgmt_cb); @@ -118,21 +138,46 @@ int network_connect(const char *ssid, const char *passwd) { NET_EVENT_IPV4_ADDR_ADD); net_mgmt_add_event_callback(&ipv4_cb); + net_if *iface = net_if_get_first_wifi(); + if (iface == nullptr) { + printf("No Wi-Fi interface found\n"); + return -1; + } + net_if_up(iface); + + // Scan networks in the area + net_mgmt_init_event_callback(&scan_cb, scan_result_handler, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); + net_mgmt_add_event_callback(&scan_cb); + for (int i = 0; i < 3; i++) { + printf("Scan %d/3 (looking for: %s)...\n", i + 1, ssid); + k_sem_reset(&scan_done_sem); + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, nullptr, 0) == 0) { + k_sem_take(&scan_done_sem, K_SECONDS(10)); + } + if (i < 2) { + k_msleep(2000); + } + } + net_mgmt_del_event_callback(&scan_cb); + // Keep trying to connect until we are connected. while (!connected) { - printf("Trying to connect...\n"); - if (send_conn_request(ssid, passwd)) { - return -1; + printf("Trying to connect to %s...\n", ssid); + k_sem_reset(&run_app); + if (send_conn_request(ssid, passwd) != 0) { + k_msleep(2000); + continue; } - k_sem_take(&run_app, K_FOREVER); + k_sem_take(&run_app, K_SECONDS(30)); if (!connected) { k_msleep(2000); } } - printf("Connected sem finished! Waiting for IP...\n"); - - k_sem_take(&ip_sem, K_FOREVER); + printf("Connected! Starting DHCP...\n"); + net_dhcpv4_start(iface); + k_sem_take(&ip_sem, K_SECONDS(30)); return 0; } From 0e9ffa94c385d6192c0ac900c2173b2f60d46ad2 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 15:38:50 +0200 Subject: [PATCH 08/28] Start writing a basic tcp client interface Seems to work, mostly just have to add three primitives now! --- platforms/Zephyr/prj.conf | 4 +++ src/Primitives/Zephyr/wifi.h | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index c3c6792b..ede3bdf7 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -77,4 +77,8 @@ CONFIG_NET_DHCPV4=y CONFIG_WIFI_CREDENTIALS=n +# TCP sockets +CONFIG_NET_SOCKETS=y +CONFIG_NET_TCP=y + CONFIG_LOG=n diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 3e2aa015..a23bff1f 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -127,6 +127,62 @@ static void net_mgmt_event_handler(net_mgmt_event_callback *cb, } } +// TCP socket test +#include +#include + +namespace warduino { + int socket_create(const char *ip, int port) { + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printk("Socket creation failed\n"); + return -1; + } + + sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(ip); + + if (connect( + sock, + (sockaddr *)&server_addr, + sizeof(server_addr)) < 0 + ) { + printk("Connection failed\n"); + close(sock); + return -1; + } + printk("Connected to %s:%d\n", ip, port); + return sock; + } + + inline int socket_send(int socket, const char* message) { + return send(socket, message, strlen(message), 0); + } + + inline int socket_close(int socket) { + return close(socket); + } +} + +int tcp_send_message(const char *ip, int port, const char *message) { + const int sock = warduino::socket_create(ip, port); + if (sock < 0) { + printf("Failed to create socket!\n"); + return -1; + } + + if (warduino::socket_send(sock, message) < 0) { + printk("Send failed\n"); + } + + warduino::socket_close(sock); + printk("Connection closed\n"); + + return 0; +} + int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); k_sleep(K_SECONDS(5)); @@ -179,5 +235,7 @@ int network_connect(const char *ssid, const char *passwd) { net_dhcpv4_start(iface); k_sem_take(&ip_sem, K_SECONDS(30)); + tcp_send_message("10.115.167.189", 12345, "Hello from WARDuino over WIFI!"); + return 0; } From e65566f7d7c864753f308b0b0e9eb9e3210672cd Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 17:10:05 +0200 Subject: [PATCH 09/28] Add tcp client primitives --- src/Primitives/Zephyr/wifi.h | 8 +++----- src/Primitives/zephyr.cpp | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index a23bff1f..6917a36c 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -132,7 +132,7 @@ static void net_mgmt_event_handler(net_mgmt_event_callback *cb, #include namespace warduino { - int socket_create(const char *ip, int port) { + inline int socket_create(const char *ip, int port) { int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { printk("Socket creation failed\n"); @@ -149,7 +149,7 @@ namespace warduino { (sockaddr *)&server_addr, sizeof(server_addr)) < 0 ) { - printk("Connection failed\n"); + printk("Failed to connect %s\n", strerror(errno)); close(sock); return -1; } @@ -183,7 +183,7 @@ int tcp_send_message(const char *ip, int port, const char *message) { return 0; } -int network_connect(const char *ssid, const char *passwd) { +inline int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); k_sleep(K_SECONDS(5)); @@ -235,7 +235,5 @@ int network_connect(const char *ssid, const char *passwd) { net_dhcpv4_start(iface); k_sem_take(&ip_sem, K_SECONDS(30)); - tcp_send_message("10.115.167.189", 12345, "Hello from WARDuino over WIFI!"); - return 0; } diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index c1d5b8e5..a1a20742 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -567,6 +567,37 @@ def_prim(wifi_connect, fourToNoneU32) { pop_args(4); return true; } + +def_prim(socket_create, threeToOneU32) { + uint32_t ip_addr = arg2.uint32; + uint32_t ip_len = arg1.uint32; + uint32_t port = arg0.uint32; + std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); + pop_args(3); + int socket = warduino::socket_create(ip.c_str(), (int)port); + pushInt32(socket); + return true; +} + +def_prim(socket_send, threeToOneU32) { + int32_t socket = arg2.int32; + uint32_t msg_addr = arg1.uint32; + uint32_t msg_len = arg0.uint32; + std::string msg = parse_utf8_string(m->memory.bytes, msg_len, msg_addr); + pop_args(3); + int sent = warduino::socket_send(socket, msg.c_str()); + pushInt32(sent); + return true; +} + +def_prim(socket_close, oneToOneI32) { + int32_t socket = arg0.int32; + pop_args(1); + int result = warduino::socket_close(socket); + pushInt32(result); + return true; +} + #endif //------------------------------------------------------ @@ -617,6 +648,9 @@ void install_primitives(Interpreter *interpreter) { #if IS_ENABLED(CONFIG_WIFI) install_primitive(wifi_connect); + install_primitive(socket_create); + install_primitive(socket_send); + install_primitive(socket_close); #endif } From e522a5eac4a6f018ecc604ea7436dd787c4c4656 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 17:38:48 +0200 Subject: [PATCH 10/28] Add primitive to disconnect from the network By actually disconnecting, re-connecting later becomes much easier since the wifi network knows that the device is gone and doesn't wait for some timeout. --- src/Primitives/Zephyr/wifi.h | 51 +++++++++++++++++++++++++++--------- src/Primitives/zephyr.cpp | 6 +++++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 6917a36c..a3b9d467 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -10,17 +10,16 @@ #include #include -#define EVENT_MASK \ - (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT) - static net_mgmt_event_callback mgmt_cb; static net_mgmt_event_callback ipv4_cb; static net_mgmt_event_callback scan_cb; +static net_mgmt_event_callback disconnect_cb; static volatile bool connected; static K_SEM_DEFINE(run_app, 0, 1); static K_SEM_DEFINE(ip_sem, 0, 1); static K_SEM_DEFINE(scan_done_sem, 0, 1); +static K_SEM_DEFINE(disconnect_done, 0, 1); void wifi_args_to_params(wifi_connect_req_params *params, const char *ssid, const char *passwd) { @@ -109,16 +108,16 @@ static void net_mgmt_event_handler(net_mgmt_event_callback *cb, continue; } - printk("IPv4 address: %s\n", + printf("IPv4 address: %s\n", net_addr_ntop( AF_INET, &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, buf, sizeof(buf))); - printk("Subnet: %s\n", + printf("Subnet: %s\n", net_addr_ntop(AF_INET, &iface->config.ip.ipv4->unicast[i].netmask, buf, sizeof(buf))); - printk("Router: %s\n", + printf("Router: %s\n", net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf))); } @@ -127,15 +126,24 @@ static void net_mgmt_event_handler(net_mgmt_event_callback *cb, } } +static void disconnect_result_handler(net_mgmt_event_callback *cb, + uint64_t mgmt_event, net_if *iface) { + if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { + printf("Disconnect event received\n"); + k_sem_give(&disconnect_done); + } +} + // TCP socket test #include #include namespace warduino { inline int socket_create(const char *ip, int port) { + printf("Create socket %s:%d\n", ip, port); int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { - printk("Socket creation failed\n"); + printf("Socket creation failed\n"); return -1; } @@ -149,19 +157,21 @@ namespace warduino { (sockaddr *)&server_addr, sizeof(server_addr)) < 0 ) { - printk("Failed to connect %s\n", strerror(errno)); + printf("Failed to connect %s\n", strerror(errno)); close(sock); return -1; } - printk("Connected to %s:%d\n", ip, port); + printf("Connected to %s:%d\n", ip, port); return sock; } inline int socket_send(int socket, const char* message) { + printf("socket_send\n"); return send(socket, message, strlen(message), 0); } inline int socket_close(int socket) { + printf("socket_close\n"); return close(socket); } } @@ -174,11 +184,11 @@ int tcp_send_message(const char *ip, int port, const char *message) { } if (warduino::socket_send(sock, message) < 0) { - printk("Send failed\n"); + printf("Send failed\n"); } warduino::socket_close(sock); - printk("Connection closed\n"); + printf("Connection closed\n"); return 0; } @@ -187,7 +197,7 @@ inline int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); k_sleep(K_SECONDS(5)); - net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK); + net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, NET_EVENT_WIFI_CONNECT_RESULT); net_mgmt_add_event_callback(&mgmt_cb); net_mgmt_init_event_callback(&ipv4_cb, net_mgmt_event_handler, @@ -237,3 +247,20 @@ inline int network_connect(const char *ssid, const char *passwd) { return 0; } + +inline int network_disconnect() { + printf("Request network disconnect\n"); + net_if *iface = net_if_get_first_wifi(); + if (iface == nullptr) { + printf("No Wi-Fi interface found\n"); + return -1; + } + net_mgmt_init_event_callback(&disconnect_cb, disconnect_result_handler, + NET_EVENT_WIFI_DISCONNECT_RESULT); + net_mgmt_add_event_callback(&disconnect_cb); + k_sem_reset(&disconnect_done); + net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, nullptr, 0); + k_sem_take(&disconnect_done, K_SECONDS(30)); + printf("Network disconnected!\n"); + return 0; +} diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index a1a20742..24eca47c 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -568,6 +568,11 @@ def_prim(wifi_connect, fourToNoneU32) { return true; } +def_prim(wifi_disconnect, NoneToOneU32) { + pushUInt32(network_disconnect()); + return true; +} + def_prim(socket_create, threeToOneU32) { uint32_t ip_addr = arg2.uint32; uint32_t ip_len = arg1.uint32; @@ -648,6 +653,7 @@ void install_primitives(Interpreter *interpreter) { #if IS_ENABLED(CONFIG_WIFI) install_primitive(wifi_connect); + install_primitive(wifi_disconnect); install_primitive(socket_create); install_primitive(socket_send); install_primitive(socket_close); From e1577ffa47d8b8c6a3b26cbd60b0e2bc1b134fce Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Fri, 10 Jul 2026 18:11:30 +0200 Subject: [PATCH 11/28] Retry 5 times when creating a socket --- src/Primitives/Zephyr/wifi.h | 15 ++++++++++++++- src/Primitives/zephyr.cpp | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index a3b9d467..ac339994 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -160,11 +160,24 @@ namespace warduino { printf("Failed to connect %s\n", strerror(errno)); close(sock); return -1; - } + } printf("Connected to %s:%d\n", ip, port); return sock; } + inline int socket_create_retry(const char *ip, int port, int times) { + int sock = -1; + while (times > 0 && (sock = socket_create(ip, port)) < 0) { + printf("Retry %d more times\n", times); + times--; + k_sleep(K_SECONDS(1)); + } + if (times == 0) { + printf("Failed after x retries\n"); + } + return sock; + } + inline int socket_send(int socket, const char* message) { printf("socket_send\n"); return send(socket, message, strlen(message), 0); diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 24eca47c..5dd8284b 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -579,7 +579,7 @@ def_prim(socket_create, threeToOneU32) { uint32_t port = arg0.uint32; std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); pop_args(3); - int socket = warduino::socket_create(ip.c_str(), (int)port); + int socket = warduino::socket_create_retry(ip.c_str(), (int)port, 5); pushInt32(socket); return true; } From 346d227111fa27b528d699db11e5d5ccb44c85c8 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Sat, 11 Jul 2026 13:11:32 +0200 Subject: [PATCH 12/28] Scan only once instead of 3 times --- src/Primitives/Zephyr/wifi.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index ac339994..1cee1522 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -228,15 +228,9 @@ inline int network_connect(const char *ssid, const char *passwd) { net_mgmt_init_event_callback(&scan_cb, scan_result_handler, NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); net_mgmt_add_event_callback(&scan_cb); - for (int i = 0; i < 3; i++) { - printf("Scan %d/3 (looking for: %s)...\n", i + 1, ssid); - k_sem_reset(&scan_done_sem); - if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, nullptr, 0) == 0) { - k_sem_take(&scan_done_sem, K_SECONDS(10)); - } - if (i < 2) { - k_msleep(2000); - } + k_sem_reset(&scan_done_sem); + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, nullptr, 0) == 0) { + k_sem_take(&scan_done_sem, K_SECONDS(10)); } net_mgmt_del_event_callback(&scan_cb); From 554f53bf21b721323951149565b0774ff41d5ecb Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Sat, 11 Jul 2026 13:15:05 +0200 Subject: [PATCH 13/28] Zero the other fields in wifi_connect_req_params This way there is no garbage in this fields which can confuse the driver. --- src/Primitives/Zephyr/wifi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 1cee1522..3e9c5de7 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -23,6 +23,7 @@ static K_SEM_DEFINE(disconnect_done, 0, 1); void wifi_args_to_params(wifi_connect_req_params *params, const char *ssid, const char *passwd) { + memset(params, 0, sizeof(*params)); params->ssid = (const uint8_t *)ssid; params->ssid_length = strlen((const char *)params->ssid); From 2971b4170d31b6ddfef8035cd18b96dd29b6a52c Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Sat, 11 Jul 2026 14:01:42 +0200 Subject: [PATCH 14/28] Add small delay to socket_close to ensure all messages have been sent + extra logging --- src/Primitives/Zephyr/wifi.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 3e9c5de7..249e6311 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -148,7 +148,7 @@ namespace warduino { return -1; } - sockaddr_in server_addr; + sockaddr_in server_addr = {}; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr(ip); @@ -163,6 +163,7 @@ namespace warduino { return -1; } printf("Connected to %s:%d\n", ip, port); + printf("sock = %d\n", sock); return sock; } @@ -180,12 +181,14 @@ namespace warduino { } inline int socket_send(int socket, const char* message) { - printf("socket_send\n"); + printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, strlen(message)); return send(socket, message, strlen(message), 0); } inline int socket_close(int socket) { - printf("socket_close\n"); + printf("socket_close(%d)\n", socket); + // Wait a bit to make sure any sent messages in the buffer are still sent. + k_sleep(K_MSEC(500)); return close(socket); } } From a4d5e58a393ca427de725b0281fa7bacd74720ed Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Sun, 12 Jul 2026 10:43:24 +0200 Subject: [PATCH 15/28] Create server socket + accept primitives TODO: Reading from a socket --- src/Primitives/Zephyr/wifi.h | 46 +++++++++++++++++++++++++++++++++++- src/Primitives/zephyr.cpp | 16 +++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 249e6311..067bf999 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -180,6 +180,50 @@ namespace warduino { return sock; } + inline int socket_create_server(const int port) { + const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printf("Server socket creation failed\n"); + return -1; + } + + constexpr int value = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); + + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { + printf("error: bind: %s\n", strerror(errno)); + close(sock); + return -1; + } + + if (listen(sock, 1) < 0) { + printf("error: listen: %s\n", strerror(errno)); + close(sock); + return -1; + } + + printf("Server listening on port %d (sock=%d)\n", port, sock); + return sock; + } + + inline int socket_accept(const int socket) { + sockaddr_in client_addr = {}; + socklen_t client_addr_len = sizeof(client_addr); + printf("Waiting for connection on sock=%d\n", socket); + const int client_sock = accept(socket, reinterpret_cast(&client_addr), &client_addr_len); + if (client_sock < 0) { + printf("error: accept failed: %s\n", strerror(errno)); + return -1; + } + printf("Client connected (client_sock=%d)\n", client_sock); + return client_sock; + } + inline int socket_send(int socket, const char* message) { printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, strlen(message)); return send(socket, message, strlen(message), 0); @@ -193,7 +237,7 @@ namespace warduino { } } -int tcp_send_message(const char *ip, int port, const char *message) { +inline int tcp_send_message(const char *ip, int port, const char *message) { const int sock = warduino::socket_create(ip, port); if (sock < 0) { printf("Failed to create socket!\n"); diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 5dd8284b..a788a3a2 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -584,6 +584,20 @@ def_prim(socket_create, threeToOneU32) { return true; } +def_prim(socket_create_server, oneToOneI32) { + const int32_t port = arg0.int32; + pop_args(1); + pushInt32(warduino::socket_create_server(port)); + return true; +} + +def_prim(socket_accept, oneToOneI32) { + const int32_t sock = arg0.int32; + pop_args(1); + pushInt32(warduino::socket_accept(sock)); + return true; +} + def_prim(socket_send, threeToOneU32) { int32_t socket = arg2.int32; uint32_t msg_addr = arg1.uint32; @@ -655,6 +669,8 @@ void install_primitives(Interpreter *interpreter) { install_primitive(wifi_connect); install_primitive(wifi_disconnect); install_primitive(socket_create); + install_primitive(socket_create_server); + install_primitive(socket_accept); install_primitive(socket_send); install_primitive(socket_close); #endif From 9568be3b347e73f24be745ddb67bfa68eab6bbbf Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Sun, 12 Jul 2026 11:19:19 +0200 Subject: [PATCH 16/28] Add socket_receive primitive This now makes it possible to for example create an echo server, among many other possibilities! --- src/Primitives/Zephyr/wifi.h | 7 ++++++- src/Primitives/zephyr.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 067bf999..5679b093 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -224,11 +224,16 @@ namespace warduino { return client_sock; } - inline int socket_send(int socket, const char* message) { + inline int socket_send(const int socket, const char* message) { printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, strlen(message)); return send(socket, message, strlen(message), 0); } + inline int socket_receive(const int socket, char* buffer, const size_t size) { + printf("socket_receive(%d, 0x%p, %d)\n", socket, buffer, size); + return recv(socket, buffer, size, 0); + } + inline int socket_close(int socket) { printf("socket_close(%d)\n", socket); // Wait a bit to make sure any sent messages in the buffer are still sent. diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index a788a3a2..0de4a721 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -609,6 +609,16 @@ def_prim(socket_send, threeToOneU32) { return true; } +def_prim(socket_receive, threeToOneU32) { + int32_t socket = arg2.int32; + uint32_t msg_addr = arg1.uint32; + uint32_t msg_len = arg0.uint32; + pop_args(3); + char *buf = reinterpret_cast(&m->memory.bytes[msg_addr]); + pushInt32(warduino::socket_receive(socket, buf, msg_len)); + return true; +} + def_prim(socket_close, oneToOneI32) { int32_t socket = arg0.int32; pop_args(1); @@ -672,6 +682,7 @@ void install_primitives(Interpreter *interpreter) { install_primitive(socket_create_server); install_primitive(socket_accept); install_primitive(socket_send); + install_primitive(socket_receive); install_primitive(socket_close); #endif } From cb56ef58f7af563b60e15e806322f95bcca4fba9 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Tue, 14 Jul 2026 15:37:55 +0200 Subject: [PATCH 17/28] clang-format --- src/Primitives/Zephyr/wifi.h | 192 +++++++++++++++++------------------ src/Primitives/zephyr.cpp | 12 +-- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 5679b093..d29fba61 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -21,8 +21,8 @@ static K_SEM_DEFINE(ip_sem, 0, 1); static K_SEM_DEFINE(scan_done_sem, 0, 1); static K_SEM_DEFINE(disconnect_done, 0, 1); -void wifi_args_to_params(wifi_connect_req_params *params, - const char *ssid, const char *passwd) { +void wifi_args_to_params(wifi_connect_req_params *params, const char *ssid, + const char *passwd) { memset(params, 0, sizeof(*params)); params->ssid = (const uint8_t *)ssid; params->ssid_length = strlen((const char *)params->ssid); @@ -65,8 +65,8 @@ static void scan_result_handler(net_mgmt_event_callback *cb, const wifi_scan_result *entry = (const struct wifi_scan_result *)cb->info; if (entry) { - printf(" AP: %-32s ch=%-3d rssi=%-4d security=%d\n", - entry->ssid, entry->channel, entry->rssi, entry->security); + printf(" AP: %-32s ch=%-3d rssi=%-4d security=%d\n", entry->ssid, + entry->channel, entry->rssi, entry->security); } } if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { @@ -77,8 +77,7 @@ static void scan_result_handler(net_mgmt_event_callback *cb, static void net_mgmt_event_handler(net_mgmt_event_callback *cb, uint64_t mgmt_event, net_if *iface) { if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { - const wifi_status *status = - (const wifi_status *)cb->info; + const wifi_status *status = (const wifi_status *)cb->info; if (status && status->conn_status == WIFI_STATUS_CONN_SUCCESS) { printf("Network connected\n"); connected = true; @@ -128,7 +127,7 @@ static void net_mgmt_event_handler(net_mgmt_event_callback *cb, } static void disconnect_result_handler(net_mgmt_event_callback *cb, - uint64_t mgmt_event, net_if *iface) { + uint64_t mgmt_event, net_if *iface) { if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) { printf("Disconnect event received\n"); k_sem_give(&disconnect_done); @@ -136,111 +135,110 @@ static void disconnect_result_handler(net_mgmt_event_callback *cb, } // TCP socket test -#include #include +#include namespace warduino { - inline int socket_create(const char *ip, int port) { - printf("Create socket %s:%d\n", ip, port); - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - printf("Socket creation failed\n"); - return -1; - } - - sockaddr_in server_addr = {}; - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(port); - server_addr.sin_addr.s_addr = inet_addr(ip); - - if (connect( - sock, - (sockaddr *)&server_addr, - sizeof(server_addr)) < 0 - ) { - printf("Failed to connect %s\n", strerror(errno)); - close(sock); - return -1; - } - printf("Connected to %s:%d\n", ip, port); - printf("sock = %d\n", sock); - return sock; +inline int socket_create(const char *ip, int port) { + printf("Create socket %s:%d\n", ip, port); + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printf("Socket creation failed\n"); + return -1; } - inline int socket_create_retry(const char *ip, int port, int times) { - int sock = -1; - while (times > 0 && (sock = socket_create(ip, port)) < 0) { - printf("Retry %d more times\n", times); - times--; - k_sleep(K_SECONDS(1)); - } - if (times == 0) { - printf("Failed after x retries\n"); - } - return sock; - } + sockaddr_in server_addr = {}; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(ip); - inline int socket_create_server(const int port) { - const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - printf("Server socket creation failed\n"); - return -1; - } + if (connect(sock, (sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + printf("Failed to connect %s\n", strerror(errno)); + close(sock); + return -1; + } + printf("Connected to %s:%d\n", ip, port); + printf("sock = %d\n", sock); + return sock; +} - constexpr int value = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); +inline int socket_create_retry(const char *ip, int port, int times) { + int sock = -1; + while (times > 0 && (sock = socket_create(ip, port)) < 0) { + printf("Retry %d more times\n", times); + times--; + k_sleep(K_SECONDS(1)); + } + if (times == 0) { + printf("Failed after x retries\n"); + } + return sock; +} - sockaddr_in addr = {}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; +inline int socket_create_server(const int port) { + const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printf("Server socket creation failed\n"); + return -1; + } - if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { - printf("error: bind: %s\n", strerror(errno)); - close(sock); - return -1; - } + constexpr int value = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); - if (listen(sock, 1) < 0) { - printf("error: listen: %s\n", strerror(errno)); - close(sock); - return -1; - } + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; - printf("Server listening on port %d (sock=%d)\n", port, sock); - return sock; + if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { + printf("error: bind: %s\n", strerror(errno)); + close(sock); + return -1; } - inline int socket_accept(const int socket) { - sockaddr_in client_addr = {}; - socklen_t client_addr_len = sizeof(client_addr); - printf("Waiting for connection on sock=%d\n", socket); - const int client_sock = accept(socket, reinterpret_cast(&client_addr), &client_addr_len); - if (client_sock < 0) { - printf("error: accept failed: %s\n", strerror(errno)); - return -1; - } - printf("Client connected (client_sock=%d)\n", client_sock); - return client_sock; + if (listen(sock, 1) < 0) { + printf("error: listen: %s\n", strerror(errno)); + close(sock); + return -1; } - inline int socket_send(const int socket, const char* message) { - printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, strlen(message)); - return send(socket, message, strlen(message), 0); - } + printf("Server listening on port %d (sock=%d)\n", port, sock); + return sock; +} - inline int socket_receive(const int socket, char* buffer, const size_t size) { - printf("socket_receive(%d, 0x%p, %d)\n", socket, buffer, size); - return recv(socket, buffer, size, 0); +inline int socket_accept(const int socket) { + sockaddr_in client_addr = {}; + socklen_t client_addr_len = sizeof(client_addr); + printf("Waiting for connection on sock=%d\n", socket); + const int client_sock = + accept(socket, reinterpret_cast(&client_addr), + &client_addr_len); + if (client_sock < 0) { + printf("error: accept failed: %s\n", strerror(errno)); + return -1; } + printf("Client connected (client_sock=%d)\n", client_sock); + return client_sock; +} - inline int socket_close(int socket) { - printf("socket_close(%d)\n", socket); - // Wait a bit to make sure any sent messages in the buffer are still sent. - k_sleep(K_MSEC(500)); - return close(socket); - } +inline int socket_send(const int socket, const char *message) { + printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, + strlen(message)); + return send(socket, message, strlen(message), 0); +} + +inline int socket_receive(const int socket, char *buffer, const size_t size) { + printf("socket_receive(%d, 0x%p, %d)\n", socket, buffer, size); + return recv(socket, buffer, size, 0); +} + +inline int socket_close(int socket) { + printf("socket_close(%d)\n", socket); + // Wait a bit to make sure any sent messages in the buffer are still sent. + k_sleep(K_MSEC(500)); + return close(socket); } +} // namespace warduino inline int tcp_send_message(const char *ip, int port, const char *message) { const int sock = warduino::socket_create(ip, port); @@ -263,7 +261,8 @@ inline int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); k_sleep(K_SECONDS(5)); - net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, NET_EVENT_WIFI_CONNECT_RESULT); + net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, + NET_EVENT_WIFI_CONNECT_RESULT); net_mgmt_add_event_callback(&mgmt_cb); net_mgmt_init_event_callback(&ipv4_cb, net_mgmt_event_handler, @@ -278,7 +277,8 @@ inline int network_connect(const char *ssid, const char *passwd) { net_if_up(iface); // Scan networks in the area - net_mgmt_init_event_callback(&scan_cb, scan_result_handler, + net_mgmt_init_event_callback( + &scan_cb, scan_result_handler, NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); net_mgmt_add_event_callback(&scan_cb); k_sem_reset(&scan_done_sem); @@ -316,7 +316,7 @@ inline int network_disconnect() { return -1; } net_mgmt_init_event_callback(&disconnect_cb, disconnect_result_handler, - NET_EVENT_WIFI_DISCONNECT_RESULT); + NET_EVENT_WIFI_DISCONNECT_RESULT); net_mgmt_add_event_callback(&disconnect_cb); k_sem_reset(&disconnect_done); net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, nullptr, 0); diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 0de4a721..4b6d71c6 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -575,8 +575,8 @@ def_prim(wifi_disconnect, NoneToOneU32) { def_prim(socket_create, threeToOneU32) { uint32_t ip_addr = arg2.uint32; - uint32_t ip_len = arg1.uint32; - uint32_t port = arg0.uint32; + uint32_t ip_len = arg1.uint32; + uint32_t port = arg0.uint32; std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); pop_args(3); int socket = warduino::socket_create_retry(ip.c_str(), (int)port, 5); @@ -599,9 +599,9 @@ def_prim(socket_accept, oneToOneI32) { } def_prim(socket_send, threeToOneU32) { - int32_t socket = arg2.int32; + int32_t socket = arg2.int32; uint32_t msg_addr = arg1.uint32; - uint32_t msg_len = arg0.uint32; + uint32_t msg_len = arg0.uint32; std::string msg = parse_utf8_string(m->memory.bytes, msg_len, msg_addr); pop_args(3); int sent = warduino::socket_send(socket, msg.c_str()); @@ -610,9 +610,9 @@ def_prim(socket_send, threeToOneU32) { } def_prim(socket_receive, threeToOneU32) { - int32_t socket = arg2.int32; + int32_t socket = arg2.int32; uint32_t msg_addr = arg1.uint32; - uint32_t msg_len = arg0.uint32; + uint32_t msg_len = arg0.uint32; pop_args(3); char *buf = reinterpret_cast(&m->memory.bytes[msg_addr]); pushInt32(warduino::socket_receive(socket, buf, msg_len)); From d9a767e0c79d3ece657c9573fa7d0a86c21b6793 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Tue, 14 Jul 2026 17:02:32 +0200 Subject: [PATCH 18/28] Add primitive to obtain the local ip address --- src/Primitives/Zephyr/wifi.h | 8 ++++++++ src/Primitives/zephyr.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index d29fba61..55032549 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -324,3 +324,11 @@ inline int network_disconnect() { printf("Network disconnected!\n"); return 0; } + +inline void network_ip(char *buf) { + net_if *iface = net_if_get_first_wifi(); + net_addr_ntop( + AF_INET, + &iface->config.ip.ipv4->unicast[0].ipv4.address.in_addr, + buf, NET_IPV4_ADDR_LEN); +} \ No newline at end of file diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 4b6d71c6..a5a14b87 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -573,6 +573,13 @@ def_prim(wifi_disconnect, NoneToOneU32) { return true; } +def_prim(wifi_localip, oneToNoneI32) { + const uint32_t buf_addr = arg0.uint32; + network_ip(reinterpret_cast(&m->memory.bytes[buf_addr])); + pop_args(1); + return true; +} + def_prim(socket_create, threeToOneU32) { uint32_t ip_addr = arg2.uint32; uint32_t ip_len = arg1.uint32; @@ -678,6 +685,7 @@ void install_primitives(Interpreter *interpreter) { #if IS_ENABLED(CONFIG_WIFI) install_primitive(wifi_connect); install_primitive(wifi_disconnect); + install_primitive(wifi_localip); install_primitive(socket_create); install_primitive(socket_create_server); install_primitive(socket_accept); From a0ebc1ab7d421bac44e2dd921f084d002cd65513 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Tue, 14 Jul 2026 17:21:40 +0200 Subject: [PATCH 19/28] Re-enable display drivers --- platforms/Zephyr/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index ede3bdf7..6bfc1862 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -39,7 +39,7 @@ CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP=y #CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y # Display drivers -CONFIG_DISPLAY=n +CONFIG_DISPLAY=y # Needed for random number generation primitives CONFIG_ENTROPY_GENERATOR=y From 794ebb2e609d10b87cc04c182f64ca66d7463f18 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Tue, 14 Jul 2026 18:11:05 +0200 Subject: [PATCH 20/28] Update rpi pico w overlay to match regular pico overlay --- .../Zephyr/boards/rpi_pico_rp2040_w.overlay | 79 +++++++++++-------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay b/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay index aa559e3f..e2662884 100644 --- a/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay +++ b/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay @@ -17,37 +17,40 @@ / { zephyr,user { warduino-gpios = - <&gpio0 0 0>, - <&gpio0 1 0>, - <&gpio0 2 0>, - <&gpio0 3 0>, - <&gpio0 4 0>, - <&gpio0 5 0>, - <&gpio0 6 0>, - <&gpio0 7 0>, - <&gpio0 8 0>, - <&gpio0 9 0>, - <&gpio0 10 0>, - <&gpio0 11 0>, - <&gpio0 12 0>, - <&gpio0 13 0>, - <&gpio0 14 0>, - <&gpio0 15 0>, - <&gpio0 16 0>, - <&gpio0 17 0>, - <&gpio0 18 0>, - <&gpio0 19 0>, - <&gpio0 20 0>, - <&gpio0 21 0>, - <&gpio0 22 0>, - <&gpio0 23 0>, - <&gpio0 24 0>, - <&gpio0 25 0>, - <&gpio0 26 0>, - <&gpio0 27 0>, - <&gpio0 28 0>, - <&gpio0 29 0>; - }; + <&gpio0 0 0>, + <&gpio0 1 0>, + <&gpio0 2 0>, + <&gpio0 3 0>, + <&gpio0 4 0>, + <&gpio0 5 0>, + <&gpio0 6 0>, + <&gpio0 7 0>, + <&gpio0 8 0>, + <&gpio0 9 0>, + <&gpio0 10 0>, + <&gpio0 11 0>, + <&gpio0 12 0>, + <&gpio0 13 0>, + <&gpio0 14 0>, + <&gpio0 15 0>, + <&gpio0 16 0>, + <&gpio0 17 0>, + <&gpio0 18 0>, + <&gpio0 19 0>, + <&gpio0 20 0>, + <&gpio0 21 0>, + <&gpio0 22 0>, + <&gpio0 23 0>, + <&gpio0 24 0>, + <&gpio0 25 0>, + <&gpio0 26 0>, + <&gpio0 27 0>, + <&gpio0 28 0>, + <&gpio0 29 0>; + + pwms = < &pwm 2 PWM_USEC(1500) PWM_POLARITY_NORMAL >; + pwm-names = "builtin-buzzer"; + }; }; / { @@ -75,3 +78,17 @@ }; }; }; + +&pinctrl { + pwm_ch1a_default: pwm_ch1a_default { + group1 { + pinmux = ; // Channel 1 A, 1 * 1 + 1 = 2, &pwm 2 in pwms + }; + }; +}; + +&pwm { + status="okay"; + divider-int-4 = <255>; + pinctrl-0 = < &pwm_ch1a_default >; +}; From fa6d24d7a0f60b569a9b369c71232e02bf48b209 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 15 Jul 2026 14:12:11 +0200 Subject: [PATCH 21/28] Minor changes removed socket retry since we don't really need it If you want retry you can always just run the socket function in a loop yourself. --- src/Primitives/Zephyr/wifi.h | 32 +++++++++----------------------- src/Primitives/zephyr.cpp | 3 +-- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 55032549..61d03130 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -139,7 +139,7 @@ static void disconnect_result_handler(net_mgmt_event_callback *cb, #include namespace warduino { -inline int socket_create(const char *ip, int port) { +inline int socket_create(const char *ip, const uint32_t port) { printf("Create socket %s:%d\n", ip, port); int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { @@ -162,34 +162,21 @@ inline int socket_create(const char *ip, int port) { return sock; } -inline int socket_create_retry(const char *ip, int port, int times) { - int sock = -1; - while (times > 0 && (sock = socket_create(ip, port)) < 0) { - printf("Retry %d more times\n", times); - times--; - k_sleep(K_SECONDS(1)); - } - if (times == 0) { - printf("Failed after x retries\n"); - } - return sock; -} - -inline int socket_create_server(const int port) { +inline int socket_create_server(const uint32_t port) { const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { printf("Server socket creation failed\n"); return -1; } - constexpr int value = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); - sockaddr_in addr = {}; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; + constexpr int value = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); + if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { printf("error: bind: %s\n", strerror(errno)); close(sock); @@ -326,9 +313,8 @@ inline int network_disconnect() { } inline void network_ip(char *buf) { - net_if *iface = net_if_get_first_wifi(); - net_addr_ntop( - AF_INET, - &iface->config.ip.ipv4->unicast[0].ipv4.address.in_addr, - buf, NET_IPV4_ADDR_LEN); + const net_if *iface = net_if_get_first_wifi(); + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[0].ipv4.address.in_addr, buf, + NET_IPV4_ADDR_LEN); } \ No newline at end of file diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index a5a14b87..6b7d9882 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -586,7 +586,7 @@ def_prim(socket_create, threeToOneU32) { uint32_t port = arg0.uint32; std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); pop_args(3); - int socket = warduino::socket_create_retry(ip.c_str(), (int)port, 5); + int socket = warduino::socket_create(ip.c_str(), port); pushInt32(socket); return true; } @@ -676,7 +676,6 @@ void install_primitives(Interpreter *interpreter) { install_primitive(display_draw_string); #endif - #if DT_PROP_HAS_NAME(DT_PATH(zephyr_user), pwms, builtin_buzzer) install_primitive(tone); install_primitive(noTone); From 22288a932536e7fcf16e09ba6dddff1ff9b94e2a Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 15 Jul 2026 14:27:26 +0200 Subject: [PATCH 22/28] Update GitHub action to include hal_espressif blobs --- .github/workflows/compile.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 44e3e1b1..1825cff8 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -147,6 +147,7 @@ jobs: cd zephyr west sdk install + west blobs fetch hal_espressif - name: Checkout repository uses: actions/checkout@v6 From 6934e1becf657802ddca7e1590558a969648a527 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 15 Jul 2026 15:45:22 +0200 Subject: [PATCH 23/28] Move socket code into a separate header file We also don't use any Zephyr code in this file so technically we could also use it in the emulator to have real socket support! --- src/Primitives/Zephyr/sockets.h | 102 ++++++++++++++++++++++++++++ src/Primitives/Zephyr/wifi.h | 116 +------------------------------- src/Primitives/zephyr.cpp | 13 ++-- 3 files changed, 111 insertions(+), 120 deletions(-) create mode 100644 src/Primitives/Zephyr/sockets.h diff --git a/src/Primitives/Zephyr/sockets.h b/src/Primitives/Zephyr/sockets.h new file mode 100644 index 00000000..01013a97 --- /dev/null +++ b/src/Primitives/Zephyr/sockets.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace sockets { +inline int socket_create(const char *ip, const uint32_t port) { + printf("Create socket %s:%d\n", ip, port); + const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printf("Socket creation failed\n"); + return -1; + } + + sockaddr_in server_addr = {}; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(ip); + + if (connect(sock, reinterpret_cast(&server_addr), + sizeof(server_addr)) < 0) { + printf("Failed to connect %s\n", strerror(errno)); + close(sock); + return -1; + } + printf("Connected to %s:%d\n", ip, port); + printf("sock = %d\n", sock); + return sock; +} + +inline int socket_create_server(const uint32_t port) { + const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + printf("Server socket creation failed\n"); + return -1; + } + + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + constexpr int value = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); + + if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { + printf("error: bind: %s\n", strerror(errno)); + close(sock); + return -1; + } + + if (listen(sock, 1) < 0) { + printf("error: listen: %s\n", strerror(errno)); + close(sock); + return -1; + } + + printf("Server listening on port %d (sock=%d)\n", port, sock); + return sock; +} + +inline int socket_accept(const int socket) { + sockaddr_in client_addr = {}; + socklen_t client_addr_len = sizeof(client_addr); + printf("Waiting for connection on sock=%d\n", socket); + const int client_sock = accept( + socket, reinterpret_cast(&client_addr), &client_addr_len); + if (client_sock < 0) { + printf("error: accept failed: %s\n", strerror(errno)); + return -1; + } + printf("Client connected (client_sock=%d)\n", client_sock); + return client_sock; +} + +inline int socket_send(const int socket, const char *message) { + printf("socket_send(%d, \"%s\" (len = %lu))\n", socket, message, + strlen(message)); + return send(socket, message, strlen(message), 0); +} + +inline int socket_receive(const int socket, char *buffer, const size_t size) { + printf("socket_receive(%d, 0x%p, %lu)\n", socket, buffer, size); + return recv(socket, buffer, size, 0); +} + +inline int socket_close(int socket) { + printf("socket_close(%d)\n", socket); + // Wait a bit to make sure any sent messages in the buffer are still sent. + timespec ts = {}; + ts.tv_sec = 0; + ts.tv_nsec = 500 * 1000000L; + nanosleep(&ts, nullptr); + return close(socket); +} +} // namespace sockets diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Zephyr/wifi.h index 61d03130..f25b0207 100644 --- a/src/Primitives/Zephyr/wifi.h +++ b/src/Primitives/Zephyr/wifi.h @@ -1,14 +1,12 @@ #pragma once -#include -#include -#include #include #include #include #include -#include +#include #include +#include static net_mgmt_event_callback mgmt_cb; static net_mgmt_event_callback ipv4_cb; @@ -134,116 +132,6 @@ static void disconnect_result_handler(net_mgmt_event_callback *cb, } } -// TCP socket test -#include -#include - -namespace warduino { -inline int socket_create(const char *ip, const uint32_t port) { - printf("Create socket %s:%d\n", ip, port); - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - printf("Socket creation failed\n"); - return -1; - } - - sockaddr_in server_addr = {}; - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(port); - server_addr.sin_addr.s_addr = inet_addr(ip); - - if (connect(sock, (sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - printf("Failed to connect %s\n", strerror(errno)); - close(sock); - return -1; - } - printf("Connected to %s:%d\n", ip, port); - printf("sock = %d\n", sock); - return sock; -} - -inline int socket_create_server(const uint32_t port) { - const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - printf("Server socket creation failed\n"); - return -1; - } - - sockaddr_in addr = {}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - - constexpr int value = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); - - if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { - printf("error: bind: %s\n", strerror(errno)); - close(sock); - return -1; - } - - if (listen(sock, 1) < 0) { - printf("error: listen: %s\n", strerror(errno)); - close(sock); - return -1; - } - - printf("Server listening on port %d (sock=%d)\n", port, sock); - return sock; -} - -inline int socket_accept(const int socket) { - sockaddr_in client_addr = {}; - socklen_t client_addr_len = sizeof(client_addr); - printf("Waiting for connection on sock=%d\n", socket); - const int client_sock = - accept(socket, reinterpret_cast(&client_addr), - &client_addr_len); - if (client_sock < 0) { - printf("error: accept failed: %s\n", strerror(errno)); - return -1; - } - printf("Client connected (client_sock=%d)\n", client_sock); - return client_sock; -} - -inline int socket_send(const int socket, const char *message) { - printf("socket_send(%d, \"%s\" (len = %d))\n", socket, message, - strlen(message)); - return send(socket, message, strlen(message), 0); -} - -inline int socket_receive(const int socket, char *buffer, const size_t size) { - printf("socket_receive(%d, 0x%p, %d)\n", socket, buffer, size); - return recv(socket, buffer, size, 0); -} - -inline int socket_close(int socket) { - printf("socket_close(%d)\n", socket); - // Wait a bit to make sure any sent messages in the buffer are still sent. - k_sleep(K_MSEC(500)); - return close(socket); -} -} // namespace warduino - -inline int tcp_send_message(const char *ip, int port, const char *message) { - const int sock = warduino::socket_create(ip, port); - if (sock < 0) { - printf("Failed to create socket!\n"); - return -1; - } - - if (warduino::socket_send(sock, message) < 0) { - printf("Send failed\n"); - } - - warduino::socket_close(sock); - printf("Connection closed\n"); - - return 0; -} - inline int network_connect(const char *ssid, const char *passwd) { printf("Initializing Wi-Fi driver\n"); k_sleep(K_SECONDS(5)); diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 6b7d9882..7fe6ed73 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -549,6 +549,7 @@ def_prim(display_draw_string, sevenToNoneU32) { #endif #if IS_ENABLED(CONFIG_WIFI) +#include "Zephyr/sockets.h" #include "Zephyr/wifi.h" def_prim(wifi_connect, fourToNoneU32) { @@ -586,7 +587,7 @@ def_prim(socket_create, threeToOneU32) { uint32_t port = arg0.uint32; std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); pop_args(3); - int socket = warduino::socket_create(ip.c_str(), port); + int socket = sockets::socket_create(ip.c_str(), port); pushInt32(socket); return true; } @@ -594,14 +595,14 @@ def_prim(socket_create, threeToOneU32) { def_prim(socket_create_server, oneToOneI32) { const int32_t port = arg0.int32; pop_args(1); - pushInt32(warduino::socket_create_server(port)); + pushInt32(sockets::socket_create_server(port)); return true; } def_prim(socket_accept, oneToOneI32) { const int32_t sock = arg0.int32; pop_args(1); - pushInt32(warduino::socket_accept(sock)); + pushInt32(sockets::socket_accept(sock)); return true; } @@ -611,7 +612,7 @@ def_prim(socket_send, threeToOneU32) { uint32_t msg_len = arg0.uint32; std::string msg = parse_utf8_string(m->memory.bytes, msg_len, msg_addr); pop_args(3); - int sent = warduino::socket_send(socket, msg.c_str()); + int sent = sockets::socket_send(socket, msg.c_str()); pushInt32(sent); return true; } @@ -622,14 +623,14 @@ def_prim(socket_receive, threeToOneU32) { uint32_t msg_len = arg0.uint32; pop_args(3); char *buf = reinterpret_cast(&m->memory.bytes[msg_addr]); - pushInt32(warduino::socket_receive(socket, buf, msg_len)); + pushInt32(sockets::socket_receive(socket, buf, msg_len)); return true; } def_prim(socket_close, oneToOneI32) { int32_t socket = arg0.int32; pop_args(1); - int result = warduino::socket_close(socket); + int result = sockets::socket_close(socket); pushInt32(result); return true; } From dea1745cd20d3a07c7380450cb389175b8f8cd43 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 15 Jul 2026 16:32:12 +0200 Subject: [PATCH 24/28] Rename directory to Networking --- src/Primitives/{Zephyr => Networking}/sockets.h | 0 src/Primitives/{Zephyr => Networking}/wifi.h | 0 src/Primitives/zephyr.cpp | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/Primitives/{Zephyr => Networking}/sockets.h (100%) rename src/Primitives/{Zephyr => Networking}/wifi.h (100%) diff --git a/src/Primitives/Zephyr/sockets.h b/src/Primitives/Networking/sockets.h similarity index 100% rename from src/Primitives/Zephyr/sockets.h rename to src/Primitives/Networking/sockets.h diff --git a/src/Primitives/Zephyr/wifi.h b/src/Primitives/Networking/wifi.h similarity index 100% rename from src/Primitives/Zephyr/wifi.h rename to src/Primitives/Networking/wifi.h diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 7fe6ed73..6107bb19 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -549,8 +549,8 @@ def_prim(display_draw_string, sevenToNoneU32) { #endif #if IS_ENABLED(CONFIG_WIFI) -#include "Zephyr/sockets.h" -#include "Zephyr/wifi.h" +#include "Networking/sockets.h" +#include "Networking/wifi.h" def_prim(wifi_connect, fourToNoneU32) { uint32_t ssid = arg3.uint32; From 25c50b9a4b77e702c79c18b1fa91501aa3439463 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 15 Jul 2026 16:32:35 +0200 Subject: [PATCH 25/28] Add functional socket primitives to the emulator --- src/Primitives/emulated.cpp | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/Primitives/emulated.cpp b/src/Primitives/emulated.cpp index eaaa0161..90b8e2a6 100644 --- a/src/Primitives/emulated.cpp +++ b/src/Primitives/emulated.cpp @@ -24,6 +24,7 @@ #include "../Utils/macros.h" #include "../Utils/util.h" #include "../WARDuino/CallbackHandler.h" +#include "Networking/sockets.h" #include "primitive_macros.h" #include "primitives.h" @@ -146,6 +147,11 @@ def_prim(wifi_connect, fourToNoneU32) { return true; } +def_prim(wifi_disconnect, NoneToNoneU32) { + debug("EMU: wifi_disconnect\n"); + return true; +} + def_prim(wifi_status, NoneToOneU32) { pushInt32(3); // return WL_CONNECTED return true; @@ -169,6 +175,60 @@ def_prim(wifi_localip, twoToOneU32) { return true; } +def_prim(socket_create, threeToOneU32) { + uint32_t ip_addr = arg2.uint32; + uint32_t ip_len = arg1.uint32; + uint32_t port = arg0.uint32; + std::string ip = parse_utf8_string(m->memory.bytes, ip_len, ip_addr); + pop_args(3); + int socket = sockets::socket_create(ip.c_str(), port); + pushInt32(socket); + return true; +} + +def_prim(socket_create_server, oneToOneI32) { + const int32_t port = arg0.int32; + pop_args(1); + pushInt32(sockets::socket_create_server(port)); + return true; +} + +def_prim(socket_accept, oneToOneI32) { + const int32_t sock = arg0.int32; + pop_args(1); + pushInt32(sockets::socket_accept(sock)); + return true; +} + +def_prim(socket_send, threeToOneU32) { + int32_t socket = arg2.int32; + uint32_t msg_addr = arg1.uint32; + uint32_t msg_len = arg0.uint32; + std::string msg = parse_utf8_string(m->memory.bytes, msg_len, msg_addr); + pop_args(3); + int sent = sockets::socket_send(socket, msg.c_str()); + pushInt32(sent); + return true; +} + +def_prim(socket_receive, threeToOneU32) { + int32_t socket = arg2.int32; + uint32_t msg_addr = arg1.uint32; + uint32_t msg_len = arg0.uint32; + pop_args(3); + char *buf = reinterpret_cast(&m->memory.bytes[msg_addr]); + pushInt32(sockets::socket_receive(socket, buf, msg_len)); + return true; +} + +def_prim(socket_close, oneToOneI32) { + int32_t socket = arg0.int32; + pop_args(1); + int result = sockets::socket_close(socket); + pushInt32(result); + return true; +} + def_prim(http_get, fourToOneU32) { // Get arguments uint32_t url = arg3.uint32; @@ -527,10 +587,18 @@ void install_primitives(Interpreter *interpreter) { install_primitive(print_string); install_primitive(wifi_connect); + install_primitive(wifi_disconnect); install_primitive(wifi_status); install_primitive(wifi_connected); install_primitive(wifi_localip); + install_primitive(socket_create); + install_primitive(socket_create_server); + install_primitive(socket_accept); + install_primitive(socket_send); + install_primitive(socket_receive); + install_primitive(socket_close); + install_primitive(http_get); install_primitive(http_post); From 30c5f6c3c04fc5b3b3524af758801f0c98046536 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Thu, 16 Jul 2026 10:15:11 +0200 Subject: [PATCH 26/28] Re-use some code from Utils/sockets for socket creation Also fixed stm32 overlay not working --- .../Zephyr/boards/stm32l496g_disco.overlay | 1 - src/Primitives/Networking/sockets.h | 32 ++----- src/Utils/sockets.cpp | 83 +++++++++++-------- src/Utils/sockets.h | 20 ++++- 4 files changed, 74 insertions(+), 62 deletions(-) diff --git a/platforms/Zephyr/boards/stm32l496g_disco.overlay b/platforms/Zephyr/boards/stm32l496g_disco.overlay index bbad9e84..8adb5140 100644 --- a/platforms/Zephyr/boards/stm32l496g_disco.overlay +++ b/platforms/Zephyr/boards/stm32l496g_disco.overlay @@ -296,7 +296,6 @@ status = "okay"; st,adc-clock-source = "SYNC"; st,adc-prescaler = < 0x4 >; - resolutions = < 0x60630c 0x51630c 0x42630c 0x33630c >; sampling-times = < 0x3 0x7 0xd 0x19 0x30 0x5d 0xf8 0x281 >; st,adc-sequencer = "programmable"; st,adc-oversampler = "minimal"; diff --git a/src/Primitives/Networking/sockets.h b/src/Primitives/Networking/sockets.h index 01013a97..05f95cd4 100644 --- a/src/Primitives/Networking/sockets.h +++ b/src/Primitives/Networking/sockets.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -9,12 +8,13 @@ #include #include +#include "../../Utils/sockets.h" + namespace sockets { -inline int socket_create(const char *ip, const uint32_t port) { +inline int socket_create(const char *ip, const int32_t port) { printf("Create socket %s:%d\n", ip, port); - const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + const int sock = createSocketFileDescriptor(); if (sock < 0) { - printf("Socket creation failed\n"); return -1; } @@ -34,30 +34,16 @@ inline int socket_create(const char *ip, const uint32_t port) { return sock; } -inline int socket_create_server(const uint32_t port) { - const int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +inline int socket_create_server(const int32_t port) { + const int sock = createSocketFileDescriptor(); if (sock < 0) { - printf("Server socket creation failed\n"); return -1; } - - sockaddr_in addr = {}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - - constexpr int value = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); - - if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { - printf("error: bind: %s\n", strerror(errno)); - close(sock); + const sockaddr_in addr = createServerAddress(port); + if (bindSocketToAddress(sock, addr) < 0) { return -1; } - - if (listen(sock, 1) < 0) { - printf("error: listen: %s\n", strerror(errno)); - close(sock); + if (startListening(sock) < 0) { return -1; } diff --git a/src/Utils/sockets.cpp b/src/Utils/sockets.cpp index c672c7fd..fc846a89 100644 --- a/src/Utils/sockets.cpp +++ b/src/Utils/sockets.cpp @@ -1,81 +1,89 @@ #include "sockets.h" -#ifndef __ZEPHYR__ +#ifdef WIFI_ENABLED #include #include #include #endif -#include -#ifndef __ZEPHYR__ #include -#endif #include #include #include #include -#ifndef __ZEPHYR__ +#ifdef WIFI_ENABLED // Socket Debugger Interface -void setFileDescriptorOptions(int socket_fd) { +int setFileDescriptorOptions(int socket_fd) { int opt = 1; if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("Failed to set socket file descriptor options"); - exit(EXIT_FAILURE); + return -1; } + return 0; } int createSocketFileDescriptor() { int socket_fd; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + if ((socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("Failed to make a new socket file descriptor"); - exit(EXIT_FAILURE); + return -1; + } + if (setFileDescriptorOptions(socket_fd) < 0) { + return -1; } - setFileDescriptorOptions(socket_fd); return socket_fd; } -void bindSocketToAddress(int socket_fd, struct sockaddr_in address) { - if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { +int bindSocketToAddress(const int socket_fd, sockaddr_in address) { + if (bind(socket_fd, reinterpret_cast(&address), + sizeof(address)) < 0) { perror("Binding socket to address failed"); - exit(EXIT_FAILURE); + close(socket_fd); + return -1; } + return 0; } -struct sockaddr_in createAddress(int port) { - struct sockaddr_in address{}; +sockaddr_in createServerAddress(int port) { + sockaddr_in address{}; address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(port); return address; } -struct sockaddr_in createLocalhostAddress(int port) { - struct sockaddr_in address = createAddress(port); - const char hostname[] = "localhost"; - struct hostent *resolvedhost = gethostbyname(hostname); - memcpy(&address.sin_addr, resolvedhost->h_addr_list[0], - resolvedhost->h_length); - return address; -} - -void startListening(int socket_fd) { +int startListening(const int socket_fd) { if (listen(socket_fd, 1) < 0) { perror("listen"); - exit(EXIT_FAILURE); + close(socket_fd); + return -1; } + return 0; } -int listenForIncomingConnection(int socket_fd, struct sockaddr_in address) { +int listenForIncomingConnection(const int socket_fd, sockaddr_in address) { int new_socket; int size = sizeof(address); - if ((new_socket = accept(socket_fd, (struct sockaddr *)&address, - (socklen_t *)&size)) < 0) { + if ((new_socket = accept(socket_fd, reinterpret_cast(&address), + reinterpret_cast(&size))) < 0) { perror("Failed to listen for incoming connections"); exit(EXIT_FAILURE); } return new_socket; } + +#endif + +#ifndef __ZEPHYR__ +sockaddr_in createLocalhostAddress(int port) { + sockaddr_in address = createServerAddress(port); + constexpr char hostname[] = "localhost"; + const hostent *resolvedhost = gethostbyname(hostname); + memcpy(&address.sin_addr, resolvedhost->h_addr_list[0], + resolvedhost->h_length); + return address; +} #endif Sink::Sink(FILE *out) { this->outStream = out; } @@ -125,9 +133,16 @@ ClientSocket::ClientSocket(int server) : WebSocket(server) {} void WebSocket::open() { // bind socket to address this->fileDescriptor = createSocketFileDescriptor(); - struct sockaddr_in address = createAddress(this->port); - bindSocketToAddress(this->fileDescriptor, address); - startListening(this->fileDescriptor); + if (this->fileDescriptor < 0) { + exit(EXIT_FAILURE); + } + const sockaddr_in address = createServerAddress(this->port); + if (bindSocketToAddress(this->fileDescriptor, address) < 0) { + exit(EXIT_FAILURE); + } + if (startListening(this->fileDescriptor) < 0) { + exit(EXIT_FAILURE); + } printf("Listening on port 127.0.0.1:%i\n", this->port); fflush(stdout); @@ -138,8 +153,8 @@ void WebSocket::open() { void ClientSocket::open() { // bind socket to address this->fileDescriptor = createSocketFileDescriptor(); - struct sockaddr_in address = createAddress(this->port); // server port - if (connect(this->fileDescriptor, (struct sockaddr *)&address, + sockaddr_in address = createServerAddress(this->port); // server port + if (connect(this->fileDescriptor, reinterpret_cast(&address), sizeof(address)) < 0) { perror("Failed to connect to socket"); exit(EXIT_FAILURE); diff --git a/src/Utils/sockets.h b/src/Utils/sockets.h index ba3a616e..bea15bb8 100644 --- a/src/Utils/sockets.h +++ b/src/Utils/sockets.h @@ -1,17 +1,29 @@ #pragma once +#include + #include -void setFileDescriptorOptions(int socket_fd); + +#ifdef __ZEPHYR__ +#if IS_ENABLED(CONFIG_WIFI) +#include // Zephyr renames sockaddr_in with macros +#define WIFI_ENABLED +#endif +#else +#define WIFI_ENABLED +#endif + +int setFileDescriptorOptions(int socket_fd); int createSocketFileDescriptor(); -void bindSocketToAddress(int socket_fd, struct sockaddr_in address); +int bindSocketToAddress(int socket_fd, struct sockaddr_in address); -struct sockaddr_in createAddress(int port); +struct sockaddr_in createServerAddress(int port); struct sockaddr_in createLocalhostAddress(int port); -void startListening(int socket_fd); +int startListening(int socket_fd); int listenForIncomingConnection(int socket_fd, struct sockaddr_in address); From c5d509e49a0c0c224c829c507d61c158dc05bf84 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Thu, 16 Jul 2026 13:19:48 +0200 Subject: [PATCH 27/28] Add WARDUINO_NETWORKING to Kconfig to toggle on and off the networking primitives This way you don't have to configure a bunch of Kconfig options to turn it on or off but just one! --- platforms/Zephyr/Kconfig | 41 +++++++++++++++++++++++++++++++++++++-- platforms/Zephyr/prj.conf | 29 ++------------------------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/platforms/Zephyr/Kconfig b/platforms/Zephyr/Kconfig index 97e9dc09..d713cf80 100644 --- a/platforms/Zephyr/Kconfig +++ b/platforms/Zephyr/Kconfig @@ -1,3 +1,40 @@ -source "samples/subsys/usb/common/Kconfig.sample_usbd" - source "Kconfig.zephyr" + +menu "WARDuino" + +config WARDUINO_NETWORKING + bool "Enable WARDuino networking primitives" + default y + select NETWORKING + select NET_MGMT + select NET_MGMT_EVENT + select NET_MGMT_EVENT_INFO + select WIFI + select NET_L2_WIFI_MGMT + select NET_IPV4 + select NET_DHCPV4 + select NET_SOCKETS + select NET_TCP + help + Enables all networking primitives supported by WARDuino. + +if WARDUINO_NETWORKING + +config NET_PKT_RX_COUNT + default 10 + +config NET_PKT_TX_COUNT + default 10 + +config NET_BUF_RX_COUNT + default 20 + +config NET_BUF_TX_COUNT + default 20 + +config NET_MAX_CONTEXTS + default 10 + +endif # WARDUINO_NETWORKING + +endmenu diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 6bfc1862..69fb9798 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -50,35 +50,10 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=y CONFIG_USB_DEVICE_PRODUCT="WARDuino Microcontroller" CONFIG_USB_DEVICE_MANUFACTURER="TOPLLab" -# Wifi -CONFIG_NETWORKING=y -CONFIG_NET_MGMT=y -# Optional but useful -CONFIG_NET_MGMT_EVENT=y -# Optional for cb->info -CONFIG_NET_MGMT_EVENT_INFO=y +CONFIG_WARDUINO_NETWORKING=y -CONFIG_WIFI=y -CONFIG_WIFI_LOG_LEVEL_DBG=y -CONFIG_NET_LOG=y -CONFIG_NET_L2_WIFI_MGMT=y +# Disable these options, they will stay disabled even when networking is enabled CONFIG_NET_SHELL=n - -CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n - -CONFIG_NET_PKT_RX_COUNT=10 -CONFIG_NET_PKT_TX_COUNT=10 -CONFIG_NET_BUF_RX_COUNT=20 -CONFIG_NET_BUF_TX_COUNT=20 -CONFIG_NET_MAX_CONTEXTS=10 - -CONFIG_NET_DHCPV4=y - CONFIG_WIFI_CREDENTIALS=n - -# TCP sockets -CONFIG_NET_SOCKETS=y -CONFIG_NET_TCP=y - CONFIG_LOG=n From f1c9692acca52b5a107a23c058dfdd1eee8ddee9 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Thu, 16 Jul 2026 14:10:52 +0200 Subject: [PATCH 28/28] Make wifi_localip have the same number of arguments and return values as the other platforms Returning the actual size is a useful thing. The second argument is not really that useful, it seems like all platforms ignore it. --- src/Primitives/zephyr.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 6107bb19..7eba3e93 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -574,10 +574,16 @@ def_prim(wifi_disconnect, NoneToOneU32) { return true; } -def_prim(wifi_localip, oneToNoneI32) { - const uint32_t buf_addr = arg0.uint32; +def_prim(wifi_localip, twoToOneU32) { + // We ignore arg0, we just have two arguments so it's the same on all + // platforms. + const uint32_t buf_addr = arg1.uint32; + pop_args(2); network_ip(reinterpret_cast(&m->memory.bytes[buf_addr])); - pop_args(1); + const uint32_t len = + strlen(reinterpret_cast(&m->memory.bytes[buf_addr])); + printf("len(wifi_localip) = %d\n", len); + pushInt32(len); return true; }