Updated RawHID with new, more intuitive API

This commit is contained in:
NicoHood 2015-11-08 20:05:53 +01:00
parent 626be84137
commit c197491272
3 changed files with 98 additions and 124 deletions

View file

@ -7,11 +7,7 @@
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.
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
@ -22,14 +18,22 @@
const int pinLed = LED_BUILTIN;
const int pinButton = 2;
uint8_t data[255];
volatile size_t len = 0;
// 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);
// No begin/end function required for RawHID
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() {
@ -50,54 +54,18 @@ void loop() {
}
// 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.
// Check if there is new data from the RawHID device
auto bytesAvailable = RawHID.available();
while (bytesAvailable--) {
if (len < sizeof(data)) {
data[len++] = RawHID.read();
}
}
// Process data from the host
if (len) {
if (bytesAvailable)
{
digitalWrite(pinLed, HIGH);
// Disable interrupts while processing the data
uint8_t oldSREG = SREG;
cli();
// Mirror data via Serial
while (bytesAvailable--) {
Serial.println(RawHID.read());
}
// 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(uint8_t num) {
// 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

@ -47,13 +47,7 @@ static const uint8_t _hidReportDescriptorRawHID[] PROGMEM = {
0xC0 /* end collection */
};
// Weak implementation of the Event function
void RawHIDEvent(uint8_t num) __attribute__ ((weak));
void RawHIDEvent(uint8_t num){
// 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,51 +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;
uint8_t num = 0;
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(num++);
}
// 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;

View file

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