Zwischenstand vor refactor
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 <zephyr/kernel.h>
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 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 */
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
module = THREAD_MGMT
|
||||
module-str = thread_mgmt
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
endif # THREAD_MGMT
|
||||
@@ -2,6 +2,7 @@
|
||||
#define THREAD_MGMT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ble_mgmt.h>
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -1,113 +1,258 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/net/openthread.h>
|
||||
#include <zephyr/random/random.h>
|
||||
#include <openthread/thread.h>
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/udp.h>
|
||||
#include <openthread/coap.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <lasertag_utils.h>
|
||||
#include <thread_mgmt.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <lasertag_utils.h>
|
||||
#include <thread_mgmt.h>
|
||||
#include <ble_mgmt.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user