|
| 1 | +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries |
| 2 | +// |
| 3 | +// SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +/********************************************************************* |
| 6 | + Adafruit invests time and resources providing this open source code, |
| 7 | + please support Adafruit and open-source hardware by purchasing |
| 8 | + products from Adafruit! |
| 9 | +
|
| 10 | + MIT license, check LICENSE for more information |
| 11 | + Copyright (c) 2019 Ha Thach for Adafruit Industries |
| 12 | + All text above, and the splash screen below must be included in |
| 13 | + any redistribution |
| 14 | +*********************************************************************/ |
| 15 | + |
| 16 | +/* This example demonstrates use of usb host with a standard HID boot keyboard. |
| 17 | + * - Host depends on MCU: |
| 18 | + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) |
| 19 | + * |
| 20 | + * Requirements: |
| 21 | + * - For rp2040: |
| 22 | + * - Pico-PIO-USB library |
| 23 | + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 |
| 24 | + * - Provide VBus (5v) and GND for peripheral |
| 25 | + */ |
| 26 | + |
| 27 | +// USBHost is defined in usbh_helper.h |
| 28 | +#include "usbh_helper.h" |
| 29 | +#include "tusb.h" |
| 30 | +#include "Adafruit_TinyUSB.h" |
| 31 | + |
| 32 | + |
| 33 | +bool printed_blank = false; |
| 34 | + |
| 35 | +void setup() { |
| 36 | + Serial.begin(115200); |
| 37 | + |
| 38 | + // configure pio-usb: defined in usbh_helper.h |
| 39 | + rp2040_configure_pio_usb(); |
| 40 | + |
| 41 | + // run host stack on controller (rhport) 1 |
| 42 | + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the |
| 43 | + // host bit-banging processing works done in core1 to free up core0 for other works |
| 44 | + USBHost.begin(1); |
| 45 | + delay(3000); |
| 46 | + Serial.print("USB D+ Pin:"); |
| 47 | + Serial.println(PIN_USB_HOST_DP); |
| 48 | + Serial.print("USB 5V Pin:"); |
| 49 | + Serial.println(PIN_5V_EN); |
| 50 | +} |
| 51 | + |
| 52 | +void loop() { |
| 53 | + USBHost.task(); |
| 54 | + Serial.flush(); |
| 55 | + |
| 56 | +} |
| 57 | + |
| 58 | +//--------------------------------------------------------------------+ |
| 59 | +// HID Host Callback Functions |
| 60 | +//--------------------------------------------------------------------+ |
| 61 | + |
| 62 | +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) |
| 63 | +{ |
| 64 | + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); |
| 65 | + |
| 66 | + // Start receiving HID reports |
| 67 | + if (!tuh_hid_receive_report(dev_addr, instance)) |
| 68 | + { |
| 69 | + Serial.printf("Error: cannot request to receive report\n"); |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) |
| 74 | +{ |
| 75 | + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); |
| 76 | +} |
| 77 | + |
| 78 | +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { |
| 79 | + |
| 80 | + if (len > 0){ |
| 81 | + |
| 82 | + //debug print report data |
| 83 | + // Serial.print("Report data: "); |
| 84 | + // for (int i = 0; i < len; i++) { |
| 85 | + // Serial.print(report[i], HEX); |
| 86 | + // Serial.print(" "); |
| 87 | + |
| 88 | + // } |
| 89 | + // Serial.println(); |
| 90 | + |
| 91 | + printKeyboardReport(report); |
| 92 | + } |
| 93 | + |
| 94 | + // Continue to receive the next report |
| 95 | + if (!tuh_hid_receive_report(dev_addr, instance)) { |
| 96 | + Serial.println("Error: cannot request to receive report"); |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +// Helper function to print key names |
| 101 | +void printKeyName(uint8_t key) { |
| 102 | + // This is a simplified list. Full HID keyboard has many more key codes |
| 103 | + switch (key) { |
| 104 | + case 0x04: Serial.print("A"); break; |
| 105 | + case 0x05: Serial.print("B"); break; |
| 106 | + case 0x06: Serial.print("C"); break; |
| 107 | + case 0x07: Serial.print("D"); break; |
| 108 | + case 0x08: Serial.print("E"); break; |
| 109 | + case 0x09: Serial.print("F"); break; |
| 110 | + case 0x0A: Serial.print("G"); break; |
| 111 | + case 0x0B: Serial.print("H"); break; |
| 112 | + case 0x0C: Serial.print("I"); break; |
| 113 | + case 0x0D: Serial.print("J"); break; |
| 114 | + case 0x0E: Serial.print("K"); break; |
| 115 | + case 0x0F: Serial.print("L"); break; |
| 116 | + case 0x10: Serial.print("M"); break; |
| 117 | + case 0x11: Serial.print("N"); break; |
| 118 | + case 0x12: Serial.print("O"); break; |
| 119 | + case 0x13: Serial.print("P"); break; |
| 120 | + case 0x14: Serial.print("Q"); break; |
| 121 | + case 0x15: Serial.print("R"); break; |
| 122 | + case 0x16: Serial.print("S"); break; |
| 123 | + case 0x17: Serial.print("T"); break; |
| 124 | + case 0x18: Serial.print("U"); break; |
| 125 | + case 0x19: Serial.print("V"); break; |
| 126 | + case 0x1A: Serial.print("W"); break; |
| 127 | + case 0x1B: Serial.print("X"); break; |
| 128 | + case 0x1C: Serial.print("Y"); break; |
| 129 | + case 0x1D: Serial.print("Z"); break; |
| 130 | + case 0x1E: Serial.print("1"); break; |
| 131 | + case 0x1F: Serial.print("2"); break; |
| 132 | + case 0x20: Serial.print("3"); break; |
| 133 | + case 0x21: Serial.print("4"); break; |
| 134 | + case 0x22: Serial.print("5"); break; |
| 135 | + case 0x23: Serial.print("6"); break; |
| 136 | + case 0x24: Serial.print("7"); break; |
| 137 | + case 0x25: Serial.print("8"); break; |
| 138 | + case 0x26: Serial.print("9"); break; |
| 139 | + case 0x27: Serial.print("0"); break; |
| 140 | + case 0x28: Serial.print("ENTER"); break; |
| 141 | + case 0x29: Serial.print("ESC"); break; |
| 142 | + case 0x2A: Serial.print("BACKSPACE"); break; |
| 143 | + case 0x2B: Serial.print("TAB"); break; |
| 144 | + case 0x2C: Serial.print("SPACE"); break; |
| 145 | + case 0x2D: Serial.print("MINUS"); break; |
| 146 | + case 0x2E: Serial.print("EQUAL"); break; |
| 147 | + case 0x2F: Serial.print("LBRACKET"); break; |
| 148 | + case 0x30: Serial.print("RBRACKET"); break; |
| 149 | + case 0x31: Serial.print("BACKSLASH"); break; |
| 150 | + case 0x33: Serial.print("SEMICOLON"); break; |
| 151 | + case 0x34: Serial.print("QUOTE"); break; |
| 152 | + case 0x35: Serial.print("GRAVE"); break; |
| 153 | + case 0x36: Serial.print("COMMA"); break; |
| 154 | + case 0x37: Serial.print("PERIOD"); break; |
| 155 | + case 0x38: Serial.print("SLASH"); break; |
| 156 | + case 0x39: Serial.print("CAPS_LOCK"); break; |
| 157 | + case 0x4F: Serial.print("RIGHT_ARROW"); break; |
| 158 | + case 0x50: Serial.print("LEFT_ARROW"); break; |
| 159 | + case 0x51: Serial.print("DOWN_ARROW"); break; |
| 160 | + case 0x52: Serial.print("UP_ARROW"); break; |
| 161 | + default: |
| 162 | + if (key >= 0x3A && key <= 0x45) { // F1-F12 |
| 163 | + Serial.print("F"); |
| 164 | + Serial.print(key - 0x3A + 1); |
| 165 | + } else { |
| 166 | + // For keys not handled above, just print the HID code |
| 167 | + Serial.print("0x"); |
| 168 | + Serial.print(key, HEX); |
| 169 | + } |
| 170 | + break; |
| 171 | + } |
| 172 | +} |
| 173 | + |
| 174 | +void printKeyboardReport(uint8_t const* report) { |
| 175 | + // First byte contains modifier keys |
| 176 | + uint8_t modifiers = report[0]; |
| 177 | + |
| 178 | + // Print modifier keys if pressed |
| 179 | + if (modifiers > 0) { |
| 180 | + Serial.print("Modifiers: "); |
| 181 | + |
| 182 | + if (modifiers & 0x01) Serial.print("LEFT_CTRL "); |
| 183 | + if (modifiers & 0x02) Serial.print("LEFT_SHIFT "); |
| 184 | + if (modifiers & 0x04) Serial.print("LEFT_ALT "); |
| 185 | + if (modifiers & 0x08) Serial.print("LEFT_GUI "); |
| 186 | + if (modifiers & 0x10) Serial.print("RIGHT_CTRL "); |
| 187 | + if (modifiers & 0x20) Serial.print("RIGHT_SHIFT "); |
| 188 | + if (modifiers & 0x40) Serial.print("RIGHT_ALT "); |
| 189 | + if (modifiers & 0x80) Serial.print("RIGHT_GUI "); |
| 190 | + |
| 191 | + Serial.println(); |
| 192 | + } |
| 193 | + |
| 194 | + // Second byte is reserved (usually 0) |
| 195 | + |
| 196 | + // Bytes 2-7 contain up to 6 key codes |
| 197 | + bool keysPressed = false; |
| 198 | + |
| 199 | + for (int i = 2; i < 8; i++) { |
| 200 | + uint8_t key = report[i]; |
| 201 | + |
| 202 | + // Skip if no key or error rollover |
| 203 | + if (key == 0 || key == 1) { |
| 204 | + continue; |
| 205 | + } |
| 206 | + |
| 207 | + if (!keysPressed) { |
| 208 | + Serial.print("Keys: "); |
| 209 | + keysPressed = true; |
| 210 | + } |
| 211 | + |
| 212 | + // Print key name based on HID Usage Tables for standard keyboard |
| 213 | + printKeyName(key); |
| 214 | + Serial.print(" "); |
| 215 | + } |
| 216 | + |
| 217 | + if (keysPressed) { |
| 218 | + Serial.println(); |
| 219 | + } else if (modifiers == 0) { |
| 220 | + Serial.println("No keys pressed"); |
| 221 | + } |
| 222 | +} |
0 commit comments