diff --git a/.development b/.development deleted file mode 100644 index e69de29..0000000 diff --git a/Readme.md b/Readme.md index 84ac634..34c0fc3 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ -Arduino HID Project 2.4 -======================= +Arduino HID Project 2.4.1 +========================= ![Header Picture](header.jpg) @@ -49,6 +49,12 @@ www.nicohood.de Version History =============== ``` +2.4.1 Release (19.12.2015) +* RawHID Improvements +* Added Keyboard Feature Report +* NKRO and Keyboard API fixes +* Arduino library manager fix + 2.4 Release (06.11.2015) * Added Arduino IDE 1.6.6 compatibility with Pluggable HID * Improved Pluggable HID (see Arduyuino changelog for my improvements) diff --git a/examples/BootKeyboard/BootKeyboard.ino b/examples/Keyboard/BootKeyboard/BootKeyboard.ino similarity index 100% rename from examples/BootKeyboard/BootKeyboard.ino rename to examples/Keyboard/BootKeyboard/BootKeyboard.ino diff --git a/examples/ImprovedKeyboard/ImprovedKeyboard.ino b/examples/Keyboard/ImprovedKeyboard/ImprovedKeyboard.ino similarity index 100% rename from examples/ImprovedKeyboard/ImprovedKeyboard.ino rename to examples/Keyboard/ImprovedKeyboard/ImprovedKeyboard.ino diff --git a/examples/KeyboardLed/KeyboardLed.ino b/examples/Keyboard/KeyboardLed/KeyboardLed.ino similarity index 100% rename from examples/KeyboardLed/KeyboardLed.ino rename to examples/Keyboard/KeyboardLed/KeyboardLed.ino diff --git a/examples/NKROKeyboard/NKROKeyboard.ino b/examples/Keyboard/NKROKeyboard/NKROKeyboard.ino similarity index 74% rename from examples/NKROKeyboard/NKROKeyboard.ino rename to examples/Keyboard/NKROKeyboard/NKROKeyboard.ino index aae4d13..9381ffc 100644 --- a/examples/NKROKeyboard/NKROKeyboard.ino +++ b/examples/Keyboard/NKROKeyboard/NKROKeyboard.ino @@ -35,17 +35,17 @@ void loop() { // Do not press to many at once or some OS will have problems. // Note that the resulting pressed order might differ, // because all keys are pressed at the same time. - NKROKeyboard.addKeyToReport('0'); - NKROKeyboard.addKeyToReport('1'); - NKROKeyboard.addKeyToReport('2'); - NKROKeyboard.addKeyToReport('3'); - NKROKeyboard.addKeyToReport('4'); - NKROKeyboard.addKeyToReport('5'); - NKROKeyboard.addKeyToReport('6'); - NKROKeyboard.addKeyToReport('7'); - NKROKeyboard.addKeyToReport('8'); - NKROKeyboard.addKeyToReport('9'); - NKROKeyboard.send_now(); + NKROKeyboard.add('0'); + NKROKeyboard.add('1'); + NKROKeyboard.add('2'); + NKROKeyboard.add('3'); + NKROKeyboard.add('4'); + NKROKeyboard.add('5'); + NKROKeyboard.add('6'); + NKROKeyboard.add('7'); + NKROKeyboard.add('8'); + NKROKeyboard.add('9'); + NKROKeyboard.send(); // Release all keys and hit enter NKROKeyboard.releaseAll(); diff --git a/examples/TeensyKeyboard/TeensyKeyboard.ino b/examples/Keyboard/TeensyKeyboard/TeensyKeyboard.ino similarity index 100% rename from examples/TeensyKeyboard/TeensyKeyboard.ino rename to examples/Keyboard/TeensyKeyboard/TeensyKeyboard.ino diff --git a/examples/AbsoluteMouse/AbsoluteMouse.ino b/examples/Mouse/AbsoluteMouse/AbsoluteMouse.ino similarity index 100% rename from examples/AbsoluteMouse/AbsoluteMouse.ino rename to examples/Mouse/AbsoluteMouse/AbsoluteMouse.ino diff --git a/examples/ImprovedMouse/ImprovedMouse.ino b/examples/Mouse/ImprovedMouse/ImprovedMouse.ino similarity index 100% rename from examples/ImprovedMouse/ImprovedMouse.ino rename to examples/Mouse/ImprovedMouse/ImprovedMouse.ino diff --git a/examples/RawHID/KeyboardFeatureReport/KeyboardFeatureReport.ino b/examples/RawHID/KeyboardFeatureReport/KeyboardFeatureReport.ino new file mode 100644 index 0000000..5946924 --- /dev/null +++ b/examples/RawHID/KeyboardFeatureReport/KeyboardFeatureReport.ino @@ -0,0 +1,84 @@ +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + KeyboardFeatureReport example + + Shows how to use BootKeyboard with a modified Hyperion Lightpack device. + This example also works with RawHID. + Might only work under linux. + https://github.com/tvdzwan/hyperion/pull/407 + https://github.com/tvdzwan/hyperion/wiki + https://github.com/FastLED/FastLED + + See HID Project documentation for more information. + https://github.com/NicoHood/HID/wiki/RawHID-API + https://github.com/NicoHood/HID/wiki/Keyboard-API#boot-keyboard +*/ + +#include "HID-Project.h" + +const int pinLed = LED_BUILTIN; + + +// FastLED +#include "FastLED.h" + +#define LED_PINS MOSI, SCK // DATA_PIN, or DATA_PIN, CLOCK_PIN +#define COLOR_ORDER RGB +#define CHIPSET WS2801 // WS2811, LPD8806, etc +#define NUM_LEDS 25 + +#define BRIGHTNESS 255 // Reduce power consumption +#define LED_DITHER 255 // Try 0 to disable flickering +#define CORRECTION TypicalLEDStrip + +CRGB leds[NUM_LEDS]; // Define the array of leds + +void setup() { + // FastLED setup + FastLED.addLeds(leds, NUM_LEDS).setCorrection(CORRECTION); + FastLED.setBrightness(BRIGHTNESS); + FastLED.setDither(LED_DITHER); + + // Startup animation + fill_solid(leds, NUM_LEDS, CRGB::Red); + FastLED.show(); + delay(500); + fill_solid(leds, NUM_LEDS, CRGB::Green); + FastLED.show(); + delay(500); + fill_solid(leds, NUM_LEDS, CRGB::Blue); + FastLED.show(); + delay(500); + FastLED.clear(); + FastLED.show(); + + pinMode(pinLed, OUTPUT); + + // Sends a clean report to the host. This is important on any Arduino type. + BootKeyboard.begin(); + + // Let the feature report data directly point at the led array + BootKeyboard.setFeatureReport(leds, sizeof(leds)); + BootKeyboard.enableFeatureReport(); +} + +void loop() { + // Check if there is new feature request data from the keyboard + if (BootKeyboard.availableFeatureReport()) + { + digitalWrite(pinLed, HIGH); + + // Update leds, do not update in the loop, to avoid corrupted data. + // For example if you write (0, 0, 0) and the interrupt + // changes the data to (255, 255, 255) you might get (0, 255, 255). + // Using a duplicated led array in cli() context would also work. + FastLED.show(); + + // Release data to let the USB interrupt overwrite it again + BootKeyboard.enableFeatureReport(); + + digitalWrite(pinLed, LOW); + } +} diff --git a/examples/RawHID/RawHID.ino b/examples/RawHID/RawHID.ino deleted file mode 100644 index 04ff209..0000000 --- a/examples/RawHID/RawHID.ino +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright (c) 2014-2015 NicoHood - See the readme for credit to other people. - - Advanced RawHID example - - Shows how to send bytes via RawHID. - Press a button to send some example values. - - Every received data is mirrored to the host. - The use of the RawHIDEvent() function is shown too. - - This sketch only tries to show the possiblities - and is not perfect.You might want to use RawHID differently. - - See HID Project documentation for more information. - https://github.com/NicoHood/HID/wiki/RawHID-API -*/ - -#include "HID-Project.h" - -const int pinLed = LED_BUILTIN; -const int pinButton = 2; - -uint8_t data[255]; -volatile size_t len = 0; - -void setup() { - pinMode(pinLed, OUTPUT); - pinMode(pinButton, INPUT_PULLUP); - - // No begin/end function required for RawHID -} - -void loop() { - // Send data to the host - if (!digitalRead(pinButton)) { - digitalWrite(pinLed, HIGH); - - // Create buffer with numbers and send it - uint8_t megabuff[100]; - for (uint8_t i = 0; i < sizeof(megabuff); i++) { - megabuff[i] = i; - } - RawHID.write(megabuff, sizeof(megabuff)); - - // Simple debounce - delay(300); - digitalWrite(pinLed, LOW); - } - - - // This will miss longer RawHID data transmissions - // and return an error to the host if data was missed. - // Only use this for non changing/less important data. - // Or you can use this if the event aborted on a full buffer. - // Please note, that all data after this full buffer is missed anyways. - auto bytesAvailable = RawHID.available(); - while (bytesAvailable--) { - if (len < sizeof(data)) { - data[len++] = RawHID.read(); - } - } - - // Process data from the host - if (len) { - digitalWrite(pinLed, HIGH); - - // Disable interrupts while processing the data - uint8_t oldSREG = SREG; - cli(); - - // Mirror the incoming data from the host back - RawHID.write(data, len); - len = 0; - - SREG = oldSREG; - - // Simple debounce for led - delay(300); - digitalWrite(pinLed, LOW); - } -} - -void RawHIDEvent(void) { - // This event is called via interrupt. - // Do not use print inside, or other long function calls! - // If you not use this event function, - // you might miss some data in the loop, - // if the host sends too fast or too much data at once. - - auto bytesAvailable = RawHID.available(); - while (bytesAvailable--) { - // Only add data to the buffer if its not full. - // If it is, no more event will occur - // and the data should be discarded - // or read (as shown) in the loop above. - if (len < sizeof(data)) { - data[len++] = RawHID.read(); - } - } -} - diff --git a/examples/RawHID/RawHID/RawHID.ino b/examples/RawHID/RawHID/RawHID.ino new file mode 100644 index 0000000..0ab8c45 --- /dev/null +++ b/examples/RawHID/RawHID/RawHID.ino @@ -0,0 +1,71 @@ +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + Advanced RawHID example + + Shows how to send bytes via RawHID. + Press a button to send some example values. + + Every received data is mirrored to the host via Serial. + + See HID Project documentation for more information. + https://github.com/NicoHood/HID/wiki/RawHID-API +*/ + +#include "HID-Project.h" + +const int pinLed = LED_BUILTIN; +const int pinButton = 2; + +// Buffer to hold RawHID data. +// If host tries to send more data than this, +// it will respond with an error. +// If the data is not read until the host sends the next data +// it will also respond with an error and the data will be lost. +uint8_t rawhidData[255]; + +void setup() { + pinMode(pinLed, OUTPUT); + pinMode(pinButton, INPUT_PULLUP); + + Serial.begin(115200); + + // Set the RawHID OUT report array. + // Feature reports are also (parallel) possible, see the other example for this. + RawHID.begin(rawhidData, sizeof(rawhidData)); +} + +void loop() { + // Send data to the host + if (!digitalRead(pinButton)) { + digitalWrite(pinLed, HIGH); + + // Create buffer with numbers and send it + uint8_t megabuff[100]; + for (uint8_t i = 0; i < sizeof(megabuff); i++) { + megabuff[i] = i; + } + RawHID.write(megabuff, sizeof(megabuff)); + + // Simple debounce + delay(300); + digitalWrite(pinLed, LOW); + } + + + // Check if there is new data from the RawHID device + auto bytesAvailable = RawHID.available(); + if (bytesAvailable) + { + digitalWrite(pinLed, HIGH); + + // Mirror data via Serial + while (bytesAvailable--) { + Serial.println(RawHID.read()); + } + + digitalWrite(pinLed, LOW); + } +} + diff --git a/examples/RawHID/RawHIDPaintpack/RawHIDPaintpack.ino b/examples/RawHID/RawHIDPaintpack/RawHIDPaintpack.ino new file mode 100644 index 0000000..40e540d --- /dev/null +++ b/examples/RawHID/RawHIDPaintpack/RawHIDPaintpack.ino @@ -0,0 +1,92 @@ +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + RawHIDPaintpack example + + Shows how to use RawHID with the Hyperion Lightpack device. + https://github.com/tvdzwan/hyperion/wiki + https://github.com/FastLED/FastLED + + See HID Project documentation for more information. + https://github.com/NicoHood/HID/wiki/RawHID-API + https://github.com/NicoHood/HID/wiki/Keyboard-API#boot-keyboard +*/ + +#include "HID-Project.h" + +const int pinLed = LED_BUILTIN; + + +// FastLED +#include "FastLED.h" + +#define LED_PINS MOSI, SCK // DATA_PIN, or DATA_PIN, CLOCK_PIN +#define COLOR_ORDER RGB +#define CHIPSET WS2801 // WS2811, LPD8806, etc +#define NUM_LEDS 25 + +#define BRIGHTNESS 255 // Reduce power consumption +#define LED_DITHER 255 // Try 0 to disable flickering +#define CORRECTION TypicalLEDStrip + +CRGB leds[NUM_LEDS]; // Define the array of leds +uint8_t rawhidData[sizeof(leds) + 2]; + +void setup() { + // FastLED setup + FastLED.addLeds(leds, NUM_LEDS).setCorrection(CORRECTION); + FastLED.setBrightness(BRIGHTNESS); + FastLED.setDither(LED_DITHER); + + // Startup animation + fill_solid(leds, NUM_LEDS, CRGB::Red); + FastLED.show(); + delay(500); + fill_solid(leds, NUM_LEDS, CRGB::Green); + FastLED.show(); + delay(500); + fill_solid(leds, NUM_LEDS, CRGB::Blue); + FastLED.show(); + delay(500); + FastLED.clear(); + FastLED.show(); + + pinMode(pinLed, OUTPUT); + + // Set the RawHID OUT report array. + // Feature reports are also (parallel) possible, see the other example for this. + RawHID.begin(rawhidData, sizeof(rawhidData)); +} + +void loop() { + // Check if there is new data from the RawHID device + auto bytesAvailable = RawHID.available(); + if (bytesAvailable == sizeof(rawhidData)) + { + digitalWrite(pinLed, HIGH); + + // Check header for errors + if (RawHID.read() != 3) { + return; + } + if (RawHID.read() != 0) { + return; + } + + // Write data to led array + uint8_t* ptr = (uint8_t*)leds; + for (int i = 0; i < sizeof(leds); i++) { + *ptr = RawHID.read(); + ptr++; + } + + // Update leds, do not update in the loop, to avoid corrupted data. + // For example if you write (0, 0, 0) and the interrupt + // changes the data to (255, 255, 255) you might get (0, 255, 255). + // Using a duplicated led array in cli() context would also work. + FastLED.show(); + + digitalWrite(pinLed, LOW); + } +} diff --git a/extras/ArduinoRawHID.rules b/extras/ArduinoRawHID.rules new file mode 100644 index 0000000..5b29231 --- /dev/null +++ b/extras/ArduinoRawHID.rules @@ -0,0 +1,44 @@ +# Original taken and modified from: +# https://github.com/ihowson/Teensy-Raw-HID-in-Python/blob/master/teensy_loader_cli/49-teensy.rules +# +# This file must be placed at: +# +# /etc/udev/rules.d/ArduinoRawHID.rules (preferred location) +# or +# /lib/udev/rules.d/ArduinoRawHID.rules (req'd on some broken systems) +# +# SUBSYSTEMS=="usb", ATTRS{idVendor}=="0x2341", ATTRS{idProduct}=="0x8036", MODE:="0666" +# +# Reload udev rules: +# udevadm control --reload && udevadm trigger +# +# +# Arduino devices (leonardo only, or all Arduino devices): +#SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8036", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", MODE:="0666" +# +# +#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", MODE:="0666" +#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="8000", MODE:="0666" +#KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", SYMLINK+="ttyUSB00%n", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1" +# +# If you share your linux system with other users, or just don't like the +# idea of write permission for everybody, you can replace MODE:="0666" with +# OWNER:="yourusername" to create the device owned by you, or with +# GROUP:="somegroupname" and mange access using standard unix groups. +# +# +# If using USB Serial you get a new device each time (Ubuntu 9.10) +# eg: /dev/ttyACM0, ttyACM1, ttyACM2, ttyACM3, ttyACM4, etc +# apt-get remove --purge modemmanager (reboot may be necessary) +# +# +# Older modem proding (eg, Ubuntu 9.04) caused very slow serial device detection. +# To fix, add this near top of /lib/udev/rules.d/77-nm-probe-modem-capabilities.rules +# SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", GOTO="nm_modem_probe_end" +# +# +# (old udev rules) +#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="047[78]", MODE:="0666" +#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="048[02]", MODE:="0666" +#KERNEL=="ttyACM*", SYMLINK+="ttyUSB00%n", MODE:="0666" diff --git a/extras/rawhid/hid_LINUX.c b/extras/rawhid/hid_LINUX.c index 8e98113..799797e 100644 --- a/extras/rawhid/hid_LINUX.c +++ b/extras/rawhid/hid_LINUX.c @@ -144,7 +144,7 @@ int rawhid_send(int num, void *buf, int len, int timeout) if (hid->ep_out) { return usb_interrupt_write(hid->usb, hid->ep_out, buf, len, timeout); } else { - return usb_control_msg(hid->usb, 0x21, 9, 0, hid->iface, buf, len, timeout); + return usb_control_msg(hid->usb, 0x21, 9, 0x0200, hid->iface, buf, len, timeout); } } diff --git a/keywords.txt b/keywords.txt index a6e5bf0..873224a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,6 +13,8 @@ begin KEYWORD2 end KEYWORD2 press KEYWORD2 +add KEYWORD2 +remove KEYWORD2 release KEYWORD2 releaseAll KEYWORD2 @@ -22,13 +24,10 @@ moveTo KEYWORD2 isPressed KEYWORD2 getLeds KEYWORD2 -pressKeycode KEYWORD2 -releaseKeycode KEYWORD2 -writeKeycode KEYWORD2 -addKeyToReport KEYWORD2 -addKeycodeToReport KEYWORD2 -removeKeyFromReport KEYWORD2 -removeKeycodeFromReport KEYWORD2 +setFeatureReport KEYWORD2 +availableFeatureReport KEYWORD2 +enableFeatureReport KEYWORD2 +disableFeatureReport KEYWORD2 write_unicode KEYWORD2 set_modifier KEYWORD2 @@ -39,7 +38,7 @@ set_key4 KEYWORD2 set_key5 KEYWORD2 set_key6 KEYWORD2 set_media KEYWORD2 -send_now KEYWORD2 +send KEYWORD2 buttons KEYWORD2 xAxis KEYWORD2 diff --git a/library.properties b/library.properties index d984e65..0dd202d 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=HID-Project -version=2.4 +version=2.4.1 author=NicoHood maintainer=NicoHood sentence=Extended HID Functions for Arduino -paragraph=Includes Consumer, System and Gamepad. Also compatible with Arduino Uno/Mega via HoodLoader2. -category=Device Control +paragraph=Includes BootKeyboard/Mouse, Consumer, System, Gamepad, RawHID and more features. Also compatible with Arduino Uno/Mega via HoodLoader2. +category=Communication url=https://github.com/NicoHood/HID -architectures=* +architectures=avr dot_a_linkage=true diff --git a/package_NicoHood_HID_index.json b/package_NicoHood_HID_index.json deleted file mode 100644 index d172297..0000000 --- a/package_NicoHood_HID_index.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "packages": [ - { - "name": "HID", - "maintainer": "NicoHood", - "websiteURL": "https://github.com/NicoHood/HID", - "email": "", - "help": { - "online": "" - }, - "platforms": [ - { - "name": "HID Project", - "architecture": "avr", - "version": "2.2", - "category": "HID", - "help": { - "online": "" - }, - "url": "https://github.com/NicoHood/HID/releases/download/2.2/2.2-boards_manager.zip", - "archiveFileName": "2.2-boards_manager.zip", - "checksum": "SHA-256:9c86ee28a7ce9fe33e8b07ec643316131e0031b0d22e63bb398902a5fdadbca9", - "size": "351303", - "boards": [ - {"name": "Arduino Leonardo"}, - {"name": "Arduino Micro"} - ], - "toolsDependencies": [ - { - "packager": "arduino", - "name": "avr-gcc", - "version": "4.8.1-arduino5" - }, - { - "packager": "arduino", - "name": "avrdude", - "version": "6.0.1-arduino5" - } - ] - } - ], - "tools": [] - } - ] -} diff --git a/src/HID-Project.h b/src/HID-Project.h index 1e7414b..5393c34 100644 --- a/src/HID-Project.h +++ b/src/HID-Project.h @@ -25,13 +25,10 @@ THE SOFTWARE. #pragma once // Software version -#define HID_PROJECT_VERSION 240 +#define HID_PROJECT_VERSION 241 -// TODO remove https://github.com/arduino/arduino-builder/issues/33 -#include - -#if ARDUINO < 10606 -#error HID Project requires Arduino IDE 1.6.6 or greater. Please update your IDE. +#if ARDUINO < 10607 +#error HID Project requires Arduino IDE 1.6.7 or greater. Please update your IDE. #endif #if !defined(USBCON) diff --git a/src/MultiReport/ImprovedKeyboard.h b/src/MultiReport/ImprovedKeyboard.h index d9185cf..d59486c 100644 --- a/src/MultiReport/ImprovedKeyboard.h +++ b/src/MultiReport/ImprovedKeyboard.h @@ -37,8 +37,7 @@ public: Keyboard_(void); void wakeupHost(void); -protected: - virtual inline int send(void) override; + virtual inline int send(void) final; }; extern Keyboard_ Keyboard; diff --git a/src/MultiReport/NKROKeyboard.h b/src/MultiReport/NKROKeyboard.h index 933c127..ef5c9b4 100644 --- a/src/MultiReport/NKROKeyboard.h +++ b/src/MultiReport/NKROKeyboard.h @@ -36,8 +36,7 @@ class NKROKeyboard_ : public NKROKeyboardAPI public: NKROKeyboard_(void); -protected: - virtual inline int send(void) override; + virtual int send(void) final; }; extern NKROKeyboard_ NKROKeyboard; diff --git a/src/SingleReport/BootKeyboard.cpp b/src/SingleReport/BootKeyboard.cpp index debadb3..0261b41 100644 --- a/src/SingleReport/BootKeyboard.cpp +++ b/src/SingleReport/BootKeyboard.cpp @@ -71,7 +71,7 @@ static const uint8_t _hidReportDescriptorKeyboard[] PROGMEM = { 0xc0 /* END_COLLECTION */ }; -BootKeyboard_::BootKeyboard_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), leds(0) +BootKeyboard_::BootKeyboard_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), leds(0), featureReport(NULL), featureLength(0) { epType[0] = EP_TYPE_INTERRUPT_IN; PluggableUSB().plug(this); @@ -120,10 +120,12 @@ bool BootKeyboard_::setup(USBSetup& setup) return true; } if (request == HID_GET_PROTOCOL) { + // TODO improve UEDATX = protocol; return true; } if (request == HID_GET_IDLE) { + // TODO improve UEDATX = idle; return true; } @@ -141,10 +143,39 @@ bool BootKeyboard_::setup(USBSetup& setup) } if (request == HID_SET_REPORT) { - // Check if data has the correct length - auto length = setup.wLength; - if(length == sizeof(leds)){ - USB_RecvControl(&leds, length); + // Check if data has the correct length afterwards + int length = setup.wLength; + + // Feature (set feature report) + if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ + // No need to check for negative featureLength values, + // except the host tries to send more then 32k bytes. + // We dont have that much ram anyways. + if (length == featureLength) { + USB_RecvControl(featureReport, featureLength); + + // Block until data is read (make length negative) + disableFeatureReport(); + return true; + } + // TODO fake clear data? + } + + // Output (set led states) + else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){ + if(length == sizeof(leds)){ + USB_RecvControl(&leds, length); + return true; + } + } + + // Input (set HID report) + else if(setup.wValueH == HID_REPORT_TYPE_INPUT) + { + if(length == sizeof(_keyReport)){ + USB_RecvControl(&_keyReport, length); + return true; + } } } } diff --git a/src/SingleReport/BootKeyboard.h b/src/SingleReport/BootKeyboard.h index 4d83e72..cd28a8f 100644 --- a/src/SingleReport/BootKeyboard.h +++ b/src/SingleReport/BootKeyboard.h @@ -38,6 +38,33 @@ public: uint8_t getLeds(void); uint8_t getProtocol(void); void wakeupHost(void); + + void setFeatureReport(void* report, int length){ + if(length > 0){ + featureReport = (uint8_t*)report; + featureLength = length; + + // Disable feature report by default + disableFeatureReport(); + } + } + + int availableFeatureReport(void){ + if(featureLength < 0){ + return featureLength & ~0x8000; + } + return 0; + } + + void enableFeatureReport(void){ + featureLength &= ~0x8000; + } + + void disableFeatureReport(void){ + featureLength |= 0x8000; + } + + virtual int send(void) final; protected: // Implementation of the PUSBListNode @@ -51,7 +78,8 @@ protected: uint8_t leds; - virtual int send(void) override; + uint8_t* featureReport; + int featureLength; }; extern BootKeyboard_ BootKeyboard; diff --git a/src/SingleReport/RawHID.cpp b/src/SingleReport/RawHID.cpp index 3cafe96..d4aa4d1 100644 --- a/src/SingleReport/RawHID.cpp +++ b/src/SingleReport/RawHID.cpp @@ -47,13 +47,7 @@ static const uint8_t _hidReportDescriptorRawHID[] PROGMEM = { 0xC0 /* end collection */ }; -// Weak implementation of the Event function -void RawHIDEvent(void) __attribute__ ((weak)); -void RawHIDEvent(void){ - // Empty -} - -RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0) +RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0), dataAvailable(0), featureReport(NULL), featureLength(0) { epType[0] = EP_TYPE_INTERRUPT_IN; PluggableUSB().plug(this); @@ -120,50 +114,36 @@ bool RawHID_::setup(USBSetup& setup) } if (request == HID_SET_REPORT) { - // Get the data length information and the corresponding bytes + // Check if data has the correct length afterwards int length = setup.wLength; - while(length) - { - // Dont receive more than the USB EP has to offer - // TODO use fixed 64 because control EP always have 64 bytes even on 16 u2. Test! - auto recvLength = length; - if(recvLength > USB_EP_SIZE){ - recvLength = USB_EP_SIZE; - } - if(recvLength > int(sizeof(data))){ - recvLength = int(sizeof(data)); - } - length -= recvLength; - - // Only receive data if the last one was read fully. - // Discard data if it wasnt read yet. - // To not miss any data you can use the (weak) event function. - if(!dataLength) - { - // Write data to fit to the end (not the beginning) of the array - USB_RecvControl(data + (sizeof(data) - recvLength), recvLength); - dataLength = recvLength; - RawHIDEvent(); - } - // Do not read the data, flag an error to the USB Host - // TODO always return no error, even if data was discarded? -> use break then - else{ - return false; + + // Feature (set feature report) + if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ + // No need to check for negative featureLength values, + // except the host tries to send more then 32k bytes. + // We dont have that much ram anyways. + if (length == featureLength) { + USB_RecvControl(featureReport, featureLength); + + // Block until data is read (make length negative) + disableFeatureReport(); + return true; + } + } + + // Output (set out report) + else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){ + if(!dataAvailable && length <= dataLength){ + // Write data to fit to the end (not the beginning) of the array + USB_RecvControl(data + dataLength - length, length); + dataAvailable = length; + return true; } } - - // Flag no error - // TODO this is required to get hyperion working - // however this blocks the CDC serial!? - return true; } } return false; } -void RawHID_::SendReport(void* data, int length){ - USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length); -} - RawHID_ RawHID; diff --git a/src/SingleReport/RawHID.h b/src/SingleReport/RawHID.h index 5f2249c..9ccc43e 100644 --- a/src/SingleReport/RawHID.h +++ b/src/SingleReport/RawHID.h @@ -73,32 +73,73 @@ class RawHID_ : public PluggableUSBModule, public Stream public: RawHID_(void); - void begin(void){ - // empty + void setFeatureReport(void* report, int length){ + if(length > 0){ + featureReport = (uint8_t*)report; + featureLength = length; + + // Disable feature report by default + disableFeatureReport(); + } + } + + int availableFeatureReport(void){ + if(featureLength < 0){ + return featureLength & ~0x8000; + } + return 0; + } + + void enableFeatureReport(void){ + featureLength &= ~0x8000; + } + + void disableFeatureReport(void){ + featureLength |= 0x8000; + } + + void begin(void* report, int length){ + if(length > 0){ + data = (uint8_t*)report; + dataLength = length; + dataAvailable = 0; + } } void end(void){ - // empty + disable(); + dataLength = 0; + } + + void enable(void){ + dataAvailable = 0; + } + + void disable(void){ + dataAvailable = -1; } virtual int available(void){ - return dataLength; + if(dataAvailable < 0){ + return 0; + } + return dataAvailable; } virtual int read(){ // Check if we have data available - if(dataLength) + if(dataAvailable > 0) { // Get next data byte (from the start to the end) - return data[sizeof(data) - dataLength--]; + return data[dataLength - dataAvailable--]; } return -1; } virtual int peek(){ // Check if we have data available - if(dataLength){ - return data[sizeof(data) - dataLength]; + if(dataAvailable > 0){ + return data[dataLength - dataAvailable]; } return -1; } @@ -114,27 +155,9 @@ public: } virtual size_t write(uint8_t *buffer, size_t size){ - // TODO this will split the data into proper USB_EP_SIZE packets already - SendReport(buffer, size); - return size; - - size_t bytesleft = size; - // First work through the buffer thats already there - while (bytesleft >= RAWHID_TX_SIZE){ - SendReport(&buffer[size - bytesleft], RAWHID_TX_SIZE); - bytesleft -= RAWHID_TX_SIZE; - } - - // Write down the leftover bytes and fill with zeros - if (bytesleft){ - SendReport(&buffer[size - bytesleft], bytesleft); - } - - return size; + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, buffer, size); } - void SendReport(void* data, int length); - protected: // Implementation of the PUSBListNode int getInterface(uint8_t* interfaceCount); @@ -147,7 +170,11 @@ protected: // Buffer pointers to hold the received data int dataLength; - uint8_t data[RAWHID_RX_SIZE]; + int dataAvailable; + uint8_t* data; + + uint8_t* featureReport; + int featureLength; }; extern RawHID_ RawHID; diff --git a/src/SingleReport/SingleNKROKeyboard.h b/src/SingleReport/SingleNKROKeyboard.h index 422a47b..d5f2ead 100644 --- a/src/SingleReport/SingleNKROKeyboard.h +++ b/src/SingleReport/SingleNKROKeyboard.h @@ -37,6 +37,8 @@ public: SingleNKROKeyboard_(void); uint8_t getLeds(void); uint8_t getProtocol(void); + + virtual int send(void) final; protected: // Implementation of the PUSBListNode @@ -49,8 +51,6 @@ protected: uint8_t idle; uint8_t leds; - - virtual inline int send(void) override; }; extern SingleNKROKeyboard_ SingleNKROKeyboard;