commit
df98686d03
26 changed files with 473 additions and 264 deletions
10
Readme.md
10
Readme.md
|
|
@ -1,5 +1,5 @@
|
|||
Arduino HID Project 2.4
|
||||
=======================
|
||||
Arduino HID Project 2.4.1
|
||||
=========================
|
||||
|
||||

|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -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<CHIPSET, LED_PINS, COLOR_ORDER>(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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
71
examples/RawHID/RawHID/RawHID.ino
Normal file
71
examples/RawHID/RawHID/RawHID.ino
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
92
examples/RawHID/RawHIDPaintpack/RawHIDPaintpack.ino
Normal file
92
examples/RawHID/RawHIDPaintpack/RawHIDPaintpack.ino
Normal file
|
|
@ -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<CHIPSET, LED_PINS, COLOR_ORDER>(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);
|
||||
}
|
||||
}
|
||||
44
extras/ArduinoRawHID.rules
Normal file
44
extras/ArduinoRawHID.rules
Normal file
|
|
@ -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"
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
keywords.txt
15
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
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
name=HID-Project
|
||||
version=2.4
|
||||
version=2.4.1
|
||||
author=NicoHood
|
||||
maintainer=NicoHood <blog@NicoHood.de>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <Arduino.h>
|
||||
|
||||
#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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue