Umbau Thread-Config an/vom leader in einem paket
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 12s

This commit is contained in:
2026-01-13 10:17:53 +01:00
parent 38396738a6
commit a041d5a49c
10 changed files with 559 additions and 334 deletions

View File

@@ -34,6 +34,10 @@ CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Lasertag-Device"
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
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
# Enable Lasertag Shared Modules
CONFIG_LASERTAG_UTILS=y

View File

@@ -34,6 +34,10 @@ CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Lasertag-Device"
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
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
# Enable Lasertag Shared Modules
CONFIG_LASERTAG_UTILS=y

View File

@@ -35,4 +35,24 @@ int ble_mgmt_adv_start(void);
*/
int ble_mgmt_adv_stop(void);
/**
* @brief Get the current system state
*/
uint8_t lasertag_get_system_state(void);
/**
* @brief Set the current system state.
*/
void lasertag_set_system_state(uint8_t state);
/**
* @brief Get the current 64-bit Game ID
*/
uint64_t lasertag_get_game_id(void);
/**
* @brief Set the current 64-bit Game ID.
*/
void lasertag_set_game_id(uint64_t id);
#endif /* BLE_MGMT_H */

View File

@@ -1,3 +1,14 @@
/**
* 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
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/bluetooth.h>
@@ -9,47 +20,104 @@
#include <lasertag_utils.h>
#include <thread_mgmt.h>
#include <ble_mgmt.h>
#include <string.h>
LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
/**
* Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cXXXX
* Alias positions: Byte 12 & 13
*/
/* ============================================================================
UUID Definitions
============================================================================
Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cXXXX
Service and characteristic IDs use the last two bytes (XXXX)
========================================================================== */
#define LT_UUID_BASE_VAL \
BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c0000)
/* ==========================================================================
SERVICE 1: PROVISIONING (0x10XX)
========================================================================== */
/* 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_PANID_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1002))
#define BT_UUID_LT_PROV_CHAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1003))
#define BT_UUID_LT_PROV_EXTPAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1004))
#define BT_UUID_LT_PROV_NETKEY_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1005))
#define BT_UUID_LT_PROV_NETNAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1006))
/* #define BT_UUID_LT_PROV_PANID_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1002)) */
/* #define BT_UUID_LT_PROV_CHAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1003)) */
/* #define BT_UUID_LT_PROV_EXTPAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1004)) */
/* #define BT_UUID_LT_PROV_NETKEY_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1005)) */
/* #define BT_UUID_LT_PROV_NETNAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1006)) */
#define BT_UUID_LT_PROV_NODES_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1007))
#define BT_UUID_LT_PROV_TYPE_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1008))
/* ==========================================================================
SERVICE 2: GAME (0x20XX)
========================================================================== */
/* Full configuration pack characteristic */
#define BT_UUID_LT_PROV_CONFIG_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c100c))
/* GAME SERVICE (0x20xx): Game-related commands and logging */
#define BT_UUID_LT_GAME_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2000))
/* Game service characteristics */
#define BT_UUID_LT_GAME_CONFIG_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2001))
#define BT_UUID_LT_GAME_COMMAND_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2002))
#define BT_UUID_LT_GAME_LOG_DATA_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2003))
/* --- Global Variables --- */
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;
/* --- GATT Callbacks --- */
/* ============================================================================
Data Structures
============================================================================ */
/**
* Leader configuration payload.
* Packed structure for transmitting full leader configuration via BLE.
* Total size: 86 bytes
*/
struct leader_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;
/* ============================================================================
Global State Variables
============================================================================ */
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 */
static uint8_t system_state = 0; /* Game system state */
static uint64_t game_id = 0; /* Current game identifier */
/* ============================================================================
Advertising Data
============================================================================ */
/* 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,
0x00, 0x10, 0x0c, 0x82, 0xae, 0xc3, 0x89, 0x92,
0x22, 0x4a, 0x64, 0x6c, 0xcf, 0xe2, 0xaf, 0x03),
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)
{
@@ -66,6 +134,8 @@ static ssize_t read_lasertag_val(struct bt_conn *conn, const struct bt_gatt_attr
val_ptr = lasertag_get_device_name();
val_len = strlen(val_ptr);
}
/* Disabled characteristics 1002-1006 */
/*
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_PANID_CHAR) == 0)
{
static uint16_t pan_id;
@@ -95,10 +165,16 @@ static ssize_t read_lasertag_val(struct bt_conn *conn, const struct bt_gatt_attr
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);
}
/**
* 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)
{
@@ -110,6 +186,8 @@ static ssize_t write_lasertag_val(struct bt_conn *conn, const struct bt_gatt_att
bt_set_name(lasertag_get_device_name());
}
}
/* Disabled characteristics 1002-1006 */
/*
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_PANID_CHAR) == 0)
{
if (len != 2)
@@ -138,12 +216,17 @@ static ssize_t write_lasertag_val(struct bt_conn *conn, const struct bt_gatt_att
{
rc = lasertag_set_thread_network_name(buf, len);
}
*/
if (rc)
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
return len;
}
/**
* Read handler for discovered nodes characteristic.
* Returns the list of discovered Thread mesh nodes as a string.
*/
static ssize_t read_discovered_nodes(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
@@ -151,6 +234,10 @@ static ssize_t read_discovered_nodes(struct bt_conn *conn, const struct bt_gatt_
return bt_gatt_attr_read(conn, attr, buf, len, offset, list, strlen(list));
}
/**
* Write handler for node discovery trigger characteristic.
* Any write to this characteristic starts the Thread mesh node discovery process.
*/
static ssize_t write_discover_cmd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{
@@ -158,67 +245,142 @@ static ssize_t write_discover_cmd(struct bt_conn *conn, const struct bt_gatt_att
thread_mgmt_discover_nodes();
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 leader_config_payload payload;
memset(&payload, 0, sizeof(payload));
/* Service Definition */
payload.system_state = lasertag_get_system_state();
payload.game_id = lasertag_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 leader_config_payload)) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
const struct leader_config_payload *payload = (const struct leader_config_payload *)buf;
/* Apply RAM values */
lasertag_set_system_state(payload->system_state);
lasertag_set_game_id(payload->game_id);
/* Apply NVS values via utils */
lasertag_set_thread_pan_id(payload->pan_id);
lasertag_set_thread_channel(payload->channel);
lasertag_set_thread_ext_pan_id(payload->ext_pan_id);
lasertag_set_thread_network_key(payload->network_key);
lasertag_set_thread_network_name(payload->network_name, strlen(payload->network_name));
lasertag_set_device_name((const void *)payload->node_name, strlen(payload->node_name));
bt_set_name(lasertag_get_device_name());
LOG_INF("Leader config updated via BLE (Packed Struct)");
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 */
/* 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 (Read-only) */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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),
*/
/* Node List / Discovery Trigger */
/* Node discovery list and trigger (read/write) */
BT_GATT_CHARACTERISTIC(BT_UUID_LT_PROV_NODES_CHAR,
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
read_discovered_nodes, write_discover_cmd, NULL), );
read_discovered_nodes, write_discover_cmd, NULL),
static uint8_t mfg_data[] = { 0xff, 0xff, 0x00 }; // Last byte for device role
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,
0x00, 0x10, 0x0c, 0x82, 0xae, 0xc3, 0x89, 0x92,
0x22, 0x4a, 0x64, 0x6c, 0xcf, 0xe2, 0xaf, 0x03),
BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)),
};
/* 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)
@@ -232,6 +394,17 @@ static void adv_restart_work_handler(struct k_work *work)
}
}
/* ============================================================================
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;
@@ -244,6 +417,12 @@ int ble_mgmt_init(uint8_t device_type)
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;
@@ -272,6 +451,11 @@ int ble_mgmt_adv_start(void)
return err;
}
/**
* Stop BLE advertising.
*
* @return 0 on success, negative error code on failure
*/
int ble_mgmt_adv_stop(void)
{
int err = bt_le_adv_stop();
@@ -283,6 +467,42 @@ int ble_mgmt_adv_stop(void)
return err;
}
/* ============================================================================
Game State Management Functions
============================================================================ */
/**
* Get the current system state.
* @return Current system state value
*/
uint8_t lasertag_get_system_state(void) { return system_state; }
/**
* Set the system state.
* @param state The new system state
*/
void lasertag_set_system_state(uint8_t state) { system_state = state; }
/**
* Get the current game ID.
* @return Current game identifier
*/
uint64_t lasertag_get_game_id(void) { return game_id; }
/**
* Set the game ID.
* @param id The new game identifier
*/
void lasertag_set_game_id(uint64_t id) { game_id = id; }
/* ============================================================================
BLE Connection Event Handlers
============================================================================ */
/**
* Callback for when a device connects.
* Logs the connection and updates advertising state.
*/
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
@@ -293,12 +513,17 @@ static void connected(struct bt_conn *conn, uint8_t err)
}
}
/**
* Callback for when a device disconnects.
* Logs the disconnection and schedules advertising restart.
*/
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
LOG_INF("Verbindung getrennt (Grund %u)", reason);
k_work_reschedule(&adv_restart_work, K_MSEC(100));
}
/* Connection callbacks structure */
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,