This commit is contained in:
@@ -24,6 +24,9 @@ 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
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <lasertag_utils.h>
|
||||
#include <thread_mgmt.h>
|
||||
#include <ble_mgmt.h>
|
||||
|
||||
LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
|
||||
|
||||
/**
|
||||
* Base UUID: 03afe2cf-6c64-4a22-9289-c3ae820cbcxx
|
||||
* Basis UUID: 03afe2cf-6c64-4a22-9289-c3ae820cbcxx
|
||||
*/
|
||||
#define LT_UUID_BASE_VAL \
|
||||
BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc00)
|
||||
@@ -24,6 +25,7 @@ LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
|
||||
#define BT_UUID_LT_EXTPAN_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc04))
|
||||
#define BT_UUID_LT_NETKEY_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc05))
|
||||
#define BT_UUID_LT_NETNAME_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc06))
|
||||
#define BT_UUID_LT_NODES_CHAR BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x03afe2cf, 0x6c64, 0x4a22, 0x9289, 0xc3ae820cbc07))
|
||||
|
||||
/* --- GATT Callbacks --- */
|
||||
|
||||
@@ -86,39 +88,66 @@ static ssize_t write_lasertag_val(struct bt_conn *conn, const struct bt_gatt_att
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Wenn irgendwas geschrieben wird, triggere Discovery im Thread Mesh */
|
||||
thread_mgmt_discover_nodes();
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Service Definition */
|
||||
BT_GATT_SERVICE_DEFINE(provisioning_svc,
|
||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_LT_SERVICE),
|
||||
|
||||
/* Gerätename */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_NAME_CHAR,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
|
||||
read_lasertag_val, write_lasertag_val, NULL),
|
||||
|
||||
/* Thread PAN ID */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_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 Kanal */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_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 */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_EXTPAN_CHAR,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
|
||||
read_lasertag_val, write_lasertag_val, NULL),
|
||||
|
||||
/* Netzwerk Key */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_NETKEY_CHAR,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
|
||||
read_lasertag_val, write_lasertag_val, NULL),
|
||||
|
||||
/* Thread Netzwerk Name */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_NETNAME_CHAR,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
|
||||
read_lasertag_val, write_lasertag_val, NULL),
|
||||
|
||||
/* Knoten-Liste / Discovery Trigger */
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_LT_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 const struct bt_data ad[] = {
|
||||
@@ -132,7 +161,7 @@ int ble_mgmt_init(void)
|
||||
{
|
||||
int err = bt_enable(NULL);
|
||||
if (err) return err;
|
||||
LOG_INF("Bluetooth initialized");
|
||||
LOG_INF("Bluetooth initialisiert");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -154,7 +183,7 @@ 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 started as: %s", name);
|
||||
LOG_INF("Advertising gestartet als: %s", name);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -163,7 +192,7 @@ int ble_mgmt_adv_stop(void)
|
||||
{
|
||||
int err = bt_le_adv_stop();
|
||||
if (!err) {
|
||||
LOG_INF("Advertising stopped");
|
||||
LOG_INF("Advertising gestoppt");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -1,17 +1,26 @@
|
||||
#ifndef THREAD_MGMT_H
|
||||
#define THREAD_MGMT_H
|
||||
|
||||
/**
|
||||
* @file thread_mgmt.h
|
||||
* @brief Thread network management and stack initialization.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize the OpenThread stack with parameters from NVS.
|
||||
* * This function configures the operational dataset (Network Name,
|
||||
* PAN ID, Key, etc.) and starts the Thread interface.
|
||||
* * @return 0 on success, negative error code otherwise.
|
||||
* @brief Initialisiert den OpenThread-Stack, UDP und CoAP.
|
||||
*/
|
||||
int thread_mgmt_init(void);
|
||||
|
||||
#endif /* THREAD_MGMT_H */
|
||||
/**
|
||||
* @brief Sendet eine UDP-Nachricht.
|
||||
*/
|
||||
int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Startet die Gerätesuche via CoAP Multicast.
|
||||
*/
|
||||
int thread_mgmt_discover_nodes(void);
|
||||
|
||||
/**
|
||||
* @brief Gibt die Liste der entdeckten Knotennamen zurück (kommagetrennt).
|
||||
*/
|
||||
const char* thread_mgmt_get_discovered_list(void);
|
||||
|
||||
#endif
|
||||
@@ -5,28 +5,133 @@
|
||||
#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>
|
||||
|
||||
LOG_MODULE_REGISTER(thread_mgmt, CONFIG_THREAD_MGMT_LOG_LEVEL);
|
||||
|
||||
#define UDP_PORT 1234
|
||||
#define MAX_DISCOVERED_NODES 10
|
||||
|
||||
static otUdpSocket s_udp_socket;
|
||||
static char discovered_nodes_list[256] = "";
|
||||
static uint8_t node_count = 0;
|
||||
|
||||
/* --- CoAP Server Logik --- */
|
||||
|
||||
static void coap_id_handler(void *context, otMessage *message, const otMessageInfo *message_info)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMessage *response;
|
||||
otInstance *instance = (otInstance *)context;
|
||||
|
||||
if (otCoapMessageGetCode(message) != OT_COAP_CODE_GET) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INF("CoAP GET /id empfangen");
|
||||
|
||||
response = otCoapNewMessage(instance, NULL);
|
||||
if (response == NULL) return;
|
||||
|
||||
otCoapMessageInitResponse(response, message, OT_COAP_TYPE_ACKNOWLEDGMENT, OT_COAP_CODE_CONTENT);
|
||||
otCoapMessageSetPayloadMarker(response);
|
||||
|
||||
const char *name = lasertag_get_device_name();
|
||||
error = otMessageAppend(response, name, strlen(name));
|
||||
if (error != OT_ERROR_NONE) {
|
||||
otMessageFree(response);
|
||||
return;
|
||||
}
|
||||
|
||||
error = otCoapSendResponse(instance, response, message_info);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
otMessageFree(response);
|
||||
}
|
||||
}
|
||||
|
||||
static otCoapResource s_id_resource = {
|
||||
.mUriPath = "id",
|
||||
.mHandler = coap_id_handler,
|
||||
.mContext = NULL,
|
||||
.mNext = NULL
|
||||
};
|
||||
|
||||
/* --- CoAP Discovery Client Logik --- */
|
||||
|
||||
static void coap_discover_res_handler(void *context, otMessage *message, const otMessageInfo *message_info, otError result)
|
||||
{
|
||||
if (result != OT_ERROR_NONE || otCoapMessageGetCode(message) != OT_COAP_CODE_CONTENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
char name_buf[32];
|
||||
uint16_t length = otMessageGetLength(message) - otMessageGetOffset(message);
|
||||
if (length > sizeof(name_buf) - 1) length = sizeof(name_buf) - 1;
|
||||
|
||||
otMessageRead(message, otMessageGetOffset(message), name_buf, length);
|
||||
name_buf[length] = '\0';
|
||||
|
||||
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);
|
||||
|
||||
/* Zur Liste hinzufügen (einfaches CSV Format für 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);
|
||||
node_count++;
|
||||
}
|
||||
}
|
||||
|
||||
int thread_mgmt_discover_nodes(void)
|
||||
{
|
||||
otInstance *instance = openthread_get_default_instance();
|
||||
otMessage *message;
|
||||
otMessageInfo message_info;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
/* Liste zurücksetzen */
|
||||
discovered_nodes_list[0] = '\0';
|
||||
node_count = 0;
|
||||
|
||||
message = otCoapNewMessage(instance, NULL);
|
||||
if (message == NULL) return -ENOMEM;
|
||||
|
||||
otCoapMessageInit(message, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_GET);
|
||||
otCoapMessageAppendUriPathOptions(message, "id");
|
||||
|
||||
memset(&message_info, 0, sizeof(message_info));
|
||||
otIp6AddressFromString("ff03::1", &message_info.mPeerAddr);
|
||||
message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
|
||||
|
||||
error = otCoapSendRequest(instance, message, &message_info, coap_discover_res_handler, NULL);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
otMessageFree(message);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("Discovery gestartet...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* thread_mgmt_get_discovered_list(void)
|
||||
{
|
||||
return discovered_nodes_list;
|
||||
}
|
||||
|
||||
/* --- UDP & Init --- */
|
||||
|
||||
/**
|
||||
* @brief Callback für empfangene UDP-Nachrichten.
|
||||
*/
|
||||
static void udp_receive_cb(void *context, otMessage *message, const otMessageInfo *message_info)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
uint16_t length = otMessageGetLength(message) - otMessageGetOffset(message);
|
||||
|
||||
if (length > sizeof(buf) - 1) {
|
||||
length = sizeof(buf) - 1;
|
||||
}
|
||||
if (length > sizeof(buf) - 1) length = sizeof(buf) - 1;
|
||||
|
||||
int read = otMessageRead(message, otMessageGetOffset(message), buf, length);
|
||||
buf[read] = '\0';
|
||||
@@ -34,7 +139,6 @@ static void udp_receive_cb(void *context, otMessage *message, const otMessageInf
|
||||
char addr_str[OT_IP6_ADDRESS_STRING_SIZE];
|
||||
otIp6AddressToString(&message_info->mPeerAddr, addr_str, sizeof(addr_str));
|
||||
|
||||
/* Deutliche Log-Ausgabe für das Testen */
|
||||
LOG_INF("------------------------------------------");
|
||||
LOG_INF("UDP DATA RECEIVED!");
|
||||
LOG_INF("From: [%s]", addr_str);
|
||||
@@ -45,7 +149,6 @@ static void udp_receive_cb(void *context, otMessage *message, const otMessageInf
|
||||
int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len)
|
||||
{
|
||||
struct otInstance *instance = openthread_get_default_instance();
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMessage *message;
|
||||
otMessageInfo message_info;
|
||||
|
||||
@@ -58,20 +161,10 @@ int thread_mgmt_send_udp(const char *addr_str, uint8_t *payload, uint16_t len)
|
||||
message = otUdpNewMessage(instance, NULL);
|
||||
if (message == NULL) return -ENOMEM;
|
||||
|
||||
error = otMessageAppend(message, payload, len);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
otMessageFree(message);
|
||||
return -EIO;
|
||||
}
|
||||
otMessageAppend(message, payload, len);
|
||||
otUdpSend(instance, &s_udp_socket, message, &message_info);
|
||||
|
||||
error = otUdpSend(instance, &s_udp_socket, message, &message_info);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
otMessageFree(message);
|
||||
LOG_ERR("UDP Senden fehlgeschlagen (err %d)", error);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("UDP gesendet an %s: %d Bytes", addr_str, len);
|
||||
LOG_INF("UDP gesendet an %s", addr_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -79,73 +172,45 @@ int thread_mgmt_init(void)
|
||||
{
|
||||
struct otInstance *instance = openthread_get_default_instance();
|
||||
otOperationalDataset dataset;
|
||||
otError error;
|
||||
|
||||
if (!instance) {
|
||||
LOG_ERR("OpenThread Instanz nicht gefunden");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!instance) return -ENODEV;
|
||||
|
||||
LOG_INF("Thread stack wird konfiguriert...");
|
||||
|
||||
/* Dataset-Struktur initialisieren */
|
||||
/* Dataset Setup */
|
||||
memset(&dataset, 0, sizeof(otOperationalDataset));
|
||||
|
||||
/* 0. Active Timestamp - Wichtig für die Netzwerksynchronisation */
|
||||
dataset.mActiveTimestamp.mSeconds = 1;
|
||||
dataset.mComponents.mIsActiveTimestampPresent = true;
|
||||
|
||||
/* 1. Netzwerkname */
|
||||
|
||||
const char *net_name = lasertag_get_thread_network_name();
|
||||
memcpy(dataset.mNetworkName.m8, net_name, strlen(net_name));
|
||||
dataset.mComponents.mIsNetworkNamePresent = true;
|
||||
|
||||
/* 2. PAN ID */
|
||||
dataset.mPanId = lasertag_get_thread_pan_id();
|
||||
dataset.mComponents.mIsPanIdPresent = true;
|
||||
|
||||
/* 3. Kanal */
|
||||
dataset.mChannel = lasertag_get_thread_channel();
|
||||
dataset.mComponents.mIsChannelPresent = true;
|
||||
|
||||
/* 4. Extended PAN ID */
|
||||
memcpy(dataset.mExtendedPanId.m8, lasertag_get_thread_ext_pan_id(), 8);
|
||||
dataset.mComponents.mIsExtendedPanIdPresent = true;
|
||||
|
||||
/* 5. Netzwerk Key */
|
||||
memcpy(dataset.mNetworkKey.m8, lasertag_get_thread_network_key(), 16);
|
||||
dataset.mComponents.mIsNetworkKeyPresent = true;
|
||||
|
||||
/* 6. Mesh Local Prefix */
|
||||
uint8_t ml_prefix[] = {0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00};
|
||||
memcpy(dataset.mMeshLocalPrefix.m8, ml_prefix, 8);
|
||||
dataset.mComponents.mIsMeshLocalPrefixPresent = true;
|
||||
|
||||
/* Dataset aktivieren */
|
||||
otDatasetSetActive(instance, &dataset);
|
||||
|
||||
/* Interface und Stack starten */
|
||||
otIp6SetEnabled(instance, true);
|
||||
otThreadSetEnabled(instance, true);
|
||||
|
||||
/* UDP Socket initialisieren */
|
||||
/* UDP Initialisierung */
|
||||
otSockAddr listen_addr;
|
||||
memset(&listen_addr, 0, sizeof(listen_addr));
|
||||
listen_addr.mPort = UDP_PORT;
|
||||
otUdpOpen(instance, &s_udp_socket, udp_receive_cb, NULL);
|
||||
otUdpBind(instance, &s_udp_socket, &listen_addr, OT_NETIF_UNSPECIFIED);
|
||||
|
||||
error = otUdpOpen(instance, &s_udp_socket, udp_receive_cb, NULL);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
LOG_ERR("UDP Socket konnte nicht geoeffnet werden (err %d)", error);
|
||||
return -EIO;
|
||||
}
|
||||
/* CoAP Initialisierung */
|
||||
otCoapStart(instance, OT_DEFAULT_COAP_PORT);
|
||||
s_id_resource.mContext = instance;
|
||||
otCoapAddResource(instance, &s_id_resource);
|
||||
|
||||
/* otUdpBind für SDK v3.2.1 mit 4 Argumenten */
|
||||
error = otUdpBind(instance, &s_udp_socket, &listen_addr, OT_NETIF_UNSPECIFIED);
|
||||
if (error != OT_ERROR_NONE) {
|
||||
LOG_ERR("UDP Bind fehlgeschlagen (err %d)", error);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("Thread MGMT: Initialisiert, UDP Port %d offen.", UDP_PORT);
|
||||
LOG_INF("Thread MGMT: Initialisiert, UDP %d & CoAP %d offen.", UDP_PORT, OT_DEFAULT_COAP_PORT);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user