prettyprint

2023年7月25日 星期二

[Raspberry Pi Pico W] BTstack BLE Ep 4. HID over GATT -- Custom keypad HID device

本篇文章介紹HID over GATT device的製作。在前篇文章介紹classic HID custom keypad製作,但是若HID device移除電源後再接上電源,HID host不能再次自動連上。修改HID SDP paramter hid_reconnect_initiate=0後,雖然在Android與Linux Debian能運作正常,但在iPhone與Windows下卻無法正常運作。

本篇文章測試HID over GATT是否能正常運作。

一、HID over GATT:

在HID over GATT profile文件中說明, HID device需具備三個必要services: HID service, battery service and device information service。 如下圖所示。

(source SIG HID over GATT profile)
 此三種service在BTstack library中均有implement。宣告GATT service時直接import即可。
在CMakeLists.txt中加pico_btstack_make_gatt_header指令產生ATT database。

二、定義hid advertising data:

HID device Class of service UUID and HID keyboard APPERANCE可由SIG assigned numbers文件查出,別為0x1812與0x03C1。

三、定義HID device keyboard descriptior:

hid keyboard descriptor定義input data為:modifier(1 byte), reserved byte(1 byte)與keycode(6 bytes)。output data為:5 bits+3 bits。

四、定義輸入ascii character與scan code對照表:

由HID report input 輸入的character需轉為scan code。

五、初始化所需的driver與註冊event handler:


六、程式主要流程:

  1. 由keypad輸入字元:get_new_keypad_value() :定義在4x4 keypad driver中。
  2. 字元存入ring buffer中,並呼叫hids_device_request_can_send_now_event(): key_input()。
  3. 在HIDS_SUBEVENT_CAN_SEND_NOW將字元的modifier與keycode送出:typing_can_send_now();
  4. typing_can_send_now():由ring buffer讀取輸入的字元,查表取得modifier與keycode,呼叫send_report(modifier, keycode),送出hid report後,再次呼叫hids_device_request_can_send_now_event()執行下次送出hid report。
  5. send_report():
    uint8_t report[] = {  modifier, 0, keycode, 0, 0, 0, 0, 0};
    送出HID descriptor所定義的input的8 bytes。
詳細程式碼附於文末。

七、成果展示影片:




八、程式碼:

    pico_keypad library程式碼,請參閱前篇文章內容。

  • hog_custom_keypad.c
