Skip to content

Commit b933f8a

Browse files
refactor: extract HID functionality into transport_hid and ble_hid modules
Implemented clean architectural separation following the established transport pattern: ## New modules created: - **transport_hid.c/h**: Pure transport bridge for BLE HID ↔ USB HID data flow - **ble_hid.c/h**: BLE HID client implementation with protocol handling and callbacks ## Architecture improvements: - **Separation of concerns**: Transport logic separated from protocol implementation - **Consistent patterns**: Matches transport_uart/ble_nus architecture - **Callback-based design**: Clean event flow between layers - **Modular initialization**: Each module handles its own setup ## Code changes: - Created transport_hid with bridge state management and USB forwarding - Created ble_hid with ESP HID event handling and device lifecycle - Refactored main.c to use callback-based architecture - Removed duplicate helper functions (log_report, log_addr, appearance_to_string) - Updated hidh_callback to forward events to ble_hid module - Added proper module initialization in app_main ## Benefits: - Cleaner code organization and maintainability - Easier to extend with future HID features - Consistent with existing transport_uart pattern - Better error handling and state management - Alphabetical file ordering (transport_hid, transport_uart) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ee956a5 commit b933f8a

14 files changed

Lines changed: 519 additions & 177 deletions

esp32/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
cmake_minimum_required(VERSION 3.16)
22

33
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
4-
project(mouthpad_esp32_ble_hid_central)
4+
project(mouthpad_usb)

