Updated RawHID, added Event function

Found a comprimiss between interrupt processing, prebuffering and processing long data inputs as well.
This commit is contained in:
NicoHood 2015-11-06 21:04:40 +01:00
parent 7310ae9298
commit b626e00b9a
5 changed files with 112 additions and 60 deletions

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;