Firmware hinzugefügt
This commit is contained in:
36
firmware/.gitignore
vendored
Normal file
36
firmware/.gitignore
vendored
Normal 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
9
firmware/CMakeLists.txt
Normal 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
72
firmware/README.rst
Normal 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
|
||||||
20
firmware/boards/nrf52840dk_nrf52840.overlay
Normal file
20
firmware/boards/nrf52840dk_nrf52840.overlay
Normal 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
53
firmware/prj-ot-host.conf
Normal 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
36
firmware/prj.conf
Normal 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
573
firmware/src/main.c
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user