diff --git a/README.rst b/README.rst index ec23fe5..c60bb74 100644 --- a/README.rst +++ b/README.rst @@ -1,97 +1,65 @@ -.. zephyr:code-sample:: blinky - :name: Blinky - :relevant-api: gpio_interface +.. SPDX-License-Identifier: Apache-2.0 - Blink an LED forever using the GPIO API. +############################ +Modbus MQTT Gateway +############################ Overview ******** -The Blinky sample blinks an LED forever using the :ref:`GPIO API `. +This Zephyr application serves as an MQTT gateway, primarily designed to bridge Modbus devices with a Home Assistant instance. It connects to a WiFi network, obtains an IP address, and communicates with an MQTT broker. -The source code shows how to: +Features +******** -#. Get a pin specification from the :ref:`devicetree ` as a - :c:struct:`gpio_dt_spec` -#. Configure the GPIO pin as an output -#. Toggle the pin forever +- **WiFi Connectivity**: Connects to a specified WiFi network using credentials provided via Kconfig. +- **Network Configuration**: Supports both DHCP and static IP addressing for flexible network integration. +- **MQTT Integration**: Configured to communicate with an MQTT broker, with specific options for Home Assistant discovery. +- **Configurability**: All major parameters, including WiFi, network, and MQTT settings, are configurable through Kconfig. +- **Simulation Support**: Includes a script and configuration for running in a simulated environment (`native_sim`). -See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead. +Configuration +************* -.. _blinky-sample-requirements: +The application is configured using Kconfig. Key options can be found in the "Home Assistant MQTT Options" menu. -Requirements -************ +- **WiFi Settings**: + - `CONFIG_WIFI_SSID`: The SSID of the WiFi network. + - `CONFIG_WIFI_PASSWORD`: The password for the WiFi network. -Your board must: +- **Network Settings**: + - `CONFIG_NET_DHCP`: Enable or disable DHCP. + - `CONFIG_NET_IP_ADDR`: Static IP address. + - `CONFIG_NET_IP_MASK`: Static IP netmask. + - `CONFIG_NET_IP_GATEWAY`: Static IP gateway. + - `CONFIG_NET_DNS_SERVER`: Static DNS server. -#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of - Zephyr's :ref:`boards`). -#. Have the LED configured using the ``led0`` devicetree alias. +- **MQTT Broker Settings**: + - `CONFIG_HA_MQTT_BROKER_HOSTNAME`: Hostname or IP of the MQTT broker. + - `CONFIG_HA_MQTT_BROKER_PORT`: Port of the MQTT broker. + - `CONFIG_HA_MQTT_USERNAME`: Username for MQTT authentication. + - `CONFIG_HA_MQTT_PASSWORD`: Password for MQTT authentication. + +- **Home Assistant Device Info**: + - `CONFIG_HA_MQTT_NAME`: Device name. + - `CONFIG_HA_MQTT_MANUFACTURER`: Manufacturer name. + - `CONFIG_HA_MQTT_MODEL`: Model name. Building and Running ******************** -Build and flash Blinky as follows, changing ``reel_board`` for your board: +**Building for Hardware (e.g., ESP32-C6)** -.. zephyr-app-commands:: - :zephyr-app: samples/basic/blinky - :board: reel_board - :goals: build flash - :compact: +.. code-block:: shell -After flashing, the LED starts to blink and messages with the current LED state -are printed on the console. If a runtime error occurs, the sample exits without -printing to the console. + west build -b esp32c6_devkitc_hpcore -Build errors -************ +**Running in Simulation** -You will see a build error at the source code line defining the ``struct -gpio_dt_spec led`` variable if you try to build Blinky for an unsupported -board. +A simulation can be run using the provided script: -On GCC-based toolchains, the error looks like this: +.. code-block:: shell -.. code-block:: none + ./run_sim.sh - error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function) - -Adding board support -******************** - -To add support for your board, add something like this to your devicetree: - -.. code-block:: DTS - - / { - aliases { - led0 = &myled0; - }; - - leds { - compatible = "gpio-leds"; - myled0: led_0 { - gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; - }; - }; - }; - -The above sets your board's ``led0`` alias to use pin 13 on GPIO controller -``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_HIGH` mean the LED is on when -the pin is set to its high state, and off when the pin is in its low state. - -Tips: - -- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs - in devicetree. - -- If you're not sure what to do, check the devicetrees for supported boards which - use the same SoC as your target. See :ref:`get-devicetree-outputs` for details. - -- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use - in devicetree. - -- If the LED is built in to your board hardware, the alias should be defined in - your :ref:`BOARD.dts file `. Otherwise, you can - define one in a :ref:`devicetree overlay `. +This will build and run the application for the `native_sim` target. \ No newline at end of file diff --git a/boards/esp32c6_devkitc_hpcore.conf b/boards/esp32c6_devkitc_hpcore.conf index 0f37ddb..fd040bc 100644 --- a/boards/esp32c6_devkitc_hpcore.conf +++ b/boards/esp32c6_devkitc_hpcore.conf @@ -1,3 +1,3 @@ CONFIG_WIFI=y -CONFIG_WIFI_ESP32=y -CONFIG_ESP32_WIFI_STA_RECONNECT=y \ No newline at end of file +CONFIG_NET_L2_WIFI_SHELL=y +CONFIG_WIFI_ESP32=y \ No newline at end of file diff --git a/prj.conf b/prj.conf index acf48f1..a28e593 100644 --- a/prj.conf +++ b/prj.conf @@ -1,3 +1,23 @@ +# --------------------------------------------------------------------------- +# APP SETTINGS +# --------------------------------------------------------------------------- +# See KConfig documentation for more details on these settings. +# Most of them can also be set in the shell. +CONFIG_NET_DHCP=n + +# ---------------------------------------------------------------------------- +# GENERAL SETTINGS +# ---------------------------------------------------------------------------- + +# Settings subsystem +CONFIG_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_SETTINGS_NVS=y +CONFIG_NVS=y +CONFIG_SETTINGS_RUNTIME=y + # Networking core CONFIG_NETWORKING=y CONFIG_NET_IPV4=y @@ -16,6 +36,7 @@ CONFIG_DNS_RESOLVER_MAX_SERVERS=2 CONFIG_NET_LOG=y CONFIG_LOG=y CONFIG_NET_SHELL=y +CONFIG_REBOOT=y # Debugging and stack CONFIG_INIT_STACKS=y diff --git a/run_sim.sh b/run_sim.sh index 4b2815f..98818d3 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -1,7 +1,6 @@ #!/bin/bash while true; do -# build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout - build/zephyr/zephyr.exe --uart_stdinout + build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout if [ $? -eq 0 ]; then break fi diff --git a/src/main.c b/src/main.c index b538aa4..6651e43 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(mqtt_gw, CONFIG_LOG_DEFAULT_LEVEL); * @return 0 on success, otherwise a negative error code. */ int main(void) { - // k_sleep(K_SECONDS(1)); // Allow time for logging initialization + k_sleep(K_MSEC(100)); // Allow time for logging initialization LOG_INF("MQTT Gateway. Board: %s", CONFIG_BOARD); net_init(); return 0; diff --git a/src/net.c b/src/net.c index 8870db1..4b2dd60 100644 --- a/src/net.c +++ b/src/net.c @@ -12,14 +12,35 @@ LOG_MODULE_REGISTER(net, LOG_LEVEL_DBG); #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); + +#define WIFI_RECONNECT_DELAY_S 10 // Wartezeit in Sekunden + +static struct net_mgmt_event_callback wifi_connect_cb; +static struct net_mgmt_event_callback wifi_disconnect_cb; + +static void attempt_wifi_reconnect_work_handler(struct k_work *work); +static struct k_timer wifi_reconnect_timer; +static K_WORK_DEFINE(reconnect_work, attempt_wifi_reconnect_work_handler); + #endif // CONFIG_WIFI -static struct net_mgmt_event_callback net_mgmt_cb; +// Hooks for MQTT client control +__weak void on_network_ready(struct net_if *iface) +{ + LOG_INF("Network is ready for communication (default weak handler)"); +} + +__weak void on_network_down(struct net_if *iface) +{ + LOG_INF("Network is down (default weak handler)"); +} #ifdef CONFIG_NET_DHCP static bool dhcp_enabled = true; @@ -32,249 +53,376 @@ 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) +static int net_settings_handle( + const char *name, size_t len, settings_read_cb read_cb, void *cb_arg); + +struct settings_handler net_settings = { + .name = "net", + .h_set = net_settings_handle, +}; + +static int net_settings_handle(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { - ARG_UNUSED(user_data); - if (!iface) { - LOG_ERR("No network interface provided"); - return; - } + const char *next; + int rc; - 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); + if (settings_name_steq(name, "dhcp", &next) && !next) { + rc = read_cb(cb_arg, &dhcp_enabled, sizeof(dhcp_enabled)); + if (rc < 0) { + LOG_ERR("Error reading setting 'dhcp_enabled' (%d)", rc); + } else { + LOG_DBG("Loaded 'dhcp_enabled' from settings: %s", + dhcp_enabled ? "ENABLED" : "DISABLED"); + } + return rc > 0 ? 0 : rc; + } + return -ENOENT; } -/** - * @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) +int net_settings_init(void) { - 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); - } - } + int rc; + rc = settings_subsys_init(); + if (rc < 0) { + LOG_ERR("Failed to initialize settings subsystem: %d", rc); + return rc; + } + rc = settings_register(&net_settings); + if (rc < 0) { + LOG_ERR("Failed to register settings handler: %d", rc); + return rc; + } + rc = settings_load(); + if (rc < 0) { + LOG_ERR("Failed to load settings: %d", rc); + return rc; + } + return 0; } -#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) +static void net_log_ip_settings(struct net_if *iface) { - if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) { - LOG_INF("Wi-Fi connected!"); - k_sem_give(&wifi_connected_sem); + char buf[NET_IPV4_ADDR_LEN]; + struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4; + if (!ipv4) { + LOG_INF("No IPv4 config on interface %s", net_if_get_device(iface)->name); + return; + } + LOG_INF("IP settings for interface: %s", net_if_get_device(iface)->name); + LOG_INF(" IP: %s", + net_addr_ntop(AF_INET, &ipv4->unicast[0].ipv4.address.in_addr, buf, sizeof(buf))); + LOG_INF( + " Netmask: %s", net_addr_ntop(AF_INET, &ipv4->unicast[0].netmask, buf, sizeof(buf))); + LOG_INF(" Gateway: %s", net_addr_ntop(AF_INET, &ipv4->gw, buf, sizeof(buf))); + if (static_dns) { + LOG_INF(" DNS: %s", static_dns); } } -/** - * @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) +static void start_dhcpv4_client(struct net_if *iface, void *user_data) { - // Netzwerk-Interface abrufen - struct net_if *iface = net_if_get_default(); + ARG_UNUSED(user_data); if (!iface) { - LOG_ERR("Could not get network interface"); + LOG_ERR("No network interface provided"); return; } - // Wi-Fi-Verbindungsparameter + 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); +} + +static void net_event_ipv4_addr_add_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + ARG_UNUSED(cb); + ARG_UNUSED(mgmt_event); + LOG_INF("#### IPV4 address assigned"); + net_log_ip_settings(iface); + on_network_ready(iface); +} + +static void net_event_if_up_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + ARG_UNUSED(cb); + ARG_UNUSED(mgmt_event); + LOG_INF("#### Network interface %s is UP", net_if_get_device(iface)->name); +} + +static void net_event_if_down_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + ARG_UNUSED(cb); + ARG_UNUSED(mgmt_event); + LOG_INF("####Network interface %s is DOWN", net_if_get_device(iface)->name); + on_network_down(iface); +} + +int net_set_ip(void) { + int rc; + + 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); + + 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, + }; + 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, + }; + + 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; + } + + if (!net_if_is_up(iface)) { + 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"); + } + } + return 0; +} + +#ifdef CONFIG_WIFI +static void schedule_reconnect(void) +{ + LOG_INF("Scheduling Wi-Fi reconnect in %d seconds.", WIFI_RECONNECT_DELAY_S); + k_timer_start(&wifi_reconnect_timer, K_SECONDS(WIFI_RECONNECT_DELAY_S), K_NO_WAIT); +} + +static void wifi_connect_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + ARG_UNUSED(mgmt_event); + ARG_UNUSED(iface); + + const int status = *(const int *)cb->info; + + if (status != 0) { + LOG_ERR("Wi-Fi connection attempt failed with status: %d", status); + return; + } + + LOG_INF("Wi-Fi connected successfully! Stopping reconnect timer."); + k_timer_stop(&wifi_reconnect_timer); + + net_set_ip(); +} + +static void wifi_disconnect_handler( + struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) +{ + ARG_UNUSED(cb); + ARG_UNUSED(mgmt_event); + + LOG_WRN("Wi-Fi disconnected!"); + net_dhcpv4_stop(iface); + on_network_down(iface); + schedule_reconnect(); +} + +int net_wifi_connect(struct net_if *iface, struct wifi_connect_req_params *cnx_params) +{ + int rc; + LOG_INF("Connecting to Wi-Fi..."); + rc = net_mgmt(NET_REQUEST_WIFI_CONNECT, + iface, + cnx_params, + sizeof(struct wifi_connect_req_params)); + if (rc != 0) { + LOG_ERR("Wi-Fi connection request failed with error: %d", rc); + } else { + LOG_INF("Wi-Fi connection request sent."); + } + return rc; +} + +int init_wifi(void) +{ + struct net_if *iface = net_if_get_default(); + if (!iface) { + LOG_ERR("Could not get network interface"); + return -ENODEV; + } + struct wifi_connect_req_params cnx_params = { - .ssid = "ItenIOT", // Ersetzen Sie dies mit Ihrer SSID + .ssid = "ItenIOT", .ssid_length = sizeof("ItenIOT") - 1, - .psk = "DasPferd", // Ersetzen Sie dies mit Ihrem Passwort + .psk = "DasPferd", .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; + static bool wifi_handlers_registered = false; + if (!wifi_handlers_registered) { + net_mgmt_init_event_callback( + &wifi_connect_cb, wifi_connect_handler, NET_EVENT_WIFI_CONNECT_RESULT); + net_mgmt_add_event_callback(&wifi_connect_cb); + net_mgmt_init_event_callback( + &wifi_disconnect_cb, wifi_disconnect_handler, NET_EVENT_WIFI_DISCONNECT_RESULT); + net_mgmt_add_event_callback(&wifi_disconnect_cb); + wifi_handlers_registered = true; } - // // 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."); + return net_wifi_connect(iface, &cnx_params); } + +static void attempt_wifi_reconnect_work_handler(struct k_work *work) +{ + LOG_INF("Reconnect timer expired. Trying to connect..."); + if (init_wifi() != 0) { + LOG_ERR("Failed to send Wi-Fi connection request, will try again."); + schedule_reconnect(); + } +} + + +static void on_reconnect_timer_expiry(struct k_timer *timer_id) +{ + k_work_submit(&reconnect_work); +} + #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); + int rc; + + rc = net_settings_init(); + if (rc < 0) { + LOG_ERR("Failed to initialize network settings: %d", rc); + return rc; + } + + static struct net_mgmt_event_callback net_mgmt_cb_ipv4_addr_add; + static struct net_mgmt_event_callback net_mgmt_cb_if_up; + static struct net_mgmt_event_callback net_mgmt_cb_if_down; + + net_mgmt_init_event_callback( + &net_mgmt_cb_ipv4_addr_add, net_event_ipv4_addr_add_handler, NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&net_mgmt_cb_ipv4_addr_add); + net_mgmt_init_event_callback(&net_mgmt_cb_if_up, net_event_if_up_handler, NET_EVENT_IF_UP); + net_mgmt_add_event_callback(&net_mgmt_cb_if_up); + net_mgmt_init_event_callback( + &net_mgmt_cb_if_down, net_event_if_down_handler, NET_EVENT_IF_DOWN); + net_mgmt_add_event_callback(&net_mgmt_cb_if_down); #ifdef CONFIG_WIFI - init_wifi(); + k_timer_init(&wifi_reconnect_timer, on_reconnect_timer_expiry, NULL); + + rc = init_wifi(); + if (rc != 0) { + LOG_ERR("Initial Wi-Fi connection request failed: %d", rc); + schedule_reconnect(); + } +#else + rc = net_set_ip(); + if (rc < 0) { + LOG_ERR("Failed to set IP: %d", rc); + return rc; + } #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; } - return 0; -} \ No newline at end of file + +static int cmd_config_show(const struct shell *shell, size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + shell_print(shell, "DHCP: %s", dhcp_enabled ? "ENABLED" : "DISABLED"); + return 0; +} + +static int cmd_config_set_dhcp(const struct shell *shell, size_t argc, char **argv) +{ + if (argc != 2) { + shell_print(shell, "Usage: config set dhcp <0|1>"); + return -EINVAL; + } + int val = atoi(argv[1]); + if (val != 0 && val != 1) { + shell_print(shell, "Value must be 0 (false) or 1 (true)"); + return -EINVAL; + } + dhcp_enabled = (val != 0); + int rc = settings_save_one("net/dhcp", &dhcp_enabled, sizeof(dhcp_enabled)); + if (rc < 0) { + shell_error(shell, "Failed to save DHCP setting: %d", rc); + return rc; + } + shell_print(shell, "DHCP set to %s and saved", dhcp_enabled ? "ENABLED" : "DISABLED"); + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_config_set, + SHELL_CMD(dhcp, NULL, "Set DHCP, 0=disabled, 1=enabled", cmd_config_set_dhcp), + SHELL_SUBCMD_SET_END +); + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_config, + SHELL_CMD(show, NULL, "Show current config", cmd_config_show), + SHELL_CMD(set, &sub_config_set, "Change config", NULL), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(config, &sub_config, "Configuration settings", NULL);