/* this file was modified from hog_keyboard_demo.c */
/*
* Copyright (C) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "btstack.h"
#include "ble/gatt-service/battery_service_server.h"
#include "ble/gatt-service/device_information_service_server.h"
#include "ble/gatt-service/hids_device.h"
#include "hog_custom_keypad.h"
#include "inttypes.h"
#include "keypad.h"
#define BACKSPACE_BUTTON 16
#define RETURN_BUTTON 17
// from USB HID Specification 1.1, Appendix B.1
const uint8_t hid_descriptor_keyboard_boot_mode[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xa1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID 1
// Modifier byte
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0xe0, // Usage Minimum (Keyboard LeftControl)
0x29, 0xe7, // Usage Maxium (Keyboard Right GUI)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
// Reserved byte
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x03, // Input (Constant, Variable, Absolute)
// LED report + padding
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maxium (Kana)
0x91, 0x02, // Output (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Constant, Variable, Absolute)
// Keycodes
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xff, // Logical Maximum (1)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (Reserved (no event indicated))
0x29, 0xff, // Usage Maxium (Reserved)
0x81, 0x00, // Input (Data, Array)
0xc0, // End collection
};
//
#define CHAR_ILLEGAL 0xff
#define CHAR_RETURN '\n'
#define CHAR_ESCAPE 27
#define CHAR_TAB '\t'
#define CHAR_BACKSPACE 0x7f
// Simplified US Keyboard with Shift modifier
/**
* English (US)
*/
static const uint8_t keytable_us_none [] = {
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4-13 */
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14-23 */
'u', 'v', 'w', 'x', 'y', 'z', /* 24-29 */
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30-39 */
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */
'-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', /* 45-54 */
'.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */
'*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */
'6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */
};
static const uint8_t keytable_us_shift[] = {
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 4-13 */
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 14-23 */
'U', 'V', 'W', 'X', 'Y', 'Z', /* 24-29 */
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', /* 30-39 */
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */
'_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<', /* 45-54 */
'>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */
'*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */
'6', '7', '8', '9', '0', '.', 0xb1, /* 97-100 */
};
static btstack_packet_callback_registration_t hci_event_callback_registration;
static btstack_packet_callback_registration_t sm_event_callback_registration;
static uint8_t battery = 100;
static hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID;
static uint8_t protocol_mode = HID_PROTOCOL_MODE_REPORT;
const uint8_t adv_data[] = {
// Flags general discoverable, BR/EDR not supported
0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06,
// Name
0x0d, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'H', 'I', 'D', ' ', 'K', 'e', 'y', 'b', 'o', 'a', 'r', 'd',
// 16-bit Service UUIDs
0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE & 0xff, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE >> 8,
// Appearance HID - Keyboard (Category 15, Sub-Category 1)
0x03, BLUETOOTH_DATA_TYPE_APPEARANCE, 0xC1, 0x03,
};
const uint8_t adv_data_len = sizeof(adv_data);
// Buffer for 30 characters
static uint8_t key_input_storage[30];
static btstack_ring_buffer_t key_input_buffer;
// HID Keyboard lookup
static int lookup_keycode(uint8_t character, const uint8_t * table, int size, uint8_t * keycode){
int i;
for (i=0;i<size;i++){
if (table[i] != character) continue;
*keycode = i;
return 1;
}
return 0;
}
static int keycode_and_modifer_us_for_character(uint8_t character, uint8_t * keycode, uint8_t * modifier){
int found;
found = lookup_keycode(character, keytable_us_none, sizeof(keytable_us_none), keycode);
if (found) {
*modifier = 0; // none
return 1;
}
found = lookup_keycode(character, keytable_us_shift, sizeof(keytable_us_shift), keycode);
if (found) {
*modifier = 2; // shift
return 1;
}
return 0;
}
// HID Report sending
static void send_report(int modifier, int keycode){
uint8_t report[] = { modifier, 0, keycode, 0, 0, 0, 0, 0};
switch (protocol_mode){
case 0:
hids_device_send_boot_keyboard_input_report(con_handle, report, sizeof(report));
break;
case 1:
hids_device_send_input_report(con_handle, report, sizeof(report));
break;
default:
break;
}
}
static enum {
W4_INPUT,
W4_CAN_SEND_FROM_BUFFER,
W4_CAN_SEND_KEY_UP,
} state;
static void typing_can_send_now(void){
switch (state){
case W4_CAN_SEND_FROM_BUFFER:
while (1){
uint8_t c;
uint32_t num_bytes_read;
btstack_ring_buffer_read(&key_input_buffer, &c, 1, &num_bytes_read);
if (num_bytes_read == 0){
state = W4_INPUT;
break;
}
uint8_t modifier;
uint8_t keycode;
int found = keycode_and_modifer_us_for_character(c, &keycode, &modifier);
if (!found) continue;
printf("sending: %c\n", c);
send_report(modifier, keycode);
state = W4_CAN_SEND_KEY_UP;
hids_device_request_can_send_now_event(con_handle);
break;
}
break;
case W4_CAN_SEND_KEY_UP:
send_report(0, 0);
if (btstack_ring_buffer_bytes_available(&key_input_buffer)){
state = W4_CAN_SEND_FROM_BUFFER;
hids_device_request_can_send_now_event(con_handle);
} else {
state = W4_INPUT;
}
break;
default:
break;
}
}
void key_input(char character){
uint8_t c = character;
btstack_ring_buffer_write(&key_input_buffer, &c, 1);
// start sending
if (state == W4_INPUT && con_handle != HCI_CON_HANDLE_INVALID){
state = W4_CAN_SEND_FROM_BUFFER;
hids_device_request_can_send_now_event(con_handle);
}
}
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_DISCONNECTION_COMPLETE:
con_handle = HCI_CON_HANDLE_INVALID;
printf("Disconnected\n");
break;
case SM_EVENT_JUST_WORKS_REQUEST:
printf("Just Works requested\n");
sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
break;
case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
break;
case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
break;
case HCI_EVENT_HIDS_META:
switch (hci_event_hids_meta_get_subevent_code(packet)){
case HIDS_SUBEVENT_INPUT_REPORT_ENABLE:
con_handle = hids_subevent_input_report_enable_get_con_handle(packet);
printf("Report Characteristic Subscribed %u\n", hids_subevent_input_report_enable_get_enable(packet));
break;
case HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE:
con_handle = hids_subevent_boot_keyboard_input_report_enable_get_con_handle(packet);
printf("Boot Keyboard Characteristic Subscribed %u\n", hids_subevent_boot_keyboard_input_report_enable_get_enable(packet));
break;
case HIDS_SUBEVENT_PROTOCOL_MODE:
protocol_mode = hids_subevent_protocol_mode_get_protocol_mode(packet);
printf("Protocol Mode: %s mode\n", hids_subevent_protocol_mode_get_protocol_mode(packet) ? "Report" : "Boot");
break;
case HIDS_SUBEVENT_CAN_SEND_NOW:
typing_can_send_now();
break;
default:
break;
}
break;
default:
break;
}
}
void key_button_callback(uint gpio, uint32_t events) {
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL, false);
gpio_acknowledge_irq(gpio, events);
if (gpio == BACKSPACE_BUTTON ) {
busy_wait_ms(100);
printf("%d\n", events);
key_input(CHAR_BACKSPACE); //Backspace key
}
if (gpio == RETURN_BUTTON) {
busy_wait_ms(200);
key_input(CHAR_RETURN); // return key
}
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_FALL, true);
}
int main()
{
stdio_init_all();
if (cyw43_arch_init()) {
printf("cyw43_arch_init error\n");
return 0;
}
//0. initialize keypad
keypad_init();
// backspace & return key
gpio_init(BACKSPACE_BUTTON);
gpio_init(RETURN_BUTTON);
gpio_pull_up(BACKSPACE_BUTTON);
gpio_pull_up(RETURN_BUTTON);
gpio_set_irq_enabled_with_callback(BACKSPACE_BUTTON, GPIO_IRQ_EDGE_FALL, true, key_button_callback);
gpio_set_irq_enabled_with_callback(RETURN_BUTTON, GPIO_IRQ_EDGE_FALL, true, key_button_callback);
//1. initialize ring buffer for key input
btstack_ring_buffer_init(&key_input_buffer, key_input_storage, sizeof(key_input_storage));
//2. l2cap initialize
l2cap_init();
//3. setup SM: Display only
sm_init();
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION | SM_AUTHREQ_BONDING);
//4. setup ATT server
att_server_init(profile_data, NULL, NULL);
//5. setup battery service
battery_service_server_init(battery);
//6. setup device information service
device_information_service_server_init();
//7. setup HID Device service
hids_device_init(0, hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode));
//8. setup advertisements
uint16_t adv_int_min = 0x0030;
uint16_t adv_int_max = 0x0030;
uint8_t adv_type = 0;
bd_addr_t null_addr;
memset(null_addr, 0, 6);
gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
gap_advertisements_enable(1);
//9. register for HCI events
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
//10. register for SM events
sm_event_callback_registration.callback = &packet_handler;
sm_add_event_handler(&sm_event_callback_registration);
//11. register for HIDS
hids_device_register_packet_handler(packet_handler);
hci_power_control(HCI_POWER_ON);
uint8_t c;
while(1) {
if (con_handle == HCI_CON_HANDLE_INVALID) continue;
c=get_new_keypad_value();
if (c) {
key_input(c);
}
}
return 0;
}
  • hog_custom_keypad.gatt
