Now only optionally force keyboard into boot protocol modemain
@@ -683,6 +683,13 @@ public: | |||
KeyboardController(USBHost &host) { init(); } | |||
KeyboardController(USBHost *host) { init(); } | |||
// need their own versions as both USBDriver and USBHIDInput provide | |||
uint16_t idVendor(); | |||
uint16_t idProduct(); | |||
const uint8_t *manufacturer(); | |||
const uint8_t *product(); | |||
const uint8_t *serialNumber(); | |||
// Some methods are in both public classes so we need to figure out which one to use | |||
operator bool() { return (device != nullptr); } | |||
// Main boot keyboard functions. | |||
@@ -704,6 +711,7 @@ public: | |||
// Added for extras information. | |||
void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; } | |||
void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; } | |||
void forceBootProtocol(); | |||
enum {MAX_KEYS_DOWN=4}; | |||
@@ -750,7 +758,8 @@ private: | |||
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]; | |||
bool force_boot_protocol; // User or VID/PID said force boot protocol? | |||
bool control_queued; | |||
}; | |||
@@ -1283,7 +1292,7 @@ private: | |||
uint8_t pl2303_v1; // Which version do we have | |||
uint8_t pl2303_v2; | |||
uint8_t interface; | |||
bool control_queued; | |||
bool control_queued; // Is there already a queued control messaged | |||
typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t; | |||
sertype_t sertype; | |||
@@ -21,21 +21,21 @@ uint32_t buttons_prev = 0; | |||
RawHIDController rawhid1(myusb); | |||
RawHIDController rawhid2(myusb, 0xffc90004); | |||
USBDriver *drivers[] = {&hub1, &hub2,&keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||
USBDriver *drivers[] = {&hub1, &hub2, &keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) | |||
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"}; | |||
const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"}; | |||
bool driver_active[CNT_DEVICES] = {false, false, false, false}; | |||
// Lets also look at HID Input devices | |||
USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2}; | |||
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | |||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"}; | |||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1", "Joystick1", "RawHid1", "RawHid2"}; | |||
bool hid_driver_active[CNT_DEVICES] = {false, false}; | |||
bool show_changed_only = false; | |||
bool show_changed_only = false; | |||
uint8_t joystick_left_trigger_value = 0; | |||
uint8_t joystick_right_trigger_value = 0; | |||
uint64_t joystick_full_notify_mask = (uint64_t)-1; | |||
uint64_t joystick_full_notify_mask = (uint64_t) - 1; | |||
void setup() | |||
{ | |||
@@ -50,6 +50,11 @@ void setup() | |||
keyboard2.attachExtrasPress(OnHIDExtrasPress); | |||
keyboard2.attachExtrasRelease(OnHIDExtrasRelease); | |||
// The below forceBootProtocol will force which ever | |||
// next keyboard that attaches to this device to be in boot protocol | |||
// Only try this if you run into keyboard with issues. If this is a combined | |||
// device like wireless mouse and keyboard this can cause mouse problems. | |||
//keyboard1.forceBootProtocol(); | |||
rawhid1.attachReceive(OnReceiveHidData); | |||
rawhid2.attachReceive(OnReceiveHidData); | |||
} | |||
@@ -60,8 +65,8 @@ void loop() | |||
myusb.Task(); | |||
if (Serial.available()) { | |||
int ch = Serial.read(); // get the first char. | |||
while (Serial.read() != -1) ; | |||
int ch = Serial.read(); // get the first char. | |||
while (Serial.read() != -1) ; | |||
if ((ch == 'b') || (ch == 'B')) { | |||
Serial.println("Only notify on Basic Axis changes"); | |||
joystick1.axisChangeNotifyMask(0x3ff); | |||
@@ -78,7 +83,7 @@ void loop() | |||
Serial.println("\n*** Show only changed fields mode ***"); | |||
} | |||
} | |||
} | |||
} | |||
for (uint8_t i = 0; i < CNT_DEVICES; i++) { | |||
if (*drivers[i] != driver_active[i]) { | |||
@@ -95,6 +100,19 @@ void loop() | |||
if (psz && *psz) Serial.printf(" product: %s\n", psz); | |||
psz = drivers[i]->serialNumber(); | |||
if (psz && *psz) Serial.printf(" Serial: %s\n", psz); | |||
// Note: with some keyboards there is an issue that they don't output in boot protocol mode | |||
// and may not work. The above code can try to force the keyboard into boot mode, but there | |||
// are issues with doing this blindly with combo devices like wireless keyboard/mouse, which | |||
// may cause the mouse to not work. Note: the above id is in the builtin list of | |||
// vendor IDs that are already forced | |||
if (drivers[i] == &keyboard1) { | |||
if (keyboard1.idVendor() == 0x04D9) { | |||
Serial.println("Gigabyte vendor: force boot protocol"); | |||
// Gigabyte keyboard | |||
keyboard1.forceBootProtocol(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -120,7 +138,7 @@ void loop() | |||
if(mouse1.available()) { | |||
if (mouse1.available()) { | |||
Serial.print("Mouse: buttons = "); | |||
Serial.print(mouse1.getButtons()); | |||
Serial.print(", mouseX = "); | |||
@@ -168,7 +186,7 @@ void loop() | |||
joystick_left_trigger_value = ltv; | |||
joystick_right_trigger_value = rtv; | |||
joystick1.setRumble(ltv, rtv); | |||
} | |||
} | |||
break; | |||
case JoystickController::PS3: | |||
@@ -178,11 +196,11 @@ void loop() | |||
joystick_left_trigger_value = ltv; | |||
joystick_right_trigger_value = rtv; | |||
joystick1.setRumble(ltv, rtv, 50); | |||
} | |||
} | |||
break; | |||
case JoystickController::XBOXONE: | |||
case JoystickController::XBOX360: | |||
case JoystickController::XBOXONE: | |||
case JoystickController::XBOX360: | |||
ltv = joystick1.getAxis(4); | |||
rtv = joystick1.getAxis(5); | |||
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) { | |||
@@ -190,16 +208,16 @@ void loop() | |||
joystick_right_trigger_value = rtv; | |||
joystick1.setRumble(ltv, rtv); | |||
Serial.printf(" Set Rumble %d %d", ltv, rtv); | |||
} | |||
} | |||
break; | |||
} | |||
if (buttons != buttons_prev) { | |||
if (joystick1.joystickType == JoystickController::PS3) { | |||
joystick1.setLEDs((buttons>>12) & 0xf); // try to get to TRI/CIR/X/SQuare | |||
joystick1.setLEDs((buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare | |||
} else { | |||
uint8_t lr = (buttons & 1)? 0xff : 0; | |||
uint8_t lg = (buttons & 2)? 0xff : 0; | |||
uint8_t lb = (buttons & 4)? 0xff : 0; | |||
uint8_t lr = (buttons & 1) ? 0xff : 0; | |||
uint8_t lg = (buttons & 2) ? 0xff : 0; | |||
uint8_t lb = (buttons & 4) ? 0xff : 0; | |||
joystick1.setLEDs(lr, lg, lb); | |||
} | |||
buttons_prev = buttons; | |||
@@ -213,7 +231,7 @@ void loop() | |||
if (rawhid1) { | |||
int ch; | |||
uint8_t buffer[64]; | |||
uint8_t count_chars = 0; | |||
uint8_t count_chars = 0; | |||
memset(buffer, 0, sizeof(buffer)); | |||
if (Serial.available()) { | |||
while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) { | |||
@@ -277,7 +295,7 @@ void OnPress(int key) | |||
//Serial.print((char)keyboard2.getKey()); | |||
//Serial.println(); | |||
} | |||
void OnHIDExtrasPress(uint32_t top, uint16_t key) | |||
void OnHIDExtrasPress(uint32_t top, uint16_t key) | |||
{ | |||
Serial.print("HID ("); | |||
Serial.print(top, HEX); | |||
@@ -513,7 +531,7 @@ void OnHIDExtrasPress(uint32_t top, uint16_t key) | |||
Serial.println(); | |||
} | |||
void OnHIDExtrasRelease(uint32_t top, uint16_t key) | |||
void OnHIDExtrasRelease(uint32_t top, uint16_t key) | |||
{ | |||
Serial.print("HID ("); | |||
Serial.print(top, HEX); | |||
@@ -523,10 +541,10 @@ void OnHIDExtrasRelease(uint32_t top, uint16_t key) | |||
bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | |||
// Called for maybe both HIDS for rawhid basic test. One is for the Teensy | |||
// to output to Serial. while still having Raw Hid... | |||
// to output to Serial. while still having Raw Hid... | |||
if (usage == 0xffc90004) { | |||
// Lets trim off trailing null characters. | |||
while ((len > 0) && (data[len-1] == 0)) { | |||
while ((len > 0) && (data[len - 1] == 0)) { | |||
len--; | |||
} | |||
if (len) { | |||
@@ -537,7 +555,7 @@ bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | |||
Serial.print("RawHID data: "); | |||
Serial.println(usage, HEX); | |||
while (len) { | |||
uint8_t cb = (len > 16)? 16 : len; | |||
uint8_t cb = (len > 16) ? 16 : len; | |||
const uint8_t *p = data; | |||
uint8_t i; | |||
for (i = 0; i < cb; i++) { | |||
@@ -545,7 +563,7 @@ bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | |||
} | |||
Serial.print(": "); | |||
for (i = 0; i < cb; i++) { | |||
Serial.write(((*data >= ' ')&&(*data <= '~'))? *data : '.'); | |||
Serial.write(((*data >= ' ') && (*data <= '~')) ? *data : '.'); | |||
data++; | |||
} | |||
len -= cb; | |||
@@ -554,4 +572,4 @@ bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | |||
} | |||
return true; | |||
} | |||
} |
@@ -36,12 +36,17 @@ typedef struct { | |||
uint8_t charNumlockOn; // We will assume when num lock is on we have all characters... | |||
} keycode_numlock_t; | |||
typedef struct { | |||
uint16_t idVendor; // vendor id of keyboard | |||
uint16_t idProduct; // product id - 0 implies all of the ones from vendor; | |||
} keyboard_force_boot_protocol_t; // list of products to force into boot protocol | |||
#ifdef M | |||
#undef M | |||
#endif | |||
#define M(n) ((n) & KEYCODE_MASK) | |||
keycode_extra_t keycode_extras[] = { | |||
static const keycode_extra_t keycode_extras[] = { | |||
{M(KEY_ENTER), '\n'}, | |||
{M(KEY_ESC), 0x1b}, | |||
{M(KEY_TAB), 0x9 }, | |||
@@ -70,7 +75,7 @@ keycode_extra_t keycode_extras[] = { | |||
}; | |||
// Some of these mapped to key + shift. | |||
keycode_numlock_t keycode_numlock[] = { | |||
static const keycode_numlock_t keycode_numlock[] = { | |||
{M(KEYPAD_SLASH), '/', '/'}, | |||
{M(KEYPAD_ASTERIX), '*', '*'}, | |||
{M(KEYPAD_MINUS), '-', '-'}, | |||
@@ -89,6 +94,11 @@ keycode_numlock_t keycode_numlock[] = { | |||
{M(KEYPAD_PERIOD), 0x80 | M(KEY_DELETE), '.'} | |||
}; | |||
static const keyboard_force_boot_protocol_t keyboard_forceBootMode[] = { | |||
{0x04D9, 0} | |||
}; | |||
#define print USBHost::print_ | |||
#define println USBHost::println_ | |||
@@ -99,6 +109,7 @@ void KeyboardController::init() | |||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
driver_ready_for_device(this); | |||
USBHIDParser::driver_ready_for_hid_collection(this); | |||
force_boot_protocol = false; // start off assuming not | |||
} | |||
bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) | |||
@@ -108,6 +119,7 @@ bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descripto | |||
// only claim at interface level | |||
if (type != 1) return false; | |||
if (len < 9+9+7) return false; | |||
print_hexbytes(descriptors, len); | |||
uint32_t numendpoint = descriptors[4]; | |||
if (numendpoint < 1) return false; | |||
@@ -139,22 +151,45 @@ bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descripto | |||
datapipe->callback_function = callback; | |||
queue_Data_Transfer(datapipe, report, 8, this); | |||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||
// see if this device in list of devices that need to be set in | |||
// boot protocol mode | |||
bool in_forceBoot_mode_list = false; | |||
for (uint8_t i = 0; i < sizeof(keyboard_forceBootMode)/sizeof(keyboard_forceBootMode[0]); i++) { | |||
if (dev->idVendor == keyboard_forceBootMode[i].idVendor) { | |||
if ((dev->idProduct == keyboard_forceBootMode[i].idProduct) || | |||
(keyboard_forceBootMode[i].idProduct == 0)) { | |||
in_forceBoot_mode_list = true; | |||
break; | |||
} | |||
} | |||
} | |||
if (in_forceBoot_mode_list) { | |||
println("SET_PROTOCOL Boot"); | |||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||
} else { | |||
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE | |||
} | |||
queue_Control_Transfer(dev, &setup, NULL, this); | |||
control_queued = true; | |||
return true; | |||
} | |||
void KeyboardController::control(const Transfer_t *transfer) | |||
{ | |||
println("control callback (keyboard)"); | |||
control_queued = false; | |||
print_hexbytes(transfer->buffer, transfer->length); | |||
// To decode hex dump to human readable HID report summary: | |||
// http://eleccelerator.com/usbdescreqparser/ | |||
uint32_t mesg = transfer->setup.word1; | |||
println(" mesg = ", mesg, HEX); | |||
if (mesg == 0x001021 && transfer->length == 0) { // SET_PROTOCOL | |||
if (mesg == 0x00B21 && transfer->length == 0) { // SET_PROTOCOL | |||
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE | |||
control_queued = true; | |||
queue_Control_Transfer(device, &setup, NULL, this); | |||
} else if (force_boot_protocol) { | |||
forceBootProtocol(); // lets setup to do the boot protocol | |||
force_boot_protocol = false; // turn back off | |||
} | |||
} | |||
@@ -166,6 +201,17 @@ void KeyboardController::callback(const Transfer_t *transfer) | |||
} | |||
} | |||
void KeyboardController::forceBootProtocol() | |||
{ | |||
if (device && !control_queued) { | |||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||
control_queued = true; | |||
queue_Control_Transfer(device, &setup, NULL, this); | |||
} else { | |||
force_boot_protocol = true; // let system know we want to force this. | |||
} | |||
} | |||
void KeyboardController::disconnect() | |||
{ | |||
// TODO: free resources | |||
@@ -437,3 +483,43 @@ void KeyboardController::hid_input_end() | |||
hid_input_begin_ = false; | |||
} | |||
} | |||
//***************************************************************************** | |||
// Some simple query functions depend on which interface we are using... | |||
//***************************************************************************** | |||
uint16_t KeyboardController::idVendor() | |||
{ | |||
if (device != nullptr) return device->idVendor; | |||
if (mydevice != nullptr) return mydevice->idVendor; | |||
return 0; | |||
} | |||
uint16_t KeyboardController::idProduct() | |||
{ | |||
if (device != nullptr) return device->idProduct; | |||
if (mydevice != nullptr) return mydevice->idProduct; | |||
return 0; | |||
} | |||
const uint8_t *KeyboardController::manufacturer() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||
return nullptr; | |||
} | |||
const uint8_t *KeyboardController::product() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||
return nullptr; | |||
} | |||
const uint8_t *KeyboardController::serialNumber() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||
return nullptr; | |||
} | |||
@@ -31,6 +31,7 @@ updateLEDS KEYWORD2 | |||
numLock KEYWORD2 | |||
capsLock KEYWORD2 | |||
scrollLock KEYWORD2 | |||
forceBootProtocol KEYWORD2 | |||
# MIDIDevice | |||
getType KEYWORD2 |