From 966748f72790f517a4996a5a8e4f947708e0bc37 Mon Sep 17 00:00:00 2001 From: Michael Dreher Date: Sat, 29 Jun 2013 23:02:25 +0200 Subject: [PATCH 1/9] Wakeup for USB host. First clean version --- hardware/arduino/cores/arduino/USBAPI.h | 1 + hardware/arduino/cores/arduino/USBCore.cpp | 45 +++++++++++++++++++++- hardware/arduino/cores/arduino/USBCore.h | 11 +++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index eb2e5937db0..1aecaacf4df 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -18,6 +18,7 @@ class USBDevice_ void attach(); void detach(); // Serial port goes down too... void poll(); + bool wakeupHost(); // returns false, when wakeup cannot be processed }; extern USBDevice_ USBDevice; diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index d3e01706567..1d4b1d40f1f 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -92,6 +92,7 @@ const DeviceDescriptor USB_DeviceDescriptorA = //================================================================== volatile u8 _usbConfiguration = 0; +volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device static inline void WaitIN(void) { @@ -527,16 +528,37 @@ ISR(USB_COM_vect) { // Standard Requests u8 r = setup.bRequest; + u16 wValue = setup.wValueL | (setup.wValueH << 8); if (GET_STATUS == r) { - Send8(0); // TODO - Send8(0); + if(requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE)) + { + Send8(_usbCurrentStatus); + Send8(0); + } + else + { + // TODO: handle the HALT state of an endpoint here + // see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information + Send8(0); + Send8(0); + } } else if (CLEAR_FEATURE == r) { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED; + } } else if (SET_FEATURE == r) { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED; + } } else if (SET_ADDRESS == r) { @@ -644,6 +666,7 @@ USBDevice_::USBDevice_() void USBDevice_::attach() { _usbConfiguration = 0; + _usbCurrentStatus = 0; UHWCON = 0x01; // power internal reg USBCON = (1< Date: Tue, 2 Jul 2013 21:48:57 +0200 Subject: [PATCH 2/9] Added first part of SUSPEND / WAKEUP handling; store SUSPI in _usbSuspendState --- hardware/arduino/cores/arduino/USBCore.cpp | 82 +++++++++++++++++----- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index 1d4b1d40f1f..cb9bf040b51 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -93,6 +93,7 @@ const DeviceDescriptor USB_DeviceDescriptorA = volatile u8 _usbConfiguration = 0; volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device +volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits static inline void WaitIN(void) { @@ -614,11 +615,39 @@ void USB_Flush(u8 ep) ReleaseTX(); } +static inline void USB_ClockDisable() +{ + USBCON = (USBCON & ~(1< Date: Tue, 2 Jul 2013 23:17:18 +0200 Subject: [PATCH 3/9] initialize _usbSuspendState in USBDevice_::attach --- hardware/arduino/cores/arduino/USBCore.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index cb9bf040b51..6f661760388 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -640,6 +640,7 @@ static inline void USB_ClockEnable() // port touch at 1200 bps. This delay fixes this behaviour. delay(1); USBCON = (USBCON & ~(1< Date: Fri, 5 Jul 2013 20:53:00 +0200 Subject: [PATCH 4/9] Added support to press power/sleep/hibernate (and some more) buttons via System Controls. Implemented in Keyboard_::systemControl(). --- hardware/arduino/cores/arduino/HID.cpp | 94 +++++++++++++++++++--- hardware/arduino/cores/arduino/USBAPI.h | 27 ++++++- hardware/arduino/cores/arduino/USBCore.cpp | 2 + 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/hardware/arduino/cores/arduino/HID.cpp b/hardware/arduino/cores/arduino/HID.cpp index ac636084493..9e64f206465 100644 --- a/hardware/arduino/cores/arduino/HID.cpp +++ b/hardware/arduino/cores/arduino/HID.cpp @@ -2,6 +2,8 @@ /* Copyright (c) 2011, Peter Barrett ** +** Sleep/Wakeup/SystemControl support added by Michael Dreher +** ** 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. @@ -43,16 +45,20 @@ Keyboard_ Keyboard; #define RAWHID_TX_SIZE 64 #define RAWHID_RX_SIZE 64 +#define HID_REPORTID_MOUSE (1) +#define HID_REPORTID_KEYBOARD (2) +#define HID_REPORTID_RAWHID (3) +#define HID_REPORTID_SYSTEMCONTROL (4) extern const u8 _hidReportDescriptor[] PROGMEM; const u8 _hidReportDescriptor[] = { - // Mouse + // 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) + 0x85, HID_REPORTID_MOUSE, // REPORT_ID (1) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) @@ -76,43 +82,73 @@ const u8 _hidReportDescriptor[] = { 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION - // Keyboard + // Keyboard 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) + 0x85, HID_REPORTID_KEYBOARD, // REPORT_ID (2) 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 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) + 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) + + 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)) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0, // END_COLLECTION + // System Control (Power Down, Sleep, Wakeup, ...) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x80, // USAGE (System Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, HID_REPORTID_SYSTEMCONTROL,// REPORT_ID (4) + 0x09, 0x81, // USAGE (System Power Down) + 0x09, 0x82, // USAGE (System Sleep) + 0x09, 0x83, // USAGE (System Wakeup) + 0x09, 0x8E, // USAGE (System Cold Restart) + 0x09, 0x8F, // USAGE (System Warm Restart) + 0x09, 0xA0, // USAGE (System Dock) + 0x09, 0xA1, // USAGE (System Undock) + 0x09, 0xA7, // USAGE (System Speaker Mute) + 0x09, 0xA8, // USAGE (System Hibernate) + // although these display usages are not that important, they don't cost much more than declaring + // the otherwise necessary constant fill bits + 0x09, 0xB0, // USAGE (System Display Invert) + 0x09, 0xB1, // USAGE (System Display Internal) + 0x09, 0xB2, // USAGE (System Display External) + 0x09, 0xB3, // USAGE (System Display Both) + 0x09, 0xB4, // USAGE (System Display Dual) + 0x09, 0xB5, // USAGE (System Display Toggle Intern/Extern) + 0x09, 0xB6, // USAGE (System Display Swap) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x10, // REPORT_COUNT (16) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + #if 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) + 0x85, HID_REPORTID_RAWHID, // REPORT_ID (3) 0x75, 0x08, // report size = 8 bits 0x15, 0x00, // logical minimum = 0 0x26, 0xFF, 0x00, // logical maximum = 255 @@ -228,7 +264,7 @@ void Mouse_::move(signed char x, signed char y, signed char wheel) m[1] = x; m[2] = y; m[3] = wheel; - HID_SendReport(1,m,4); + HID_SendReport(HID_REPORTID_MOUSE,m,sizeof(m)); } void Mouse_::buttons(uint8_t b) @@ -275,7 +311,7 @@ void Keyboard_::end(void) void Keyboard_::sendReport(KeyReport* keys) { - HID_SendReport(2,keys,sizeof(KeyReport)); + HID_SendReport(HID_REPORTID_KEYBOARD,keys,sizeof(*keys)); } extern @@ -462,6 +498,38 @@ size_t Keyboard_::press(uint8_t k) return 1; } +// System Control +// k is one of the SYSTEM_CONTROL defines which come from the HID usage table "Generic Desktop Page (0x01)" +// in "HID Usage Tables" (HUT1_12v2.pdf) +size_t Keyboard_::systemControl(uint8_t k) +{ + if(k <= 16) + { + u16 mask = 0; + u8 m[2]; + + if(k > 0) + { + mask = 1 << (k - 1); + } + + m[0] = LSB(mask); + m[1] = MSB(mask); + HID_SendReport(HID_REPORTID_SYSTEMCONTROL,m,sizeof(m)); + + // these are all OSCs, so send a clear to make it possible to send it again later + m[0] = 0; + m[1] = 0; + HID_SendReport(HID_REPORTID_SYSTEMCONTROL,m,sizeof(m)); + return 1; + } + else + { + setWriteError(); + return 0; + } +} + // 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. @@ -517,4 +585,4 @@ size_t Keyboard_::write(uint8_t c) #endif -#endif /* if defined(USBCON) */ \ No newline at end of file +#endif /* if defined(USBCON) */ diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index 1aecaacf4df..39873fd5136 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -112,6 +112,30 @@ extern Mouse_ Mouse; #define KEY_F11 0xCC #define KEY_F12 0xCD + +// System Control values for Keyboard_::systemControl() +// these defines come from the HID usage table "Generic Desktop Page (0x01)" +// in the USB standard document "HID Usage Tables" (HUT1_12v2.pdf) +// Currently this list contains only OSC (one shot control) values, +// the implementation of systemControl will have to be changed when +// adding OOC or RTC values. +#define SYSTEM_CONTROL_POWER_DOWN 1 +#define SYSTEM_CONTROL_SLEEP 2 +#define SYSTEM_CONTROL_WAKEUP 3 +#define SYSTEM_CONTROL_COLD_RESTART 4 +#define SYSTEM_CONTROL_WARM_RESTART 5 +#define SYSTEM_CONTROL_DOCK 6 +#define SYSTEM_CONTROL_UNDOCK 7 +#define SYSTEM_CONTROL_SPEAKER_MUTE 8 +#define SYSTEM_CONTROL_HIBERNATE 9 +#define SYSTEM_CONTROL_DISPLAY_INVERT 10 +#define SYSTEM_CONTROL_DISPLAY_INTERNAL 11 +#define SYSTEM_CONTROL_DISPLAY_EXTERNAL 12 +#define SYSTEM_CONTROL_DISPLAY_BOTH 13 +#define SYSTEM_CONTROL_DISPLAY_DUAL 14 +#define SYSTEM_CONTROL_DISPLAY_TOGGLE_INT_EXT 15 +#define SYSTEM_CONTROL_DISPLAY_SWAP 16 + // Low level key report: up to 6 keys and shift, ctrl etc at once typedef struct { @@ -133,6 +157,7 @@ class Keyboard_ : public Print virtual size_t press(uint8_t k); virtual size_t release(uint8_t k); virtual void releaseAll(void); + virtual size_t systemControl(uint8_t k); }; extern Keyboard_ Keyboard; @@ -194,4 +219,4 @@ void USB_Flush(uint8_t ep); #endif -#endif /* if defined(USBCON) */ \ No newline at end of file +#endif /* if defined(USBCON) */ diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index 6f661760388..558a57ab157 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -2,6 +2,8 @@ /* Copyright (c) 2010, Peter Barrett ** +** Sleep/Wakeup/SystemControl support added by Michael Dreher +** ** 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. From 5456707b2406546290797a108224cc312eb031f5 Mon Sep 17 00:00:00 2001 From: Michael Dreher Date: Sat, 13 Jul 2013 16:55:33 +0200 Subject: [PATCH 5/9] Added Keyboard.pressRaw(), releaseRaw() and writeRaw() to make it possible to send other keys than just ASCII --- hardware/arduino/cores/arduino/HID.cpp | 128 ++++++++++++--------- hardware/arduino/cores/arduino/USBAPI.h | 3 + hardware/arduino/cores/arduino/USBCore.cpp | 50 ++++++-- 3 files changed, 115 insertions(+), 66 deletions(-) diff --git a/hardware/arduino/cores/arduino/HID.cpp b/hardware/arduino/cores/arduino/HID.cpp index 9e64f206465..f97fb511aa6 100644 --- a/hardware/arduino/cores/arduino/HID.cpp +++ b/hardware/arduino/cores/arduino/HID.cpp @@ -89,6 +89,7 @@ const u8 _hidReportDescriptor[] = { 0x85, HID_REPORTID_KEYBOARD, // REPORT_ID (2) 0x05, 0x07, // USAGE_PAGE (Keyboard) + // Keyboard Modifiers (shift, alt, ...) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) @@ -101,14 +102,14 @@ const u8 _hidReportDescriptor[] = { 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) + // Keyboard keys 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x26, 0xDF, 0x00, // LOGICAL_MAXIMUM (239) 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x29, 0xDF, // USAGE_MAXIMUM (Left Control - 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0, // END_COLLECTION @@ -457,9 +458,33 @@ uint8_t USBPutChar(uint8_t c); // 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) +size_t Keyboard_::pressRaw(uint8_t k) { uint8_t i; + // 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 || (k >= 0xE0)) { + setWriteError(); + return 0; + } + } + sendReport(&_keyReport); + return 1; +} + +// translates ASCII characters to usage +size_t Keyboard_::press(uint8_t k) +{ if (k >= 136) { // it's a non-printing key (not a modifier) k = k - 136; } else if (k >= 128) { // it's a modifier key @@ -476,28 +501,48 @@ size_t Keyboard_::press(uint8_t k) 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; - } + return pressRaw(k); +} + +// 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_::releaseRaw(uint8_t k) +{ + uint8_t i; + // 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; } - if (i == 6) { - setWriteError(); - return 0; - } } + sendReport(&_keyReport); return 1; } +// translates ASCII characters to usage +size_t Keyboard_::release(uint8_t k) +{ + 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; + } + } + return releaseRaw(k); +} + // System Control // k is one of the SYSTEM_CONTROL defines which come from the HID usage table "Generic Desktop Page (0x01)" // in "HID Usage Tables" (HUT1_12v2.pdf) @@ -530,40 +575,6 @@ size_t Keyboard_::systemControl(uint8_t k) } } -// 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; @@ -576,10 +587,17 @@ void Keyboard_::releaseAll(void) sendReport(&_keyReport); } +size_t Keyboard_::writeRaw(uint8_t c) +{ + uint8_t p = pressRaw(c); // Keydown + releaseRaw(c); // Keyup + return (p); // just return the result of press() since release() almost always returns 1 +} + size_t Keyboard_::write(uint8_t c) { uint8_t p = press(c); // Keydown - uint8_t r = release(c); // Keyup + release(c); // Keyup return (p); // just return the result of press() since release() almost always returns 1 } diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index 39873fd5136..68e41f42ec7 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -154,8 +154,11 @@ class Keyboard_ : public Print void begin(void); void end(void); virtual size_t write(uint8_t k); + virtual size_t writeRaw(uint8_t c); virtual size_t press(uint8_t k); + virtual size_t pressRaw(uint8_t k); virtual size_t release(uint8_t k); + virtual size_t releaseRaw(uint8_t k); virtual void releaseAll(void); virtual size_t systemControl(uint8_t k); }; diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index 558a57ab157..fc867f31e43 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -24,13 +24,13 @@ #if defined(USBCON) -#define EP_TYPE_CONTROL 0x00 -#define EP_TYPE_BULK_IN 0x81 -#define EP_TYPE_BULK_OUT 0x80 -#define EP_TYPE_INTERRUPT_IN 0xC1 -#define EP_TYPE_INTERRUPT_OUT 0xC0 -#define EP_TYPE_ISOCHRONOUS_IN 0x41 -#define EP_TYPE_ISOCHRONOUS_OUT 0x40 +#define EP_TYPE_CONTROL (0x00) +#define EP_TYPE_BULK_IN ((1< Date: Sun, 14 Jul 2013 09:26:25 +0200 Subject: [PATCH 6/9] Added error messages when USB chip is unknown or clock rate is not supported --- hardware/arduino/cores/arduino/USBCore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index fc867f31e43..22b816e69a2 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -634,6 +634,8 @@ static inline void USB_ClockEnable() PLLCSR |= (1< Date: Thu, 18 Jul 2013 10:20:46 +0200 Subject: [PATCH 7/9] removed pressRaw + releaseRaw because this functionality is already contained in the fix for issue #1391 and the code was redundant --- hardware/arduino/cores/arduino/HID.cpp | 121 ++++++++++-------------- hardware/arduino/cores/arduino/USBAPI.h | 3 - 2 files changed, 52 insertions(+), 72 deletions(-) diff --git a/hardware/arduino/cores/arduino/HID.cpp b/hardware/arduino/cores/arduino/HID.cpp index f97fb511aa6..3f8967d2441 100644 --- a/hardware/arduino/cores/arduino/HID.cpp +++ b/hardware/arduino/cores/arduino/HID.cpp @@ -458,33 +458,9 @@ uint8_t USBPutChar(uint8_t c); // 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_::pressRaw(uint8_t k) -{ - uint8_t i; - // 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 || (k >= 0xE0)) { - setWriteError(); - return 0; - } - } - sendReport(&_keyReport); - return 1; -} - -// translates ASCII characters to usage 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 @@ -501,48 +477,28 @@ size_t Keyboard_::press(uint8_t k) k &= 0x7F; } } - return pressRaw(k); -} - -// 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_::releaseRaw(uint8_t k) -{ - uint8_t i; - // 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; + + // 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; } -// translates ASCII characters to usage -size_t Keyboard_::release(uint8_t k) -{ - 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; - } - } - return releaseRaw(k); -} - // System Control // k is one of the SYSTEM_CONTROL defines which come from the HID usage table "Generic Desktop Page (0x01)" // in "HID Usage Tables" (HUT1_12v2.pdf) @@ -575,6 +531,40 @@ size_t Keyboard_::systemControl(uint8_t k) } } +// 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; @@ -587,17 +577,10 @@ void Keyboard_::releaseAll(void) sendReport(&_keyReport); } -size_t Keyboard_::writeRaw(uint8_t c) -{ - uint8_t p = pressRaw(c); // Keydown - releaseRaw(c); // Keyup - return (p); // just return the result of press() since release() almost always returns 1 -} - size_t Keyboard_::write(uint8_t c) { uint8_t p = press(c); // Keydown - release(c); // Keyup + uint8_t r = release(c); // Keyup return (p); // just return the result of press() since release() almost always returns 1 } diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index 68e41f42ec7..39873fd5136 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -154,11 +154,8 @@ class Keyboard_ : public Print void begin(void); void end(void); virtual size_t write(uint8_t k); - virtual size_t writeRaw(uint8_t c); virtual size_t press(uint8_t k); - virtual size_t pressRaw(uint8_t k); virtual size_t release(uint8_t k); - virtual size_t releaseRaw(uint8_t k); virtual void releaseAll(void); virtual size_t systemControl(uint8_t k); }; From 674ab3beda7589aa88f08dea0e5bfc74472a6966 Mon Sep 17 00:00:00 2001 From: Michael Dreher Date: Thu, 18 Jul 2013 21:29:29 +0200 Subject: [PATCH 8/9] Added error message when method of USB PLL initialization is unknown. --- hardware/arduino/cores/arduino/USBCore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hardware/arduino/cores/arduino/USBCore.cpp b/hardware/arduino/cores/arduino/USBCore.cpp index 22b816e69a2..113926e39f3 100644 --- a/hardware/arduino/cores/arduino/USBCore.cpp +++ b/hardware/arduino/cores/arduino/USBCore.cpp @@ -656,6 +656,8 @@ static inline void USB_ClockEnable() #else #error "Clock rate of F_CPU not supported" #endif +#else +#error "USB Chip not supported, please defined method of USB PLL initialization" #endif PLLCSR |= (1< Date: Sun, 21 Jul 2013 13:18:39 +0200 Subject: [PATCH 9/9] added Mouse.moveAbs() as a new feature for absolute mouse positioning as requested in issue #1417. all parameters have the range of -32768 to 32767 and must be scaled to screen pixels some examples: x=0, y=0 is the middle of the screen x=-32768, y=-32768 is the top left corner x=32767, y=-32768 is the top right corner x=32767, y=32767 is the bottom right corner x=-32768, y=32767 is the bottom left corner --- hardware/arduino/cores/arduino/HID.cpp | 57 ++++++++++++++++++++++++- hardware/arduino/cores/arduino/USBAPI.h | 4 ++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/hardware/arduino/cores/arduino/HID.cpp b/hardware/arduino/cores/arduino/HID.cpp index 3f8967d2441..3f820095e4d 100644 --- a/hardware/arduino/cores/arduino/HID.cpp +++ b/hardware/arduino/cores/arduino/HID.cpp @@ -49,10 +49,11 @@ Keyboard_ Keyboard; #define HID_REPORTID_KEYBOARD (2) #define HID_REPORTID_RAWHID (3) #define HID_REPORTID_SYSTEMCONTROL (4) +#define HID_REPORTID_MOUSE_ABS (5) extern const u8 _hidReportDescriptor[] PROGMEM; const u8 _hidReportDescriptor[] = { - // Mouse + // Mouse relative 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) @@ -82,6 +83,38 @@ const u8 _hidReportDescriptor[] = { 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION +#ifdef MOUSE_ABS_ENABLED + // Mouse absolute + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x85, HID_REPORTID_MOUSE_ABS, // REPORT_ID (5) + 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) + 0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768) + 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +#endif + // Keyboard 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 0x09, 0x06, // USAGE (Keyboard) @@ -268,6 +301,28 @@ void Mouse_::move(signed char x, signed char y, signed char wheel) HID_SendReport(HID_REPORTID_MOUSE,m,sizeof(m)); } +#ifdef MOUSE_ABS_ENABLED +// all parameters have the range of -32768 to 32767 and must be scaled to screen pixels +// some examples: +// x=0,y=0 is the middle of the screen +// x=-32768,y=-32768 is the top left corner +// x=32767,y=-32768 is the top right corner +// x=32767,y=32767 is the bottom right corner +// x=-32768,y=32767 is the bottom left corner +void Mouse_::moveAbs(int16_t x, int16_t y, int16_t wheel) +{ + u8 m[7]; + m[0] = _buttons; // TODO: is it a good idea to take over the _buttons from relative report here or should it be left out? + m[1] = LSB(x); + m[2] = MSB(x); + m[3] = LSB(y); + m[4] = MSB(y); + m[5] = LSB(wheel); + m[6] = MSB(wheel); + HID_SendReport(HID_REPORTID_MOUSE_ABS,m,sizeof(m)); +} +#endif + void Mouse_::buttons(uint8_t b) { if (b != _buttons) diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index 39873fd5136..97d7cff21e7 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -4,6 +4,7 @@ #define __USBAPI__ #if defined(USBCON) +#define MOUSE_ABS_ENABLED //================================================================================ //================================================================================ @@ -65,6 +66,9 @@ class Mouse_ void end(void); void click(uint8_t b = MOUSE_LEFT); void move(signed char x, signed char y, signed char wheel = 0); +#ifdef MOUSE_ABS_ENABLED + void moveAbs(int16_t x, int16_t y, int16_t wheel); // all parameters have the range of -32768 to 32767 and must be scaled to screen pixels +#endif 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