diff --git a/examples/RawHID/RawHID.ino b/examples/RawHID/RawHID.ino index 24677ce..0ab8c45 100644 --- a/examples/RawHID/RawHID.ino +++ b/examples/RawHID/RawHID.ino @@ -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(); - } - } -} - diff --git a/src/SingleReport/RawHID.cpp b/src/SingleReport/RawHID.cpp index 2f81830..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(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; 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;