Updated RawHID, added Event function
Found a comprimiss between interrupt processing, prebuffering and processing long data inputs as well.
This commit is contained in:
parent
7310ae9298
commit
b626e00b9a
5 changed files with 112 additions and 60 deletions
|
|
@ -7,6 +7,12 @@
|
|||
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
|
||||
*/
|
||||
|
|
@ -16,20 +22,26 @@
|
|||
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 function needed for RawHID
|
||||
|
||||
// No begin/end function required for RawHID
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Send data to the host
|
||||
if (!digitalRead(pinButton)) {
|
||||
digitalWrite(pinLed, HIGH);
|
||||
|
||||
// Create buffer and send it
|
||||
// Create buffer with numbers and send it
|
||||
uint8_t megabuff[100];
|
||||
for (int i = 0; i < sizeof(megabuff); i++)
|
||||
for (uint8_t i = 0; i < sizeof(megabuff); i++) {
|
||||
megabuff[i] = i;
|
||||
}
|
||||
RawHID.write(megabuff, sizeof(megabuff));
|
||||
|
||||
// Simple debounce
|
||||
|
|
@ -37,20 +49,55 @@ void loop() {
|
|||
digitalWrite(pinLed, LOW);
|
||||
}
|
||||
|
||||
uint8_t len = RawHID.available();
|
||||
|
||||
// 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);
|
||||
|
||||
// Mirror the incoming data from the host back
|
||||
uint8_t buff[len + 1];
|
||||
buff[0] = len;
|
||||
for (int i = 1; i < sizeof(buff); i++) {
|
||||
buff[i] = RawHID.read();
|
||||
}
|
||||
RawHID.write(buff, len);
|
||||
// Disable interrupts while processing the data
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
|
||||
// Simple debounce
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ THE SOFTWARE.
|
|||
// Software version
|
||||
#define HID_PROJECT_VERSION 240
|
||||
|
||||
// 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.
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ THE SOFTWARE.
|
|||
#ifndef HID_REPORTID_RAWHID
|
||||
// This will not work properly in most cases.
|
||||
// The number is just kept from the old number counting.
|
||||
#define HID_REPORTID_RAWHID 3
|
||||
//#define HID_REPORTID_RAWHID 3
|
||||
#endif
|
||||
|
||||
#ifndef HID_REPORTID_CONSUMERCONTROL
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ 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)
|
||||
{
|
||||
epType[0] = EP_TYPE_INTERRUPT_IN;
|
||||
|
|
@ -55,7 +61,6 @@ RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_P
|
|||
|
||||
int RawHID_::getInterface(uint8_t* interfaceCount)
|
||||
{
|
||||
// TODO add a 2nd OUT endpoint to get more speed???
|
||||
// Maybe as optional device FastRawHID with different USAGE PAGE
|
||||
*interfaceCount += 1; // uses 1
|
||||
HIDDescriptor hidInterface = {
|
||||
|
|
@ -117,36 +122,40 @@ bool RawHID_::setup(USBSetup& setup)
|
|||
{
|
||||
// Get the data length information and the corresponding bytes
|
||||
int length = setup.wLength;
|
||||
|
||||
// Ensure that there IS some data
|
||||
if(length > 0)
|
||||
while(length)
|
||||
{
|
||||
void* data = malloc(length);
|
||||
if(data){
|
||||
auto recvLength = length;
|
||||
//TODO loop can be improved maybe? Or does the compiler do this already?
|
||||
while(recvLength > USB_EP_SIZE){
|
||||
USB_RecvControl((uint8_t*)data + (length - recvLength), USB_EP_SIZE);
|
||||
recvLength -= USB_EP_SIZE;
|
||||
}
|
||||
USB_RecvControl((uint8_t*)data + (length - recvLength), recvLength);
|
||||
|
||||
// Only overwrite the buffer if its empty.
|
||||
// This avoids corrupted data while reading.
|
||||
if(!dataLength){
|
||||
// Save new data
|
||||
dataLength = length;
|
||||
dataHead = (uint8_t*) data;
|
||||
dataTail = (uint8_t*)(data) + length;
|
||||
|
||||
// Clear the passed in pointer to not free the data
|
||||
data = NULL;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Release data if the pointer still exists
|
||||
free(data);
|
||||
}
|
||||
|
||||
// Flag no error
|
||||
// TODO this is required to get hyperion working
|
||||
// however this blocks the CDC serial!?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ THE SOFTWARE.
|
|||
// Keep one byte offset for the reportID if used
|
||||
#if (HID_REPORTID_RAWHID)
|
||||
#define RAWHID_SIZE (USB_EP_SIZE-1)
|
||||
#error RAWHID does not work properly with a report ID and multiple reports.
|
||||
#error Please remove this manually if you know what you are doing.
|
||||
#else
|
||||
#define RAWHID_SIZE (USB_EP_SIZE)
|
||||
#endif
|
||||
|
|
@ -84,36 +86,28 @@ public:
|
|||
}
|
||||
|
||||
virtual int read(){
|
||||
if(dataLength){
|
||||
// Get next data byte
|
||||
uint8_t data = *(dataTail - dataLength);
|
||||
dataLength--;
|
||||
|
||||
// Release buffer if its read fully
|
||||
if(!dataLength){
|
||||
free(dataHead);
|
||||
}
|
||||
|
||||
return data;
|
||||
// Check if we have data available
|
||||
if(dataLength)
|
||||
{
|
||||
// Get next data byte (from the start to the end)
|
||||
return data[sizeof(data) - dataLength--];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual int peek(){
|
||||
// Check if we have data available
|
||||
if(dataLength){
|
||||
return *(dataTail - dataLength);
|
||||
return data[sizeof(data) - dataLength];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual void flush(void){
|
||||
// Delete all incoming bytes
|
||||
if(dataLength){
|
||||
free(dataHead);
|
||||
dataLength = 0;
|
||||
}
|
||||
// Writing will always flush by the USB driver
|
||||
}
|
||||
|
||||
// Wrapper for a single byte
|
||||
using Print::write;
|
||||
virtual size_t write(uint8_t b){
|
||||
return write(&b, 1);
|
||||
|
|
@ -153,8 +147,7 @@ protected:
|
|||
|
||||
// Buffer pointers to hold the received data
|
||||
int dataLength;
|
||||
uint8_t* dataHead;
|
||||
uint8_t* dataTail;
|
||||
uint8_t data[RAWHID_RX_SIZE];
|
||||
};
|
||||
extern RawHID_ RawHID;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue