From fb4578ac51de8bed8fb94f969dbf7569625de646 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Wed, 14 Jan 2026 15:58:45 +0100 Subject: [PATCH] Zwischenstand vor refactor --- firmware/apps/leader/prj.conf | 16 +- firmware/apps/vest/prj.conf | 17 +- firmware/libs/ble_mgmt/Kconfig | 6 +- firmware/libs/ble_mgmt/include/ble_mgmt.h | 14 + firmware/libs/ble_mgmt/src/ble_mgmt.c | 459 ++++++------------ .../lasertag_utils/include/lasertag_utils.h | 73 +-- .../libs/lasertag_utils/src/lasertag_utils.c | 109 +---- firmware/libs/thread_mgmt/Kconfig | 10 +- .../libs/thread_mgmt/include/thread_mgmt.h | 10 +- firmware/libs/thread_mgmt/src/thread_mgmt.c | 265 +++++++--- 10 files changed, 418 insertions(+), 561 deletions(-) diff --git a/firmware/apps/leader/prj.conf b/firmware/apps/leader/prj.conf index dae3e17..52577f2 100644 --- a/firmware/apps/leader/prj.conf +++ b/firmware/apps/leader/prj.conf @@ -1,16 +1,17 @@ # Console and Logging CONFIG_LOG=y + # Shell and Built-in Commands CONFIG_SHELL=y -CONFIG_KERNEL_SHELL=y -CONFIG_DEVICE_SHELL=y -CONFIG_REBOOT=y +CONFIG_DEVICE_SHELL=n +CONFIG_DEVMEM_SHELL=n -# --- STACK SIZE UPDATES (Fixes the Hard Fault) --- + +# --- STACK SIZE UPDATES (Fixes the MPU/Stack Fault) --- CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 -CONFIG_BT_RX_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_BT_RX_STACK_SIZE=4096 # Storage and Settings (NVS) CONFIG_FLASH=y @@ -39,9 +40,12 @@ CONFIG_BT_L2CAP_TX_MTU=252 CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_BUF_ACL_RX_SIZE=251 CONFIG_BT_ATT_PREPARE_COUNT=5 +CONFIG_BT_LOG_LEVEL_WRN=y # Enable Lasertag Shared Modules CONFIG_LASERTAG_UTILS=y CONFIG_THREAD_MGMT=y +CONFIG_THREAD_MGMT_LOG_LEVEL_DBG=y CONFIG_BLE_MGMT=y +CONFIG_BLE_MGMT_LOG_LEVEL_DBG=y CONFIG_GAME_MGMT=y \ No newline at end of file diff --git a/firmware/apps/vest/prj.conf b/firmware/apps/vest/prj.conf index bea73c3..52577f2 100644 --- a/firmware/apps/vest/prj.conf +++ b/firmware/apps/vest/prj.conf @@ -1,16 +1,17 @@ # Console and Logging CONFIG_LOG=y + # Shell and Built-in Commands CONFIG_SHELL=y -CONFIG_KERNEL_SHELL=y -CONFIG_DEVICE_SHELL=y -CONFIG_REBOOT=y +CONFIG_DEVICE_SHELL=n +CONFIG_DEVMEM_SHELL=n -# --- STACK SIZE UPDATES (Fixes the Hard Fault) --- + +# --- STACK SIZE UPDATES (Fixes the MPU/Stack Fault) --- CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 -CONFIG_BT_RX_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_BT_RX_STACK_SIZE=4096 # Storage and Settings (NVS) CONFIG_FLASH=y @@ -24,6 +25,7 @@ CONFIG_NET_L2_OPENTHREAD=y CONFIG_OPENTHREAD=y CONFIG_OPENTHREAD_FTD=y CONFIG_OPENTHREAD_SHELL=y +CONFIG_OPENTHREAD_DEFAULT_TX_POWER=8 # --- CoAP & UDP Features --- CONFIG_OPENTHREAD_COAP=y @@ -38,9 +40,12 @@ CONFIG_BT_L2CAP_TX_MTU=252 CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_BUF_ACL_RX_SIZE=251 CONFIG_BT_ATT_PREPARE_COUNT=5 +CONFIG_BT_LOG_LEVEL_WRN=y # Enable Lasertag Shared Modules CONFIG_LASERTAG_UTILS=y CONFIG_THREAD_MGMT=y +CONFIG_THREAD_MGMT_LOG_LEVEL_DBG=y CONFIG_BLE_MGMT=y +CONFIG_BLE_MGMT_LOG_LEVEL_DBG=y CONFIG_GAME_MGMT=y \ No newline at end of file diff --git a/firmware/libs/ble_mgmt/Kconfig b/firmware/libs/ble_mgmt/Kconfig index 96205b0..903a28e 100644 --- a/firmware/libs/ble_mgmt/Kconfig +++ b/firmware/libs/ble_mgmt/Kconfig @@ -5,9 +5,9 @@ menuconfig BLE_MGMT Library for BLE provisioning of the lasertag device. if BLE_MGMT - config BLE_MGMT_LOG_LEVEL - int "BLE Management Log Level" - default 3 + module = BLE_MGMT + module-str = ble_mgmt + source "subsys/logging/Kconfig.template.log_config" config BLE_MGMT_CAN_BE_GAME_LEADER bool "Can be game leader" diff --git a/firmware/libs/ble_mgmt/include/ble_mgmt.h b/firmware/libs/ble_mgmt/include/ble_mgmt.h index 5ec9197..19decd2 100644 --- a/firmware/libs/ble_mgmt/include/ble_mgmt.h +++ b/firmware/libs/ble_mgmt/include/ble_mgmt.h @@ -15,6 +15,20 @@ #define LT_TYPE_VEST 0x03 #define LT_TYPE_BEACON 0x04 +/** + * @brief Device configuration payload structure for BLE management. + */ +typedef struct __packed { + uint8_t system_state; /* Offset 0 */ + uint64_t game_id; /* Offset 1 */ + uint16_t pan_id; /* Offset 9 */ + uint8_t channel; /* Offset 11 */ + uint8_t ext_pan_id[8]; /* Offset 12 */ + uint8_t network_key[16]; /* Offset 20 */ + char network_name[17]; /* Offset 36 */ + char node_name[33]; /* Offset 53 */ +} device_config_payload_t; + /** * @brief Initialize Bluetooth and prepare services. * diff --git a/firmware/libs/ble_mgmt/src/ble_mgmt.c b/firmware/libs/ble_mgmt/src/ble_mgmt.c index a57f06f..d158838 100644 --- a/firmware/libs/ble_mgmt/src/ble_mgmt.c +++ b/firmware/libs/ble_mgmt/src/ble_mgmt.c @@ -1,12 +1,7 @@ /** * BLE Management Module (ble_mgmt.c) - * - * Handles Bluetooth Low Energy (BLE) setup, advertising, GATT services, - * and connection management for the Lasertag device. - * - * Services provided: - * - Provisioning Service (0x10xx): Device configuration and Thread mesh setup - * - Game Service (0x20xx): Game-related commands and logging + * * Structural Fix: Offloading heavy NVS and Thread operations to a workqueue + * to prevent stack overflows in the BT RX thread. */ #include @@ -25,61 +20,160 @@ LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL); -/* ============================================================================ - UUID Definitions - ============================================================================ - Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cXXXX - Service and characteristic IDs use the last two bytes (XXXX) - ========================================================================== */ +/* UUID Definitions */ +#define BT_UUID_LT_PROV_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1000)) +#define BT_UUID_LT_PROV_NAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1001)) +#define BT_UUID_LT_PROV_TYPE_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1008)) +#define BT_UUID_LT_PROV_CONFIG_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c100c)) -#define LT_UUID_BASE_VAL \ - BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c0000) - - -/* PROVISIONING SERVICE (0x10xx): Device configuration & Thread mesh setup */ -#define BT_UUID_LT_PROV_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1000)) - -/* Provisioning characteristics */ -#define BT_UUID_LT_PROV_NAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1001)) -#define BT_UUID_LT_PROV_TYPE_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1008)) -#define BT_UUID_LT_PROV_CONFIG_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c100c)) +/* Global state and Workqueue structures */ +static uint8_t device_role = 0; +static uint8_t adv_enabled = 0; +static struct k_work_delayable adv_restart_work; +/* Buffers for asynchronous config application */ +static device_config_payload_t pending_config; +static struct k_work config_apply_work; /* ============================================================================ - Data Structures + Workqueue Handlers + ============================================================================ */ +static void config_apply_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + LOG_DBG("conf rcv, name: " BOLD("%s") ", state: " BOLD("%d") ", game-id: " BOLD("0x%llx") ", net name: " BOLD("%s") ", channel: " BOLD("%u") ", pan: " BOLD("0x%04X"), + pending_config.node_name, + pending_config.system_state, + pending_config.game_id, + pending_config.network_name, + pending_config.channel, + pending_config.pan_id); + LOG_HEXDUMP_DBG(pending_config.ext_pan_id, 8, "ext pan id"); + LOG_HEXDUMP_DBG(pending_config.network_key, 16, "network key"); + + if (pending_config.system_state != SYS_STATE_NO_CHANGE) { + game_mgmt_set_state((sys_state_t)pending_config.system_state); + } + if (pending_config.game_id != 0) { + game_mgmt_set_game_id(pending_config.game_id); + } + + if (pending_config.node_name[0] != '\0') { + lasertag_set_device_name(pending_config.node_name, strlen(pending_config.node_name)); + bt_set_name(lasertag_get_device_name()); + } + + if (pending_config.channel != 0) { + thread_mgmt_restart_thread_stack(&pending_config, false); + } +} + +static void adv_restart_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + LOG_DBG("Restarting BLE advertising via System Workqueue..."); + if (adv_enabled == 0) { + int err = ble_mgmt_adv_start(); + if (err) { + LOG_ERR("Fehler beim Neustart des Advertisings (err %d)", err); + } + } +} +/* ============================================================================ + GATT Handlers ============================================================================ */ -/** - * Device configuration payload. - * Packed structure for transmitting full device configuration via BLE. - * Total size: 86 bytes - */ -struct device_config_payload { - uint8_t system_state; /* Offset 0 */ - uint64_t game_id; /* Offset 1 */ - uint16_t pan_id; /* Offset 9 */ - uint8_t channel; /* Offset 11 */ - uint8_t ext_pan_id[8]; /* Offset 12 */ - uint8_t network_key[16]; /* Offset 20 */ - char network_name[17]; /* Offset 36 (16 chars + \0) */ - char node_name[33]; /* Offset 53 (32 chars + \0) */ -} __packed; +static ssize_t read_leader_config(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + device_config_payload_t payload; + memset(&payload, 0, sizeof(payload)); + payload.system_state = (uint8_t)game_mgmt_get_state(); + payload.game_id = game_mgmt_get_game_id(); + payload.pan_id = thread_mgmt_get_pan_id(); + payload.channel = thread_mgmt_get_channel(); + thread_mgmt_get_ext_pan_id(payload.ext_pan_id); + thread_mgmt_get_network_key(payload.network_key); + thread_mgmt_get_network_name(payload.network_name, sizeof(payload.network_name)); + strncpy(payload.node_name, lasertag_get_device_name(), 32); + + LOG_DBG("conf snd, name: " BOLD("%s") ", state: " BOLD("%d") ", game-id: " BOLD("0x%llx") ", net name: " BOLD("%s") ", channel: " BOLD("%u") ", pan: " BOLD("0x%04X"), + payload.node_name, + payload.system_state, + payload.game_id, + payload.network_name, + payload.channel, + payload.pan_id); + LOG_HEXDUMP_DBG(payload.ext_pan_id, 8, "ext pan id"); + LOG_HEXDUMP_DBG(payload.network_key, 16, "network key"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &payload, sizeof(payload)); +} + +static ssize_t write_leader_config(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) +{ + if (len != sizeof(device_config_payload_t)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + /* Copy data to buffer and delegate to system workqueue */ + memcpy(&pending_config, buf, sizeof(pending_config)); + k_work_submit(&config_apply_work); + + LOG_DBG("Config write received, delegated to workqueue."); + return len; +} + +/* Simple value handlers for name and type */ +static ssize_t read_simple_val(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + const char *val_ptr = NULL; + size_t val_len = 0; + + if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_TYPE_CHAR) == 0) { + val_ptr = (char *)&device_role; + val_len = sizeof(device_role); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NAME_CHAR) == 0) { + val_ptr = lasertag_get_device_name(); + val_len = strlen(val_ptr); + } + return bt_gatt_attr_read(conn, attr, buf, len, offset, val_ptr, val_len); +} + +static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) +{ + int rc = lasertag_set_device_name(buf, len); + if (rc == 0) bt_set_name(lasertag_get_device_name()); + return rc ? BT_GATT_ERR(BT_ATT_ERR_UNLIKELY) : len; +} /* ============================================================================ - Global State Variables + Service Definition ============================================================================ */ -static uint8_t device_role = 0; /* Store device type for provisioning */ -static uint8_t adv_enabled = 0; /* Track advertising state */ -static struct k_work_delayable adv_restart_work; /* Delayed advertising restart */ +BT_GATT_SERVICE_DEFINE(provisioning_svc, + BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_PROV_SERVICE), + BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_NAME_CHAR, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_simple_val, write_name, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_TYPE_CHAR, + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, + read_simple_val, NULL, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_CONFIG_CHAR, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_leader_config, write_leader_config, NULL), +); /* ============================================================================ - Advertising Data + Advertising & Management ============================================================================ */ -/* Manufacturer data: last byte contains device role type */ static uint8_t mfg_data[] = { 0xff, 0xff, 0x00 }; - -/* Advertising data array with UUID and flags */ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID128_ALL, @@ -88,277 +182,32 @@ static const struct bt_data ad[] = { BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), }; - -/* ============================================================================ - GATT Callback Handlers - - These functions handle read/write operations on GATT characteristics. - They validate requests and interface with device configuration APIs. - ============================================================================ */ - -/** - * Read handler for provisioning characteristics. - * Supports reading: device type, name, PAN ID, channel, extended PAN ID, - * network key, and network name. - */ -static ssize_t read_lasertag_val(struct bt_conn *conn, const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - const char *val_ptr = NULL; - size_t val_len = 0; - - if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_TYPE_CHAR) == 0) - { - val_ptr = (char *)&device_role; - val_len = sizeof(device_role); - } - else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NAME_CHAR) == 0) - { - val_ptr = lasertag_get_device_name(); - val_len = strlen(val_ptr); - } - - return bt_gatt_attr_read(conn, attr, buf, len, offset, val_ptr, val_len); -} - -/** - * Write handler for provisioning characteristics. - * Validates write length and updates device configuration via lasertag_utils APIs. - * Also updates Bluetooth advertised name when device name is changed. - */ -static ssize_t write_lasertag_val(struct bt_conn *conn, const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, uint8_t flags) -{ - int rc = 0; - if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NAME_CHAR) == 0) - { - rc = lasertag_set_device_name(buf, len); - if (rc == 0 ) { - bt_set_name(lasertag_get_device_name()); - } - } - - if (rc) - return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); - return len; -} - -/** - * Read handler for the full leader configuration. - * Returns a packed structure containing all device configuration in a single read. - */ -static ssize_t read_leader_config(struct bt_conn *conn, const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - struct device_config_payload payload; - memset(&payload, 0, sizeof(payload)); - - payload.system_state = game_mgmt_get_state(); - payload.game_id = game_mgmt_get_game_id(); - payload.pan_id = lasertag_get_thread_pan_id(); - payload.channel = lasertag_get_thread_channel(); - - memcpy(payload.ext_pan_id, lasertag_get_thread_ext_pan_id(), 8); - memcpy(payload.network_key, lasertag_get_thread_network_key(), 16); - - /* Ensure null termination and copy strings */ - strncpy(payload.network_name, lasertag_get_thread_network_name(), 16); - strncpy(payload.node_name, lasertag_get_device_name(), 32); - - return bt_gatt_attr_read(conn, attr, buf, len, offset, (const void *)&payload, sizeof(payload)); -} - -/** - * Write handler for the full leader configuration. - * Accepts a packed structure and applies all configuration at once. - */ -static ssize_t write_leader_config(struct bt_conn *conn, const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, uint8_t flags) -{ - if (len != sizeof(struct device_config_payload)) - { - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); - } - - const struct device_config_payload *payload = (const struct device_config_payload *)buf; - - /* Apply RAM values */ - if (payload->system_state != SYS_STATE_NO_CHANGE) - { - game_mgmt_set_state(payload->system_state); - } - if (payload->game_id != 0) - { - game_mgmt_set_game_id(payload->game_id); - } - - /* Apply NVS values via utils */ - if (payload->node_name[0] != '\0') // Only update if a name is provided - { - lasertag_set_device_name((const void *)payload->node_name, strlen(payload->node_name)); - bt_set_name(lasertag_get_device_name()); - } - - if (payload->channel != 0) - { - lasertag_set_thread_pan_id(payload->pan_id); - lasertag_set_thread_channel(payload->channel); - lasertag_set_thread_ext_pan_id(payload->ext_pan_id); - LOG_HEXDUMP_INF(payload->network_key, 16, "Setting new Thread network key:"); - lasertag_set_thread_network_key(payload->network_key); - if (payload->network_name[0] != '\0') // Only update if a name is provided - { - lasertag_set_thread_network_name(payload->network_name, strlen(payload->network_name)); - } - thread_mgmt_restart_thread_stack(false); - } - - LOG_INF("Device config processed. Only changed values were applied."); - return len; -} - -/* ============================================================================ - GATT Service Definition - - Defines the Provisioning Service with all characteristics and callbacks. - ============================================================================ */ -BT_GATT_SERVICE_DEFINE(provisioning_svc, - BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_PROV_SERVICE), - - /* Device name (readable and writable) */ - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_NAME_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - - /* Device type / role (read-only) */ - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_TYPE_CHAR, - BT_GATT_CHRC_READ, - BT_GATT_PERM_READ, - read_lasertag_val, NULL, NULL), - - /* Thread PAN ID (read/write) - DISABLED */ - /* - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_PANID_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - */ - - /* Thread channel (read/write) - DISABLED */ - /* - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_CHAN_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - */ - - /* Extended PAN ID (read/write) - DISABLED */ - /* - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_EXTPAN_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - */ - - /* Network key (read/write) - DISABLED */ - /* - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_NETKEY_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - */ - - /* Thread network name (read/write) - DISABLED */ - /* - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_NETNAME_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_lasertag_val, write_lasertag_val, NULL), - */ - - /* Full leader configuration (packed struct) */ - BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_CONFIG_CHAR, - BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_leader_config, write_leader_config, NULL), ); - - -/* ============================================================================ - Internal Helper Functions - ============================================================================ */ - -/** - * Work handler for delayed advertising restart. - * Called when a device disconnects to resume advertising after a brief delay. - */ -static void adv_restart_work_handler(struct k_work *work) -{ - if (adv_enabled == 0) - { - int err = ble_mgmt_adv_start(); - if (err) { - LOG_ERR("Fehler beim verzögerten Neustarten des Advertisings (err %d)", err); - } else { - LOG_INF("Advertising nach Verzögerung erfolgreich neu gestartet"); - } - } -} - -/* ============================================================================ - Public Initialization & Management Functions - ============================================================================ */ - -/** - * Initialize the BLE module. - * Enables Bluetooth and sets up the device role for advertising. - * - * @param device_type The device type/role (leader, weapon, vest, beacon) - * @return 0 on success, negative error code on failure - */ int ble_mgmt_init(uint8_t device_type) { device_role = device_type; + /* Initialize work structures */ k_work_init_delayable(&adv_restart_work, adv_restart_work_handler); + k_work_init(&config_apply_work, config_apply_work_handler); int err = bt_enable(NULL); - if (err) - return err; - LOG_INF("Bluetooth initialized"); + if (err) return err; + LOG_DBG("Bluetooth initialized successfully."); return 0; } -/** - * Start BLE advertising. - * Advertises device name and type, configures fast advertising intervals. - * - * @return 0 on success, negative error code on failure - */ int ble_mgmt_adv_start(void) { - const char set_device_role = device_role; - mfg_data[2] = set_device_role; // Update device role in advertising data - + mfg_data[2] = device_role; const char *name = lasertag_get_device_name(); bt_set_name(name); - - struct bt_data dynamic_sd[] = { - BT_DATA(BT_DATA_NAME_COMPLETE, name, strlen(name)), - }; - - struct bt_le_adv_param adv_param = { - .id = BT_ID_DEFAULT, + struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, name, strlen(name)) }; + struct bt_le_adv_param param = { .options = (BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_SCANNABLE), .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, .interval_max = BT_GAP_ADV_FAST_INT_MAX_2, }; - - int err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), dynamic_sd, ARRAY_SIZE(dynamic_sd)); - if (!err) - { - LOG_INF("Advertising started as: %s, type: %d", name, device_role); - adv_enabled = 1; - } + int err = bt_le_adv_start(¶m, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + if (!err) adv_enabled = 1; return err; } @@ -372,7 +221,7 @@ int ble_mgmt_adv_stop(void) int err = bt_le_adv_stop(); if (!err) { - LOG_INF("Advertising stopped"); + LOG_DBG("Advertising stopped"); adv_enabled = 0; } return err; @@ -391,7 +240,7 @@ static void connected(struct bt_conn *conn, uint8_t err) if (err) { LOG_ERR("Verbindung fehlgeschlagen (err %u)", err); } else { - LOG_INF("Host verbunden"); + LOG_DBG("Host verbunden"); adv_enabled = 0; } } @@ -402,7 +251,7 @@ static void connected(struct bt_conn *conn, uint8_t err) */ static void disconnected(struct bt_conn *conn, uint8_t reason) { - LOG_INF("Verbindung getrennt (Grund %u)", reason); + LOG_DBG("Verbindung getrennt (Grund %u)", reason); k_work_reschedule(&adv_restart_work, K_MSEC(100)); } diff --git a/firmware/libs/lasertag_utils/include/lasertag_utils.h b/firmware/libs/lasertag_utils/include/lasertag_utils.h index 789eae3..76cc90a 100644 --- a/firmware/libs/lasertag_utils/include/lasertag_utils.h +++ b/firmware/libs/lasertag_utils/include/lasertag_utils.h @@ -3,6 +3,13 @@ #include +// ANSI Escape Codes für die Formatierung +#define ANSI_BOLD "\x1b[1m" +#define ANSI_RESET "\x1b[0m" + +// Das BOLD-Makro +#define BOLD(s) ANSI_BOLD s ANSI_RESET + /** * @file lasertag_utils.h * @brief Common utility functions for the lasertag system. @@ -19,36 +26,6 @@ void lasertag_utils_init(void); */ const char* lasertag_get_device_name(void); -/** - * @brief Get the configured Thread PAN ID. - * @return 16-bit PAN ID. - */ -uint16_t lasertag_get_thread_pan_id(void); - -/** - * @brief Get the configured Thread Network Name. - * @return Pointer to the network name string. - */ -const char* lasertag_get_thread_network_name(void); - -/** - * @brief Get the configured Thread Channel. - * @return 8-bit channel (usually 11-26). - */ -uint8_t lasertag_get_thread_channel(void); - -/** - * @brief Get the configured Thread Extended PAN ID. - * @return Pointer to the 8-byte extended PAN ID. - */ -const uint8_t* lasertag_get_thread_ext_pan_id(void); - -/** - * @brief Get the configured Thread Network Key. - * @return Pointer to the 16-byte network key. - */ -const uint8_t* lasertag_get_thread_network_key(void); - /** * @brief Set the device name. * @param name Pointer to the name string. @@ -57,40 +34,4 @@ const uint8_t* lasertag_get_thread_network_key(void); */ int lasertag_set_device_name(const char *name, size_t len); -/** - * @brief Set the Thread PAN ID. - * @param pan_id 16-bit PAN ID. - * @return 0 on success, negative error code otherwise. - */ -int lasertag_set_thread_pan_id(uint16_t pan_id); - -/** - * @brief Set the Thread Network Name. - * @param name Pointer to the network name string. - * @param len Length of the name. - * @return 0 on success, negative error code otherwise. - */ -int lasertag_set_thread_network_name(const char *name, size_t len); - -/** - * @brief Set the Thread Channel. - * @param channel 8-bit channel (usually 11-26). - * @return 0 on success, negative error code otherwise. - */ -int lasertag_set_thread_channel(uint8_t channel); - -/** - * @brief Set the Thread Extended PAN ID. - * @param ext_id Pointer to the 8-byte extended PAN ID. - * @return 0 on success, negative error code otherwise. - */ -int lasertag_set_thread_ext_pan_id(const uint8_t *ext_id); - -/** - * @brief Set the Thread Network Key. - * @param key Pointer to the 16-byte network key. - * @return 0 on success, negative error code otherwise. - */ -int lasertag_set_thread_network_key(const uint8_t *key); - #endif /* LASERTAG_UTILS_H */ \ No newline at end of file diff --git a/firmware/libs/lasertag_utils/src/lasertag_utils.c b/firmware/libs/lasertag_utils/src/lasertag_utils.c index 1dd2a2e..f36a563 100644 --- a/firmware/libs/lasertag_utils/src/lasertag_utils.c +++ b/firmware/libs/lasertag_utils/src/lasertag_utils.c @@ -12,14 +12,7 @@ LOG_MODULE_REGISTER(lasertag_utils, CONFIG_LASERTAG_UTILS_LOG_LEVEL); -static char device_name[32] = "UnknownDevice"; -static uint16_t thread_pan_id = 0xabcd; -static char thread_network_name[17] = "OpenThread-nRF"; -static uint8_t thread_channel = 15; -static uint8_t thread_ext_pan_id[8] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe}; -static uint8_t thread_network_key[16] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; +static char device_name[32] = "Eriks Lasertag Device"; /* --- Settings Handler --- */ @@ -37,33 +30,6 @@ static int lasertag_settings_set(const char *name, size_t len, settings_read_cb return 0; } } - if (settings_name_steq(name, "pan_id", &next) && !next) - { - return read_cb(cb_arg, &thread_pan_id, sizeof(thread_pan_id)) >= 0 ? 0 : -EIO; - } - if (settings_name_steq(name, "net_name", &next) && !next) - { - if (len > sizeof(thread_network_name) - 1) - return -EINVAL; - ssize_t rc = read_cb(cb_arg, thread_network_name, len); - if (rc >= 0) - { - thread_network_name[rc] = '\0'; - return 0; - } - } - if (settings_name_steq(name, "channel", &next) && !next) - { - return read_cb(cb_arg, &thread_channel, sizeof(thread_channel)) >= 0 ? 0 : -EIO; - } - if (settings_name_steq(name, "ext_pan_id", &next) && !next) - { - return read_cb(cb_arg, thread_ext_pan_id, sizeof(thread_ext_pan_id)) >= 0 ? 0 : -EIO; - } - if (settings_name_steq(name, "net_key", &next) && !next) - { - return read_cb(cb_arg, thread_network_key, sizeof(thread_network_key)) >= 0 ? 0 : -EIO; - } return -ENOENT; } @@ -71,27 +37,13 @@ struct settings_handler lasertag_conf = {.name = "lasertag", .h_set = lasertag_s void lasertag_utils_init(void) { - LOG_INF("=========================================="); - LOG_INF("Lasertag System - Common Lib v0.0.1"); - settings_subsys_init(); settings_register(&lasertag_conf); settings_load(); - - LOG_INF("Device Name : %s", device_name); - LOG_INF("Thread PAN : 0x%04x", thread_pan_id); - LOG_INF("Thread Name : %s", thread_network_name); - LOG_INF("Thread Chan : %d", thread_channel); - LOG_INF("=========================================="); } /* Getters */ const char *lasertag_get_device_name(void) { return device_name; } -uint16_t lasertag_get_thread_pan_id(void) { return thread_pan_id; } -const char *lasertag_get_thread_network_name(void) { return thread_network_name; } -uint8_t lasertag_get_thread_channel(void) { return thread_channel; } -const uint8_t *lasertag_get_thread_ext_pan_id(void) { return thread_ext_pan_id; } -const uint8_t *lasertag_get_thread_network_key(void) { return thread_network_key; } /* Setters */ int lasertag_set_device_name(const char *name, size_t len) @@ -102,49 +54,10 @@ int lasertag_set_device_name(const char *name, size_t len) device_name[len] = '\0'; return settings_save_one("lasertag/name", device_name, len); } -int lasertag_set_thread_pan_id(uint16_t pan_id) -{ - thread_pan_id = pan_id; - return settings_save_one("lasertag/pan_id", &thread_pan_id, sizeof(thread_pan_id)); -} -int lasertag_set_thread_network_name(const char *name, size_t len) -{ - if (len >= sizeof(thread_network_name)) - len = sizeof(thread_network_name) - 1; - memcpy(thread_network_name, name, len); - thread_network_name[len] = '\0'; - return settings_save_one("lasertag/net_name", thread_network_name, len); -} -int lasertag_set_thread_channel(uint8_t channel) -{ - thread_channel = channel; - return settings_save_one("lasertag/channel", &thread_channel, sizeof(thread_channel)); -} -int lasertag_set_thread_ext_pan_id(const uint8_t *ext_id) -{ - memcpy(thread_ext_pan_id, ext_id, 8); - return settings_save_one("lasertag/ext_pan_id", thread_ext_pan_id, 8); -} -int lasertag_set_thread_network_key(const uint8_t *key) -{ - memcpy(thread_network_key, key, 16); - return settings_save_one("lasertag/net_key", thread_network_key, 16); -} /* --- Shell Commands --- */ #if CONFIG_LASERTAG_SHELL - -static int lasertag_hex2bin(const char *hex, uint8_t *bin, size_t bin_len) -{ - for (size_t i = 0; i < bin_len; i++) - { - char buf[3] = {hex[i * 2], hex[i * 2 + 1], '\0'}; - bin[i] = (uint8_t)strtoul(buf, NULL, 16); - } - return 0; -} - static int cmd_reboot(const struct shell *sh, size_t argc, char **argv) { shell_print(sh, "Rebooting..."); @@ -159,25 +72,6 @@ static int cmd_name_set(const struct shell *sh, size_t argc, char **argv) return 0; } -static int cmd_thread_set_panid(const struct shell *sh, size_t argc, char **argv) -{ - uint16_t pan = (uint16_t)strtoul(argv[1], NULL, 0); - lasertag_set_thread_pan_id(pan); - return 0; -} - -static int cmd_thread_set_chan(const struct shell *sh, size_t argc, char **argv) -{ - uint8_t chan = (uint8_t)strtoul(argv[1], NULL, 10); - lasertag_set_thread_channel(chan); - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(sub_thread, - SHELL_CMD_ARG(panid, NULL, "Set PAN ID", cmd_thread_set_panid, 2, 0), - SHELL_CMD_ARG(chan, NULL, "Set channel", cmd_thread_set_chan, 2, 0), - SHELL_SUBCMD_SET_END); - static int cmd_ble_start(const struct shell *sh, size_t argc, char **argv) { return ble_mgmt_adv_start(); @@ -189,7 +83,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_ble, SHELL_STATIC_SUBCMD_SET_CREATE(sub_lasertag, SHELL_CMD_ARG(name, NULL, "Set name", cmd_name_set, 2, 0), - SHELL_CMD(thread, &sub_thread, "Thread configuration", NULL), SHELL_CMD(ble, &sub_ble, "BLE Management", NULL), SHELL_CMD(reboot, NULL, "Reboot", cmd_reboot), SHELL_SUBCMD_SET_END); diff --git a/firmware/libs/thread_mgmt/Kconfig b/firmware/libs/thread_mgmt/Kconfig index 4f06adf..0cb7dbd 100644 --- a/firmware/libs/thread_mgmt/Kconfig +++ b/firmware/libs/thread_mgmt/Kconfig @@ -6,9 +6,7 @@ menuconfig THREAD_MGMT Library for initializing and managing the OpenThread stack. if THREAD_MGMT - config THREAD_MGMT_LOG_LEVEL - int "Thread Management Log Level" - default 3 - help - Set the verbosity of the thread management library. -endif \ No newline at end of file + module = THREAD_MGMT + module-str = thread_mgmt + source "subsys/logging/Kconfig.template.log_config" +endif # THREAD_MGMT \ No newline at end of file diff --git a/firmware/libs/thread_mgmt/include/thread_mgmt.h b/firmware/libs/thread_mgmt/include/thread_mgmt.h index 36d768f..31577f8 100644 --- a/firmware/libs/thread_mgmt/include/thread_mgmt.h +++ b/firmware/libs/thread_mgmt/include/thread_mgmt.h @@ -2,6 +2,7 @@ #define THREAD_MGMT_H #include +#include /** * @brief Initializes the OpenThread stack. @@ -12,5 +13,12 @@ int thread_mgmt_init(void); * @brief Restarts the Thread stack. * @param force If true, forces a full restart even if dataset is unchanged. */ -void thread_mgmt_restart_thread_stack(bool force); +void thread_mgmt_restart_thread_stack(device_config_payload_t *pending_config, bool force); + +uint16_t thread_mgmt_get_pan_id(void); +uint8_t thread_mgmt_get_channel(void); +void thread_mgmt_get_ext_pan_id(uint8_t *dest_8byte); +void thread_mgmt_get_network_key(uint8_t *dest_16byte); +void thread_mgmt_get_network_name(char *dest_str, size_t max_len); + #endif \ No newline at end of file diff --git a/firmware/libs/thread_mgmt/src/thread_mgmt.c b/firmware/libs/thread_mgmt/src/thread_mgmt.c index 3e52c7b..8382ef6 100644 --- a/firmware/libs/thread_mgmt/src/thread_mgmt.c +++ b/firmware/libs/thread_mgmt/src/thread_mgmt.c @@ -1,113 +1,258 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include #include #include +#include +#include +#include LOG_MODULE_REGISTER(thread_mgmt, CONFIG_THREAD_MGMT_LOG_LEVEL); -#define UDP_PORT 1234 -#define MAX_DISCOVERED_NODES 10 +#if (CONFIG_THREAD_MGMT_LOG_LEVEL >= LOG_LEVEL_DBG) +static void thread_mgmt_state_notify_callback(otChangedFlags aFlags, void *aContext) +{ + ARG_UNUSED(aContext); + if (aFlags & OT_CHANGED_THREAD_ROLE) + { + struct otInstance *instance = openthread_get_default_instance(); + otDeviceRole role = otThreadGetDeviceRole(instance); + LOG_DBG("Thread Role changed: " BOLD("%s"), otThreadDeviceRoleToString(role)); + } +} + +struct openthread_state_changed_callback thread_state_callback = { + .otCallback = thread_mgmt_state_notify_callback, + .user_data = NULL, +}; + +void thread_mgmt_print_dataset(const otOperationalDataset *dataset) +{ + if (dataset == NULL) + { + return; + } + + // Network Name + char net_name[OT_NETWORK_NAME_MAX_SIZE + 1] = {0}; + memcpy(net_name, dataset->mNetworkName.m8, sizeof(dataset->mNetworkName.m8)); + + // Hex-Konvertierungen mit bin2hex + char ext_pan_id_str[17]; + bin2hex(dataset->mExtendedPanId.m8, 8, ext_pan_id_str, sizeof(ext_pan_id_str)); + + char net_key_str[33]; + bin2hex(dataset->mNetworkKey.m8, 16, net_key_str, sizeof(net_key_str)); + LOG_DBG(" Timestamp: " BOLD("%llu"), dataset->mActiveTimestamp.mSeconds); + LOG_DBG(" Network Name: " BOLD("%s"), net_name); + LOG_DBG(" PAN ID: " BOLD("0x%04X"), dataset->mPanId); + LOG_DBG(" Channel: " BOLD("%u"), dataset->mChannel); + LOG_DBG(" Extended PAN ID: " BOLD("%s"), ext_pan_id_str); + LOG_DBG(" Network Key: " BOLD("%s"), net_key_str); +} +#endif int thread_mgmt_init(void) { struct otInstance *instance = openthread_get_default_instance(); otOperationalDataset dataset; - if (!instance) return -ENODEV; + if (!instance) + return -ENODEV; + +#if (CONFIG_THREAD_MGMT_LOG_LEVEL >= LOG_LEVEL_DBG) + openthread_state_changed_callback_register(&thread_state_callback); +#endif - /* Dataset Setup */ memset(&dataset, 0, sizeof(otOperationalDataset)); - dataset.mActiveTimestamp.mSeconds = 1; - dataset.mComponents.mIsActiveTimestampPresent = true; - - const char *net_name = lasertag_get_thread_network_name(); - memcpy(dataset.mNetworkName.m8, net_name, strlen(net_name)); - dataset.mComponents.mIsNetworkNamePresent = true; - dataset.mPanId = lasertag_get_thread_pan_id(); - dataset.mComponents.mIsPanIdPresent = true; - dataset.mChannel = lasertag_get_thread_channel(); - dataset.mComponents.mIsChannelPresent = true; - memcpy(dataset.mExtendedPanId.m8, lasertag_get_thread_ext_pan_id(), 8); - dataset.mComponents.mIsExtendedPanIdPresent = true; - memcpy(dataset.mNetworkKey.m8, lasertag_get_thread_network_key(), 16); - dataset.mComponents.mIsNetworkKeyPresent = true; - uint8_t ml_prefix[] = {0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00}; - memcpy(dataset.mMeshLocalPrefix.m8, ml_prefix, 8); - dataset.mComponents.mIsMeshLocalPrefixPresent = true; + if (otDatasetGetActive(instance, &dataset)) + { + // No dataset found, proceed to set up a new one + LOG_INF("No active Thread dataset found, initializing new dataset."); + dataset.mActiveTimestamp.mSeconds = 1; + dataset.mComponents.mIsActiveTimestampPresent = true; + uint8_t network_name[] = "Eriks Lasertag\0"; + strncpy(dataset.mNetworkName.m8, network_name, strlen(network_name)); + dataset.mComponents.mIsNetworkNamePresent = true; + dataset.mPanId = 0xdead; + dataset.mComponents.mIsPanIdPresent = true; + dataset.mChannel = 15; + dataset.mComponents.mIsChannelPresent = true; + uint8_t ext_pan_id[8]; + sys_csrand_get(ext_pan_id, sizeof(ext_pan_id)); + memcpy(dataset.mExtendedPanId.m8, ext_pan_id, 8); + dataset.mComponents.mIsExtendedPanIdPresent = true; + uint8_t network_key[16]; + sys_csrand_get(network_key, sizeof(network_key)); + memcpy(dataset.mNetworkKey.m8, network_key, 16); + dataset.mComponents.mIsNetworkKeyPresent = true; + memset(dataset.mMeshLocalPrefix.m8, 0, 8); + uint8_t mesh_local_prefix[8] = {0xfd, 0x00, 0x03, 0x08, 0x20, 0x13, 0x00, 0x00}; + memcpy(dataset.mMeshLocalPrefix.m8, mesh_local_prefix, 8); + dataset.mComponents.mIsMeshLocalPrefixPresent = true; + otDatasetSetActive(instance, &dataset); + } - otDatasetSetActive(instance, &dataset); otIp6SetEnabled(instance, true); otThreadSetEnabled(instance, true); - LOG_INF("Thread MGMT: Initialized, UDP %d & CoAP %d open.", UDP_PORT, OT_DEFAULT_COAP_PORT); +#if (CONFIG_THREAD_MGMT_LOG_LEVEL >= LOG_LEVEL_DBG) + memset(&dataset, 0, sizeof(otOperationalDataset)); + otDatasetGetActive(instance, &dataset); + LOG_DBG("Thread stack dataset after Thread stack initialization:"); + thread_mgmt_print_dataset(&dataset); +#endif return 0; } -void thread_mgmt_restart_thread_stack(bool force) +void thread_mgmt_restart_thread_stack(device_config_payload_t *pending_config, bool force) { + struct otInstance *instance = openthread_get_default_instance(); - otOperationalDataset active_dataset; + otOperationalDataset dataset; bool changed = false; + memset(&dataset, 0, sizeof(otOperationalDataset)); + // Get current active dataset. Force restart if unable to get it. - if (otDatasetGetActive(instance, &active_dataset) != OT_ERROR_NONE) { + if (otDatasetGetActive(instance, &dataset) != OT_ERROR_NONE) + { LOG_WRN("Failed to get active dataset, forcing Thread stack restart."); force = true; } - + // Compare each relevant field and set 'changed' if any differ - if (force || active_dataset.mChannel != lasertag_get_thread_channel()) { - active_dataset.mChannel = lasertag_get_thread_channel(); - active_dataset.mComponents.mIsChannelPresent = true; + if (force || dataset.mChannel != pending_config->channel) + { + LOG_DBG("Thrad channel change detected: %u -> %u", dataset.mChannel, pending_config->channel); + dataset.mChannel = pending_config->channel; + dataset.mComponents.mIsChannelPresent = true; changed = true; } - if (force || active_dataset.mPanId != lasertag_get_thread_pan_id()) { - active_dataset.mPanId = lasertag_get_thread_pan_id(); - active_dataset.mComponents.mIsPanIdPresent = true; + if (force || dataset.mPanId != pending_config->pan_id) + { + LOG_DBG("Thread PAN ID change detected: 0x%04X -> 0x%04X", dataset.mPanId, pending_config->pan_id); + dataset.mPanId = pending_config->pan_id; + dataset.mComponents.mIsPanIdPresent = true; changed = true; } - if (force || memcmp(active_dataset.mExtendedPanId.m8, lasertag_get_thread_ext_pan_id(), 8) != 0) { - memcpy(active_dataset.mExtendedPanId.m8, lasertag_get_thread_ext_pan_id(), 8); - active_dataset.mComponents.mIsExtendedPanIdPresent = true; - changed = true; - } - if (force || memcmp(active_dataset.mNetworkKey.m8, lasertag_get_thread_network_key(), 16) != 0) { - memcpy(active_dataset.mNetworkKey.m8, lasertag_get_thread_network_key(), 16); - active_dataset.mComponents.mIsNetworkKeyPresent = true; - changed = true; - } - const char *net_name = lasertag_get_thread_network_name(); - if (force || strncmp(active_dataset.mNetworkName.m8, net_name, strlen(net_name)) != 0) { - memcpy(active_dataset.mNetworkName.m8, net_name, strlen(net_name)); - active_dataset.mComponents.mIsNetworkNamePresent = true; + if (force || memcmp(dataset.mExtendedPanId.m8, pending_config->ext_pan_id, 8) != 0) + { + LOG_DBG("Thread extended PAN ID change detected."); + memcpy(dataset.mExtendedPanId.m8, pending_config->ext_pan_id, 8); + dataset.mComponents.mIsExtendedPanIdPresent = true; changed = true; } - if (changed) { - active_dataset.mActiveTimestamp.mSeconds += 1; // Increment timestamp to signal change - + if (force || memcmp(dataset.mNetworkKey.m8, pending_config->network_key, 16) != 0) + { + LOG_DBG("Thread network key change detected."); + LOG_HEXDUMP_DBG(dataset.mNetworkKey.m8, 16, "Old network key in dataset before update"); + memcpy(dataset.mNetworkKey.m8, pending_config->network_key, 16); + LOG_HEXDUMP_DBG(pending_config->network_key, 16, "New network key from pending config"); + LOG_HEXDUMP_DBG(dataset.mNetworkKey.m8, 16, "Network key in dataset after update"); + dataset.mComponents.mIsNetworkKeyPresent = true; + changed = true; + } + + if (force || strncmp(dataset.mNetworkName.m8, pending_config->network_name, 16) != 0) + { + LOG_DBG("Thread network name change detected: %s -> %s", dataset.mNetworkName.m8, pending_config->network_name); + strncpy(dataset.mNetworkName.m8, pending_config->network_name, 16); + dataset.mComponents.mIsNetworkNamePresent = true; + changed = true; + } + + if (changed) + { + LOG_DBG("Thread stack restart required; dataset changed."); + dataset.mActiveTimestamp.mSeconds++; + dataset.mComponents.mIsActiveTimestampPresent = true; + otThreadSetEnabled(instance, false); otIp6SetEnabled(instance, false); - otError error = otDatasetSetActive(instance, &active_dataset); - if (error != OT_ERROR_NONE) { - LOG_ERR("Failed to set active dataset: %d", error); - return; + + otError err = otDatasetSetActive(instance, &dataset); + if (err!= OT_ERROR_NONE) { + LOG_ERR("Error writing dataset: %d", err); } + otIp6SetEnabled(instance, true); otThreadSetEnabled(instance, true); - LOG_INF("Thread stack restarted with updated dataset."); - } else { - LOG_INF("Thread stack restart not required; dataset unchanged."); +#if (CONFIG_THREAD_MGMT_LOG_LEVEL >= LOG_LEVEL_DBG) + otOperationalDataset new_active_dataset; + memset(&new_active_dataset, 0, sizeof(otOperationalDataset)); + otDatasetGetActive(instance, &new_active_dataset); + LOG_DBG("Thread stack dataset after Thread stack update:"); + thread_mgmt_print_dataset(&new_active_dataset); +#endif + LOG_DBG("Thread stack restarted successfully."); + } + else + { + LOG_DBG("Thread stack restart not required; dataset unchanged."); + } +} + +uint16_t thread_mgmt_get_pan_id(void) +{ + struct otInstance *instance = openthread_get_default_instance(); + otOperationalDataset dataset; + + if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) + { + return dataset.mPanId; + } + return 0; +} + +uint8_t thread_mgmt_get_channel(void) +{ + struct otInstance *instance = openthread_get_default_instance(); + otOperationalDataset dataset; + + if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) + { + return dataset.mChannel; + } + return 0; +} + +void thread_mgmt_get_ext_pan_id(uint8_t *dest_8byte) +{ + struct otInstance *instance = openthread_get_default_instance(); + otOperationalDataset dataset; + + if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) { + memcpy(dest_8byte, dataset.mExtendedPanId.m8, 8); + } +} + +void thread_mgmt_get_network_key(uint8_t *dest_16byte) +{ + struct otInstance *instance = openthread_get_default_instance(); + otOperationalDataset dataset; + + if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) { + memcpy(dest_16byte, dataset.mNetworkKey.m8, 16); + } +} + +void thread_mgmt_get_network_name(char *dest_str, size_t max_len) +{ + struct otInstance *instance = openthread_get_default_instance(); + otOperationalDataset dataset; + + if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) { + // Sicher kopieren und Null-Terminierung erzwingen + snprintf(dest_str, max_len, "%s", dataset.mNetworkName.m8); } - }