Skip to content

Commit 0317c06

Browse files
committed
add hid_remap example with keyboard
1 parent 5fb0923 commit 0317c06

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed

examples/DualRole/HID/hid_remapper/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
13+
/* This example demonstrates use of both device and host, where
14+
* - Device run on native usb controller (controller0)
15+
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
16+
*
17+
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
18+
* and remap it to another key and send it via device interface (to PC). For simplicity,
19+
* this example only toggle shift key to the report, effectively remap:
20+
* - all character key <-> upper case
21+
* - number <-> its symbol (with shift)
22+
*
23+
* Requirements:
24+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
25+
* - 2 consecutive GPIOs: D+ is defined by HOST_PIN_DP (gpio20), D- = D+ +1 (gpio21)
26+
* - Provide VBus (5v) and GND for peripheral
27+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
28+
*/
29+
30+
// pio-usb is required for rp2040 host
31+
#include "pio_usb.h"
32+
#include "Adafruit_TinyUSB.h"
33+
34+
// Pin D+ for host, D- = D+ + 1
35+
#define HOST_PIN_DP 20
36+
37+
// Pin for enabling Host VBUS. comment out if not used
38+
#define HOST_PIN_VBUS_EN 22
39+
#define HOST_PIN_VBUS_EN_STATE 1
40+
41+
// Language ID: English
42+
#define LANGUAGE_ID 0x0409
43+
44+
// USB Host object
45+
Adafruit_USBH_Host USBHost;
46+
47+
// HID report descriptor using TinyUSB's template
48+
// Single Report (no ID) descriptor
49+
uint8_t const desc_hid_report[] =
50+
{
51+
TUD_HID_REPORT_DESC_KEYBOARD()
52+
};
53+
54+
// USB HID object. For ESP32 these values cannot be changed after this declaration
55+
// desc report, desc len, protocol, interval, use out endpoint
56+
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
57+
58+
//--------------------------------------------------------------------+
59+
// Setup and Loop on Core0
60+
//--------------------------------------------------------------------+
61+
62+
void setup()
63+
{
64+
Serial.begin(115200);
65+
usb_hid.begin();
66+
67+
//while ( !Serial ) delay(10); // wait for native usb
68+
69+
Serial.println("TinyUSB Host HID Remap Example");
70+
}
71+
72+
void loop()
73+
{
74+
75+
}
76+
77+
//--------------------------------------------------------------------+
78+
// Setup and Loop on Core1
79+
//--------------------------------------------------------------------+
80+
81+
void setup1() {
82+
//while ( !Serial ) delay(10); // wait for native usb
83+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
84+
85+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
86+
uint32_t cpu_hz = clock_get_hz(clk_sys);
87+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
88+
while ( !Serial ) delay(10); // wait for native usb
89+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
90+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
91+
while(1) delay(1);
92+
}
93+
94+
#ifdef HOST_PIN_VBUS_EN
95+
pinMode(HOST_PIN_VBUS_EN, OUTPUT);
96+
digitalWrite(HOST_PIN_VBUS_EN, HOST_PIN_VBUS_EN_STATE);
97+
#endif
98+
99+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
100+
pio_cfg.pin_dp = HOST_PIN_DP;
101+
USBHost.configure_pio_usb(1, &pio_cfg);
102+
103+
// run host stack on controller (rhport) 1
104+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
105+
// host bit-banging processing works done in core1 to free up core0 for other works
106+
USBHost.begin(1);
107+
}
108+
109+
void loop1()
110+
{
111+
USBHost.task();
112+
}
113+
114+
// Invoked when device with hid interface is mounted
115+
// Report descriptor is also available for use.
116+
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
117+
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
118+
// it will be skipped therefore report_desc = NULL, desc_len = 0
119+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
120+
(void)desc_report;
121+
(void)desc_len;
122+
uint16_t vid, pid;
123+
tuh_vid_pid_get(dev_addr, &vid, &pid);
124+
125+
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
126+
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
127+
128+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
129+
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
130+
Serial.printf("HID Keyboard\r\n", vid, pid);
131+
if (!tuh_hid_receive_report(dev_addr, instance)) {
132+
Serial.printf("Error: cannot request to receive report\r\n");
133+
}
134+
}
135+
}
136+
137+
// Invoked when device with hid interface is un-mounted
138+
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
139+
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
140+
}
141+
142+
void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report_t* remapped_report)
143+
{
144+
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
145+
146+
// only remap if not empty report i.e key released
147+
for(uint8_t i=0; i<6; i++) {
148+
if (remapped_report->keycode[i] != 0) {
149+
// Note: we ignore right shift here
150+
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
151+
break;
152+
}
153+
}
154+
}
155+
156+
// Invoked when received report from device via interrupt endpoint
157+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
158+
if ( len != 8 ) {
159+
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
160+
}else {
161+
hid_keyboard_report_t remapped_report;
162+
remap_key((hid_keyboard_report_t const*) report, &remapped_report);
163+
164+
// send remapped report to PC
165+
// NOTE: for better performance you should save/queue remapped report instead of
166+
// blocking wait for usb_hid ready here
167+
while ( !usb_hid.ready() ) {
168+
yield();
169+
}
170+
171+
usb_hid.sendReport(0, &remapped_report, sizeof(hid_keyboard_report_t));
172+
}
173+
174+
// continue to request to receive report
175+
if (!tuh_hid_receive_report(dev_addr, instance)) {
176+
Serial.printf("Error: cannot request to receive report\r\n");
177+
}
178+
}

0 commit comments

Comments
 (0)