Added device types and vest mini app
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 22s

This commit is contained in:
2026-01-10 09:07:49 +01:00
parent 978f93ec3d
commit ce4d0d1a44
31 changed files with 621 additions and 273 deletions

View File

@@ -12,7 +12,7 @@ int main(void)
lasertag_utils_init();
/* Initialize and start BLE management for provisioning */
int rc = ble_mgmt_init();
int rc = ble_mgmt_init(LT_TYPE_LEADER);
if (rc) {
LOG_ERR("BLE initialization failed (err %d)", rc);
return rc;
@@ -20,6 +20,14 @@ int main(void)
LOG_INF("BLE Management initialized successfully.");
}
/* Start BLE advertising */
rc = ble_mgmt_adv_start();
if (rc) {
LOG_ERR("BLE advertising start failed (err %d)", rc);
} else {
LOG_INF("BLE advertising started.");
}
/* Initialize and start OpenThread stack */
rc = thread_mgmt_init();
if (rc) {

View File

@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.20)
# Tell Zephyr to look into our libs folder for extra modules
list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/../../libs)
# Set board root to find custom board overlays in firmware/boards
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(lasertag_vest)
# Define application source files
target_sources(app PRIVATE src/main.c)

View File

@@ -0,0 +1,41 @@
# 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
# --- 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
CONFIG_NVS=y
CONFIG_SETTINGS=y
# Network and OpenThread
CONFIG_NETWORKING=y
CONFIG_NET_L2_OPENTHREAD=y
CONFIG_OPENTHREAD=y
CONFIG_OPENTHREAD_FTD=y
CONFIG_OPENTHREAD_SHELL=y
# --- CoAP & UDP Features ---
CONFIG_OPENTHREAD_COAP=y
CONFIG_OPENTHREAD_MANUAL_START=y
# Bluetooth
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Lasertag-Device"
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
# Enable Lasertag Shared Modules
CONFIG_LASERTAG_UTILS=y
CONFIG_THREAD_MGMT=y
CONFIG_BLE_MGMT=y

View File

@@ -0,0 +1,46 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <lasertag_utils.h>
#include <thread_mgmt.h>
#include <ble_mgmt.h>
LOG_MODULE_REGISTER(vest_app, CONFIG_LOG_DEFAULT_LEVEL);
int main(void)
{
/* Initialize shared project logic and NVS */
lasertag_utils_init();
/* Initialize and start BLE management for provisioning */
int rc = ble_mgmt_init(LT_TYPE_VEST);
if (rc) {
LOG_ERR("BLE initialization failed (err %d)", rc);
return rc;
} else {
LOG_INF("BLE Management initialized successfully.");
}
/* Start BLE advertising */
rc = ble_mgmt_adv_start();
if (rc) {
LOG_ERR("BLE advertising start failed (err %d)", rc);
} else {
LOG_INF("BLE advertising started.");
}
/* Initialize and start OpenThread stack */
rc = thread_mgmt_init();
if (rc) {
LOG_ERR("Thread initialization failed (err %d)", rc);
} else {
LOG_INF("Leader Application successfully started with Thread Mesh.");
return rc;
}
while (1) {
/* Main loop - handle high-level game logic here */
k_sleep(K_MSEC(1000));
}
return 0;
}

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
# Zephyr mitteilen, dass unsere Libs Teil des Projekts sind
# Tell Zephyr that our libs are part of the project
list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/../../libs)
# Set board root to find custom board overlays in firmware/boards

View File

