DIY hardware that links a Bluetooth keyboard to an USB port.
Useful when you want a Bluetooth keyboard to be available during boot time on desktop computers (BIOS or dual-boot selection).
Based on ESP32 and Raspberry Pi Pico.
Layout made with diagrams.net.
- Bluetooth Low Energy
BLE: used for selecting which Bluetooth HID will be used via the mobile app. - Bluetooth Classic
BR/EDR: used to interact to HID peripherals. It scans nearby Bluetooth HID peripherals. Once one device is choosen by the mobile app,hidlinkwill keep connected to it. - UART: used to send HID reports (ie. keyboard strokes) from ESP32 to Raspberry Pi Pico, which in turn send these reports to PC via USB HID interface.
- USB HID:
Layout made with Fritzing.
- Power and USB communication are plugged via the Raspberry Pi Pico board (micro USB cable).
- ESP32-DevKitV1
VINconnects to Raspberry Pi PicoVBUS. - ESP32-DevKitV1
GNDconnects to Raspberry Pi PicoGND.
- ESP32-DevKitV1
- ESP32-DevKitV1 board is powered via the
REDandBLUEwires. - Communication between ESP32-DevKitV1 and Raspberry Pi Pico is made via the orange wire:
- ESP32-DevKitV1
U2_TXDconnects to Raspberry Pi PicoUART0 RX. - The 1K resistor is not really needed, but is advisable to avoid damage to the digital pins due electromagnetic induction.
- ESP32-DevKitV1
02 01 06 08 09 68 69 64 6c 69 6e 6b
hidlink
- Service UUID:
59534241-ef18-4d1f-850e-b7a87878dfa0- Data characteristic UUID:
59534241-ef18-4d1f-850e-b7a87878dfa1- Requests are performed by:
- Writing to this characteristic
- Responses are received by:
- Reading to this characteristic or
- Receiving indications from this characteristic
- Receiving notifications from this characteristic
- Requests end responses follow the hidlink BLE Protocol described below.
- Requests are performed by:
- Data characteristic UUID:
header command len data checksum
header- Packet start marker
- Length: 1 byte
- Fixed
0x3efor request - Fixed
0x3cfor reponse
command- Command code
- Length: 1 byte
- See available codes below
len- Length of
datafield in bytes - Length: 1 byte
- Length of
data- Data field
- Length: Value of
lenbytes
checksum- Two's complement of the 8 bit truncated sum of all previous fields
- Suming all bytes of all fields to
checksumvalue must result in0x00for a valid packet
Returns the current status of HIDLINK device.
- Request:
0x3e0x010x000xc1 - Response:
0x3c0x010x01statuschecksumstatus0x01NOT CONNECTED0x02SCANNING0x03CONNECTED0x04ERROR ESP320x05ERROR RP2040
Starts scanning of nearby peripherals. The scanning process lasts for 10 seconds. Whenever a scan process is started, the list of scanned devices previously is cleared prior to the new scanning start.
- Request:
0x3e0x020x000xc0 - Response:
0x3c0x020x01ackchecksumack0x06SUCCESS0x15FAIL
Stops scanning of peripherals if HIDLINK is in scanning mode. If not in scanning mode, this command has no effect. If there are any peripherals in the scanned devices list, the devices are kept and can be attached to.
- Request:
0x3e0x030x000xbf - Response:
0x3C0x030x01ackchecksumack0x06SUCCESS0x15FAIL
- Request:
0x3e0x040x000xbe - Response:
0x3c0x040x01countchecksumcount: Number of valid HID peripherals found during scanning process.
- Request:
0x3e0x050x01indexchecksumindex: Index of HID peripheral in scan list. Starts in 1. Maximum value iscountfrom command0x04.
- Response:
0x3c0x05lenaddressnamechecksumlen: Data field lend in bytes (1 byte)address: HID peripheral MAC address (6 bytes)name: HID peripheral name (len- 6 bytes)
- Request:
0x3e0x060x01indexchecksumindex: Index of HID peripheral in scan list. Starts in 1. Maximum value iscountfrom command0x04.
- Response:
0x3c0x060x01ackchecksumack0x06SUCCESS0x15FAIL
- Request:
0x3e0x070x000xbb - Response:
0x3c0x07lenaddressnamechecksumlen: Data field lend in bytes (1 byte)address: HID peripheral MAC address (6 bytes)name: HID peripheral name (len- 6 bytes)
- Request:
0x3e0x080x000xba - Response:
0x3c0x080x01ackchecksumack0x06SUCCESS0x15FAIL
Communication between ESP32 and RP2040 is performed via UART.
- Baudrate: 115200 bps
- Data bits: 8
- Parity: NONE
- Stop bits: ONE
header command len data checksum
header- Packet start marker
- Length: 1 byte
- Fixed
0xaafor request - Fixed
0xa5for reponse
command- Command code
- Length: 1 byte
- See available codes below
len- Length of
datafield in bytes - Length: 1 byte
- Length of
data- Data field
- Length: Value of
lenbytes
checksum- Two's complement of the 8 bit truncated sum of all previous fields
- Suming all bytes of all fields to
checksumvalue must result in0x00for a valid packet
Returns the current status of RP2040 firmware.
- Request:
0xaa0x010x000x55 - Response:
0xa50x010x01statuschecksumstatus0x01TO BE DEFINED0x02TO BE DEFINED0x03TO BE DEFINED
Sends HID report (ie. keyboard key stroke) to be sent via USB by RP2040.
- Request:
0xaa0x02hid_reportchecksumhid_report: HID report data as receive from Bluetooth peripheral. It will be sent to USB in the same format.
- Response:
0xa50x020x01ackchecksumack0x06SUCCESS0x15FAIL
- Install system packages
sudo pacman -S cmake arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib arm-none-eabi-gdb
- Get
pico-sdkrepositorycd ~ git clone https://github.com/raspberrypi/pico-sdk cd pico-sdk git checkout 1.5.1 git submodule update --init --recursive
- Configure
cmakecd [path_where_hidlink_repo_is]/hidlink/firmware_rp2040 mkdir build cmake -DPICO_SDK_PATH=/home/[user_name]/pico-sdk -B build -GNinja - Build
ninja -C build
The generated files will be available at the build dir. The file with uf2 extension can be loaded directly into the USB drive of the Raspberry Pi Pico board.

