From 908bace5c448adaa1340b15b743e5ded4cf2c021 Mon Sep 17 00:00:00 2001 From: awalol Date: Thu, 14 May 2026 21:50:39 +0800 Subject: [PATCH] feat(bt_rssi): add 0xf9 feature report to get bt rssi --- src/bt.cpp | 30 ++++++++++++++++- src/bt.h | 1 + src/cmd.cpp | 17 +++++++++- src/usb_descriptors.cpp | 72 +++++++++++++++++++++++------------------ src/utils.h | 2 ++ 5 files changed, 88 insertions(+), 34 deletions(-) diff --git a/src/bt.cpp b/src/bt.cpp index b4572b7..c830099 100644 --- a/src/bt.cpp +++ b/src/bt.cpp @@ -9,6 +9,7 @@ #include #include #include "btstack_event.h" +#include "gap.h" #include "l2cap.h" #include "pico/cyw43_arch.h" #include "utils.h" @@ -37,6 +38,7 @@ static uint16_t hid_control_cid; static uint16_t hid_interrupt_cid; static bt_data_callback_t bt_data_callback = nullptr; static bool check_dse = false; +static int8_t bt_rssi = 0; unordered_map > feature_data; queue_t send_fifo; queue_t priority_send_fifo; @@ -74,6 +76,15 @@ bool bt_disconnect() { return true; } +void bt_get_signal_strength(int8_t *rssi) { + if (acl_handle != HCI_CON_HANDLE_INVALID) { + gap_read_rssi(acl_handle); + } + if (rssi != nullptr) { + *rssi = bt_rssi; + } +} + void bt_l2cap_init() { l2cap_event_callback_registration.callback = &l2cap_packet_handler; l2cap_add_event_handler(&l2cap_event_callback_registration); @@ -198,7 +209,14 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p case HCI_EVENT_COMMAND_COMPLETE: { const uint8_t status = hci_event_command_complete_get_return_parameters(packet)[0]; const uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); - printf("[HCI] CmdComplete %s(0x%04X) status=0x%02X\n", opcode_to_str(opcode), opcode, status); + if (opcode != HCI_OPCODE_HCI_READ_RSSI) { + printf("[HCI] CmdComplete %s(0x%04X) status=0x%02X\n", opcode_to_str(opcode), opcode, status); + } + if (opcode == HCI_OPCODE_HCI_READ_RSSI) { + if (status != ERROR_CODE_SUCCESS || packet[1] < 7) { + printf("[HCI] RSSI complete failed status=0x%02X param_len=%u\n", status, packet[1]); + } + } break; } @@ -207,6 +225,7 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p if (status == 0) { const hci_con_handle_t handle = hci_event_connection_complete_get_connection_handle(packet); acl_handle = handle; + bt_rssi = 0; hci_event_connection_complete_get_bd_addr(packet, current_device_addr); printf("[HCI] ACL connected handle=0x%04X\n", handle); printf("[HCI] Request authentication on handle=0x%04X\n", handle); @@ -316,6 +335,7 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p device_found = false; new_pair = false; acl_handle = HCI_CON_HANDLE_INVALID; + bt_rssi = 0; hid_control_cid = 0; hid_interrupt_cid = 0; feature_data.clear(); @@ -324,6 +344,14 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p gap_inquiry_start(30); break; } + + case GAP_EVENT_RSSI_MEASUREMENT: { + const hci_con_handle_t handle = gap_event_rssi_measurement_get_con_handle(packet); + if (handle == acl_handle) { + bt_rssi = static_cast(gap_event_rssi_measurement_get_rssi(packet)); + } + break; + } } } diff --git a/src/bt.h b/src/bt.h index 6404f9b..8d426c6 100644 --- a/src/bt.h +++ b/src/bt.h @@ -20,6 +20,7 @@ void bt_register_data_callback(bt_data_callback_t callback); void bt_send_packet(uint8_t *data, uint16_t len); void bt_send_control(uint8_t *data, uint16_t len); void bt_write(const uint8_t *data, uint16_t len, bool priority = false); +void bt_get_signal_strength(int8_t *rssi); std::vector get_feature_data(uint8_t reportId,uint16_t len); void init_feature(); void set_feature_data(uint8_t reportId, uint8_t* data,uint16_t len); diff --git a/src/cmd.cpp b/src/cmd.cpp index 8dfc217..8a2add8 100644 --- a/src/cmd.cpp +++ b/src/cmd.cpp @@ -8,6 +8,7 @@ #include #include +#include "bt.h" #include "config.h" #include "device/usbd.h" #include "pico/time.h" @@ -15,7 +16,8 @@ bool is_pico_cmd(uint8_t report_id) { if (report_id == 0xf6 || report_id == 0xf7 || - report_id == 0xf8 + report_id == 0xf8 || + report_id == 0xf9 ) { return true; } @@ -38,6 +40,19 @@ uint16_t pico_cmd_get(uint8_t report_id, uint8_t *buffer, uint16_t reqlen) { memcpy(buffer, PICO_PROGRAM_VERSION_STRING, len); return len; } + if (report_id == 0xf9) { + // [-128,0] + int8_t rssi = 0; + bt_get_signal_strength(&rssi); + if (reqlen == 0) { + return 0; + } + buffer[0] = rssi; +#if ENABLE_VERBOSE + printf("[HID] 0xf9 RSSI=%d raw=0x%02X\n", rssi, buffer[0]); +#endif + return 1; + } return 0; } diff --git a/src/usb_descriptors.cpp b/src/usb_descriptors.cpp index 17964bd..0194ef2 100644 --- a/src/usb_descriptors.cpp +++ b/src/usb_descriptors.cpp @@ -362,8 +362,8 @@ uint8_t descriptor_configuration[] = { 0x00, // bCountryCode: Not localized 0x01, // bNumDescriptors: 1 report descriptor 0x22, // bDescriptorType: Report - 0x39, 0x01, // wDescriptorLength: 313 (0x0139) DS - // 0xAD, 0x01, // wDescriptorLength: 429 (0x01AD) DSE + 0x41, 0x01, // wDescriptorLength: 321 (0x0141) DS + // 0xB5, 0x01, // wDescriptorLength: 437 (0x01B5) DSE // Endpoint Descriptor (HID IN: EP4) 0x07, // bLength @@ -408,9 +408,9 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { descriptor_configuration[offset - 1] = bInterval; descriptor_configuration[offset - 8] = bInterval; if (ds_mode()) { - descriptor_configuration[offset - 16] = 0x39; + descriptor_configuration[offset - 16] = 0x41; }else { - descriptor_configuration[offset - 16] = 0xAD; + descriptor_configuration[offset - 16] = 0xB5; } return descriptor_configuration; } @@ -561,22 +561,26 @@ uint8_t const desc_hid_report_ds[] = { 0x09, 0x36, // Usage (0x36) 0x95, 0x03, // Report Count (3) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xF6, - 0x09, 0x37, - 0x95, 0x3F, - 0xB1, 0x02, - 0x85, 0xF7, - 0x09, 0x38, - 0x95, 0x3F, - 0xB1, 0x02, - 0x85, 0xF8, - 0x09, 0x39, - 0x95, 0x3F, - 0xB1, 0x02, + 0x85, 0xF6, // Report ID (-10) + 0x09, 0x37, // Usage (Vendor 0x37) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF7, // Report ID (-9) + 0x09, 0x38, // Usage (Vendor 0x38) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF8, // Report ID (-8) + 0x09, 0x39, // Usage (Vendor 0x39) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF9, // Report ID (-7) + 0x09, 0x3A, // Usage (Vendor 0x3A) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection - // 313 bytes + // 321 bytes }; -static_assert(sizeof(desc_hid_report_ds) == 0x0139); +static_assert(sizeof(desc_hid_report_ds) == 0x0141); uint8_t const desc_hid_report_dse[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) @@ -778,22 +782,26 @@ uint8_t const desc_hid_report_dse[] = { 0x85, 0x7B, // Report ID (123) 0x09, 0x53, // Usage (0x53) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xF6, - 0x09, 0x37, - 0x95, 0x3F, - 0xB1, 0x02, - 0x85, 0xF7, - 0x09, 0x38, - 0x95, 0x3F, - 0xB1, 0x02, - 0x85, 0xF8, - 0x09, 0x39, - 0x95, 0x3F, - 0xB1, 0x02, + 0x85, 0xF6, // Report ID (-10) + 0x09, 0x37, // Usage (Vendor 0x37) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF7, // Report ID (-9) + 0x09, 0x38, // Usage (Vendor 0x38) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF8, // Report ID (-8) + 0x09, 0x39, // Usage (Vendor 0x39) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF9, // Report ID (-7) + 0x09, 0x3A, // Usage (Vendor 0x3A) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection - // 429 bytes + // 437 bytes }; -static_assert(sizeof(desc_hid_report_dse) == 0x01AD); +static_assert(sizeof(desc_hid_report_dse) == 0x01B5); // Invoked when received GET HID REPORT DESCRIPTOR // Application return pointer to descriptor diff --git a/src/utils.h b/src/utils.h index 29db588..66eff31 100644 --- a/src/utils.h +++ b/src/utils.h @@ -83,6 +83,8 @@ inline const char *opcode_to_str(const uint16_t opcode) { return "HCI_READ_BD_ADDR"; case HCI_OPCODE_HCI_READ_ENCRYPTION_KEY_SIZE: return "HCI_READ_ENCRYPTION_KEY_SIZE"; + case HCI_OPCODE_HCI_READ_RSSI: + return "HCI_READ_RSSI"; case 0xFC01: return "HCI_VENDOR_0xFC01"; default: