From cbbd5f5fea3529aefb45f2555f9365ceb8b0033d Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Sat, 19 Jul 2025 09:10:05 +0200 Subject: [PATCH] feat: add doxygen headers to all functions --- .vscode/settings.json | 9 + .vscode/tasks.json | 11 + CMakeLists.txt | 3 +- Kconfig | 43 ++ boards/esp32c6_devkitc_hpcore.conf | 3 + ...overkay => esp32c6_devkitc_hpcore.overlay} | 0 boards/native_sim.overlay | 11 - prj.conf | 94 +--- run_sim.sh | 3 +- sample.yaml | 12 - src/main.c | 275 +---------- src/mqtt_client.c | 434 ------------------ src/mqtt_client.h | 43 -- src/mqtt_client_shell.c | 119 ----- src/mqtt_client_shell.h | 8 - src/net.c | 280 +++++++++++ src/net.h | 17 + 17 files changed, 405 insertions(+), 960 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 boards/esp32c6_devkitc_hpcore.conf rename boards/{esp32c6_devkitc_esp32c6_hpcore.overkay => esp32c6_devkitc_hpcore.overlay} (100%) delete mode 100644 sample.yaml delete mode 100644 src/mqtt_client.c delete mode 100644 src/mqtt_client.h delete mode 100644 src/mqtt_client_shell.c delete mode 100644 src/mqtt_client_shell.h create mode 100644 src/net.c create mode 100644 src/net.h diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..317b07e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json", + "files.associations": { + "log.h": "c", + "kernel.h": "c", + "dns_resolve.h": "c", + "net_if.h": "c" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ba91cb4 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "Build Zephyr app", + "command": "west build -b esp32c6_devkitc .", + "group": "build" + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ff9d58d..e08b378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,5 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(blinky) -target_sources(app PRIVATE src/main.c src/mqtt_client.c src/mqtt_client_shell.c) +target_sources(app PRIVATE src/main.c) +target_sources(app PRIVATE src/net.c) \ No newline at end of file diff --git a/Kconfig b/Kconfig index 54a1e3b..5ba9355 100644 --- a/Kconfig +++ b/Kconfig @@ -1,4 +1,47 @@ menu "Home Assistant MQTT Options" + +config WIFI_SSID + string "WiFi SSID" + default "ItenIOT" + help + The SSID of the WiFi network to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "DasPferd" + help + The password for the WiFi network. Leave empty if the network is open. + +config NET_DHCP + bool "Enable DHCP" + default y + help + Enable DHCP for the network interface. If disabled, static IP configuration must be provided. + +config NET_IP_ADDR + string "Static IP address" + default "192.168.1.77" + help + Static IP address to use if DHCP is disabled. Must be in the same subnet as the router. + +config NET_IP_MASK + string "Static IP netmask" + default "255.255.255.0" + help + Static IP netmask to use if DHCP is disabled. Must be in the same subnet as the router. + +config NET_IP_GATEWAY + string "Static IP gateway" + default "192.168.1.1" + help + Static IP gateway to use if DHCP is disabled. This is usually the IP address of the router. + +config NET_DNS_SERVER + string "Static IP DNS server" + default "192.168.1.1" + help + Static IP DNS server to use if DHCP is disabled. This is usually the IP address of the router. + config HA_MQTT_BROKER_HOSTNAME string "MQTT broker hostname" default "homeassistant.local" diff --git a/boards/esp32c6_devkitc_hpcore.conf b/boards/esp32c6_devkitc_hpcore.conf new file mode 100644 index 0000000..0f37ddb --- /dev/null +++ b/boards/esp32c6_devkitc_hpcore.conf @@ -0,0 +1,3 @@ +CONFIG_WIFI=y +CONFIG_WIFI_ESP32=y +CONFIG_ESP32_WIFI_STA_RECONNECT=y \ No newline at end of file diff --git a/boards/esp32c6_devkitc_esp32c6_hpcore.overkay b/boards/esp32c6_devkitc_hpcore.overlay similarity index 100% rename from boards/esp32c6_devkitc_esp32c6_hpcore.overkay rename to boards/esp32c6_devkitc_hpcore.overlay diff --git a/boards/native_sim.overlay b/boards/native_sim.overlay index af5808b..336d7a2 100644 --- a/boards/native_sim.overlay +++ b/boards/native_sim.overlay @@ -1,13 +1,2 @@ / { - switches { - compatible = "gpio-keys"; - sw0: switch_0 { - label = "User switch"; - gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; - }; - }; - - aliases { - switch0 = &sw0; - }; }; diff --git a/prj.conf b/prj.conf index 2b73aa6..acf48f1 100644 --- a/prj.conf +++ b/prj.conf @@ -1,78 +1,26 @@ -# ============================================================================= -# LOGGING AND DEBUGGING -# ============================================================================= -CONFIG_LOG=y -#CONFIG_MQTT_LOG_LEVEL_DBG=y - -# ============================================================================= -# SYSTEM AND HARDWARE -# ============================================================================= -CONFIG_GPIO=y -CONFIG_POSIX_API=y -CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_REBOOT=y - -# ============================================================================= -# SHELL AND COMMAND LINE INTERFACE -# ============================================================================= -CONFIG_SHELL=y -CONFIG_NET_SHELL=y -CONFIG_SHELL_PROMPT_UART="(MQTT GW)> " -CONFIG_SHELL_BACKEND_TELNET=y -CONFIG_SHELL_TELNET_PORT=23 -CONFIG_SHELL_PROMPT_TELNET="(MQTT GW)> " - -# ============================================================================= -# NETWORKING CORE -# ============================================================================= +# Networking core CONFIG_NETWORKING=y -CONFIG_NET_SOCKETS=y -CONFIG_NET_TCP=y -CONFIG_NET_LOG=y -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_ZVFS_POLL_MAX=10 - - -# ============================================================================= -# IPv4 NETWORKING -# ============================================================================= CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_ARP=y +CONFIG_NET_MGMT=y +CONFIG_NET_MGMT_EVENT=y + +# DHCP and DNS CONFIG_NET_DHCPV4=y - -# ============================================================================= -# MQTT PROTOCOL -# ============================================================================= -CONFIG_MQTT_LIB=y - -# ============================================================================= -# ENTROPY AND RANDOM NUMBER GENERATION -# ============================================================================= -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y - -# ============================================================================= -# HWINFO FOR UUID -# ============================================================================= -CONFIG_HWINFO=y - -# ============================================================================= -# JSON ENCODING SUPPORT -# ============================================================================= -CONFIG_JSON_LIBRARY=y - -# ============================================================================= -# SETTINGS SUBSYSTEM -# ============================================================================= -CONFIG_FLASH=y -CONFIG_FLASH_MAP=y -CONFIG_SETTINGS=y -CONFIG_NVS=y -CONFIG_SETTINGS_NVS=y - -# ============================================================================= -# DNS/mDNS RESOLVER SUPPORT FOR .local HOSTNAMES -# ============================================================================= +CONFIG_NET_DHCPV4_OPTION_CALLBACKS=y CONFIG_DNS_RESOLVER=y -CONFIG_MDNS_RESOLVER=y CONFIG_DNS_RESOLVER_MAX_SERVERS=2 -CONFIG_DNS_RESOLVER_LOG_LEVEL_DBG=y \ No newline at end of file + +# Logging and shell +CONFIG_NET_LOG=y +CONFIG_LOG=y +CONFIG_NET_SHELL=y + +# Debugging and stack +CONFIG_INIT_STACKS=y + +# IPv6 (disabled) +CONFIG_NET_IPV6=n + +# CONFIG_NET_DHCP=n \ No newline at end of file diff --git a/run_sim.sh b/run_sim.sh index 98818d3..4b2815f 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -1,6 +1,7 @@ #!/bin/bash while true; do - build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout +# build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout + build/zephyr/zephyr.exe --uart_stdinout if [ $? -eq 0 ]; then break fi diff --git a/sample.yaml b/sample.yaml deleted file mode 100644 index de71191..0000000 --- a/sample.yaml +++ /dev/null @@ -1,12 +0,0 @@ -sample: - name: Blinky Sample -tests: - sample.basic.blinky: - tags: - - LED - - gpio - filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") - depends_on: gpio - harness: led - integration_platforms: - - frdm_k64f diff --git a/src/main.c b/src/main.c index db3da12..b538aa4 100644 --- a/src/main.c +++ b/src/main.c @@ -1,265 +1,24 @@ -/* - * Copyright (c) 2023-2024 Golioth, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(ha_mqtt_switch, CONFIG_LOG_DEFAULT_LEVEL); - #include #include -#include -#include -#include -#include -#include -#include -#include // For sys_rand32_get -#include // For strlen, strncpy -#include "mqtt_client.h" -#include "mqtt_client_shell.h" +#include +#include -#define SWITCH_NODE DT_ALIAS(switch0) +#include "net.h" -#define UUID_MAX_LEN 40 -#define HA_MQTT_STR_MAX_LEN 48 +LOG_MODULE_REGISTER(mqtt_gw, CONFIG_LOG_DEFAULT_LEVEL); -static const struct gpio_dt_spec sw = GPIO_DT_SPEC_GET_OR(SWITCH_NODE, gpios, {0}); -static struct gpio_callback switch_cb_data; - - - -void switch_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) -{ - state = !state; - state_changed = true; - LOG_INF("Switch state: %s (via GPIO)", state ? "ON" : "OFF"); -} - -// Settings handler für uuid, name, broker -static int settings_set_ha(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg) -{ - if (strcmp(key, "uuid") == 0 && len < UUID_MAX_LEN) { - ssize_t rc = read_cb(cb_arg, uuid, len); - if (rc > 0) uuid[rc] = '\0'; - return 0; - } - if (strcmp(key, "name") == 0 && len < HA_MQTT_STR_MAX_LEN) { - ssize_t rc = read_cb(cb_arg, name, len); - if (rc > 0) name[rc] = '\0'; - return 0; - } - if (strcmp(key, "broker") == 0 && len < BROKER_HOST_MAX_LEN) { - ssize_t rc = read_cb(cb_arg, broker_host, len); - if (rc > 0) broker_host[rc] = '\0'; - return 0; - } - return -ENOENT; -} - -static int settings_export_ha(int (*cb)(const char *name, const void *val, size_t val_len)) -{ - int ret = 0; - ret |= cb("uuid", uuid, strlen(uuid)); - ret |= cb("name", name, strlen(name)); - ret |= cb("broker", broker_host, strlen(broker_host)); - return ret; -} - -SETTINGS_STATIC_HANDLER_DEFINE(ha, "ha", NULL, settings_set_ha, NULL, settings_export_ha); - -// Shell command: ha set name -static int cmd_ha_set_name(const struct shell *shell, size_t argc, char **argv) -{ - if (argc != 2) { - shell_print(shell, "Usage: ha set name "); - return -EINVAL; - } - if (strlen(argv[1]) >= HA_MQTT_STR_MAX_LEN) { - shell_print(shell, "Error: name too long (max %d chars)", HA_MQTT_STR_MAX_LEN - 1); - return -EINVAL; - } - strncpy(name, argv[1], HA_MQTT_STR_MAX_LEN - 1); - name[HA_MQTT_STR_MAX_LEN - 1] = '\0'; - settings_save_one("ha/name", name, strlen(name)); - shell_print(shell, "Name set to: %s", name); +/** + * @brief Main application entry point. + * + * This function initializes the MQTT gateway application. It logs the board + * name and initializes the network stack. + * + * @return 0 on success, otherwise a negative error code. + */ +int main(void) { + // k_sleep(K_SECONDS(1)); // Allow time for logging initialization + LOG_INF("MQTT Gateway. Board: %s", CONFIG_BOARD); + net_init(); return 0; -} - - -// Shell command nur noch für uuid -static int cmd_ha_set_uuid(const struct shell *shell, size_t argc, char **argv) -{ - if (argc != 2) { - shell_print(shell, "Usage: ha set uuid "); - return -EINVAL; - } - if (strlen(argv[1]) >= UUID_MAX_LEN) { - shell_print(shell, "Error: uuid too long (max %d chars)", UUID_MAX_LEN - 1); - return -EINVAL; - } - strncpy(uuid, argv[1], UUID_MAX_LEN - 1); - uuid[UUID_MAX_LEN - 1] = '\0'; - settings_save_one("ha/uuid", uuid, strlen(uuid)); - shell_print(shell, "UUID set to: %s", uuid); - return 0; -} - -static int cmd_ha_set_broker(const struct shell *shell, size_t argc, char **argv) -{ - if (mqtt_running) { - shell_print(shell, "Cannot change broker while MQTT client is running. Stop the client first."); - return -EBUSY; - } - if (argc != 2) { - shell_print(shell, "Usage: ha set broker "); - return -EINVAL; - } - if (strlen(argv[1]) >= BROKER_HOST_MAX_LEN) { - shell_print(shell, "Error: broker hostname too long (max %d chars)", BROKER_HOST_MAX_LEN - 1); - return -EINVAL; - } - strncpy(broker_host, argv[1], BROKER_HOST_MAX_LEN - 1); - broker_host[BROKER_HOST_MAX_LEN - 1] = '\0'; - settings_save_one("ha/broker", broker_host, strlen(broker_host)); - shell_print(shell, "Broker hostname set to: %s", broker_host); - return 0; -} - -static int cmd_ha_show(const struct shell *shell, size_t argc, char **argv) -{ - ARG_UNUSED(argc); - ARG_UNUSED(argv); - shell_print(shell, "UUID: %s", uuid); - shell_print(shell, "Name: %s", name); - shell_print(shell, "Broker: %s", broker_host); - return 0; -} - -static int cmd_ha_stop(const struct shell *shell, size_t argc, char **argv) -{ - int err = ha_mqtt_stop(); - if (err) { - shell_print(shell, "Failed to stop MQTT client: %d", err); - return err; - } - shell_print(shell, "MQTT client stopped."); - return 0; -} - -static int cmd_ha_start(const struct shell *shell, size_t argc, char **argv) -{ - if (mqtt_running) { - shell_print(shell, "MQTT client is already running."); - return 0; - } - int err = ha_mqtt_start(); - if (err) { - shell_print(shell, "Failed to start MQTT client: %d", err); - return err; - } - shell_print(shell, "MQTT client started."); - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(ha_set_cmds, - SHELL_CMD(uuid, NULL, "Set Home Assistant UUID", cmd_ha_set_uuid), - SHELL_CMD(name, NULL, "Set Home Assistant Name", cmd_ha_set_name), - SHELL_CMD(broker, NULL, "Set MQTT broker hostname", cmd_ha_set_broker), - SHELL_SUBCMD_SET_END -); - -SHELL_STATIC_SUBCMD_SET_CREATE(ha_cmds, - SHELL_CMD(set, &ha_set_cmds, "Set settings", NULL), - SHELL_CMD(show, NULL, "Show settings", cmd_ha_show), - SHELL_CMD(stop, NULL, "Stop MQTT client", cmd_ha_stop), - SHELL_CMD(start, NULL, "Start MQTT client and send discovery", cmd_ha_start), - SHELL_SUBCMD_SET_END -); - -SHELL_CMD_REGISTER(ha, &ha_cmds, "Home Assistant commands", NULL); - -int main(void) -{ - int err; - - settings_subsys_init(); - settings_load(); - LOG_INF("Loaded uuid: '%s'", uuid); - if (strlen(uuid) == 0) { - // UUID initialisieren, falls leer: HW-UUID holen - uint8_t hwid[16]; - ssize_t len = hwinfo_get_device_id(hwid, sizeof(hwid)); - if (len > 0) { - char *p = uuid; - for (ssize_t i = 0; i < len && (p - uuid) < UUID_MAX_LEN - 2; ++i) { - p += snprintf(p, UUID_MAX_LEN - (p - uuid), "%02X", hwid[i]); - } - *p = '\0'; - settings_save_one("ha/uuid", uuid, strlen(uuid)); - LOG_INF("Generated default UUID from HW: %s", uuid); - } else { - /* Fallback for native_sim oder Plattformen ohne HW UUID: random value */ - uint32_t rnd1 = sys_rand32_get(); - uint32_t rnd2 = sys_rand32_get(); - snprintf(uuid, UUID_MAX_LEN, "SIM-%08X%08X", rnd1, rnd2); - settings_save_one("ha/uuid", uuid, strlen(uuid)); - LOG_WRN("No HW UUID available, generated random UUID: %s", uuid); - } - } - if (strlen(uuid) == 0) { - LOG_ERR("uuid is not set! Use 'ha set uuid ' in the shell."); - return -EINVAL; - } - if (strlen(uuid) >= UUID_MAX_LEN) { - LOG_ERR("uuid too long (%zu >= %d), MQTT client will not start!", strlen(uuid), UUID_MAX_LEN); - return -EINVAL; - } - - LOG_INF("HA MQTT Switch sample started"); - - if (!sw.port) { - LOG_ERR("Switch GPIO device not found in device tree!"); - return 0; - } - if (!gpio_is_ready_dt(&sw)) { - LOG_ERR("Switch device %s is not ready", sw.port->name); - return 0; - } - - err = gpio_pin_configure_dt(&sw, GPIO_INPUT); - if (err) { - LOG_ERR("Failed to configure switch pin: %d", err); - return 0; - } - - err = gpio_pin_interrupt_configure_dt(&sw, GPIO_INT_EDGE_TO_ACTIVE); - if (err) { - LOG_ERR("Failed to configure switch interrupt: %d", err); - return 0; - } - - gpio_init_callback(&switch_cb_data, switch_callback, BIT(sw.pin)); - gpio_add_callback(sw.port, &switch_cb_data); - - // Wait for DHCP to complete and get an IPv4 address - struct net_if *iface = net_if_get_default(); - LOG_INF("Waiting for IPv4 address via DHCP..."); - for (int i = 0; i < 200; ++i) { // Wait up to ~20s - const struct in_addr *addr = net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED); - if (addr && addr->s_addr != 0) { - char buf[NET_IPV4_ADDR_LEN]; - LOG_INF("Got IPv4 address: %s", net_addr_ntop(AF_INET, addr, buf, sizeof(buf))); - break; - } - k_sleep(K_MSEC(100)); - if (i == 199) { - LOG_ERR("No IPv4 address after DHCP timeout"); - return 0; - } - } - - return 0; -} +} \ No newline at end of file diff --git a/src/mqtt_client.c b/src/mqtt_client.c deleted file mode 100644 index 069d2cf..0000000 --- a/src/mqtt_client.c +++ /dev/null @@ -1,434 +0,0 @@ -#include -#include -#include -#include -#include -#include "mqtt_client.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(mqtt_client, LOG_LEVEL_DBG); - -#define HA_DISCOVERY_PREFIX "homeassistant" -#define MQTT_CLIENTID "ha-switch-zephyr" -#define APP_CONNECT_TIMEOUT_MS 2000 -#define APP_SLEEP_MSECS 500 -#define APP_MQTT_BUFFER_SIZE 2048 -#define UUID_MAX_LEN 40 -#define HA_MQTT_STR_MAX_LEN 48 -#define TOPIC_BUF_LEN 128 -#define BROKER_HOST_MAX_LEN 64 - -static struct pollfd fds[1]; -static int nfds; -static struct mqtt_utf8 mqtt_username; -static struct mqtt_utf8 mqtt_password; -static uint8_t rx_buffer[APP_MQTT_BUFFER_SIZE]; -static uint8_t tx_buffer[APP_MQTT_BUFFER_SIZE]; -struct mqtt_client client_ctx; -static struct sockaddr_storage broker; - -char broker_host[BROKER_HOST_MAX_LEN] = "127.0.0.1"; // Default broker host, replace as needed -bool mqtt_running = false; -bool state = false; -bool state_changed = false; -char name[HA_MQTT_STR_MAX_LEN] = CONFIG_HA_MQTT_NAME; -char uuid[UUID_MAX_LEN] = {0}; - -static void prepare_fds(struct mqtt_client *client) -{ - if (client->transport.type == MQTT_TRANSPORT_NON_SECURE) { - fds[0].fd = client->transport.tcp.sock; - } -#if defined(CONFIG_MQTT_LIB_TLS) - else if (client->transport.type == MQTT_TRANSPORT_SECURE) { - fds[0].fd = client->transport.tls.sock; - } -#endif - else { - nfds = 0; - return; - } - fds[0].events = POLLIN; - nfds = 1; -} - -void clear_fds(void) -{ - nfds = 0; -} - -int wait(int timeout) -{ - int ret = -EAGAIN; - if (nfds > 0) { - ret = poll(fds, nfds, timeout); - if (ret > 0) { - if (fds[0].revents & (POLLIN | POLLERR)) { - ret = 0; - } else { - ret = -EIO; - } - } - } - return ret; -} - -void mqtt_auth_init(void) -{ - static char username_buf[64]; - static char password_buf[64]; - strncpy(username_buf, CONFIG_HA_MQTT_USERNAME, sizeof(username_buf) - 1); - username_buf[sizeof(username_buf) - 1] = '\0'; - strncpy(password_buf, CONFIG_HA_MQTT_PASSWORD, sizeof(password_buf) - 1); - password_buf[sizeof(password_buf) - 1] = '\0'; - mqtt_username.utf8 = (uint8_t *)username_buf; - mqtt_username.size = strlen(username_buf); - mqtt_password.utf8 = (uint8_t *)password_buf; - mqtt_password.size = strlen(password_buf); -} - -int client_init(void) -{ - int err; - LOG_DBG("Initializing MQTT client..."); - mqtt_client_init(&client_ctx); - client_ctx.broker = &broker; - client_ctx.evt_cb = mqtt_evt_handler; - client_ctx.client_id.utf8 = (uint8_t *)MQTT_CLIENTID; - client_ctx.client_id.size = strlen(MQTT_CLIENTID); - mqtt_auth_init(); - client_ctx.user_name = &mqtt_username; - client_ctx.password = &mqtt_password; - client_ctx.protocol_version = MQTT_VERSION_3_1_1; - client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE; - client_ctx.rx_buf = rx_buffer; - client_ctx.rx_buf_size = sizeof(rx_buffer); - client_ctx.tx_buf = tx_buffer; - client_ctx.tx_buf_size = sizeof(tx_buffer); - struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker; - broker4->sin_family = AF_INET; - broker4->sin_port = htons(CONFIG_HA_MQTT_BROKER_PORT); - err = zsock_inet_pton(AF_INET, broker_host, &broker4->sin_addr); - if (err < 0) { - LOG_ERR("Failed to set broker address: %d", err); - return err; - } - LOG_DBG("MQTT client initialized."); - return 0; -} - -int publish(struct mqtt_client *client, enum mqtt_qos qos, const char *topic, const char *payload) -{ - struct mqtt_publish_param param; - param.message.topic.qos = qos; - param.message.topic.topic.utf8 = (uint8_t *)topic; - param.message.topic.topic.size = strlen(topic); - param.message.payload.data = (uint8_t *)payload; - param.message.payload.len = strlen(payload); - param.message_id = sys_rand32_get(); - param.dup_flag = 0U; - param.retain_flag = 0U; - return mqtt_publish(client, ¶m); -} - -int subscribe(struct mqtt_client *client, const char *topic) -{ - struct mqtt_topic sub_topic = { - .topic = { - .utf8 = (uint8_t *)topic, - .size = strlen(topic) - }, - .qos = MQTT_QOS_0_AT_MOST_ONCE - }; - const struct mqtt_subscription_list sub_list = { - .list = &sub_topic, - .list_count = 1U, - .message_id = sys_rand32_get(), - }; - return mqtt_subscribe(client, &sub_list); -} - -void build_topic(char *buf, size_t buflen, const char *fmt) -{ - int n = snprintf(buf, buflen, fmt, uuid); - if (n < 0 || n >= buflen) { - LOG_ERR("Topic buffer overflow or encoding error! fmt='%s', uuid='%s'", fmt, uuid); - } -} - -int ha_publish_discovery_document(struct mqtt_client *client) -{ - struct device_info { - const char *identifiers; - const char *name; - const char *model; - const char *mf; - }; - struct config_info { - const char *name; - const char *cmd_t; - const char *stat_t; - const char *uniq_id; - struct device_info device; - }; - static const struct json_obj_descr device_descr[] = { - JSON_OBJ_DESCR_PRIM(struct device_info, identifiers, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct device_info, name, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct device_info, model, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct device_info, mf, JSON_TOK_STRING), - }; - static const struct json_obj_descr config_descr[] = { - JSON_OBJ_DESCR_PRIM(struct config_info, name, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct config_info, cmd_t, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct config_info, stat_t, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct config_info, uniq_id, JSON_TOK_STRING), - JSON_OBJ_DESCR_OBJECT(struct config_info, device, device_descr), - }; - char cmd_topic[TOPIC_BUF_LEN]; - char state_topic[TOPIC_BUF_LEN]; - char uniq_id[UUID_MAX_LEN]; - char ident[TOPIC_BUF_LEN]; - char disc_topic[TOPIC_BUF_LEN]; - snprintf(cmd_topic, sizeof(cmd_topic), HA_DISCOVERY_PREFIX "/switch/%s/set", uuid); - snprintf(state_topic, sizeof(state_topic), HA_DISCOVERY_PREFIX "/switch/%s/state", uuid); - strncpy(uniq_id, uuid, sizeof(uniq_id) - 1); - uniq_id[sizeof(uniq_id) - 1] = '\0'; - snprintf(ident, sizeof(ident), "zephyr-ha-%s", uuid); - snprintf(disc_topic, sizeof(disc_topic), HA_DISCOVERY_PREFIX "/switch/%s/config", uuid); - LOG_DBG("Publishing discovery document to topic: %s", disc_topic); - LOG_DBG("Command topic: %s", cmd_topic); - LOG_DBG("State topic: %s", state_topic); - LOG_DBG("Unique ID: %s", uniq_id); - LOG_DBG("Device identifier: %s", ident); - char model[HA_MQTT_STR_MAX_LEN]; - strncpy(model, CONFIG_HA_MQTT_MODEL, HA_MQTT_STR_MAX_LEN - 1); - model[HA_MQTT_STR_MAX_LEN - 1] = '\0'; - char mf[HA_MQTT_STR_MAX_LEN]; - strncpy(mf, CONFIG_HA_MQTT_MANUFACTURER, HA_MQTT_STR_MAX_LEN - 1); - mf[HA_MQTT_STR_MAX_LEN - 1] = '\0'; - struct device_info dev = { - .identifiers = ident, - .name = name, - .model = model, - .mf = mf - }; - struct config_info cfg = { - .name = name, - .cmd_t = cmd_topic, - .stat_t = state_topic, - .uniq_id = uniq_id, - .device = dev - }; - char payload[APP_MQTT_BUFFER_SIZE]; - int err; - LOG_DBG("Encoding JSON discovery document..."); - err = json_obj_encode_buf(config_descr, ARRAY_SIZE(config_descr), &cfg, payload, sizeof(payload)); - if (err < 0) { - LOG_ERR("Failed to encode JSON: %d", err); - return err; - } - LOG_DBG("Discovery document: %s", payload); - LOG_DBG("Publishing discovery document..."); - return publish(client, MQTT_QOS_0_AT_MOST_ONCE, disc_topic, payload); -} - -void mqtt_evt_handler(struct mqtt_client *client, const struct mqtt_evt *evt) -{ - int err; - switch (evt->type) { - case MQTT_EVT_CONNACK: - if (evt->result != 0) { - LOG_ERR("MQTT connect failed: %d", evt->result); - mqtt_running = false; - break; - } - LOG_INF("MQTT client connected!"); - // Publish discovery document and subscribe to command topic on successful connection - err = ha_publish_discovery_document(client); - if (err) { - LOG_ERR("Failed to publish discovery document: %d", err); - } else { - LOG_INF("Published discovery document"); - } - - char cmd_topic[TOPIC_BUF_LEN]; - build_topic(cmd_topic, sizeof(cmd_topic), HA_DISCOVERY_PREFIX "/switch/%s/set"); - err = subscribe(client, cmd_topic); - if (err) { - LOG_ERR("Failed to subscribe to topic: %d", err); - } else { - LOG_INF("Subscribed to topic %s", cmd_topic); - } - break; - - case MQTT_EVT_DISCONNECT: - LOG_INF("MQTT client disconnected: %d", evt->result); - mqtt_running = false; - clear_fds(); - break; - - case MQTT_EVT_PUBLISH: - LOG_INF("MQTT PUBLISH event received!"); - const struct mqtt_publish_param *p = &evt->param.publish; - char payload_str[APP_MQTT_BUFFER_SIZE]; // Use a fixed-size buffer - char topic_str[TOPIC_BUF_LEN]; // Use a fixed-size buffer - - if (p->message.payload.len >= sizeof(payload_str)) { - LOG_ERR("Payload too long for buffer"); - break; - } - memcpy(payload_str, p->message.payload.data, p->message.payload.len); - payload_str[p->message.payload.len] = '\0'; - - if (p->message.topic.topic.size >= sizeof(topic_str)) { - LOG_ERR("Topic too long for buffer"); - break; - } - memcpy(topic_str, p->message.topic.topic.utf8, p->message.topic.topic.size); - topic_str[p->message.topic.topic.size] = '\0'; - - LOG_INF("Topic: %s, Payload: %s", topic_str, payload_str); - - // Handle switch command - char cmd_topic_expected[TOPIC_BUF_LEN]; - build_topic(cmd_topic_expected, sizeof(cmd_topic_expected), HA_DISCOVERY_PREFIX "/switch/%s/set"); - - if (strcmp(topic_str, cmd_topic_expected) == 0) { - if (strcmp(payload_str, "ON") == 0) { - state = true; - state_changed = true; - LOG_INF("Switch state set to ON (via MQTT)"); - } else if (strcmp(payload_str, "OFF") == 0) { - state = false; - state_changed = true; - LOG_INF("Switch state set to OFF (via MQTT)"); - } else { - LOG_WRN("Unknown command payload: %s", payload_str); - } - } - break; - - case MQTT_EVT_SUBACK: - LOG_INF("MQTT SUBACK event received!"); - break; - - case MQTT_EVT_UNSUBACK: - LOG_INF("MQTT UNSUBACK event received!"); - break; - - case MQTT_EVT_PUBACK: - LOG_INF("MQTT PUBACK event received!"); - break; - - case MQTT_EVT_PUBREC: - LOG_INF("MQTT PUBREC event received!"); - break; - - case MQTT_EVT_PUBREL: - LOG_INF("MQTT PUBREL event received!"); - break; - - case MQTT_EVT_PUBCOMP: - LOG_INF("MQTT PUBCOMP event received!"); - break; - - default: - LOG_DBG("Unhandled MQTT event type: %d", evt->type); - break; - } -} - -void mqtt_client_run_loop(void) -{ - int err; - while (mqtt_running) { - err = wait(APP_SLEEP_MSECS); - if (err && err != -EAGAIN) { - LOG_ERR("Failed to wait for MQTT client: %d", err); - break; - } - - err = mqtt_input(&client_ctx); - if (err) { - LOG_ERR("Failed to process MQTT input: %d", err); - // Continue to allow for potential recovery or disconnect event - } - - err = mqtt_live(&client_ctx); - if (err && err != -EAGAIN) { - LOG_ERR("Failed to send MQTT keepalive: %d", err); - break; - } else if (err == 0) { - LOG_DBG("Sent MQTT keepalive (PINGREQ)"); - } - - if (state_changed) { - char state_topic[TOPIC_BUF_LEN]; - snprintf(state_topic, sizeof(state_topic), HA_DISCOVERY_PREFIX "/switch/%s/state", uuid); - err = publish(&client_ctx, MQTT_QOS_0_AT_MOST_ONCE, state_topic, state ? "ON" : "OFF"); - if (err) { - LOG_ERR("Failed to publish switch state: %d", err); - } else { - LOG_INF("Published switch state: %s", state ? "ON" : "OFF"); - state_changed = false; - } - } - } - // Clean up after loop exits (e.g., mqtt_running becomes false) - err = mqtt_disconnect(&client_ctx, NULL); - if (err) { - LOG_ERR("Failed to disconnect MQTT client: %d", err); - } - clear_fds(); - LOG_INF("MQTT client run loop terminated."); -} - -int ha_mqtt_start(void) -{ - int err = client_init(); - if (err) { - LOG_ERR("Failed to initialize MQTT client: %d", err); - return err; - } - err = mqtt_connect(&client_ctx); - if (err) { - LOG_ERR("Failed to connect to MQTT broker: %d", err); - return err; - } - mqtt_running = true; - struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker; - char ip_str[NET_IPV4_ADDR_LEN]; - if (zsock_inet_ntop(AF_INET, &broker4->sin_addr, ip_str, sizeof(ip_str))) { - LOG_INF("Connected to MQTT broker at %s:%d", ip_str, ntohs(broker4->sin_port)); - } - prepare_fds(&client_ctx); - - // Start the MQTT client run loop in a separate thread or manage it here - // For now, we'll call it directly, assuming it's blocking until mqtt_running is false - // In a real application, you might want to k_thread_create this. - mqtt_client_run_loop(); - - return 0; -} - -int ha_mqtt_stop(void) -{ - if (!mqtt_running) { - LOG_INF("MQTT client is not running."); - return 0; - } - // Setting mqtt_running to false will cause the mqtt_client_run_loop to exit - mqtt_running = false; - LOG_INF("MQTT client stop requested."); - return 0; -} diff --git a/src/mqtt_client.h b/src/mqtt_client.h deleted file mode 100644 index a84ad47..0000000 --- a/src/mqtt_client.h +++ /dev/null @@ -1,43 +0,0 @@ - -#ifndef MQTT_CLIENT_H -#define MQTT_CLIENT_H - -#define HA_MQTT_STR_MAX_LEN 48 -#define UUID_MAX_LEN 40 -#define BROKER_HOST_MAX_LEN 64 - -extern char broker_host[BROKER_HOST_MAX_LEN]; -extern bool mqtt_running; -extern bool state; -extern bool state_changed; -extern char uuid[]; -extern char name[]; -extern char broker_host[]; - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int mqtt_client_init_all(void); -int ha_mqtt_start(void); -int ha_mqtt_stop(void); -int ha_publish_discovery_document(struct mqtt_client *client); -int subscribe(struct mqtt_client *client, const char *topic); -void mqtt_evt_handler(struct mqtt_client *client, const struct mqtt_evt *evt); -void mqtt_client_run_loop(void); - -void build_topic(char *buf, size_t buflen, const char *fmt); -void clear_fds(void); -int wait(int timeout); -int publish(struct mqtt_client *client, enum mqtt_qos qos, const char *topic, const char *payload); - -extern struct mqtt_client client_ctx; - -#ifdef __cplusplus -} -#endif - -#endif // MQTT_CLIENT_H diff --git a/src/mqtt_client_shell.c b/src/mqtt_client_shell.c deleted file mode 100644 index 8d0d3d7..0000000 --- a/src/mqtt_client_shell.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "mqtt_client_shell.h" -#include "mqtt_client.h" -#include -#include -#include - -// Shell command: ha set name -static int cmd_ha_set_name(const struct shell *shell, size_t argc, char **argv) -{ - if (argc != 2) { - shell_print(shell, "Usage: ha set name "); - return -EINVAL; - } - if (strlen(argv[1]) >= HA_MQTT_STR_MAX_LEN) { - shell_print(shell, "Error: name too long (max %d chars)", HA_MQTT_STR_MAX_LEN - 1); - return -EINVAL; - } - strncpy(name, argv[1], HA_MQTT_STR_MAX_LEN - 1); - name[HA_MQTT_STR_MAX_LEN - 1] = '\0'; - settings_save_one("ha/name", name, strlen(name)); - shell_print(shell, "Name set to: %s", name); - return 0; -} - -// Shell command: ha set uuid -static int cmd_ha_set_uuid(const struct shell *shell, size_t argc, char **argv) -{ - if (argc != 2) { - shell_print(shell, "Usage: ha set uuid "); - return -EINVAL; - } - if (strlen(argv[1]) >= UUID_MAX_LEN) { - shell_print(shell, "Error: uuid too long (max %d chars)", UUID_MAX_LEN - 1); - return -EINVAL; - } - strncpy(uuid, argv[1], UUID_MAX_LEN - 1); - uuid[UUID_MAX_LEN - 1] = '\0'; - settings_save_one("ha/uuid", uuid, strlen(uuid)); - shell_print(shell, "UUID set to: %s", uuid); - return 0; -} - -// Shell command: ha set broker -static int cmd_ha_set_broker(const struct shell *shell, size_t argc, char **argv) -{ - if (mqtt_running) { - shell_print(shell, "Cannot change broker while MQTT client is running. Stop the client first."); - return -EBUSY; - } - if (argc != 2) { - shell_print(shell, "Usage: ha set broker "); - return -EINVAL; - } - if (strlen(argv[1]) >= BROKER_HOST_MAX_LEN) { - shell_print(shell, "Error: broker hostname too long (max %d chars)", BROKER_HOST_MAX_LEN - 1); - return -EINVAL; - } - strncpy(broker_host, argv[1], BROKER_HOST_MAX_LEN - 1); - broker_host[BROKER_HOST_MAX_LEN - 1] = '\0'; - settings_save_one("ha/broker", broker_host, strlen(broker_host)); - shell_print(shell, "Broker hostname set to: %s", broker_host); - return 0; -} - -static int cmd_ha_show(const struct shell *shell, size_t argc, char **argv) -{ - ARG_UNUSED(argc); - ARG_UNUSED(argv); - shell_print(shell, "UUID: %s", uuid); - shell_print(shell, "Name: %s", name); - shell_print(shell, "Broker: %s", broker_host); - return 0; -} - -static int cmd_ha_stop(const struct shell *shell, size_t argc, char **argv) -{ - int err = ha_mqtt_stop(); - if (err) { - shell_print(shell, "Failed to stop MQTT client: %d", err); - return err; - } - shell_print(shell, "MQTT client stopped."); - return 0; -} - -static int cmd_ha_start(const struct shell *shell, size_t argc, char **argv) -{ - if (mqtt_running) { - shell_print(shell, "MQTT client is already running."); - return 0; - } - int err = ha_mqtt_start(); - if (err) { - shell_print(shell, "Failed to start MQTT client: %d", err); - return err; - } - shell_print(shell, "MQTT client started."); - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(ha_set_cmds, - SHELL_CMD(uuid, NULL, "Set Home Assistant UUID", cmd_ha_set_uuid), - SHELL_CMD(name, NULL, "Set Home Assistant Name", cmd_ha_set_name), - SHELL_CMD(broker, NULL, "Set MQTT broker hostname", cmd_ha_set_broker), - SHELL_SUBCMD_SET_END -); - -SHELL_STATIC_SUBCMD_SET_CREATE(ha_cmds, - SHELL_CMD(set, &ha_set_cmds, "Set settings", NULL), - SHELL_CMD(show, NULL, "Show settings", cmd_ha_show), - SHELL_CMD(stop, NULL, "Stop MQTT client", cmd_ha_stop), - SHELL_CMD(start, NULL, "Start MQTT client and send discovery", cmd_ha_start), - SHELL_SUBCMD_SET_END -); - -void mqtt_client_shell_register(void) -{ - SHELL_CMD_REGISTER(ha, &ha_cmds, "Home Assistant commands", NULL); -} diff --git a/src/mqtt_client_shell.h b/src/mqtt_client_shell.h deleted file mode 100644 index 372fec9..0000000 --- a/src/mqtt_client_shell.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MQTT_CLIENT_SHELL_H -#define MQTT_CLIENT_SHELL_H - -#include - -void mqtt_client_shell_register(void); - -#endif // MQTT_CLIENT_SHELL_H diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..8870db1 --- /dev/null +++ b/src/net.c @@ -0,0 +1,280 @@ +#include +LOG_MODULE_REGISTER(net, LOG_LEVEL_DBG); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_WIFI +#include +static struct net_mgmt_event_callback wifi_mgmt_cb; +static K_SEM_DEFINE(wifi_connected_sem, 0, 1); +#endif // CONFIG_WIFI + +static struct net_mgmt_event_callback net_mgmt_cb; + + +#ifdef CONFIG_NET_DHCP +static bool dhcp_enabled = true; +#else +static bool dhcp_enabled = false; +#endif + +static char *static_ip = CONFIG_NET_IP_ADDR; +static char *static_netmask = CONFIG_NET_IP_MASK; +static char *static_gateway = CONFIG_NET_IP_GATEWAY; +static char *static_dns = CONFIG_NET_DNS_SERVER; + +/** + * @brief Starts the DHCPv4 client on the given network interface. + * + * @param iface The network interface. + * @param user_data A pointer to user data (unused). + */ +static void start_dhcpv4_client(struct net_if *iface, void *user_data) +{ + ARG_UNUSED(user_data); + if (!iface) { + LOG_ERR("No network interface provided"); + return; + } + + if (!net_if_is_up(iface)) { + LOG_ERR("Network interface %s is not up", net_if_get_device(iface)->name); + return; + } + + LOG_INF("Starting DHCPv4 client on interface: %s, index %d", + net_if_get_device(iface)->name, + net_if_get_by_iface(iface)); + net_dhcpv4_start(iface); +} + +/** + * @brief Network management event handler. + * + * This function is called when a network management event occurs. It logs + * information about the new IP address, subnet mask, router, and lease time + * when an IPv4 address is added. + * + * @param cb The network management event callback structure. + * @param mgmt_event The network management event. + * @param iface The network interface. + */ +static void net_mgmt_event_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { + 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; + } + + LOG_INF(" Address[%d]: %s", + net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr, + buf, + sizeof(buf))); + LOG_INF(" Subnet[%d]: %s", + net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].netmask, + buf, + sizeof(buf))); + LOG_INF(" Router[%d]: %s", + net_if_get_by_iface(iface), + net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf))); + LOG_INF("Lease time[%d]: %u seconds", + net_if_get_by_iface(iface), + iface->config.dhcpv4.lease_time); + } + } +} + +#ifdef CONFIG_WIFI + +/** + * @brief Wi-Fi management event handler. + * + * This function is called when a Wi-Fi management event occurs. It gives the + * `wifi_connected_sem` semaphore when the Wi-Fi is connected. + * + * @param cb The network management event callback structure. + * @param mgmt_event The network management event. + * @param iface The network interface. + */ +static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, + uint64_t mgmt_event, struct net_if *iface) +{ + if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { + LOG_INF("Wi-Fi connected!"); + k_sem_give(&wifi_connected_sem); + } +} + +/** + * @brief Initializes the Wi-Fi connection. + * + * This function sets up the Wi-Fi connection parameters and starts the + * connection process. It registers an event handler to listen for connection + * results. + */ +void init_wifi(void) +{ + // Netzwerk-Interface abrufen + struct net_if *iface = net_if_get_default(); + if (!iface) { + LOG_ERR("Could not get network interface"); + return; + } + + // Wi-Fi-Verbindungsparameter + struct wifi_connect_req_params cnx_params = { + .ssid = "ItenIOT", // Ersetzen Sie dies mit Ihrer SSID + .ssid_length = sizeof("ItenIOT") - 1, + .psk = "DasPferd", // Ersetzen Sie dies mit Ihrem Passwort + .psk_length = sizeof("DasPferd") - 1, + .security = WIFI_SECURITY_TYPE_PSK, + .channel = WIFI_CHANNEL_ANY, + }; + + // Event-Handler registrieren + net_mgmt_init_event_callback(&wifi_mgmt_cb, wifi_mgmt_event_handler, NET_EVENT_WIFI_CONNECT_RESULT); + net_mgmt_add_event_callback(&wifi_mgmt_cb); + + LOG_INF("Connecting to Wi-Fi..."); + + // Verbindungsanfrage senden + if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { + LOG_ERR("Wi-Fi connection request failed"); + return; + } + + // // Warten, bis die Verbindung hergestellt ist + if (k_sem_take(&wifi_connected_sem, K_SECONDS(30)) != 0) { + LOG_ERR("Wi-Fi connection timed out"); + return; + } + + // Ab hier ist die Wi-Fi-Verbindung aufgebaut und Sie können Netzwerkoperationen durchführen. + // Ein DHCP-Client wird automatisch gestartet, um eine IP-Adresse zu beziehen. + LOG_INF("Wi-Fi setup complete."); +} +#endif // CONFIG_WIFI + +/** + * @brief Initializes the network stack. + * + * This function initializes the network stack. It initializes and adds a + * network management event callback to log network events. If Wi-Fi is + * enabled, it initializes the Wi-Fi connection. If DHCP is enabled, it + * starts the DHCP client on all interfaces. Otherwise, it sets a static IP + * configuration. + * + * @return 0 on success, otherwise a negative error code. + */ +int net_init(void) +{ + int rc; + net_mgmt_init_event_callback(&net_mgmt_cb, net_mgmt_event_handler, NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&net_mgmt_cb); + +#ifdef CONFIG_WIFI + init_wifi(); +#endif // CONFIG_WIFI + + if (dhcp_enabled) { + LOG_INF("DHCP is enabled, starting DHCP client on all interfaces"); + net_if_foreach(start_dhcpv4_client, NULL); + } else { + struct net_if *iface = net_if_get_default(); + if (!iface) { + LOG_ERR("No default network interface found"); + return -ENODEV; + } + LOG_INF("DHCP is disabled, setting static IP configuration on interface: %s", + net_if_get_device(iface)->name); + if (net_if_is_up(iface)) { + LOG_INF("Bringing down network interface %s before setting static IP", + net_if_get_device(iface)->name); + // Ensure the interface is down before applying static configuration + rc = net_if_down(iface); + if (rc < 0) { + LOG_ERR("Failed to bring down network interface %s: %d", + net_if_get_device(iface)->name, + rc); + return rc; + } + } + struct in_addr ipaddr, netmask, gw; + + if (net_addr_pton(AF_INET, static_ip, &ipaddr) < 0 || + net_addr_pton(AF_INET, static_netmask, &netmask) < 0 || + net_addr_pton(AF_INET, static_gateway, &gw) < 0) { + LOG_ERR("Invalid static IP configuration"); + return -EINVAL; + } + + struct net_if_addr *ifaddr = + net_if_ipv4_addr_add(iface, &ipaddr, NET_ADDR_MANUAL, 0); + if (ifaddr == NULL) { + LOG_ERR("Failed to add IPv4 address"); + return -EIO; + } + + rc = net_if_ipv4_set_netmask_by_addr(iface, &ipaddr, &netmask); + if (rc < 0) { + LOG_ERR("Failed to set netmask: %d", rc); + return rc; + } + net_if_ipv4_set_gw(iface, &gw); + + const char *dns_servers_str[] = { + static_dns, + NULL, // Terminate the list with NULL + }; + struct sockaddr_in dns_server; + dns_server.sin_family = AF_INET; + dns_server.sin_port = htons(53); + rc = net_addr_pton(AF_INET, static_dns, &dns_server.sin_addr); + if (rc < 0) { + LOG_ERR("Invalid DNS server address"); + return rc; + } + const struct sockaddr *dns_servers_sa[] = { + (struct sockaddr *)&dns_server, + NULL, // Terminate the list with NULL + }; + + struct dns_resolve_context dns_ctx; + rc = dns_resolve_init(&dns_ctx, dns_servers_str, dns_servers_sa); + if (rc < 0) { + LOG_ERR("Failed to add DNS server: %d", rc); + return rc; + } + + rc = net_if_up(iface); + if (rc < 0) { + LOG_ERR("Failed to bring up network interface %s: %d", + net_if_get_device(iface)->name, + rc); + return rc; + } + LOG_INF("Static IP configuration set"); + LOG_INF(" IP: %s", static_ip); + LOG_INF(" Netmask: %s", static_netmask); + LOG_INF(" Gateway: %s", static_gateway); + LOG_INF(" DNS: %s", static_dns); +} + return 0; +} \ No newline at end of file diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..6a709de --- /dev/null +++ b/src/net.h @@ -0,0 +1,17 @@ +#ifndef __NET_H__ +#define __NET_H__ + +/** + * @brief Initializes the network stack. + * + * This function initializes the network stack. It initializes and adds a + * network management event callback to log network events. If Wi-Fi is + * enabled, it initializes the Wi-Fi connection. If DHCP is enabled, it + * starts the DHCP client on all interfaces. Otherwise, it sets a static IP + * configuration. + * + * @return 0 on success, otherwise a negative error code. + */ +int net_init(void); + +#endif // __NET_H__ \ No newline at end of file