feat: 添加 BLE HID 键盘支持与配置
- 在 sdkconfig.defaults 中更新 BLE 配置以支持 HID 键盘功能 - 新增 ble_hid.c 和 ble_hid.h 文件,实现 BLE HID 键盘的核心功能 - 更新 CMakeLists.txt,包含新的服务文件以支持 BLE HID - 修改 ui_handlers.c,响应启动按钮事件以发送 HID 按键 - 更新 ble_manager.c,初始化 BLE HID 功能并处理连接状态 - 新增 esp_hid_gap.c 和 esp_hid_gap.h 文件,管理 BLE HID 的 GAP 相关功能
This commit is contained in:
@@ -7,6 +7,8 @@ idf_component_register(SRCS
|
|||||||
"bsp/boot_button.c"
|
"bsp/boot_button.c"
|
||||||
"services/wifi_manager.c"
|
"services/wifi_manager.c"
|
||||||
"services/ble_manager.c"
|
"services/ble_manager.c"
|
||||||
|
"services/ble_hid.c"
|
||||||
|
"services/esp_hid_gap.c"
|
||||||
"ui/ui.c"
|
"ui/ui.c"
|
||||||
"ui/ui_helpers.c"
|
"ui/ui_helpers.c"
|
||||||
"ui/screens/ui_Screen1.c"
|
"ui/screens/ui_Screen1.c"
|
||||||
@@ -14,6 +16,7 @@ idf_component_register(SRCS
|
|||||||
"ui/widgets/ui_comp_hook.c"
|
"ui/widgets/ui_comp_hook.c"
|
||||||
PRIV_REQUIRES
|
PRIV_REQUIRES
|
||||||
bt
|
bt
|
||||||
|
esp_hid
|
||||||
nvs_flash
|
nvs_flash
|
||||||
esp_driver_ledc
|
esp_driver_ledc
|
||||||
esp_driver_spi
|
esp_driver_spi
|
||||||
|
|||||||
+8
-11
@@ -2,28 +2,25 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "ble_hid.h"
|
||||||
#include "boot_button.h"
|
#include "boot_button.h"
|
||||||
#include "lvgl_port.h"
|
#include "esp_log.h"
|
||||||
#include "ui.h"
|
|
||||||
#include "ui_events.h"
|
#include "ui_events.h"
|
||||||
|
|
||||||
static bool s_showing_screen1;
|
static const char *TAG = "ui_handlers";
|
||||||
|
|
||||||
static void ui_toggle_screen(void)
|
static void on_boot_press(void)
|
||||||
{
|
{
|
||||||
lvgl_port_lock();
|
if (ble_hid_ready()) {
|
||||||
if (s_showing_screen1) {
|
ble_hid_send_combo(0, HID_KEY_C);
|
||||||
_ui_screen_change(&ui_Screen2, LV_SCR_LOAD_ANIM_FADE_ON, 200, 0, ui_Screen2_screen_init);
|
|
||||||
} else {
|
} else {
|
||||||
_ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_FADE_ON, 200, 0, ui_Screen1_screen_init);
|
ESP_LOGW(TAG, "HID not ready");
|
||||||
}
|
}
|
||||||
s_showing_screen1 = !s_showing_screen1;
|
|
||||||
lvgl_port_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_handlers_init(void)
|
void ui_handlers_init(void)
|
||||||
{
|
{
|
||||||
boot_button_init(ui_toggle_screen);
|
boot_button_init(on_boot_press);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_year_action(lv_event_t * e)
|
void update_year_action(lv_event_t * e)
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
#include "ble_hid.h"
|
||||||
|
|
||||||
|
#include "board_config.h"
|
||||||
|
|
||||||
|
#if BOARD_BLE_ENABLED
|
||||||
|
|
||||||
|
#include "esp_hidd.h"
|
||||||
|
#include "esp_hid_common.h"
|
||||||
|
#include "esp_hid_gap.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char *TAG = "ble_hid";
|
||||||
|
|
||||||
|
#define HID_KEYBOARD_REPORT_ID 1
|
||||||
|
#define HID_KEYBOARD_REPORT_LEN 7
|
||||||
|
|
||||||
|
static const unsigned char s_keyboard_report_map[] = {
|
||||||
|
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x85, 0x01, 0x05, 0x07, 0x19, 0xE0,
|
||||||
|
0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02,
|
||||||
|
0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08,
|
||||||
|
0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x03,
|
||||||
|
0x95, 0x05, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00,
|
||||||
|
0x29, 0x65, 0x81, 0x00, 0xC0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static esp_hid_raw_report_map_t s_report_maps[] = {
|
||||||
|
{
|
||||||
|
.data = s_keyboard_report_map,
|
||||||
|
.len = sizeof(s_keyboard_report_map),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static esp_hid_device_config_t s_hid_config = {
|
||||||
|
.vendor_id = 0x16C0,
|
||||||
|
.product_id = 0x05DF,
|
||||||
|
.version = 0x0100,
|
||||||
|
.device_name = CONFIG_ESP_BLE_DEVICE_NAME,
|
||||||
|
.manufacturer_name = "HeavenlyHeroStar",
|
||||||
|
.serial_number = "1234567890",
|
||||||
|
.report_maps = s_report_maps,
|
||||||
|
.report_maps_len = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static esp_hidd_dev_t *s_hid_dev;
|
||||||
|
static ble_hid_status_cb_t s_status_cb;
|
||||||
|
static bool s_connected;
|
||||||
|
|
||||||
|
static void ble_hid_log_buffer(const char *label, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
char hex[32];
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len && pos + 3 < sizeof(hex); i++) {
|
||||||
|
pos += (size_t)snprintf(hex + pos, sizeof(hex) - pos, "%02x ", data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "%s len=%u: %s", label, (unsigned)len, hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ble_hid_send_idle_report(void)
|
||||||
|
{
|
||||||
|
uint8_t buffer[HID_KEYBOARD_REPORT_LEN] = {0};
|
||||||
|
|
||||||
|
if (!ble_hid_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ble_hid_log_buffer("idle", buffer, sizeof(buffer));
|
||||||
|
(void)esp_hidd_dev_input_set(s_hid_dev, 0, HID_KEYBOARD_REPORT_ID, buffer,
|
||||||
|
sizeof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ble_hid_idle_task(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
/* Windows often enables notify a few seconds after connect. */
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(3500));
|
||||||
|
ble_hid_send_idle_report();
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ble_hid_hidd_event(void *handler_args, esp_event_base_t base, int32_t id,
|
||||||
|
void *event_data)
|
||||||
|
{
|
||||||
|
esp_hidd_event_t event = (esp_hidd_event_t)id;
|
||||||
|
esp_hidd_event_data_t *param = (esp_hidd_event_data_t *)event_data;
|
||||||
|
|
||||||
|
(void)handler_args;
|
||||||
|
(void)base;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case ESP_HIDD_START_EVENT:
|
||||||
|
ESP_LOGI(TAG, "HID stack started");
|
||||||
|
esp_hid_ble_gap_adv_start();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESP_HIDD_CONNECT_EVENT:
|
||||||
|
if (param->connect.status == 0) {
|
||||||
|
s_connected = true;
|
||||||
|
ESP_LOGI(TAG, "HID connected");
|
||||||
|
if (s_status_cb != NULL) {
|
||||||
|
s_status_cb(true);
|
||||||
|
}
|
||||||
|
xTaskCreate(ble_hid_idle_task, "ble_hid_idle", 2048, NULL, 5, NULL);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "HID connect failed status=%d", param->connect.status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESP_HIDD_DISCONNECT_EVENT:
|
||||||
|
s_connected = false;
|
||||||
|
ESP_LOGI(TAG, "HID disconnected reason=%d", param->disconnect.reason);
|
||||||
|
if (s_status_cb != NULL) {
|
||||||
|
s_status_cb(false);
|
||||||
|
}
|
||||||
|
esp_hid_ble_gap_adv_start();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESP_HIDD_PROTOCOL_MODE_EVENT:
|
||||||
|
ESP_LOGI(TAG, "protocol mode map=%u mode=%s",
|
||||||
|
param->protocol_mode.map_index,
|
||||||
|
param->protocol_mode.protocol_mode ? "REPORT" : "BOOT");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESP_HIDD_CONTROL_EVENT:
|
||||||
|
ESP_LOGI(TAG, "control map=%u %sSUSPEND",
|
||||||
|
param->control.map_index,
|
||||||
|
param->control.control ? "EXIT_" : "");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESP_HIDD_OUTPUT_EVENT:
|
||||||
|
ESP_LOGD(TAG, "output map=%u id=%u len=%d",
|
||||||
|
param->output.map_index, param->output.report_id, param->output.length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_init(ble_hid_status_cb_t status_cb)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
s_status_cb = status_cb;
|
||||||
|
s_connected = false;
|
||||||
|
|
||||||
|
ret = esp_hidd_dev_init(&s_hid_config, ESP_HID_TRANSPORT_BLE, ble_hid_hidd_event,
|
||||||
|
&s_hid_dev);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_hidd_dev_init failed: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "esp_hidd keyboard ready (report payload=%u bytes)",
|
||||||
|
(unsigned)HID_KEYBOARD_REPORT_LEN);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ble_hid_on_input_notify(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled) {
|
||||||
|
ble_hid_send_idle_report();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ble_hid_ready(void)
|
||||||
|
{
|
||||||
|
return s_connected && s_hid_dev != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_key_press(uint8_t modifier, uint8_t keycode)
|
||||||
|
{
|
||||||
|
uint8_t buffer[HID_KEYBOARD_REPORT_LEN] = {0};
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
if (!ble_hid_ready()) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0] = modifier;
|
||||||
|
buffer[2] = keycode;
|
||||||
|
ble_hid_log_buffer("press", buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
ret = esp_hidd_dev_input_set(s_hid_dev, 0, HID_KEYBOARD_REPORT_ID, buffer,
|
||||||
|
sizeof(buffer));
|
||||||
|
return (ret == ESP_OK) ? 0 : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_key_release(void)
|
||||||
|
{
|
||||||
|
uint8_t buffer[HID_KEYBOARD_REPORT_LEN] = {0};
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
if (!ble_hid_ready()) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ble_hid_log_buffer("release", buffer, sizeof(buffer));
|
||||||
|
ret = esp_hidd_dev_input_set(s_hid_dev, 0, HID_KEYBOARD_REPORT_ID, buffer,
|
||||||
|
sizeof(buffer));
|
||||||
|
return (ret == ESP_OK) ? 0 : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_send_combo(uint8_t modifier, uint8_t keycode)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ble_hid_key_press(modifier, keycode);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
return ble_hid_key_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int ble_hid_init(ble_hid_status_cb_t status_cb)
|
||||||
|
{
|
||||||
|
(void)status_cb;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ble_hid_ready(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_key_press(uint8_t modifier, uint8_t keycode)
|
||||||
|
{
|
||||||
|
(void)modifier;
|
||||||
|
(void)keycode;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_key_release(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ble_hid_send_combo(uint8_t modifier, uint8_t keycode)
|
||||||
|
{
|
||||||
|
(void)modifier;
|
||||||
|
(void)keycode;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BOARD_BLE_ENABLED */
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define HID_MOD_LCTRL 0x01
|
||||||
|
#define HID_MOD_LSHIFT 0x02
|
||||||
|
#define HID_MOD_LALT 0x04
|
||||||
|
#define HID_MOD_LGUI 0x08
|
||||||
|
|
||||||
|
#define HID_KEY_C 0x06
|
||||||
|
#define HID_KEY_F5 0x3E
|
||||||
|
|
||||||
|
typedef void (*ble_hid_status_cb_t)(bool connected);
|
||||||
|
|
||||||
|
int ble_hid_init(ble_hid_status_cb_t status_cb);
|
||||||
|
bool ble_hid_ready(void);
|
||||||
|
|
||||||
|
int ble_hid_key_press(uint8_t modifier, uint8_t keycode);
|
||||||
|
int ble_hid_key_release(void);
|
||||||
|
int ble_hid_send_combo(uint8_t modifier, uint8_t keycode);
|
||||||
|
|
||||||
|
#if defined(BOARD_BLE_ENABLED) && BOARD_BLE_ENABLED
|
||||||
|
void ble_hid_on_input_notify(bool enabled);
|
||||||
|
#endif
|
||||||
+30
-197
@@ -1,96 +1,28 @@
|
|||||||
#include "ble_manager.h"
|
#include "ble_manager.h"
|
||||||
|
|
||||||
#include "board_config.h"
|
#include "board_config.h"
|
||||||
|
#include "ble_hid.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#if BOARD_BLE_ENABLED
|
#if BOARD_BLE_ENABLED
|
||||||
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_hid_gap.h"
|
||||||
|
#include "esp_hid_common.h"
|
||||||
#include "host/ble_hs.h"
|
#include "host/ble_hs.h"
|
||||||
#include "host/ble_uuid.h"
|
|
||||||
#include "host/util/util.h"
|
|
||||||
#include "nimble/nimble_port.h"
|
#include "nimble/nimble_port.h"
|
||||||
#include "nimble/nimble_port_freertos.h"
|
#include "nimble/nimble_port_freertos.h"
|
||||||
#include "services/gap/ble_svc_gap.h"
|
|
||||||
#include "services/gatt/ble_svc_gatt.h"
|
|
||||||
#include "store/config/ble_store_config.h"
|
#include "store/config/ble_store_config.h"
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define BLE_DEVICE_NAME CONFIG_ESP_BLE_DEVICE_NAME
|
|
||||||
|
|
||||||
#define HHS_SVC_UUID16 0xFFF0
|
|
||||||
#define HHS_CHR_UUID16 0xFFF1
|
|
||||||
|
|
||||||
static const char *TAG = "ble_manager";
|
static const char *TAG = "ble_manager";
|
||||||
|
|
||||||
|
#define BLE_DEVICE_NAME CONFIG_ESP_BLE_DEVICE_NAME
|
||||||
|
|
||||||
static ble_status_cb_t s_status_cb;
|
static ble_status_cb_t s_status_cb;
|
||||||
static bool s_connected;
|
static bool s_connected;
|
||||||
static uint8_t s_own_addr_type;
|
|
||||||
static uint16_t s_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
|
||||||
|
|
||||||
static uint8_t s_chr_val[20] = "HeavenlyHeroStar";
|
static void on_hid_status(bool connected)
|
||||||
static uint16_t s_chr_val_handle;
|
|
||||||
static const ble_uuid16_t s_hhs_svc_uuid = BLE_UUID16_INIT(HHS_SVC_UUID16);
|
|
||||||
static const ble_uuid16_t s_hhs_chr_uuid = BLE_UUID16_INIT(HHS_CHR_UUID16);
|
|
||||||
|
|
||||||
static void start_advertising(void);
|
|
||||||
static int gap_event_handler(struct ble_gap_event *event, void *arg);
|
|
||||||
|
|
||||||
static int chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
|
||||||
{
|
|
||||||
(void)arg;
|
|
||||||
|
|
||||||
if (attr_handle != s_chr_val_handle) {
|
|
||||||
return BLE_ATT_ERR_UNLIKELY;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ctxt->op) {
|
|
||||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
|
||||||
return os_mbuf_append(ctxt->om, s_chr_val, sizeof(s_chr_val)) == 0
|
|
||||||
? 0
|
|
||||||
: BLE_ATT_ERR_INSUFFICIENT_RES;
|
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
|
||||||
uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
|
|
||||||
if (len > sizeof(s_chr_val)) {
|
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
|
||||||
}
|
|
||||||
memset(s_chr_val, 0, sizeof(s_chr_val));
|
|
||||||
int rc = ble_hs_mbuf_to_flat(ctxt->om, s_chr_val, sizeof(s_chr_val), NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
return BLE_ATT_ERR_UNLIKELY;
|
|
||||||
}
|
|
||||||
ESP_LOGI(TAG, "characteristic write from conn=%d, len=%u", conn_handle, len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return BLE_ATT_ERR_UNLIKELY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ble_gatt_svc_def s_gatt_svcs[] = {
|
|
||||||
{
|
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = &s_hhs_svc_uuid.u,
|
|
||||||
.characteristics =
|
|
||||||
(struct ble_gatt_chr_def[]){
|
|
||||||
{
|
|
||||||
.uuid = &s_hhs_chr_uuid.u,
|
|
||||||
.access_cb = chr_access,
|
|
||||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
|
||||||
.val_handle = &s_chr_val_handle,
|
|
||||||
},
|
|
||||||
{0},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{0},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void notify_status(bool connected)
|
|
||||||
{
|
{
|
||||||
s_connected = connected;
|
s_connected = connected;
|
||||||
gpio_set_level(BOARD_PIN_LED, connected ? 1 : 0);
|
gpio_set_level(BOARD_PIN_LED, connected ? 1 : 0);
|
||||||
@@ -99,119 +31,15 @@ static void notify_status(bool connected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_advertising(void)
|
|
||||||
{
|
|
||||||
struct ble_hs_adv_fields fields = {0};
|
|
||||||
struct ble_gap_adv_params adv_params = {0};
|
|
||||||
const char *name = ble_svc_gap_device_name();
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
|
||||||
fields.name = (uint8_t *)name;
|
|
||||||
fields.name_len = strlen(name);
|
|
||||||
fields.name_is_complete = 1;
|
|
||||||
|
|
||||||
rc = ble_gap_adv_set_fields(&fields);
|
|
||||||
if (rc != 0) {
|
|
||||||
ESP_LOGE(TAG, "failed to set advertising data: %d", rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
|
||||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
|
||||||
|
|
||||||
rc = ble_gap_adv_start(s_own_addr_type, NULL, BLE_HS_FOREVER, &adv_params,
|
|
||||||
gap_event_handler, NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
ESP_LOGE(TAG, "failed to start advertising: %d", rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "advertising as \"%s\"", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gap_event_handler(struct ble_gap_event *event, void *arg)
|
|
||||||
{
|
|
||||||
(void)arg;
|
|
||||||
|
|
||||||
switch (event->type) {
|
|
||||||
case BLE_GAP_EVENT_CONNECT:
|
|
||||||
if (event->connect.status == 0) {
|
|
||||||
s_conn_handle = event->connect.conn_handle;
|
|
||||||
ESP_LOGI(TAG, "connected, handle=%d", s_conn_handle);
|
|
||||||
notify_status(true);
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "connection failed, status=%d", event->connect.status);
|
|
||||||
start_advertising();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case BLE_GAP_EVENT_DISCONNECT:
|
|
||||||
ESP_LOGI(TAG, "disconnected, reason=%d", event->disconnect.reason);
|
|
||||||
s_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
|
||||||
notify_status(false);
|
|
||||||
start_advertising();
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
|
||||||
start_advertising();
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_stack_sync(void)
|
|
||||||
{
|
|
||||||
int rc = ble_hs_util_ensure_addr(0);
|
|
||||||
if (rc != 0) {
|
|
||||||
ESP_LOGE(TAG, "no available BT address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ble_hs_id_infer_auto(0, &s_own_addr_type);
|
|
||||||
if (rc != 0) {
|
|
||||||
ESP_LOGE(TAG, "failed to infer address type: %d", rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_advertising();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_stack_reset(int reason)
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "nimble stack reset, reason=%d", reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gatt_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
|
||||||
{
|
|
||||||
(void)ctxt;
|
|
||||||
(void)arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gatt_svc_init(void)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
ble_svc_gatt_init();
|
|
||||||
rc = ble_gatts_count_cfg(s_gatt_svcs);
|
|
||||||
if (rc != 0) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ble_gatts_add_svcs(s_gatt_svcs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ble_store_config_init(void);
|
|
||||||
|
|
||||||
static void nimble_host_task(void *param)
|
static void nimble_host_task(void *param)
|
||||||
{
|
{
|
||||||
(void)param;
|
(void)param;
|
||||||
nimble_port_run();
|
nimble_port_run();
|
||||||
vTaskDelete(NULL);
|
nimble_port_freertos_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ble_store_config_init(void);
|
||||||
|
|
||||||
#endif /* BOARD_BLE_ENABLED */
|
#endif /* BOARD_BLE_ENABLED */
|
||||||
|
|
||||||
void ble_manager_set_status_cb(ble_status_cb_t cb)
|
void ble_manager_set_status_cb(ble_status_cb_t cb)
|
||||||
@@ -235,36 +63,41 @@ bool ble_manager_is_connected(void)
|
|||||||
void ble_manager_init(void)
|
void ble_manager_init(void)
|
||||||
{
|
{
|
||||||
#if BOARD_BLE_ENABLED
|
#if BOARD_BLE_ENABLED
|
||||||
int rc;
|
esp_err_t ret;
|
||||||
|
|
||||||
gpio_reset_pin(BOARD_PIN_LED);
|
gpio_reset_pin(BOARD_PIN_LED);
|
||||||
gpio_set_direction(BOARD_PIN_LED, GPIO_MODE_OUTPUT);
|
gpio_set_direction(BOARD_PIN_LED, GPIO_MODE_OUTPUT);
|
||||||
gpio_set_level(BOARD_PIN_LED, 0);
|
gpio_set_level(BOARD_PIN_LED, 0);
|
||||||
|
|
||||||
ESP_ERROR_CHECK(nimble_port_init());
|
ESP_LOGI(TAG, "init esp_hid_gap (NimBLE)");
|
||||||
|
ret = esp_hid_gap_init(HIDD_BLE_MODE);
|
||||||
ble_svc_gap_init();
|
if (ret != ESP_OK) {
|
||||||
rc = ble_svc_gap_device_name_set(BLE_DEVICE_NAME);
|
ESP_LOGE(TAG, "esp_hid_gap_init failed: %d", ret);
|
||||||
if (rc != 0) {
|
|
||||||
ESP_LOGE(TAG, "failed to set device name");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = gatt_svc_init();
|
ret = esp_hid_ble_gap_adv_init(ESP_HID_APPEARANCE_KEYBOARD, BLE_DEVICE_NAME);
|
||||||
if (rc != 0) {
|
if (ret != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "failed to init GATT service: %d", rc);
|
ESP_LOGE(TAG, "esp_hid_ble_gap_adv_init failed: %d", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ble_hid_init(on_hid_status);
|
||||||
|
if (ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "ble_hid_init failed: %d", ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_hs_cfg.reset_cb = on_stack_reset;
|
|
||||||
ble_hs_cfg.sync_cb = on_stack_sync;
|
|
||||||
ble_hs_cfg.gatts_register_cb = gatt_register_cb;
|
|
||||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
|
||||||
ble_store_config_init();
|
ble_store_config_init();
|
||||||
|
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||||
|
|
||||||
nimble_port_freertos_init(nimble_host_task);
|
ret = esp_nimble_enable(nimble_host_task);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_nimble_enable failed: %d", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "BLE peripheral started");
|
ESP_LOGI(TAG, "BLE HID keyboard started as \"%s\"", BLE_DEVICE_NAME);
|
||||||
#else
|
#else
|
||||||
ESP_LOGI("ble_manager", "BLE disabled by board config");
|
ESP_LOGI("ble_manager", "BLE disabled by board config");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ESP_HID_GAP_H_
|
||||||
|
#define _ESP_HID_GAP_H_
|
||||||
|
|
||||||
|
#define HIDD_IDLE_MODE 0x00
|
||||||
|
#define HIDD_BLE_MODE 0x01
|
||||||
|
#define HIDD_BT_MODE 0x02
|
||||||
|
#define HIDD_BTDM_MODE 0x03
|
||||||
|
|
||||||
|
#if CONFIG_BT_HID_DEVICE_ENABLED
|
||||||
|
#if CONFIG_BT_BLE_ENABLED
|
||||||
|
#define HID_DEV_MODE HIDD_BTDM_MODE
|
||||||
|
#else
|
||||||
|
#define HID_DEV_MODE HIDD_BT_MODE
|
||||||
|
#endif
|
||||||
|
#elif CONFIG_BT_BLE_ENABLED
|
||||||
|
#define HID_DEV_MODE HIDD_BLE_MODE
|
||||||
|
#elif CONFIG_BT_NIMBLE_ENABLED
|
||||||
|
#define HID_DEV_MODE HIDD_BLE_MODE
|
||||||
|
#else
|
||||||
|
#define HID_DEV_MODE HIDD_IDLE_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#include "esp_bt.h"
|
||||||
|
#if !CONFIG_BT_NIMBLE_ENABLED
|
||||||
|
#include "esp_bt_defs.h"
|
||||||
|
#include "esp_bt_main.h"
|
||||||
|
#include "esp_gap_bt_api.h"
|
||||||
|
#endif
|
||||||
|
#include "esp_hid_common.h"
|
||||||
|
#if CONFIG_BT_BLE_ENABLED
|
||||||
|
#include "esp_gattc_api.h"
|
||||||
|
#include "esp_gatt_defs.h"
|
||||||
|
#include "esp_gap_ble_api.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CONFIG_BT_NIMBLE_ENABLED
|
||||||
|
typedef struct esp_hidh_scan_result_s {
|
||||||
|
struct esp_hidh_scan_result_s *next;
|
||||||
|
|
||||||
|
esp_bd_addr_t bda;
|
||||||
|
const char *name;
|
||||||
|
int8_t rssi;
|
||||||
|
esp_hid_usage_t usage;
|
||||||
|
esp_hid_transport_t transport; //BT, BLE or USB
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
esp_bt_cod_t cod;
|
||||||
|
esp_bt_uuid_t uuid;
|
||||||
|
} bt;
|
||||||
|
struct {
|
||||||
|
esp_ble_addr_type_t addr_type;
|
||||||
|
uint16_t appearance;
|
||||||
|
} ble;
|
||||||
|
};
|
||||||
|
} esp_hid_scan_result_t;
|
||||||
|
|
||||||
|
esp_err_t esp_hid_scan(uint32_t seconds, size_t *num_results, esp_hid_scan_result_t **results);
|
||||||
|
void esp_hid_scan_results_free(esp_hid_scan_result_t *results);
|
||||||
|
const char *ble_addr_type_str(esp_ble_addr_type_t ble_addr_type);
|
||||||
|
void print_uuid(esp_bt_uuid_t *uuid);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
esp_err_t esp_hid_gap_init(uint8_t mode);
|
||||||
|
esp_err_t esp_hid_gap_deinit(void);
|
||||||
|
|
||||||
|
esp_err_t esp_hid_ble_gap_adv_init(uint16_t appearance, const char *device_name);
|
||||||
|
esp_err_t esp_hid_ble_gap_adv_start(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ESP_HIDH_GAP_H_ */
|
||||||
+11
-1
@@ -5,7 +5,17 @@ CONFIG_ESP_LCD_TOUCH_CST816S_DISABLE_READ_ID=y
|
|||||||
CONFIG_PARTITION_TABLE_SINGLE_APP=n
|
CONFIG_PARTITION_TABLE_SINGLE_APP=n
|
||||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||||
|
|
||||||
# BLE (NimBLE peripheral)
|
# BLE (NimBLE peripheral + HID keyboard)
|
||||||
CONFIG_BT_ENABLED=y
|
CONFIG_BT_ENABLED=y
|
||||||
CONFIG_BT_NIMBLE_ENABLED=y
|
CONFIG_BT_NIMBLE_ENABLED=y
|
||||||
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n
|
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n
|
||||||
|
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y
|
||||||
|
CONFIG_BT_NIMBLE_SM_LEGACY=y
|
||||||
|
CONFIG_BT_NIMBLE_SM_SC=y
|
||||||
|
CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
||||||
|
CONFIG_BT_NIMBLE_HID_SERVICE=y
|
||||||
|
CONFIG_BT_NIMBLE_SVC_HID_MAX_RPTS=3
|
||||||
|
CONFIG_BT_NIMBLE_BAS_SERVICE=y
|
||||||
|
CONFIG_BT_NIMBLE_DIS_SERVICE=y
|
||||||
|
CONFIG_BT_NIMBLE_SVC_DIS_PNP_ID=y
|
||||||
|
CONFIG_BT_NIMBLE_SVC_DIS_MANUFACTURER_NAME=y
|
||||||
|
|||||||
Reference in New Issue
Block a user