PRIMARY_SERVICE, GAP_SERVICE
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "HID Keyboard"
CHARACTERISTIC, GATT_DATABASE_HASH, READ,
// add Battery Service
#import <battery_service.gatt>
// add Device ID Service
#import <device_information_service.gatt>
// add HID Service
#import <hids.gatt>
  • CMakeLists.txt
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "/home/duser/pico/pico-sdk")
set(PICO_BOARD pico_w CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
project(hog_custom_keypad C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(hog_custom_keypad hog_custom_keypad.c )
pico_set_program_name(hog_custom_keypad "hog_custom_keypad")
pico_set_program_version(hog_custom_keypad "0.1")
pico_enable_stdio_uart(hog_custom_keypad 1)
pico_enable_stdio_usb(hog_custom_keypad 0)
# Add the standard library to the build
target_link_libraries(hog_custom_keypad
pico_stdlib
pico_cyw43_arch_none
pico_btstack_cyw43
pico_btstack_ble)
# Add the standard include files to the build
target_include_directories(hog_custom_keypad PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)
pico_btstack_make_gatt_header(hog_custom_keypad PRIVATE "${CMAKE_CURRENT_LIST_DIR}/hog_custom_keypad.gatt")
# Add any user requested libraries
add_subdirectory(pico_keypad)
target_link_libraries(hog_custom_keypad
pico_keypad)
pico_add_extra_outputs(hog_custom_keypad)
  • btstack_config.h
#ifndef _PICO_BTSTACK_BTSTACK_CONFIG_H
#define _PICO_BTSTACK_BTSTACK_CONFIG_H
// BTstack features that can be enabled
#ifdef ENABLE_BLE
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_CENTRAL
#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE
#endif
#ifdef ENABLE_MESH
// Mesh Config
#define ENABLE_MESH_ADV_BEARER
#define ENABLE_MESH_GATT_BEARER
#define ENABLE_MESH_PB_ADV
#define ENABLE_MESH_PB_GATT
#define ENABLE_MESH_PROXY_SERVER
#define ENABLE_MESH_RELAY
#define ENABLE_MESH_PROVISIONER
#define MAX_NR_MESH_SUBNETS 2
#define MAX_NR_MESH_TRANSPORT_KEYS 16
#define MAX_NR_MESH_VIRTUAL_ADDRESSES 16
// allow for one NetKey update
#define MAX_NR_MESH_NETWORK_KEYS (MAX_NR_MESH_SUBNETS+1)
#endif
#define ENABLE_LOG_INFO
#define ENABLE_LOG_ERROR
#define ENABLE_PRINTF_HEXDUMP
#define ENABLE_SCO_OVER_HCI
// BTstack configuration. buffers, sizes, ...
#define HCI_OUTGOING_PRE_BUFFER_SIZE 4
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4
#define MAX_NR_AVDTP_CONNECTIONS 1
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
#define MAX_NR_AVRCP_CONNECTIONS 2
#define MAX_NR_BNEP_CHANNELS 1
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS 2
#define MAX_NR_HID_HOST_CONNECTIONS 1
#define MAX_NR_HIDS_CLIENTS 1
#define MAX_NR_HFP_CONNECTIONS 1
#define MAX_NR_L2CAP_CHANNELS 4
#define MAX_NR_L2CAP_SERVICES 3
#define MAX_NR_RFCOMM_CHANNELS 1
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
#define MAX_NR_RFCOMM_SERVICES 1
#define MAX_NR_SERVICE_RECORD_ITEMS 4
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_WHITELIST_ENTRIES 16
#define MAX_NR_LE_DEVICE_DB_ENTRIES 16
// Limit number of ACL/SCO Buffer to use by stack to avoid cyw43 shared bus overrun
#define MAX_NR_CONTROLLER_ACL_BUFFERS 3
#define MAX_NR_CONTROLLER_SCO_PACKETS 3
// Enable and configure HCI Controller to Host Flow Control to avoid cyw43 shared bus overrun
#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
#define HCI_HOST_ACL_PACKET_LEN 1024
#define HCI_HOST_ACL_PACKET_NUM 3
#define HCI_HOST_SCO_PACKET_LEN 120
#define HCI_HOST_SCO_PACKET_NUM 3
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
#define NVM_NUM_DEVICE_DB_ENTRIES 16
#define NVM_NUM_LINK_KEYS 16
// We don't give btstack a malloc, so use a fixed-size ATT DB.
#define MAX_ATT_DB_SIZE 512
// BTstack HAL configuration
#define HAVE_EMBEDDED_TIME_MS
// map btstack_assert onto Pico SDK assert()
#define HAVE_ASSERT
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
#define ENABLE_SOFTWARE_AES128
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
//#define HAVE_BTSTACK_STDIN
// To get the audio demos working even with HCI dump at 115200, this truncates long ACL packets
//#define HCI_DUMP_STDOUT_MAX_SIZE_ACL 100
#ifdef ENABLE_CLASSIC
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
#endif
#define HAVE_MALLOC
// BTstack configuration. buffers, sizes, ...
#define HCI_INCOMING_PRE_BUFFER_SIZE 6
#endif // _PICO_BTSTACK_BTSTACK_CONFIG_H

沒有留言:

張貼留言