add ble nus

This commit is contained in:
Tomasz Duda 2024-02-21 01:14:36 +01:00
parent 4df58663d7
commit 84959cc167
7 changed files with 237 additions and 16 deletions

View File

@ -40,16 +40,23 @@ void Logger::write_header_(int level, const char *tag, int line) {
const char *color = LOG_LEVEL_COLORS[level];
const char *letter = LOG_LEVEL_LETTERS[level];
#ifdef USE_ARDUINO
void *current_task = xTaskGetCurrentTaskHandle();
void * current_task = xTaskGetCurrentTaskHandle();
#elif defined(USE_ZEPHYR)
k_tid_t current_task = k_current_get();
#else
void * current_task = nullptr;
#endif
if (current_task == main_task_) {
#endif
this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line);
#ifdef USE_ARDUINO
} else {
this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line,
ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), pcTaskGetName(current_task), color);
}
#ifdef USE_ARDUINO
const char *thread_name = pcTaskGetName(current_task);
#elif defined(USE_ZEPHYR)
const char *thread_name = k_thread_name_get(current_task);
#endif
this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line,
ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), thread_name, color);
}
}
void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) { // NOLINT
@ -149,6 +156,8 @@ Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate
this->tx_buffer_ = new char[this->tx_buffer_size_ + 1]; // NOLINT
#ifdef USE_ARDUINO
this->main_task_ = xTaskGetCurrentTaskHandle();
#elif defined(USE_ZEPHYR)
this->main_task_ = k_current_get();
#endif
}

View File

@ -77,6 +77,9 @@ void Logger::pre_setup() {
#ifdef USE_ZEPHYR
void HOT Logger::write_msg_(const char *msg) {
#ifdef CONFIG_PRINTK
printk("%s\n", msg);
#endif
if (nullptr == uart_dev_) {
return;
}

View File

@ -0,0 +1,29 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
CONF_LOG,
)
from esphome.components.zephyr import zephyr_add_prj_conf
DEPENDENCIES = ["zephyr_ble_server"]
zephyr_ble_nus_ns = cg.esphome_ns.namespace("zephyr_ble_nus")
BLENUS = zephyr_ble_nus_ns.class_("BLENUS", cg.Component)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BLENUS),
cv.Optional(CONF_LOG, default=False): cv.boolean,
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_with_zephyr,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
zephyr_add_prj_conf("BT_NUS", True)
cg.add(var.set_expose_log(config[CONF_LOG]))
await cg.register_component(var, config)

View File

@ -0,0 +1,135 @@
#include "ble_nus.h"
#include <zephyr/kernel.h>
#include <bluetooth/services/nus.h>
#include "esphome/core/log.h"
#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#include "esphome/core/application.h"
#endif
namespace esphome {
namespace zephyr_ble_nus {
BLENUS *global_ble_nus; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static const char *const TAG = "zephyr_ble_nus";
size_t BLENUS::write_array(const uint8_t *data, size_t len) {
if (atomic_get(&tx_status_) == TX_DISABLED) {
return 0;
}
return ring_buf_put(&tx_ringbuf_, data, len);
}
void BLENUS::connected_(bt_conn *conn, uint8_t err) {
if (err == 0) {
global_ble_nus->conn_ = bt_conn_ref(conn);
}
}
void BLENUS::disconnected_(bt_conn *conn, uint8_t reason) {
bt_conn_unref(global_ble_nus->conn_);
global_ble_nus->conn_ = nullptr;
}
void BLENUS::tx_callback_(bt_conn *conn) {
atomic_cas(&global_ble_nus->tx_status_, TX_BUSY, TX_ENABLED);
ESP_LOGVV(TAG, "Sent operation completed");
}
void BLENUS::send_enabled_callback_(bt_nus_send_status status) {
switch (status) {
case BT_NUS_SEND_STATUS_ENABLED:
atomic_set(&global_ble_nus->tx_status_, TX_ENABLED);
#ifdef USE_LOGGER
App.schedule_dump_config();
#endif
ESP_LOGD(TAG, "NUS notification has been enabled");
break;
case BT_NUS_SEND_STATUS_DISABLED:
atomic_set(&global_ble_nus->tx_status_, TX_DISABLED);
ESP_LOGD(TAG, "NUS notification has been disabled");
break;
}
}
void BLENUS::rx_callback_(bt_conn *conn, const uint8_t *const data, uint16_t len) {
ESP_LOGD(TAG, "Received %d bytes.", len);
}
BLENUS::BLENUS(size_t buffer_size) {
uint8_t *buffer = new uint8_t[buffer_size];
ring_buf_init(&tx_ringbuf_, buffer_size, buffer);
}
void BLENUS::setup() {
bt_nus_cb callbacks = {
.received = rx_callback_,
.sent = tx_callback_,
.send_enabled = send_enabled_callback_,
};
bt_nus_init(&callbacks);
static bt_conn_cb conn_callbacks = {
.connected = BLENUS::connected_,
.disconnected = BLENUS::disconnected_,
};
bt_conn_cb_register(&conn_callbacks);
global_ble_nus = this;
#ifdef USE_LOGGER
if (logger::global_logger != nullptr && this->expose_log_) {
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
this->write_array(reinterpret_cast<const uint8_t *>(message), strlen(message));
});
}
#endif
}
void BLENUS::dump_config() {
ESP_LOGCONFIG(TAG, "ble nus:");
ESP_LOGCONFIG(TAG, " log: %s", YESNO(this->expose_log_));
}
void BLENUS::loop() {
if (ring_buf_is_empty(&tx_ringbuf_)) {
return;
}
if (!atomic_cas(&tx_status_, TX_ENABLED, TX_BUSY)) {
ring_buf_reset(&tx_ringbuf_);
return;
}
bt_conn *conn = bt_conn_ref(conn_);
if (nullptr == conn) {
atomic_cas(&tx_status_, TX_BUSY, TX_ENABLED);
return;
}
uint32_t req_len = bt_nus_get_mtu(conn);
uint8_t *buf;
uint32_t size = ring_buf_get_claim(&tx_ringbuf_, &buf, req_len);
int err, err2;
err = bt_nus_send(conn, buf, size);
err2 = ring_buf_get_finish(&tx_ringbuf_, size);
if (err2) {
ESP_LOGE(TAG, "Failed to ring buf finish (%d error)", err2);
}
if (err == 0) {
ESP_LOGVV(TAG, "Sent %d bytes", size);
} else {
ESP_LOGE(TAG, "Failed to send %d bytes (%d error)", size, err);
atomic_cas(&tx_status_, TX_BUSY, TX_ENABLED);
}
bt_conn_unref(conn);
}
} // namespace zephyr_ble_nus
} // namespace esphome

