From 23ba2788b4bd7c8cd0ad94d4b6ad69ad6f3af60a Mon Sep 17 00:00:00 2001 From: Nico Date: Fri, 21 Nov 2014 18:39:36 +0100 Subject: [PATCH] Added 16u2 Compatibility + New HID Cores --- CDC.cpp | 28 +- HID.cpp | 690 ++++++++++++++------------------- USBAPI.h | 975 +++++++++++++++++++++++++++++++++++++++++++---- USBCore.cpp | 219 +++++++---- USBDesc.h | 27 ++ wiring_private.h | 4 +- 6 files changed, 1371 insertions(+), 572 deletions(-) diff --git a/CDC.cpp b/CDC.cpp index 5d4f2a0..1c4672f 100644 --- a/CDC.cpp +++ b/CDC.cpp @@ -16,6 +16,29 @@ ** SOFTWARE. */ +/* +Copyright (c) 2014 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 "USBAPI.h" #include @@ -50,8 +73,9 @@ const CDCDescriptor _cdcInterface = // CDC data interface D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), - D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x40,0), - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0) + // edit by NicoHood + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) }; int WEAK CDC_GetInterface(u8* interfaceNum) diff --git a/HID.cpp b/HID.cpp index 75c37b2..27f3150 100644 --- a/HID.cpp +++ b/HID.cpp @@ -1,19 +1,42 @@ -/* 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. +/* 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. +*/ + +/* +Copyright (c) 2014 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 "USBAPI.h" @@ -21,117 +44,205 @@ #if defined(USBCON) #ifdef HID_ENABLED -//#define RAWHID_ENABLED - -// Singletons for mouse and keyboard - -Mouse_ Mouse; -Keyboard_ Keyboard; - //================================================================================ //================================================================================ - // 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 - extern const u8 _hidReportDescriptor[] PROGMEM; const u8 _hidReportDescriptor[] = { - - // Mouse - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 - 0x09, 0x02, // USAGE (Mouse) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x01, // USAGE (Pointer) - 0xa1, 0x00, // COLLECTION (Physical) - 0x85, 0x01, // REPORT_ID (1) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x03, // USAGE_MAXIMUM (Button 3) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x03, // REPORT_COUNT (3) - 0x75, 0x01, // REPORT_SIZE (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x05, // REPORT_SIZE (5) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x38, // USAGE (Wheel) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x03, // REPORT_COUNT (3) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION +#ifdef HID_MOUSE_ENABLED + // Mouse + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x85, HID_REPORTID_MouseReport,// REPORT_ID + // 5 buttons + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x05, // USAGE_MAXIMUM (Button 5) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + // reserved + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + // x, y, wheel + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x38, // USAGE (Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x06, // INPUT (Data,Var,Rel) + // end + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +#endif - // Keyboard - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - +#ifdef HID_KEYBOARD_ENABLED + // Keyboard + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, HID_REPORTID_KeyboardReport, // REPORT_ID + 0x05, 0x07, // USAGE_PAGE (Keyboard) + // modifiers 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - + 0x81, 0x02, // INPUT (Data,Var,Abs) + // reserved byte + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + // Key[6] Array 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0, // END_COLLECTION + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + // LEDs for num lock etc + //0x05, 0x08, /* USAGE_PAGE (LEDs) */ + //0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ + //0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ + //0x95, 0x05, /* REPORT_COUNT (5) */ + //0x75, 0x01, /* REPORT_SIZE (1) */ + //0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ + // Reserved 3 bits + //0x95, 0x01, /* REPORT_COUNT (1) */ + //0x75, 0x03, /* REPORT_SIZE (3) */ + //0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ + // end + 0xc0, // END_COLLECTION +#endif -#ifdef RAWHID_ENABLED - // RAW HID +#ifdef HID_RAWHID_ENABLED + // RAW HID 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - 0xA1, 0x01, // Collection 0x01 - 0x85, 0x03, // REPORT_ID (3) - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 + 0xA1, 0x01, // Collection 0x01 + 0x85, HID_REPORTID_RawKeyboardReport, // REPORT_ID + 0x75, 0x08, // report size = 8 bits + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 - 0x95, 64, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) + 0x95, RAWHID_TX_SIZE, // report count TX + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) - 0x95, 64, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0 // end collection + 0x95, RAWHID_RX_SIZE, // report count RX + 0x09, 0x02, // usage + 0x91, 0x02, // Output (array) + 0xC0, // end collection +#endif + +#ifdef HID_MEDIA_ENABLED + // Media + 0x05, 0x0C, // usage page (consumer device) + 0x09, 0x01, // usage -- consumer control + 0xA1, 0x01, // collection (application) + 0x85, HID_REPORTID_MediaReport, // report id + //0x05, 0x0C, // usage page (consumer) + + // 4 media Keys + 0x15, 0x00, //logical minimum + 0x26, 0xFF, 0x03, //logical maximum (3ff) + 0x19, 0x00, // usage minimum (0) + 0x2A, 0xFF, 0x03, //usage maximum (3ff) + 0x95, 0x04, //report count (4) + 0x75, 0x10, //report size (16) + + 0x81, 0x00, //input + 0xC0, //end collection +#endif + +#ifdef HID_SYSTEM_ENABLED + // System + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x80, // USAGE (System Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, HID_REPORTID_SystemReport, // REPORT_ID + // 1 system key + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x19, 0x00, // USAGE_MINIMUM (Undefined) + 0x29, 0xff, // USAGE_MAXIMUM (System Menu Down) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION +#endif + +#ifdef HID_GAMEPAD_ENABLED + // Gamepad + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x04, // USAGE (Joystick) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, HID_REPORTID_GamepadReport, // REPORT_ID + // 32 Buttons + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x20, // USAGE_MAXIMUM (Button 32) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x20, // REPORT_COUNT (32) + 0x81, 0x02, // INPUT (Data,Var,Abs) + // 4 16bit Axis + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0xa1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x33, // USAGE (Rx) + 0x09, 0x34, // USAGE (Ry) + 0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768) + 0x26, 0xFF, 0x7F, // LOGICAL_MAXIMUM (32767) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + // 2 8bit Axis + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x15, 0x80, // LOGICAL_MINIMUM (-128) + 0x25, 0x7F, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + // 2 Hat Switches + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x39, // USAGE (Hat switch) + 0x09, 0x39, // USAGE (Hat switch) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x08, // LOGICAL_MAXIMUM (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION #endif }; extern const HIDDescriptor _hidInterface PROGMEM; const HIDDescriptor _hidInterface = { - D_INTERFACE(HID_INTERFACE,1,3,0,0), + D_INTERFACE(HID_INTERFACE, 1, 3, 0, 0), D_HIDREPORT(sizeof(_hidReportDescriptor)), - D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) + // edit by NicoHood + D_ENDPOINT(USB_ENDPOINT_IN(HID_ENDPOINT_INT), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) }; //================================================================================ @@ -146,18 +257,18 @@ u8 _hid_idle = 1; int WEAK HID_GetInterface(u8* interfaceNum) { interfaceNum[0] += 1; // uses 1 - return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); + return USB_SendControl(TRANSFER_PGM, &_hidInterface, sizeof(_hidInterface)); } int WEAK HID_GetDescriptor(int /* i */) { - return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); + return USB_SendControl(TRANSFER_PGM, _hidReportDescriptor, sizeof(_hidReportDescriptor)); } void WEAK HID_SendReport(u8 id, const void* data, int len) { USB_Send(HID_TX, &id, 1); - USB_Send(HID_TX | TRANSFER_RELEASE,data,len); + USB_Send(HID_TX | TRANSFER_RELEASE, data, len); } bool WEAK HID_Setup(Setup& setup) @@ -177,7 +288,7 @@ bool WEAK HID_Setup(Setup& setup) return true; } } - + if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if (HID_SET_PROTOCOL == r) @@ -195,324 +306,77 @@ bool WEAK HID_Setup(Setup& setup) return false; } -//================================================================================ -//================================================================================ -// Mouse +#endif -Mouse_::Mouse_(void) : _buttons(0) +#else if defined(USE_USB_API) + +// still provide the weak HID_SendReport function to be able to overwrite it externaly +void __attribute__((weak)) HID_SendReport(uint8_t id, const void* data, int len) { + // the user has to overwrite this if no USB Core is used } -void Mouse_::begin(void) -{ -} +#endif /* if defined(USBCON) */ -void Mouse_::end(void) -{ -} - -void Mouse_::click(uint8_t b) -{ - _buttons = b; - move(0,0,0); - _buttons = 0; - move(0,0,0); -} - -void Mouse_::move(signed char x, signed char y, signed char wheel) -{ - u8 m[4]; - m[0] = _buttons; - m[1] = x; - m[2] = y; - m[3] = wheel; - HID_SendReport(1,m,4); -} - -void Mouse_::buttons(uint8_t b) -{ - if (b != _buttons) - { - _buttons = b; - move(0,0,0); - } -} - -void Mouse_::press(uint8_t b) -{ - buttons(_buttons | b); -} - -void Mouse_::release(uint8_t b) -{ - buttons(_buttons & ~b); -} - -bool Mouse_::isPressed(uint8_t b) -{ - if ((b & _buttons) > 0) - return true; - return false; -} +// HID API libs are only included if the device has USB functionality or if the USE_USB_API is needed +#if defined(USBCON) || defined(USE_USB_API) //================================================================================ +// Mouse //================================================================================ -// Keyboard -Keyboard_::Keyboard_(void) -{ -} +#ifdef HID_MOUSE_ENABLED -void Keyboard_::begin(void) -{ -} - -void Keyboard_::end(void) -{ -} - -void Keyboard_::sendReport(KeyReport* keys) -{ - HID_SendReport(2,keys,sizeof(KeyReport)); -} - -extern -const uint8_t _asciimap[128] PROGMEM; - -#define SHIFT 0x80 -const uint8_t _asciimap[128] = -{ - 0x00, // NUL - 0x00, // SOH - 0x00, // STX - 0x00, // ETX - 0x00, // EOT - 0x00, // ENQ - 0x00, // ACK - 0x00, // BEL - 0x2a, // BS Backspace - 0x2b, // TAB Tab - 0x28, // LF Enter - 0x00, // VT - 0x00, // FF - 0x00, // CR - 0x00, // SO - 0x00, // SI - 0x00, // DEL - 0x00, // DC1 - 0x00, // DC2 - 0x00, // DC3 - 0x00, // DC4 - 0x00, // NAK - 0x00, // SYN - 0x00, // ETB - 0x00, // CAN - 0x00, // EM - 0x00, // SUB - 0x00, // ESC - 0x00, // FS - 0x00, // GS - 0x00, // RS - 0x00, // US - - 0x2c, // ' ' - 0x1e|SHIFT, // ! - 0x34|SHIFT, // " - 0x20|SHIFT, // # - 0x21|SHIFT, // $ - 0x22|SHIFT, // % - 0x24|SHIFT, // & - 0x34, // ' - 0x26|SHIFT, // ( - 0x27|SHIFT, // ) - 0x25|SHIFT, // * - 0x2e|SHIFT, // + - 0x36, // , - 0x2d, // - - 0x37, // . - 0x38, // / - 0x27, // 0 - 0x1e, // 1 - 0x1f, // 2 - 0x20, // 3 - 0x21, // 4 - 0x22, // 5 - 0x23, // 6 - 0x24, // 7 - 0x25, // 8 - 0x26, // 9 - 0x33|SHIFT, // : - 0x33, // ; - 0x36|SHIFT, // < - 0x2e, // = - 0x37|SHIFT, // > - 0x38|SHIFT, // ? - 0x1f|SHIFT, // @ - 0x04|SHIFT, // A - 0x05|SHIFT, // B - 0x06|SHIFT, // C - 0x07|SHIFT, // D - 0x08|SHIFT, // E - 0x09|SHIFT, // F - 0x0a|SHIFT, // G - 0x0b|SHIFT, // H - 0x0c|SHIFT, // I - 0x0d|SHIFT, // J - 0x0e|SHIFT, // K - 0x0f|SHIFT, // L - 0x10|SHIFT, // M - 0x11|SHIFT, // N - 0x12|SHIFT, // O - 0x13|SHIFT, // P - 0x14|SHIFT, // Q - 0x15|SHIFT, // R - 0x16|SHIFT, // S - 0x17|SHIFT, // T - 0x18|SHIFT, // U - 0x19|SHIFT, // V - 0x1a|SHIFT, // W - 0x1b|SHIFT, // X - 0x1c|SHIFT, // Y - 0x1d|SHIFT, // Z - 0x2f, // [ - 0x31, // bslash - 0x30, // ] - 0x23|SHIFT, // ^ - 0x2d|SHIFT, // _ - 0x35, // ` - 0x04, // a - 0x05, // b - 0x06, // c - 0x07, // d - 0x08, // e - 0x09, // f - 0x0a, // g - 0x0b, // h - 0x0c, // i - 0x0d, // j - 0x0e, // k - 0x0f, // l - 0x10, // m - 0x11, // n - 0x12, // o - 0x13, // p - 0x14, // q - 0x15, // r - 0x16, // s - 0x17, // t - 0x18, // u - 0x19, // v - 0x1a, // w - 0x1b, // x - 0x1c, // y - 0x1d, // z - 0x2f|SHIFT, // - 0x31|SHIFT, // | - 0x30|SHIFT, // } - 0x35|SHIFT, // ~ - 0 // DEL -}; - -uint8_t USBPutChar(uint8_t c); - -// press() adds the specified key (printing, non-printing, or modifier) -// to the persistent key report and sends the report. Because of the way -// USB HID works, the host acts like the key remains pressed until we -// call release(), releaseAll(), or otherwise clear the report and resend. -size_t Keyboard_::press(uint8_t k) -{ - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers |= (1<<(k-128)); - k = 0; - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - setWriteError(); - return 0; - } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers |= 0x02; // the left shift modifier - k &= 0x7F; - } - } - - // Add k to the key report only if it's not already present - // and if there is an empty slot. - if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && - _keyReport.keys[2] != k && _keyReport.keys[3] != k && - _keyReport.keys[4] != k && _keyReport.keys[5] != k) { - - for (i=0; i<6; i++) { - if (_keyReport.keys[i] == 0x00) { - _keyReport.keys[i] = k; - break; - } - } - if (i == 6) { - setWriteError(); - return 0; - } - } - sendReport(&_keyReport); - return 1; -} - -// release() takes the specified key out of the persistent key report and -// sends the report. This tells the OS the key is no longer pressed and that -// it shouldn't be repeated any more. -size_t Keyboard_::release(uint8_t k) -{ - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers &= ~(1<<(k-128)); - k = 0; - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - return 0; - } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers &= ~(0x02); // the left shift modifier - k &= 0x7F; - } - } - - // Test the key report to see if k is present. Clear it if it exists. - // Check all positions in case the key is present more than once (which it shouldn't be) - for (i=0; i<6; i++) { - if (0 != k && _keyReport.keys[i] == k) { - _keyReport.keys[i] = 0x00; - } - } - - sendReport(&_keyReport); - return 1; -} - -void Keyboard_::releaseAll(void) -{ - _keyReport.keys[0] = 0; - _keyReport.keys[1] = 0; - _keyReport.keys[2] = 0; - _keyReport.keys[3] = 0; - _keyReport.keys[4] = 0; - _keyReport.keys[5] = 0; - _keyReport.modifiers = 0; - sendReport(&_keyReport); -} - -size_t Keyboard_::write(uint8_t c) -{ - uint8_t p = press(c); // Keydown - release(c); // Keyup - return p; // just return the result of press() since release() almost always returns 1 -} +// object instance +Mouse_ Mouse; #endif -#endif /* if defined(USBCON) */ +//================================================================================ +// Keyboard +//================================================================================ + +#ifdef HID_KEYBOARD_ENABLED + +// object instance +Keyboard_ Keyboard; + +#endif + + +//================================================================================ +// Media +//================================================================================ + +#ifdef HID_MEDIA_ENABLED + +// object instance +Media_ Media; + +#endif + + +//================================================================================ +// System +//================================================================================ + +#ifdef HID_SYSTEAM_ENABLED + +// object instance +System_ System; + +#endif + + +//================================================================================ +// Gamepad +//================================================================================ + +#ifdef HID_GAMEPAD_ENABLED + +// object instance +Gamepad_ Gamepad; + +#endif + +#endif // if defined(USBCON) || defined(USE_USB_API) \ No newline at end of file diff --git a/USBAPI.h b/USBAPI.h index 2fab957..9270655 100644 --- a/USBAPI.h +++ b/USBAPI.h @@ -15,6 +15,29 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* +Copyright (c) 2014 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. */ #ifndef __USBAPI__ @@ -32,6 +55,89 @@ typedef unsigned long u32; #include "Arduino.h" +#ifdef USBCON +// include needed HID devices +// the more you activate, the more flash it will take +// by default only Mouse + Keyboard are activated +#define HID_MOUSE_ENABLED +#define HID_KEYBOARD_ENABLED +//#define HID_RAWHID_ENABLED +//#define HID_MEDIA_ENABLED +//#define HID_SYSTEM_ENABLED +//#define HID_GAMEPAD_ENABLED + +// calculate HID report size for each device + +#ifdef HID_MOUSE_ENABLED +#define HID_MOUSE_SIZE 54 +#else +#define HID_MOUSE_SIZE 0 +#endif + +#ifdef HID_KEYBOARD_ENABLED +#define HID_KEYBOARD_SIZE (65-18) //18 for missing led out report = 47 +#else +#define HID_KEYBOARD_SIZE 0 +#endif + +#ifdef HID_RAWHID_ENABLED +#define HID_RAWHID_SIZE 30 +#else +#define HID_RAWHID_SIZE 0 +#endif + +#ifdef HID_MEDIA_ENABLED +#define HID_MEDIA_SIZE 25 +#else +#define HID_MEDIA_SIZE 0 +#endif + +#ifdef HID_SYSTEM_ENABLED +#define HID_SYSTEM_SIZE 24 +#else +#define HID_SYSTEM_SIZE 0 +#endif + +#ifdef HID_GAMEPAD_ENABLED +#define HID_GAMEPAD_SIZE 80 +#else +#define HID_GAMEPAD_SIZE 0 +#endif + +// check if usb descriptor isn't too big for USBCore (seems to not work properly then) +#define HID_DESCRIPTOR_SIZE (HID_MOUSE_SIZE + HID_KEYBOARD_SIZE + HID_RAWHID_SIZE + \ +HID_MEDIA_SIZE + HID_SYSTEM_SIZE + HID_GAMEPAD_SIZE + 0) +#if (HID_DESCRIPTOR_SIZE >= 256) +#error Please do not use HID reports >= 256 bytes. Edit USBAPI.h and remove some devices, please. +#endif + +#else // ifdef USBCON + +// still use USE_USB_API sending API to be able to overwrite the HID_SendReport function +#define USE_USB_API + +// activate all API's +#define HID_MOUSE_ENABLED +#define HID_KEYBOARD_ENABLED +#define HID_RAWHID_ENABLED +#define HID_MEDIA_ENABLED +#define HID_SYSTEM_ENABLED +#define HID_GAMEPAD_ENABLED + +#endif + +/** Enum for the HID report IDs used in the device. */ +typedef enum{ + HID_REPORTID_NotAReport = 0x00, /**< first entry is always zero for multireports */ + HID_REPORTID_MouseReport = 0x01, /**< Report ID for the Mouse report within the device. */ + HID_REPORTID_KeyboardReport = 0x02, /**< Report ID for the Keyboard report within the device. */ + HID_REPORTID_RawKeyboardReport = 0x03, /**< Report ID for the Raw Keyboard report within the device. */ + HID_REPORTID_MediaReport = 0x04, /**< Report ID for the Media report within the device. */ + HID_REPORTID_SystemReport = 0x05, /**< Report ID for the Power report within the device. */ + HID_REPORTID_GamepadReport = 0x06, /**< Report ID for the Gamepad report within the device. */ +} HID_Report_IDs; + +// usb core functions #if defined(USBCON) #include "USBDesc.h" @@ -94,33 +200,177 @@ extern Serial_ Serial; //================================================================================ //================================================================================ -// Mouse +// Low level API -#define MOUSE_LEFT 1 -#define MOUSE_RIGHT 2 -#define MOUSE_MIDDLE 4 -#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} Setup; + +//================================================================================ +//================================================================================ +// HID 'Driver' + +int HID_GetInterface(uint8_t* interfaceNum); +int HID_GetDescriptor(int i); +bool HID_Setup(Setup& setup); +void HID_SendReport(uint8_t id, const void* data, int len); + +//================================================================================ +//================================================================================ +// MSC 'Driver' + +int MSC_GetInterface(uint8_t* interfaceNum); +int MSC_GetDescriptor(int i); +bool MSC_Setup(Setup& setup); +bool MSC_Data(uint8_t rx, uint8_t tx); + +//================================================================================ +//================================================================================ +// CSC 'Driver' + +int CDC_GetInterface(uint8_t* interfaceNum); +int CDC_GetDescriptor(int i); +bool CDC_Setup(Setup& setup); + +//================================================================================ +//================================================================================ + +#define TRANSFER_PGM 0x80 +#define TRANSFER_RELEASE 0x40 +#define TRANSFER_ZERO 0x20 + +int USB_SendControl(uint8_t flags, const void* d, int len); +int USB_RecvControl(void* d, int len); + +uint8_t USB_Available(uint8_t ep); +int USB_Send(uint8_t ep, const void* data, int len); // blocking +int USB_Recv(uint8_t ep, void* data, int len); // non-blocking +int USB_Recv(uint8_t ep); // non-blocking +void USB_Flush(uint8_t ep); + + +#else if defined(USE_USB_API) + +// still provide the weak HID_SendReport function to be able to overwrite it externaly +void HID_SendReport(uint8_t id, const void* data, int len); + +#endif /* if defined(USBCON) */ + +// HID API libs are only included if the device has USB functionality or if the USE_USB_API is needed +#if defined(USBCON) || defined(USE_USB_API) + +//================================================================================ +// Mouse +//================================================================================ + +#ifdef HID_MOUSE_ENABLED + +#define MOUSE_LEFT 0x01 +#define MOUSE_RIGHT 0x02 +#define MOUSE_MIDDLE 0x04 +#define MOUSE_PREV 0x08 +#define MOUSE_NEXT 0x10 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_PREV | MOUSE_NEXT) + +typedef union{ + // mouse report: 5 buttons, position, wheel + uint8_t whole8[4]; + uint16_t whole16[4 / 2]; + uint32_t whole32[4 / 4]; + + struct{ + uint8_t buttons : 5; + uint8_t reserved : 3; + int8_t xAxis; + int8_t yAxis; + int8_t wheel; + }; +} HID_MouseReport_Data_t; class Mouse_ { +public: + inline Mouse_(void) { + // removed this to avoid creating an instance of Mouse if not needed + // the user should call begin first. + //: _buttons(0){ + // empty + } + + inline void begin(void){ + // release all buttons + end(); + } + + inline void end(void){ + _buttons = 0; + move(0, 0, 0); + } + + inline void click(uint8_t b = MOUSE_LEFT){ + _buttons = b; + move(0, 0, 0); + _buttons = 0; + move(0, 0, 0); + } + + inline void move(signed char x, signed char y, signed char wheel = 0){ + u8 m[4]; + m[0] = _buttons; + m[1] = x; + m[2] = y; + m[3] = wheel; + HID_SendReport(1, m, 4); + } + + inline void press(uint8_t b = MOUSE_LEFT){ + // press LEFT by default + buttons(_buttons | b); + } + + inline void release(uint8_t b = MOUSE_LEFT){ + // release LEFT by default + buttons(_buttons & ~b); + } + + inline bool isPressed(uint8_t b = MOUSE_LEFT){ + // check LEFT by default + if ((b & _buttons) > 0) + return true; + return false; + } + private: uint8_t _buttons; - void buttons(uint8_t b); -public: - Mouse_(void); - void begin(void); - void end(void); - void click(uint8_t b = MOUSE_LEFT); - void move(signed char x, signed char y, signed char wheel = 0); - void press(uint8_t b = MOUSE_LEFT); // press LEFT by default - void release(uint8_t b = MOUSE_LEFT); // release LEFT by default - bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default + inline void buttons(uint8_t b){ + if (b != _buttons) + { + _buttons = b; + move(0, 0, 0); + } + } }; extern Mouse_ Mouse; +#endif + + //================================================================================ +// Keyboard //================================================================================ -// Keyboard + +#ifdef HID_KEYBOARD_ENABLED + +//Keyboard fixed/added missing Keys +#define KEY_PRINT 0xCE +#define KEY_SCROLL_LOCK 0xCF +#define KEY_PAUSE 0xD0 #define KEY_LEFT_CTRL 0x80 #define KEY_LEFT_SHIFT 0x81 @@ -159,86 +409,645 @@ extern Mouse_ Mouse; #define KEY_F11 0xCC #define KEY_F12 0xCD -// Low level key report: up to 6 keys and shift, ctrl etc at once -typedef struct -{ - uint8_t modifiers; - uint8_t reserved; - uint8_t keys[6]; -} KeyReport; +//Raw Keyboard definitions +#define RAW_KEYBOARD_LEFT_CTRL B00000001 +#define RAW_KEYBOARD_LEFT_SHIFT B00000010 +#define RAW_KEYBOARD_LEFT_ALT B00000100 +#define RAW_KEYBOARD_LEFT_GUI B00001000 +#define RAW_KEYBOARD_RIGHT_CTRL B00010000 +#define RAW_KEYBOARD_RIGHT_SHIFT B00100000 +#define RAW_KEYBOARD_RIGHT_ALT B01000000 +#define RAW_KEYBOARD_RIGHT_GUI B10000000 -class Keyboard_ : public Print +#define RAW_KEYBOARD_KEY(key) ((key>='a' && key<='z') ? (0x04 + key-'a') :\ +(key>='A' && key<='Z') ? (0x04 + key-'A') : (key>='1' && key<='9') ? (0x1E + key-'1') : 0x27) + +#define RAW_KEYBOARD_UP_ARROW 0x52 +#define RAW_KEYBOARD_DOWN_ARROW 0x51 +#define RAW_KEYBOARD_LEFT_ARROW 0x50 +#define RAW_KEYBOARD_RIGHT_ARROW 0x4F +#define RAW_KEYBOARD_SPACEBAR 0x2C +#define RAW_KEYBOARD_BACKSPACE 0x2A +#define RAW_KEYBOARD_TAB 0x2B +#define RAW_KEYBOARD_RETURN 0x28 +#define RAW_KEYBOARD_ESC 0x29 +#define RAW_KEYBOARD_INSERT 0x49 +#define RAW_KEYBOARD_DELETE 0x4C +#define RAW_KEYBOARD_PAGE_UP 0x4B +#define RAW_KEYBOARD_PAGE_DOWN 0x4E +#define RAW_KEYBOARD_HOME 0x4A +#define RAW_KEYBOARD_END 0x4D +#define RAW_KEYBOARD_CAPS_LOCK 0x39 +#define RAW_KEYBOARD_F1 0x3A +#define RAW_KEYBOARD_F2 0x3B +#define RAW_KEYBOARD_F3 0x3C +#define RAW_KEYBOARD_F4 0x3D +#define RAW_KEYBOARD_F5 0x3E +#define RAW_KEYBOARD_F6 0x3F +#define RAW_KEYBOARD_F7 0x40 +#define RAW_KEYBOARD_F8 0x41 +#define RAW_KEYBOARD_F9 0x42 +#define RAW_KEYBOARD_F10 0x43 +#define RAW_KEYBOARD_F11 0x44 +#define RAW_KEYBOARD_F12 0x45 +#define RAW_KEYBOARD_PRINT 0x46 +#define RAW_KEYBOARD_SCROLL_LOCK 0x47 +#define RAW_KEYBOARD_PAUSE 0x48 + +#define SHIFT 0x80 +static const uint8_t _asciimap[128] PROGMEM = { -private: - KeyReport _keyReport; - void sendReport(KeyReport* keys); + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e | SHIFT, // ! + 0x34 | SHIFT, // " + 0x20 | SHIFT, // # + 0x21 | SHIFT, // $ + 0x22 | SHIFT, // % + 0x24 | SHIFT, // & + 0x34, // ' + 0x26 | SHIFT, // ( + 0x27 | SHIFT, // ) + 0x25 | SHIFT, // * + 0x2e | SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33 | SHIFT, // : + 0x33, // ; + 0x36 | SHIFT, // < + 0x2e, // = + 0x37 | SHIFT, // > + 0x38 | SHIFT, // ? + 0x1f | SHIFT, // @ + 0x04 | SHIFT, // A + 0x05 | SHIFT, // B + 0x06 | SHIFT, // C + 0x07 | SHIFT, // D + 0x08 | SHIFT, // E + 0x09 | SHIFT, // F + 0x0a | SHIFT, // G + 0x0b | SHIFT, // H + 0x0c | SHIFT, // I + 0x0d | SHIFT, // J + 0x0e | SHIFT, // K + 0x0f | SHIFT, // L + 0x10 | SHIFT, // M + 0x11 | SHIFT, // N + 0x12 | SHIFT, // O + 0x13 | SHIFT, // P + 0x14 | SHIFT, // Q + 0x15 | SHIFT, // R + 0x16 | SHIFT, // S + 0x17 | SHIFT, // T + 0x18 | SHIFT, // U + 0x19 | SHIFT, // V + 0x1a | SHIFT, // W + 0x1b | SHIFT, // X + 0x1c | SHIFT, // Y + 0x1d | SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23 | SHIFT, // ^ + 0x2d | SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f | SHIFT, // + 0x31 | SHIFT, // | + 0x30 | SHIFT, // } + 0x35 | SHIFT, // ~ + 0 // DEL +}; + +typedef union{ + // Low level key report: up to 6 keys and shift, ctrl etc at once + uint8_t whole8[8]; + uint16_t whole16[8 / 2]; + uint32_t whole32[8 / 4]; + + struct{ + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; + }; +} HID_KeyboardReport_Data_t; + +class Keyboard_ : public Print{ public: - Keyboard_(void); - void begin(void); - void end(void); - virtual size_t write(uint8_t k); - virtual size_t press(uint8_t k); - virtual size_t release(uint8_t k); - virtual void releaseAll(void); + inline Keyboard_(void){ + // empty + } + + inline void begin(void){ + end(); + } + + inline void end(void){ + // edit by NicoHood + releaseAll(); + } + + inline size_t write(uint8_t c){ + uint8_t p = press(c); // Keydown + release(c); // Keyup + return (p); // just return the result of press() since release() almost always returns 1 + } + + // press() adds the specified key (printing, non-printing, or modifier) + // to the persistent key report and sends the report. Because of the way + // USB HID works, the host acts like the key remains pressed until we + // call release(), releaseAll(), or otherwise clear the report and resend. + inline size_t press(uint8_t k) + { + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } + else if (k >= 128) { // it's a modifier key + _keyReport.modifiers |= (1 << (k - 128)); + k = 0; + } + else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + setWriteError(); + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers |= 0x02; // the left shift modifier + k &= 0x7F; + } + } + + // Add k to the key report only if it's not already present + // and if there is an empty slot. + if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && + _keyReport.keys[2] != k && _keyReport.keys[3] != k && + _keyReport.keys[4] != k && _keyReport.keys[5] != k) { + + for (i = 0; i < 6; i++) { + if (_keyReport.keys[i] == 0x00) { + _keyReport.keys[i] = k; + break; + } + } + if (i == 6) { + setWriteError(); + return 0; + } + } + sendReport(&_keyReport); + return 1; + } + + // release() takes the specified key out of the persistent key report and + // sends the report. This tells the OS the key is no longer pressed and that + // it shouldn't be repeated any more. + inline size_t release(uint8_t k) + { + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } + else if (k >= 128) { // it's a modifier key + _keyReport.modifiers &= ~(1 << (k - 128)); + k = 0; + } + else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers &= ~(0x02); // the left shift modifier + k &= 0x7F; + } + } + + // Test the key report to see if k is present. Clear it if it exists. + // Check all positions in case the key is present more than once (which it shouldn't be) + for (i = 0; i < 6; i++) { + if (0 != k && _keyReport.keys[i] == k) { + _keyReport.keys[i] = 0x00; + } + } + + sendReport(&_keyReport); + return 1; + } + + inline void releaseAll(void){ + // release all keys + memset(&_keyReport, 0x00, sizeof(_keyReport)); + sendReport(&_keyReport); + } + +private: + HID_KeyboardReport_Data_t _keyReport; + inline void sendReport(HID_KeyboardReport_Data_t* keys){ + HID_SendReport(HID_REPORTID_KeyboardReport, &_keyReport, sizeof(_keyReport)); + } }; extern Keyboard_ Keyboard; -//================================================================================ -//================================================================================ -// Low level API +#endif -typedef struct -{ - uint8_t bmRequestType; - uint8_t bRequest; - uint8_t wValueL; - uint8_t wValueH; - uint16_t wIndex; - uint16_t wLength; -} Setup; - -//================================================================================ -//================================================================================ -// HID 'Driver' - -int HID_GetInterface(uint8_t* interfaceNum); -int HID_GetDescriptor(int i); -bool HID_Setup(Setup& setup); -void HID_SendReport(uint8_t id, const void* data, int len); - -//================================================================================ -//================================================================================ -// MSC 'Driver' - -int MSC_GetInterface(uint8_t* interfaceNum); -int MSC_GetDescriptor(int i); -bool MSC_Setup(Setup& setup); -bool MSC_Data(uint8_t rx,uint8_t tx); - -//================================================================================ -//================================================================================ -// CSC 'Driver' - -int CDC_GetInterface(uint8_t* interfaceNum); -int CDC_GetDescriptor(int i); -bool CDC_Setup(Setup& setup); //================================================================================ +// RawHID //================================================================================ -#define TRANSFER_PGM 0x80 -#define TRANSFER_RELEASE 0x40 -#define TRANSFER_ZERO 0x20 +#ifdef HID_RAWHID_ENABLED -int USB_SendControl(uint8_t flags, const void* d, int len); -int USB_RecvControl(void* d, int len); +#define LSB(_x) ((_x) & 0xFF) +#define MSB(_x) ((_x) >> 8) -uint8_t USB_Available(uint8_t ep); -int USB_Send(uint8_t ep, const void* data, int len); // blocking -int USB_Recv(uint8_t ep, void* data, int len); // non-blocking -int USB_Recv(uint8_t ep); // non-blocking -void USB_Flush(uint8_t ep); +//TODO +#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF +#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF +#define RAWHID_TX_SIZE 64 //TODO 16? +#define RAWHID_RX_SIZE 64 +//#define RAWHID_TX_SIZE 15 // 1 byte for report ID +//#define RAWHID_RX_SIZE 15 // 1 byte for report ID + +typedef union{ + // a RAWHID_TX_SIZE byte buffer for rx or tx + uint8_t whole8[RAWHID_TX_SIZE]; + uint16_t whole16[RAWHID_TX_SIZE / 2]; + uint32_t whole32[RAWHID_TX_SIZE / 4]; + uint8_t buff[RAWHID_TX_SIZE]; +} HID_RawKeyboardReport_Data_t; + +class RawHID_ : public Print{ +public: + inline RawHID_(void){ + // empty + } + + inline void begin(void){ + // empty + } + + inline void end(void){ + // empty + } + + using Print::write; // to get the String version of write + inline size_t write(uint8_t b){ + write(&b, 1); + } + + inline size_t write(const uint8_t *buffer, size_t size){ + size_t bytesleft = size; + // first work through the buffer thats already there + while (bytesleft >= RAWHID_RX_SIZE){ + HID_SendReport(HID_REPORTID_RawKeyboardReport, &buffer[size - bytesleft], RAWHID_RX_SIZE); + bytesleft -= RAWHID_RX_SIZE; + } + // write down the other bytes and fill with zeros + if (bytesleft){ + uint8_t rest[RAWHID_RX_SIZE]; + memcpy(rest, &buffer[size - bytesleft], bytesleft); + memset(&rest[bytesleft], 0, RAWHID_RX_SIZE - bytesleft); + HID_SendReport(HID_REPORTID_RawKeyboardReport, &rest, RAWHID_RX_SIZE); + } + } +}; +extern RawHID_ RawHID; #endif -#endif /* if defined(USBCON) */ + +//================================================================================ +// Media +//================================================================================ + +#ifdef HID_MEDIA_ENABLED + +// Media key definitions, see official USB docs for more +#define MEDIA_FAST_FORWARD 0xB3 +#define MEDIA_REWIND 0xB4 +#define MEDIA_NEXT 0xB5 +#define MEDIA_PREVIOUS 0xB6 +#define MEDIA_STOP 0xB7 +#define MEDIA_PLAY_PAUSE 0xCD + +#define MEDIA_VOLUME_MUTE 0xE2 +#define MEDIA_VOLUME_UP 0xE9 +#define MEDIA_VOLUME_DOWN 0xEA + +#define MEDIA_EMAIL_READER 0x18A +#define MEDIA_CALCULATOR 0x192 +#define MEDIA_EXPLORER 0x194 + +#define MEDIA_BROWSER_HOME 0x223 +#define MEDIA_BROWSER_BACK 0x224 +#define MEDIA_BROWSER_FORWARD 0x225 +#define MEDIA_BROWSER_REFRESH 0x227 +#define MEDIA_BROWSER_BOOKMARKS 0x22A + +typedef union{ + // every usable media key possible, up to 4 keys presses possible + uint8_t whole8[8]; + uint16_t whole16[8 / 2]; + uint32_t whole32[8 / 4]; + + struct{ + uint16_t key1; + uint16_t key2; + uint16_t key3; + uint16_t key4; + }; +} HID_MediaReport_Data_t; + +class Media_{ +public: + inline Media_(void){ + // empty + } + + inline void begin(void){ + // release all buttons + end(); + } + + inline void end(void){ + memset(&_report, 0, sizeof(_report)); + HID_SendReport(HID_REPORTID_MediaReport, &_report, sizeof(_report)); + } + + inline void write(uint16_t m){ + press(m); + release(m); + } + + inline void press(uint16_t m){ + // search for a free spot + for (int i = 0; i < sizeof(HID_MediaReport_Data_t) / 2; i++) { + if (_report.whole16[i] == 0x00) { + _report.whole16[i] = m; + break; + } + } + HID_SendReport(HID_REPORTID_MediaReport, &_report, sizeof(_report)); + } + + inline void release(uint16_t m){ + // search and release the keypress + for (int i = 0; i < sizeof(HID_MediaReport_Data_t) / 2; i++) { + if (_report.whole16[i] == m) { + _report.whole16[i] = 0x00; + // no break to delete multiple keys + } + } + HID_SendReport(HID_REPORTID_MediaReport, &_report, sizeof(_report)); + } + + inline void releaseAll(void){ + begin(); + } +private: + HID_MediaReport_Data_t _report; +}; +extern Media_ Media; + +#endif + + +//================================================================================ +// System +//================================================================================ + +#ifdef HID_SYSTEM_ENABLED + +#define SYSTEM_POWER_DOWN 0x81 +#define SYSTEM_SLEEP 0x82 +#define SYSTEM_WAKE_UP 0x83 + +typedef union{ + // every usable system control key possible + uint8_t whole8[1]; + uint8_t key; +} HID_SystemReport_Data_t; + +class System_{ +public: + inline System_(void){ + // empty + } + + inline void begin(void){ + // release all buttons + end(); + } + + inline void end(void){ + uint8_t _report = 0; + HID_SendReport(HID_REPORTID_SystemReport, &_report, sizeof(_report)); + } + + inline void write(uint8_t s){ + press(s); + release(); + } + + inline void press(uint8_t s){ + HID_SendReport(HID_REPORTID_SystemReport, &s, sizeof(s)); + } + + inline void release(void){ + begin(); + } + + inline void releaseAll(void){ + begin(); + } +}; +extern System_ System; + +#endif + +//================================================================================ +// Gamepad +//================================================================================ + +#ifdef HID_GAMEPAD_ENABLED + +// Dpad directions +#define GAMEPAD_DPAD_CENTERED 0 +#define GAMEPAD_DPAD_UP 1 +#define GAMEPAD_DPAD_UP_RIGHT 2 +#define GAMEPAD_DPAD_RIGHT 3 +#define GAMEPAD_DPAD_DOWN_RIGHT 4 +#define GAMEPAD_DPAD_DOWN 5 +#define GAMEPAD_DPAD_DOWN_LEFT 6 +#define GAMEPAD_DPAD_LEFT 7 +#define GAMEPAD_DPAD_UP_LEFT 8 + +typedef union { + // 32 Buttons, 6 Axis, 2 D-Pads + uint8_t whole8[15]; + uint16_t whole16[15 / 2]; + uint32_t whole32[15 / 4]; + uint32_t buttons; + + struct{ + uint8_t button1 : 1; + uint8_t button2 : 1; + uint8_t button3 : 1; + uint8_t button4 : 1; + uint8_t button5 : 1; + uint8_t button6 : 1; + uint8_t button7 : 1; + uint8_t button8 : 1; + + uint8_t button9 : 1; + uint8_t button10 : 1; + uint8_t button11 : 1; + uint8_t button12 : 1; + uint8_t button13 : 1; + uint8_t button14 : 1; + uint8_t button15 : 1; + uint8_t button16 : 1; + + uint8_t button17 : 1; + uint8_t button18 : 1; + uint8_t button19 : 1; + uint8_t button20 : 1; + uint8_t button21 : 1; + uint8_t button22 : 1; + uint8_t button23 : 1; + uint8_t button24 : 1; + + uint8_t button25 : 1; + uint8_t button26 : 1; + uint8_t button27 : 1; + uint8_t button28 : 1; + uint8_t button29 : 1; + uint8_t button30 : 1; + uint8_t button31 : 1; + uint8_t button32 : 1; + + int16_t xAxis; + int16_t yAxis; + + int16_t rxAxis; + int16_t ryAxis; + + int8_t zAxis; + int8_t rzAxis; + + uint8_t dPad1 : 4; + uint8_t dPad2 : 4; + }; +} HID_GamepadReport_Data_t; + +class Gamepad_{ +public: + inline Gamepad_(void){ + // empty + } + + inline void begin(void){ + // release all buttons + end(); + } + + inline void end(void){ + memset(&_report, 0, sizeof(_report)); + HID_SendReport(HID_REPORTID_GamepadReport, &_report, sizeof(_report)); + } + + inline void write(void){ HID_SendReport(HID_REPORTID_GamepadReport, &_report, sizeof(_report)); } + inline void press(uint8_t b){ _report.buttons |= (uint32_t)1 << (b - 1); } + inline void release(uint8_t b){ _report.buttons &= ~((uint32_t)1 << (b - 1)); } + inline void releaseAll(void){ memset(&_report, 0x00, sizeof(_report)); } + + inline void buttons(uint32_t b){ _report.buttons = b; } + inline void xAxis(int16_t a){ _report.xAxis = a; } + inline void yAxis(int16_t a){ _report.yAxis = a; } + inline void zAxis(int8_t a){ _report.zAxis = a; } + inline void rxAxis(int16_t a){ _report.rxAxis = a; } + inline void ryAxis(int16_t a){ _report.ryAxis = a; } + inline void rzAxis(int8_t a){ _report.rzAxis = a; } + inline void dPad1(int8_t d){ _report.dPad1 = d; } + inline void dPad2(int8_t d){ _report.dPad2 = d; } +private: + HID_GamepadReport_Data_t _report; +}; +extern Gamepad_ Gamepad; + +#endif + +#endif // if defined(USBCON) || defined(USE_USB_API) + +#endif /* if defined(__USBAPI__) */ diff --git a/USBCore.cpp b/USBCore.cpp index b4f7bed..b95b50f 100644 --- a/USBCore.cpp +++ b/USBCore.cpp @@ -1,19 +1,42 @@ -/* Copyright (c) 2010, 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. +/* Copyright (c) 2010, 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. +*/ + +/* +Copyright (c) 2014 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 "USBAPI.h" @@ -43,7 +66,7 @@ extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM; extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM; const u16 STRING_LANGUAGE[2] = { - (3<<8) | (2+2), + (3 << 8) | (2 + 2), 0x0409 // English }; @@ -78,12 +101,13 @@ const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER; #define DEVICE_CLASS 0x00 #endif +//TODO warning from USBlyzer with a 16u2 // DEVICE DESCRIPTOR const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +D_DEVICE(0x00, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); const DeviceDescriptor USB_DeviceDescriptorA = - D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +D_DEVICE(DEVICE_CLASS, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); //================================================================== //================================================================== @@ -92,40 +116,40 @@ volatile u8 _usbConfiguration = 0; static inline void WaitIN(void) { - while (!(UEINTX & (1<