vor ble umbau
This commit is contained in:
5
firmware/libs/ble_mgmt/CMakeLists.txt
Normal file
5
firmware/libs/ble_mgmt/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
if(CONFIG_BLE_MGMT)
|
||||
zephyr_library()
|
||||
zephyr_library_sources(src/ble_mgmt.c)
|
||||
zephyr_include_directories(include)
|
||||
endif()
|
||||
62
firmware/libs/ble_mgmt/Kconfig
Normal file
62
firmware/libs/ble_mgmt/Kconfig
Normal file
@@ -0,0 +1,62 @@
|
||||
menuconfig BLE_MGMT
|
||||
bool "Bluetooth Management"
|
||||
select BT
|
||||
select BT_PERIPHERAL
|
||||
select BT_LOG_LEVEL_WARN
|
||||
select BT_DEVICE_NAME_DYNAMIC
|
||||
help
|
||||
Library for initializing and managing Bluetooth functionality.
|
||||
|
||||
if BLE_MGMT
|
||||
config BLE_MGMT_DEFAULT_DEVICE_NAME
|
||||
string "Default Bluetooth Device Name"
|
||||
default "Edis Buzzer"
|
||||
config BLE_MGMT_ADV_INT_MIN
|
||||
int "Minimum Advertising Interval (in 0.625 ms units)"
|
||||
default 160
|
||||
help
|
||||
Minimal advertising interval. 160 equals to 100ms.
|
||||
config BLE_MGMT_ADV_INT_MAX
|
||||
int "Maximum Advertising Interval (ms)"
|
||||
default 160
|
||||
help
|
||||
Maximal advertising interval. 160 equals to 100ms.
|
||||
|
||||
# 1. MTU und Data Length (Maximale Paketgrößen)
|
||||
config BT_L2CAP_TX_MTU
|
||||
default 247
|
||||
config BT_BUF_ACL_RX_SIZE
|
||||
default 251
|
||||
config BT_BUF_ACL_TX_SIZE
|
||||
default 251
|
||||
config BT_CTLR_DATA_LENGTH_MAX
|
||||
default 251
|
||||
config BT_USER_DATA_LEN_UPDATE
|
||||
default y
|
||||
|
||||
# 2. Physical Layer (Erlaubt 2M PHY)
|
||||
config BT_USER_PHY_UPDATE
|
||||
default y
|
||||
|
||||
# 3. Flow-Control und Queues (High Throughput, Host + SDC Controller synchronisiert)
|
||||
config BT_HCI_ACL_FLOW_CONTROL
|
||||
default y
|
||||
config BT_BUF_EVT_RX_COUNT
|
||||
default 22
|
||||
config BT_BUF_ACL_TX_COUNT
|
||||
default 20
|
||||
config BT_L2CAP_TX_BUF_COUNT
|
||||
default 20
|
||||
config BT_CONN_TX_MAX
|
||||
default 20
|
||||
|
||||
# 4. SDC Controller Buffering (an Host-Tiefen angeglichen)
|
||||
config BT_CTLR_SDC_TX_PACKET_COUNT
|
||||
default 20
|
||||
config BT_CTLR_SDC_RX_PACKET_COUNT
|
||||
default 20
|
||||
|
||||
module = BLE_MGMT
|
||||
module-str = ble_mgmt
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
endif # BLE_MGMT
|
||||
38
firmware/libs/ble_mgmt/include/ble_mgmt.h
Normal file
38
firmware/libs/ble_mgmt/include/ble_mgmt.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef BLE_MGMT_H
|
||||
#define BLE_MGMT_H
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
typedef void (*ble_mgmt_rx_cb_t)(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Initializes the BLE management module, sets up the GATT service and starts advertising.
|
||||
* @param rx_cb Callback function to handle received data from the central device.
|
||||
* @param device_name Optional custom device name for advertising. If NULL, a default name is used.
|
||||
* @return 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int ble_mgmt_init(ble_mgmt_rx_cb_t rx_cb, const char *device_name);
|
||||
|
||||
/**
|
||||
* Sends data to the connected central device via a GATT characteristic.
|
||||
* @param data Pointer to the data buffer to send.
|
||||
* @param len Length of the data in bytes.
|
||||
* @return 0 on success, -EACCES if notifications are not enabled, or a negative error code on failure.
|
||||
*/
|
||||
int ble_mgmt_send(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Updates the advertised device name and restarts advertising with the new name.
|
||||
* @param new_name The new device name to advertise.
|
||||
* @return 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int ble_mgmt_update_adv_name(const char *new_name);
|
||||
|
||||
/**
|
||||
* Retrieves the maximum payload size that can be sent in a single notification.
|
||||
* This is determined by the current ATT MTU size minus the GATT header overhead.
|
||||
* @return The maximum payload size in bytes.
|
||||
*/
|
||||
uint16_t ble_mgmt_get_max_payload(void);
|
||||
|
||||
#endif // BLE_MGMT_H
|
||||
258
firmware/libs/ble_mgmt/src/ble_mgmt.c
Normal file
258
firmware/libs/ble_mgmt/src/ble_mgmt.c
Normal file
@@ -0,0 +1,258 @@
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ble_mgmt.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
|
||||
|
||||
#define BUZZ_SERVICE_UUID_VAL \
|
||||
BT_UUID_128_ENCODE(0xe517d988, 0xbab5, 0x4574, 0x8479, 0x97c6cb115ca0)
|
||||
#define BUZZ_RX_UUID_VAL \
|
||||
BT_UUID_128_ENCODE(0xe517d988, 0xbab5, 0x4574, 0x8479, 0x97c6cb115ca1)
|
||||
#define BUZZ_TX_UUID_VAL \
|
||||
BT_UUID_128_ENCODE(0xe517d988, 0xbab5, 0x4574, 0x8479, 0x97c6cb115ca2)
|
||||
|
||||
static struct bt_uuid_128 buzz_service_uuid = BT_UUID_INIT_128(BUZZ_SERVICE_UUID_VAL);
|
||||
static struct bt_uuid_128 buzz_rx_uuid = BT_UUID_INIT_128(BUZZ_RX_UUID_VAL);
|
||||
static struct bt_uuid_128 buzz_tx_uuid = BT_UUID_INIT_128(BUZZ_TX_UUID_VAL);
|
||||
|
||||
static ble_mgmt_rx_cb_t app_rx_cb = NULL;
|
||||
static bool notify_enabled = false;
|
||||
static uint16_t current_tx_mtu = 23;
|
||||
|
||||
#define MAX_ADV_NAME_LEN 29
|
||||
static char current_device_name[MAX_ADV_NAME_LEN + 1];
|
||||
|
||||
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, BUZZ_SERVICE_UUID_VAL),
|
||||
};
|
||||
|
||||
static struct bt_data sd[] = {
|
||||
BT_DATA(BT_DATA_NAME_COMPLETE, current_device_name, 0),
|
||||
};
|
||||
|
||||
static struct bt_le_adv_param adv_param = {
|
||||
.id = BT_ID_DEFAULT,
|
||||
.sid = 0,
|
||||
.secondary_max_skip = 0,
|
||||
.options = BT_LE_ADV_OPT_CONN,
|
||||
.interval_min = CONFIG_BLE_MGMT_ADV_INT_MIN,
|
||||
.interval_max = CONFIG_BLE_MGMT_ADV_INT_MAX,
|
||||
.peer = NULL,
|
||||
};
|
||||
|
||||
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
LOG_INF("MTU exchanged: TX %u bytes, RX %u bytes", tx, rx);
|
||||
current_tx_mtu = tx;
|
||||
}
|
||||
|
||||
static ssize_t rx_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
|
||||
{
|
||||
LOG_DBG("Received %u bytes", len);
|
||||
LOG_HEXDUMP_DBG(buf, len, "Data:");
|
||||
|
||||
if (app_rx_cb) {
|
||||
app_rx_cb((const uint8_t *)buf, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void tx_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||||
{
|
||||
notify_enabled = (value == BT_GATT_CCC_NOTIFY);
|
||||
LOG_DBG("Notifications %s", notify_enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
BT_GATT_SERVICE_DEFINE(ble_mgmt_svc,
|
||||
BT_GATT_PRIMARY_SERVICE(&buzz_service_uuid),
|
||||
BT_GATT_CHARACTERISTIC(&buzz_rx_uuid.uuid, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
|
||||
BT_GATT_PERM_WRITE, NULL, rx_cb, NULL),
|
||||
BT_GATT_CHARACTERISTIC(&buzz_tx_uuid.uuid, BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_NONE, NULL, NULL, NULL),
|
||||
BT_GATT_CCC(tx_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
|
||||
);
|
||||
|
||||
uint16_t ble_mgmt_get_max_payload(void)
|
||||
{
|
||||
/* Kappe die verhandelte MTU auf die hart konfigurierte Zephyr-Puffergrenze */
|
||||
uint16_t effective_mtu = current_tx_mtu;
|
||||
|
||||
#ifdef CONFIG_BT_L2CAP_TX_MTU
|
||||
if (effective_mtu > CONFIG_BT_L2CAP_TX_MTU) {
|
||||
effective_mtu = CONFIG_BT_L2CAP_TX_MTU;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 3 Bytes abziehen für den GATT Notification Overhead */
|
||||
return (effective_mtu > 3) ? (effective_mtu - 3) : 20;
|
||||
}
|
||||
|
||||
int ble_mgmt_send(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!notify_enabled) {
|
||||
return -EACCES;
|
||||
}
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = bt_gatt_notify(NULL, &ble_mgmt_svc.attrs[4], data, len);
|
||||
if (rc == -ENOMEM) {
|
||||
k_sleep(K_MSEC(5)); // Thread pausieren, bis TX-Buffer frei wird
|
||||
}
|
||||
} while (rc == -ENOMEM);
|
||||
|
||||
if (rc) {
|
||||
LOG_ERR("Failed to send notification (err %d)", rc);
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Interne Hilfsfunktion zur Zuweisung des Namens */
|
||||
static void set_device_name(const char *name)
|
||||
{
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(current_device_name, name, MAX_ADV_NAME_LEN);
|
||||
current_device_name[MAX_ADV_NAME_LEN] = '\0';
|
||||
|
||||
/* Längen-Update im Scan-Response Array */
|
||||
sd[0].data_len = strlen(current_device_name);
|
||||
|
||||
#ifdef CONFIG_BT_DEVICE_NAME_DYNAMIC
|
||||
/* Setzt den Namen parallel im Zephyr GAP-Service (wichtig für macOS) */
|
||||
bt_set_name(current_device_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ble_mgmt_update_adv_name(const char *new_name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
bt_le_adv_stop();
|
||||
set_device_name(new_name);
|
||||
|
||||
rc = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
|
||||
if (rc) {
|
||||
LOG_ERR("Advertising failed to restart after name update (err %d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
LOG_INF("Advertising updated. New Name: %s", current_device_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mgmt_init(ble_mgmt_rx_cb_t rx_cb, const char *device_name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
app_rx_cb = rx_cb;
|
||||
|
||||
static struct bt_gatt_cb gatt_callbacks = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
bt_gatt_cb_register(&gatt_callbacks);
|
||||
|
||||
rc = bt_enable(NULL);
|
||||
if (rc) {
|
||||
LOG_ERR("Bluetooth init failed (err %d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char *name_to_use = (device_name != NULL) ? device_name : CONFIG_BLE_MGMT_DEFAULT_DEVICE_NAME;
|
||||
set_device_name(name_to_use);
|
||||
|
||||
rc = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
|
||||
if (rc) {
|
||||
LOG_ERR("Advertising failed to start (err %d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
LOG_INF("Bluetooth initialized. Adv-Name: %s", current_device_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t err)
|
||||
{
|
||||
if (err) {
|
||||
LOG_ERR("Connection failed (err 0x%02x)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
struct bt_conn_info info;
|
||||
|
||||
int rc = bt_conn_get_info(conn, &info);
|
||||
if (rc == 0) {
|
||||
bt_addr_le_to_str(info.le.dst, addr_str, sizeof(addr_str));
|
||||
LOG_INF("Connected to %s", addr_str);
|
||||
|
||||
/* Nur noch die Rolle ausgeben, da Timing-Parameter hier deprecated sind */
|
||||
LOG_DBG("Role: %s", info.role == BT_CONN_ROLE_CENTRAL ? "Central" : "Peripheral");
|
||||
} else {
|
||||
LOG_INF("Connected (info retrieval failed)");
|
||||
}
|
||||
struct bt_conn_le_phy_param phy_param = {
|
||||
.options = BT_CONN_LE_PHY_OPT_NONE,
|
||||
.pref_tx_phy = BT_GAP_LE_PHY_2M,
|
||||
.pref_rx_phy = BT_GAP_LE_PHY_2M,
|
||||
};
|
||||
rc = bt_conn_le_phy_update(conn, &phy_param);
|
||||
if (rc) {
|
||||
LOG_WRN("PHY update failed (err %d)", rc);
|
||||
}
|
||||
struct bt_le_conn_param *param = BT_LE_CONN_PARAM(12, 24, 0, 400);
|
||||
rc = bt_conn_le_param_update(conn, param);
|
||||
if (rc) {
|
||||
LOG_WRN("Connection update failed (err %d)", rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
LOG_DBG("Disconnected (reason 0x%02x)", reason);
|
||||
|
||||
/* Startet Advertising mit dem global definierten Setup neu */
|
||||
int rc = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
|
||||
if (rc) {
|
||||
LOG_ERR("Advertising failed to restart (err %d)", rc);
|
||||
} else {
|
||||
LOG_DBG("Advertising successfully restarted");
|
||||
}
|
||||
}
|
||||
|
||||
static void le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param)
|
||||
{
|
||||
const char *tx_phy_str = (param->tx_phy == BT_GAP_LE_PHY_2M) ? "2M" :
|
||||
(param->tx_phy == BT_GAP_LE_PHY_1M) ? "1M" : "Coded/Unknown";
|
||||
const char *rx_phy_str = (param->rx_phy == BT_GAP_LE_PHY_2M) ? "2M" :
|
||||
(param->rx_phy == BT_GAP_LE_PHY_1M) ? "1M" : "Coded/Unknown";
|
||||
|
||||
LOG_INF("LE PHY updated: TX PHY %s, RX PHY %s", tx_phy_str, rx_phy_str);
|
||||
}
|
||||
|
||||
static void le_param_updated(struct bt_conn *conn, uint16_t interval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
{
|
||||
LOG_INF("Connection parameters updated: Interval: %u, Latency: %u, Timeout: %u",
|
||||
interval, latency, timeout);
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.le_param_updated = le_param_updated,
|
||||
.le_phy_updated = le_phy_updated,
|
||||
};
|
||||
Reference in New Issue
Block a user