View File

@ -0,0 +1,40 @@
#pragma once
#include "esphome/core/defines.h"
#include "esphome/core/component.h"
#include <zephyr/sys/ring_buffer.h>
#include <shell/shell_bt_nus.h>
namespace esphome {
namespace zephyr_ble_nus {
class BLENUS : public Component {
enum tx_status {
TX_DISABLED,
TX_ENABLED,
TX_BUSY,
};
public:
BLENUS(size_t buffer_size = 1024);
void setup() override;
void dump_config() override;
void loop() override;
size_t write_array(const uint8_t *data, size_t len);
void set_expose_log(bool expose_log) { this->expose_log_ = expose_log; }
protected:
static void send_enabled_callback_(bt_nus_send_status status);
static void tx_callback_(bt_conn *conn);
static void rx_callback_(bt_conn *conn, const uint8_t *const data, uint16_t len);
static void connected_(bt_conn *conn, uint8_t err);
static void disconnected_(bt_conn *conn, uint8_t reason);
bt_conn *conn_ = nullptr;
ring_buf tx_ringbuf_;
bool expose_log_ = false;
atomic_t tx_status_ = ATOMIC_INIT(TX_DISABLED);
};
} // namespace zephyr_ble_nus
} // namespace esphome

View File

@ -10,21 +10,28 @@ namespace zephyr_ble_server {
static const char *const TAG = "zephyr_ble_server";
static struct k_work advertise_work;
static const struct bt_data AD[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
#ifdef USE_OTA
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
static const struct bt_data AD[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static const struct bt_data SD[] = {
#ifdef USE_OTA
BT_DATA_BYTES(BT_DATA_UUID128_ALL, 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86, 0xd3, 0x4c, 0xb7, 0x1d, 0x1d,
0xdc, 0x53, 0x8d),
#endif
};
const struct bt_le_adv_param* const ADV_PARAM = BT_LE_ADV_CONN_NAME;
const struct bt_le_adv_param* const ADV_PARAM = BT_LE_ADV_CONN;
static void advertise(struct k_work *work) {
bt_le_adv_stop();
int rc = bt_le_adv_start(ADV_PARAM, AD, ARRAY_SIZE(AD), NULL, 0);
int rc = bt_le_adv_start(ADV_PARAM, AD, ARRAY_SIZE(AD), SD, ARRAY_SIZE(SD));
if (rc) {
ESP_LOGE(TAG, "Advertising failed to start (rc %d)", rc);
return;

View File

@ -30,11 +30,6 @@ interval:
then:
- switch.toggle: gpio_15
# sensor:
# - platform: uptime
# name: Uptime Sensor
# update_interval: 5s
output:
- platform: gpio
pin:
@ -71,3 +66,6 @@ ota:
- logger.log: "OTA start"
zephyr_ble_server:
zephyr_ble_nus:
log: true