Firmware hinzugefügt

This commit is contained in:
2026-07-02 14:05:56 +02:00
parent 5677bae9de
commit 16d66e57e1
7 changed files with 799 additions and 0 deletions

36
firmware/.gitignore vendored Normal file
View File

@@ -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

9
firmware/CMakeLists.txt Normal file
View File

@@ -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})

72
firmware/README.rst Normal file
View File

@@ -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: <board to use>
:conf: <config file to use>
: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

View File

@@ -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 = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_VDD>; // Hier greift er intern VDD ab!
zephyr,resolution = <12>;
};
};

53
firmware/prj-ot-host.conf Normal file
View File

@@ -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

36
firmware/prj.conf Normal file
View File

@@ -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

573
firmware/src/main.c Normal file
View File

@@ -0,0 +1,573 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/net_ip.h>
#include <zephyr/net/openthread.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include <openthread/thread.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
// #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;
}