mirror of
https://github.com/esphome/esphome.git
synced 2024-11-17 10:55:36 +01:00
add ble nus
This commit is contained in:
parent
4df58663d7
commit
84959cc167
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
29
esphome/components/zephyr_ble_nus/__init__.py
Normal file
29
esphome/components/zephyr_ble_nus/__init__.py
Normal 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)
|
135
esphome/components/zephyr_ble_nus/ble_nus.cpp
Normal file
135
esphome/components/zephyr_ble_nus/ble_nus.cpp
Normal 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
|
40
esphome/components/zephyr_ble_nus/ble_nus.h
Normal file
40
esphome/components/zephyr_ble_nus/ble_nus.h
Normal 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user