esp32/main/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
idf_component_register(SRCS "transport_uart.c" "ble_central.c" "dev_dfu.c" "ble_dis.c" "ble_nus.c" "button.c" "ble_bas.c" "leds.c" "main.c" "usb_hid.c" "usb_cdc.c"
1+
idf_component_register(SRCS "usb_dfu.c" "ble_hid.c" "transport_hid.c" "transport_uart.c" "ble_central.c" "ble_dis.c" "ble_nus.c" "button.c" "ble_bas.c" "leds.c" "main.c" "usb_hid.c" "usb_cdc.c"
22
INCLUDE_DIRS "."
33
REQUIRES bt esp_hid nvs_flash esp_driver_uart)

esp32/main/ble_dis.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "freertos/queue.h"
1010
#include "string.h"
1111

12-
static const char *TAG = "BLE_DEVICE_INFO";
12+
static const char *TAG = "BLE_DIS";
1313

1414
// Device info client state
1515
static esp_gatt_if_t dis_gattc_if = ESP_GATT_IF_NONE;

esp32/main/ble_hid.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#include "ble_hid.h"
2+
#include "esp_log.h"
3+
#include "esp_hidh.h"
4+
#include "esp_hid_common.h"
5+
#include "string.h"
6+
7+
static const char *TAG = "BLE_HID";
8+
9+
// Client state and callbacks
10+
static ble_hid_client_config_t s_config = {0};
11+
static esp_hidh_dev_t *s_active_dev = NULL;
12+
static bool s_connected = false;
13+
14+
// Helper function to log HID reports
15+
static void log_report(const uint8_t *data, size_t length)
16+
{
17+
if (!data || !length) {
18+
ESP_LOGI(TAG, "Empty report");
19+
return;
20+
}
21+
22+
char buffer[3 * 32 + 1];
23+
size_t to_print = length < 32 ? length : 32;
24+
for (size_t i = 0; i < to_print; ++i) {
25+
snprintf(buffer + i * 3, sizeof(buffer) - i * 3, "%02X ", data[i]);
26+
}
27+
buffer[to_print * 3] = '\0';
28+
ESP_LOGI(TAG, "Report (%d bytes): %s%s", (int)length, buffer,
29+
length > to_print ? "..." : "");
30+
}
31+
32+
// Helper function to log device address
33+
static void log_addr(const uint8_t *addr)
34+
{
35+
if (!addr) {
36+
ESP_LOGI(TAG, "(unknown addr)");
37+
return;
38+
}
39+
ESP_LOGI(TAG, "Address: %02X:%02X:%02X:%02X:%02X:%02X",
40+
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
41+
}
42+
43+
esp_err_t ble_hid_client_init(const ble_hid_client_config_t *config)
44+
{
45+
if (!config) {
46+
ESP_LOGE(TAG, "Invalid config");
47+
return ESP_ERR_INVALID_ARG;
48+
}
49+
50+
ESP_LOGI(TAG, "Initializing BLE HID client");
51+
52+
// Store configuration
53+
memcpy(&s_config, config, sizeof(ble_hid_client_config_t));
54+
55+
// Initialize state
56+
s_active_dev = NULL;
57+
s_connected = false;
58+
59+
ESP_LOGI(TAG, "BLE HID client initialized successfully");
60+
return ESP_OK;
61+
}
62+
63+
void ble_hid_client_handle_event(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
64+
{
65+
(void)handler_args;
66+
(void)base;
67+
esp_hidh_event_t event = (esp_hidh_event_t)id;
68+
esp_hidh_event_data_t *param = (esp_hidh_event_data_t *)event_data;
69+
70+
switch (event) {
71+
case ESP_HIDH_OPEN_EVENT:
72+
if (param->open.dev) {
73+
const uint8_t *bda = esp_hidh_dev_bda_get(param->open.dev);
74+
ESP_LOGI(TAG, "=== HID DEVICE CONNECTED ===");
75+
ESP_LOGI(TAG, "Name: %s", esp_hidh_dev_name_get(param->open.dev));
76+
if (bda) {
77+
log_addr(bda);
78+
}
79+
80+
// Update state
81+
s_active_dev = param->open.dev;
82+
s_connected = true;
83+
84+
// Notify transport layer via callback
85+
if (s_config.connected_cb && bda) {
86+
s_config.connected_cb(param->open.dev, bda);
87+
}
88+
}
89+
break;
90+
91+
case ESP_HIDH_BATTERY_EVENT:
92+
ESP_LOGI(TAG, "Battery event");
93+
if (s_config.battery_cb) {
94+
s_config.battery_cb(param->battery.level, param->battery.status);
95+
}
96+
if (param->battery.status != ESP_OK) {
97+
ESP_LOGW(TAG, "Battery event error: %d", param->battery.status);
98+
}
99+
break;
100+
101+
case ESP_HIDH_INPUT_EVENT:
102+
if (param->input.dev) {
103+
// Forward to transport layer via callback (fast path)
104+
if (s_config.input_cb) {
105+
s_config.input_cb(param->input.report_id, param->input.data, param->input.length);
106+
}
107+
// Optional verbose logging can be enabled here if needed
108+
}
109+
break;
110+
111+
case ESP_HIDH_FEATURE_EVENT:
112+
if (param->feature.dev) {
113+
ESP_LOGI(TAG, "Feature report (usage=%s, id=%u)",
114+
esp_hid_usage_str(param->feature.usage), param->feature.report_id);
115+
log_report(param->feature.data, param->feature.length);
116+
117+
// Notify callback if set
118+
if (s_config.feature_cb) {
119+
s_config.feature_cb(param->feature.dev, param->feature.report_id,
120+
param->feature.data, param->feature.length, param->feature.usage);
121+
}
122+
}
123+
break;
124+
125+
case ESP_HIDH_CLOSE_EVENT:
126+
ESP_LOGI(TAG, "HID device disconnected");
127+
128+
// Update state
129+
if (param->close.dev == s_active_dev) {
130+
s_active_dev = NULL;
131+
s_connected = false;
132+
}
133+
134+
// Notify transport layer via callback
135+
if (s_config.disconnected_cb) {
136+
s_config.disconnected_cb(param->close.dev);
137+
}
138+
139+
// Clean up device handle
140+
if (param->close.dev) {
141+
esp_hidh_dev_free(param->close.dev);
142+
}
143+
break;
144+
145+
default:
146+
ESP_LOGD(TAG, "Unhandled HID event %d", event);
147+
break;
148+
}
149+
}
150+
151+
esp_hidh_dev_t *ble_hid_client_get_active_device(void)
152+
{
153+
return s_active_dev;
154+
}
155+
156+
bool ble_hid_client_is_connected(void)
157+
{
158+
return s_connected && s_active_dev != NULL;
159+
}

esp32/main/ble_hid.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#pragma once
2+
3+
#include "esp_err.h"
4+
#include "esp_hidh.h"
5+
#include "esp_event.h"
6+
#include <stdbool.h>
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
// BLE HID client configuration structure
13+
typedef struct {
14+
void (*connected_cb)(esp_hidh_dev_t *dev, const uint8_t *bda);
15+
void (*disconnected_cb)(esp_hidh_dev_t *dev);
16+
void (*input_cb)(uint8_t report_id, const uint8_t *data, uint16_t length);
17+
void (*feature_cb)(esp_hidh_dev_t *dev, uint8_t report_id, const uint8_t *data, uint16_t length, esp_hid_usage_t usage);
18+
void (*battery_cb)(uint8_t level, esp_err_t status);
19+
} ble_hid_client_config_t;
20+
21+
/**
22+
* @brief Initialize the BLE HID client
23+
*
24+
* @param config Configuration structure with callbacks
25+
* @return esp_err_t ESP_OK on success
26+
*/
27+
esp_err_t ble_hid_client_init(const ble_hid_client_config_t *config);
28+
29+
/**
30+
* @brief Handle ESP HID host events (called from main HID callback)
31+
*
32+
* @param handler_args Handler arguments (unused)
33+
* @param base Event base
34+
* @param id Event ID
35+
* @param event_data Event data
36+
*/
37+
void ble_hid_client_handle_event(void *handler_args, esp_event_base_t base, int32_t id, void *event_data);
38+
39+
/**
40+
* @brief Get the currently active HID device
41+
*
42+
* @return esp_hidh_dev_t* Active device or NULL if none
43+
*/
44+
esp_hidh_dev_t *ble_hid_client_get_active_device(void);
45+
46+
/**
47+
* @brief Check if a HID device is currently connected
48+
*
49+
* @return true if connected, false otherwise
50+
*/
51+
bool ble_hid_client_is_connected(void);
52+
53+
#ifdef __cplusplus
54+
}
55+
#endif

esp32/main/ble_nus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "freertos/queue.h"
1010
#include "string.h"
1111

12-
static const char *TAG = "BLE_NUS_CLIENT";
12+
static const char *TAG = "BLE_NUS";
1313

1414
// NUS client state
1515
static esp_gatt_if_t nus_gattc_if = ESP_GATT_IF_NONE;

esp32/main/dev_dfu.h

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)