-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
1,217 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* | ||
Modified by Matthew Heironimus to support HID Report Descriptors to be in | ||
standard RAM in addition to program memory (PROGMEM). | ||
Copyright (c) 2015, Arduino LLC | ||
Original code (pre-library): Copyright (c) 2011, Peter Barrett | ||
Permission to use, copy, modify, and/or distribute this software for | ||
any purpose with or without fee is hereby granted, provided that the | ||
above copyright notice and this permission notice appear in all copies. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR | ||
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | ||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | ||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | ||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | ||
SOFTWARE. | ||
*/ | ||
|
||
#include "DynamicHID.h" | ||
|
||
#if defined(USBCON) | ||
|
||
#ifdef _VARIANT_ARDUINO_DUE_X_ | ||
#define USB_SendControl USBD_SendControl | ||
#define USB_Send USBD_Send | ||
#endif | ||
|
||
DynamicHID_& DynamicHID() | ||
{ | ||
static DynamicHID_ obj; | ||
return obj; | ||
} | ||
|
||
int DynamicHID_::getInterface(uint8_t* interfaceCount) | ||
{ | ||
*interfaceCount += 1; // uses 1 | ||
DYNAMIC_HIDDescriptor hidInterface = { | ||
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, DYNAMIC_HID_SUBCLASS_NONE, DYNAMIC_HID_PROTOCOL_NONE), | ||
D_HIDREPORT(descriptorSize), | ||
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) | ||
}; | ||
return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); | ||
} | ||
|
||
int DynamicHID_::getDescriptor(USBSetup& setup) | ||
{ | ||
// Check if this is a HID Class Descriptor request | ||
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } | ||
if (setup.wValueH != DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE) { return 0; } | ||
|
||
// In a HID Class Descriptor wIndex cointains the interface number | ||
if (setup.wIndex != pluggedInterface) { return 0; } | ||
|
||
int total = 0; | ||
DynamicHIDSubDescriptor* node; | ||
for (node = rootNode; node; node = node->next) { | ||
int res = USB_SendControl((node->inProgMem ? TRANSFER_PGM : 0), node->data, node->length); | ||
if (res == -1) | ||
return -1; | ||
total += res; | ||
} | ||
|
||
// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol | ||
// due to the USB specs, but Windows and Linux just assumes its in report mode. | ||
protocol = DYNAMIC_HID_REPORT_PROTOCOL; | ||
|
||
return total; | ||
} | ||
|
||
uint8_t DynamicHID_::getShortName(char *name) | ||
{ | ||
name[0] = 'H'; | ||
name[1] = 'I'; | ||
name[2] = 'D'; | ||
name[3] = 'A' + (descriptorSize & 0x0F); | ||
name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); | ||
return 5; | ||
} | ||
|
||
void DynamicHID_::AppendDescriptor(DynamicHIDSubDescriptor *node) | ||
{ | ||
if (!rootNode) { | ||
rootNode = node; | ||
} else { | ||
DynamicHIDSubDescriptor *current = rootNode; | ||
while (current->next) { | ||
current = current->next; | ||
} | ||
current->next = node; | ||
} | ||
descriptorSize += node->length; | ||
} | ||
|
||
int DynamicHID_::SendReport(uint8_t id, const void* data, int len) | ||
{ | ||
uint8_t p[len + 1]; | ||
p[0] = id; | ||
memcpy(&p[1], data, len); | ||
return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, p, len + 1); | ||
} | ||
|
||
bool DynamicHID_::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 == DYNAMIC_HID_GET_REPORT) { | ||
// TODO: DYNAMIC_HID_GetReport(); | ||
return true; | ||
} | ||
if (request == DYNAMIC_HID_GET_PROTOCOL) { | ||
// TODO: Send8(protocol); | ||
return true; | ||
} | ||
if (request == DYNAMIC_HID_GET_IDLE) { | ||
// TODO: Send8(idle); | ||
} | ||
} | ||
|
||
if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) | ||
{ | ||
if (request == DYNAMIC_HID_SET_PROTOCOL) { | ||
// The USB Host tells us if we are in boot or report mode. | ||
// This only works with a real boot compatible device. | ||
protocol = setup.wValueL; | ||
return true; | ||
} | ||
if (request == DYNAMIC_HID_SET_IDLE) { | ||
idle = setup.wValueL; | ||
return true; | ||
} | ||
if (request == DYNAMIC_HID_SET_REPORT) | ||
{ | ||
//uint8_t reportID = setup.wValueL; | ||
//uint16_t length = setup.wLength; | ||
//uint8_t data[length]; | ||
// Make sure to not read more data than USB_EP_SIZE. | ||
// You can read multiple times through a loop. | ||
// The first byte (may!) contain the reportID on a multreport. | ||
//USB_RecvControl(data, length); | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
DynamicHID_::DynamicHID_(void) : PluggableUSBModule(1, 1, epType), | ||
rootNode(NULL), descriptorSize(0), | ||
protocol(DYNAMIC_HID_REPORT_PROTOCOL), idle(1) | ||
{ | ||
epType[0] = EP_TYPE_INTERRUPT_IN; | ||
PluggableUSB().plug(this); | ||
} | ||
|
||
int DynamicHID_::begin(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
#endif /* if defined(USBCON) */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* | ||
Modified by Matthew Heironimus to support HID Report Descriptors to be in | ||
standard RAM in addition to program memory (PROGMEM). | ||
Copyright (c) 2015, Arduino LLC | ||
Original code (pre-library): Copyright (c) 2011, Peter Barrett | ||
Permission to use, copy, modify, and/or distribute this software for | ||
any purpose with or without fee is hereby granted, provided that the | ||
above copyright notice and this permission notice appear in all copies. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR | ||
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | ||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | ||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | ||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | ||
SOFTWARE. | ||
*/ | ||
|
||
#ifndef DYNAMIC_HID_h | ||
#define DYNAMIC_HID_h | ||
|
||
#include <stdint.h> | ||
#include <Arduino.h> | ||
|
||
#ifdef _VARIANT_ARDUINO_DUE_X_ | ||
// The following values are the same as AVR's USBAPI.h | ||
// Reproduced here because SAM doesn't have these in | ||
// its own USBAPI.H | ||
#define USB_EP_SIZE 64 | ||
#define TRANSFER_PGM 0x80 | ||
|
||
#include "USB/PluggableUSB.h" | ||
#else | ||
#include "PluggableUSB.h" | ||
#endif | ||
|
||
#if defined(USBCON) | ||
|
||
#define _USING_DYNAMIC_HID | ||
|
||
// DYNAMIC_HID 'Driver' | ||
// ------------ | ||
#define DYNAMIC_HID_GET_REPORT 0x01 | ||
#define DYNAMIC_HID_GET_IDLE 0x02 | ||
#define DYNAMIC_HID_GET_PROTOCOL 0x03 | ||
#define DYNAMIC_HID_SET_REPORT 0x09 | ||
#define DYNAMIC_HID_SET_IDLE 0x0A | ||
#define DYNAMIC_HID_SET_PROTOCOL 0x0B | ||
|
||
#define DYNAMIC_HID_DESCRIPTOR_TYPE 0x21 | ||
#define DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE 0x22 | ||
#define DYNAMIC_HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 | ||
|
||
// HID subclass HID1.11 Page 8 4.2 Subclass | ||
#define DYNAMIC_HID_SUBCLASS_NONE 0 | ||
#define DYNAMIC_HID_SUBCLASS_BOOT_INTERFACE 1 | ||
|
||
// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols | ||
#define DYNAMIC_HID_PROTOCOL_NONE 0 | ||
#define DYNAMIC_HID_PROTOCOL_KEYBOARD 1 | ||
#define DYNAMIC_HID_PROTOCOL_MOUSE 2 | ||
|
||
// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request | ||
// "protocol" variable is used for this purpose. | ||
#define DYNAMIC_HID_BOOT_PROTOCOL 0 | ||
#define DYNAMIC_HID_REPORT_PROTOCOL 1 | ||
|
||
// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request | ||
#define DYNAMIC_HID_REPORT_TYPE_INPUT 1 | ||
#define DYNAMIC_HID_REPORT_TYPE_OUTPUT 2 | ||
#define DYNAMIC_HID_REPORT_TYPE_FEATURE 3 | ||
|
||
typedef struct | ||
{ | ||
uint8_t len; // 9 | ||
uint8_t dtype; // 0x21 | ||
uint8_t addr; | ||
uint8_t versionL; // 0x101 | ||
uint8_t versionH; // 0x101 | ||
uint8_t country; | ||
uint8_t desctype; // 0x22 report | ||
uint8_t descLenL; | ||
uint8_t descLenH; | ||
} DYNAMIC_HIDDescDescriptor; | ||
|
||
typedef struct | ||
{ | ||
InterfaceDescriptor hid; | ||
DYNAMIC_HIDDescDescriptor desc; | ||
EndpointDescriptor in; | ||
} DYNAMIC_HIDDescriptor; | ||
|
||
class DynamicHIDSubDescriptor { | ||
public: | ||
DynamicHIDSubDescriptor *next = NULL; | ||
DynamicHIDSubDescriptor(const void *d, const uint16_t l, const bool ipm = true) : data(d), length(l), inProgMem(ipm) { } | ||
|
||
const void* data; | ||
const uint16_t length; | ||
const bool inProgMem; | ||
}; | ||
|
||
class DynamicHID_ : public PluggableUSBModule | ||
{ | ||
public: | ||
DynamicHID_(void); | ||
int begin(void); | ||
int SendReport(uint8_t id, const void* data, int len); | ||
void AppendDescriptor(DynamicHIDSubDescriptor* node); | ||
|
||
protected: | ||
// Implementation of the PluggableUSBModule | ||
int getInterface(uint8_t* interfaceCount); | ||
int getDescriptor(USBSetup& setup); | ||
bool setup(USBSetup& setup); | ||
uint8_t getShortName(char* name); | ||
|
||
private: | ||
#ifdef _VARIANT_ARDUINO_DUE_X_ | ||
uint32_t epType[1]; | ||
#else | ||
uint8_t epType[1]; | ||
#endif | ||
|
||
DynamicHIDSubDescriptor* rootNode; | ||
uint16_t descriptorSize; | ||
|
||
uint8_t protocol; | ||
uint8_t idle; | ||
}; | ||
|
||
// Replacement for global singleton. | ||
// This function prevents static-initialization-order-fiasco | ||
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use | ||
DynamicHID_& DynamicHID(); | ||
|
||
#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } | ||
|
||
#endif // USBCON | ||
|
||
#endif // DYNAMIC_HID_h |
Oops, something went wrong.