From 16d66e57e178e339a07e4bce7763b26634328368 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Thu, 2 Jul 2026 14:05:56 +0200 Subject: [PATCH] =?UTF-8?q?Firmware=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- firmware/.gitignore | 36 ++ firmware/CMakeLists.txt | 9 + firmware/README.rst | 72 +++ firmware/boards/nrf52840dk_nrf52840.overlay | 20 + firmware/prj-ot-host.conf | 53 ++ firmware/prj.conf | 36 ++ firmware/src/main.c | 573 ++++++++++++++++++++ 7 files changed, 799 insertions(+) create mode 100644 firmware/.gitignore create mode 100644 firmware/CMakeLists.txt create mode 100644 firmware/README.rst create mode 100644 firmware/boards/nrf52840dk_nrf52840.overlay create mode 100644 firmware/prj-ot-host.conf create mode 100644 firmware/prj.conf create mode 100644 firmware/src/main.c diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000..6b2cc23 --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1,36 @@ +# ========================================== +# Zephyr & West Build-Artefakte +# ========================================== +# Ignoriert den Standard-Build-Ordner und alle abgewandelten (z.B. build_nrf52840) +build*/ +# Falls du west lokal im Ordner initialisierst +.west/ + +# ========================================== +# Python (für West / nRF Connect SDK) +# ========================================== +__pycache__/ +*.py[cod] +*$py.class +venv/ +.venv/ + +# ========================================== +# IDEs & Editoren +# ========================================== +# VS Code (oft von der nRF Connect Extension generiert) +.vscode/ +# Segger Embedded Studio (falls du das mal nutzt) +*.emProject +*.emSession +*.jlink +# Andere Editoren +.idea/ +*.swp +*.swo + +# ========================================== +# OS Generiert +# ========================================== +.DS_Store +Thumbs.db diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt new file mode 100644 index 0000000..03371f7 --- /dev/null +++ b/firmware/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(poolthermo) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/firmware/README.rst b/firmware/README.rst new file mode 100644 index 0000000..906f65c --- /dev/null +++ b/firmware/README.rst @@ -0,0 +1,72 @@ +.. zephyr:code-sample:: openthread-shell + :name: OpenThread shell + :relevant-api: net_stats + + Test Thread and IEEE 802.15.4 using the OpenThread shell. + +Overview +******** + +This sample allows testing the Thread protocol and the underlying IEEE 802.15.4 drivers for various +boards using the OpenThread shell. + +Building and Running +******************** + +Verify that the board and chip you are targeting provide IEEE 802.15.4 support. + +There are configuration files for different boards and setups in the shell directory: + +- :file:`prj.conf` + Generic config file. + +- :file:`overlay-ot-rcp-host-nxp.conf` + This overlay config enables support of OpenThread RCP host running on NXP chips over IMU interface. + +Build shell application like this: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/openthread/shell + :board: + :conf: + :goals: build + :compact: + +Example building for Nordic's nRF52840 DK. + +.. zephyr-app-commands:: + :zephyr-app: samples/net/openthread/shell + :board: nrf52840dk/nrf52840 + :conf: "prj.conf" + :goals: build + :compact: + +Example building for NXP's RW612 FRDM (RCP host). + +.. zephyr-app-commands:: + :zephyr-app: samples/net/openthread/shell + :board: frdm_rw612 + :conf: "prj-ot-host.conf" + :goals: build + :compact: + +Example building for NXP's MCXW72 FRDM (host). + +.. zephyr-app-commands:: + :zephyr-app: samples/net/openthread/shell + :board: frdm_mcxw72 + :conf: "prj-ot-host.conf" + :goals: build + :compact: + + +Sample console interaction +========================== + +.. code-block:: console + + uart:~$ ot scan + | PAN | MAC Address | Ch | dBm | LQI | + +------+------------------+----+-----+-----+ + | fe09 | abcdef1234567890 | 15 | -78 | 60 | + Done diff --git a/firmware/boards/nrf52840dk_nrf52840.overlay b/firmware/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 0000000..3214d3f --- /dev/null +++ b/firmware/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,20 @@ +/ { + zephyr,user { + io-channels = <&adc 0>; + }; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1_6"; + zephyr,reference = "ADC_REF_INTERNAL"; // Intern 0.6V + zephyr,acquisition-time = ; + zephyr,input-positive = ; // Hier greift er intern VDD ab! + zephyr,resolution = <12>; + }; +}; diff --git a/firmware/prj-ot-host.conf b/firmware/prj-ot-host.conf new file mode 100644 index 0000000..1565846 --- /dev/null +++ b/firmware/prj-ot-host.conf @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable Networking and OpenThread stack +CONFIG_NETWORKING=y +CONFIG_NET_L2_OPENTHREAD=y + +# Networking and OpenThread shells +CONFIG_SHELL=y +CONFIG_NET_SHELL=y +CONFIG_OPENTHREAD_SHELL=y +CONFIG_NET_L2_IEEE802154_SHELL=y + +# CPP library +CONFIG_CPP=y + +# Shell +CONFIG_SHELL_ARGC_MAX=26 +CONFIG_SHELL_CMD_BUFF_SIZE=512 +CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH=1024 + +# Flash +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y + +# Enable OpenThread features set +CONFIG_OPENTHREAD_MANUAL_START=y +CONFIG_OPENTHREAD_THREAD_VERSION_1_3=y +CONFIG_OPENTHREAD_DHCP6_SERVER=y +CONFIG_OPENTHREAD_COMMISSIONER=y +CONFIG_OPENTHREAD_BORDER_AGENT=y +CONFIG_OPENTHREAD_BORDER_ROUTER=y +CONFIG_OPENTHREAD_UDP_FORWARD=y +CONFIG_OPENTHREAD_ENABLE_SERVICE=y +CONFIG_OPENTHREAD_EXTERNAL_HEAP=y +CONFIG_OPENTHREAD_PING_SENDER=y +CONFIG_OPENTHREAD_SLAAC=y +CONFIG_OPENTHREAD_SETTINGS_RAM=y +CONFIG_OPENTHREAD_NUM_MESSAGE_BUFFERS=256 +CONFIG_OPENTHREAD_COAP=y +CONFIG_OPENTHREAD_JOINER=y +CONFIG_OPENTHREAD_REFERENCE_DEVICE=y +CONFIG_OPENTHREAD_DHCP6_CLIENT=y +CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR=y +CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT=y +CONFIG_OPENTHREAD_DUA=y +CONFIG_OPENTHREAD_MLR=y +CONFIG_OPENTHREAD_ECDSA=y +CONFIG_OPENTHREAD_DNS_CLIENT=y +CONFIG_OPENTHREAD_DNSSD_SERVER=y +CONFIG_OPENTHREAD_SRP_CLIENT=y +CONFIG_OPENTHREAD_SRP_SERVER=y +CONFIG_OPENTHREAD_MAC_FILTER=y +CONFIG_OPENTHREAD_IP6_FRAGM=y diff --git a/firmware/prj.conf b/firmware/prj.conf new file mode 100644 index 0000000..5608e30 --- /dev/null +++ b/firmware/prj.conf @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Increased main stack size required for initialization +CONFIG_MAIN_STACK_SIZE=4096 + +# Enable Networking and OpenThread stack +CONFIG_NETWORKING=y +CONFIG_NET_UDP=y +CONFIG_POSIX_API=y +CONFIG_NET_L2_OPENTHREAD=y +CONFIG_OPENTHREAD_SLAAC=y + +# Disable manual start to allow autostart via Zephyr L2 +CONFIG_OPENTHREAD_MANUAL_START=n +CONFIG_OPENTHREAD_JOINER=y + +# Minimal End Device (MED) Role Configuration +CONFIG_OPENTHREAD_FTD=n +CONFIG_OPENTHREAD_MTD=y +CONFIG_OPENTHREAD_MTD_SED=y + +# Logging +CONFIG_LOG=y +CONFIG_NET_LOG=y + +# Networking and OpenThread shells +CONFIG_SHELL=y +CONFIG_NET_SHELL=y +CONFIG_OPENTHREAD_SHELL=y + +# HW info for Identifier +CONFIG_HWINFO=y + +# Interner Temperatursensor +CONFIG_SENSOR=y +CONFIG_ADC=y \ No newline at end of file diff --git a/firmware/src/main.c b/firmware/src/main.c new file mode 100644 index 0000000..606f28c --- /dev/null +++ b/firmware/src/main.c @@ -0,0 +1,573 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define FAST_TIMES // use seconds instead of minutes and hours for testing + +// --- Konfiguration --- +#define TARGET_IP "fd00:10:0:10:be24:11ff:fe12:6196" +#define TARGET_PORT 6969 +#define LISTEN_PORT 6969 +#define MEASURE_INTERVAL_M 5 +#define SEND_DELTA_MC 10 +#define MAX_SEND_INTERVAL_M 20 +#define BATTERY_MEASURE_INTERVAL_H 24 +#define UDP_RX_POLL_TIMEOUT_MS 100 + +#define S_TO_MS(s) ((uint64_t)(s) * 1000ULL) +#define M_TO_MS(m) ((uint64_t)(m) * 60ULL * 1000ULL) +#define H_TO_MS(h) ((uint64_t)(h) * 60ULL * 60ULL * 1000ULL) + +LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); + +enum payload_type +{ + PAYLOAD_TYPE_TEMP = 0x00, + PAYLOAD_TYPE_BATTERY = 0x01, + PAYLOAD_TYPE_CONFIG = 0x10 +}; + +// --- Payload Definition --- +struct header +{ + uint8_t proto_version; + uint8_t type; + uint8_t device_id[8]; + uint16_t seq_num; +} __attribute__((packed)); + +int32_t temp_mcelsius; +int16_t adc_buffer; + +uint16_t measure_interval_m = MEASURE_INTERVAL_M; +uint16_t send_delta_mc = SEND_DELTA_MC; +uint16_t max_send_interval_m = MAX_SEND_INTERVAL_M; +uint16_t battery_measure_interval_h = BATTERY_MEASURE_INTERVAL_H; + +int sock; +struct sockaddr_in6 dest_addr; +struct header header = {.proto_version = 1, .device_id = {0}, .seq_num = 0}; + +static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user)); +struct adc_sequence sequence = { + .buffer = &adc_buffer, + .buffer_size = sizeof(adc_buffer), + .calibrate = true, +}; + +static int pool_settings_set(const char *name, size_t len, + settings_read_cb read_cb, void *cb_arg) +{ + const char *next; + size_t name_len = settings_name_next(name, &next); + int rc; + + if (name_len == 0) + { + return -ENOENT; + } + + LOG_DBG("settings_set: name='%.*s', len=%zu", (int)name_len, name, len); + + if (strncmp(name, "meas_int", name_len) == 0) + { + rc = read_cb(cb_arg, &measure_interval_m, sizeof(measure_interval_m)); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen von meas_int: %d", rc); + return rc; + } + LOG_DBG("Gelesen: meas_int=%u", measure_interval_m); + return 0; + } + if (strncmp(name, "delta_mc", name_len) == 0) + { + rc = read_cb(cb_arg, &send_delta_mc, sizeof(send_delta_mc)); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen von delta_mc: %d", rc); + return rc; + } + LOG_DBG("Gelesen: delta_mc=%u", send_delta_mc); + return 0; + } + if (strncmp(name, "max_int", name_len) == 0) + { + rc = read_cb(cb_arg, &max_send_interval_m, sizeof(max_send_interval_m)); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen von max_int: %d", rc); + return rc; + } + LOG_DBG("Gelesen: max_int=%u", max_send_interval_m); + return 0; + } + if (strncmp(name, "batt_h", name_len) == 0) + { + rc = read_cb(cb_arg, &battery_measure_interval_h, sizeof(battery_measure_interval_h)); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen von batt_h: %d", rc); + return rc; + } + LOG_DBG("Gelesen: batt_h=%u", battery_measure_interval_h); + return 0; + } + + return -ENOENT; +} + +struct settings_handler pool_conf_handler = { + .name = "pool", + .h_set = pool_settings_set}; + +static bool thread_is_attached(void) +{ + otInstance *instance; + otDeviceRole role; + + openthread_mutex_lock(); + instance = openthread_get_default_instance(); + if (instance == NULL) + { + openthread_mutex_unlock(); + return false; + } + + role = otThreadGetDeviceRole(instance); + openthread_mutex_unlock(); + + return role == OT_DEVICE_ROLE_CHILD || + role == OT_DEVICE_ROLE_ROUTER || + role == OT_DEVICE_ROLE_LEADER; +} + +int adc_init(void) +{ + int rc; + // ADC-Sequenz konfigurieren + + if (!adc_is_ready_dt(&adc_channel)) + { + printk("Fehler: ADC-Device ist nicht bereit.\n"); + return -ENODEV; + } + + // Kanal initialisieren + rc = adc_channel_setup_dt(&adc_channel); + if (rc < 0) + { + printk("Fehler beim Setup des ADC-Kanals (%d)\n", rc); + return rc; + } + + // Sequence mit den DT-Specs füllen + rc = adc_sequence_init_dt(&adc_channel, &sequence); + if (rc < 0) + { + printk("Fehler beim Initialisieren der Sequenz (%d)\n", rc); + return rc; + } + return 0; +} + +int send_frame(uint8_t type, uint8_t *data, size_t data_len) +{ + int rc; + uint8_t buffer[sizeof(header) + data_len]; + + header.type = type; + buffer[0] = header.proto_version; + buffer[1] = header.type; + memcpy(&buffer[2], header.device_id, sizeof(header.device_id)); + sys_put_be16(header.seq_num, &buffer[10]); + memcpy(&buffer[12], data, data_len); + + rc = zsock_sendto(sock, buffer, sizeof(header) + data_len, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + + if (rc < 0) + { + LOG_ERR("Senden fehlgeschlagen: %d", rc); + } + else + { + LOG_INF("Paket gesendet | Typ: 0x%02x | Seq: %u", header.type, header.seq_num); + LOG_HEXDUMP_DBG(buffer, sizeof(header) + data_len, "Gesendete Daten:"); + } + + header.seq_num++; + return rc; +} + +int send_config(void) +{ + uint8_t send_buf[8]; + sys_put_be16(measure_interval_m, &send_buf[0]); + sys_put_be16(send_delta_mc, &send_buf[2]); + sys_put_be16(max_send_interval_m, &send_buf[4]); + sys_put_be16(battery_measure_interval_h, &send_buf[6]); + + return send_frame(PAYLOAD_TYPE_CONFIG, send_buf, sizeof(send_buf)); +} + +int recv_udp(void) +{ + uint8_t recv_buf[32]; + struct sockaddr_in6 from_addr; + socklen_t from_addr_len = sizeof(from_addr); + + // Poll-Struktur vorbereiten + struct zsock_pollfd fds[1]; + fds[0].fd = sock; + fds[0].events = ZSOCK_POLLIN; + + LOG_DBG("Warte kurz auf eingehende Konfigurationsdaten..."); + + // poll blockiert maximal UDP_RX_POLL_TIMEOUT_MS + int ret = zsock_poll(fds, 1, UDP_RX_POLL_TIMEOUT_MS); + + if (ret > 0) + { + // Daten liegen bereit! recvfrom blockiert JETZT nicht mehr + if (fds[0].revents & ZSOCK_POLLIN) + { + int len = zsock_recvfrom(sock, recv_buf, sizeof(recv_buf), 0, + (struct sockaddr *)&from_addr, &from_addr_len); + + if (len < 0) + { + LOG_ERR("recvfrom fehlgeschlagen: %d (errno: %d)", len, errno); + return len; + } + + if (len >= 12 && + recv_buf[0] == header.proto_version && + recv_buf[1] == PAYLOAD_TYPE_CONFIG) + { + /* Kurzes Config-Format ohne UUID: + * [ver(1), type(1), seq(2), meas(2), delta(2), max(2), batt(2)] + */ + uint16_t rx_seq = sys_get_be16(&recv_buf[2]); + uint16_t new_meas_int = sys_get_be16(&recv_buf[4]); + uint16_t new_delta_mc = sys_get_be16(&recv_buf[6]); + uint16_t new_max_int = sys_get_be16(&recv_buf[8]); + uint16_t new_batt_int = sys_get_be16(&recv_buf[10]); + + LOG_HEXDUMP_DBG(recv_buf, len, "Empfangene Config-Daten:"); + LOG_INF("Neue Config erhalten! Seq: %u", rx_seq); + LOG_INF(" -> Messintervall: %u min", new_meas_int); + LOG_INF(" -> Temp Delta-T: %u m°C", new_delta_mc); + LOG_INF(" -> Max Intervall: %u min", new_max_int); + LOG_INF(" -> Batt Intervall:%u h", new_batt_int); + + if (new_max_int < new_meas_int) + { + LOG_WRN("Empfangenes Max-Intervall (%u) ist kleiner als Messintervall (%u). Ignoriere Max-Intervall.", + new_max_int, new_meas_int); + new_max_int = new_meas_int; // Behalte alten Wert bei + } + + if (new_meas_int >= 0 && new_meas_int <= 60 && new_meas_int != measure_interval_m) + { + measure_interval_m = new_meas_int; + settings_save_one("pool/meas_int", &measure_interval_m, sizeof(measure_interval_m)); + LOG_INF("Messintervall auf %u min gesetzt und im Flash gespeichert.", measure_interval_m); + } + if (new_delta_mc > 0 && new_delta_mc <= 2000 && new_delta_mc != send_delta_mc) + { + send_delta_mc = new_delta_mc; + settings_save_one("pool/delta_mc", &send_delta_mc, sizeof(send_delta_mc)); + LOG_INF("Temp Delta auf %u m°C gesetzt und im Flash gespeichert.", send_delta_mc); + } + if (new_max_int >= 5 && new_max_int <= 120 && new_max_int != max_send_interval_m) + { + max_send_interval_m = new_max_int; + settings_save_one("pool/max_int", &max_send_interval_m, sizeof(max_send_interval_m)); + LOG_INF("Max Intervall auf %u min gesetzt und im Flash gespeichert.", max_send_interval_m); + } + if (new_batt_int >= 2 && new_batt_int <= 72 && new_batt_int != battery_measure_interval_h) + { + battery_measure_interval_h = new_batt_int; + settings_save_one("pool/batt_h", &battery_measure_interval_h, sizeof(battery_measure_interval_h)); + LOG_INF("Batterie Intervall auf %u h gesetzt und im Flash gespeichert.", battery_measure_interval_h); + } + LOG_INF("Settings im Flash gespeichert."); + + send_config(); // Sende die neue Config zurück, um zu bestätigen + } + else + { + LOG_DBG("UDP Paket ignoriert (len=%d, type=0x%02x)", len, + len > 1 ? recv_buf[1] : 0xff); + } + } + } + else if (ret == 0) + { + // Das ist der Timeout nach 1 Sekunde + LOG_DBG("Keine Config-Daten vom Gateway ausstehend (Timeout)."); + } + else + { + LOG_ERR("Fehler beim Pollen des Sockets: %d (errno: %d)", ret, errno); + } + return 0; +} + +int main(void) +{ + static int rc; + static struct sensor_value temp_val; + static uint32_t battery_mv; + static uint8_t send_buf[8]; + static bool was_connected = false; + static uint64_t last_temp_send_time = 0; + static int32_t last_temp_send_mc = 0; + static uint64_t last_battery_send_time = 0; + + const struct device *const temp_dev = DEVICE_DT_GET_ANY(nordic_nrf_temp); + + if (temp_dev == NULL) + { + LOG_ERR("Fehler: Kein nRF-Temperatursensor gefunden."); + return -ENODEV; + } + + if (!device_is_ready(temp_dev)) + { + LOG_ERR("Fehler: Temperatursensor-Device ist nicht bereit."); + return -ENODEV; + } + + LOG_INF("Temperatursensor (%s) erfolgreich initialisiert.", temp_dev->name); + + rc = adc_init(); + if (rc < 0) + { + printk("Fehler beim Initialisieren des ADC (%d)\n", rc); + return rc; + } + + rc = settings_subsys_init(); + if (rc < 0) + { + LOG_ERR("Settings Subsystem Init fehlgeschlagen: %d", rc); + } + else + { + rc = settings_register(&pool_conf_handler); + if (rc < 0) + { + LOG_ERR("Settings Register fehlgeschlagen: %d", rc); + } + // Lädt alle gespeicherten Werte aus dem NVS-Flash und triggert den Handler + rc = settings_load(); + if (rc < 0) + { + LOG_ERR("Settings Load fehlgeschlagen: %d", rc); + } + else + { + LOG_INF("Settings erfolgreich aus dem Flash geladen."); + } + } + + LOG_INF("Starte UDP Sensor Node..."); + + k_sleep(K_SECONDS(1)); + + LOG_INF("Warte auf OpenThread Attach..."); + for (int i = 0; i < 15; i++) + { + if (thread_is_attached()) + { + was_connected = true; + LOG_INF("OpenThread verbunden. UDP wird gestartet."); + break; + } + + k_sleep(K_SECONDS(2)); + } + + if (!was_connected) + { + LOG_WRN("Noch nicht attached, starte im Pause-Modus und warte auf Re-Attach."); + } + + sock = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + { + LOG_ERR("Fehler beim Erstellen des Sockets: %d", sock); + return -1; + } + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.sin6_family = AF_INET6; + dest_addr.sin6_port = htons(TARGET_PORT); + rc = zsock_inet_pton(AF_INET6, TARGET_IP, &dest_addr.sin6_addr); + if (rc != 1) + { + LOG_ERR("Ungueltige Ziel-IP: %s", TARGET_IP); + zsock_close(sock); + return -EINVAL; + } + + struct sockaddr_in6 local_addr; + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin6_family = AF_INET6; + local_addr.sin6_port = htons(LISTEN_PORT); // Höre genau auf Port 6969! + local_addr.sin6_addr = in6addr_any; // Akzeptiere Pakete auf allen lokalen IPs + + rc = zsock_bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)); + if (rc < 0) + { + LOG_ERR("Fehler beim Binden des Sockets (bind): %d", errno); + zsock_close(sock); + return -1; + } + LOG_INF("Socket erfolgreich an lokalen Port %d gebunden.", LISTEN_PORT); + + LOG_INF("Ziel: [%s]:%d", TARGET_IP, TARGET_PORT); + + hwinfo_get_device_id(header.device_id, sizeof(header.device_id)); + LOG_INF("Device ID: %02x%02x%02x%02x%02x%02x%02x%02x", + header.device_id[0], header.device_id[1], header.device_id[2], header.device_id[3], + header.device_id[4], header.device_id[5], header.device_id[6], header.device_id[7]); + + + #ifdef FAST_TIMES + last_temp_send_time = -S_TO_MS(measure_interval_m); + last_battery_send_time = -S_TO_MS(battery_measure_interval_h); + #else + last_temp_send_time = -M_TO_MS(measure_interval_m); + last_battery_send_time = -H_TO_MS(battery_measure_interval_h); + #endif + + send_config(); + + while (1) + { + bool connected = thread_is_attached(); + uint64_t current_time = k_uptime_get(); + + if (connected != was_connected) + { + if (connected) + { + LOG_INF("OpenThread wieder verbunden, sende weiter."); + send_config(); + } + else + { + LOG_WRN("OpenThread getrennt, Senden pausiert."); + } + + was_connected = connected; + } + + if (!connected) + { + k_sleep(K_SECONDS(2)); + continue; + } + + // Temparaturpaket (Simulation mit die temp anstatt DS18B20) + rc = sensor_sample_fetch(temp_dev); + if (rc < 0) + { + LOG_ERR("Fehler beim Abrufen der Temperaturdaten (%d)", rc); + } + else + { + rc = sensor_channel_get(temp_dev, SENSOR_CHAN_DIE_TEMP, &temp_val); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen des Temperaturkanals (%d)", rc); + k_msleep(2000); + continue; + } + + temp_mcelsius = (uint32_t)(temp_val.val1 * 1000 + temp_val.val2 / 1000); // Umrechnung in Milligrad Celsius + + LOG_DBG("Die-Temperatur: %u.%03u °C", temp_mcelsius / 1000, temp_mcelsius % 1000); + +#ifdef FAST_TIMES + if (abs(temp_mcelsius - last_temp_send_mc) >= send_delta_mc || current_time - last_temp_send_time >= S_TO_MS(max_send_interval_m)) + { +#else + if (abs(temp_mcelsius - last_temp_send_mc) >= send_delta_mc || current_time - last_temp_send_time >= M_TO_MS(max_send_interval_m)) + { +#endif + sys_put_be32(temp_mcelsius, &send_buf[0]); + rc = send_frame(PAYLOAD_TYPE_TEMP, send_buf, sizeof(temp_mcelsius)); + + if (rc >= 0) + { + recv_udp(); + last_temp_send_mc = temp_mcelsius; + last_temp_send_time = current_time; + } + } + } + +// Batteriepaket +#ifdef FAST_TIMES + if (current_time - last_battery_send_time >= S_TO_MS(battery_measure_interval_h)) +#else + if (current_time - last_battery_send_time >= H_TO_MS(battery_measure_interval_h)) +#endif + { + last_battery_send_time = current_time; + + rc = adc_read(adc_channel.dev, &sequence); + if (rc < 0) + { + LOG_ERR("Fehler beim Lesen des ADC-Kanals (%d)", rc); + break; + } + else + { + battery_mv = adc_buffer; + // Umrechnung des ADC-Werts in Millivolt (abhängig von der Referenzspannung und dem ADC-Auflösungsbereich) + rc = adc_raw_to_millivolts_dt(&adc_channel, &battery_mv); + if (rc < 0) + { + LOG_ERR("Fehler bei der mV-Konvertierung (%d)\n", rc); + } + else + { + LOG_DBG("VDD Spannung: %d mV ", battery_mv); + } + + uint16_t battery_mv_u16 = (uint16_t)battery_mv; // Konvertierung in uint16_t, falls nötig + sys_put_be16(battery_mv_u16, &send_buf[0]); + + rc = send_frame(PAYLOAD_TYPE_BATTERY, send_buf, sizeof(battery_mv_u16)); + if (rc >= 0) + { + last_battery_send_time = current_time; + } + } + } +#ifdef FAST_TIMES + k_sleep(K_SECONDS(measure_interval_m)); +#else + k_sleep(K_MINUTES(measure_interval_m)); +#endif + } + + return 0; +} \ No newline at end of file