From dbe5292471eb0a4c366f2c305d6f328fba5d3a03 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Tue, 10 Oct 2017 18:48:57 -0700 Subject: [PATCH 1/5] Keyboard HID extras plus map extra keys This delta, adds an extra keyboard object to handle those keys that are not part of the main keyboard class. In particular there are separate HID reports for some of the keys, such as Power keys, and multimedia keys. These reports might be on separate Interface or in cases where the mouse and keyboard are on the same device, the extra reports may be on the Mouse Interface. So far I have not tried to combine with Keyboard object as might require multiple inheritance which I would like to avoid. Also I extended the special key mapping table to map several other keys like F1-12, Arrow, Home/end... To special values where the 0x80 bit is set. I used the same values as used for the Arduino Keyboard library. I did not use their defines as they used defines like KEY_F1, which already exists in core, but in core it is the scan code from the keyboard and not the end user value. --- USBHost_t36.h | 59 +++++++++++++++++++- examples/Mouse/Mouse.ino | 75 ++++++++++++++++++++++--- hid.cpp | 16 ++++++ keyboard.cpp | 49 ++++++++++++---- keyboardHIDExtras.cpp | 118 +++++++++++++++++++++++++++++++++++++++ mouse.cpp | 6 +- 6 files changed, 299 insertions(+), 24 deletions(-) create mode 100644 keyboardHIDExtras.cpp diff --git a/USBHost_t36.h b/USBHost_t36.h index cfbe277..c3ec10b 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -56,7 +56,7 @@ // your best effort to read chapter 4 before asking USB questions! -// #define USBHOST_PRINT_DEBUG +//#define USBHOST_PRINT_DEBUG /************************************************/ /* Data Types */ @@ -88,6 +88,31 @@ typedef struct Transfer_struct Transfer_t; class USBDriver; class USBDriverTimer; +/************************************************/ +/* Added Defines */ +/************************************************/ +#define KEYD_UP 0xDA +#define KEYD_DOWN 0xD9 +#define KEYD_LEFT 0xD8 +#define KEYD_RIGHT 0xD7 +#define KEYD_INSERT 0xD1 +#define KEYD_DELETE 0xD4 +#define KEYD_PAGE_UP 0xD3 +#define KEYD_PAGE_DOWN 0xD6 +#define KEYD_HOME 0xD2 +#define KEYD_END 0xD5 +#define KEYD_F1 0xC2 +#define KEYD_F2 0xC3 +#define KEYD_F3 0xC4 +#define KEYD_F4 0xC5 +#define KEYD_F5 0xC6 +#define KEYD_F6 0xC7 +#define KEYD_F7 0xC8 +#define KEYD_F8 0xC9 +#define KEYD_F9 0xCA +#define KEYD_F10 0xCB +#define KEYD_F11 0xCC +#define KEYD_F12 0xCD /************************************************/ /* Data Structure Definitions */ @@ -508,7 +533,7 @@ public: static void driver_ready_for_hid_collection(USBHIDInput *driver); protected: enum { TOPUSAGE_LIST_LEN = 4 }; - enum { USAGE_LIST_LEN = 12 }; + enum { USAGE_LIST_LEN = 24 }; virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); virtual void control(const Transfer_t *transfer); virtual void disconnect(); @@ -763,6 +788,7 @@ protected: private: uint8_t collections_claimed = 0; volatile bool mouseEvent = false; + volatile bool hid_input_begin_ = false; uint8_t buttons = 0; int mouseX = 0; int mouseY = 0; @@ -792,4 +818,33 @@ private: int16_t axis[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; }; + +class KeyboardHIDExtrasController : public USBHIDInput { +public: + KeyboardHIDExtrasController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); } + void clear() { event_ = false;} + bool available() { return event_; } + void attachPress(void (*f)(uint32_t top, uint16_t code)) { keyPressedFunction = f; } + void attachRelease(void (*f)(uint32_t top, uint16_t code)) { keyReleasedFunction = f; } + enum {MAX_KEYS_DOWN=4}; +// uint32_t buttons() { return buttons_; } +protected: + virtual bool claim_collection(Device_t *dev, uint32_t topusage); + virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); + virtual void hid_input_data(uint32_t usage, int32_t value); + virtual void hid_input_end(); + virtual void disconnect_collection(Device_t *dev); +private: + void (*keyPressedFunction)(uint32_t top, uint16_t code); + void (*keyReleasedFunction)(uint32_t top, uint16_t code); + uint32_t topusage_ = 0; // What top report am I processing? + uint8_t collections_claimed_ = 0; + volatile bool event_ = false; + volatile bool hid_input_begin_ = false; + volatile bool hid_input_data_ = false; // did we receive any valid data with report? + uint8_t count_keys_down_ = 0; + uint16_t keys_down[MAX_KEYS_DOWN]; +}; + + #endif diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index 0a72fff..a5836dd 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -10,6 +10,7 @@ USBHub hub2(myusb); USBHub hub3(myusb); KeyboardController keyboard1(myusb); KeyboardController keyboard2(myusb); +KeyboardHIDExtrasController hidextras(myusb); USBHIDParser hid1(myusb); USBHIDParser hid2(myusb); USBHIDParser hid3(myusb); @@ -25,6 +26,8 @@ void setup() myusb.begin(); keyboard1.attachPress(OnPress); keyboard2.attachPress(OnPress); + hidextras.attachPress(OnHIDExtrasPress); + hidextras.attachRelease(OnHIDExtrasRelease); } @@ -68,16 +71,70 @@ void loop() } + void OnPress(int key) { - Serial.print("key '"); - Serial.print((char)key); - Serial.print("' "); - Serial.println(key); - //Serial.print("key "); - //Serial.print((char)keyboard1.getKey()); - //Serial.print(" "); - //Serial.print((char)keyboard2.getKey()); - //Serial.println(); + Serial.print("key '"); + switch (key) { + case KEYD_UP : Serial.print("UP"); break; + case KEYD_DOWN : Serial.print("DN"); break; + case KEYD_LEFT : Serial.print("LEFT"); break; + case KEYD_RIGHT : Serial.print("RIGHT"); break; + case KEYD_INSERT : Serial.print("Ins"); break; + case KEYD_DELETE : Serial.print("Del"); break; + case KEYD_PAGE_UP : Serial.print("PUP"); break; + case KEYD_PAGE_DOWN: Serial.print("PDN"); break; + case KEYD_HOME : Serial.print("HOME"); break; + case KEYD_END : Serial.print("END"); break; + case KEYD_F1 : Serial.print("F1"); break; + case KEYD_F2 : Serial.print("F2"); break; + case KEYD_F3 : Serial.print("F3"); break; + case KEYD_F4 : Serial.print("F4"); break; + case KEYD_F5 : Serial.print("F5"); break; + case KEYD_F6 : Serial.print("F6"); break; + case KEYD_F7 : Serial.print("F7"); break; + case KEYD_F8 : Serial.print("F8"); break; + case KEYD_F9 : Serial.print("F9"); break; + case KEYD_F10 : Serial.print("F10"); break; + case KEYD_F11 : Serial.print("F11"); break; + case KEYD_F12 : Serial.print("F12"); break; + default: Serial.print((char)key); break; + } + Serial.print("' "); + Serial.print(key); + Serial.print(" MOD: "); + if (keyboard1) { + Serial.print(keyboard1.getModifiers(), HEX); + Serial.print(" OEM: "); + Serial.print(keyboard1.getOemKey(), HEX); + Serial.print(" LEDS: "); + Serial.println(keyboard1.LEDS(), HEX); + } else { + Serial.print(keyboard2.getModifiers(), HEX); + Serial.print(" OEM: "); + Serial.print(keyboard2.getOemKey(), HEX); + Serial.print(" LEDS: "); + Serial.println(keyboard2.LEDS(), HEX); + } + + //Serial.print("key "); + //Serial.print((char)keyboard1.getKey()); + //Serial.print(" "); + //Serial.print((char)keyboard2.getKey()); + //Serial.println(); +} +void OnHIDExtrasPress(uint32_t top, uint16_t key) +{ + Serial.print("HID ("); + Serial.print(top, HEX); + Serial.print(") key press:"); + Serial.println(key, HEX); } +void OnHIDExtrasRelease(uint32_t top, uint16_t key) +{ + Serial.print("HID ("); + Serial.print(top, HEX); + Serial.print(") key release:"); + Serial.println(key, HEX); +} diff --git a/hid.cpp b/hid.cpp index 94f855f..829052d 100644 --- a/hid.cpp +++ b/hid.cpp @@ -57,6 +57,10 @@ bool USBHIDParser::claim(Device_t *dev, int type, const uint8_t *descriptors, ui // do not claim boot protocol keyboards if (descriptors[6] == 1 && descriptors[7] == 1) return false; + print("HID Parser Claim: "); + print_hexbytes(descriptors, len); + + // hid interface descriptor uint32_t hidlen = descriptors[9]; if (hidlen < 9) return false; @@ -198,6 +202,14 @@ void USBHIDParser::disconnect() // Called when the HID device sends a report void USBHIDParser::in_data(const Transfer_t *transfer) { + /*Serial.print("HID: "); + uint8_t *pb = (uint8_t*)transfer->buffer; + for (uint8_t i = 0; i < transfer->length; i++) { + Serial.print(pb[i], HEX); + Serial.print(" "); + } + Serial.println(); */ + print("HID: "); print_hexbytes(transfer->buffer, transfer->length); const uint8_t *buf = (const uint8_t *)transfer->buffer; @@ -531,6 +543,10 @@ void USBHIDParser::parse(uint16_t type_and_report_id, const uint8_t *data, uint3 print(" usage = ", u, HEX); println(" data = 1"); driver->hid_input_data(u, 1); + } else { + print (" usage =", u, HEX); + print(" out of range: ", logical_min, HEX); + println(" ", logical_max, HEX); } bitindex += report_size; } diff --git a/keyboard.cpp b/keyboard.cpp index 4fddb9a..d3850c2 100644 --- a/keyboard.cpp +++ b/keyboard.cpp @@ -44,7 +44,29 @@ typedef struct { keycode_extra_t keycode_extras[] = { {M(KEY_ENTER), '\n'}, {M(KEY_ESC), 0x1b}, - {M(KEY_TAB), 0x9 } + {M(KEY_TAB), 0x9 }, + {M(KEY_UP), KEYD_UP }, + {M(KEY_DOWN), KEYD_DOWN }, + {M(KEY_LEFT), KEYD_LEFT }, + {M(KEY_RIGHT), KEYD_RIGHT }, + {M(KEY_INSERT), KEYD_INSERT }, + {M(KEY_DELETE), KEYD_DELETE }, + {M(KEY_PAGE_UP), KEYD_PAGE_UP }, + {M(KEY_PAGE_DOWN), KEYD_PAGE_DOWN }, + {M(KEY_HOME), KEYD_HOME }, + {M(KEY_END), KEYD_END }, + {M(KEY_F1), KEYD_F1 }, + {M(KEY_F2), KEYD_F2 }, + {M(KEY_F3), KEYD_F3 }, + {M(KEY_F4), KEYD_F4 }, + {M(KEY_F5), KEYD_F5 }, + {M(KEY_F6), KEYD_F6 }, + {M(KEY_F7), KEYD_F7 }, + {M(KEY_F8), KEYD_F8 }, + {M(KEY_F9), KEYD_F9 }, + {M(KEY_F10), KEYD_F10 }, + {M(KEY_F11), KEYD_F11 }, + {M(KEY_F12), KEYD_F12 } }; // Some of these mapped to key + shift. @@ -242,9 +264,10 @@ void KeyboardController::key_release(uint32_t mod, uint32_t key) uint16_t KeyboardController::convert_to_unicode(uint32_t mod, uint32_t key) { - // TODO: special keys - // TODO: caps lock + // WIP: special keys // TODO: dead key sequences + + if (key & SHIFT_MASK) { // Many of these keys will look like they are other keys with shift mask... // Check for any of our mapped extra keys @@ -261,11 +284,19 @@ uint16_t KeyboardController::convert_to_unicode(uint32_t mod, uint32_t key) } } } - - // If we made it here without doing something then return 0; - if (key & SHIFT_MASK) return 0; } + // Check for any of our mapped extra keys - Done early as some of these keys are + // above and some below the SHIFT_MASK value + for (uint8_t i = 0; i < (sizeof(keycode_extras)/sizeof(keycode_extras[0])); i++) { + if (keycode_extras[i].code == key) { + return keycode_extras[i].ascii; + } + } + + // If we made it here without doing something then return 0; + if (key & SHIFT_MASK) return 0; + if ((mod & 0x02) || (mod & 0x20)) key |= SHIFT_MASK; if (leds_.capsLock) key ^= SHIFT_MASK; // Caps lock will switch the Shift; for (int i=0; i < 96; i++) { @@ -275,12 +306,6 @@ uint16_t KeyboardController::convert_to_unicode(uint32_t mod, uint32_t key) } } - // Check for any of our mapped extra keys - for (uint8_t i = 0; i < (sizeof(keycode_extras)/sizeof(keycode_extras[0])); i++) { - if (keycode_extras[i].code == key) { - return keycode_extras[i].ascii; - } - } #ifdef ISO_8859_1_A0 for (int i=0; i < 96; i++) { diff --git a/keyboardHIDExtras.cpp b/keyboardHIDExtras.cpp new file mode 100644 index 0000000..0ccc2b3 --- /dev/null +++ b/keyboardHIDExtras.cpp @@ -0,0 +1,118 @@ +/* USB keyboard power Host for Teensy 3.6 + * Copyright 2017 Paul Stoffregen (paul@pjrc.com) + * + * 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 +#include "USBHost_t36.h" // Read this header first for key info + +#define TOPUSAGE_SYS_CONTROL 0x10080 +#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001 + +bool KeyboardHIDExtrasController::claim_collection(Device_t *dev, uint32_t topusage) +{ + // Lets try to claim a few specific Keyboard related collection/reports + if ((topusage != TOPUSAGE_SYS_CONTROL) && (topusage != TOPUSAGE_CONSUMER_CONTROL)) return false; + // only claim from one physical device + //Serial.println("KeyboardHIDExtrasController claim collection"); + if (mydevice != NULL && dev != mydevice) return false; + mydevice = dev; + collections_claimed_++; + return true; +} + +void KeyboardHIDExtrasController::disconnect_collection(Device_t *dev) +{ + if (--collections_claimed_ == 0) { + mydevice = NULL; + } +} + +void KeyboardHIDExtrasController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax) +{ + //Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax); + topusage_ = topusage; // remember which report we are processing. + hid_input_begin_ = true; + hid_input_data_ = false; +} + +void KeyboardHIDExtrasController::hid_input_data(uint32_t usage, int32_t value) +{ + //Serial.printf("KeyboardHIDExtrasController: usage=%X, value=%d\n", usage, value); + + // See if the value is in our keys_down list + usage &= 0xffff; // only keep the actual key + if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items. + + // Remember if we have received any logical key up events. Some keyboard appear to send them + // others do no... + hid_input_data_ = true; + + uint8_t key_index; + for (key_index = 0; key_index < count_keys_down_; key_index++) { + if (keys_down[key_index] == usage) { + if (value) return; // still down + + if (keyReleasedFunction) { + keyReleasedFunction(topusage_, usage); + } + + // Remove from list + count_keys_down_--; + for (;key_index < count_keys_down_; key_index++) { + keys_down[key_index] = keys_down[key_index+1]; + } + return; + } + } + // Was not in list + if (!value) return; // still 0 + if (keyPressedFunction) { + keyPressedFunction(topusage_, usage); + } + if (count_keys_down_ < MAX_KEYS_DOWN) { + keys_down[count_keys_down_++] = usage; + } +} + +void KeyboardHIDExtrasController::hid_input_end() +{ + //Serial.println("KPC:hid_input_end"); + if (hid_input_begin_) { + + // See if we received any data from parser if not, assume all keys released... + if (!hid_input_data_ ) { + if (keyPressedFunction) { + while (count_keys_down_) { + count_keys_down_--; + keyReleasedFunction(topusage_, keys_down[count_keys_down_]); + } + } + count_keys_down_ = 0; + } + + event_ = true; + hid_input_begin_ = false; + } +} + + + diff --git a/mouse.cpp b/mouse.cpp index 46ef496..8ab1219 100644 --- a/mouse.cpp +++ b/mouse.cpp @@ -47,6 +47,7 @@ void MouseController::disconnect_collection(Device_t *dev) void MouseController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax) { // TODO: check if absolute coordinates + hid_input_begin_ = true; } void MouseController::hid_input_data(uint32_t usage, int32_t value) @@ -84,7 +85,10 @@ void MouseController::hid_input_data(uint32_t usage, int32_t value) void MouseController::hid_input_end() { - mouseEvent = true; + if (hid_input_begin_) { + mouseEvent = true; + hid_input_begin_ = false; + } } void MouseController::mouseDataClear() { From 3c34cc2f6f30eadf837b63e071121db98ebd21a2 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Thu, 12 Oct 2017 19:23:02 -0700 Subject: [PATCH 2/5] Work around for MS keyboard I updated the keyboard extras to detect if the report ID is 0xff00 and if so ignore it in the Mouse extras process code. This helped not handling a lot of extra messages generated by MS keyboard. Also updated Test app to show names of some of these special keys. --- examples/Mouse/Mouse.ino | 230 ++++++++++++++++++++++++++++++++++++++- keyboardHIDExtras.cpp | 9 +- 2 files changed, 236 insertions(+), 3 deletions(-) diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index a5836dd..67e9416 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -128,7 +128,235 @@ void OnHIDExtrasPress(uint32_t top, uint16_t key) Serial.print("HID ("); Serial.print(top, HEX); Serial.print(") key press:"); - Serial.println(key, HEX); + Serial.print(key, HEX); + if (top == 0xc0000) { + switch (key) { + case 0x20 : Serial.print(" - +10"); break; + case 0x21 : Serial.print(" - +100"); break; + case 0x22 : Serial.print(" - AM/PM"); break; + case 0x30 : Serial.print(" - Power"); break; + case 0x31 : Serial.print(" - Reset"); break; + case 0x32 : Serial.print(" - Sleep"); break; + case 0x33 : Serial.print(" - Sleep After"); break; + case 0x34 : Serial.print(" - Sleep Mode"); break; + case 0x35 : Serial.print(" - Illumination"); break; + case 0x36 : Serial.print(" - Function Buttons"); break; + case 0x40 : Serial.print(" - Menu"); break; + case 0x41 : Serial.print(" - Menu Pick"); break; + case 0x42 : Serial.print(" - Menu Up"); break; + case 0x43 : Serial.print(" - Menu Down"); break; + case 0x44 : Serial.print(" - Menu Left"); break; + case 0x45 : Serial.print(" - Menu Right"); break; + case 0x46 : Serial.print(" - Menu Escape"); break; + case 0x47 : Serial.print(" - Menu Value Increase"); break; + case 0x48 : Serial.print(" - Menu Value Decrease"); break; + case 0x60 : Serial.print(" - Data On Screen"); break; + case 0x61 : Serial.print(" - Closed Caption"); break; + case 0x62 : Serial.print(" - Closed Caption Select"); break; + case 0x63 : Serial.print(" - VCR/TV"); break; + case 0x64 : Serial.print(" - Broadcast Mode"); break; + case 0x65 : Serial.print(" - Snapshot"); break; + case 0x66 : Serial.print(" - Still"); break; + case 0x80 : Serial.print(" - Selection"); break; + case 0x81 : Serial.print(" - Assign Selection"); break; + case 0x82 : Serial.print(" - Mode Step"); break; + case 0x83 : Serial.print(" - Recall Last"); break; + case 0x84 : Serial.print(" - Enter Channel"); break; + case 0x85 : Serial.print(" - Order Movie"); break; + case 0x86 : Serial.print(" - Channel"); break; + case 0x87 : Serial.print(" - Media Selection"); break; + case 0x88 : Serial.print(" - Media Select Computer"); break; + case 0x89 : Serial.print(" - Media Select TV"); break; + case 0x8A : Serial.print(" - Media Select WWW"); break; + case 0x8B : Serial.print(" - Media Select DVD"); break; + case 0x8C : Serial.print(" - Media Select Telephone"); break; + case 0x8D : Serial.print(" - Media Select Program Guide"); break; + case 0x8E : Serial.print(" - Media Select Video Phone"); break; + case 0x8F : Serial.print(" - Media Select Games"); break; + case 0x90 : Serial.print(" - Media Select Messages"); break; + case 0x91 : Serial.print(" - Media Select CD"); break; + case 0x92 : Serial.print(" - Media Select VCR"); break; + case 0x93 : Serial.print(" - Media Select Tuner"); break; + case 0x94 : Serial.print(" - Quit"); break; + case 0x95 : Serial.print(" - Help"); break; + case 0x96 : Serial.print(" - Media Select Tape"); break; + case 0x97 : Serial.print(" - Media Select Cable"); break; + case 0x98 : Serial.print(" - Media Select Satellite"); break; + case 0x99 : Serial.print(" - Media Select Security"); break; + case 0x9A : Serial.print(" - Media Select Home"); break; + case 0x9B : Serial.print(" - Media Select Call"); break; + case 0x9C : Serial.print(" - Channel Increment"); break; + case 0x9D : Serial.print(" - Channel Decrement"); break; + case 0x9E : Serial.print(" - Media Select SAP"); break; + case 0xA0 : Serial.print(" - VCR Plus"); break; + case 0xA1 : Serial.print(" - Once"); break; + case 0xA2 : Serial.print(" - Daily"); break; + case 0xA3 : Serial.print(" - Weekly"); break; + case 0xA4 : Serial.print(" - Monthly"); break; + case 0xB0 : Serial.print(" - Play"); break; + case 0xB1 : Serial.print(" - Pause"); break; + case 0xB2 : Serial.print(" - Record"); break; + case 0xB3 : Serial.print(" - Fast Forward"); break; + case 0xB4 : Serial.print(" - Rewind"); break; + case 0xB5 : Serial.print(" - Scan Next Track"); break; + case 0xB6 : Serial.print(" - Scan Previous Track"); break; + case 0xB7 : Serial.print(" - Stop"); break; + case 0xB8 : Serial.print(" - Eject"); break; + case 0xB9 : Serial.print(" - Random Play"); break; + case 0xBA : Serial.print(" - Select DisC"); break; + case 0xBB : Serial.print(" - Enter Disc"); break; + case 0xBC : Serial.print(" - Repeat"); break; + case 0xBD : Serial.print(" - Tracking"); break; + case 0xBE : Serial.print(" - Track Normal"); break; + case 0xBF : Serial.print(" - Slow Tracking"); break; + case 0xC0 : Serial.print(" - Frame Forward"); break; + case 0xC1 : Serial.print(" - Frame Back"); break; + case 0xC2 : Serial.print(" - Mark"); break; + case 0xC3 : Serial.print(" - Clear Mark"); break; + case 0xC4 : Serial.print(" - Repeat From Mark"); break; + case 0xC5 : Serial.print(" - Return To Mark"); break; + case 0xC6 : Serial.print(" - Search Mark Forward"); break; + case 0xC7 : Serial.print(" - Search Mark Backwards"); break; + case 0xC8 : Serial.print(" - Counter Reset"); break; + case 0xC9 : Serial.print(" - Show Counter"); break; + case 0xCA : Serial.print(" - Tracking Increment"); break; + case 0xCB : Serial.print(" - Tracking Decrement"); break; + case 0xCD : Serial.print(" - Pause/Continue"); break; + case 0xE0 : Serial.print(" - Volume"); break; + case 0xE1 : Serial.print(" - Balance"); break; + case 0xE2 : Serial.print(" - Mute"); break; + case 0xE3 : Serial.print(" - Bass"); break; + case 0xE4 : Serial.print(" - Treble"); break; + case 0xE5 : Serial.print(" - Bass Boost"); break; + case 0xE6 : Serial.print(" - Surround Mode"); break; + case 0xE7 : Serial.print(" - Loudness"); break; + case 0xE8 : Serial.print(" - MPX"); break; + case 0xE9 : Serial.print(" - Volume Up"); break; + case 0xEA : Serial.print(" - Volume Down"); break; + case 0xF0 : Serial.print(" - Speed Select"); break; + case 0xF1 : Serial.print(" - Playback Speed"); break; + case 0xF2 : Serial.print(" - Standard Play"); break; + case 0xF3 : Serial.print(" - Long Play"); break; + case 0xF4 : Serial.print(" - Extended Play"); break; + case 0xF5 : Serial.print(" - Slow"); break; + case 0x100: Serial.print(" - Fan Enable"); break; + case 0x101: Serial.print(" - Fan Speed"); break; + case 0x102: Serial.print(" - Light"); break; + case 0x103: Serial.print(" - Light Illumination Level"); break; + case 0x104: Serial.print(" - Climate Control Enable"); break; + case 0x105: Serial.print(" - Room Temperature"); break; + case 0x106: Serial.print(" - Security Enable"); break; + case 0x107: Serial.print(" - Fire Alarm"); break; + case 0x108: Serial.print(" - Police Alarm"); break; + case 0x150: Serial.print(" - Balance Right"); break; + case 0x151: Serial.print(" - Balance Left"); break; + case 0x152: Serial.print(" - Bass Increment"); break; + case 0x153: Serial.print(" - Bass Decrement"); break; + case 0x154: Serial.print(" - Treble Increment"); break; + case 0x155: Serial.print(" - Treble Decrement"); break; + case 0x160: Serial.print(" - Speaker System"); break; + case 0x161: Serial.print(" - Channel Left"); break; + case 0x162: Serial.print(" - Channel Right"); break; + case 0x163: Serial.print(" - Channel Center"); break; + case 0x164: Serial.print(" - Channel Front"); break; + case 0x165: Serial.print(" - Channel Center Front"); break; + case 0x166: Serial.print(" - Channel Side"); break; + case 0x167: Serial.print(" - Channel Surround"); break; + case 0x168: Serial.print(" - Channel Low Frequency Enhancement"); break; + case 0x169: Serial.print(" - Channel Top"); break; + case 0x16A: Serial.print(" - Channel Unknown"); break; + case 0x170: Serial.print(" - Sub-channel"); break; + case 0x171: Serial.print(" - Sub-channel Increment"); break; + case 0x172: Serial.print(" - Sub-channel Decrement"); break; + case 0x173: Serial.print(" - Alternate Audio Increment"); break; + case 0x174: Serial.print(" - Alternate Audio Decrement"); break; + case 0x180: Serial.print(" - Application Launch Buttons"); break; + case 0x181: Serial.print(" - AL Launch Button Configuration Tool"); break; + case 0x182: Serial.print(" - AL Programmable Button Configuration"); break; + case 0x183: Serial.print(" - AL Consumer Control Configuration"); break; + case 0x184: Serial.print(" - AL Word Processor"); break; + case 0x185: Serial.print(" - AL Text Editor"); break; + case 0x186: Serial.print(" - AL Spreadsheet"); break; + case 0x187: Serial.print(" - AL Graphics Editor"); break; + case 0x188: Serial.print(" - AL Presentation App"); break; + case 0x189: Serial.print(" - AL Database App"); break; + case 0x18A: Serial.print(" - AL Email Reader"); break; + case 0x18B: Serial.print(" - AL Newsreader"); break; + case 0x18C: Serial.print(" - AL Voicemail"); break; + case 0x18D: Serial.print(" - AL Contacts/Address Book"); break; + case 0x18E: Serial.print(" - AL Calendar/Schedule"); break; + case 0x18F: Serial.print(" - AL Task/Project Manager"); break; + case 0x190: Serial.print(" - AL Log/Journal/Timecard"); break; + case 0x191: Serial.print(" - AL Checkbook/Finance"); break; + case 0x192: Serial.print(" - AL Calculator"); break; + case 0x193: Serial.print(" - AL A/V Capture/Playback"); break; + case 0x194: Serial.print(" - AL Local Machine Browser"); break; + case 0x195: Serial.print(" - AL LAN/WAN Browser"); break; + case 0x196: Serial.print(" - AL Internet Browser"); break; + case 0x197: Serial.print(" - AL Remote Networking/ISP Connect"); break; + case 0x198: Serial.print(" - AL Network Conference"); break; + case 0x199: Serial.print(" - AL Network Chat"); break; + case 0x19A: Serial.print(" - AL Telephony/Dialer"); break; + case 0x19B: Serial.print(" - AL Logon"); break; + case 0x19C: Serial.print(" - AL Logoff"); break; + case 0x19D: Serial.print(" - AL Logon/Logoff"); break; + case 0x19E: Serial.print(" - AL Terminal Lock/Screensaver"); break; + case 0x19F: Serial.print(" - AL Control Panel"); break; + case 0x1A0: Serial.print(" - AL Command Line Processor/Run"); break; + case 0x1A1: Serial.print(" - AL Process/Task Manager"); break; + case 0x1A2: Serial.print(" - AL Select Tast/Application"); break; + case 0x1A3: Serial.print(" - AL Next Task/Application"); break; + case 0x1A4: Serial.print(" - AL Previous Task/Application"); break; + case 0x1A5: Serial.print(" - AL Preemptive Halt Task/Application"); break; + case 0x200: Serial.print(" - Generic GUI Application Controls"); break; + case 0x201: Serial.print(" - AC New"); break; + case 0x202: Serial.print(" - AC Open"); break; + case 0x203: Serial.print(" - AC Close"); break; + case 0x204: Serial.print(" - AC Exit"); break; + case 0x205: Serial.print(" - AC Maximize"); break; + case 0x206: Serial.print(" - AC Minimize"); break; + case 0x207: Serial.print(" - AC Save"); break; + case 0x208: Serial.print(" - AC Print"); break; + case 0x209: Serial.print(" - AC Properties"); break; + case 0x21A: Serial.print(" - AC Undo"); break; + case 0x21B: Serial.print(" - AC Copy"); break; + case 0x21C: Serial.print(" - AC Cut"); break; + case 0x21D: Serial.print(" - AC Paste"); break; + case 0x21E: Serial.print(" - AC Select All"); break; + case 0x21F: Serial.print(" - AC Find"); break; + case 0x220: Serial.print(" - AC Find and Replace"); break; + case 0x221: Serial.print(" - AC Search"); break; + case 0x222: Serial.print(" - AC Go To"); break; + case 0x223: Serial.print(" - AC Home"); break; + case 0x224: Serial.print(" - AC Back"); break; + case 0x225: Serial.print(" - AC Forward"); break; + case 0x226: Serial.print(" - AC Stop"); break; + case 0x227: Serial.print(" - AC Refresh"); break; + case 0x228: Serial.print(" - AC Previous Link"); break; + case 0x229: Serial.print(" - AC Next Link"); break; + case 0x22A: Serial.print(" - AC Bookmarks"); break; + case 0x22B: Serial.print(" - AC History"); break; + case 0x22C: Serial.print(" - AC Subscriptions"); break; + case 0x22D: Serial.print(" - AC Zoom In"); break; + case 0x22E: Serial.print(" - AC Zoom Out"); break; + case 0x22F: Serial.print(" - AC Zoom"); break; + case 0x230: Serial.print(" - AC Full Screen View"); break; + case 0x231: Serial.print(" - AC Normal View"); break; + case 0x232: Serial.print(" - AC View Toggle"); break; + case 0x233: Serial.print(" - AC Scroll Up"); break; + case 0x234: Serial.print(" - AC Scroll Down"); break; + case 0x235: Serial.print(" - AC Scroll"); break; + case 0x236: Serial.print(" - AC Pan Left"); break; + case 0x237: Serial.print(" - AC Pan Right"); break; + case 0x238: Serial.print(" - AC Pan"); break; + case 0x239: Serial.print(" - AC New Window"); break; + case 0x23A: Serial.print(" - AC Tile Horizontally"); break; + case 0x23B: Serial.print(" - AC Tile Vertically"); break; + case 0x23C: Serial.print(" - AC Format"); break; + + } + } + Serial.println(); } void OnHIDExtrasRelease(uint32_t top, uint16_t key) diff --git a/keyboardHIDExtras.cpp b/keyboardHIDExtras.cpp index 0ccc2b3..f98eed1 100644 --- a/keyboardHIDExtras.cpp +++ b/keyboardHIDExtras.cpp @@ -30,7 +30,10 @@ bool KeyboardHIDExtrasController::claim_collection(Device_t *dev, uint32_t topusage) { // Lets try to claim a few specific Keyboard related collection/reports - if ((topusage != TOPUSAGE_SYS_CONTROL) && (topusage != TOPUSAGE_CONSUMER_CONTROL)) return false; + //Serial.printf("KBH Claim %x\n", topusage); + if ((topusage != TOPUSAGE_SYS_CONTROL) + && (topusage != TOPUSAGE_CONSUMER_CONTROL) + ) return false; // only claim from one physical device //Serial.println("KeyboardHIDExtrasController claim collection"); if (mydevice != NULL && dev != mydevice) return false; @@ -56,7 +59,9 @@ void KeyboardHIDExtrasController::hid_input_begin(uint32_t topusage, uint32_t ty void KeyboardHIDExtrasController::hid_input_data(uint32_t usage, int32_t value) { - //Serial.printf("KeyboardHIDExtrasController: usage=%X, value=%d\n", usage, value); + // Hack ignore 0xff00 high words as these are user values... + if ((usage & 0xffff0000) == 0xff000000) return; + //Serial.printf("KeyboardHIDExtrasController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value); // See if the value is in our keys_down list usage &= 0xffff; // only keep the actual key From 9abafa61068648e17989611f414fb34012b70622 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Fri, 13 Oct 2017 12:25:24 -0700 Subject: [PATCH 3/5] Example: Show which drivers are active I was wondering which drivers were in use, so now print when they are connected or disconnected --- examples/Mouse/Mouse.ino | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index 67e9416..09a934b 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -19,6 +19,11 @@ USBHIDParser hid5(myusb); MouseController mouse1(myusb); JoystickController joystick1(myusb); +USBDriver *drivers[] = {&hub1, &hub2, &hub3, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; +#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[1])) +const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2","Hub3", "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; +bool driver_active[CNT_DEVICES] = {false, false, false, false}; + void setup() { while (!Serial) ; // wait for Arduino Serial Monitor @@ -34,6 +39,20 @@ void setup() void loop() { myusb.Task(); + + for (uint8_t i = 0; i < CNT_DEVICES; i++) { + if (*drivers[i] != driver_active[i]) { + if (driver_active[i]) { + Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]); + driver_active[i] = false; + } else { + Serial.printf("*** Device %s - connected ***\n", driver_names[i]); + driver_active[i] = true; + + } + } + } + if(mouse1.available()) { Serial.print("Mouse: buttons = "); Serial.print(mouse1.getButtons()); From 03a7150872e18b9fd2ecdb8879b8c359d01c855d Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 14 Oct 2017 08:16:11 -0700 Subject: [PATCH 4/5] Display Vendor/Product ID on connect --- examples/Mouse/Mouse.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index 09a934b..328bffc 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -27,7 +27,7 @@ bool driver_active[CNT_DEVICES] = {false, false, false, false}; void setup() { while (!Serial) ; // wait for Arduino Serial Monitor - Serial.println("USB Host Testing"); + Serial.println("\n\nUSB Host Testing"); myusb.begin(); keyboard1.attachPress(OnPress); keyboard2.attachPress(OnPress); @@ -46,7 +46,7 @@ void loop() Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]); driver_active[i] = false; } else { - Serial.printf("*** Device %s - connected ***\n", driver_names[i]); + Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); driver_active[i] = true; } From 40cb6322acbb957d8c153baa5c780cb09445dda5 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 14 Oct 2017 14:27:09 -0700 Subject: [PATCH 5/5] WIP - Add Strings to device structure Added the ability to query the Manufactur, product name and serial number strings from a device. WIP - Eats up lots of memory, next up experiment move from Device_t object to maybe top level objects. Probably fewer than them as each hub allocates something like 7 Device objects --- USBHost_t36.h | 9 +++++++++ enumeration.cpp | 36 ++++++++++++++++++++++++++++++++++-- examples/Mouse/Mouse.ino | 6 ++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/USBHost_t36.h b/USBHost_t36.h index c3ec10b..d459c00 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -141,6 +141,7 @@ typedef union { } setup_t; // Device_t holds all the information about a USB device +#define DEVICE_STRUCT_STRING_BUF_SIZE 48 struct Device_struct { Pipe_t *control_pipe; Pipe_t *data_pipes; @@ -159,6 +160,8 @@ struct Device_struct { uint16_t idVendor; uint16_t idProduct; uint16_t LanguageID; + uint8_t string_buf[DEVICE_STRUCT_STRING_BUF_SIZE]; // Probably want a place to allocate fewer of these... + uint8_t iStrings[3]; // 3 indexes - vendor string, product string, serial number. }; // Pipe_t holes all information about each USB endpoint/pipe @@ -248,6 +251,7 @@ protected: static volatile bool enumeration_busy; private: static void isr(); + static void convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer); static void claim_drivers(Device_t *dev); static uint32_t assign_address(void); static bool queue_Transfer(Pipe_t *pipe, Transfer_t *transfer); @@ -350,6 +354,11 @@ public: operator bool() { return (device != nullptr); } uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 0; } + + const uint8_t *manufacturer() { return (device != nullptr) ? &(device->string_buf[device->iStrings[0]]) : nullptr; } + const uint8_t *product() { return (device != nullptr) ? &(device->string_buf[device->iStrings[1]]) : nullptr; } + const uint8_t *serialNumber() { return (device != nullptr) ? &(device->string_buf[device->iStrings[2]]) : nullptr; } + // TODO: user-level functions // check if device is bound/active/online // query vid, pid diff --git a/enumeration.cpp b/enumeration.cpp index 268bf39..4c8be2e 100644 --- a/enumeration.cpp +++ b/enumeration.cpp @@ -201,6 +201,10 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 4; return; case 4: // parse Language ID + dev->iStrings[0] = 0; // Set indexes into string buffer to say not there... + dev->iStrings[1] = 0; + dev->iStrings[2] = 0; + dev->string_buf[0] = 0; // have trailing NULL.. if (enumbuf[4] < 4 || enumbuf[5] != 3) { dev->enum_state = 11; } else { @@ -218,6 +222,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 6; return; case 6: // parse Manufacturer string + convertStringDescriptorToASCIIString(0, dev, transfer); // TODO: receive the string... if (enumbuf[1]) dev->enum_state = 7; else if (enumbuf[2]) dev->enum_state = 9; @@ -230,7 +235,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 8; return; case 8: // parse Product string - // TODO: receive the string... + convertStringDescriptorToASCIIString(1, dev, transfer); if (enumbuf[2]) dev->enum_state = 9; else dev->enum_state = 11; break; @@ -241,7 +246,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 10; return; case 10: // parse Serial Number string - // TODO: receive the string... + convertStringDescriptorToASCIIString(2, dev, transfer); dev->enum_state = 11; break; case 11: // request first 9 bytes of config desc @@ -286,6 +291,33 @@ void USBHost::enumeration(const Transfer_t *transfer) } } +void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { + uint8_t *buffer = (uint8_t*)transfer->buffer; + uint8_t buf_index = string_index? dev->iStrings[string_index]+1 : 0; + + // Try to verify - The first byte should be length and the 2nd byte should be 0x3 + if (!buffer || (buffer[1] != 0x3)) { + return; // No string so can simply return + } + + dev->iStrings[string_index] = buf_index; // remember our starting positio + uint8_t count_bytes_returned = buffer[0]; + if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) + count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; + + // Now copy into our storage buffer. + for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { + dev->string_buf[buf_index++] = buffer[i]; + } + dev->string_buf[buf_index] = 0; // null terminate. + + // Update other indexes to point to null character + while (++string_index < 3) { + dev->iStrings[string_index] = buf_index; // point to trailing NULL character + } +} + + void USBHost::claim_drivers(Device_t *dev) { USBDriver *driver, *prev=NULL; diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index 328bffc..0bbe298 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -49,6 +49,12 @@ void loop() Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); driver_active[i] = true; + const uint8_t *psz = drivers[i]->manufacturer(); + if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); + psz = drivers[i]->product(); + if (psz && *psz) Serial.printf(" product: %s\n", psz); + psz = drivers[i]->serialNumber(); + if (psz && *psz) Serial.printf(" Serial: %s\n", psz); } } }