From b40e44c99170abbf54c5607749a3004b3b9c26e8 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Fri, 2 Jan 2026 17:46:30 +0100 Subject: [PATCH] Thread provisioning and ping works --- firmware/apps/leader/prj.conf | 5 + firmware/libs/ble_mgmt/src/ble_mgmt.c | 152 ++++---- .../libs/lasertag_utils/src/lasertag_utils.c | 160 ++++---- firmware/libs/thread_mgmt/src/thread_mgmt.c | 128 +++++-- lasertag.code-workspace | 12 + software/provisioning/index.html | 342 ++++++++++++++++-- 6 files changed, 592 insertions(+), 207 deletions(-) create mode 100644 lasertag.code-workspace diff --git a/firmware/apps/leader/prj.conf b/firmware/apps/leader/prj.conf index 0573209..3a2f1c6 100644 --- a/firmware/apps/leader/prj.conf +++ b/firmware/apps/leader/prj.conf @@ -7,6 +7,11 @@ CONFIG_KERNEL_SHELL=y CONFIG_DEVICE_SHELL=y CONFIG_REBOOT=y +# --- STACK SIZE UPDATES (Fixes the Hard Fault) --- +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 +CONFIG_BT_RX_STACK_SIZE=2048 + # Storage and Settings (NVS) CONFIG_FLASH=y CONFIG_FLASH_MAP=y diff --git a/firmware/libs/ble_mgmt/src/ble_mgmt.c b/firmware/libs/ble_mgmt/src/ble_mgmt.c index 7c77a83..6ecce67 100644 --- a/firmware/libs/ble_mgmt/src/ble_mgmt.c +++ b/firmware/libs/ble_mgmt/src/ble_mgmt.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -12,7 +13,6 @@ LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL); /** * Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cbcxx - * Service ends in 00 to match the Web App filter. */ #define LT_UUID_BASE_VAL \ BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc00) @@ -21,70 +21,108 @@ LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL); #define BT_UUID_LT_NAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc01)) #define BT_UUID_LT_PANID_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc02)) #define BT_UUID_LT_CHAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc03)) +#define BT_UUID_LT_EXTPAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc04)) +#define BT_UUID_LT_NETKEY_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc05)) +#define BT_UUID_LT_NETNAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc06)) /* --- GATT Callbacks --- */ -static ssize_t read_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, +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 *name = lasertag_get_device_name(); - return bt_gatt_attr_read(conn, attr, buf, len, offset, name, strlen(name)); + const char *val_ptr = NULL; + size_t val_len = 0; + + if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NAME_CHAR) == 0) { + val_ptr = lasertag_get_device_name(); + val_len = strlen(val_ptr); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PANID_CHAR) == 0) { + static uint16_t pan_id; + pan_id = lasertag_get_thread_pan_id(); + val_ptr = (char *)&pan_id; + val_len = sizeof(pan_id); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_CHAN_CHAR) == 0) { + static uint8_t chan; + chan = lasertag_get_thread_channel(); + val_ptr = (char *)&chan; + val_len = sizeof(chan); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_EXTPAN_CHAR) == 0) { + val_ptr = (char *)lasertag_get_thread_ext_pan_id(); + val_len = 8; + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NETKEY_CHAR) == 0) { + val_ptr = (char *)lasertag_get_thread_network_key(); + val_len = 16; + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NETNAME_CHAR) == 0) { + val_ptr = lasertag_get_thread_network_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, +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) { - LOG_INF("BLE: New name received (len %d)", len); + int rc = 0; + if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NAME_CHAR) == 0) { + rc = lasertag_set_device_name(buf, len); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PANID_CHAR) == 0) { + if (len != 2) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + rc = lasertag_set_thread_pan_id(*(uint16_t*)buf); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_CHAN_CHAR) == 0) { + if (len != 1) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + rc = lasertag_set_thread_channel(*(uint8_t*)buf); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_EXTPAN_CHAR) == 0) { + if (len != 8) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + rc = lasertag_set_thread_ext_pan_id(buf); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NETKEY_CHAR) == 0) { + if (len != 16) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + rc = lasertag_set_thread_network_key(buf); + } else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_NETNAME_CHAR) == 0) { + rc = lasertag_set_thread_network_name(buf, len); + } + + if (rc) return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); return len; } -static ssize_t read_panid(struct bt_conn *conn, const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - uint16_t pan_id = lasertag_get_thread_pan_id(); - return bt_gatt_attr_read(conn, attr, buf, len, offset, &pan_id, sizeof(pan_id)); -} - -static ssize_t read_chan(struct bt_conn *conn, const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - uint8_t chan = lasertag_get_thread_channel(); - return bt_gatt_attr_read(conn, attr, buf, len, offset, &chan, sizeof(chan)); -} - -/* Service and Characteristic Definition */ +/* Service Definition */ BT_GATT_SERVICE_DEFINE(provisioning_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_SERVICE), - /* Device Name Characteristic */ BT_GATT_CHARACTERISTIC(BT_UUID_LT_NAME_CHAR, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, - read_name, write_name, NULL), + read_lasertag_val, write_lasertag_val, NULL), - /* Thread PAN ID Characteristic */ BT_GATT_CHARACTERISTIC(BT_UUID_LT_PANID_CHAR, - BT_GATT_CHRC_READ, - BT_GATT_PERM_READ, - read_panid, NULL, NULL), + 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 Characteristic */ BT_GATT_CHARACTERISTIC(BT_UUID_LT_CHAN_CHAR, - BT_GATT_CHRC_READ, - BT_GATT_PERM_READ, - read_chan, NULL, NULL), + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_lasertag_val, write_lasertag_val, NULL), + + BT_GATT_CHARACTERISTIC(BT_UUID_LT_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), + + BT_GATT_CHARACTERISTIC(BT_UUID_LT_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), + + BT_GATT_CHARACTERISTIC(BT_UUID_LT_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), ); -/** - * Advertising Data - * * Note: Legacy advertising is limited to 31 bytes. - * Flags: 3 bytes - * UUID128: 18 bytes - * Total: 21 bytes (Fits within limit) - */ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - /* We put the Service UUID here so the Web App can filter for it */ BT_DATA_BYTES(BT_DATA_UUID128_ALL, 0x00, 0xbc, 0x0c, 0x82, 0xae, 0xc3, 0x89, 0x92, 0x22, 0x4a, 0x64, 0x6c, 0xcf, 0xe2, 0xaf, 0x03), @@ -93,11 +131,7 @@ static const struct bt_data ad[] = { int ble_mgmt_init(void) { int err = bt_enable(NULL); - if (err) { - LOG_ERR("Bluetooth init failed (err %d)", err); - return err; - } - + if (err) return err; LOG_INF("Bluetooth initialized"); return 0; } @@ -105,47 +139,31 @@ int ble_mgmt_init(void) int ble_mgmt_adv_start(void) { const char *name = lasertag_get_device_name(); - - /* Set the stack name */ bt_set_name(name); - /** - * Scan Response contains the full complete name. - * This is sent in a separate packet when requested by the scanner. - */ 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, - .sid = 0, - .secondary_max_skip = 0, .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, - .peer = NULL, }; - int err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), - dynamic_sd, ARRAY_SIZE(dynamic_sd)); - if (err) { - LOG_ERR("Advertising failed to start (err %d)", err); - return err; + 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", name); } - - LOG_INF("Advertising started as: %s", name); - return 0; + return err; } int ble_mgmt_adv_stop(void) { int err = bt_le_adv_stop(); - if (err) { - LOG_ERR("Advertising failed to stop (err %d)", err); - return err; + if (!err) { + LOG_INF("Advertising stopped"); } - - LOG_INF("Advertising stopped"); - return 0; + return err; } \ 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 9a1778b..e81bf97 100644 --- a/firmware/libs/lasertag_utils/src/lasertag_utils.c +++ b/firmware/libs/lasertag_utils/src/lasertag_utils.c @@ -7,13 +7,12 @@ #include #include #include +#include +#include LOG_MODULE_REGISTER(lasertag_utils, CONFIG_LASERTAG_UTILS_LOG_LEVEL); -/* Application-level persistence storage */ static char device_name[32] = "UnknownDevice"; - -/* Thread configuration parameters */ static uint16_t thread_pan_id = 0xabcd; static char thread_network_name[17] = "OpenThread-nRF"; static uint8_t thread_channel = 15; @@ -23,58 +22,44 @@ static uint8_t thread_network_key[16] = { 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; -/* --- Settings Handling (Persistent Storage) --- */ +/* --- Settings Handler --- */ static int lasertag_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { const char *next; - if (settings_name_steq(name, "name", &next) && !next) { if (len > sizeof(device_name) - 1) return -EINVAL; ssize_t rc = read_cb(cb_arg, device_name, len); if (rc >= 0) { device_name[rc] = '\0'; return 0; } - return (int)rc; } - 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; } - return (int)rc; } - 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; } -struct settings_handler lasertag_conf = { - .name = "lasertag", - .h_set = lasertag_settings_set -}; +struct settings_handler lasertag_conf = { .name = "lasertag", .h_set = lasertag_settings_set }; void lasertag_utils_init(void) { LOG_INF("=========================================="); LOG_INF("Lasertag System - Common Lib v0.0.1"); - - int rc = settings_subsys_init(); - if (rc) LOG_ERR("Settings subsys init failed (err %d)", rc); + settings_subsys_init(); settings_register(&lasertag_conf); settings_load(); @@ -85,6 +70,7 @@ void lasertag_utils_init(void) 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; } @@ -92,14 +78,40 @@ 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) { + if (len >= sizeof(device_name)) len = sizeof(device_name) - 1; + memcpy(device_name, name, 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 -/** - * @brief Helper to convert hex string to binary. - * Renamed to lasertag_hex2bin to avoid conflict with Zephyr sys/util.h - */ 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' }; @@ -108,80 +120,64 @@ static int lasertag_hex2bin(const char *hex, uint8_t *bin, size_t bin_len) { return 0; } -static int cmd_ble_start(const struct shell *sh, size_t argc, char **argv) { - shell_print(sh, "Starting BLE Advertising..."); - return ble_mgmt_adv_start(); -} - -static int cmd_ble_stop(const struct shell *sh, size_t argc, char **argv) { - shell_print(sh, "Stopping BLE Advertising..."); - return ble_mgmt_adv_stop(); -} - -static int cmd_thread_set_chan(const struct shell *sh, size_t argc, char **argv) { - thread_channel = (uint8_t)strtoul(argv[1], NULL, 10); - settings_save_one("lasertag/channel", &thread_channel, sizeof(thread_channel)); - shell_print(sh, "Thread Channel saved: %d", thread_channel); - return 0; -} - -static int cmd_thread_set_extpan(const struct shell *sh, size_t argc, char **argv) { - if (strlen(argv[1]) != 16) { shell_error(sh, "ExtPANID must be 16 hex chars"); return -EINVAL; } - lasertag_hex2bin(argv[1], thread_ext_pan_id, 8); - settings_save_one("lasertag/ext_pan_id", thread_ext_pan_id, 8); - shell_print(sh, "Thread Extended PAN ID saved."); - return 0; -} - -static int cmd_thread_set_key(const struct shell *sh, size_t argc, char **argv) { - if (strlen(argv[1]) != 32) { shell_error(sh, "Network Key must be 32 hex chars"); return -EINVAL; } - lasertag_hex2bin(argv[1], thread_network_key, 16); - settings_save_one("lasertag/net_key", thread_network_key, 16); - shell_print(sh, "Thread Network Key saved."); - return 0; -} - -static int cmd_name_set(const struct shell *sh, size_t argc, char **argv) { - strncpy(device_name, argv[1], sizeof(device_name) - 1); - device_name[sizeof(device_name) - 1] = '\0'; - settings_save_one("lasertag/name", device_name, strlen(device_name)); - shell_print(sh, "Device name saved: %s", device_name); - return 0; -} - static int cmd_reboot(const struct shell *sh, size_t argc, char **argv) { - ARG_UNUSED(argc); - ARG_UNUSED(argv); shell_print(sh, "Rebooting..."); sys_reboot(SYS_REBOOT_COLD); return 0; } -/* Subcommands for 'lasertag thread' */ +static int cmd_name_set(const struct shell *sh, size_t argc, char **argv) { + lasertag_set_device_name(argv[1], strlen(argv[1])); + shell_print(sh, "Name gespeichert."); + return 0; +} + +static int cmd_thread_ping(const struct shell *sh, size_t argc, char **argv) { + char msg[64]; + snprintf(msg, sizeof(msg), "Ping von %s", device_name); + shell_print(sh, "Sende Multicast-Ping an ff03::1..."); + int rc = thread_mgmt_send_udp("ff03::1", (uint8_t*)msg, strlen(msg)); + if (rc) shell_error(sh, "Ping fehlgeschlagen (%d)", rc); + return 0; +} + +/* Subcommands definitions omitted for brevity, but they should include 'ping' */ +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 ", NULL, 2, 0), - SHELL_CMD_ARG(name, NULL, "Set Net Name ", NULL, 2, 0), - SHELL_CMD_ARG(chan, NULL, "Set Channel <11-26>", cmd_thread_set_chan, 2, 0), - SHELL_CMD_ARG(extid, NULL, "Set ExtPANID <16 hex chars>", cmd_thread_set_extpan, 2, 0), - SHELL_CMD_ARG(key, NULL, "Set NetKey <32 hex chars>", cmd_thread_set_key, 2, 0), + SHELL_CMD_ARG(panid, NULL, "PAN ID setzen", cmd_thread_set_panid, 2, 0), + SHELL_CMD_ARG(chan, NULL, "Kanal setzen", cmd_thread_set_chan, 2, 0), + SHELL_CMD(ping, NULL, "Multicast Ping senden", cmd_thread_ping), SHELL_SUBCMD_SET_END ); +static int cmd_ble_start(const struct shell *sh, size_t argc, char **argv) { + return ble_mgmt_adv_start(); +} + SHELL_STATIC_SUBCMD_SET_CREATE(sub_ble, - SHELL_CMD(start, NULL, "Start BLE advertising", cmd_ble_start), - SHELL_CMD(stop, NULL, "Stop BLE advertising", cmd_ble_stop), + SHELL_CMD(start, NULL, "Start BLE", cmd_ble_start), SHELL_SUBCMD_SET_END ); -/* Main command 'lasertag' with thread + ble helpers */ SHELL_STATIC_SUBCMD_SET_CREATE(sub_lasertag, - SHELL_CMD_ARG(name, NULL, "Set device name ", cmd_name_set, 2, 0), - SHELL_CMD(thread, &sub_thread, "Thread network configuration", NULL), - SHELL_CMD(ble, &sub_ble, "Bluetooth management", NULL), - SHELL_CMD(reboot, NULL, "Reboot the device", cmd_reboot), + SHELL_CMD_ARG(name, NULL, "Name setzen", cmd_name_set, 2, 0), + SHELL_CMD(thread, &sub_thread, "Thread Konfiguration", NULL), + SHELL_CMD(ble, &sub_ble, "BLE Management", NULL), + SHELL_CMD(reboot, NULL, "Reboot", cmd_reboot), SHELL_SUBCMD_SET_END ); -SHELL_CMD_REGISTER(lasertag, &sub_lasertag, "Lasertag control commands", NULL); +SHELL_CMD_REGISTER(lasertag, &sub_lasertag, "Lasertag Befehle", NULL); -#endif /* CONFIG_LASERTAG_SHELL */ \ No newline at end of file +#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 5d49622..05c4dee 100644 --- a/firmware/libs/thread_mgmt/src/thread_mgmt.c +++ b/firmware/libs/thread_mgmt/src/thread_mgmt.c @@ -4,74 +4,148 @@ #include #include #include +#include +#include #include #include +#include LOG_MODULE_REGISTER(thread_mgmt, CONFIG_THREAD_MGMT_LOG_LEVEL); +#define UDP_PORT 1234 + +static otUdpSocket s_udp_socket; + +/** + * @brief Callback für empfangene UDP-Nachrichten. + */ +static void udp_receive_cb(void *context, otMessage *message, const otMessageInfo *message_info) +{ + uint8_t buf[64]; + uint16_t length = otMessageGetLength(message) - otMessageGetOffset(message); + + if (length > sizeof(buf) - 1) { + length = sizeof(buf) - 1; + } + + int read = otMessageRead(message, otMessageGetOffset(message), buf, length); + buf[read] = '\0'; + + char addr_str[OT_IP6_ADDRESS_STRING_SIZE]; + otIp6AddressToString(&message_info->mPeerAddr, addr_str, sizeof(addr_str)); + + /* Deutliche Log-Ausgabe für das Testen */ + LOG_INF("------------------------------------------"); + LOG_INF("UDP DATA RECEIVED!"); + LOG_INF("From: [%s]", addr_str); + LOG_INF("Payload: %s", buf); + LOG_INF("------------------------------------------"); +} + +int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len) +{ + struct otInstance *instance = openthread_get_default_instance(); + otError error = OT_ERROR_NONE; + otMessage *message; + otMessageInfo message_info; + + if (!instance) return -ENODEV; + + memset(&message_info, 0, sizeof(message_info)); + otIp6AddressFromString(addr_str, &message_info.mPeerAddr); + message_info.mPeerPort = UDP_PORT; + + message = otUdpNewMessage(instance, NULL); + if (message == NULL) return -ENOMEM; + + error = otMessageAppend(message, payload, len); + if (error != OT_ERROR_NONE) { + otMessageFree(message); + return -EIO; + } + + error = otUdpSend(instance, &s_udp_socket, message, &message_info); + if (error != OT_ERROR_NONE) { + otMessageFree(message); + LOG_ERR("UDP Senden fehlgeschlagen (err %d)", error); + return -EIO; + } + + LOG_INF("UDP gesendet an %s: %d Bytes", addr_str, len); + return 0; +} + int thread_mgmt_init(void) { struct otInstance *instance = openthread_get_default_instance(); otOperationalDataset dataset; - int rc; + otError error; if (!instance) { - LOG_ERR("Failed to get OpenThread instance"); + LOG_ERR("OpenThread Instanz nicht gefunden"); return -ENODEV; } - LOG_INF("Configuring Thread stack with stored settings..."); + LOG_INF("Thread stack wird konfiguriert..."); - /* Initialize dataset structure */ + /* Dataset-Struktur initialisieren */ memset(&dataset, 0, sizeof(otOperationalDataset)); - /* 1. Set Network Name */ + /* 0. Active Timestamp - Wichtig für die Netzwerksynchronisation */ + dataset.mActiveTimestamp.mSeconds = 1; + dataset.mComponents.mIsActiveTimestampPresent = true; + + /* 1. Netzwerkname */ const char *net_name = lasertag_get_thread_network_name(); - size_t name_len = strlen(net_name); - memcpy(dataset.mNetworkName.m8, net_name, name_len); + memcpy(dataset.mNetworkName.m8, net_name, strlen(net_name)); dataset.mComponents.mIsNetworkNamePresent = true; - /* 2. Set PAN ID */ + /* 2. PAN ID */ dataset.mPanId = lasertag_get_thread_pan_id(); dataset.mComponents.mIsPanIdPresent = true; - /* 3. Set Channel */ + /* 3. Kanal */ dataset.mChannel = lasertag_get_thread_channel(); dataset.mComponents.mIsChannelPresent = true; - /* 4. Set Extended PAN ID */ + /* 4. Extended PAN ID */ memcpy(dataset.mExtendedPanId.m8, lasertag_get_thread_ext_pan_id(), 8); dataset.mComponents.mIsExtendedPanIdPresent = true; - /* 5. Set Network Key */ + /* 5. Netzwerk Key */ memcpy(dataset.mNetworkKey.m8, lasertag_get_thread_network_key(), 16); dataset.mComponents.mIsNetworkKeyPresent = true; - /* 6. Set Mesh Local Prefix (Default for OpenThread) */ + /* 6. Mesh Local Prefix */ uint8_t ml_prefix[] = {0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00}; memcpy(dataset.mMeshLocalPrefix.m8, ml_prefix, 8); dataset.mComponents.mIsMeshLocalPrefixPresent = true; - /* Apply the dataset as the Active Dataset */ - rc = otDatasetSetActive(instance, &dataset); - if (rc != OT_ERROR_NONE) { - LOG_ERR("Failed to set Active Dataset (err %d)", rc); + /* Dataset aktivieren */ + otDatasetSetActive(instance, &dataset); + + /* Interface und Stack starten */ + otIp6SetEnabled(instance, true); + otThreadSetEnabled(instance, true); + + /* UDP Socket initialisieren */ + otSockAddr listen_addr; + memset(&listen_addr, 0, sizeof(listen_addr)); + listen_addr.mPort = UDP_PORT; + + error = otUdpOpen(instance, &s_udp_socket, udp_receive_cb, NULL); + if (error != OT_ERROR_NONE) { + LOG_ERR("UDP Socket konnte nicht geoeffnet werden (err %d)", error); return -EIO; } - /* Start the interface */ - rc = otIp6SetEnabled(instance, true); - if (rc != OT_ERROR_NONE) { - LOG_ERR("Failed to enable IPv6 (err %d)", rc); + /* otUdpBind für SDK v3.2.1 mit 4 Argumenten */ + error = otUdpBind(instance, &s_udp_socket, &listen_addr, OT_NETIF_UNSPECIFIED); + if (error != OT_ERROR_NONE) { + LOG_ERR("UDP Bind fehlgeschlagen (err %d)", error); return -EIO; } - rc = otThreadSetEnabled(instance, true); - if (rc != OT_ERROR_NONE) { - LOG_ERR("Failed to enable Thread (err %d)", rc); - return -EIO; - } - - LOG_INF("Thread stack initialized and interface enabled."); + LOG_INF("Thread MGMT: Initialisiert, UDP Port %d offen.", UDP_PORT); return 0; } \ No newline at end of file diff --git a/lasertag.code-workspace b/lasertag.code-workspace new file mode 100644 index 0000000..c7dc82f --- /dev/null +++ b/lasertag.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "nrf-connect.applications": [ + "${workspaceFolder}/firmware/apps/leader" + ] + } +} \ No newline at end of file diff --git a/software/provisioning/index.html b/software/provisioning/index.html index 357bd65..41a7c7c 100644 --- a/software/provisioning/index.html +++ b/software/provisioning/index.html @@ -1,66 +1,346 @@ - + Lasertag Provisioning
-

Lasertag Setup

-

Connect to your device via Bluetooth to configure Thread settings.

- -
Ready to connect...
+

Lasertag Konfiguration

+
Bereit zum Scannen...
+ +
+ + +
+ +
+ +
+ + + +
+
- Connected to:
-

Next step: Implement Characteristic Write/Read.

+
+ +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+
+ +

Hinweis: Alle Änderungen werden im NVS gespeichert. Ein Reboot ist erforderlich, um Thread neu zu starten.

\ No newline at end of file