[HID] port to stable PluggableUSB API

This commit is contained in:
Martino Facchin 2015-10-12 14:41:23 +02:00
parent b4541209cb
commit ddae105dc3
2 changed files with 169 additions and 162 deletions

View File

@ -16,153 +16,131 @@
** SOFTWARE. ** SOFTWARE.
*/ */
#include "USB/PluggableUSB.h"
#include "HID.h" #include "HID.h"
HID_ HID; #if defined(USBCON)
static uint8_t HID_ENDPOINT_INT; HID_& HID()
//================================================================================
//================================================================================
// HID report descriptor
#define LSB(_x) ((_x) & 0xFF)
#define MSB(_x) ((_x) >> 8)
#define RAWHID_USAGE_PAGE 0xFFC0
#define RAWHID_USAGE 0x0C00
#define RAWHID_TX_SIZE 64
#define RAWHID_RX_SIZE 64
static uint8_t HID_INTERFACE;
HIDDescriptor _hidInterface;
static HIDDescriptorListNode* rootNode = NULL;
static uint8_t sizeof_hidReportDescriptor = 0;
static uint8_t modules_count = 0;
//================================================================================
//================================================================================
// Driver
uint8_t _hid_protocol = 1;
uint8_t _hid_idle = 1;
int HID_GetInterface(uint8_t* interfaceNum)
{ {
interfaceNum[0] += 1; // uses 1 static HID_ obj;
_hidInterface = return obj;
{ }
D_INTERFACE(HID_INTERFACE,1,3,0,0),
D_HIDREPORT(sizeof_hidReportDescriptor), int HID_::getInterface(uint8_t* interfaceCount)
D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) {
*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, 0x40, 0x01)
}; };
return USBD_SendControl(0,&_hidInterface,sizeof(_hidInterface)); return USBD_SendControl(0, &hidInterface, sizeof(hidInterface));
} }
int HID_GetDescriptor(int8_t t) int HID_::getDescriptor(USBSetup& setup)
{ {
if (HID_REPORT_DESCRIPTOR_TYPE == t) { // Check if this is a HID Class Descriptor request
HIDDescriptorListNode* current = rootNode; if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; }
int total = 0; if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; }
while(current != NULL) {
total += USBD_SendControl(0,current->data,current->length); // In a HID Class Descriptor wIndex cointains the interface number
current = current->next; if (setup.wIndex != pluggedInterface) { return 0; }
}
return total; int total = 0;
} else { HIDSubDescriptor* node;
return 0; for (node = rootNode; node; node = node->next) {
int res = USBD_SendControl(0, node->data, node->length);
if (res == -1)
return -1;
total += res;
} }
return total;
} }
void HID_::AppendDescriptor(HIDDescriptorListNode *node) void HID_::AppendDescriptor(HIDSubDescriptor *node)
{ {
if (modules_count == 0) { if (!rootNode) {
rootNode = node; rootNode = node;
} else { } else {
HIDDescriptorListNode *current = rootNode; HIDSubDescriptor *current = rootNode;
while(current->next != NULL) { while (current->next) {
current = current->next; current = current->next;
} }
current->next = node; current->next = node;
} }
modules_count++; descriptorSize += node->length;
sizeof_hidReportDescriptor += node->length;
} }
void HID_::SendReport(uint8_t id, const void* data, int len) void HID_::SendReport(uint8_t id, const void* data, int len)
{ {
uint8_t p[64]; uint8_t p[64];
const uint8_t *d = reinterpret_cast<const uint8_t *>(data);
p[0] = id; p[0] = id;
for (uint32_t i=0; i<len; i++) memcpy(&p[1], data, len);
p[i+1] = d[i]; USBD_Send(pluggedEndpoint, p, len+1);
USBD_Send(HID_TX, p, len+1);
} }
bool HID_Setup(USBSetup& setup, uint8_t i) bool HID_::setup(USBSetup& setup)
{ {
if (HID_INTERFACE != i) { if (pluggedInterface != setup.wIndex) {
return false;
} else {
uint8_t r = setup.bRequest;
uint8_t requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (HID_GET_REPORT == r)
{
//HID_GetReport();
return true;
}
if (HID_GET_PROTOCOL == r)
{
//Send8(_hid_protocol); // TODO
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (HID_SET_PROTOCOL == r)
{
_hid_protocol = setup.wValueL;
return true;
}
if (HID_SET_IDLE == r)
{
_hid_idle = setup.wValueL;
return true;
}
}
return false; 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) HID_::HID_(void) : PluggableUSBModule(1, 1, epType),
rootNode(NULL), descriptorSize(0),
protocol(1), idle(1)
{ {
static uint32_t endpointType[1]; epType[0] = EP_TYPE_INTERRUPT_IN;
PluggableUSB().plug(this);
endpointType[0] = EP_TYPE_INTERRUPT_IN;
static PUSBCallbacks cb = {
.setup = &HID_Setup,
.getInterface = &HID_GetInterface,
.getDescriptor = &HID_GetDescriptor,
.numEndpoints = 1,
.numInterfaces = 1,
.endpointType = endpointType,
};
static PUSBListNode node(&cb);
HID_ENDPOINT_INT = PUSB_AddFunction(&node, &HID_INTERFACE);
} }
int HID_::begin(void) int HID_::begin(void)
{ {
return 0; return 0;
} }
#endif /* if defined(USBCON) */

View File

@ -1,36 +1,34 @@
/* /*
HID.h
Copyright (c) 2015, Arduino LLC Copyright (c) 2015, Arduino LLC
Original code (pre-library): Copyright (c) 2011, Peter Barrett Original code (pre-library): Copyright (c) 2011, Peter Barrett
This library is free software; you can redistribute it and/or Permission to use, copy, modify, and/or distribute this software for
modify it under the terms of the GNU Lesser General Public any purpose with or without fee is hereby granted, provided that the
License as published by the Free Software Foundation; either above copyright notice and this permission notice appear in all copies.
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
but WITHOUT ANY WARRANTY; without even the implied warranty of WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
Lesser General Public License for more details. BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
You should have received a copy of the GNU Lesser General Public WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
License along with this library; if not, write to the Free Software ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA SOFTWARE.
*/ */
#ifndef HID_h #ifndef HID_h
#define HID_h #define HID_h
#include <stdint.h> #include <stdint.h>
#include <Arduino.h> #include <Arduino.h>
#include "USB/PluggableUSB.h"
#if defined(USBCON)
#define _USING_HID #define _USING_HID
//================================================================================ // HID 'Driver'
//================================================================================ // ------------
// HID 'Driver'
#define HID_GET_REPORT 0x01 #define HID_GET_REPORT 0x01
#define HID_GET_IDLE 0x02 #define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03 #define HID_GET_PROTOCOL 0x03
@ -42,49 +40,80 @@
#define HID_REPORT_DESCRIPTOR_TYPE 0x22 #define HID_REPORT_DESCRIPTOR_TYPE 0x22
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 #define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
class HIDDescriptorListNode { // 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
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: public:
HIDDescriptorListNode *next = NULL; HIDSubDescriptor *next = NULL;
HIDDescriptorListNode(const void *d, const uint16_t l) : data(d), length(l) { } HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { }
const void* data; const void* data;
const uint16_t length; const uint16_t length;
}; };
class HID_ class HID_ : public PluggableUSBModule
{ {
public: public:
HID_(void); HID_(void);
int begin(void); int begin(void);
void SendReport(uint8_t id, const void* data, int len); void SendReport(uint8_t id, const void* data, int len);
void AppendDescriptor(HIDDescriptorListNode* node); void AppendDescriptor(HIDSubDescriptor* node);
protected:
// Implementation of the PluggableUSBModule
int getInterface(uint8_t* interfaceCount);
int getDescriptor(USBSetup& setup);
bool setup(USBSetup& setup);
private:
uint32_t epType[1];
HIDSubDescriptor* rootNode;
uint16_t descriptorSize;
uint8_t protocol;
uint8_t idle;
}; };
typedef struct // Replacement for global singleton.
{ // This function prevents static-initialization-order-fiasco
uint8_t len; // 9 // https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
uint8_t dtype; // 0x21 HID_& HID();
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 #define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) }
{
InterfaceDescriptor hid;
HIDDescDescriptor desc;
EndpointDescriptor in;
} HIDDescriptor;
#define HID_TX HID_ENDPOINT_INT #endif // USBCON
#define D_HIDREPORT(_descriptorLength) \ #endif // HID_h
{ 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 }
#define WEAK __attribute__ ((weak))
#endif