aboutsummaryrefslogtreecommitdiff
path: root/libraries/HID/src
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/HID/src')
-rw-r--r--libraries/HID/src/HID.cpp162
-rw-r--r--libraries/HID/src/HID.h125
2 files changed, 287 insertions, 0 deletions
diff --git a/libraries/HID/src/HID.cpp b/libraries/HID/src/HID.cpp
new file mode 100644
index 0000000..21ede26
--- /dev/null
+++ b/libraries/HID/src/HID.cpp
@@ -0,0 +1,162 @@
+/*
+ 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 "HID.h"
+
+#if defined(USBCON)
+
+HID_& HID()
+{
+ static HID_ obj;
+ return obj;
+}
+
+int HID_::getInterface(uint8_t* interfaceCount)
+{
+ *interfaceCount += 1; // uses 1
+ HIDDescriptor hidInterface = {
+ D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, 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 HID_::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; }
+
+ int total = 0;
+ HIDSubDescriptor* node;
+ for (node = rootNode; node; node = node->next) {
+ int res = USB_SendControl(TRANSFER_PGM, 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 = HID_REPORT_PROTOCOL;
+
+ return total;
+}
+
+uint8_t HID_::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 HID_::AppendDescriptor(HIDSubDescriptor *node)
+{
+ if (!rootNode) {
+ rootNode = node;
+ } else {
+ HIDSubDescriptor *current = rootNode;
+ while (current->next) {
+ current = current->next;
+ }
+ current->next = node;
+ }
+ descriptorSize += node->length;
+}
+
+int HID_::SendReport(uint8_t id, const void* data, int len)
+{
+ auto ret = USB_Send(pluggedEndpoint, &id, 1);
+ if (ret < 0) return ret;
+ auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len);
+ if (ret2 < 0) return ret2;
+ return ret + ret2;
+}
+
+bool HID_::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 (request == HID_GET_IDLE) {
+ // TODO: Send8(idle);
+ }
+ }
+
+ if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE)
+ {
+ if (request == 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 == HID_SET_IDLE) {
+ idle = setup.wValueL;
+ return true;
+ }
+ if (request == 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;
+}
+
+HID_::HID_(void) : PluggableUSBModule(1, 1, epType),
+ rootNode(NULL), descriptorSize(0),
+ protocol(HID_REPORT_PROTOCOL), idle(1)
+{
+ epType[0] = EP_TYPE_INTERRUPT_IN;
+ PluggableUSB().plug(this);
+}
+
+int HID_::begin(void)
+{
+ return 0;
+}
+
+#endif /* if defined(USBCON) */
diff --git a/libraries/HID/src/HID.h b/libraries/HID/src/HID.h
new file mode 100644
index 0000000..93c4bd5
--- /dev/null
+++ b/libraries/HID/src/HID.h
@@ -0,0 +1,125 @@
+/*
+ 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 HID_h
+#define HID_h
+
+#include <stdint.h>
+#include <Arduino.h>
+#include "PluggableUSB.h"
+
+#if defined(USBCON)
+
+#define _USING_HID
+
+// HID 'Driver'
+// ------------
+#define HID_GET_REPORT 0x01
+#define HID_GET_IDLE 0x02
+#define HID_GET_PROTOCOL 0x03
+#define HID_SET_REPORT 0x09
+#define HID_SET_IDLE 0x0A
+#define HID_SET_PROTOCOL 0x0B
+
+#define HID_HID_DESCRIPTOR_TYPE 0x21
+#define HID_REPORT_DESCRIPTOR_TYPE 0x22
+#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
+
+// HID subclass HID1.11 Page 8 4.2 Subclass
+#define HID_SUBCLASS_NONE 0
+#define HID_SUBCLASS_BOOT_INTERFACE 1
+
+// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols
+#define HID_PROTOCOL_NONE 0
+#define HID_PROTOCOL_KEYBOARD 1
+#define 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 HID_BOOT_PROTOCOL 0
+#define HID_REPORT_PROTOCOL 1
+
+// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request
+#define HID_REPORT_TYPE_INPUT 1
+#define HID_REPORT_TYPE_OUTPUT 2
+#define 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;
+} HIDDescDescriptor;
+
+typedef struct
+{
+ InterfaceDescriptor hid;
+ HIDDescDescriptor desc;
+ EndpointDescriptor in;
+} HIDDescriptor;
+
+class HIDSubDescriptor {
+public:
+ HIDSubDescriptor *next = NULL;
+ HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { }
+
+ const void* data;
+ const uint16_t length;
+};
+
+class HID_ : public PluggableUSBModule
+{
+public:
+ HID_(void);
+ int begin(void);
+ int SendReport(uint8_t id, const void* data, int len);
+ void AppendDescriptor(HIDSubDescriptor* 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:
+ uint8_t epType[1];
+
+ HIDSubDescriptor* 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
+HID_& HID();
+
+#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) }
+
+#endif // USBCON
+
+#endif // HID_h