From 929ed2a0f47af08c28e19e7e812655816a58ddc3 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Fri, 13 Aug 2021 16:43:32 +0300 Subject: [PATCH 01/17] Implement USB HID Devices --- .../USB/examples/CompositeDevice/.skip.esp32 | 0 .../examples/CompositeDevice/.skip.esp32c3 | 0 .../CompositeDevice/CompositeDevice.ino | 212 ++++++++++ .../USB/examples/ConsumerControl/.skip.esp32 | 0 .../examples/ConsumerControl/.skip.esp32c3 | 0 .../ConsumerControl/ConsumerControl.ino | 20 + libraries/USB/examples/Gamepad/.skip.esp32 | 0 libraries/USB/examples/Gamepad/.skip.esp32c3 | 0 libraries/USB/examples/Gamepad/Gamepad.ino | 20 + libraries/USB/examples/HIDVendor/.skip.esp32 | 0 .../USB/examples/HIDVendor/.skip.esp32c3 | 0 .../USB/examples/HIDVendor/HIDVendor.ino | 51 +++ .../Keyboard/KeyboardLogout/.skip.esp32 | 0 .../Keyboard/KeyboardLogout/.skip.esp32c3 | 0 .../KeyboardLogout/KeyboardLogout.ino | 91 +++++ .../Keyboard/KeyboardMessage/.skip.esp32 | 0 .../Keyboard/KeyboardMessage/.skip.esp32c3 | 0 .../KeyboardMessage/KeyboardMessage.ino | 54 +++ .../Keyboard/KeyboardReprogram/.skip.esp32 | 0 .../Keyboard/KeyboardReprogram/.skip.esp32c3 | 0 .../KeyboardReprogram/KeyboardReprogram.ino | 105 +++++ .../Keyboard/KeyboardSerial/.skip.esp32 | 0 .../Keyboard/KeyboardSerial/.skip.esp32c3 | 0 .../KeyboardSerial/KeyboardSerial.ino | 39 ++ .../KeyboardAndMouseControl/.skip.esp32 | 0 .../KeyboardAndMouseControl/.skip.esp32c3 | 0 .../KeyboardAndMouseControl.ino | 94 +++++ .../Mouse/ButtonMouseControl/.skip.esp32 | 0 .../Mouse/ButtonMouseControl/.skip.esp32c3 | 0 .../ButtonMouseControl/ButtonMouseControl.ino | 85 ++++ .../USB/examples/SystemControl/.skip.esp32 | 0 .../USB/examples/SystemControl/.skip.esp32c3 | 0 .../examples/SystemControl/SystemControl.ino | 20 + libraries/USB/src/USBHID.cpp | 257 ++++++++++++ libraries/USB/src/USBHID.h | 72 ++++ libraries/USB/src/USBHIDConsumerControl.cpp | 88 +++++ libraries/USB/src/USBHIDConsumerControl.h | 86 ++++ libraries/USB/src/USBHIDGamepad.cpp | 141 +++++++ libraries/USB/src/USBHIDGamepad.h | 88 +++++ libraries/USB/src/USBHIDKeyboard.cpp | 373 ++++++++++++++++++ libraries/USB/src/USBHIDKeyboard.h | 141 +++++++ libraries/USB/src/USBHIDMouse.cpp | 113 ++++++ libraries/USB/src/USBHIDMouse.h | 55 +++ libraries/USB/src/USBHIDSystemControl.cpp | 90 +++++ libraries/USB/src/USBHIDSystemControl.h | 40 ++ libraries/USB/src/USBHIDVendor.cpp | 236 +++++++++++ libraries/USB/src/USBHIDVendor.h | 64 +++ libraries/USB/src/USB_NOT.h | 15 - 48 files changed, 2635 insertions(+), 15 deletions(-) create mode 100644 libraries/USB/examples/CompositeDevice/.skip.esp32 create mode 100644 libraries/USB/examples/CompositeDevice/.skip.esp32c3 create mode 100644 libraries/USB/examples/CompositeDevice/CompositeDevice.ino create mode 100644 libraries/USB/examples/ConsumerControl/.skip.esp32 create mode 100644 libraries/USB/examples/ConsumerControl/.skip.esp32c3 create mode 100644 libraries/USB/examples/ConsumerControl/ConsumerControl.ino create mode 100644 libraries/USB/examples/Gamepad/.skip.esp32 create mode 100644 libraries/USB/examples/Gamepad/.skip.esp32c3 create mode 100644 libraries/USB/examples/Gamepad/Gamepad.ino create mode 100644 libraries/USB/examples/HIDVendor/.skip.esp32 create mode 100644 libraries/USB/examples/HIDVendor/.skip.esp32c3 create mode 100644 libraries/USB/examples/HIDVendor/HIDVendor.ino create mode 100644 libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32 create mode 100644 libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32c3 create mode 100644 libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino create mode 100644 libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32 create mode 100644 libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32c3 create mode 100644 libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino create mode 100644 libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32 create mode 100644 libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32c3 create mode 100644 libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino create mode 100644 libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32 create mode 100644 libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32c3 create mode 100644 libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino create mode 100644 libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32 create mode 100644 libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32c3 create mode 100644 libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino create mode 100644 libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32 create mode 100644 libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32c3 create mode 100644 libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino create mode 100644 libraries/USB/examples/SystemControl/.skip.esp32 create mode 100644 libraries/USB/examples/SystemControl/.skip.esp32c3 create mode 100644 libraries/USB/examples/SystemControl/SystemControl.ino create mode 100644 libraries/USB/src/USBHID.cpp create mode 100644 libraries/USB/src/USBHID.h create mode 100644 libraries/USB/src/USBHIDConsumerControl.cpp create mode 100644 libraries/USB/src/USBHIDConsumerControl.h create mode 100644 libraries/USB/src/USBHIDGamepad.cpp create mode 100644 libraries/USB/src/USBHIDGamepad.h create mode 100644 libraries/USB/src/USBHIDKeyboard.cpp create mode 100644 libraries/USB/src/USBHIDKeyboard.h create mode 100644 libraries/USB/src/USBHIDMouse.cpp create mode 100644 libraries/USB/src/USBHIDMouse.h create mode 100644 libraries/USB/src/USBHIDSystemControl.cpp create mode 100644 libraries/USB/src/USBHIDSystemControl.h create mode 100644 libraries/USB/src/USBHIDVendor.cpp create mode 100644 libraries/USB/src/USBHIDVendor.h delete mode 100644 libraries/USB/src/USB_NOT.h diff --git a/libraries/USB/examples/CompositeDevice/.skip.esp32 b/libraries/USB/examples/CompositeDevice/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/CompositeDevice/.skip.esp32c3 b/libraries/USB/examples/CompositeDevice/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/CompositeDevice/CompositeDevice.ino b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino new file mode 100644 index 00000000000..16d137ed22f --- /dev/null +++ b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino @@ -0,0 +1,212 @@ +#include "USB.h" +#include "USBHIDMouse.h" +#include "USBHIDKeyboard.h" +#include "USBHIDGamepad.h" +#include "USBHIDConsumerControl.h" +#include "USBHIDSystemControl.h" +#include "USBHIDVendor.h" +#include "FirmwareMSC.h" + +#if !ARDUINO_USB_MSC_ON_BOOT +FirmwareMSC MSC_Update; +#endif +#if ARDUINO_USB_CDC_ON_BOOT +#define HWSerial Serial0 +#define USBSerial Serial +#else +#define HWSerial Serial +USBCDC USBSerial; +#endif + +USBHID HID; +USBHIDKeyboard Keyboard; +USBHIDMouse Mouse; +USBHIDGamepad Gamepad; +USBHIDConsumerControl ConsumerControl; +USBHIDSystemControl SystemControl; +USBHIDVendor Vendor; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + if(event_base == ARDUINO_USB_EVENTS){ + arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_STARTED_EVENT: + HWSerial.println("USB PLUGGED"); + break; + case ARDUINO_USB_STOPPED_EVENT: + HWSerial.println("USB UNPLUGGED"); + break; + case ARDUINO_USB_SUSPEND_EVENT: + HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); + break; + case ARDUINO_USB_RESUME_EVENT: + HWSerial.println("USB RESUMED"); + break; + + default: + break; + } + } else if(event_base == ARDUINO_USB_CDC_EVENTS){ + arduino_usb_cdc_event_data_t * data = (arduino_usb_cdc_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_CDC_CONNECTED_EVENT: + HWSerial.println("CDC CONNECTED"); + break; + case ARDUINO_USB_CDC_DISCONNECTED_EVENT: + HWSerial.println("CDC DISCONNECTED"); + break; + case ARDUINO_USB_CDC_LINE_STATE_EVENT: + HWSerial.printf("CDC LINE STATE: dtr: %u, rts: %u\n", data->line_state.dtr, data->line_state.rts); + break; + case ARDUINO_USB_CDC_LINE_CODING_EVENT: + HWSerial.printf("CDC LINE CODING: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", data->line_coding.bit_rate, data->line_coding.data_bits, data->line_coding.stop_bits, data->line_coding.parity); + break; + case ARDUINO_USB_CDC_RX_EVENT: + HWSerial.printf("CDC RX [%u]:", data->rx.len); + { + uint8_t buf[data->rx.len]; + size_t len = USBSerial.read(buf, data->rx.len); + HWSerial.write(buf, len); + } + HWSerial.println(); + break; + + default: + break; + } + } else if(event_base == ARDUINO_FIRMWARE_MSC_EVENTS){ + arduino_firmware_msc_event_data_t * data = (arduino_firmware_msc_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_FIRMWARE_MSC_START_EVENT: + HWSerial.println("MSC Update Start"); + break; + case ARDUINO_FIRMWARE_MSC_WRITE_EVENT: + //HWSerial.printf("MSC Update Write %u bytes at offset %u\n", data->write.size, data->write.offset); + HWSerial.print("."); + break; + case ARDUINO_FIRMWARE_MSC_END_EVENT: + HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size); + break; + case ARDUINO_FIRMWARE_MSC_ERROR_EVENT: + HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size); + break; + case ARDUINO_FIRMWARE_MSC_POWER_EVENT: + HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject); + break; + + default: + break; + } + } else if(event_base == ARDUINO_USB_HID_EVENTS){ + arduino_usb_hid_event_data_t * data = (arduino_usb_hid_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_HID_SET_PROTOCOL_EVENT: + HWSerial.printf("HID SET PROTOCOL: %s\n", data->set_protocol.protocol?"REPORT":"BOOT"); + break; + case ARDUINO_USB_HID_SET_IDLE_EVENT: + HWSerial.printf("HID SET IDLE: %u\n", data->set_idle.idle_rate); + break; + + default: + break; + } + } else if(event_base == ARDUINO_USB_HID_KEYBOARD_EVENTS){ + arduino_usb_hid_keyboard_event_data_t * data = (arduino_usb_hid_keyboard_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_HID_KEYBOARD_LED_EVENT: + HWSerial.printf("HID KEYBOARD LED: NumLock:%u, CapsLock:%u, ScrollLock:%u\n", data->numlock, data->capslock, data->scrolllock); + break; + + default: + break; + } + } else if(event_base == ARDUINO_USB_HID_VENDOR_EVENTS){ + arduino_usb_hid_vendor_event_data_t * data = (arduino_usb_hid_vendor_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT: + HWSerial.printf("HID VENDOR GET FEATURE: len:%u\n", data->len); + for(uint16_t i=0; ilen; i++){ + HWSerial.write(data->buffer[i]?data->buffer[i]:'.'); + } + HWSerial.println(); + break; + case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT: + HWSerial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len); + for(uint16_t i=0; ilen; i++){ + HWSerial.write(data->buffer[i]?data->buffer[i]:'.'); + } + HWSerial.println(); + break; + case ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT: + HWSerial.printf("HID VENDOR OUTPUT: len:%u\n", data->len); + for(uint16_t i=0; ilen; i++){ + HWSerial.write(Vendor.read()); + } + HWSerial.println(); + break; + + default: + break; + } + } +} + +void setup() { + HWSerial.begin(115200); + HWSerial.setDebugOutput(true); + + USB.onEvent(usbEventCallback); + USBSerial.onEvent(usbEventCallback); + MSC_Update.onEvent(usbEventCallback); + HID.onEvent(usbEventCallback); + Keyboard.onEvent(usbEventCallback); + Vendor.onEvent(usbEventCallback); + + USBSerial.begin(); + MSC_Update.begin(); + Vendor.begin(); + Mouse.begin(); + Keyboard.begin(); + Gamepad.begin(); + ConsumerControl.begin(); + SystemControl.begin(); + HID.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if (buttonState != previousButtonState) { + previousButtonState = buttonState; + if (buttonState == LOW) { + HWSerial.println("Button Pressed"); + USBSerial.println("Button Pressed"); + Vendor.println("Button Pressed"); + Mouse.move(10,10); + Keyboard.pressRaw(HID_KEY_CAPS_LOCK); + Gamepad.leftStick(100,100); + ConsumerControl.press(CONSUMER_CONTROL_VOLUME_INCREMENT); + //SystemControl.press(SYSTEM_CONTROL_POWER_OFF); + } else { + Keyboard.releaseRaw(HID_KEY_CAPS_LOCK); + Gamepad.leftStick(0,0); + ConsumerControl.release(); + //SystemControl.release(); + Vendor.println("Button Released"); + USBSerial.println("Button Released"); + HWSerial.println("Button Released"); + } + delay(100); + } + + while(HWSerial.available()){ + size_t l = HWSerial.available(); + uint8_t b[l]; + l = HWSerial.read(b, l); + USBSerial.write(b, l); + Vendor.write(b,l); + } +} diff --git a/libraries/USB/examples/ConsumerControl/.skip.esp32 b/libraries/USB/examples/ConsumerControl/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/ConsumerControl/.skip.esp32c3 b/libraries/USB/examples/ConsumerControl/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/ConsumerControl/ConsumerControl.ino b/libraries/USB/examples/ConsumerControl/ConsumerControl.ino new file mode 100644 index 00000000000..d3fbe81f85f --- /dev/null +++ b/libraries/USB/examples/ConsumerControl/ConsumerControl.ino @@ -0,0 +1,20 @@ +#include "USBHIDConsumerControl.h" +USBHIDConsumerControl ConsumerControl; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +void setup() { + pinMode(buttonPin, INPUT_PULLUP); + ConsumerControl.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if ((buttonState != previousButtonState) && (buttonState == LOW)) { + ConsumerControl.press(CONSUMER_CONTROL_VOLUME_INCREMENT); + ConsumerControl.release(); + } + previousButtonState = buttonState; +} diff --git a/libraries/USB/examples/Gamepad/.skip.esp32 b/libraries/USB/examples/Gamepad/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Gamepad/.skip.esp32c3 b/libraries/USB/examples/Gamepad/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Gamepad/Gamepad.ino b/libraries/USB/examples/Gamepad/Gamepad.ino new file mode 100644 index 00000000000..e7cd9a4d817 --- /dev/null +++ b/libraries/USB/examples/Gamepad/Gamepad.ino @@ -0,0 +1,20 @@ +#include "USBHIDGamepad.h" +USBHIDGamepad Gamepad; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +void setup() { + pinMode(buttonPin, INPUT_PULLUP); + Gamepad.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if ((buttonState != previousButtonState) && (buttonState == LOW)) { + Gamepad.pressButton(BUTTON_START); + Gamepad.releaseButton(BUTTON_START); + } + previousButtonState = buttonState; +} diff --git a/libraries/USB/examples/HIDVendor/.skip.esp32 b/libraries/USB/examples/HIDVendor/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/HIDVendor/.skip.esp32c3 b/libraries/USB/examples/HIDVendor/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/HIDVendor/HIDVendor.ino b/libraries/USB/examples/HIDVendor/HIDVendor.ino new file mode 100644 index 00000000000..f4727415761 --- /dev/null +++ b/libraries/USB/examples/HIDVendor/HIDVendor.ino @@ -0,0 +1,51 @@ +#include "USBHIDVendor.h" +USBHIDVendor Vendor; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +static void vendorEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + if(event_base == ARDUINO_USB_HID_VENDOR_EVENTS){ + arduino_usb_hid_vendor_event_data_t * data = (arduino_usb_hid_vendor_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT: + Serial.printf("HID VENDOR GET FEATURE: len:%u\n", data->len); + break; + case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT: + Serial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len); + for(uint16_t i=0; ilen; i++){ + Serial.printf("0x%02X ",data->buffer); + } + Serial.println(); + break; + case ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT: + Serial.printf("HID VENDOR OUTPUT: len:%u\n", data->len); + // for(uint16_t i=0; ilen; i++){ + // Serial.write(Vendor.read()); + // } + break; + + default: + break; + } + } +} + +void setup() { + pinMode(buttonPin, INPUT_PULLUP); + Serial.begin(115200); + Vendor.onEvent(vendorEventCallback); + Vendor.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if ((buttonState != previousButtonState) && (buttonState == LOW)) { + Vendor.println("Hello World!"); + } + previousButtonState = buttonState; + while(Vendor.available()){ + Serial.write(Vendor.read()); + } +} diff --git a/libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32 b/libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32c3 b/libraries/USB/examples/Keyboard/KeyboardLogout/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino b/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino new file mode 100644 index 00000000000..90cf6bb4bac --- /dev/null +++ b/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino @@ -0,0 +1,91 @@ +/* + Keyboard logout + + This sketch demonstrates the Keyboard library. + + When you connect pin 2 to ground, it performs a logout. + It uses keyboard combinations to do this, as follows: + + On Windows, CTRL-ALT-DEL followed by ALT-l + On Ubuntu, CTRL-ALT-DEL, and ENTER + On OSX, CMD-SHIFT-q + + To wake: Spacebar. + + Circuit: + - Arduino Leonardo or Micro + - wire to connect D2 to ground + + created 6 Mar 2012 + modified 27 Mar 2012 + by Tom Igoe + + This example is in the public domain. + + http://www.arduino.cc/en/Tutorial/KeyboardLogout +*/ + +#define OSX 0 +#define WINDOWS 1 +#define UBUNTU 2 + +#include "USBHIDKeyboard.h" +USBHIDKeyboard Keyboard; + +// change this to match your platform: +int platform = OSX; + +void setup() { + // make pin 0 an input and turn on the pull-up resistor so it goes high unless + // connected to ground: + pinMode(0, INPUT_PULLUP); + Keyboard.begin(); + USB.begin(); +} + +void loop() { + while (digitalRead(0) == HIGH) { + // do nothing until pin 2 goes low + delay(500); + } + delay(1000); + + switch (platform) { + case OSX: + Keyboard.press(KEY_LEFT_GUI); + // Shift-Q logs out: + Keyboard.press(KEY_LEFT_SHIFT); + Keyboard.press('Q'); + delay(100); + Keyboard.releaseAll(); + // enter: + Keyboard.write(KEY_RETURN); + break; + case WINDOWS: + // CTRL-ALT-DEL: + Keyboard.press(KEY_LEFT_CTRL); + Keyboard.press(KEY_LEFT_ALT); + Keyboard.press(KEY_DELETE); + delay(100); + Keyboard.releaseAll(); + // ALT-l: + delay(2000); + Keyboard.press(KEY_LEFT_ALT); + Keyboard.press('l'); + Keyboard.releaseAll(); + break; + case UBUNTU: + // CTRL-ALT-DEL: + Keyboard.press(KEY_LEFT_CTRL); + Keyboard.press(KEY_LEFT_ALT); + Keyboard.press(KEY_DELETE); + delay(1000); + Keyboard.releaseAll(); + // Enter to confirm logout: + Keyboard.write(KEY_RETURN); + break; + } + + // do nothing: + while (true) delay(1000); +} diff --git a/libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32 b/libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32c3 b/libraries/USB/examples/Keyboard/KeyboardMessage/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino b/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino new file mode 100644 index 00000000000..93766bad3df --- /dev/null +++ b/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino @@ -0,0 +1,54 @@ +/* + Keyboard Message test + + For the Arduino Leonardo and Micro. + + Sends a text string when a button is pressed. + + The circuit: + - pushbutton attached from pin 0 to ground + - 10 kilohm resistor attached from pin 0 to +5V + + created 24 Oct 2011 + modified 27 Mar 2012 + by Tom Igoe + modified 11 Nov 2013 + by Scott Fitzgerald + + This example code is in the public domain. + + http://www.arduino.cc/en/Tutorial/KeyboardMessage +*/ + +#include "USBHIDKeyboard.h" +USBHIDKeyboard Keyboard; + +const int buttonPin = 0; // input pin for pushbutton +int previousButtonState = HIGH; // for checking the state of a pushButton +int counter = 0; // button push counter + +void setup() { + // make the pushButton pin an input: + pinMode(buttonPin, INPUT_PULLUP); + // initialize control over the keyboard: + Keyboard.begin(); + USB.begin(); +} + +void loop() { + // read the pushbutton: + int buttonState = digitalRead(buttonPin); + // if the button state has changed, + if ((buttonState != previousButtonState) + // and it's currently pressed: + && (buttonState == LOW)) { + // increment the button counter + counter++; + // type out a message + Keyboard.print("You pressed the button "); + Keyboard.print(counter); + Keyboard.println(" times."); + } + // save the current button state for comparison next time: + previousButtonState = buttonState; +} diff --git a/libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32 b/libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32c3 b/libraries/USB/examples/Keyboard/KeyboardReprogram/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino b/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino new file mode 100644 index 00000000000..192f91f03fb --- /dev/null +++ b/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino @@ -0,0 +1,105 @@ +/* + Arduino Programs Blink + + This sketch demonstrates the Keyboard library. + + For Leonardo and Due boards only. + + When you connect pin 2 to ground, it creates a new window with a key + combination (CTRL-N), then types in the Blink sketch, then auto-formats the + text using another key combination (CTRL-T), then uploads the sketch to the + currently selected Arduino using a final key combination (CTRL-U). + + Circuit: + - Arduino Leonardo, Micro, Due, LilyPad USB, or Yún + - wire to connect D2 to ground + + created 5 Mar 2012 + modified 29 Mar 2012 + by Tom Igoe + modified 3 May 2014 + by Scott Fitzgerald + + This example is in the public domain. + + http://www.arduino.cc/en/Tutorial/KeyboardReprogram +*/ + +#include "USBHIDKeyboard.h" +USBHIDKeyboard Keyboard; + +// use this option for OSX. +// Comment it out if using Windows or Linux: +char ctrlKey = KEY_LEFT_GUI; +// use this option for Windows and Linux. +// leave commented out if using OSX: +// char ctrlKey = KEY_LEFT_CTRL; + + +void setup() { + // make pin 0 an input and turn on the pull-up resistor so it goes high unless + // connected to ground: + pinMode(0, INPUT_PULLUP); + // initialize control over the keyboard: + Keyboard.begin(); + USB.begin(); +} + +void loop() { + while (digitalRead(0) == HIGH) { + // do nothing until pin 0 goes low + delay(500); + } + delay(1000); + // new document: + Keyboard.press(ctrlKey); + Keyboard.press('n'); + delay(100); + Keyboard.releaseAll(); + // wait for new window to open: + delay(1000); + + // versions of the Arduino IDE after 1.5 pre-populate new sketches with + // setup() and loop() functions let's clear the window before typing anything new + // select all + Keyboard.press(ctrlKey); + Keyboard.press('a'); + delay(500); + Keyboard.releaseAll(); + // delete the selected text + Keyboard.write(KEY_BACKSPACE); + delay(500); + + // Type out "blink": + Keyboard.println("void setup() {"); + Keyboard.println("pinMode(13, OUTPUT);"); + Keyboard.println("}"); + Keyboard.println(); + Keyboard.println("void loop() {"); + Keyboard.println("digitalWrite(13, HIGH);"); + Keyboard.print("delay(3000);"); + // 3000 ms is too long. Delete it: + for (int keystrokes = 0; keystrokes < 6; keystrokes++) { + delay(500); + Keyboard.write(KEY_BACKSPACE); + } + // make it 1000 instead: + Keyboard.println("1000);"); + Keyboard.println("digitalWrite(13, LOW);"); + Keyboard.println("delay(1000);"); + Keyboard.println("}"); + // tidy up: + Keyboard.press(ctrlKey); + Keyboard.press('t'); + delay(100); + Keyboard.releaseAll(); + delay(3000); + // upload code: + Keyboard.press(ctrlKey); + Keyboard.press('u'); + delay(100); + Keyboard.releaseAll(); + + // wait for the sweet oblivion of reprogramming: + while (true)delay(1000); +} diff --git a/libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32 b/libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32c3 b/libraries/USB/examples/Keyboard/KeyboardSerial/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino b/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino new file mode 100644 index 00000000000..bcfa7542d4d --- /dev/null +++ b/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino @@ -0,0 +1,39 @@ +/* + Keyboard test + + Reads a byte from the serial port, sends a keystroke back. + The sent keystroke is one higher than what's received, e.g. if you send a, + you get b, send A you get B, and so forth. + + The circuit: + - none + + created 21 Oct 2011 + modified 27 Mar 2012 + by Tom Igoe + + This example code is in the public domain. + + http://www.arduino.cc/en/Tutorial/KeyboardSerial +*/ + +#include "USBHIDKeyboard.h" +USBHIDKeyboard Keyboard; + +void setup() { + // open the serial port: + Serial.begin(115200); + // initialize control over the keyboard: + Keyboard.begin(); + USB.begin(); +} + +void loop() { + // check for incoming serial data: + if (Serial.available() > 0) { + // read incoming serial data: + char inChar = Serial.read(); + // Type the next ASCII value from what you received: + Keyboard.write(inChar + 1); + } +} diff --git a/libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32 b/libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32c3 b/libraries/USB/examples/KeyboardAndMouseControl/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino b/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino new file mode 100644 index 00000000000..14623929c07 --- /dev/null +++ b/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino @@ -0,0 +1,94 @@ +/* + KeyboardAndMouseControl + + Hardware: + - five pushbuttons attached to D12, D13, D14, D15, D0 + + The mouse movement is always relative. This sketch reads four pushbuttons, and + uses them to set the movement of the mouse. + + WARNING: When you use the Mouse.move() command, the Arduino takes over your + mouse! Make sure you have control before you use the mouse commands. + + created 15 Mar 2012 + modified 27 Mar 2012 + by Tom Igoe + + This example code is in the public domain. + + http://www.arduino.cc/en/Tutorial/KeyboardAndMouseControl +*/ + +#include "USBHIDMouse.h" +#include "USBHIDKeyboard.h" +USBHIDMouse Mouse; +USBHIDKeyboard Keyboard; + +// set pin numbers for the five buttons: +const int upButton = 12; +const int downButton = 13; +const int leftButton = 14; +const int rightButton = 15; +const int mouseButton = 0; + +void setup() { // initialize the buttons' inputs: + pinMode(upButton, INPUT_PULLUP); + pinMode(downButton, INPUT_PULLUP); + pinMode(leftButton, INPUT_PULLUP); + pinMode(rightButton, INPUT_PULLUP); + pinMode(mouseButton, INPUT_PULLUP); + + Serial.begin(115200); + // initialize mouse control: + Mouse.begin(); + Keyboard.begin(); + USB.begin(); +} + +void loop() { + // use serial input to control the mouse: + if (Serial.available() > 0) { + char inChar = Serial.read(); + + switch (inChar) { + case 'u': + // move mouse up + Mouse.move(0, -40); + break; + case 'd': + // move mouse down + Mouse.move(0, 40); + break; + case 'l': + // move mouse left + Mouse.move(-40, 0); + break; + case 'r': + // move mouse right + Mouse.move(40, 0); + break; + case 'm': + // perform mouse left click + Mouse.click(MOUSE_LEFT); + break; + } + } + + // use the pushbuttons to control the keyboard: + if (digitalRead(upButton) == LOW) { + Keyboard.write('u'); + } + if (digitalRead(downButton) == LOW) { + Keyboard.write('d'); + } + if (digitalRead(leftButton) == LOW) { + Keyboard.write('l'); + } + if (digitalRead(rightButton) == LOW) { + Keyboard.write('r'); + } + if (digitalRead(mouseButton) == LOW) { + Keyboard.write('m'); + } + delay(5); +} diff --git a/libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32 b/libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32c3 b/libraries/USB/examples/Mouse/ButtonMouseControl/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino b/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino new file mode 100644 index 00000000000..8bc1200afcb --- /dev/null +++ b/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino @@ -0,0 +1,85 @@ +/* + ButtonMouseControl + + Controls the mouse from five pushbuttons on an Arduino Leonardo, Micro or Due. + + Hardware: + - five pushbuttons attached to D12, D13, D14, D15, D0 + + The mouse movement is always relative. This sketch reads four pushbuttons, + and uses them to set the movement of the mouse. + + WARNING: When you use the Mouse.move() command, the Arduino takes over your + mouse! Make sure you have control before you use the mouse commands. + + created 15 Mar 2012 + modified 27 Mar 2012 + by Tom Igoe + + This example code is in the public domain. + + http://www.arduino.cc/en/Tutorial/ButtonMouseControl +*/ + +#include "USBHIDMouse.h" +USBHIDMouse Mouse; + + +// set pin numbers for the five buttons: +const int upButton = 12; +const int downButton = 13; +const int leftButton = 14; +const int rightButton = 15; +const int mouseButton = 0; + +int range = 5; // output range of X or Y movement; affects movement speed +int responseDelay = 10; // response delay of the mouse, in ms + + +void setup() { + // initialize the buttons' inputs: + pinMode(upButton, INPUT_PULLUP); + pinMode(downButton, INPUT_PULLUP); + pinMode(leftButton, INPUT_PULLUP); + pinMode(rightButton, INPUT_PULLUP); + pinMode(mouseButton, INPUT_PULLUP); + // initialize mouse control: + Mouse.begin(); + USB.begin(); +} + +void loop() { + // read the buttons: + int upState = digitalRead(upButton); + int downState = digitalRead(downButton); + int rightState = digitalRead(rightButton); + int leftState = digitalRead(leftButton); + int clickState = digitalRead(mouseButton); + + // calculate the movement distance based on the button states: + int xDistance = (leftState - rightState) * range; + int yDistance = (upState - downState) * range; + + // if X or Y is non-zero, move: + if ((xDistance != 0) || (yDistance != 0)) { + Mouse.move(xDistance, yDistance, 0); + } + + // if the mouse button is pressed: + if (clickState == LOW) { + // if the mouse is not pressed, press it: + if (!Mouse.isPressed(MOUSE_LEFT)) { + Mouse.press(MOUSE_LEFT); + } + } + // else the mouse button is not pressed: + else { + // if the mouse is pressed, release it: + if (Mouse.isPressed(MOUSE_LEFT)) { + Mouse.release(MOUSE_LEFT); + } + } + + // a delay so the mouse doesn't move too fast: + delay(responseDelay); +} diff --git a/libraries/USB/examples/SystemControl/.skip.esp32 b/libraries/USB/examples/SystemControl/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/SystemControl/.skip.esp32c3 b/libraries/USB/examples/SystemControl/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/SystemControl/SystemControl.ino b/libraries/USB/examples/SystemControl/SystemControl.ino new file mode 100644 index 00000000000..f4a7f5c5843 --- /dev/null +++ b/libraries/USB/examples/SystemControl/SystemControl.ino @@ -0,0 +1,20 @@ +#include "USBHIDSystemControl.h" +USBHIDSystemControl SystemControl; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +void setup() { + pinMode(buttonPin, INPUT_PULLUP); + SystemControl.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if ((buttonState != previousButtonState) && (buttonState == LOW)) { + SystemControl.press(SYSTEM_CONTROL_POWER_OFF); + SystemControl.release(); + } + previousButtonState = buttonState; +} diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp new file mode 100644 index 00000000000..c73b3edc2bb --- /dev/null +++ b/libraries/USB/src/USBHID.cpp @@ -0,0 +1,257 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHID.h" + +#if CFG_TUD_HID +#define USB_HID_DEVICES_MAX 10 + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +static void log_print_buf_line(const uint8_t *b, size_t len){ + for(size_t i = 0; i= 0x20) && (b[i] < 0x80))?b[i]:'.'); + } + log_printf("\n"); +} + +void log_print_buf(const uint8_t *b, size_t len){ + if(!len || !b){ + return; + } + for(size_t i = 0; i= USB_HID_DEVICES_MAX){ + log_e("Maximum devices already enabled! Device not enabled"); + return false; + } + tinyusb_hid_device_descriptor_len += descriptor_len; + tinyusb_loaded_hid_devices_callbacks[tinyusb_loaded_hid_devices_num++] = cb; + log_d("Device enabled"); + return true; +} + +static uint16_t tinyusb_load_hid_descriptor(uint8_t interface, uint8_t * dst, uint8_t report_id) +{ + if(interface < USB_HID_DEVICES_MAX && tinyusb_loaded_hid_devices_callbacks[interface] != NULL){ + return tinyusb_loaded_hid_devices_callbacks[interface](dst, report_id); + } + return 0; +} + +static bool tinyusb_load_enabled_hid_devices(){ + tinyusb_hid_device_descriptor = (uint8_t *)malloc(tinyusb_hid_device_descriptor_len); + if (tinyusb_hid_device_descriptor == NULL) { + log_e("HID Descriptor Malloc Failed"); + return false; + } + uint8_t * dst = tinyusb_hid_device_descriptor; + + for(uint8_t i=0; i 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). +bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate){ + log_d("instance: %u, idle_rate:%u", instance, idle_rate); + arduino_usb_hid_event_data_t p = {0}; + p.instance = instance; + p.set_idle.idle_rate = idle_rate; + arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_IDLE_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY); + return true; +} + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){ + if(report_id < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report_id]){ + return tinyusb_hid_devices[report_id]->_onGetFeature(buffer, reqlen); + } + log_d("instance: %u, report_id: %u, report_type: %s, reqlen: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], reqlen); + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize){ + if(!report_id && !report_type){ + report_id = buffer[0]; + if(report_id < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report_id]){ + tinyusb_hid_devices[report_id]->_onOutput(buffer+1, bufsize-1); + } else { + log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, *buffer, tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1); + log_print_buf(buffer+1, bufsize-1); + } + } else { + if(report_id < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report_id]){ + tinyusb_hid_devices[report_id]->_onSetFeature(buffer, bufsize); + } else { + log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], bufsize); + log_print_buf(buffer, bufsize); + } + } +} + +// Invoked when sent REPORT successfully to host +// Application can use this to send the next report +// Note: For composite reports, report[0] is report ID +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){ + if(report[0] < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report[0]]){ + tinyusb_hid_devices[report[0]]->_onInputDone(report+1, len-1); + } else { + log_i("instance: %u, report_id: %u, report_type: %s, bufsize:%u", instance, report[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_INPUT], len-1); + log_print_buf(report+1, len-1); + } +} + +bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms){ + if(tud_hid_n_ready(instance)){ + return true; + } + uint32_t start_ms = millis(); + while(!tud_hid_n_ready(instance)){ + if((millis() - start_ms) > timeout_ms){ + return false; + } + delay(1); + } + return true; +} + +USBHID::USBHID(){ + if(!tinyusb_hid_devices_is_initialized){ + tinyusb_hid_devices_is_initialized = true; + memset(tinyusb_hid_devices, 0, sizeof(tinyusb_hid_devices)); + tinyusb_hid_devices_num = 0; + tinyusb_enable_interface(USB_INTERFACE_HID, TUD_HID_INOUT_DESC_LEN, tusb_hid_load_descriptor); + } + +} + +void USBHID::begin(){ + +} + +void USBHID::end(){ + +} + +bool USBHID::addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb){ + if(device && tinyusb_loaded_hid_devices_num < USB_HID_DEVICES_MAX){ + if(!tinyusb_enable_hid_device(descriptor_len, cb)){ + return false; + } + device->id = tinyusb_loaded_hid_devices_num; + tinyusb_hid_devices[tinyusb_loaded_hid_devices_num] = device; + return true; + } + return false; +} + +void USBHID::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_HID_ANY_EVENT, callback); +} +void USBHID::onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_HID_EVENTS, event, callback, this); +} + +#endif /* CONFIG_USB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHID.h b/libraries/USB/src/USBHID.h new file mode 100644 index 00000000000..dba35fb8a4f --- /dev/null +++ b/libraries/USB/src/USBHID.h @@ -0,0 +1,72 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include +#include "esp32-hal.h" +#include "USB.h" +#if CONFIG_TINYUSB_HID_ENABLED + +#include "class/hid/hid.h" +#include "esp_event.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_EVENTS); + +typedef enum { + ARDUINO_USB_HID_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_HID_SET_PROTOCOL_EVENT = 0, + ARDUINO_USB_HID_SET_IDLE_EVENT, + ARDUINO_USB_HID_MAX_EVENT, +} arduino_usb_hid_event_t; + +typedef struct { + uint8_t instance; + union { + struct { + uint8_t protocol; + } set_protocol; + struct { + uint8_t idle_rate; + } set_idle; + }; +} arduino_usb_hid_event_data_t; + +typedef uint16_t (*tinyusb_hid_device_descriptor_cb_t)(uint8_t * dst, uint8_t report_id); + +class USBHIDDevice +{ +public: + uint8_t id; + USBHIDDevice():id(0){} + virtual uint16_t _onGetFeature(uint8_t* buffer, uint16_t len){return 0;} + virtual void _onSetFeature(const uint8_t* buffer, uint16_t len){} + virtual void _onOutput(const uint8_t* buffer, uint16_t len){} + virtual void _onInputDone(const uint8_t* buffer, uint16_t len){} +}; + +class USBHID +{ +public: + USBHID(void); + void begin(void); + void end(void); + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback); + static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb); +}; + +bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms); + +#endif diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp new file mode 100644 index 00000000000..9cf98d4539a --- /dev/null +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -0,0 +1,88 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDConsumerControl.h" + +#if CFG_TUD_HID + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDConsumerControl::USBHIDConsumerControl(): hid(), tx_sem(NULL){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + } else { + isr_log_e("Only one instance of USBHIDConsumerControl is allowed!"); + abort(); + } +} + +void USBHIDConsumerControl::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } +} + +void USBHIDConsumerControl::end(){ + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDConsumerControl::_onInputDone(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + xSemaphoreGive(tx_sem); +} + +bool USBHIDConsumerControl::send(uint16_t value){ + uint32_t timeout_ms = 100; + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return false; + } + bool res = tud_hid_n_report(0, id, &value, 2); + if(!res){ + log_e("report failed"); + return false; + } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + return false; + } + return true; +} + +size_t USBHIDConsumerControl::press(uint16_t k){ + return send(k); +} + +size_t USBHIDConsumerControl::release(){ + return send(0); +} + + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDConsumerControl.h b/libraries/USB/src/USBHIDConsumerControl.h new file mode 100644 index 00000000000..df0b5275b85 --- /dev/null +++ b/libraries/USB/src/USBHIDConsumerControl.h @@ -0,0 +1,86 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +// Power Control +#define CONSUMER_CONTROL_POWER 0x0030 +#define CONSUMER_CONTROL_RESET 0x0031 +#define CONSUMER_CONTROL_SLEEP 0x0032 + +// Screen Brightness +#define CONSUMER_CONTROL_BRIGHTNESS_INCREMENT 0x006F +#define CONSUMER_CONTROL_BRIGHTNESS_DECREMENT 0x0070 + +// These HID usages operate only on mobile systems (battery powered) and +// require Windows 8 (build 8302 or greater). +#define CONSUMER_CONTROL_WIRELESS_RADIO_CONTROLS 0x000C +#define CONSUMER_CONTROL_WIRELESS_RADIO_BUTTONS 0x00C6 +#define CONSUMER_CONTROL_WIRELESS_RADIO_LED 0x00C7 +#define CONSUMER_CONTROL_WIRELESS_RADIO_SLIDER_SWITCH 0x00C8 + +// Media Control +#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD +#define CONSUMER_CONTROL_SCAN_NEXT 0x00B5 +#define CONSUMER_CONTROL_SCAN_PREVIOUS 0x00B6 +#define CONSUMER_CONTROL_STOP 0x00B7 +#define CONSUMER_CONTROL_VOLUME 0x00E0 +#define CONSUMER_CONTROL_MUTE 0x00E2 +#define CONSUMER_CONTROL_BASS 0x00E3 +#define CONSUMER_CONTROL_TREBLE 0x00E4 +#define CONSUMER_CONTROL_BASS_BOOST 0x00E5 +#define CONSUMER_CONTROL_VOLUME_INCREMENT 0x00E9 +#define CONSUMER_CONTROL_VOLUME_DECREMENT 0x00EA +#define CONSUMER_CONTROL_BASS_INCREMENT 0x0152 +#define CONSUMER_CONTROL_BASS_DECREMENT 0x0153 +#define CONSUMER_CONTROL_TREBLE_INCREMENT 0x0154 +#define CONSUMER_CONTROL_TREBLE_DECREMENT 0x0155 + +// Application Launcher +#define CONSUMER_CONTROL_CONFIGURATION 0x0183 +#define CONSUMER_CONTROL_EMAIL_READER 0x018A +#define CONSUMER_CONTROL_CALCULATOR 0x0192 +#define CONSUMER_CONTROL_LOCAL_BROWSER 0x0194 + +// Browser/Explorer Specific +#define CONSUMER_CONTROL_SEARCH 0x0221 +#define CONSUMER_CONTROL_HOME 0x0223 +#define CONSUMER_CONTROL_BACK 0x0224 +#define CONSUMER_CONTROL_FORWARD 0x0225 +#define CONSUMER_CONTROL_BR_STOP 0x0226 +#define CONSUMER_CONTROL_REFRESH 0x0227 +#define CONSUMER_CONTROL_BOOKMARKS 0x022A + +// Mouse Horizontal scroll +#define CONSUMER_CONTROL_PAN 0x0238 + +class USBHIDConsumerControl: public USBHIDDevice { +private: + USBHID hid; + xSemaphoreHandle tx_sem; + bool send(uint16_t value); +public: + USBHIDConsumerControl(void); + void begin(void); + void end(void); + size_t press(uint16_t k); + size_t release(); + + //internal use + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp new file mode 100644 index 00000000000..0c13e9de516 --- /dev/null +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -0,0 +1,141 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDGamepad.h" + +#if CFG_TUD_HID + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDGamepad::USBHIDGamepad(): hid(), tx_sem(NULL), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + } else { + isr_log_e("Only one instance of USBHIDGamepad is allowed!"); + abort(); + } +} + +void USBHIDGamepad::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } +} + +void USBHIDGamepad::end(){ + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDGamepad::_onInputDone(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + xSemaphoreGive(tx_sem); +} + +bool USBHIDGamepad::write(){ + uint32_t timeout_ms = 100; + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return false; + } + bool res = tud_hid_n_gamepad_report(0, id, _x, _y, _z, _rz, _rx, _ry, _hat, _buttons); + if(!res){ + log_e("report failed"); + return false; + } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + return false; + } + return true; +} + +bool USBHIDGamepad::leftStick(int8_t x, int8_t y){ + _x = x; + _y = y; + return write(); +} + +bool USBHIDGamepad::rightStick(int8_t z, int8_t rz){ + _z = z; + _rz = rz; + return write(); +} + +bool USBHIDGamepad::leftTrigger(int8_t rx){ + _rx = rx; + return write(); +} + +bool USBHIDGamepad::rightTrigger(int8_t ry){ + _ry = ry; + return write(); +} + +bool USBHIDGamepad::hat(uint8_t hat){ + if(hat > 9){ + return false; + } + _hat = hat; + return write(); +} + +bool USBHIDGamepad::pressButton(uint8_t button){ + if(button > 31){ + return false; + } + _buttons |= (1 << button); + return write(); +} + +bool USBHIDGamepad::releaseButton(uint8_t button){ + if(button > 31){ + return false; + } + _buttons &= ~(1 << button); + return write(); +} + +bool USBHIDGamepad::send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons){ + if(hat > 9){ + return false; + } + _x = x; + _y = y; + _z = z; + _rz = rz; + _rx = rx; + _ry = ry; + _hat = hat; + _buttons = buttons; + return write(); +} + + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDGamepad.h b/libraries/USB/src/USBHIDGamepad.h new file mode 100644 index 00000000000..bace503c890 --- /dev/null +++ b/libraries/USB/src/USBHIDGamepad.h @@ -0,0 +1,88 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +/// Standard Gamepad Buttons Naming from Linux input event codes +/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h +#define BUTTON_A 0 +#define BUTTON_B 1 +#define BUTTON_C 2 +#define BUTTON_X 3 +#define BUTTON_Y 4 +#define BUTTON_Z 5 +#define BUTTON_TL 6 +#define BUTTON_TR 7 +#define BUTTON_TL2 8 +#define BUTTON_TR2 9 +#define BUTTON_SELECT 10 +#define BUTTON_START 11 +#define BUTTON_MODE 12 +#define BUTTON_THUMBL 13 +#define BUTTON_THUMBR 14 + +#define BUTTON_SOUTH BUTTON_A +#define BUTTON_EAST BUTTON_B +#define BUTTON_NORTH BUTTON_X +#define BUTTON_WEST BUTTON_Y + +/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes) +#define HAT_CENTER 0 +#define HAT_UP 1 +#define HAT_UP_RIGHT 2 +#define HAT_RIGHT 3 +#define HAT_DOWN_RIGHT 4 +#define HAT_DOWN 5 +#define HAT_DOWN_LEFT 6 +#define HAT_LEFT 7 +#define HAT_UP_LEFT 8 + +class USBHIDGamepad: public USBHIDDevice { +private: + USBHID hid; + xSemaphoreHandle tx_sem; + int8_t _x; ///< Delta x movement of left analog-stick + int8_t _y; ///< Delta y movement of left analog-stick + int8_t _z; ///< Delta z movement of right analog-joystick + int8_t _rz; ///< Delta Rz movement of right analog-joystick + int8_t _rx; ///< Delta Rx movement of analog left trigger + int8_t _ry; ///< Delta Ry movement of analog right trigger + uint8_t _hat; ///< Buttons mask for currently pressed buttons in the DPad/hat + uint32_t _buttons; ///< Buttons mask for currently pressed buttons + bool write(); +public: + USBHIDGamepad(void); + void begin(void); + void end(void); + + bool leftStick(int8_t x, int8_t y); + bool rightStick(int8_t z, int8_t rz); + + bool leftTrigger(int8_t rx); + bool rightTrigger(int8_t ry); + + bool hat(uint8_t hat); + + bool pressButton(uint8_t button); + bool releaseButton(uint8_t button); + + bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + + //internal use + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USBHIDKeyboard.cpp b/libraries/USB/src/USBHIDKeyboard.cpp new file mode 100644 index 00000000000..2bb59243e66 --- /dev/null +++ b/libraries/USB/src/USBHIDKeyboard.cpp @@ -0,0 +1,373 @@ +/* + Keyboard.cpp + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDKeyboard.h" + +#if CFG_TUD_HID + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDKeyboard::USBHIDKeyboard(): hid(), tx_sem(NULL){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + } else { + isr_log_e("Only one instance of USBHIDKeyboard is allowed!"); + abort(); + } +} + +void USBHIDKeyboard::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } +} + +void USBHIDKeyboard::end(){ + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDKeyboard::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_HID_KEYBOARD_ANY_EVENT, callback); +} +void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this); +} + +void USBHIDKeyboard::_onInputDone(const uint8_t* buffer, uint16_t len){ + //log_d("len: %u", len); + xSemaphoreGive(tx_sem); +} + +void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){ + //log_d("LEDS: 0x%02x", buffer[0]); + arduino_usb_hid_keyboard_event_data_t p = {0}; + p.leds = buffer[0]; + arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY); +} + +void USBHIDKeyboard::sendReport(KeyReport* keys) +{ + uint32_t timeout_ms = 100; + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return; + } + bool res = tud_hid_n_keyboard_report(0, id, keys->modifiers, keys->keys); + if(!res){ + log_e("report failed"); + } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + } +} + +#define SHIFT 0x80 +const uint8_t _asciimap[128] = +{ + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e|SHIFT, // ! + 0x34|SHIFT, // " + 0x20|SHIFT, // # + 0x21|SHIFT, // $ + 0x22|SHIFT, // % + 0x24|SHIFT, // & + 0x34, // ' + 0x26|SHIFT, // ( + 0x27|SHIFT, // ) + 0x25|SHIFT, // * + 0x2e|SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33|SHIFT, // : + 0x33, // ; + 0x36|SHIFT, // < + 0x2e, // = + 0x37|SHIFT, // > + 0x38|SHIFT, // ? + 0x1f|SHIFT, // @ + 0x04|SHIFT, // A + 0x05|SHIFT, // B + 0x06|SHIFT, // C + 0x07|SHIFT, // D + 0x08|SHIFT, // E + 0x09|SHIFT, // F + 0x0a|SHIFT, // G + 0x0b|SHIFT, // H + 0x0c|SHIFT, // I + 0x0d|SHIFT, // J + 0x0e|SHIFT, // K + 0x0f|SHIFT, // L + 0x10|SHIFT, // M + 0x11|SHIFT, // N + 0x12|SHIFT, // O + 0x13|SHIFT, // P + 0x14|SHIFT, // Q + 0x15|SHIFT, // R + 0x16|SHIFT, // S + 0x17|SHIFT, // T + 0x18|SHIFT, // U + 0x19|SHIFT, // V + 0x1a|SHIFT, // W + 0x1b|SHIFT, // X + 0x1c|SHIFT, // Y + 0x1d|SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23|SHIFT, // ^ + 0x2d|SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f|SHIFT, // { + 0x31|SHIFT, // | + 0x30|SHIFT, // } + 0x35|SHIFT, // ~ + 0 // DEL +}; + +size_t USBHIDKeyboard::pressRaw(uint8_t k) +{ + uint8_t i; + if (k >= 0xE0 && k < 0xE8) { + // it's a modifier key + _keyReport.modifiers |= (1<<(k-0x80)); + } else if (k && k < 0xA5) { + // Add k to the key report only if it's not already present + // and if there is an empty slot. + if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && + _keyReport.keys[2] != k && _keyReport.keys[3] != k && + _keyReport.keys[4] != k && _keyReport.keys[5] != k) { + + for (i=0; i<6; i++) { + if (_keyReport.keys[i] == 0x00) { + _keyReport.keys[i] = k; + break; + } + } + if (i == 6) { + return 0; + } + } + } else { + //not a modifier and not a key + return 0; + } + sendReport(&_keyReport); + return 1; +} + +size_t USBHIDKeyboard::releaseRaw(uint8_t k) +{ + uint8_t i; + if (k >= 0xE0 && k < 0xE8) { + // it's a modifier key + _keyReport.modifiers &= ~(1<<(k-0x80)); + } else if (k && k < 0xA5) { + // Test the key report to see if k is present. Clear it if it exists. + // Check all positions in case the key is present more than once (which it shouldn't be) + for (i=0; i<6; i++) { + if (0 != k && _keyReport.keys[i] == k) { + _keyReport.keys[i] = 0x00; + } + } + } else { + //not a modifier and not a key + return 0; + } + + sendReport(&_keyReport); + return 1; +} + +// press() adds the specified key (printing, non-printing, or modifier) +// to the persistent key report and sends the report. Because of the way +// USB HID works, the host acts like the key remains pressed until we +// call release(), releaseAll(), or otherwise clear the report and resend. +size_t USBHIDKeyboard::press(uint8_t k) +{ + uint8_t i; + if (k >= 0x88) { // it's a non-printing key (not a modifier) + k = k - 0x88; + } else if (k >= 0x80) { // it's a modifier key + _keyReport.modifiers |= (1<<(k-0x80)); + k = 0; + } else { // it's a printing key + k = _asciimap[k]; + if (!k) { + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers |= 0x02; // the left shift modifier + k &= 0x7F; + } + } + return pressRaw(k); +} + +// release() takes the specified key out of the persistent key report and +// sends the report. This tells the OS the key is no longer pressed and that +// it shouldn't be repeated any more. +size_t USBHIDKeyboard::release(uint8_t k) +{ + uint8_t i; + if (k >= 0x88) { // it's a non-printing key (not a modifier) + k = k - 0x88; + } else if (k >= 0x80) { // it's a modifier key + _keyReport.modifiers &= ~(1<<(k-0x80)); + k = 0; + } else { // it's a printing key + k = _asciimap[k]; + if (!k) { + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers &= ~(0x02); // the left shift modifier + k &= 0x7F; + } + } + return releaseRaw(k); +} + +void USBHIDKeyboard::releaseAll(void) +{ + _keyReport.keys[0] = 0; + _keyReport.keys[1] = 0; + _keyReport.keys[2] = 0; + _keyReport.keys[3] = 0; + _keyReport.keys[4] = 0; + _keyReport.keys[5] = 0; + _keyReport.modifiers = 0; + sendReport(&_keyReport); +} + +size_t USBHIDKeyboard::write(uint8_t c) +{ + uint8_t p = press(c); // Keydown + release(c); // Keyup + return p; // just return the result of press() since release() almost always returns 1 +} + +size_t USBHIDKeyboard::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while (size--) { + if (*buffer != '\r') { + if (write(*buffer)) { + n++; + } else { + break; + } + } + buffer++; + } + return n; +} + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDKeyboard.h b/libraries/USB/src/USBHIDKeyboard.h new file mode 100644 index 00000000000..5f4c0e813f4 --- /dev/null +++ b/libraries/USB/src/USBHIDKeyboard.h @@ -0,0 +1,141 @@ +/* + Keyboard.h + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once +#include "Print.h" +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +#include "esp_event.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); + +typedef enum { + ARDUINO_USB_HID_KEYBOARD_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_HID_KEYBOARD_LED_EVENT = 0, + ARDUINO_USB_HID_KEYBOARD_MAX_EVENT, +} arduino_usb_hid_keyboard_event_t; + +typedef union { + struct { + uint8_t numlock:1; + uint8_t capslock:1; + uint8_t scrolllock:1; + uint8_t compose:1; + uint8_t kana:1; + uint8_t reserved:3; + }; + uint8_t leds; +} arduino_usb_hid_keyboard_event_data_t; + +#define KEY_LEFT_CTRL 0x80 +#define KEY_LEFT_SHIFT 0x81 +#define KEY_LEFT_ALT 0x82 +#define KEY_LEFT_GUI 0x83 +#define KEY_RIGHT_CTRL 0x84 +#define KEY_RIGHT_SHIFT 0x85 +#define KEY_RIGHT_ALT 0x86 +#define KEY_RIGHT_GUI 0x87 + +#define KEY_UP_ARROW 0xDA +#define KEY_DOWN_ARROW 0xD9 +#define KEY_LEFT_ARROW 0xD8 +#define KEY_RIGHT_ARROW 0xD7 +#define KEY_BACKSPACE 0xB2 +#define KEY_TAB 0xB3 +#define KEY_RETURN 0xB0 +#define KEY_ESC 0xB1 +#define KEY_INSERT 0xD1 +#define KEY_DELETE 0xD4 +#define KEY_PAGE_UP 0xD3 +#define KEY_PAGE_DOWN 0xD6 +#define KEY_HOME 0xD2 +#define KEY_END 0xD5 +#define KEY_CAPS_LOCK 0xC1 +#define KEY_F1 0xC2 +#define KEY_F2 0xC3 +#define KEY_F3 0xC4 +#define KEY_F4 0xC5 +#define KEY_F5 0xC6 +#define KEY_F6 0xC7 +#define KEY_F7 0xC8 +#define KEY_F8 0xC9 +#define KEY_F9 0xCA +#define KEY_F10 0xCB +#define KEY_F11 0xCC +#define KEY_F12 0xCD +#define KEY_F13 0xF0 +#define KEY_F14 0xF1 +#define KEY_F15 0xF2 +#define KEY_F16 0xF3 +#define KEY_F17 0xF4 +#define KEY_F18 0xF5 +#define KEY_F19 0xF6 +#define KEY_F20 0xF7 +#define KEY_F21 0xF8 +#define KEY_F22 0xF9 +#define KEY_F23 0xFA +#define KEY_F24 0xFB + +#define LED_NUMLOCK 0x01 +#define LED_CAPSLOCK 0x02 +#define LED_SCROLLLOCK 0x04 +#define LED_COMPOSE 0x08 +#define LED_KANA 0x10 + +// Low level key report: up to 6 keys and shift, ctrl etc at once +typedef struct +{ + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; +} KeyReport; + +class USBHIDKeyboard: public USBHIDDevice, public Print +{ +private: + USBHID hid; + xSemaphoreHandle tx_sem; + KeyReport _keyReport; + void sendReport(KeyReport* keys); +public: + USBHIDKeyboard(void); + void begin(void); + void end(void); + size_t write(uint8_t k); + size_t write(const uint8_t *buffer, size_t size); + size_t press(uint8_t k); + size_t release(uint8_t k); + void releaseAll(void); + + //raw functions work with TinyUSB's HID_KEY_* macros + size_t pressRaw(uint8_t k); + size_t releaseRaw(uint8_t k); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback); + + //internal use + void _onOutput(const uint8_t* buffer, uint16_t len); + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp new file mode 100644 index 00000000000..0eb2683d4c1 --- /dev/null +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -0,0 +1,113 @@ +/* + Mouse.cpp + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDMouse.h" + +#if CFG_TUD_HID + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDMouse::USBHIDMouse(): hid(), _buttons(0), tx_sem(NULL){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + } else { + isr_log_e("Only one instance of USBHIDMouse is allowed!"); + abort(); + } +} + +void USBHIDMouse::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } +} + +void USBHIDMouse::end(){ + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDMouse::_onInputDone(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + xSemaphoreGive(tx_sem); +} + +void USBHIDMouse::click(uint8_t b){ + _buttons = b; + move(0,0); + _buttons = 0; + move(0,0); +} + +void USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){ + uint32_t timeout_ms = 100; + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return; + } + bool res = tud_hid_n_mouse_report(0, id, _buttons, x, y, wheel, pan); + if(!res){ + log_e("report failed"); + } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + } +} + +void USBHIDMouse::buttons(uint8_t b){ + if (b != _buttons){ + _buttons = b; + move(0,0); + } +} + +void USBHIDMouse::press(uint8_t b){ + buttons(_buttons | b); +} + +void USBHIDMouse::release(uint8_t b){ + buttons(_buttons & ~b); +} + +bool USBHIDMouse::isPressed(uint8_t b){ + if ((b & _buttons) > 0) { + return true; + } + return false; +} + + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDMouse.h b/libraries/USB/src/USBHIDMouse.h new file mode 100644 index 00000000000..e7ce493208b --- /dev/null +++ b/libraries/USB/src/USBHIDMouse.h @@ -0,0 +1,55 @@ +/* + Mouse.h + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +#define MOUSE_LEFT 0x01 +#define MOUSE_RIGHT 0x02 +#define MOUSE_MIDDLE 0x04 +#define MOUSE_BACKWARD 0x08 +#define MOUSE_FORWARD 0x10 +#define MOUSE_ALL 0x1F + +class USBHIDMouse: public USBHIDDevice { +private: + USBHID hid; + uint8_t _buttons; + xSemaphoreHandle tx_sem; + void buttons(uint8_t b); + bool write(int8_t x, int8_t y, int8_t vertical, int8_t horizontal); +public: + USBHIDMouse(void); + void begin(void); + void end(void); + + void click(uint8_t b = MOUSE_LEFT); + void move(int8_t x, int8_t y, int8_t wheel = 0, int8_t pan = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default + + //internal use + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp new file mode 100644 index 00000000000..5b41c78bbcf --- /dev/null +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -0,0 +1,90 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDSystemControl.h" + +#if CFG_TUD_HID + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDSystemControl::USBHIDSystemControl(): hid(), tx_sem(NULL){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + } else { + isr_log_e("Only one instance of USBHIDSystemControl is allowed!"); + abort(); + } +} + +void USBHIDSystemControl::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } +} + +void USBHIDSystemControl::end(){ + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDSystemControl::_onInputDone(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + xSemaphoreGive(tx_sem); +} + +bool USBHIDSystemControl::send(uint8_t value){ + uint32_t timeout_ms = 100; + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return false; + } + bool res = tud_hid_n_report(0, id, &value, 1); + if(!res){ + log_e("report failed"); + return false; + } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + return false; + } + return true; +} + +size_t USBHIDSystemControl::press(uint8_t k){ + if(k > 3){ + return 0; + } + return send(k); +} + +size_t USBHIDSystemControl::release(){ + return send(0); +} + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDSystemControl.h b/libraries/USB/src/USBHIDSystemControl.h new file mode 100644 index 00000000000..7a5f65764db --- /dev/null +++ b/libraries/USB/src/USBHIDSystemControl.h @@ -0,0 +1,40 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +#define SYSTEM_CONTROL_NONE 0 +#define SYSTEM_CONTROL_POWER_OFF 1 +#define SYSTEM_CONTROL_STANDBY 2 +#define SYSTEM_CONTROL_WAKE_HOST 3 + +class USBHIDSystemControl: public USBHIDDevice { +private: + USBHID hid; + xSemaphoreHandle tx_sem; + bool send(uint8_t value); +public: + USBHIDSystemControl(void); + void begin(void); + void end(void); + size_t press(uint8_t k); + size_t release(); + + //internal use + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp new file mode 100644 index 00000000000..45497cf73e3 --- /dev/null +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -0,0 +1,236 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBHIDVendor.h" + +#if CFG_TUD_HID + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_VENDOR_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + + +//GENERIC HID + +// HID Generic Input, Output & Feature +// - 1st parameter is report size (mandatory) +// - 2nd parameter is report id HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ + HID_USAGE ( 0x01 ),\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* Input */ \ + HID_USAGE ( 0x02 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX ( 0xff ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + /* Output */ \ + HID_USAGE ( 0x03 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX ( 0xff ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + /* Feature */ \ + HID_USAGE ( 0x04 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX ( 0xff ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + HID_COLLECTION_END \ + +#define TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN 46 + +static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(63, HID_REPORT_ID(report_id)) + }; + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + +USBHIDVendor::USBHIDVendor(): hid(), tx_sem(NULL){ + static bool initialized = false; + if(!initialized){ + initialized = true; + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(0, HID_REPORT_ID(0)) + }; + hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + memset(feature, 0, 63); + } else { + isr_log_e("Only one instance of USBHIDVendor is allowed!"); + abort(); + } +} + +size_t USBHIDVendor::setRxBufferSize(size_t rx_queue_len){ + if(rx_queue){ + if(!rx_queue_len){ + vQueueDelete(rx_queue); + rx_queue = NULL; + } + return 0; + } + rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!rx_queue){ + return 0; + } + return rx_queue_len; +} + +void USBHIDVendor::begin(){ + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + xSemaphoreTake(tx_sem, 0); + } + setRxBufferSize(256);//default if not preset +} + +void USBHIDVendor::end(){ + setRxBufferSize(0); + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +void USBHIDVendor::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_HID_VENDOR_ANY_EVENT, callback); +} +void USBHIDVendor::onEvent(arduino_usb_hid_vendor_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_HID_VENDOR_EVENTS, event, callback, this); +} + +uint16_t USBHIDVendor::_onGetFeature(uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + memcpy(buffer, feature, len); + arduino_usb_hid_vendor_event_data_t p = {0}; + p.buffer = feature; + p.len = len; + arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); + return len; +} +void USBHIDVendor::_onSetFeature(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + memcpy(feature, buffer, len); + arduino_usb_hid_vendor_event_data_t p = {0}; + p.buffer = feature; + p.len = len; + arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); +} +void USBHIDVendor::_onOutput(const uint8_t* buffer, uint16_t len){ + //log_i("len: %u", len); + for(uint32_t i=0; i max_send){ + will_send = max_send; + } + if(!tud_hid_n_wait_ready(0, timeout_ms)){ + log_e("not ready"); + return len - to_send; + } + hid_in[1] = (uint8_t)will_send; + memcpy(hid_in+2, data, will_send); + memset(hid_in+2+will_send, 0, 64 - (will_send+2)); + if(!tud_hid_n_report(0, 0, hid_in, 64)){ + log_e("report failed"); + return len - to_send; + } + if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report wait failed"); + return len - to_send; + } + to_send -= will_send; + data += will_send; + } + return len; +} + +size_t USBHIDVendor::write(uint8_t c){ + return write(&c, 1); +} + +int USBHIDVendor::available(void){ + if(rx_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx_queue); +} + +int USBHIDVendor::peek(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c; + if(xQueuePeek(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +int USBHIDVendor::read(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +size_t USBHIDVendor::read(uint8_t *buffer, size_t size){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + size_t count = 0; + while(count < size && xQueueReceive(rx_queue, &c, 0)){ + buffer[count++] = c; + } + return count; +} + +void USBHIDVendor::flush(void){} + + +#endif /* CFG_TUD_HID */ diff --git a/libraries/USB/src/USBHIDVendor.h b/libraries/USB/src/USBHIDVendor.h new file mode 100644 index 00000000000..395529115ba --- /dev/null +++ b/libraries/USB/src/USBHIDVendor.h @@ -0,0 +1,64 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "Stream.h" +#include "USBHID.h" +#if CONFIG_TINYUSB_HID_ENABLED + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_VENDOR_EVENTS); + +typedef enum { + ARDUINO_USB_HID_VENDOR_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT = 0, + ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT, + ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT, + ARDUINO_USB_HID_VENDOR_MAX_EVENT, +} arduino_usb_hid_vendor_event_t; + +typedef struct { + const uint8_t* buffer; + uint16_t len; +} arduino_usb_hid_vendor_event_data_t; + +class USBHIDVendor: public USBHIDDevice, public Stream { +private: + USBHID hid; + uint8_t feature[63]; + xSemaphoreHandle tx_sem; + xQueueHandle rx_queue; +public: + USBHIDVendor(void); + void begin(void); + void end(void); + size_t setRxBufferSize(size_t); + size_t write(const uint8_t* buffer, uint16_t len); + size_t write(uint8_t); + int available(void); + int peek(void); + int read(void); + size_t read(uint8_t *buffer, size_t size); + void flush(void); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_hid_vendor_event_t event, esp_event_handler_t callback); + + //internal use + uint16_t _onGetFeature(uint8_t* buffer, uint16_t len); + void _onSetFeature(const uint8_t* buffer, uint16_t len); + void _onOutput(const uint8_t* buffer, uint16_t len); + void _onInputDone(const uint8_t* buffer, uint16_t len); +}; + +#endif diff --git a/libraries/USB/src/USB_NOT.h b/libraries/USB/src/USB_NOT.h deleted file mode 100644 index f349ad19817..00000000000 --- a/libraries/USB/src/USB_NOT.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once From a7fab63e8407019f2f6fc268d9f7c46a4ca28ef1 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Fri, 13 Aug 2021 16:47:33 +0300 Subject: [PATCH 02/17] Update CMakeLists.txt --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2801ba615ef..a1afff1655c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,13 @@ set(LIBRARY_SRCS libraries/Ticker/src/Ticker.cpp libraries/Update/src/Updater.cpp libraries/Update/src/HttpsOTAUpdate.cpp + libraries/USB/src/USBHID.cpp + libraries/USB/src/USBHIDMouse.cpp + libraries/USB/src/USBHIDKeyboard.cpp + libraries/USB/src/USBHIDGamepad.cpp + libraries/USB/src/USBHIDConsumerControl.cpp + libraries/USB/src/USBHIDSystemControl.cpp + libraries/USB/src/USBHIDVendor.cpp libraries/WebServer/src/WebServer.cpp libraries/WebServer/src/Parsing.cpp libraries/WebServer/src/detail/mimetable.cpp From 0eeacc87399ada765b7ad814a080917e802620d2 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Sat, 14 Aug 2021 04:43:36 +0300 Subject: [PATCH 03/17] Provide thread-safe USBHID::SendReport --- .../CompositeDevice/CompositeDevice.ino | 3 +- libraries/USB/src/USBHID.cpp | 82 ++++++++++++------- libraries/USB/src/USBHID.h | 4 +- libraries/USB/src/USBHIDConsumerControl.cpp | 31 +------ libraries/USB/src/USBHIDConsumerControl.h | 4 - libraries/USB/src/USBHIDGamepad.cpp | 40 +++------ libraries/USB/src/USBHIDGamepad.h | 4 - libraries/USB/src/USBHIDKeyboard.cpp | 34 +++----- libraries/USB/src/USBHIDKeyboard.h | 2 - libraries/USB/src/USBHIDMouse.cpp | 35 +++----- libraries/USB/src/USBHIDMouse.h | 4 - libraries/USB/src/USBHIDSystemControl.cpp | 31 +------ libraries/USB/src/USBHIDSystemControl.h | 4 - libraries/USB/src/USBHIDVendor.cpp | 61 ++++++-------- libraries/USB/src/USBHIDVendor.h | 2 - 15 files changed, 117 insertions(+), 224 deletions(-) diff --git a/libraries/USB/examples/CompositeDevice/CompositeDevice.ino b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino index 16d137ed22f..1f9b9159d2e 100644 --- a/libraries/USB/examples/CompositeDevice/CompositeDevice.ino +++ b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino @@ -94,7 +94,7 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size); break; case ARDUINO_FIRMWARE_MSC_POWER_EVENT: - HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject); + HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u\n", data->power.power_condition, data->power.start, data->power.load_eject); break; default: @@ -173,7 +173,6 @@ void setup() { Gamepad.begin(); ConsumerControl.begin(); SystemControl.begin(); - HID.begin(); USB.begin(); } diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index c73b3edc2bb..0fffd1650df 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -128,12 +128,14 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf) static USBHIDDevice * tinyusb_hid_devices[USB_HID_DEVICES_MAX+1]; static uint8_t tinyusb_hid_devices_num = 0; static bool tinyusb_hid_devices_is_initialized = false; +static xSemaphoreHandle tinyusb_hid_device_input_sem = NULL; +static xSemaphoreHandle tinyusb_hid_device_input_mutex = NULL; // Invoked when received GET HID REPORT DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){ - log_d("instance: %u", instance); + log_v("instance: %u", instance); return tinyusb_hid_device_descriptor; } @@ -191,32 +193,6 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ } } -// Invoked when sent REPORT successfully to host -// Application can use this to send the next report -// Note: For composite reports, report[0] is report ID -void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){ - if(report[0] < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report[0]]){ - tinyusb_hid_devices[report[0]]->_onInputDone(report+1, len-1); - } else { - log_i("instance: %u, report_id: %u, report_type: %s, bufsize:%u", instance, report[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_INPUT], len-1); - log_print_buf(report+1, len-1); - } -} - -bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms){ - if(tud_hid_n_ready(instance)){ - return true; - } - uint32_t start_ms = millis(); - while(!tud_hid_n_ready(instance)){ - if((millis() - start_ms) > timeout_ms){ - return false; - } - delay(1); - } - return true; -} - USBHID::USBHID(){ if(!tinyusb_hid_devices_is_initialized){ tinyusb_hid_devices_is_initialized = true; @@ -224,15 +200,63 @@ USBHID::USBHID(){ tinyusb_hid_devices_num = 0; tinyusb_enable_interface(USB_INTERFACE_HID, TUD_HID_INOUT_DESC_LEN, tusb_hid_load_descriptor); } - } void USBHID::begin(){ - + if(tinyusb_hid_device_input_sem == NULL){ + tinyusb_hid_device_input_sem = xSemaphoreCreateBinary(); + } + if(tinyusb_hid_device_input_mutex == NULL){ + tinyusb_hid_device_input_mutex = xSemaphoreCreateMutex(); + } } void USBHID::end(){ + if (tinyusb_hid_device_input_sem != NULL) { + vSemaphoreDelete(tinyusb_hid_device_input_sem); + tinyusb_hid_device_input_sem = NULL; + } + if (tinyusb_hid_device_input_mutex != NULL) { + vSemaphoreDelete(tinyusb_hid_device_input_mutex); + tinyusb_hid_device_input_mutex = NULL; + } +} + +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){ + if (tinyusb_hid_device_input_sem) { + xSemaphoreGive(tinyusb_hid_device_input_sem); + } +} + +bool USBHID::SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms){ + if(!tinyusb_hid_device_input_sem || !tinyusb_hid_device_input_mutex){ + log_e("TX Semaphore is NULL. You must call USBHID::begin() before you can send reports"); + return false; + } + + if(xSemaphoreTake(tinyusb_hid_device_input_mutex, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report %u mutex failed", id); + return false; + } + + bool res = tud_hid_n_ready(0); + if(!res){ + log_e("not ready"); + } else { + res = tud_hid_n_report(0, id, data, len); + if(!res){ + log_e("report %u failed", id); + } else { + xSemaphoreTake(tinyusb_hid_device_input_sem, 0); + if(xSemaphoreTake(tinyusb_hid_device_input_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + log_e("report %u wait failed", id); + res = false; + } + } + } + xSemaphoreGive(tinyusb_hid_device_input_mutex); + return res; } bool USBHID::addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb){ diff --git a/libraries/USB/src/USBHID.h b/libraries/USB/src/USBHID.h index dba35fb8a4f..defd3349a64 100644 --- a/libraries/USB/src/USBHID.h +++ b/libraries/USB/src/USBHID.h @@ -53,7 +53,6 @@ class USBHIDDevice virtual uint16_t _onGetFeature(uint8_t* buffer, uint16_t len){return 0;} virtual void _onSetFeature(const uint8_t* buffer, uint16_t len){} virtual void _onOutput(const uint8_t* buffer, uint16_t len){} - virtual void _onInputDone(const uint8_t* buffer, uint16_t len){} }; class USBHID @@ -62,11 +61,10 @@ class USBHID USBHID(void); void begin(void); void end(void); + bool SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms = 100); void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback); static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb); }; -bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms); - #endif diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp index 9cf98d4539a..9f2a4340c60 100644 --- a/libraries/USB/src/USBHIDConsumerControl.cpp +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -26,7 +26,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i return sizeof(report_descriptor); } -USBHIDConsumerControl::USBHIDConsumerControl(): hid(), tx_sem(NULL){ +USBHIDConsumerControl::USBHIDConsumerControl(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; @@ -41,39 +41,14 @@ USBHIDConsumerControl::USBHIDConsumerControl(): hid(), tx_sem(NULL){ } void USBHIDConsumerControl::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); } void USBHIDConsumerControl::end(){ - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } -} - -void USBHIDConsumerControl::_onInputDone(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); - xSemaphoreGive(tx_sem); } bool USBHIDConsumerControl::send(uint16_t value){ - uint32_t timeout_ms = 100; - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return false; - } - bool res = tud_hid_n_report(0, id, &value, 2); - if(!res){ - log_e("report failed"); - return false; - } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); - return false; - } - return true; + return hid.SendReport(id, &value, 2); } size_t USBHIDConsumerControl::press(uint16_t k){ diff --git a/libraries/USB/src/USBHIDConsumerControl.h b/libraries/USB/src/USBHIDConsumerControl.h index df0b5275b85..579e5704b4f 100644 --- a/libraries/USB/src/USBHIDConsumerControl.h +++ b/libraries/USB/src/USBHIDConsumerControl.h @@ -70,7 +70,6 @@ class USBHIDConsumerControl: public USBHIDDevice { private: USBHID hid; - xSemaphoreHandle tx_sem; bool send(uint16_t value); public: USBHIDConsumerControl(void); @@ -78,9 +77,6 @@ class USBHIDConsumerControl: public USBHIDDevice { void end(void); size_t press(uint16_t k); size_t release(); - - //internal use - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp index 0c13e9de516..44f23a2da8d 100644 --- a/libraries/USB/src/USBHIDGamepad.cpp +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -26,7 +26,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i return sizeof(report_descriptor); } -USBHIDGamepad::USBHIDGamepad(): hid(), tx_sem(NULL), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){ +USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){ static bool initialized = false; if(!initialized){ initialized = true; @@ -41,39 +41,25 @@ USBHIDGamepad::USBHIDGamepad(): hid(), tx_sem(NULL), _x(0), _y(0), _z(0), _rz(0) } void USBHIDGamepad::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); } void USBHIDGamepad::end(){ - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } -} -void USBHIDGamepad::_onInputDone(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); - xSemaphoreGive(tx_sem); } bool USBHIDGamepad::write(){ - uint32_t timeout_ms = 100; - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return false; - } - bool res = tud_hid_n_gamepad_report(0, id, _x, _y, _z, _rz, _rx, _ry, _hat, _buttons); - if(!res){ - log_e("report failed"); - return false; - } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); - return false; - } - return true; + hid_gamepad_report_t report = { + .x = _x, + .y = _y, + .z = _z, + .rz = _rz, + .rx = _rx, + .ry = _ry, + .hat = _hat, + .buttons = _buttons + }; + return hid.SendReport(id, &report, sizeof(report)); } bool USBHIDGamepad::leftStick(int8_t x, int8_t y){ diff --git a/libraries/USB/src/USBHIDGamepad.h b/libraries/USB/src/USBHIDGamepad.h index bace503c890..d6b81cc53f4 100644 --- a/libraries/USB/src/USBHIDGamepad.h +++ b/libraries/USB/src/USBHIDGamepad.h @@ -53,7 +53,6 @@ class USBHIDGamepad: public USBHIDDevice { private: USBHID hid; - xSemaphoreHandle tx_sem; int8_t _x; ///< Delta x movement of left analog-stick int8_t _y; ///< Delta y movement of left analog-stick int8_t _z; ///< Delta z movement of right analog-joystick @@ -80,9 +79,6 @@ class USBHIDGamepad: public USBHIDDevice { bool releaseButton(uint8_t button); bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); - - //internal use - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDKeyboard.cpp b/libraries/USB/src/USBHIDKeyboard.cpp index 2bb59243e66..2d3e69d8fed 100644 --- a/libraries/USB/src/USBHIDKeyboard.cpp +++ b/libraries/USB/src/USBHIDKeyboard.cpp @@ -37,7 +37,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i return sizeof(report_descriptor); } -USBHIDKeyboard::USBHIDKeyboard(): hid(), tx_sem(NULL){ +USBHIDKeyboard::USBHIDKeyboard(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; @@ -52,17 +52,10 @@ USBHIDKeyboard::USBHIDKeyboard(): hid(), tx_sem(NULL){ } void USBHIDKeyboard::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); } void USBHIDKeyboard::end(){ - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } } void USBHIDKeyboard::onEvent(esp_event_handler_t callback){ @@ -72,11 +65,6 @@ void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_h arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this); } -void USBHIDKeyboard::_onInputDone(const uint8_t* buffer, uint16_t len){ - //log_d("len: %u", len); - xSemaphoreGive(tx_sem); -} - void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){ //log_d("LEDS: 0x%02x", buffer[0]); arduino_usb_hid_keyboard_event_data_t p = {0}; @@ -86,17 +74,15 @@ void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){ void USBHIDKeyboard::sendReport(KeyReport* keys) { - uint32_t timeout_ms = 100; - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return; - } - bool res = tud_hid_n_keyboard_report(0, id, keys->modifiers, keys->keys); - if(!res){ - log_e("report failed"); - } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); + hid_keyboard_report_t report; + report.reserved = 0; + report.modifier = keys->modifiers; + if (keys->keys) { + memcpy(report.keycode, keys->keys, 6); + } else { + memset(report.keycode, 0, 6); } + hid.SendReport(id, &report, sizeof(report)); } #define SHIFT 0x80 diff --git a/libraries/USB/src/USBHIDKeyboard.h b/libraries/USB/src/USBHIDKeyboard.h index 5f4c0e813f4..77833f4ccd2 100644 --- a/libraries/USB/src/USBHIDKeyboard.h +++ b/libraries/USB/src/USBHIDKeyboard.h @@ -113,7 +113,6 @@ class USBHIDKeyboard: public USBHIDDevice, public Print { private: USBHID hid; - xSemaphoreHandle tx_sem; KeyReport _keyReport; void sendReport(KeyReport* keys); public: @@ -135,7 +134,6 @@ class USBHIDKeyboard: public USBHIDDevice, public Print //internal use void _onOutput(const uint8_t* buffer, uint16_t len); - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp index 0eb2683d4c1..2d05b741a22 100644 --- a/libraries/USB/src/USBHIDMouse.cpp +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -33,7 +33,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i return sizeof(report_descriptor); } -USBHIDMouse::USBHIDMouse(): hid(), _buttons(0), tx_sem(NULL){ +USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){ static bool initialized = false; if(!initialized){ initialized = true; @@ -48,22 +48,10 @@ USBHIDMouse::USBHIDMouse(): hid(), _buttons(0), tx_sem(NULL){ } void USBHIDMouse::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); } void USBHIDMouse::end(){ - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } -} - -void USBHIDMouse::_onInputDone(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); - xSemaphoreGive(tx_sem); } void USBHIDMouse::click(uint8_t b){ @@ -74,17 +62,14 @@ void USBHIDMouse::click(uint8_t b){ } void USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){ - uint32_t timeout_ms = 100; - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return; - } - bool res = tud_hid_n_mouse_report(0, id, _buttons, x, y, wheel, pan); - if(!res){ - log_e("report failed"); - } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); - } + hid_mouse_report_t report = { + .buttons = _buttons, + .x = x, + .y = y, + .wheel = wheel, + .pan = pan + }; + hid.SendReport(id, &report, sizeof(report)); } void USBHIDMouse::buttons(uint8_t b){ diff --git a/libraries/USB/src/USBHIDMouse.h b/libraries/USB/src/USBHIDMouse.h index e7ce493208b..afa238f43f6 100644 --- a/libraries/USB/src/USBHIDMouse.h +++ b/libraries/USB/src/USBHIDMouse.h @@ -34,7 +34,6 @@ class USBHIDMouse: public USBHIDDevice { private: USBHID hid; uint8_t _buttons; - xSemaphoreHandle tx_sem; void buttons(uint8_t b); bool write(int8_t x, int8_t y, int8_t vertical, int8_t horizontal); public: @@ -47,9 +46,6 @@ class USBHIDMouse: public USBHIDDevice { void press(uint8_t b = MOUSE_LEFT); // press LEFT by default void release(uint8_t b = MOUSE_LEFT); // release LEFT by default bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default - - //internal use - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp index 5b41c78bbcf..5c22861af8b 100644 --- a/libraries/USB/src/USBHIDSystemControl.cpp +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -26,7 +26,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i return sizeof(report_descriptor); } -USBHIDSystemControl::USBHIDSystemControl(): hid(), tx_sem(NULL){ +USBHIDSystemControl::USBHIDSystemControl(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; @@ -41,39 +41,14 @@ USBHIDSystemControl::USBHIDSystemControl(): hid(), tx_sem(NULL){ } void USBHIDSystemControl::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); } void USBHIDSystemControl::end(){ - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } -} - -void USBHIDSystemControl::_onInputDone(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); - xSemaphoreGive(tx_sem); } bool USBHIDSystemControl::send(uint8_t value){ - uint32_t timeout_ms = 100; - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return false; - } - bool res = tud_hid_n_report(0, id, &value, 1); - if(!res){ - log_e("report failed"); - return false; - } else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); - return false; - } - return true; + return hid.SendReport(id, &value, 1); } size_t USBHIDSystemControl::press(uint8_t k){ diff --git a/libraries/USB/src/USBHIDSystemControl.h b/libraries/USB/src/USBHIDSystemControl.h index 7a5f65764db..af83d22ba1c 100644 --- a/libraries/USB/src/USBHIDSystemControl.h +++ b/libraries/USB/src/USBHIDSystemControl.h @@ -24,7 +24,6 @@ class USBHIDSystemControl: public USBHIDDevice { private: USBHID hid; - xSemaphoreHandle tx_sem; bool send(uint8_t value); public: USBHIDSystemControl(void); @@ -32,9 +31,6 @@ class USBHIDSystemControl: public USBHIDDevice { void end(void); size_t press(uint8_t k); size_t release(); - - //internal use - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index 45497cf73e3..9336b4d0bfb 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -21,9 +21,6 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_VENDOR_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); - -//GENERIC HID - // HID Generic Input, Output & Feature // - 1st parameter is report size (mandatory) // - 2nd parameter is report id HID_REPORT_ID(n) (optional) @@ -58,23 +55,26 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i #define TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN 46 +// max size is 64 and we need one byte for the report ID +static const uint8_t HID_VENDOR_REPORT_SIZE = 63; + static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(63, HID_REPORT_ID(report_id)) + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(report_id)) }; memcpy(dst, report_descriptor, sizeof(report_descriptor)); return sizeof(report_descriptor); } -USBHIDVendor::USBHIDVendor(): hid(), tx_sem(NULL){ +USBHIDVendor::USBHIDVendor(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(0, HID_REPORT_ID(0)) + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(1)) }; hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); - memset(feature, 0, 63); + memset(feature, 0, HID_VENDOR_REPORT_SIZE); } else { isr_log_e("Only one instance of USBHIDVendor is allowed!"); abort(); @@ -97,30 +97,24 @@ size_t USBHIDVendor::setRxBufferSize(size_t rx_queue_len){ } void USBHIDVendor::begin(){ - if(tx_sem == NULL){ - tx_sem = xSemaphoreCreateBinary(); - xSemaphoreTake(tx_sem, 0); - } + hid.begin(); setRxBufferSize(256);//default if not preset } void USBHIDVendor::end(){ setRxBufferSize(0); - if (tx_sem != NULL) { - vSemaphoreDelete(tx_sem); - tx_sem = NULL; - } } void USBHIDVendor::onEvent(esp_event_handler_t callback){ onEvent(ARDUINO_USB_HID_VENDOR_ANY_EVENT, callback); } + void USBHIDVendor::onEvent(arduino_usb_hid_vendor_event_t event, esp_event_handler_t callback){ arduino_usb_event_handler_register_with(ARDUINO_USB_HID_VENDOR_EVENTS, event, callback, this); } uint16_t USBHIDVendor::_onGetFeature(uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); + log_v("len: %u", len); memcpy(buffer, feature, len); arduino_usb_hid_vendor_event_data_t p = {0}; p.buffer = feature; @@ -128,16 +122,18 @@ uint16_t USBHIDVendor::_onGetFeature(uint8_t* buffer, uint16_t len){ arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); return len; } + void USBHIDVendor::_onSetFeature(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); + log_v("len: %u", len); memcpy(feature, buffer, len); arduino_usb_hid_vendor_event_data_t p = {0}; p.buffer = feature; p.len = len; arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); } + void USBHIDVendor::_onOutput(const uint8_t* buffer, uint16_t len){ - //log_i("len: %u", len); + log_v("len: %u", len); for(uint32_t i=0; i max_send){ will_send = max_send; } - if(!tud_hid_n_wait_ready(0, timeout_ms)){ - log_e("not ready"); - return len - to_send; - } - hid_in[1] = (uint8_t)will_send; - memcpy(hid_in+2, data, will_send); - memset(hid_in+2+will_send, 0, 64 - (will_send+2)); - if(!tud_hid_n_report(0, 0, hid_in, 64)){ - log_e("report failed"); - return len - to_send; - } - if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ - log_e("report wait failed"); + // On Mac, I can get INPUT only when data length equals the input report size + // To be tested on other platforms + //uint8_t hid_in[HID_VENDOR_REPORT_SIZE]; + //memcpy(hid_in, data, will_send); + //memset(hid_in + will_send, 0, HID_VENDOR_REPORT_SIZE - will_send); + //if(!hid.SendReport(id, hid_in, HID_VENDOR_REPORT_SIZE)){ + if(!hid.SendReport(id, buffer + (len - to_send), will_send)){ return len - to_send; } to_send -= will_send; diff --git a/libraries/USB/src/USBHIDVendor.h b/libraries/USB/src/USBHIDVendor.h index 395529115ba..1f88c25ef01 100644 --- a/libraries/USB/src/USBHIDVendor.h +++ b/libraries/USB/src/USBHIDVendor.h @@ -36,7 +36,6 @@ class USBHIDVendor: public USBHIDDevice, public Stream { private: USBHID hid; uint8_t feature[63]; - xSemaphoreHandle tx_sem; xQueueHandle rx_queue; public: USBHIDVendor(void); @@ -58,7 +57,6 @@ class USBHIDVendor: public USBHIDDevice, public Stream { uint16_t _onGetFeature(uint8_t* buffer, uint16_t len); void _onSetFeature(const uint8_t* buffer, uint16_t len); void _onOutput(const uint8_t* buffer, uint16_t len); - void _onInputDone(const uint8_t* buffer, uint16_t len); }; #endif From f36e48361194c672efbde582a6085b0a715b3463 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 17 Aug 2021 15:27:17 +0300 Subject: [PATCH 04/17] Parse and assign report IDs to devices This allows one device to have multiple report IDs, but also requires that different devices do not use the same report ID --- libraries/USB/src/USBHID.cpp | 153 +++++++++++++++----- libraries/USB/src/USBHID.h | 26 ++-- libraries/USB/src/USBHIDConsumerControl.cpp | 22 ++- libraries/USB/src/USBHIDConsumerControl.h | 3 + libraries/USB/src/USBHIDGamepad.cpp | 22 ++- libraries/USB/src/USBHIDGamepad.h | 3 + libraries/USB/src/USBHIDKeyboard.cpp | 24 ++- libraries/USB/src/USBHIDKeyboard.h | 5 +- libraries/USB/src/USBHIDMouse.cpp | 36 +++-- libraries/USB/src/USBHIDMouse.h | 3 + libraries/USB/src/USBHIDSystemControl.cpp | 22 ++- libraries/USB/src/USBHIDSystemControl.h | 3 + libraries/USB/src/USBHIDVendor.cpp | 36 +++-- libraries/USB/src/USBHIDVendor.h | 9 +- 14 files changed, 230 insertions(+), 137 deletions(-) diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 0fffd1650df..de241c293dd 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -14,6 +14,7 @@ #include "esp32-hal.h" #include "esp32-hal-tinyusb.h" #include "USBHID.h" +#include "esp_hid_common.h" #if CFG_TUD_HID #define USB_HID_DEVICES_MAX 10 @@ -46,16 +47,26 @@ void log_print_buf(const uint8_t *b, size_t len){ } } +typedef struct { + USBHIDDevice * device; + uint8_t reports_num; + uint8_t * report_ids; +} tinyusb_hid_device_t; + +static tinyusb_hid_device_t tinyusb_hid_devices[USB_HID_DEVICES_MAX]; + +static uint8_t tinyusb_hid_devices_num = 0; +static bool tinyusb_hid_devices_is_initialized = false; +static xSemaphoreHandle tinyusb_hid_device_input_sem = NULL; +static xSemaphoreHandle tinyusb_hid_device_input_mutex = NULL; static bool tinyusb_hid_is_initialized = false; -static tinyusb_hid_device_descriptor_cb_t tinyusb_loaded_hid_devices_callbacks[USB_HID_DEVICES_MAX]; static uint8_t tinyusb_loaded_hid_devices_num = 0; -static uint8_t tinyusb_loaded_hid_devices_report_id = 1; static uint16_t tinyusb_hid_device_descriptor_len = 0; static uint8_t * tinyusb_hid_device_descriptor = NULL; static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"}; -static bool tinyusb_enable_hid_device(uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb){ +static bool tinyusb_enable_hid_device(uint16_t descriptor_len, USBHIDDevice * device){ if(tinyusb_hid_is_initialized){ log_e("TinyUSB HID has already started! Device not enabled"); return false; @@ -65,20 +76,102 @@ static bool tinyusb_enable_hid_device(uint16_t descriptor_len, tinyusb_hid_devic return false; } tinyusb_hid_device_descriptor_len += descriptor_len; - tinyusb_loaded_hid_devices_callbacks[tinyusb_loaded_hid_devices_num++] = cb; - log_d("Device enabled"); + tinyusb_hid_devices[tinyusb_loaded_hid_devices_num++].device = device; + + log_d("Device[%u] len: %u", tinyusb_loaded_hid_devices_num-1, descriptor_len); return true; } -static uint16_t tinyusb_load_hid_descriptor(uint8_t interface, uint8_t * dst, uint8_t report_id) -{ - if(interface < USB_HID_DEVICES_MAX && tinyusb_loaded_hid_devices_callbacks[interface] != NULL){ - return tinyusb_loaded_hid_devices_callbacks[interface](dst, report_id); +USBHIDDevice * tinyusb_get_device_by_report_id(uint8_t report_id){ + for(uint8_t i=0; idevice && device->reports_num){ + for(uint8_t r=0; rreports_num; r++){ + if(report_id == device->report_ids[r]){ + return device->device; + } + } + } + } + return NULL; +} + +static uint16_t tinyusb_on_get_feature(uint8_t report_id, uint8_t* buffer, uint16_t reqlen){ + USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); + if(device){ + return device->_onGetFeature(report_id, buffer, reqlen); } return 0; } +static bool tinyusb_on_set_feature(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){ + USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); + if(device){ + device->_onSetFeature(report_id, buffer, reqlen); + return true; + } + return false; +} + +static bool tinyusb_on_set_output(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){ + USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); + if(device){ + device->_onOutput(report_id, buffer, reqlen); + return true; + } + return false; +} + +static uint16_t tinyusb_on_add_descriptor(uint8_t device_index, uint8_t * dst){ + uint16_t res = 0; + uint8_t report_id = 0, reports_num = 0; + tinyusb_hid_device_t * device = &tinyusb_hid_devices[device_index]; + if(device->device){ + res = device->device->_onGetDescriptor(dst); + if(res){ + + esp_hid_report_map_t *hid_report_map = esp_hid_parse_report_map(dst, res); + if(hid_report_map){ + if(device->report_ids){ + free(device->report_ids); + } + device->reports_num = hid_report_map->reports_len; + device->report_ids = (uint8_t*)malloc(device->reports_num); + memset(device->report_ids, 0, device->reports_num); + reports_num = device->reports_num; + + for(uint8_t i=0; ireports_num; i++){ + if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){ + report_id = hid_report_map->reports[i].report_id; + for(uint8_t r=0; rreports_num; r++){ + if(report_id == device->report_ids[r]){ + //already added + reports_num--; + break; + } else if(!device->report_ids[r]){ + //empty slot + device->report_ids[r] = report_id; + break; + } + } + } else { + reports_num--; + } + } + device->reports_num = reports_num; + esp_hid_free_report_map(hid_report_map); + } + + } + } + return res; +} + + static bool tinyusb_load_enabled_hid_devices(){ + if(tinyusb_hid_device_descriptor != NULL){ + return true; + } tinyusb_hid_device_descriptor = (uint8_t *)malloc(tinyusb_hid_device_descriptor_len); if (tinyusb_hid_device_descriptor == NULL) { log_e("HID Descriptor Malloc Failed"); @@ -86,15 +179,15 @@ static bool tinyusb_load_enabled_hid_devices(){ } uint8_t * dst = tinyusb_hid_device_descriptor; - for(uint8_t i=0; i_onGetFeature(buffer, reqlen); + uint16_t res = tinyusb_on_get_feature(report_id, buffer, reqlen); + if(!res){ + log_d("instance: %u, report_id: %u, report_type: %s, reqlen: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], reqlen); } - log_d("instance: %u, report_id: %u, report_type: %s, reqlen: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], reqlen); - return 0; + return res; } // Invoked when received SET_REPORT control request or @@ -177,18 +264,14 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize){ if(!report_id && !report_type){ report_id = buffer[0]; - if(report_id < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report_id]){ - tinyusb_hid_devices[report_id]->_onOutput(buffer+1, bufsize-1); - } else { + if(!tinyusb_on_set_output(report_id, buffer+1, bufsize-1)){ log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, *buffer, tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1); - log_print_buf(buffer+1, bufsize-1); + //log_print_buf(buffer+1, bufsize-1); } } else { - if(report_id < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report_id]){ - tinyusb_hid_devices[report_id]->_onSetFeature(buffer, bufsize); - } else { + if(!tinyusb_on_set_feature(report_id, buffer, bufsize)){ log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], bufsize); - log_print_buf(buffer, bufsize); + //log_print_buf(buffer, bufsize); } } } @@ -196,7 +279,9 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ USBHID::USBHID(){ if(!tinyusb_hid_devices_is_initialized){ tinyusb_hid_devices_is_initialized = true; - memset(tinyusb_hid_devices, 0, sizeof(tinyusb_hid_devices)); + for(uint8_t i=0; iid = tinyusb_loaded_hid_devices_num; - tinyusb_hid_devices[tinyusb_loaded_hid_devices_num] = device; return true; } return false; diff --git a/libraries/USB/src/USBHID.h b/libraries/USB/src/USBHID.h index defd3349a64..426cfd9b28d 100644 --- a/libraries/USB/src/USBHID.h +++ b/libraries/USB/src/USBHID.h @@ -22,6 +22,17 @@ #include "class/hid/hid.h" #include "esp_event.h" +// Used by the included TinyUSB drivers +enum { + HID_REPORT_ID_NONE, + HID_REPORT_ID_KEYBOARD, + HID_REPORT_ID_MOUSE, + HID_REPORT_ID_GAMEPAD, + HID_REPORT_ID_CONSUMER_CONTROL, + HID_REPORT_ID_SYSTEM_CONTROL, + HID_REPORT_ID_VENDOR +}; + ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_EVENTS); typedef enum { @@ -43,16 +54,13 @@ typedef struct { }; } arduino_usb_hid_event_data_t; -typedef uint16_t (*tinyusb_hid_device_descriptor_cb_t)(uint8_t * dst, uint8_t report_id); - class USBHIDDevice { public: - uint8_t id; - USBHIDDevice():id(0){} - virtual uint16_t _onGetFeature(uint8_t* buffer, uint16_t len){return 0;} - virtual void _onSetFeature(const uint8_t* buffer, uint16_t len){} - virtual void _onOutput(const uint8_t* buffer, uint16_t len){} + virtual uint16_t _onGetDescriptor(uint8_t* buffer){return 0;} + virtual uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len){return 0;} + virtual void _onSetFeature(uint8_t report_id, const uint8_t* buffer, uint16_t len){} + virtual void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){} }; class USBHID @@ -61,10 +69,10 @@ class USBHID USBHID(void); void begin(void); void end(void); - bool SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms = 100); + bool SendReport(uint8_t report_id, const void* data, size_t len, uint32_t timeout_ms = 100); void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback); - static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb); + static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len); }; #endif diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp index 9f2a4340c60..33c867e9cf1 100644 --- a/libraries/USB/src/USBHIDConsumerControl.cpp +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -18,28 +18,26 @@ #if CFG_TUD_HID -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(HID_REPORT_ID_CONSUMER_CONTROL)) +}; USBHIDConsumerControl::USBHIDConsumerControl(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(0)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); } else { isr_log_e("Only one instance of USBHIDConsumerControl is allowed!"); abort(); } } +uint16_t USBHIDConsumerControl::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + void USBHIDConsumerControl::begin(){ hid.begin(); } @@ -48,7 +46,7 @@ void USBHIDConsumerControl::end(){ } bool USBHIDConsumerControl::send(uint16_t value){ - return hid.SendReport(id, &value, 2); + return hid.SendReport(HID_REPORT_ID_CONSUMER_CONTROL, &value, 2); } size_t USBHIDConsumerControl::press(uint16_t k){ diff --git a/libraries/USB/src/USBHIDConsumerControl.h b/libraries/USB/src/USBHIDConsumerControl.h index 579e5704b4f..9c60ff69e6f 100644 --- a/libraries/USB/src/USBHIDConsumerControl.h +++ b/libraries/USB/src/USBHIDConsumerControl.h @@ -77,6 +77,9 @@ class USBHIDConsumerControl: public USBHIDDevice { void end(void); size_t press(uint16_t k); size_t release(); + + // internal use + uint16_t _onGetDescriptor(uint8_t* buffer); }; #endif diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp index 44f23a2da8d..b77aea3acd6 100644 --- a/libraries/USB/src/USBHIDGamepad.cpp +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -18,28 +18,26 @@ #if CFG_TUD_HID -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(HID_REPORT_ID_GAMEPAD)) +}; USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(0)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); } else { isr_log_e("Only one instance of USBHIDGamepad is allowed!"); abort(); } } +uint16_t USBHIDGamepad::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + void USBHIDGamepad::begin(){ hid.begin(); } @@ -59,7 +57,7 @@ bool USBHIDGamepad::write(){ .hat = _hat, .buttons = _buttons }; - return hid.SendReport(id, &report, sizeof(report)); + return hid.SendReport(HID_REPORT_ID_GAMEPAD, &report, sizeof(report)); } bool USBHIDGamepad::leftStick(int8_t x, int8_t y){ diff --git a/libraries/USB/src/USBHIDGamepad.h b/libraries/USB/src/USBHIDGamepad.h index d6b81cc53f4..72b096db005 100644 --- a/libraries/USB/src/USBHIDGamepad.h +++ b/libraries/USB/src/USBHIDGamepad.h @@ -79,6 +79,9 @@ class USBHIDGamepad: public USBHIDDevice { bool releaseButton(uint8_t button); bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + + // internal use + uint16_t _onGetDescriptor(uint8_t* buffer); }; #endif diff --git a/libraries/USB/src/USBHIDKeyboard.cpp b/libraries/USB/src/USBHIDKeyboard.cpp index 2d3e69d8fed..ec3444ba6c6 100644 --- a/libraries/USB/src/USBHIDKeyboard.cpp +++ b/libraries/USB/src/USBHIDKeyboard.cpp @@ -29,28 +29,26 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_REPORT_ID_KEYBOARD)) +}; USBHIDKeyboard::USBHIDKeyboard(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(0)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); } else { isr_log_e("Only one instance of USBHIDKeyboard is allowed!"); abort(); } } +uint16_t USBHIDKeyboard::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + void USBHIDKeyboard::begin(){ hid.begin(); } @@ -65,7 +63,7 @@ void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_h arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this); } -void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){ +void USBHIDKeyboard::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){ //log_d("LEDS: 0x%02x", buffer[0]); arduino_usb_hid_keyboard_event_data_t p = {0}; p.leds = buffer[0]; @@ -82,7 +80,7 @@ void USBHIDKeyboard::sendReport(KeyReport* keys) } else { memset(report.keycode, 0, 6); } - hid.SendReport(id, &report, sizeof(report)); + hid.SendReport(HID_REPORT_ID_KEYBOARD, &report, sizeof(report)); } #define SHIFT 0x80 diff --git a/libraries/USB/src/USBHIDKeyboard.h b/libraries/USB/src/USBHIDKeyboard.h index 77833f4ccd2..5f9fdfc4696 100644 --- a/libraries/USB/src/USBHIDKeyboard.h +++ b/libraries/USB/src/USBHIDKeyboard.h @@ -132,8 +132,9 @@ class USBHIDKeyboard: public USBHIDDevice, public Print void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback); - //internal use - void _onOutput(const uint8_t* buffer, uint16_t len); + // internal use + uint16_t _onGetDescriptor(uint8_t* buffer); + void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len); }; #endif diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp index 2d05b741a22..2592ec24489 100644 --- a/libraries/USB/src/USBHIDMouse.cpp +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -25,28 +25,26 @@ #if CFG_TUD_HID -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_REPORT_ID_MOUSE)) +}; USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(0)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); } else { isr_log_e("Only one instance of USBHIDMouse is allowed!"); abort(); } } +uint16_t USBHIDMouse::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + void USBHIDMouse::begin(){ hid.begin(); } @@ -54,13 +52,6 @@ void USBHIDMouse::begin(){ void USBHIDMouse::end(){ } -void USBHIDMouse::click(uint8_t b){ - _buttons = b; - move(0,0); - _buttons = 0; - move(0,0); -} - void USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){ hid_mouse_report_t report = { .buttons = _buttons, @@ -69,7 +60,14 @@ void USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){ .wheel = wheel, .pan = pan }; - hid.SendReport(id, &report, sizeof(report)); + hid.SendReport(HID_REPORT_ID_MOUSE, &report, sizeof(report)); +} + +void USBHIDMouse::click(uint8_t b){ + _buttons = b; + move(0,0); + _buttons = 0; + move(0,0); } void USBHIDMouse::buttons(uint8_t b){ diff --git a/libraries/USB/src/USBHIDMouse.h b/libraries/USB/src/USBHIDMouse.h index afa238f43f6..17adf17b471 100644 --- a/libraries/USB/src/USBHIDMouse.h +++ b/libraries/USB/src/USBHIDMouse.h @@ -46,6 +46,9 @@ class USBHIDMouse: public USBHIDDevice { void press(uint8_t b = MOUSE_LEFT); // press LEFT by default void release(uint8_t b = MOUSE_LEFT); // release LEFT by default bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default + + // internal use + uint16_t _onGetDescriptor(uint8_t* buffer); }; #endif diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp index 5c22861af8b..0a40f48c867 100644 --- a/libraries/USB/src/USBHIDSystemControl.cpp +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -18,28 +18,26 @@ #if CFG_TUD_HID -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(HID_REPORT_ID_SYSTEM_CONTROL)) +}; USBHIDSystemControl::USBHIDSystemControl(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(0)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); } else { isr_log_e("Only one instance of USBHIDSystemControl is allowed!"); abort(); } } +uint16_t USBHIDSystemControl::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + void USBHIDSystemControl::begin(){ hid.begin(); } @@ -48,7 +46,7 @@ void USBHIDSystemControl::end(){ } bool USBHIDSystemControl::send(uint8_t value){ - return hid.SendReport(id, &value, 1); + return hid.SendReport(HID_REPORT_ID_SYSTEM_CONTROL, &value, 1); } size_t USBHIDSystemControl::press(uint8_t k){ diff --git a/libraries/USB/src/USBHIDSystemControl.h b/libraries/USB/src/USBHIDSystemControl.h index af83d22ba1c..05ba573f2b4 100644 --- a/libraries/USB/src/USBHIDSystemControl.h +++ b/libraries/USB/src/USBHIDSystemControl.h @@ -31,6 +31,9 @@ class USBHIDSystemControl: public USBHIDDevice { void end(void); size_t press(uint8_t k); size_t release(); + + // internal use + uint16_t _onGetDescriptor(uint8_t* buffer); }; #endif diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index 9336b4d0bfb..f775c6a28e7 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -58,22 +58,15 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i // max size is 64 and we need one byte for the report ID static const uint8_t HID_VENDOR_REPORT_SIZE = 63; -static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_id){ - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(report_id)) - }; - memcpy(dst, report_descriptor, sizeof(report_descriptor)); - return sizeof(report_descriptor); -} +static const uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(HID_REPORT_ID_VENDOR)) +}; USBHIDVendor::USBHIDVendor(): hid(){ static bool initialized = false; if(!initialized){ initialized = true; - uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(1)) - }; - hid.addDevice(this, sizeof(report_descriptor), tinyusb_hid_device_descriptor_cb); + hid.addDevice(this, sizeof(report_descriptor)); memset(feature, 0, HID_VENDOR_REPORT_SIZE); } else { isr_log_e("Only one instance of USBHIDVendor is allowed!"); @@ -81,6 +74,11 @@ USBHIDVendor::USBHIDVendor(): hid(){ } } +uint16_t USBHIDVendor::_onGetDescriptor(uint8_t* dst){ + memcpy(dst, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); +} + size_t USBHIDVendor::setRxBufferSize(size_t rx_queue_len){ if(rx_queue){ if(!rx_queue_len){ @@ -113,7 +111,7 @@ void USBHIDVendor::onEvent(arduino_usb_hid_vendor_event_t event, esp_event_handl arduino_usb_event_handler_register_with(ARDUINO_USB_HID_VENDOR_EVENTS, event, callback, this); } -uint16_t USBHIDVendor::_onGetFeature(uint8_t* buffer, uint16_t len){ +uint16_t USBHIDVendor::_onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len){ log_v("len: %u", len); memcpy(buffer, feature, len); arduino_usb_hid_vendor_event_data_t p = {0}; @@ -123,7 +121,7 @@ uint16_t USBHIDVendor::_onGetFeature(uint8_t* buffer, uint16_t len){ return len; } -void USBHIDVendor::_onSetFeature(const uint8_t* buffer, uint16_t len){ +void USBHIDVendor::_onSetFeature(uint8_t report_id, const uint8_t* buffer, uint16_t len){ log_v("len: %u", len); memcpy(feature, buffer, len); arduino_usb_hid_vendor_event_data_t p = {0}; @@ -132,7 +130,7 @@ void USBHIDVendor::_onSetFeature(const uint8_t* buffer, uint16_t len){ arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); } -void USBHIDVendor::_onOutput(const uint8_t* buffer, uint16_t len){ +void USBHIDVendor::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){ log_v("len: %u", len); for(uint32_t i=0; i Date: Tue, 17 Aug 2021 15:47:49 +0300 Subject: [PATCH 05/17] Allow more than one instance of the same device --- libraries/USB/src/USBHIDConsumerControl.cpp | 3 --- libraries/USB/src/USBHIDGamepad.cpp | 3 --- libraries/USB/src/USBHIDKeyboard.cpp | 12 +++++------- libraries/USB/src/USBHIDMouse.cpp | 3 --- libraries/USB/src/USBHIDSystemControl.cpp | 3 --- libraries/USB/src/USBHIDVendor.cpp | 18 ++++++++++++------ libraries/USB/src/USBHIDVendor.h | 2 -- 7 files changed, 17 insertions(+), 27 deletions(-) diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp index 33c867e9cf1..35dee39beb7 100644 --- a/libraries/USB/src/USBHIDConsumerControl.cpp +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -27,9 +27,6 @@ USBHIDConsumerControl::USBHIDConsumerControl(): hid(){ if(!initialized){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); - } else { - isr_log_e("Only one instance of USBHIDConsumerControl is allowed!"); - abort(); } } diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp index b77aea3acd6..37e65e79ffc 100644 --- a/libraries/USB/src/USBHIDGamepad.cpp +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -27,9 +27,6 @@ USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry( if(!initialized){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); - } else { - isr_log_e("Only one instance of USBHIDGamepad is allowed!"); - abort(); } } diff --git a/libraries/USB/src/USBHIDKeyboard.cpp b/libraries/USB/src/USBHIDKeyboard.cpp index ec3444ba6c6..15914ceed3c 100644 --- a/libraries/USB/src/USBHIDKeyboard.cpp +++ b/libraries/USB/src/USBHIDKeyboard.cpp @@ -38,9 +38,6 @@ USBHIDKeyboard::USBHIDKeyboard(): hid(){ if(!initialized){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); - } else { - isr_log_e("Only one instance of USBHIDKeyboard is allowed!"); - abort(); } } @@ -64,10 +61,11 @@ void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_h } void USBHIDKeyboard::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){ - //log_d("LEDS: 0x%02x", buffer[0]); - arduino_usb_hid_keyboard_event_data_t p = {0}; - p.leds = buffer[0]; - arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY); + if(report_id == HID_REPORT_ID_KEYBOARD){ + arduino_usb_hid_keyboard_event_data_t p = {0}; + p.leds = buffer[0]; + arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY); + } } void USBHIDKeyboard::sendReport(KeyReport* keys) diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp index 2592ec24489..dbc84c97505 100644 --- a/libraries/USB/src/USBHIDMouse.cpp +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -34,9 +34,6 @@ USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){ if(!initialized){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); - } else { - isr_log_e("Only one instance of USBHIDMouse is allowed!"); - abort(); } } diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp index 0a40f48c867..d1dafc30906 100644 --- a/libraries/USB/src/USBHIDSystemControl.cpp +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -27,9 +27,6 @@ USBHIDSystemControl::USBHIDSystemControl(): hid(){ if(!initialized){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); - } else { - isr_log_e("Only one instance of USBHIDSystemControl is allowed!"); - abort(); } } diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index f775c6a28e7..39e35fcd363 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -58,6 +58,9 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i // max size is 64 and we need one byte for the report ID static const uint8_t HID_VENDOR_REPORT_SIZE = 63; +static uint8_t feature[HID_VENDOR_REPORT_SIZE]; +static xQueueHandle rx_queue = NULL; + static const uint8_t report_descriptor[] = { TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(HID_REPORT_ID_VENDOR)) }; @@ -68,9 +71,6 @@ USBHIDVendor::USBHIDVendor(): hid(){ initialized = true; hid.addDevice(this, sizeof(report_descriptor)); memset(feature, 0, HID_VENDOR_REPORT_SIZE); - } else { - isr_log_e("Only one instance of USBHIDVendor is allowed!"); - abort(); } } @@ -112,7 +112,9 @@ void USBHIDVendor::onEvent(arduino_usb_hid_vendor_event_t event, esp_event_handl } uint16_t USBHIDVendor::_onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len){ - log_v("len: %u", len); + if(report_id != HID_REPORT_ID_VENDOR){ + return 0; + } memcpy(buffer, feature, len); arduino_usb_hid_vendor_event_data_t p = {0}; p.buffer = feature; @@ -122,7 +124,9 @@ uint16_t USBHIDVendor::_onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_ } void USBHIDVendor::_onSetFeature(uint8_t report_id, const uint8_t* buffer, uint16_t len){ - log_v("len: %u", len); + if(report_id != HID_REPORT_ID_VENDOR){ + return; + } memcpy(feature, buffer, len); arduino_usb_hid_vendor_event_data_t p = {0}; p.buffer = feature; @@ -131,7 +135,9 @@ void USBHIDVendor::_onSetFeature(uint8_t report_id, const uint8_t* buffer, uint1 } void USBHIDVendor::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){ - log_v("len: %u", len); + if(report_id != HID_REPORT_ID_VENDOR){ + return; + } for(uint32_t i=0; i Date: Tue, 17 Aug 2021 16:59:05 +0300 Subject: [PATCH 06/17] Update USBHID.cpp --- libraries/USB/src/USBHID.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index de241c293dd..1a897a4d0a4 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -23,30 +23,6 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); -static void log_print_buf_line(const uint8_t *b, size_t len){ - for(size_t i = 0; i= 0x20) && (b[i] < 0x80))?b[i]:'.'); - } - log_printf("\n"); -} - -void log_print_buf(const uint8_t *b, size_t len){ - if(!len || !b){ - return; - } - for(size_t i = 0; i Date: Tue, 17 Aug 2021 17:18:59 +0300 Subject: [PATCH 07/17] Add bool HID::ready() --- .../USB/examples/CompositeDevice/CompositeDevice.ino | 6 ++++-- libraries/USB/src/USBHID.cpp | 12 ++++++++---- libraries/USB/src/USBHID.h | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libraries/USB/examples/CompositeDevice/CompositeDevice.ino b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino index 1f9b9159d2e..af811420590 100644 --- a/libraries/USB/examples/CompositeDevice/CompositeDevice.ino +++ b/libraries/USB/examples/CompositeDevice/CompositeDevice.ino @@ -178,7 +178,7 @@ void setup() { void loop() { int buttonState = digitalRead(buttonPin); - if (buttonState != previousButtonState) { + if (HID.ready() && buttonState != previousButtonState) { previousButtonState = buttonState; if (buttonState == LOW) { HWSerial.println("Button Pressed"); @@ -206,6 +206,8 @@ void loop() { uint8_t b[l]; l = HWSerial.read(b, l); USBSerial.write(b, l); - Vendor.write(b,l); + if(HID.ready()){ + Vendor.write(b,l); + } } } diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 1a897a4d0a4..d24ae310332 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -173,9 +173,6 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf) return 0; } tinyusb_hid_is_initialized = true; - if(!tinyusb_load_enabled_hid_devices()){ - return 0; - } uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB HID"); uint8_t ep_in = tinyusb_get_free_in_endpoint(); @@ -199,6 +196,9 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf) // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){ log_v("instance: %u", instance); + if(!tinyusb_load_enabled_hid_devices()){ + return NULL; + } return tinyusb_hid_device_descriptor; } @@ -281,6 +281,10 @@ void USBHID::end(){ } } +bool USBHID::ready(void){ + return tud_hid_n_ready(0); +} + void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){ if (tinyusb_hid_device_input_sem) { xSemaphoreGive(tinyusb_hid_device_input_sem); @@ -298,7 +302,7 @@ bool USBHID::SendReport(uint8_t id, const void* data, size_t len, uint32_t timeo return false; } - bool res = tud_hid_n_ready(0); + bool res = ready(); if(!res){ log_e("not ready"); } else { diff --git a/libraries/USB/src/USBHID.h b/libraries/USB/src/USBHID.h index 426cfd9b28d..9c62d018954 100644 --- a/libraries/USB/src/USBHID.h +++ b/libraries/USB/src/USBHID.h @@ -69,6 +69,7 @@ class USBHID USBHID(void); void begin(void); void end(void); + bool ready(void); bool SendReport(uint8_t report_id, const void* data, size_t len, uint32_t timeout_ms = 100); void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback); From c919886bd3147bf47a9f3b24528e16fa40fa8f1d Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 17 Aug 2021 18:20:35 +0300 Subject: [PATCH 08/17] Add custom HID device example --- .../USB/examples/CustomHIDDevice/.skip.esp32 | 0 .../examples/CustomHIDDevice/.skip.esp32c3 | 0 .../CustomHIDDevice/CustomHIDDevice.ino | 79 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 libraries/USB/examples/CustomHIDDevice/.skip.esp32 create mode 100644 libraries/USB/examples/CustomHIDDevice/.skip.esp32c3 create mode 100644 libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino diff --git a/libraries/USB/examples/CustomHIDDevice/.skip.esp32 b/libraries/USB/examples/CustomHIDDevice/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/CustomHIDDevice/.skip.esp32c3 b/libraries/USB/examples/CustomHIDDevice/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino b/libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino new file mode 100644 index 00000000000..15d69b6a63b --- /dev/null +++ b/libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino @@ -0,0 +1,79 @@ +#include "USB.h" +#include "USBHID.h" +USBHID HID; + +static const uint8_t report_descriptor[] = { // 8 axis + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xa1, 0x01, // Collection (Application) + 0xa1, 0x00, // Collection (Physical) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x36, // Usage (Slider) + 0x09, 0x36, // Usage (Slider) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7f, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +class CustomHIDDevice: public USBHIDDevice { +public: + CustomHIDDevice(void){ + static bool initialized = false; + if(!initialized){ + initialized = true; + HID.addDevice(this, sizeof(report_descriptor)); + } + } + + void begin(void){ + HID.begin(); + } + + uint16_t _onGetDescriptor(uint8_t* buffer){ + memcpy(buffer, report_descriptor, sizeof(report_descriptor)); + return sizeof(report_descriptor); + } + + bool send(uint8_t * value){ + return HID.SendReport(0, value, 8); + } +}; + +CustomHIDDevice Device; + +const int buttonPin = 0; +int previousButtonState = HIGH; +uint8_t axis[8]; + +void setup() { + Serial.begin(115200); + Serial.setDebugOutput(true); + pinMode(buttonPin, INPUT_PULLUP); + Device.begin(); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if (HID.ready() && buttonState != previousButtonState) { + previousButtonState = buttonState; + if (buttonState == LOW) { + Serial.println("Button Pressed"); + axis[0] = random() & 0xFF; + Device.send(axis); + } else { + Serial.println("Button Released"); + } + delay(100); + } +} From 8559d8b0cb393ee60da13b5c7ddb63364dcc5d09 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 18 Aug 2021 03:21:32 +0300 Subject: [PATCH 09/17] Make Vendor class more flexible --- libraries/USB/src/USBHIDVendor.cpp | 46 ++++++++++++++++++------------ libraries/USB/src/USBHIDVendor.h | 10 +++++-- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index 39e35fcd363..96e0d6e1661 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -56,29 +56,36 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i #define TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN 46 // max size is 64 and we need one byte for the report ID -static const uint8_t HID_VENDOR_REPORT_SIZE = 63; - -static uint8_t feature[HID_VENDOR_REPORT_SIZE]; +static uint8_t HID_VENDOR_REPORT_SIZE = 63; +static uint8_t feature[64]; static xQueueHandle rx_queue = NULL; +static bool prepend_size = false; -static const uint8_t report_descriptor[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(HID_REPORT_ID_VENDOR)) -}; - -USBHIDVendor::USBHIDVendor(): hid(){ +USBHIDVendor::USBHIDVendor(uint8_t report_size, bool prepend): hid(){ static bool initialized = false; if(!initialized){ initialized = true; - hid.addDevice(this, sizeof(report_descriptor)); - memset(feature, 0, HID_VENDOR_REPORT_SIZE); + hid.addDevice(this, TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN); + memset(feature, 0, 64); + if(report_size < 64){ + HID_VENDOR_REPORT_SIZE = report_size; + } + prepend_size = prepend; } } uint16_t USBHIDVendor::_onGetDescriptor(uint8_t* dst){ + uint8_t report_descriptor[] = { + TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE(HID_VENDOR_REPORT_SIZE, HID_REPORT_ID(HID_REPORT_ID_VENDOR)) + }; memcpy(dst, report_descriptor, sizeof(report_descriptor)); return sizeof(report_descriptor); } +void USBHIDVendor::prependInputPacketsWithSize(bool enable){ + prepend_size = enable; +} + size_t USBHIDVendor::setRxBufferSize(size_t rx_queue_len){ if(rx_queue){ if(!rx_queue_len){ @@ -151,21 +158,24 @@ void USBHIDVendor::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY); } -size_t USBHIDVendor::write(const uint8_t* buffer, uint16_t len){ +size_t USBHIDVendor::write(const uint8_t* buffer, size_t len){ + uint8_t hid_in[HID_VENDOR_REPORT_SIZE]; const uint8_t * data = (const uint8_t *)buffer; - size_t to_send = len, max_send=HID_VENDOR_REPORT_SIZE, will_send=0; + uint8_t size_offset = prepend_size?1:0; + size_t to_send = len, max_send=HID_VENDOR_REPORT_SIZE - size_offset, will_send=0; while(to_send){ will_send = to_send; if(will_send > max_send){ will_send = max_send; } - // On Mac, I can get INPUT only when data length equals the input report size - // To be tested on other platforms - uint8_t hid_in[HID_VENDOR_REPORT_SIZE]; - memcpy(hid_in, data, will_send); - memset(hid_in + will_send, 0, HID_VENDOR_REPORT_SIZE - will_send); + if(prepend_size){ + hid_in[0] = will_send; + } + // We can get INPUT only when data length equals the input report size + memcpy(hid_in + size_offset, data, will_send); + // pad with zeroes + memset(hid_in + size_offset + will_send, 0, max_send - will_send); if(!hid.SendReport(HID_REPORT_ID_VENDOR, hid_in, HID_VENDOR_REPORT_SIZE)){ - //if(!hid.SendReport(HID_REPORT_ID_VENDOR, buffer + (len - to_send), will_send)){ return len - to_send; } to_send -= will_send; diff --git a/libraries/USB/src/USBHIDVendor.h b/libraries/USB/src/USBHIDVendor.h index 26362d5eeea..fe11c0b5e11 100644 --- a/libraries/USB/src/USBHIDVendor.h +++ b/libraries/USB/src/USBHIDVendor.h @@ -36,11 +36,17 @@ class USBHIDVendor: public USBHIDDevice, public Stream { private: USBHID hid; public: - USBHIDVendor(void); + // Max report size is 64, but we need one byte for report ID, so in reality max is 63. + // Because input packets are always with length equal to the report size + // it will not be known how many bytes actually matter. Setting 'prepend_size' to 'true' will + // make the first byte of each packet to be the length of data in that packet. + // This comes with penalty of one byte, but is very useful when using Vendor for streaming + USBHIDVendor(uint8_t report_size=63, bool prepend_size=false); void begin(void); void end(void); + void prependInputPacketsWithSize(bool enable); size_t setRxBufferSize(size_t); - size_t write(const uint8_t* buffer, uint16_t len); + size_t write(const uint8_t* buffer, size_t len); size_t write(uint8_t); int available(void); int peek(void); From b70fc32e87f966a1bb564f3c06bd8f7ccfaaf92c Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 18 Aug 2021 14:09:09 +0300 Subject: [PATCH 10/17] Handle better devices that use report ID 0 --- libraries/USB/src/USBHID.cpp | 43 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index d24ae310332..d29993021d8 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -120,7 +120,10 @@ static uint16_t tinyusb_on_add_descriptor(uint8_t device_index, uint8_t * dst){ if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){ report_id = hid_report_map->reports[i].report_id; for(uint8_t r=0; rreports_num; r++){ - if(report_id == device->report_ids[r]){ + if(!report_id){ + //todo: handle better when device has no report ID set + break; + } else if(report_id == device->report_ids[r]){ //already added reports_num--; break; @@ -156,12 +159,31 @@ static bool tinyusb_load_enabled_hid_devices(){ uint8_t * dst = tinyusb_hid_device_descriptor; for(uint8_t i=0; ireports_len; i++){ + if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){ + log_d(" ID: %3u, Type: %7s, Size: %2u, Usage: %8s", + hid_report_map->reports[i].report_id, + esp_hid_report_type_str(hid_report_map->reports[i].report_type), + hid_report_map->reports[i].value_len, + esp_hid_usage_str(hid_report_map->reports[i].usage) + ); } + } + esp_hid_free_report_map(hid_report_map); + } else { + log_e("Failed to parse the hid report descriptor!"); + return false; } return true; @@ -205,7 +227,7 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){ // Invoked when received SET_PROTOCOL request // protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){ - log_d("instance: %u, protocol:%u", instance, protocol); + log_v("instance: %u, protocol:%u", instance, protocol); arduino_usb_hid_event_data_t p = {0}; p.instance = instance; p.set_protocol.protocol = protocol; @@ -216,7 +238,7 @@ void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){ // - Idle Rate = 0 : only send report if there is changes, i.e skip duplication // - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate){ - log_d("instance: %u, idle_rate:%u", instance, idle_rate); + log_v("instance: %u, idle_rate:%u", instance, idle_rate); arduino_usb_hid_event_data_t p = {0}; p.instance = instance; p.set_idle.idle_rate = idle_rate; @@ -239,9 +261,8 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t // received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize){ if(!report_id && !report_type){ - report_id = buffer[0]; - if(!tinyusb_on_set_output(report_id, buffer+1, bufsize-1)){ - log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, *buffer, tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1); + if(!tinyusb_on_set_output(0, buffer, bufsize) && !tinyusb_on_set_output(buffer[0], buffer+1, bufsize-1)){ + log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, buffer[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1); } } else { if(!tinyusb_on_set_feature(report_id, buffer, bufsize)){ From 196ce947789c1d8f3a86047110049ab0edbef5ec Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 19 Aug 2021 13:21:33 +0300 Subject: [PATCH 11/17] Refactor includes and config keys for USB classes --- cores/esp32/FirmwareMSC.cpp | 6 +++--- cores/esp32/FirmwareMSC.h | 1 + cores/esp32/USB.cpp | 7 +++++-- cores/esp32/USB.h | 8 +++----- cores/esp32/USBCDC.cpp | 9 +++------ cores/esp32/USBMSC.cpp | 8 ++++---- cores/esp32/USBMSC.h | 6 ++++-- libraries/USB/src/USBHID.cpp | 10 ++++++---- libraries/USB/src/USBHID.h | 10 +++++----- libraries/USB/src/USBHIDConsumerControl.cpp | 9 ++++----- libraries/USB/src/USBHIDGamepad.cpp | 9 ++++----- libraries/USB/src/USBHIDKeyboard.cpp | 9 ++++----- libraries/USB/src/USBHIDMouse.cpp | 9 ++++----- libraries/USB/src/USBHIDSystemControl.cpp | 9 ++++----- libraries/USB/src/USBHIDVendor.cpp | 11 ++++++----- 15 files changed, 60 insertions(+), 61 deletions(-) diff --git a/cores/esp32/FirmwareMSC.cpp b/cores/esp32/FirmwareMSC.cpp index c399a013b25..473e220bd83 100644 --- a/cores/esp32/FirmwareMSC.cpp +++ b/cores/esp32/FirmwareMSC.cpp @@ -11,17 +11,17 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "FirmwareMSC.h" + +#if CONFIG_TINYUSB_MSC_ENABLED #include -#include "FirmwareMSC.h" #include "esp_partition.h" #include "esp_ota_ops.h" #include "esp32-hal.h" #include "pins_arduino.h" #include "firmware_msc_fat.h" -#if CONFIG_TINYUSB_MSC_ENABLED - #ifndef USB_FW_MSC_VENDOR_ID #define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars #endif diff --git a/cores/esp32/FirmwareMSC.h b/cores/esp32/FirmwareMSC.h index 3caaf6a0e64..570feac8e2f 100644 --- a/cores/esp32/FirmwareMSC.h +++ b/cores/esp32/FirmwareMSC.h @@ -15,6 +15,7 @@ #pragma once #include #include "USBMSC.h" + #if CONFIG_TINYUSB_MSC_ENABLED #include "esp_event.h" diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp index 1221707cb0a..28daa8001a1 100644 --- a/cores/esp32/USB.cpp +++ b/cores/esp32/USB.cpp @@ -11,11 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" #include "USB.h" + #if CONFIG_TINYUSB_ENABLED +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "common/tusb_common.h" + #ifndef USB_VID #define USB_VID USB_ESPRESSIF_VID #endif diff --git a/cores/esp32/USB.h b/cores/esp32/USB.h index d64962c7fc7..33f3a2c1dfc 100644 --- a/cores/esp32/USB.h +++ b/cores/esp32/USB.h @@ -13,13 +13,11 @@ // limitations under the License. #pragma once -#include "sdkconfig.h" -#if CONFIG_TINYUSB_ENABLED - #include "Arduino.h" -#include "USBCDC.h" -#include "common/tusb_common.h" + +#if CONFIG_TINYUSB_ENABLED #include "esp_event.h" +#include "USBCDC.h" #define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 7a9cf5e011c..ce2380feebf 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -11,17 +11,16 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" #include "USB.h" +#if CONFIG_TINYUSB_CDC_ENABLED + #include "USBCDC.h" -#if CONFIG_TINYUSB_ENABLED +#include "esp32-hal-tinyusb.h" ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); -#if CFG_TUD_CDC #define MAX_USB_CDC_DEVICES 2 USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; @@ -389,5 +388,3 @@ USBCDC Serial(0); #endif #endif /* CONFIG_TINYUSB_CDC_ENABLED */ - -#endif /* CONFIG_TINYUSB_ENABLED */ diff --git a/cores/esp32/USBMSC.cpp b/cores/esp32/USBMSC.cpp index c6327ecdee0..479d68e5802 100644 --- a/cores/esp32/USBMSC.cpp +++ b/cores/esp32/USBMSC.cpp @@ -11,12 +11,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "USBMSC.h" + +#if CONFIG_TINYUSB_MSC_ENABLED -#include "esp32-hal.h" #include "esp32-hal-tinyusb.h" -#include "USBMSC.h" -#if CFG_TUD_MSC extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf) { uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); @@ -257,4 +257,4 @@ void USBMSC::mediaPresent(bool media_present){ msc_luns[_lun].media_present = media_present; } -#endif /* CONFIG_USB_MSC_ENABLED */ +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ diff --git a/cores/esp32/USBMSC.h b/cores/esp32/USBMSC.h index 799322a30b5..287a57ceb31 100644 --- a/cores/esp32/USBMSC.h +++ b/cores/esp32/USBMSC.h @@ -15,7 +15,8 @@ #pragma once #include #include -#include "esp32-hal.h" +#include "sdkconfig.h" + #if CONFIG_TINYUSB_MSC_ENABLED // Invoked when received Start Stop Unit command @@ -46,4 +47,5 @@ class USBMSC private: uint8_t _lun; }; -#endif + +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index d29993021d8..2d497f2266e 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -11,12 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" #include "USBHID.h" + +#if CONFIG_TINYUSB_HID_ENABLED + +#include "esp32-hal-tinyusb.h" +#include "USB.h" #include "esp_hid_common.h" -#if CFG_TUD_HID #define USB_HID_DEVICES_MAX 10 ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_EVENTS); @@ -360,4 +362,4 @@ void USBHID::onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback arduino_usb_event_handler_register_with(ARDUINO_USB_HID_EVENTS, event, callback, this); } -#endif /* CONFIG_USB_HID_ENABLED */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHID.h b/libraries/USB/src/USBHID.h index 9c62d018954..e7eaae10fab 100644 --- a/libraries/USB/src/USBHID.h +++ b/libraries/USB/src/USBHID.h @@ -15,12 +15,12 @@ #pragma once #include #include -#include "esp32-hal.h" -#include "USB.h" -#if CONFIG_TINYUSB_HID_ENABLED +#include "sdkconfig.h" -#include "class/hid/hid.h" +#if CONFIG_TINYUSB_HID_ENABLED #include "esp_event.h" +#include "class/hid/hid.h" +#include "class/hid/hid_device.h" // Used by the included TinyUSB drivers enum { @@ -76,4 +76,4 @@ class USBHID static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len); }; -#endif +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp index 35dee39beb7..7977fdd1f24 100644 --- a/libraries/USB/src/USBHIDConsumerControl.cpp +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -11,12 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "USBHID.h" -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDConsumerControl.h" +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "USBHIDConsumerControl.h" static const uint8_t report_descriptor[] = { TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(HID_REPORT_ID_CONSUMER_CONTROL)) @@ -55,4 +54,4 @@ size_t USBHIDConsumerControl::release(){ } -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp index 37e65e79ffc..57a2f028356 100644 --- a/libraries/USB/src/USBHIDGamepad.cpp +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -11,12 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "USBHID.h" -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDGamepad.h" +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "USBHIDGamepad.h" static const uint8_t report_descriptor[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(HID_REPORT_ID_GAMEPAD)) @@ -119,4 +118,4 @@ bool USBHIDGamepad::send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int } -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDKeyboard.cpp b/libraries/USB/src/USBHIDKeyboard.cpp index 15914ceed3c..9a9445ded89 100644 --- a/libraries/USB/src/USBHIDKeyboard.cpp +++ b/libraries/USB/src/USBHIDKeyboard.cpp @@ -18,12 +18,11 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "USBHID.h" -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDKeyboard.h" +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "USBHIDKeyboard.h" ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); @@ -352,4 +351,4 @@ size_t USBHIDKeyboard::write(const uint8_t *buffer, size_t size) { return n; } -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp index dbc84c97505..92efd617661 100644 --- a/libraries/USB/src/USBHIDMouse.cpp +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -18,12 +18,11 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "USBHID.h" -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDMouse.h" +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "USBHIDMouse.h" static const uint8_t report_descriptor[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_REPORT_ID_MOUSE)) @@ -90,4 +89,4 @@ bool USBHIDMouse::isPressed(uint8_t b){ } -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp index d1dafc30906..6bd165619d9 100644 --- a/libraries/USB/src/USBHIDSystemControl.cpp +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -11,12 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "USBHID.h" -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDSystemControl.h" +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "USBHIDSystemControl.h" static const uint8_t report_descriptor[] = { TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(HID_REPORT_ID_SYSTEM_CONTROL)) @@ -57,4 +56,4 @@ size_t USBHIDSystemControl::release(){ return send(0); } -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index 96e0d6e1661..0a6495abe71 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -11,11 +11,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "esp32-hal.h" -#include "esp32-hal-tinyusb.h" -#include "USBHIDVendor.h" +#include "USBHID.h" + +#if CONFIG_TINYUSB_HID_ENABLED -#if CFG_TUD_HID +#include "esp32-hal-log.h" +#include "USBHIDVendor.h" ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_VENDOR_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); @@ -232,4 +233,4 @@ size_t USBHIDVendor::read(uint8_t *buffer, size_t size){ void USBHIDVendor::flush(void){} -#endif /* CFG_TUD_HID */ +#endif /* CONFIG_TINYUSB_HID_ENABLED */ From d493788a949eb07cccbb768db3d3ee4cdb4050b0 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 19 Aug 2021 13:41:39 +0300 Subject: [PATCH 12/17] Fix examples --- cores/esp32/USB.h | 3 ++- cores/esp32/USBCDC.h | 7 +++---- libraries/USB/examples/ConsumerControl/ConsumerControl.ino | 1 + libraries/USB/examples/Gamepad/Gamepad.ino | 1 + libraries/USB/examples/HIDVendor/HIDVendor.ino | 1 + .../examples/Keyboard/KeyboardLogout/KeyboardLogout.ino | 1 + .../examples/Keyboard/KeyboardMessage/KeyboardMessage.ino | 1 + .../Keyboard/KeyboardReprogram/KeyboardReprogram.ino | 1 + .../examples/Keyboard/KeyboardSerial/KeyboardSerial.ino | 1 + .../KeyboardAndMouseControl/KeyboardAndMouseControl.ino | 1 + .../Mouse/ButtonMouseControl/ButtonMouseControl.ino | 1 + libraries/USB/examples/SystemControl/SystemControl.ino | 1 + 12 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cores/esp32/USB.h b/cores/esp32/USB.h index 33f3a2c1dfc..131ff6d4268 100644 --- a/cores/esp32/USB.h +++ b/cores/esp32/USB.h @@ -13,9 +13,10 @@ // limitations under the License. #pragma once -#include "Arduino.h" +#include "sdkconfig.h" #if CONFIG_TINYUSB_ENABLED + #include "esp_event.h" #include "USBCDC.h" diff --git a/cores/esp32/USBCDC.h b/cores/esp32/USBCDC.h index 26df8a3c81c..ced588f45f2 100644 --- a/cores/esp32/USBCDC.h +++ b/cores/esp32/USBCDC.h @@ -13,13 +13,12 @@ // limitations under the License. #pragma once -#include - -#include "Stream.h" -#include "esp32-hal.h" +#include "sdkconfig.h" #if CONFIG_TINYUSB_CDC_ENABLED +#include #include "esp_event.h" +#include "Stream.h" ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS); diff --git a/libraries/USB/examples/ConsumerControl/ConsumerControl.ino b/libraries/USB/examples/ConsumerControl/ConsumerControl.ino index d3fbe81f85f..ab6fb19d9ca 100644 --- a/libraries/USB/examples/ConsumerControl/ConsumerControl.ino +++ b/libraries/USB/examples/ConsumerControl/ConsumerControl.ino @@ -1,3 +1,4 @@ +#include "USB.h" #include "USBHIDConsumerControl.h" USBHIDConsumerControl ConsumerControl; diff --git a/libraries/USB/examples/Gamepad/Gamepad.ino b/libraries/USB/examples/Gamepad/Gamepad.ino index e7cd9a4d817..da9ff69e9dd 100644 --- a/libraries/USB/examples/Gamepad/Gamepad.ino +++ b/libraries/USB/examples/Gamepad/Gamepad.ino @@ -1,3 +1,4 @@ +#include "USB.h" #include "USBHIDGamepad.h" USBHIDGamepad Gamepad; diff --git a/libraries/USB/examples/HIDVendor/HIDVendor.ino b/libraries/USB/examples/HIDVendor/HIDVendor.ino index f4727415761..223edba1d90 100644 --- a/libraries/USB/examples/HIDVendor/HIDVendor.ino +++ b/libraries/USB/examples/HIDVendor/HIDVendor.ino @@ -1,3 +1,4 @@ +#include "USB.h" #include "USBHIDVendor.h" USBHIDVendor Vendor; diff --git a/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino b/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino index 90cf6bb4bac..a7f8214b78a 100644 --- a/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino +++ b/libraries/USB/examples/Keyboard/KeyboardLogout/KeyboardLogout.ino @@ -29,6 +29,7 @@ #define WINDOWS 1 #define UBUNTU 2 +#include "USB.h" #include "USBHIDKeyboard.h" USBHIDKeyboard Keyboard; diff --git a/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino b/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino index 93766bad3df..30f92a47821 100644 --- a/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino +++ b/libraries/USB/examples/Keyboard/KeyboardMessage/KeyboardMessage.ino @@ -20,6 +20,7 @@ http://www.arduino.cc/en/Tutorial/KeyboardMessage */ +#include "USB.h" #include "USBHIDKeyboard.h" USBHIDKeyboard Keyboard; diff --git a/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino b/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino index 192f91f03fb..3c6520556fe 100644 --- a/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino +++ b/libraries/USB/examples/Keyboard/KeyboardReprogram/KeyboardReprogram.ino @@ -25,6 +25,7 @@ http://www.arduino.cc/en/Tutorial/KeyboardReprogram */ +#include "USB.h" #include "USBHIDKeyboard.h" USBHIDKeyboard Keyboard; diff --git a/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino b/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino index bcfa7542d4d..e3bb8769737 100644 --- a/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino +++ b/libraries/USB/examples/Keyboard/KeyboardSerial/KeyboardSerial.ino @@ -17,6 +17,7 @@ http://www.arduino.cc/en/Tutorial/KeyboardSerial */ +#include "USB.h" #include "USBHIDKeyboard.h" USBHIDKeyboard Keyboard; diff --git a/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino b/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino index 14623929c07..6cf564bbc9f 100644 --- a/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino +++ b/libraries/USB/examples/KeyboardAndMouseControl/KeyboardAndMouseControl.ino @@ -19,6 +19,7 @@ http://www.arduino.cc/en/Tutorial/KeyboardAndMouseControl */ +#include "USB.h" #include "USBHIDMouse.h" #include "USBHIDKeyboard.h" USBHIDMouse Mouse; diff --git a/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino b/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino index 8bc1200afcb..0a7ee0caa34 100644 --- a/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino +++ b/libraries/USB/examples/Mouse/ButtonMouseControl/ButtonMouseControl.ino @@ -21,6 +21,7 @@ http://www.arduino.cc/en/Tutorial/ButtonMouseControl */ +#include "USB.h" #include "USBHIDMouse.h" USBHIDMouse Mouse; diff --git a/libraries/USB/examples/SystemControl/SystemControl.ino b/libraries/USB/examples/SystemControl/SystemControl.ino index f4a7f5c5843..7d644ea9164 100644 --- a/libraries/USB/examples/SystemControl/SystemControl.ino +++ b/libraries/USB/examples/SystemControl/SystemControl.ino @@ -1,3 +1,4 @@ +#include "USB.h" #include "USBHIDSystemControl.h" USBHIDSystemControl SystemControl; From 1cf4559b7be7ef57d53d35d08ee22c07ff476529 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 19 Aug 2021 20:56:09 +0300 Subject: [PATCH 13/17] Update esp32-hal-tinyusb.c --- cores/esp32/esp32-hal-tinyusb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 0da912b0210..a413c75260e 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -424,12 +424,6 @@ static bool tinyusb_load_enabled_interfaces(){ log_e("Descriptor Load Failed"); return false; } else { - if(i == USB_INTERFACE_CDC){ - if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){ - log_e("CDC Reserve Endpoints Failed"); - return false; - } - } dst += len; } } @@ -505,6 +499,7 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){ && (config->usb_class != TUSB_CLASS_CDC) ){ config->usb_class = TUSB_CLASS_CDC; + config->usb_protocol = 0x00; } WEBUSB_ENABLED = config->webusb_enabled; @@ -573,6 +568,12 @@ esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descr log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); return ESP_FAIL; } + if(interface == USB_INTERFACE_CDC){ + if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){ + log_e("CDC Reserve Endpoints Failed"); + return ESP_FAIL; + } + } tinyusb_loaded_interfaces_mask |= (1U << interface); tinyusb_config_descriptor_len += descriptor_len; tinyusb_loaded_interfaces_callbacks[interface] = cb; @@ -586,7 +587,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { } tinyusb_is_initialized = true; - tinyusb_endpoints.val = 0; + //tinyusb_endpoints.val = 0; tinyusb_apply_device_config(config); if (!tinyusb_load_enabled_interfaces()) { tinyusb_is_initialized = false; From 2918858bfa7b8231d293875f2a16dfc715fd2a12 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 19 Aug 2021 22:43:56 +0300 Subject: [PATCH 14/17] Add support and example for USB Vendor --- libraries/USB/examples/USBVendor/.skip.esp32 | 0 .../USB/examples/USBVendor/.skip.esp32c3 | 0 .../USB/examples/USBVendor/USBVendor.ino | 165 ++++++++++++++ libraries/USB/src/USBVendor.cpp | 209 ++++++++++++++++++ libraries/USB/src/USBVendor.h | 66 ++++++ 5 files changed, 440 insertions(+) create mode 100644 libraries/USB/examples/USBVendor/.skip.esp32 create mode 100644 libraries/USB/examples/USBVendor/.skip.esp32c3 create mode 100644 libraries/USB/examples/USBVendor/USBVendor.ino create mode 100644 libraries/USB/src/USBVendor.cpp create mode 100644 libraries/USB/src/USBVendor.h diff --git a/libraries/USB/examples/USBVendor/.skip.esp32 b/libraries/USB/examples/USBVendor/.skip.esp32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/USBVendor/.skip.esp32c3 b/libraries/USB/examples/USBVendor/.skip.esp32c3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/USB/examples/USBVendor/USBVendor.ino b/libraries/USB/examples/USBVendor/USBVendor.ino new file mode 100644 index 00000000000..d9286043bb5 --- /dev/null +++ b/libraries/USB/examples/USBVendor/USBVendor.ino @@ -0,0 +1,165 @@ +#include "USB.h" +#include "USBVendor.h" +#include "class/cdc/cdc.h" + +#if ARDUINO_USB_CDC_ON_BOOT +#define HWSerial Serial0 +#else +#define HWSerial Serial +#endif + +USBVendor Vendor; + +const int buttonPin = 0; +int previousButtonState = HIGH; + +static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + if(event_base == ARDUINO_USB_EVENTS){ + arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_STARTED_EVENT: + HWSerial.println("USB PLUGGED"); + break; + case ARDUINO_USB_STOPPED_EVENT: + HWSerial.println("USB UNPLUGGED"); + break; + case ARDUINO_USB_SUSPEND_EVENT: + HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); + break; + case ARDUINO_USB_RESUME_EVENT: + HWSerial.println("USB RESUMED"); + break; + + default: + break; + } + } else if(event_base == ARDUINO_USB_VENDOR_EVENTS){ + arduino_usb_vendor_event_data_t * data = (arduino_usb_vendor_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_VENDOR_DATA_EVENT: + HWSerial.printf("Vendor RX: len:%u\n", data->data.len); + for(uint16_t i=0; idata.len; i++){ + HWSerial.write(Vendor.read()); + } + HWSerial.println(); + break; + + default: + break; + } + } +} + +bool vendorRequestCallback(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ + static const char * vendorRequestTypes[] = {"Standard", "Class", "Vendor"}; + static const char * vendorRequestRecipients[] = {"Device", "Interface", "Endpoint", "Other"}; + static const char * vendorStages[] = {"Setup","Data","Ack"}; + HWSerial.printf("Vendor Request: Stage: %5s, Direction: %3s, Type: %8s, Recipient: %9s, bRequest: 0x%02x, wValue: 0x%04x, wIndex: %u, wLength: %u\n", vendorStages[stage], + request->bmRequestType_bit.direction?"IN":"OUT", + vendorRequestTypes[request->bmRequestType_bit.type], + vendorRequestRecipients[request->bmRequestType_bit.recipient], + request->bRequest, request->wValue, request->wIndex, request->wLength); + + + static uint8_t vendor_line_state = 0;// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + static cdc_line_coding_t vendor_line_coding; + bool result = false; + + if(request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE && request->bRequest == 0x0b){ + if(stage == CONTROL_STAGE_SETUP) { + // response with status OK + result = Vendor.sendResponse(rhport, request); + } else { + result = true; + } + } else if(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE){ + //Implement CDC Control Requests + switch (request->bRequest) { + + // CDC Set Line Coding + case CDC_REQUEST_SET_LINE_CODING: //0x20 + if(request->wLength != sizeof(cdc_line_coding_t) || request->bmRequestType_bit.direction != TUSB_DIR_OUT){ + break; + } + if(stage == CONTROL_STAGE_SETUP) { + //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage) + result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(cdc_line_coding_t)); + } else if(stage == CONTROL_STAGE_ACK){ + //In the ACK stage the requst->response is complete + HWSerial.printf("Vendor Line Coding: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", vendor_line_coding.bit_rate, vendor_line_coding.data_bits, vendor_line_coding.stop_bits, vendor_line_coding.parity); + } + result = true; + break; + + // CDC Get Line Coding + case CDC_REQUEST_GET_LINE_CODING: //0x21 + if(request->wLength != sizeof(cdc_line_coding_t) || request->bmRequestType_bit.direction != TUSB_DIR_IN){ + break; + } + if(stage == CONTROL_STAGE_SETUP) { + result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(cdc_line_coding_t)); + } + result = true; + break; + + // CDC Set Line State + case CDC_REQUEST_SET_CONTROL_LINE_STATE: //0x22 + if(request->wLength != 0 || request->bmRequestType_bit.direction != TUSB_DIR_OUT){ + break; + } + if(stage == CONTROL_STAGE_SETUP) { + vendor_line_state = request->wValue; + result = Vendor.sendResponse(rhport, request); + } else if(stage == CONTROL_STAGE_ACK){ + bool dtr = tu_bit_test(vendor_line_state, 0); + bool rts = tu_bit_test(vendor_line_state, 1); + HWSerial.printf("Vendor Line State: dtr: %u, rts: %u\n", dtr, rts); + } + result = true; + break; + + default: + // stall unknown request + break; + } + } + + return result; +} + +void setup() { + pinMode(buttonPin, INPUT_PULLUP); + HWSerial.begin(115200); + HWSerial.setDebugOutput(true); + + Vendor.onEvent(usbEventCallback); + Vendor.onRequest(vendorRequestCallback); + Vendor.begin(); + + USB.onEvent(usbEventCallback); + USB.webUSB(true); + USB.webUSBURL("http://localhost/webusb"); + USB.begin(); +} + +void loop() { + int buttonState = digitalRead(buttonPin); + if (buttonState != previousButtonState) { + previousButtonState = buttonState; + if (buttonState == LOW) { + HWSerial.println("Button Pressed"); + Vendor.println("Button Pressed"); + } else { + Vendor.println("Button Released"); + HWSerial.println("Button Released"); + } + delay(100); + } + + while(HWSerial.available()){ + size_t l = HWSerial.available(); + uint8_t b[l]; + l = HWSerial.read(b, l); + Vendor.write(b,l); + } +} diff --git a/libraries/USB/src/USBVendor.cpp b/libraries/USB/src/USBVendor.cpp new file mode 100644 index 00000000000..26a75c547fa --- /dev/null +++ b/libraries/USB/src/USBVendor.cpp @@ -0,0 +1,209 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "USBVendor.h" + +#if CONFIG_TINYUSB_VENDOR_ENABLED + +#include "esp32-hal-tinyusb.h" + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_VENDOR_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +uint16_t tusb_vendor_load_descriptor(uint8_t * dst, uint8_t * itf) +{ + uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Vendor"); + uint8_t ep_num = tinyusb_get_free_duplex_endpoint(); + TU_VERIFY (ep_num != 0); + uint8_t descriptor[TUD_VENDOR_DESC_LEN] = { + // Interface number, string index, EP Out & IN address, EP size + TUD_VENDOR_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) + }; + *itf+=1; + memcpy(dst, descriptor, TUD_VENDOR_DESC_LEN); + return TUD_VENDOR_DESC_LEN; +} + +static USBVendor * _Vendor = NULL; +static xQueueHandle rx_queue = NULL; + +void tud_vendor_rx_cb(uint8_t itf){ + log_v("%u", len); + size_t len = tud_vendor_n_available(itf); + if(len){ + uint8_t buffer[len]; + len = tud_vendor_n_read(itf, buffer, len); + log_buf_v(buffer, len); + if(_Vendor) { + _Vendor->_onRX(buffer, len); + } + } else { + if(_Vendor) { + _Vendor->_onRX(NULL, len); + } + } +} + +extern "C" bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ + log_v("Port: %u, Stage: %u, Direction: %u, Type: %u, Recipient: %u, bRequest: 0x%x, wValue: %u, wIndex: %u, wLength: %u", + rhport, stage, request->bmRequestType_bit.direction, + request->bmRequestType_bit.type, request->bmRequestType_bit.recipient, + request->bRequest, request->wValue, request->wIndex, request->wLength); + + if(_Vendor) { + return _Vendor->_onRequest(rhport, stage, request); + } + return false; +} + +USBVendor::USBVendor():itf(0), cb(NULL){ + if(!_Vendor){ + _Vendor = this; + tinyusb_enable_interface(USB_INTERFACE_VENDOR, TUD_VENDOR_DESC_LEN, tusb_vendor_load_descriptor); + } +} + +size_t USBVendor::setRxBufferSize(size_t rx_queue_len){ + if(rx_queue){ + if(!rx_queue_len){ + vQueueDelete(rx_queue); + rx_queue = NULL; + } + return 0; + } + rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!rx_queue){ + return 0; + } + return rx_queue_len; +} + +void USBVendor::begin(){ + setRxBufferSize(256);//default if not preset +} + +void USBVendor::end(){ + setRxBufferSize(0); +} + +void USBVendor::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_VENDOR_ANY_EVENT, callback); +} + +void USBVendor::onEvent(arduino_usb_vendor_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_VENDOR_EVENTS, event, callback, this); +} + +bool USBVendor::mounted(){ + return tud_vendor_n_mounted(itf); +} + +bool USBVendor::sendResponse(uint8_t rhport, tusb_control_request_t const * request, void * data, size_t len){ + if(!request){ + return false; + } + if(!data || !len){ + return tud_control_status(rhport, request); + } else { + return tud_control_xfer(rhport, request, data, len); + } +} + +void USBVendor::onRequest(arduino_usb_vendor_control_request_handler_t handler){ + cb = handler; +} + +bool USBVendor::_onRequest(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ + if(cb){ + return cb(rhport, stage, request); + } + return false; +} + +void USBVendor::_onRX(const uint8_t* buffer, size_t len){ + for(uint32_t i=0; i max_len){ + len = max_len; + } + if(len){ + return tud_vendor_n_write(itf, buffer, len); + } + return len; +} + +size_t USBVendor::write(uint8_t c){ + return write(&c, 1); +} + +int USBVendor::available(void){ + if(rx_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx_queue); +} + +int USBVendor::peek(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c; + if(xQueuePeek(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +int USBVendor::read(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +size_t USBVendor::read(uint8_t *buffer, size_t size){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + size_t count = 0; + while(count < size && xQueueReceive(rx_queue, &c, 0)){ + buffer[count++] = c; + } + return count; +} + +void USBVendor::flush(void){} + +#endif /* CONFIG_TINYUSB_VENDOR_ENABLED */ diff --git a/libraries/USB/src/USBVendor.h b/libraries/USB/src/USBVendor.h new file mode 100644 index 00000000000..b641fd9de31 --- /dev/null +++ b/libraries/USB/src/USBVendor.h @@ -0,0 +1,66 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "Stream.h" +#include "sdkconfig.h" + +#if CONFIG_TINYUSB_VENDOR_ENABLED +#include "esp_event.h" +#include "common/tusb_common.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_VENDOR_EVENTS); + +typedef enum { + ARDUINO_USB_VENDOR_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_VENDOR_DATA_EVENT, + ARDUINO_USB_VENDOR_MAX_EVENT, +} arduino_usb_vendor_event_t; + +typedef union { + struct { + uint16_t len; + } data; +} arduino_usb_vendor_event_data_t; + +typedef bool (*arduino_usb_vendor_control_request_handler_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +class USBVendor: public Stream { +private: + uint8_t itf; + arduino_usb_vendor_control_request_handler_t cb; +public: + USBVendor(); + void begin(void); + void end(void); + size_t setRxBufferSize(size_t); + bool mounted(void); + size_t write(const uint8_t* buffer, size_t len); + size_t write(uint8_t); + int available(void); + int peek(void); + int read(void); + size_t read(uint8_t *buffer, size_t size); + void flush(void); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_vendor_event_t event, esp_event_handler_t callback); + void onRequest(arduino_usb_vendor_control_request_handler_t handler); + bool sendResponse(uint8_t rhport, tusb_control_request_t const * request, void * data=NULL, size_t len=0); + + bool _onRequest(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + void _onRX(const uint8_t* buffer, size_t len); +}; + +#endif /* CONFIG_TINYUSB_VENDOR_ENABLED */ From c0942e8c315050a918ebd3cb5b18cde14d3ac644 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 19 Aug 2021 22:46:22 +0300 Subject: [PATCH 15/17] Update CMakeLists.txt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1afff1655c..cdb1f07952b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ set(LIBRARY_SRCS libraries/USB/src/USBHIDConsumerControl.cpp libraries/USB/src/USBHIDSystemControl.cpp libraries/USB/src/USBHIDVendor.cpp + libraries/USB/src/USBVendor.cpp libraries/WebServer/src/WebServer.cpp libraries/WebServer/src/Parsing.cpp libraries/WebServer/src/detail/mimetable.cpp From a56aab43f4b0816acd5b6f46c29109d092b2da21 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Fri, 20 Aug 2021 01:45:43 +0300 Subject: [PATCH 16/17] Update USBVendor example --- .../USB/examples/USBVendor/USBVendor.ino | 192 ++++++++++-------- libraries/USB/src/USBVendor.cpp | 27 ++- libraries/USB/src/USBVendor.h | 38 +++- 3 files changed, 159 insertions(+), 98 deletions(-) diff --git a/libraries/USB/examples/USBVendor/USBVendor.ino b/libraries/USB/examples/USBVendor/USBVendor.ino index d9286043bb5..f8976a07e85 100644 --- a/libraries/USB/examples/USBVendor/USBVendor.ino +++ b/libraries/USB/examples/USBVendor/USBVendor.ino @@ -1,6 +1,5 @@ #include "USB.h" #include "USBVendor.h" -#include "class/cdc/cdc.h" #if ARDUINO_USB_CDC_ON_BOOT #define HWSerial Serial0 @@ -9,14 +8,31 @@ #endif USBVendor Vendor; - const int buttonPin = 0; -int previousButtonState = HIGH; -static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ - if(event_base == ARDUINO_USB_EVENTS){ +//CDC Control Requests +#define REQUEST_SET_LINE_CODING 0x20 +#define REQUEST_GET_LINE_CODING 0x21 +#define REQUEST_SET_CONTROL_LINE_STATE 0x22 + +//CDC Line Coding Control Request Structure +typedef struct __attribute__ ((packed)) { + uint32_t bit_rate; + uint8_t stop_bits; //0: 1 stop bit, 1: 1.5 stop bits, 2: 2 stop bits + uint8_t parity; //0: None, 1: Odd, 2: Even, 3: Mark, 4: Space + uint8_t data_bits; //5, 6, 7, 8 or 16 +} request_line_coding_t; + +static request_line_coding_t vendor_line_coding = {9600, 0, 0, 8}; + +// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) +static uint8_t vendor_line_state = 0; + +//USB and Vendor events +static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + if (event_base == ARDUINO_USB_EVENTS) { arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data; - switch (event_id){ + switch (event_id) { case ARDUINO_USB_STARTED_EVENT: HWSerial.println("USB PLUGGED"); break; @@ -29,113 +45,122 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve case ARDUINO_USB_RESUME_EVENT: HWSerial.println("USB RESUMED"); break; - + default: break; } - } else if(event_base == ARDUINO_USB_VENDOR_EVENTS){ + } else if (event_base == ARDUINO_USB_VENDOR_EVENTS) { arduino_usb_vendor_event_data_t * data = (arduino_usb_vendor_event_data_t*)event_data; - switch (event_id){ + switch (event_id) { case ARDUINO_USB_VENDOR_DATA_EVENT: HWSerial.printf("Vendor RX: len:%u\n", data->data.len); - for(uint16_t i=0; idata.len; i++){ + for (uint16_t i = 0; i < data->data.len; i++) { HWSerial.write(Vendor.read()); } HWSerial.println(); break; - + default: break; } } } -bool vendorRequestCallback(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ - static const char * vendorRequestTypes[] = {"Standard", "Class", "Vendor"}; - static const char * vendorRequestRecipients[] = {"Device", "Interface", "Endpoint", "Other"}; - static const char * vendorStages[] = {"Setup","Data","Ack"}; - HWSerial.printf("Vendor Request: Stage: %5s, Direction: %3s, Type: %8s, Recipient: %9s, bRequest: 0x%02x, wValue: 0x%04x, wIndex: %u, wLength: %u\n", vendorStages[stage], - request->bmRequestType_bit.direction?"IN":"OUT", - vendorRequestTypes[request->bmRequestType_bit.type], - vendorRequestRecipients[request->bmRequestType_bit.recipient], - request->bRequest, request->wValue, request->wIndex, request->wLength); - - - static uint8_t vendor_line_state = 0;// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - static cdc_line_coding_t vendor_line_coding; - bool result = false; - - if(request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE && request->bRequest == 0x0b){ - if(stage == CONTROL_STAGE_SETUP) { - // response with status OK - result = Vendor.sendResponse(rhport, request); - } else { - result = true; - } - } else if(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE){ - //Implement CDC Control Requests - switch (request->bRequest) { - - // CDC Set Line Coding - case CDC_REQUEST_SET_LINE_CODING: //0x20 - if(request->wLength != sizeof(cdc_line_coding_t) || request->bmRequestType_bit.direction != TUSB_DIR_OUT){ - break; - } - if(stage == CONTROL_STAGE_SETUP) { - //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage) - result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(cdc_line_coding_t)); - } else if(stage == CONTROL_STAGE_ACK){ - //In the ACK stage the requst->response is complete - HWSerial.printf("Vendor Line Coding: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", vendor_line_coding.bit_rate, vendor_line_coding.data_bits, vendor_line_coding.stop_bits, vendor_line_coding.parity); - } - result = true; - break; +static const char * strRequestDirections[] = {"OUT", "IN"}; +static const char * strRequestTypes[] = {"STANDARD", "CLASS", "VENDOR", "INVALID"}; +static const char * strRequestRecipients[] = {"DEVICE", "INTERFACE", "ENDPOINT", "OTHER"}; +static const char * strRequestStages[] = {"SETUP", "DATA", "ACK"}; + +//Handle USB requests to the vendor interface +bool vendorRequestCallback(uint8_t rhport, uint8_t requestStage, arduino_usb_control_request_t const * request) { + HWSerial.printf("Vendor Request: Stage: %5s, Direction: %3s, Type: %8s, Recipient: %9s, bRequest: 0x%02x, wValue: 0x%04x, wIndex: %u, wLength: %u\n", + strRequestStages[requestStage], + strRequestDirections[request->bmRequestDirection], + strRequestTypes[request->bmRequestType], + strRequestRecipients[request->bmRequestRecipient], + request->bRequest, request->wValue, request->wIndex, request->wLength); - // CDC Get Line Coding - case CDC_REQUEST_GET_LINE_CODING: //0x21 - if(request->wLength != sizeof(cdc_line_coding_t) || request->bmRequestType_bit.direction != TUSB_DIR_IN){ - break; - } - if(stage == CONTROL_STAGE_SETUP) { - result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(cdc_line_coding_t)); - } - result = true; + bool result = false; + + if (request->bmRequestDirection == REQUEST_DIRECTION_OUT && + request->bmRequestType == REQUEST_TYPE_STANDARD && + request->bmRequestRecipient == REQUEST_RECIPIENT_INTERFACE && + request->bRequest == 0x0b + ) { + if (requestStage == REQUEST_STAGE_SETUP) { + // response with status OK + result = Vendor.sendResponse(rhport, request); + } else { + result = true; + } + } else + //Implement CDC Control Requests + if (request->bmRequestType == REQUEST_TYPE_CLASS && request->bmRequestRecipient == REQUEST_RECIPIENT_DEVICE) { + switch (request->bRequest) { + + case REQUEST_SET_LINE_CODING: //0x20 + // Accept only direction OUT with data size 7 + if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_OUT) { break; + } + if (requestStage == REQUEST_STAGE_SETUP) { + //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage) + result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(request_line_coding_t)); + } else if (requestStage == REQUEST_STAGE_ACK) { + //In the ACK stage the response is complete + HWSerial.printf("Vendor Line Coding: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", vendor_line_coding.bit_rate, vendor_line_coding.data_bits, vendor_line_coding.stop_bits, vendor_line_coding.parity); + } + result = true; + break; - // CDC Set Line State - case CDC_REQUEST_SET_CONTROL_LINE_STATE: //0x22 - if(request->wLength != 0 || request->bmRequestType_bit.direction != TUSB_DIR_OUT){ - break; - } - if(stage == CONTROL_STAGE_SETUP) { - vendor_line_state = request->wValue; - result = Vendor.sendResponse(rhport, request); - } else if(stage == CONTROL_STAGE_ACK){ - bool dtr = tu_bit_test(vendor_line_state, 0); - bool rts = tu_bit_test(vendor_line_state, 1); - HWSerial.printf("Vendor Line State: dtr: %u, rts: %u\n", dtr, rts); - } - result = true; + case REQUEST_GET_LINE_CODING: //0x21 + // Accept only direction IN with data size 7 + if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_IN) { break; + } + if (requestStage == REQUEST_STAGE_SETUP) { + //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage) + result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(request_line_coding_t)); + } + result = true; + break; - default: - // stall unknown request + case REQUEST_SET_CONTROL_LINE_STATE: //0x22 + // Accept only direction OUT with data size 0 + if (request->wLength != 0 || request->bmRequestDirection != REQUEST_DIRECTION_OUT) { break; - } + } + if (requestStage == REQUEST_STAGE_SETUP) { + //Send the response in setup stage + vendor_line_state = request->wValue; + result = Vendor.sendResponse(rhport, request); + } else if (requestStage == REQUEST_STAGE_ACK) { + //In the ACK stage the response is complete + bool dtr = (vendor_line_state & 1) != 0; + bool rts = (vendor_line_state & 2) != 0; + HWSerial.printf("Vendor Line State: dtr: %u, rts: %u\n", dtr, rts); + } + result = true; + break; + + default: + // stall unknown request + break; + } } - return result; + return result; } void setup() { pinMode(buttonPin, INPUT_PULLUP); HWSerial.begin(115200); HWSerial.setDebugOutput(true); - + Vendor.onEvent(usbEventCallback); Vendor.onRequest(vendorRequestCallback); Vendor.begin(); - + USB.onEvent(usbEventCallback); USB.webUSB(true); USB.webUSBURL("http://localhost/webusb"); @@ -143,6 +168,7 @@ void setup() { } void loop() { + static int previousButtonState = HIGH; int buttonState = digitalRead(buttonPin); if (buttonState != previousButtonState) { previousButtonState = buttonState; @@ -155,11 +181,11 @@ void loop() { } delay(100); } - - while(HWSerial.available()){ + + while (HWSerial.available()) { size_t l = HWSerial.available(); uint8_t b[l]; l = HWSerial.read(b, l); - Vendor.write(b,l); + Vendor.write(b, l); } } diff --git a/libraries/USB/src/USBVendor.cpp b/libraries/USB/src/USBVendor.cpp index 26a75c547fa..0a91fac9354 100644 --- a/libraries/USB/src/USBVendor.cpp +++ b/libraries/USB/src/USBVendor.cpp @@ -21,6 +21,10 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_VENDOR_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); +static USBVendor * _Vendor = NULL; +static xQueueHandle rx_queue = NULL; +static uint8_t USB_VENDOR_ENDPOINT_SIZE = 64; + uint16_t tusb_vendor_load_descriptor(uint8_t * dst, uint8_t * itf) { uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Vendor"); @@ -28,16 +32,13 @@ uint16_t tusb_vendor_load_descriptor(uint8_t * dst, uint8_t * itf) TU_VERIFY (ep_num != 0); uint8_t descriptor[TUD_VENDOR_DESC_LEN] = { // Interface number, string index, EP Out & IN address, EP size - TUD_VENDOR_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) + TUD_VENDOR_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), USB_VENDOR_ENDPOINT_SIZE) }; *itf+=1; memcpy(dst, descriptor, TUD_VENDOR_DESC_LEN); return TUD_VENDOR_DESC_LEN; } -static USBVendor * _Vendor = NULL; -static xQueueHandle rx_queue = NULL; - void tud_vendor_rx_cb(uint8_t itf){ log_v("%u", len); size_t len = tud_vendor_n_available(itf); @@ -62,15 +63,21 @@ extern "C" bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, request->bRequest, request->wValue, request->wIndex, request->wLength); if(_Vendor) { - return _Vendor->_onRequest(rhport, stage, request); + return _Vendor->_onRequest(rhport, stage, (arduino_usb_control_request_t const *)request); } return false; } -USBVendor::USBVendor():itf(0), cb(NULL){ +USBVendor::USBVendor(uint8_t endpoint_size):itf(0), cb(NULL){ if(!_Vendor){ _Vendor = this; + if(endpoint_size <= 64){ + USB_VENDOR_ENDPOINT_SIZE = endpoint_size; + } tinyusb_enable_interface(USB_INTERFACE_VENDOR, TUD_VENDOR_DESC_LEN, tusb_vendor_load_descriptor); + } else { + itf = _Vendor->itf; + cb = _Vendor->cb; } } @@ -109,14 +116,14 @@ bool USBVendor::mounted(){ return tud_vendor_n_mounted(itf); } -bool USBVendor::sendResponse(uint8_t rhport, tusb_control_request_t const * request, void * data, size_t len){ +bool USBVendor::sendResponse(uint8_t rhport, arduino_usb_control_request_t const * request, void * data, size_t len){ if(!request){ return false; } if(!data || !len){ - return tud_control_status(rhport, request); + return tud_control_status(rhport, (tusb_control_request_t const *)request); } else { - return tud_control_xfer(rhport, request, data, len); + return tud_control_xfer(rhport, (tusb_control_request_t const *)request, data, len); } } @@ -124,7 +131,7 @@ void USBVendor::onRequest(arduino_usb_vendor_control_request_handler_t handler){ cb = handler; } -bool USBVendor::_onRequest(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ +bool USBVendor::_onRequest(uint8_t rhport, uint8_t stage, arduino_usb_control_request_t const * request){ if(cb){ return cb(rhport, stage, request); } diff --git a/libraries/USB/src/USBVendor.h b/libraries/USB/src/USBVendor.h index b641fd9de31..2016a76a790 100644 --- a/libraries/USB/src/USBVendor.h +++ b/libraries/USB/src/USBVendor.h @@ -18,10 +18,38 @@ #if CONFIG_TINYUSB_VENDOR_ENABLED #include "esp_event.h" -#include "common/tusb_common.h" ESP_EVENT_DECLARE_BASE(ARDUINO_USB_VENDOR_EVENTS); +#define REQUEST_STAGE_SETUP 0 +#define REQUEST_STAGE_DATA 1 +#define REQUEST_STAGE_ACK 2 + +#define REQUEST_TYPE_STANDARD 0 +#define REQUEST_TYPE_CLASS 1 +#define REQUEST_TYPE_VENDOR 2 +#define REQUEST_TYPE_INVALID 3 + +#define REQUEST_RECIPIENT_DEVICE 0 +#define REQUEST_RECIPIENT_INTERFACE 1 +#define REQUEST_RECIPIENT_ENDPOINT 2 +#define REQUEST_RECIPIENT_OTHER 3 + +#define REQUEST_DIRECTION_OUT 0 +#define REQUEST_DIRECTION_IN 1 + +typedef struct __attribute__ ((packed)) { + struct __attribute__ ((packed)) { + uint8_t bmRequestRecipient : 5; + uint8_t bmRequestType : 2; + uint8_t bmRequestDirection : 1; + }; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} arduino_usb_control_request_t; + typedef enum { ARDUINO_USB_VENDOR_ANY_EVENT = ESP_EVENT_ANY_ID, ARDUINO_USB_VENDOR_DATA_EVENT, @@ -34,14 +62,14 @@ typedef union { } data; } arduino_usb_vendor_event_data_t; -typedef bool (*arduino_usb_vendor_control_request_handler_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +typedef bool (*arduino_usb_vendor_control_request_handler_t)(uint8_t rhport, uint8_t stage, arduino_usb_control_request_t const * request); class USBVendor: public Stream { private: uint8_t itf; arduino_usb_vendor_control_request_handler_t cb; public: - USBVendor(); + USBVendor(uint8_t endpoint_size=64); void begin(void); void end(void); size_t setRxBufferSize(size_t); @@ -57,9 +85,9 @@ class USBVendor: public Stream { void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_vendor_event_t event, esp_event_handler_t callback); void onRequest(arduino_usb_vendor_control_request_handler_t handler); - bool sendResponse(uint8_t rhport, tusb_control_request_t const * request, void * data=NULL, size_t len=0); + bool sendResponse(uint8_t rhport, arduino_usb_control_request_t const * request, void * data=NULL, size_t len=0); - bool _onRequest(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + bool _onRequest(uint8_t rhport, uint8_t stage, arduino_usb_control_request_t const * request); void _onRX(const uint8_t* buffer, size_t len); }; From bae30affc092a987b7db494096e8cb3a7ab84610 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Mon, 23 Aug 2021 15:37:01 +0300 Subject: [PATCH 17/17] Convert tabs to spaces --- libraries/USB/src/USBHIDConsumerControl.cpp | 10 +++++----- libraries/USB/src/USBHIDGamepad.cpp | 10 +++++----- libraries/USB/src/USBHIDMouse.cpp | 10 +++++----- libraries/USB/src/USBHIDSystemControl.cpp | 10 +++++----- libraries/USB/src/USBHIDVendor.cpp | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/libraries/USB/src/USBHIDConsumerControl.cpp b/libraries/USB/src/USBHIDConsumerControl.cpp index 7977fdd1f24..b1863dee3f3 100644 --- a/libraries/USB/src/USBHIDConsumerControl.cpp +++ b/libraries/USB/src/USBHIDConsumerControl.cpp @@ -22,11 +22,11 @@ static const uint8_t report_descriptor[] = { }; USBHIDConsumerControl::USBHIDConsumerControl(): hid(){ - static bool initialized = false; - if(!initialized){ - initialized = true; - hid.addDevice(this, sizeof(report_descriptor)); - } + static bool initialized = false; + if(!initialized){ + initialized = true; + hid.addDevice(this, sizeof(report_descriptor)); + } } uint16_t USBHIDConsumerControl::_onGetDescriptor(uint8_t* dst){ diff --git a/libraries/USB/src/USBHIDGamepad.cpp b/libraries/USB/src/USBHIDGamepad.cpp index 57a2f028356..9ddf67f4a99 100644 --- a/libraries/USB/src/USBHIDGamepad.cpp +++ b/libraries/USB/src/USBHIDGamepad.cpp @@ -22,11 +22,11 @@ static const uint8_t report_descriptor[] = { }; USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){ - static bool initialized = false; - if(!initialized){ - initialized = true; - hid.addDevice(this, sizeof(report_descriptor)); - } + static bool initialized = false; + if(!initialized){ + initialized = true; + hid.addDevice(this, sizeof(report_descriptor)); + } } uint16_t USBHIDGamepad::_onGetDescriptor(uint8_t* dst){ diff --git a/libraries/USB/src/USBHIDMouse.cpp b/libraries/USB/src/USBHIDMouse.cpp index 92efd617661..30b802a4607 100644 --- a/libraries/USB/src/USBHIDMouse.cpp +++ b/libraries/USB/src/USBHIDMouse.cpp @@ -29,11 +29,11 @@ static const uint8_t report_descriptor[] = { }; USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){ - static bool initialized = false; - if(!initialized){ - initialized = true; - hid.addDevice(this, sizeof(report_descriptor)); - } + static bool initialized = false; + if(!initialized){ + initialized = true; + hid.addDevice(this, sizeof(report_descriptor)); + } } uint16_t USBHIDMouse::_onGetDescriptor(uint8_t* dst){ diff --git a/libraries/USB/src/USBHIDSystemControl.cpp b/libraries/USB/src/USBHIDSystemControl.cpp index 6bd165619d9..93ef897fd69 100644 --- a/libraries/USB/src/USBHIDSystemControl.cpp +++ b/libraries/USB/src/USBHIDSystemControl.cpp @@ -22,11 +22,11 @@ static const uint8_t report_descriptor[] = { }; USBHIDSystemControl::USBHIDSystemControl(): hid(){ - static bool initialized = false; - if(!initialized){ - initialized = true; - hid.addDevice(this, sizeof(report_descriptor)); - } + static bool initialized = false; + if(!initialized){ + initialized = true; + hid.addDevice(this, sizeof(report_descriptor)); + } } uint16_t USBHIDSystemControl::_onGetDescriptor(uint8_t* dst){ diff --git a/libraries/USB/src/USBHIDVendor.cpp b/libraries/USB/src/USBHIDVendor.cpp index 0a6495abe71..53b0e999d44 100644 --- a/libraries/USB/src/USBHIDVendor.cpp +++ b/libraries/USB/src/USBHIDVendor.cpp @@ -63,16 +63,16 @@ static xQueueHandle rx_queue = NULL; static bool prepend_size = false; USBHIDVendor::USBHIDVendor(uint8_t report_size, bool prepend): hid(){ - static bool initialized = false; - if(!initialized){ - initialized = true; - hid.addDevice(this, TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN); + static bool initialized = false; + if(!initialized){ + initialized = true; + hid.addDevice(this, TUD_HID_REPORT_DESC_GENERIC_INOUT_FEATURE_LEN); memset(feature, 0, 64); if(report_size < 64){ HID_VENDOR_REPORT_SIZE = report_size; } prepend_size = prepend; - } + } } uint16_t USBHIDVendor::_onGetDescriptor(uint8_t* dst){