diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 44e3e1b14..1825cff8d 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 diff --git a/platforms/Zephyr/Kconfig b/platforms/Zephyr/Kconfig index 97e9dc09a..d713cf80d 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/boards/rpi_pico_rp2040_w.conf b/platforms/Zephyr/boards/rpi_pico_rp2040_w.conf new file mode 100644 index 000000000..dfa1050d2 --- /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 000000000..e26628845 --- /dev/null +++ b/platforms/Zephyr/boards/rpi_pico_rp2040_w.overlay @@ -0,0 +1,94 @@ +#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>; + + pwms = < &pwm 2 PWM_USEC(1500) PWM_POLARITY_NORMAL >; + pwm-names = "builtin-buzzer"; + }; +}; + +/ { + 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; + }; + }; +}; + +&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 >; +}; diff --git a/platforms/Zephyr/boards/stm32l496g_disco.overlay b/platforms/Zephyr/boards/stm32l496g_disco.overlay index bbad9e843..8adb51400 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/platforms/Zephyr/main.cpp b/platforms/Zephyr/main.cpp index b2bb39f3b..5e43ed0d2 100644 --- a/platforms/Zephyr/main.cpp +++ b/platforms/Zephyr/main.cpp @@ -119,4 +119,4 @@ int main(void) { loaded_modules.clear(); return 0; -} \ No newline at end of file +} diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 3073cb765..69fb97982 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -49,3 +49,11 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=y CONFIG_USB_DEVICE_PRODUCT="WARDuino Microcontroller" CONFIG_USB_DEVICE_MANUFACTURER="TOPLLab" + +CONFIG_WARDUINO_NETWORKING=y + +# Disable these options, they will stay disabled even when networking is enabled +CONFIG_NET_SHELL=n +CONFIG_NET_IPV6=n +CONFIG_WIFI_CREDENTIALS=n +CONFIG_LOG=n diff --git a/src/Primitives/Networking/sockets.h b/src/Primitives/Networking/sockets.h new file mode 100644 index 000000000..05f95cd47 --- /dev/null +++ b/src/Primitives/Networking/sockets.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include "../../Utils/sockets.h" + +namespace sockets { +inline int socket_create(const char *ip, const int32_t port) { + printf("Create socket %s:%d\n", ip, port); + const int sock = createSocketFileDescriptor(); + if (sock < 0) { + 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 int32_t port) { + const int sock = createSocketFileDescriptor(); + if (sock < 0) { + return -1; + } + const sockaddr_in addr = createServerAddress(port); + if (bindSocketToAddress(sock, addr) < 0) { + return -1; + } + if (startListening(sock) < 0) { + 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/Networking/wifi.h b/src/Primitives/Networking/wifi.h new file mode 100644 index 000000000..f25b02076 --- /dev/null +++ b/src/Primitives/Networking/wifi.h @@ -0,0 +1,208 @@ +#pragma once +#include +#include +#include +#include + +#include +#include +#include + +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) { + memset(params, 0, sizeof(*params)); + 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_DISABLE; + params->timeout = SYS_FOREVER_MS; + 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) { + wifi_connect_req_params cnx_params; + + net_if *iface = net_if_get_first_wifi(); + if (iface == NULL) { + printf("No Wi-Fi interface found\n"); + return -1; + } + + wifi_args_to_params(&cnx_params, ssid, passwd); + + 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("Connection request failed, err: %d\n", err); + return err; + } + return 0; +} + +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) { + 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("Connection failed, retrying\n"); + k_sem_give(&run_app); + } else { + printf("Network disconnected\n"); + connected = false; + } + 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; + } + + printf("IPv4 address: %s\n", + net_addr_ntop( + AF_INET, + &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, + buf, sizeof(buf))); + printf("Subnet: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].netmask, + buf, sizeof(buf))); + printf("Router: %s\n", + net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, + sizeof(buf))); + } + k_sem_give(&ip_sem); + return; + } +} + +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); + } +} + +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_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); + + 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); + 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); + + // Keep trying to connect until we are connected. + while (!connected) { + 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_SECONDS(30)); + if (!connected) { + k_msleep(2000); + } + } + + printf("Connected! Starting DHCP...\n"); + net_dhcpv4_start(iface); + k_sem_take(&ip_sem, K_SECONDS(30)); + + 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; +} + +inline void network_ip(char *buf) { + 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/emulated.cpp b/src/Primitives/emulated.cpp index eaaa0161a..90b8e2a66 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); diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index c250f231c..7eba3e93c 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,101 @@ def_prim(display_draw_string, sevenToNoneU32) { } #endif +#if IS_ENABLED(CONFIG_WIFI) +#include "Networking/sockets.h" +#include "Networking/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; +} + +def_prim(wifi_disconnect, NoneToOneU32) { + pushUInt32(network_disconnect()); + return true; +} + +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])); + const uint32_t len = + strlen(reinterpret_cast(&m->memory.bytes[buf_addr])); + printf("len(wifi_localip) = %d\n", len); + pushInt32(len); + 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; +} + +#endif + //------------------------------------------------------ // Installing all the primitives //------------------------------------------------------ @@ -587,6 +687,18 @@ void install_primitives(Interpreter *interpreter) { install_primitive(tone); install_primitive(noTone); #endif + +#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); + install_primitive(socket_send); + install_primitive(socket_receive); + install_primitive(socket_close); +#endif } Memory external_mem = {0, 0, 0, nullptr}; diff --git a/src/Utils/sockets.cpp b/src/Utils/sockets.cpp index c672c7fd2..fc846a890 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 ba3a616e5..bea15bb84 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);