diff --git a/src/SingleReport/RawHID.cpp b/src/SingleReport/RawHID.cpp new file mode 100644 index 0000000..7a4c9dd --- /dev/null +++ b/src/SingleReport/RawHID.cpp @@ -0,0 +1,125 @@ +/* +Copyright (c) 2014-2015 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "RawHID.h" + +static const uint8_t _hidReportDescriptorRawHID[] PROGMEM = { + /* RAW HID */ + 0x06, lowByte(RAWHID_USAGE_PAGE), highByte(RAWHID_USAGE_PAGE), /* 30 */ + 0x0A, lowByte(RAWHID_USAGE), highByte(RAWHID_USAGE), + + 0xA1, 0x01, /* Collection 0x01 */ + // RawHID is not multireport compatible. + // On Linux it might work with some modifications, + // however you are not happy to use it like that. + //0x85, HID_REPORTID_RAWHID, /* REPORT_ID */ + 0x75, 0x08, /* report size = 8 bits */ + 0x15, 0x00, /* logical minimum = 0 */ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ + + 0x95, RAWHID_TX_SIZE, /* report count TX */ + 0x09, 0x01, /* usage */ + 0x81, 0x02, /* Input (array) */ + + 0x95, RAWHID_RX_SIZE, /* report count RX */ + 0x09, 0x02, /* usage */ + 0x91, 0x02, /* Output (array) */ + 0xC0 /* end collection */ +}; + +RawHID_::RawHID_(void) : PUSBListNode(1, 1, epType), protocol(1), idle(1), dataLength(0) +{ + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int RawHID_::getInterface(uint8_t* interfaceCount) +{ + // TODO add a 2nd OUT endpoint to get more speed??? + // Maybe as optional device + *interfaceCount += 1; // uses 1 + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), + D_HIDREPORT(sizeof(_hidReportDescriptorRawHID)), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int RawHID_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + return USB_SendControl(TRANSFER_PGM, _hidReportDescriptorRawHID, sizeof(_hidReportDescriptorRawHID)); +} + +bool RawHID_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == HID_GET_REPORT) { + // TODO: HID_GetReport(); + return true; + } + if (request == HID_GET_PROTOCOL) { + // TODO: Send8(protocol); + return true; + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == HID_SET_PROTOCOL) { + protocol = setup.wValueL; + return true; + } + if (request == HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == HID_SET_REPORT) + { + // TODO + } + } + + 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 new file mode 100644 index 0000000..399039f --- /dev/null +++ b/src/SingleReport/RawHID.h @@ -0,0 +1,176 @@ +/* +Copyright (c) 2014-2015 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Include guard +#pragma once + +#include +#include "PluggableUSB.h" +#include "HID.h" +#include "HID-Settings.h" + +// RawHID might never work with multireports, because of OS problems +// therefore we have to make it a single report with no idea. No other HID device will be supported then. +#undef RAWHID_USAGE_PAGE +#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF + +#undef RAWHID_USAGE +#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF + +// Keep one byte offset for the reportID if used +#if (HID_REPORTID_RAWHID) +#define RAWHID_SIZE (USB_EP_SIZE-1) +#else +#define RAWHID_SIZE (USB_EP_SIZE) +#endif + +#undef RAWHID_TX_SIZE +#define RAWHID_TX_SIZE RAWHID_SIZE + +#undef RAWHID_RX_SIZE +#define RAWHID_RX_SIZE RAWHID_SIZE + +typedef union{ + // a RAWHID_TX_SIZE byte buffer for tx + uint8_t whole8[]; + uint16_t whole16[]; + uint32_t whole32[]; + uint8_t buff[RAWHID_TX_SIZE]; +} HID_RawKeyboardTXReport_Data_t; + +typedef union{ + // a RAWHID_TX_SIZE byte buffer for rx + uint8_t whole8[]; + uint16_t whole16[]; + uint32_t whole32[]; + uint8_t buff[RAWHID_RX_SIZE]; +} HID_RawKeyboardRXReport_Data_t; + +class RawHID_ : public PUSBListNode, public Stream +{ +public: + RawHID_(void); + + void begin(void){ + // empty + } + + void end(void){ + // empty + } + + virtual int available(void){ + return dataLength; + } + + 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; + } + return -1; + } + + virtual int peek(){ + if(dataLength){ + return *(dataTail - dataLength); + } + return -1; + } + + virtual void flush(void){ + // Delete all incoming bytes + if(dataLength){ + free(dataHead); + dataLength = 0; + } + } + + using Print::write; + virtual size_t write(uint8_t b){ + return write(&b, 1); + } + + virtual size_t write(uint8_t *buffer, size_t size){ + // TODO this only sends the report ID in the first packat + // TODO this will split the data into USB_EP_SIZE packets + 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; + } + + void SendReport(void* data, int length); + +protected: + // Implementation of the PUSBListNode + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + + uint8_t epType[1]; + uint8_t protocol; + uint8_t idle; + + + virtual void setReportData(void* &data, int len){ + // Only overwrite the buffer if its empty. + // This avoids corrupted data while reading. + if(!dataLength){ + // Save new data + dataLength = len; + dataHead = (uint8_t*) data; + dataTail = (uint8_t*)(data) + len; + + // Clear the passed in pointer to not free the data + data = NULL; + } + } + + // Buffer pointers to hold the received data + int dataLength; + uint8_t* dataHead; + uint8_t* dataTail; +}; +extern RawHID_ RawHID; +