@@ -4,12 +4,12 @@
#include <openthread/thread.h>
#include <openthread/coap.h>
/* Unsere neue Library */
/* Our new library */
#include "game_logic.h"
LOG_MODULE_REGISTER(weapon_app, LOG_LEVEL_INF);
/* Spiel-Kontext */
/* Game context */
static struct game_ctx game;
/* Forward Declarations */
@@ -19,15 +19,15 @@ static void on_button_changed(uint32_t button_state, uint32_t has_changed);
static void on_game_state_change(enum game_state new_state)
{
LOG_INF("APP: Spielstatus geändert -> %d", new_state);
LOG_INF("APP: Game state changed -> %d", new_state);
switch (new_state) {
case GAME_STATE_RUNNING:
dk_set_led_on(DK_LED1); // LED an wenn Spiel läuft
dk_set_led_on(DK_LED1); // LED on when game is running
break;
case GAME_STATE_FINISHED:
dk_set_led_off(DK_LED1);
// Blinken oder ähnliches
// Blink or similar
break;
default:
dk_set_led_off(DK_LED1);
@@ -37,46 +37,46 @@ static void on_game_state_change(enum game_state new_state)
static void on_hit_received(uint16_t shooter_id)
{
LOG_WARN("APP: AUA! Getroffen von Spieler %d. Leben: %d", shooter_id, game.health);
LOG_WARN("APP: OUCH! Hit by player %d. Health: %d", shooter_id, game.health);
// Visuelles Feedback: LED 2 blinkt kurz
dk_set_led_on(DK_LED2);
k_msleep(200);
dk_set_led_off(DK_LED2);
// TODO: Hier später CoAP Nachricht an Leader senden!
// TODO: Send CoAP message to leader later!
// send_hit_report_to_leader(...);
}
static void on_shot_fired(void)
{
LOG_INF("APP: PENG! Schuss abgefeuert.");
// TODO: Hier IR-Protokoll senden (NEC/RC5)
LOG_INF("APP: BANG! Shot fired.");
// TODO: Send IR protocol here (NEC/RC5)
}
/* --- Hardware Callbacks --- */
static void on_button_changed(uint32_t button_state, uint32_t has_changed)
{
// Button 1: Schießen
// Button 1: Shoot
if ((has_changed & DK_BTN1_MSK) && (button_state & DK_BTN1_MSK)) {
if (game.current_state == GAME_STATE_RUNNING) {
on_shot_fired();
} else {
LOG_INF("Schuss blockiert - Spiel läuft nicht.");
LOG_INF("Shot blocked - game not running.");
}
}
// Button 2: Treffer simulieren (Self-Hit Test)
// Button 2: Simulate hit (Self-Hit Test)
if ((has_changed & DK_BTN2_MSK) && (button_state & DK_BTN2_MSK)) {
LOG_INF("Simuliere Treffer durch Spieler 99...");
LOG_INF("Simulating hit by player 99...");
struct game_hit_packet hit_packet;
// Wir tun so, als hätte der IR-Sensor Spieler 99 erkannt
// Pretend the IR sensor detected player 99
if (game_logic_register_hit(99, &hit_packet)) {
// Wenn Treffer gültig war (Spiel läuft, wir leben noch), haben wir jetzt ein Paket
// das wir via Thread versenden könnten.
LOG_INF("Treffer registriert! Damage: %d", hit_packet.damage);
// If hit was valid (game running, we're still alive), we now have a packet
// that we could send via Thread.
LOG_INF("Hit registered! Damage: %d", hit_packet.damage);
}
}
}
@@ -89,18 +89,18 @@ void main(void)
int err = dk_buttons_init(on_button_changed);
if (err) {
LOG_ERR("Buttons konnten nicht initialisiert werden (err %d)", err);
LOG_ERR("Buttons could not be initialized (err %d)", err);
}
// Game Logic Setup
game.on_state_change = on_game_state_change;
game.on_hit_received = on_hit_received;
// Initialisiere als Spieler mit ID aus Kconfig (oder NVS später)
// Initialize as player with ID from Kconfig (or NVS later)
game_logic_init(&game, CONFIG_LASERTAG_PLAYER_ID_DEFAULT);
// Zum Testen setzen wir den Status manuell auf RUNNING,
// bis wir das Start-Signal vom Leader via Thread empfangen.
// For testing, we manually set the status to RUNNING,
// until we receive the start signal from the leader via Thread.
struct game_state_packet fake_start = {.state = GAME_STATE_RUNNING};
game_logic_handle_state_update(&fake_start);

View File

@@ -15,6 +15,6 @@ CONFIG_LASERTAG_GAME_LOGIC=y
CONFIG_LASERTAG_ROLE_PLAYER=y
CONFIG_LASERTAG_PLAYER_ID_DEFAULT=2
# Optional: Shell für Debugging
# Optional: Shell for debugging
CONFIG_SHELL=y
CONFIG_OPENTHREAD_SHELL=y

View File

@@ -3,4 +3,4 @@
add_subdirectory(ble_mgmt)
add_subdirectory(thread_mgmt)
add_subdirectory(lasertag_utils)
add_subdirectory(ir_send)
add_subdirectory(ir)

View File

@@ -2,4 +2,4 @@
rsource "lasertag_utils/Kconfig"
rsource "thread_mgmt/Kconfig"
rsource "ble_mgmt/Kconfig"
rsource "ir_send/Kconfig"
rsource "ir/Kconfig"

View File

@@ -3,14 +3,25 @@
/**
* @file ble_mgmt.h
* @brief Bluetooth Low Energy management for provisioning.
* @brief Bluetooth Low Energy management for provisioning and game communication.
* This module handles Bluetooth initialization, advertising, and stopping advertising.
*/
/**
* @brief Device types for LaserTag devices.
*/
#define LT_TYPE_LEADER 0x01
#define LT_TYPE_WEAPON 0x02
#define LT_TYPE_VEST 0x03
#define LT_TYPE_BEACON 0x04
/**
* @brief Initialize Bluetooth and prepare services.
*
* @param device_type The type of the device (e.g., leader, weapon, vest, beacon).
* @return 0 on success.
*/
int ble_mgmt_init(void);
int ble_mgmt_init(uint8_t device_type);
/**
* @brief Start Bluetooth advertising so the web app can find the device.

View File

@@ -13,62 +13,83 @@
LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
/**
* Basis UUID: 03afe2cf-6c64-4a22-9289-c3ae820cXXXX
* Alias-Stellen: Byte 12 & 13
* Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cXXXX
* Alias positions: Byte 12 & 13
*/
#define LT_UUID_BASE_VAL \
BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c0000)
BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c0000)
/* ==========================================================================
SERVICE 1: PROVISIONING (0x10XX)
========================================================================== */
#define BT_UUID_LT_PROV_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1000))
#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_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_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_NODES_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c1007))
#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)
========================================================================== */
#define BT_UUID_LT_GAME_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2000))
#define BT_UUID_LT_GAME_SERVICE BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820c2000))
#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_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
/* --- GATT Callbacks --- */
static ssize_t read_lasertag_val(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
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_NAME_CHAR) == 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);
} else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_PANID_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_CHAN_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_EXTPAN_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_NETKEY_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NETKEY_CHAR) == 0)
{
val_ptr = (char *)lasertag_get_thread_network_key();
val_len = 16;
} else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NETNAME_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NETNAME_CHAR) == 0)
{
val_ptr = lasertag_get_thread_network_name();
val_len = strlen(val_ptr);
}
@@ -77,110 +98,138 @@ static ssize_t read_lasertag_val(struct bt_conn *conn, const struct bt_gatt_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)
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) {
if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NAME_CHAR) == 0)
{
rc = lasertag_set_device_name(buf, len);
} else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_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_PROV_EXTPAN_CHAR) == 0) {
if (len != 8) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_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_PROV_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_PROV_NETKEY_CHAR) == 0) {
if (len != 16) return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_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_PROV_NETNAME_CHAR) == 0) {
}
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NETNAME_CHAR) == 0)
{
rc = lasertag_set_thread_network_name(buf, len);
}
if (rc) return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
if (rc)
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
return len;
}
static ssize_t read_discovered_nodes(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
void *buf, uint16_t len, uint16_t offset)
{
const char *list = thread_mgmt_get_discovered_list();
return bt_gatt_attr_read(conn, attr, buf, len, offset, list, strlen(list));
}
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)
const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{
/* Wenn irgendwas geschrieben wird, triggere Discovery im Thread Mesh */
/* If anything is written, trigger discovery in Thread Mesh */
thread_mgmt_discover_nodes();
return len;
}
/* Service Definition */
BT_GATT_SERVICE_DEFINE(provisioning_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_PROV_SERVICE),
/* Gerätename */
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),
/* Thread PAN ID */
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),
BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_PROV_SERVICE),
/* Thread Kanal */
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),
/* Device name */
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),
/* Extended PAN ID */
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),
/* Device Type (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 */
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),
/* Netzwerk Key */
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 Channel */
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),
/* Thread Netzwerk Name */
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),
/* Extended PAN ID */
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),
/* Knoten-Liste / Discovery Trigger */
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),
);
/* Network Key */
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 */
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 */
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), );
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, 0xbc, 0x0c, 0x82, 0xae, 0xc3, 0x89, 0x92,
0x22, 0x4a, 0x64, 0x6c, 0xcf, 0xe2, 0xaf, 0x03),
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)),
};
int ble_mgmt_init(void)
int ble_mgmt_init(uint8_t device_type)
{
device_role = device_type;
int err = bt_enable(NULL);
if (err) return err;
LOG_INF("Bluetooth initialisiert");
if (err)
return err;
LOG_INF("Bluetooth initialized");
return 0;
}
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
const char *name = lasertag_get_device_name();
bt_set_name(name);
@@ -196,8 +245,9 @@ int ble_mgmt_adv_start(void)
};
int err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), dynamic_sd, ARRAY_SIZE(dynamic_sd));
if (!err) {
LOG_INF("Advertising gestartet als: %s", name);
if (!err)
{
LOG_INF("Advertising started as: %s, type: %d", name, device_role);
}
return err;
}
@@ -205,8 +255,9 @@ int ble_mgmt_adv_start(void)
int ble_mgmt_adv_stop(void)
{
int err = bt_le_adv_stop();
if (!err) {
LOG_INF("Advertising gestoppt");
if (!err)
{
LOG_INF("Advertising stopped");
}
return err;
}

View File

@@ -0,0 +1,2 @@
add_subdirectory(send)
add_subdirectory(recv)

73
firmware/libs/ir/Kconfig Normal file
View File

@@ -0,0 +1,73 @@
menu "IR protocol"
config IR_PROTO
bool "IR protocol core"
help
Enable shared IR protocol settings used by send/receive libraries.
if IR_PROTO
menu "IR protocol configuration"
config IR_SEND_CARRIER_HZ
int "IR carrier frequency (Hz)"
default 38000
range 30000 45000
help
Carrier frequency for PWM generation. Standard value is 38 kHz for TSOP48xx receivers.
config IR_SEND_DUTY_CYCLE_PERCENT
int "Carrier duty cycle (%)"
default 50
range 25 75
help
PWM duty cycle percentage. Some receivers prefer 33%, others 50%.
Default 50% works with most TSOP-series receivers.
config IR_PROTO_BASE_US
int "IR base period (microseconds)"
default 600
range 300 1000
help
Base timing used for start/mark/space. Default 600 µs (similar to Sony SIRC).
config IR_PROTO_START_MULT
int "Start burst factor"
default 4
range 2 8
help
Start burst duration = base × factor. Default 4× for robust sync.
config IR_PROTO_GAP_MULT
int "Start gap factor"
default 1
range 0 4
help
Gap after start burst (carrier off) = base × factor. 0 disables the gap.
config IR_PROTO_MARK_MULT
int "Mark factor"
default 1
range 1 2
help
Mark duration = base × factor. Default 1×.
config IR_PROTO_SPACE0_MULT
int "Space0 factor (bit 0)"
default 1
range 1 3
help
Space for bit 0 = base × factor. Default 1×.
config IR_PROTO_SPACE1_MULT
int "Space1 factor (bit 1)"
default 2
range 1 4
help
Space for bit 1 = base × factor. Default 2× (double base time).
endmenu
endif
endmenu

View File

@@ -0,0 +1,5 @@
if(CONFIG_IR_RECV)
zephyr_library()
zephyr_sources(src/ir_recv.c)
zephyr_include_directories(include)
endif()

View File

@@ -0,0 +1,6 @@
config IR_RECV
bool "IR Receive Library"
select IR_PROTO
help
Enable IR receive library for the laser tag system.
Placeholder implementation; timing parameters come from IR_PROTO.*

View File

@@ -0,0 +1,14 @@
#ifndef IR_RECV_H
#define IR_RECV_H
#include <zephyr/device.h>
/**
* @brief Initialize IR receive pipeline (stub).
*
* Intended to configure GPIO/interrupts/ppi for future implementation.
* @return 0 on success, negative errno otherwise.
*/
int ir_recv_init(void);
#endif /* IR_RECV_H */

View File

@@ -0,0 +1,12 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include "ir_recv.h"
LOG_MODULE_REGISTER(ir_recv, LOG_LEVEL_INF);
int ir_recv_init(void)
{
LOG_INF("IR receive stub initialized (no implementation yet)");
return 0;
}

View File

@@ -0,0 +1,6 @@
config IR_SEND
bool "IR Send Library"
select IR_PROTO
help
Enable IR transmission library for laser tag system.
Provides PWM-based IR carrier generation with pulse-distance coding.

View File

@@ -24,37 +24,47 @@ config IR_SEND_DUTY_CYCLE_PERCENT
PWM duty cycle percentage. Some receivers prefer 33%, others 50%.
Default 50% works with most TSOP-series receivers.
config IR_SEND_MARK_US
int "Mark duration (microseconds)"
config IR_PROTO_BASE_US
int "IR Basistakt (Mikrosekunden)"
default 600
range 300 1000
help
Duration of carrier burst (mark) for each bit. Standard is 600 µs
following Sony SIRC timing.
Gemeinsamer Basistakt für Mark/Space/Start. Standard 600 µs (Sony SIRC ähnlich).
config IR_SEND_SPACE0_US
int "Space duration for bit 0 (microseconds)"
default 600
range 300 1000
config IR_PROTO_START_MULT
int "Startburst Faktor"
default 4
range 2 8
help
Carrier-off duration (space) after mark for logical 0.
Default 600 µs creates 1.2 ms total bit time.
Startburst-Dauer = Basistakt × Faktor. Standard 4× zur sicheren Synchronisation.
config IR_SEND_SPACE1_US
int "Space duration for bit 1 (microseconds)"
default 1200
range 800 2000
config IR_PROTO_GAP_MULT
int "Start-Gap Faktor"
default 1
range 0 4
help
Carrier-off duration (space) after mark for logical 1.
Default 1200 µs creates 1.8 ms total bit time.
Gap nach Startburst (Träger AUS) = Basistakt × Faktor. 0 deaktiviert Gap.
config IR_SEND_START_BURST_US
int "Start burst duration (microseconds)"
default 2400
range 1500 4000
config IR_PROTO_MARK_MULT
int "Mark Faktor"
default 1
range 1 2
help
Initial synchronization burst at frame start. Receivers detect
this to sync on incoming frames. Default 2400 µs = 4× mark time.
Mark-Dauer = Basistakt × Faktor. Standard 1×.
config IR_PROTO_SPACE0_MULT
int "Space0 Faktor (Bit 0)"
default 1
range 1 3
help
Space für Bit 0 = Basistakt × Faktor. Standard 1×.
config IR_PROTO_SPACE1_MULT
int "Space1 Faktor (Bit 1)"
default 2
range 1 4
help
Space für Bit 1 = Basistakt × Faktor. Standard 2× (doppelte Basiszeit).
endmenu

View File

@@ -49,4 +49,48 @@ const uint8_t* lasertag_get_thread_ext_pan_id(void);
*/
const uint8_t* lasertag_get_thread_network_key(void);
/**
* @brief Set the device name.
* @param name Pointer to the name string.
* @param len Length of the name.
* @return 0 on success, negative error code otherwise.
*/
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 */

View File

@@ -155,9 +155,9 @@ static int cmd_thread_set_chan(const struct shell *sh, size_t argc, char **argv)
}
SHELL_STATIC_SUBCMD_SET_CREATE(sub_thread,
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_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_CMD(ping, NULL, "Send multicast ping", cmd_thread_ping),
SHELL_SUBCMD_SET_END
);
@@ -171,8 +171,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_ble,
);
SHELL_STATIC_SUBCMD_SET_CREATE(sub_lasertag,
SHELL_CMD_ARG(name, NULL, "Name setzen", cmd_name_set, 2, 0),
SHELL_CMD(thread, &sub_thread, "Thread Konfiguration", NULL),
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

View File

@@ -4,22 +4,22 @@
#include <stdint.h>
/**
* @brief Initialisiert den OpenThread-Stack, UDP und CoAP.
* @brief Initializes the OpenThread stack, UDP and CoAP.
*/
int thread_mgmt_init(void);
/**
* @brief Sendet eine UDP-Nachricht.
* @brief Sends a UDP message.
*/
int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len);
/**
* @brief Startet die Gerätesuche via CoAP Multicast.
* @brief Starts device discovery via CoAP Multicast.
*/
int thread_mgmt_discover_nodes(void);
/**
* @brief Gibt die Liste der entdeckten Knotennamen zurück (kommagetrennt).
* @brief Returns the list of discovered node names (comma-separated).
*/
const char* thread_mgmt_get_discovered_list(void);

