| /* 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 "Arduino.h" |
| |
| #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 uint8_t _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 |
| |
| // 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) |
| |
| 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) |
| |
| 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) |
| |
| 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) |
| |
| 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) |
| 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) |
| 0x81, 0x00, // INPUT (Data,Ary,Abs) |
| 0xc0, // END_COLLECTION |
| |
| #ifdef 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 |
| |
| 0x95, 64, // 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 |
| #endif |
| }; |
| |
| _Pragma("pack(1)") |
| extern const HIDDescriptor _hidInterface = |
| { |
| 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) |
| }; |
| _Pragma("pack()") |
| |
| //================================================================================ |
| //================================================================================ |
| // Driver |
| |
| uint8_t _hid_protocol = 1; |
| uint8_t _hid_idle = 1; |
| |
| #define WEAK __attribute__ ((weak)) |
| |
| int WEAK HID_GetInterface(uint8_t* interfaceNum) |
| { |
| interfaceNum[0] += 1; // uses 1 |
| return USBD_SendControl(0,&_hidInterface,sizeof(_hidInterface)); |
| } |
| |
| int WEAK HID_GetDescriptor(int i) |
| { |
| return USBD_SendControl(0,_hidReportDescriptor,sizeof(_hidReportDescriptor)); |
| } |
| |
| void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len) |
| { |
| USBD_Send(HID_TX, &id, 1); |
| USBD_Send(HID_TX | TRANSFER_RELEASE,data,len); |
| } |
| |
| bool WEAK HID_Setup(Setup& setup) |
| { |
| 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; |
| } |
| |
| //================================================================================ |
| //================================================================================ |
| // Mouse |
| |
| Mouse_::Mouse_(void) : _buttons(0) |
| { |
| } |
| |
| void Mouse_::begin(void) |
| { |
| } |
| |
| 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) |
| { |
| uint8_t 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; |
| } |
| |
| //================================================================================ |
| //================================================================================ |
| // Keyboard |
| |
| Keyboard_::Keyboard_(void) |
| { |
| } |
| |
| void Keyboard_::begin(void) |
| { |
| } |
| |
| void Keyboard_::end(void) |
| { |
| } |
| |
| void Keyboard_::sendReport(KeyReport* keys) |
| { |
| HID_SendReport(2,keys,sizeof(KeyReport)); |
| } |
| |
| #define SHIFT 0x80 |
| extern 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 = _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 = _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 |
| uint8_t r = release(c); // Keyup |
| return (p); // just return the result of press() since release() almost always returns 1 |
| } |
| |
| #endif |
| |
| #endif /* if defined(USBCON) */ |