View File

@@ -33,7 +33,7 @@ static void coap_id_handler(void *context, otMessage *message, const otMessageIn
return;
}
LOG_INF("CoAP GET /id empfangen");
LOG_INF("CoAP GET /id received");
response = otCoapNewMessage(instance, NULL);
if (response == NULL) return;
@@ -79,9 +79,9 @@ static void coap_discover_res_handler(void *context, otMessage *message, const o
char addr_str[OT_IP6_ADDRESS_STRING_SIZE];
otIp6AddressToString(&message_info->mPeerAddr, addr_str, sizeof(addr_str));
LOG_INF("Node entdeckt: %s (%s)", name_buf, addr_str);
LOG_INF("Node discovered: %s (%s)", name_buf, addr_str);
/* Zur Liste hinzufügen (einfaches CSV Format für BLE) */
/* Add to list (simple CSV format for BLE) */
if (node_count < MAX_DISCOVERED_NODES && !strstr(discovered_nodes_list, name_buf)) {
if (node_count > 0) strcat(discovered_nodes_list, ",");
strcat(discovered_nodes_list, name_buf);
@@ -96,7 +96,7 @@ int thread_mgmt_discover_nodes(void)
otMessageInfo message_info;
otError error = OT_ERROR_NONE;
/* Liste zurücksetzen */
/* Reset list */
discovered_nodes_list[0] = '\0';
node_count = 0;
@@ -116,7 +116,7 @@ int thread_mgmt_discover_nodes(void)
return -EIO;
}
LOG_INF("Discovery gestartet...");
LOG_INF("Discovery started...");
return 0;
}
@@ -164,7 +164,7 @@ int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len)
otMessageAppend(message, payload, len);
otUdpSend(instance, &s_udp_socket, message, &message_info);
LOG_INF("UDP gesendet an %s", addr_str);
LOG_INF("UDP sent to %s", addr_str);
return 0;
}
@@ -211,6 +211,6 @@ int thread_mgmt_init(void)
s_id_resource.mContext = instance;
otCoapAddResource(instance, &s_id_resource);
LOG_INF("Thread MGMT: Initialisiert, UDP %d & CoAP %d offen.", UDP_PORT, OT_DEFAULT_COAP_PORT);
LOG_INF("Thread MGMT: Initialized, UDP %d & CoAP %d open.", UDP_PORT, OT_DEFAULT_COAP_PORT);
return 0;
}