arduino-libraries / Arduino_USBHostMbed5

Apache License 2.0
4 stars 11 forks source link

Support Low Speed device? like many boot level keyboards? #43

Open KurtE opened 1 year ago

KurtE commented 1 year ago

There are several devices like keyboards, which run in USB Low Speed (1.5MBps) and are not properly being handled. For example, I have a Dell keyboard plugged in. I believe this one came with my newer computer I purchased in the last couple of years.

If I run the KeyboardGiga example sketch from the USBHostGiga library it receives, the keystrokes and prints them out in the Serial monitor.

If I instead run a similar test using this library it does not.

/*
  USBHost Keyboard test

  The circuit:
   - Arduino GIGA

  This example code is in the public domain.
*/

#include <Arduino_USBHostMbed5.h>
#include <USBHostHID/USBHostKeyboard.h>
REDIRECT_STDOUT_TO(Serial)

USBHostKeyboard kbd;

// If you are using a Portenta Machine Control uncomment the following line
// mbed::DigitalOut otg(PB_14, 0);

void setup()
{
    Serial.begin(115200);
    while (!Serial) {}

    Serial.println("Starting Keyboard test...");

    // Enable the USBHost 
    pinMode(PA_15, OUTPUT);
    digitalWrite(PA_15, HIGH);

    // if you are using a Max Carrier uncomment the following line
    // start_hub();
    kbd.attach(&kbd_key_cb);
    kbd.attach(&kbd_keycode_cb);

    while (!kbd.connect()) {
      Serial.println("No keyboard connected");        
        delay(5000);
    }
}

void loop()
{
    delay(1000);
}

void kbd_key_cb(uint8_t key) {
  Serial.print("Key pressed: ");
  Serial.print(key, HEX);
  Serial.print("(");
  if ((key >= ' ') && (key <= '~')) Serial.write(key);
  Serial.println(")");
}

void kbd_keycode_cb(uint8_t keycode, uint8_t mod) {
  Serial.print("Keycode: ");
  Serial.print(keycode, HEX);
  Serial.print(" mod: ");
  Serial.println(mod, HEX);
}

I added debug output to the keyboard class... So I know it is being called. Debug shows:

Starting Keyboard test...
No keyboard connected
got device
intf_class: 3
intf_subclass: 1
intf_protocol: 1
intf_nb: 0
intf_class: 3
intf_subclass: 0
intf_protocol: 0
ret: 0
after enumerate

The input code for the Serial class is not receiving any data. I have a Logic Analyzer attached and it is showing the device is sending data: image

And using my USB Analyzers for the Saleae, we see the following messages: <html xmlns:v="urn:schemas-microsoft-com:vml"

xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">

0.832053362 | SETUP | 0x0 | 0x0 | [GET_DESCRIPTOR - DEVICE #:0 I:0x0 L:0x8] | 0x80 0x6 0x0 0x1 0x0 0x0 0x8 0x0 |   -- | -- | -- | -- | -- | -- | -- 0.832366214 | IN | 0x0 | 0x0 |   | 0x12 0x1 0x10 0x1 0x0 0x0 0x0 0x8 |   0.832567682 | SETUP | 0x0 | 0x0 | SET_ADDRESS I:0x0 L:0x0] | 0x0 0x5 0x1 0x0 0x0 0x0 0x0 0x0 |   0.83507364 | SETUP | 0x0 | 0x1 | [GET_DESCRIPTOR - DEVICE #:0 I:0x0 L:0x8] | 0x80 0x6 0x0 0x1 0x0 0x0 0x8 0x0 |   0.835433222 | IN | 0x0 | 0x1 |   | 0x12 0x1 0x10 0x1 0x0 0x0 0x0 0x8 |   5.247817658 | SETUP | 0x0 | 0x1 | [GET_DESCRIPTOR - DEVICE #:0 I:0x0 L:0x12] | 0x80 0x6 0x0 0x1 0x0 0x0 0x12 0x0 |   5.248132034 | IN | 0x0 | 0x1 |   | 0x12 0x1 0x10 0x1 0x0 0x0 0x0 0x8 |   5.248332872 | IN | 0x0 | 0x1 |   | 0xca 0x4 0x27 0x0 0x18 0x1 0x1 0x2 |   5.24848434 | IN | 0x0 | 0x1 |   | 0x0 0x1 |   |   |   |   5.248818002 | SETUP | 0x0 | 0x1 | [GET_DESCRIPTOR - CONFIG #:0 I:0x0 L:0x9] | 0x80 0x6 0x0 0x2 0x0 0x0 0x9 0x0 |   5.249177614 | IN | 0x0 | 0x1 |   | 0x9 0x2 0x3b 0x0 0x2 0x1 0x0 0xa0 |   5.249328152 | IN | 0x0 | 0x1 |   | 0x32 |   |   |   |   5.24949202 | SETUP | 0x0 | 0x1 | [GET_DESCRIPTOR - CONFIG #:0 I:0x0 L:0x3b] | 0x80 0x6 0x0 0x2 0x0 0x0 0x3b 0x0 |   5.249817728 | IN | 0x0 | 0x1 |   | 0x9 0x2 0x3b 0x0 0x2 0x1 0x0 0xa0 |   5.250017522 | IN | 0x0 | 0x1 |   | 0x32 0x9 0x4 0x0 0x0 0x1 0x3 0x1 |   5.250218148 | IN | 0x0 | 0x1 |   | 0x1 0x0 0x9 0x21 0x10 0x1 0x0 0x1 |   5.250416976 | IN | 0x0 | 0x1 |   | 0x22 0x41 0x0 0x7 0x5 0x81 0x3 0x8 |   5.25081862 | IN | 0x0 | 0x1 |   | 0x0 0x18 0x9 0x4 0x1 0x0 0x1 0x3 |   5.251016772 | IN | 0x0 | 0x1 |   | 0x0 0x0 0x0 0x9 0x21 0x10 0x1 0x0 |   5.251216778 | IN | 0x0 | 0x1 |   | 0x1 0x22 0x9f 0x0 0x7 0x5 0x82 0x3 |   5.25141592 | IN | 0x0 | 0x1 |   | 0x8 0x0 0xa |   |   |   5.257467042 | SETUP | 0x0 | 0x1 | [SET_CONFIGURATION I:0x0 L:0x0] | 0x0 0x9 0x1 0x0 0x0 0x0 0x0 0x0 |   5.762888028 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |   5.85990304 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x38 0x0 0x0 0x0 0x0 0x0 |   5.952923144 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |   6.079945542 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x38 0x0 0x0 0x0 0x0 0x0 |   6.228969228 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |   6.351984988 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x38 0x0 0x0 0x0 0x0 0x0 |   6.476997196 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |   6.59402179 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x38 0x0 0x0 0x0 0x0 0x0 |   6.71103967 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |   6.816071866 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x10 0x0 0x0 0x0 0x0 0x0 |   7.007111472 | IN | 0x1 | 0x1 |   | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 |  

For more information about this device, I ran my sketch which tries to print out information about the device, Currently up at: https://github.com/KurtE/GIGA_USBHostMBed5_devices/tree/main/examples/GIGA_USBHost_DeviceInfo


*** starting Device information sketch ***
Device:0x2400c714
VID: 4CA, PID: 27
Manufacturer: Lite-On Technology Corp.
Product: USB Multimedia Keyboard
Speed: 0
Size of configuration Descriptor: 59
Configuration Descriptor
2400E8D0 - 09 02 3B 00 02 01 00 A0  32 09 04 00 00 01 03 01  : ..;..... 2.......
2400E8E0 - 01 00 09 21 10 01 00 01  22 41 00 07 05 81 03 08  : ...!.... "A......
2400E8F0 - 00 18 09 04 01 00 01 03  00 00 00 09 21 10 01 00  : ........ ....!...
2400E900 - 01 22 9F 00 07 05 82 03  08 00 0A                 : ."...... ...
Config:
 wTotalLength: 59
 bNumInterfaces: 2
 bConfigurationValue: 1
 iConfiguration: 0
 bmAttributes: 160
 bMaxPower: 50
****************************************
** Interface level **
  bInterfaceNumber: 0
  bAlternateSetting: 0
  Number of endpoints: 1
  bInterfaceClass: 3
  bInterfaceSubClass: 1
    HID (BOOT)
  bInterfaceProtocol: 1
    Keyboard
  iInterface: 0
  HID Descriptor size: 65
  Endpoint: 81 In
    Attrributes: 3 Interrupt
    Size: 8
    Interval: 24
>>>>> USBDumperDevice::getHIDDesc(0) called <<<<< 
2400E918 - 05 01 09 06 A1 01 05 07  19 E0 29 E7 15 00 25 01  : ........ ..)...%.
2400E928 - 95 08 75 01 81 02 95 08  75 01 81 01 05 08 19 01  : ..u..... u.......
2400E938 - 29 03 95 03 75 01 91 02  95 01 75 05 91 01 05 07  : )...u... ..u.....
2400E948 - 19 00 2A FF 00 15 00 26  FF 00 95 06 75 08 81 00  : ..*....& ....u...
2400E958 - C0                                                : .

HID Report Descriptor (0x2400e918) size: 65
  05 01 // Usage Page(1) - Generic Desktop
  09 06 // Usage(6) -(Keyboard)
  A1 01 // Collection(1) top Usage(10000)
    05 07   // Usage Page(7) - Keycode
    19 E0   // Usage Minimum(e0) - (Left Control)
    29 E7   // Usage Maximum(e7) - (Right GUI)
    15 00   // Logical Minimum(0)
    25 01   // Logical maximum(1)
    95 08   // Report Count(8)
    75 01   // Report Size(1)
    81 02   // Input(2) // (Data, Variable, Absolute)
    95 08   // Report Count(8)
    75 01   // Report Size(1)
    81 01   // Input(1) // (Constant, Array, Absolute)
    05 08   // Usage Page(8) - LEDs
    19 01   // Usage Minimum(1) - 
    29 03   // Usage Maximum(3) - 
    95 03   // Report Count(3)
    75 01   // Report Size(1)
    91 02   // Output(2)    // (Data, Variable, Absolute)
    95 01   // Report Count(1)
    75 05   // Report Size(5)
    91 01   // Output(1)    // (Constant, Array, Absolute)
    05 07   // Usage Page(7) - Keycode
    19 00   // Usage Minimum(0) - (Keycode 0)
    2A FF 00    // Usage Maximum(ff) - (Keycode 255)
    15 00   // Logical Minimum(0)
    26 FF 00    // Logical maximum(ff)
    95 06   // Report Count(6)
    75 08   // Report Size(8)
    81 00   // Input(0) // (Data, Array, Absolute)
    C0  // End Collection
****************************************
** Interface level **
  bInterfaceNumber: 1
  bAlternateSetting: 0
  Number of endpoints: 1
  bInterfaceClass: 3
  bInterfaceSubClass: 0
    HID
  bInterfaceProtocol: 0
    None
  iInterface: 0
  HID Descriptor size: 159
  Endpoint: 82 In
    Attrributes: 3 Interrupt
    Size: 8
    Interval: 10
>>>>> USBDumperDevice::getHIDDesc(1) called <<<<< 
2400E918 - 05 01 09 80 A1 01 85 01  05 01 19 81 29 88 15 00  : ........ ....)...
2400E928 - 25 01 95 08 75 01 81 02  C0 05 0C 09 01 A1 01 85  : %...u... ........
2400E938 - 02 15 00 25 01 0A 83 01  0A CD 00 0A B7 00 0A E9  : ...%.... ........
2400E948 - 00 0A EA 00 0A E2 00 0A  B6 00 0A B5 00 0A 8A 01  : ........ ........
2400E958 - 0A 92 01 0A 94 01 0A 21  02 0A 23 02 0A 24 02 0A  : .......! ..#..$..
2400E968 - 25 02 0A 26 02 0A 27 02  0A 2A 02 95 12 75 01 81  : %..&..'. .*...u..
2400E978 - 02 95 01 75 06 81 01 C0  05 09 09 01 A1 01 85 03  : ...u.... ........
2400E988 - 15 00 25 01 0A 2C 00 0A  18 00 0A 20 00 0A 1F 00  : ..%..,.. ... ....
2400E998 - 0A 1C 00 0A 3D 00 0A 41  00 0A 42 00 0A 43 00 0A  : ....=..A ..B..C..
2400E9A8 - 46 00 95 0A 75 01 81 02  95 01 75 06 81 01 C0     : F...u... ..u....

HID Report Descriptor (0x2400e918) size: 159
  05 01 // Usage Page(1) - Generic Desktop
  09 80 // Usage(80) -(?)
  A1 01 // Collection(1) top Usage(10080)
    85 01   // Report ID(1)
    05 01   // Usage Page(1) - Generic Desktop
    19 81   // Usage Minimum(81) - (System Power Down)
    29 88   // Usage Maximum(88) - (?)
    15 00   // Logical Minimum(0)
    25 01   // Logical maximum(1)
    95 08   // Report Count(8)
    75 01   // Report Size(1)
    81 02   // Input(2) // (Data, Variable, Absolute)
    C0  // End Collection
  05 0C // Usage Page(c) - Consumer
  09 01 // Usage(1) -(Consumer Controls)
  A1 01 // Collection(1) top Usage(c0000)
    85 02   // Report ID(2)
    15 00   // Logical Minimum(0)
    25 01   // Logical maximum(1)
    0A 83 01    // Usage(183) -(AL Consumer Control Configuration)
    0A CD 00    // Usage(cd) -(Pause/Continue)
    0A B7 00    // Usage(b7) -(Stop)
    0A E9 00    // Usage(e9) -(Volume Up)
    0A EA 00    // Usage(ea) -(Volume Down)
    0A E2 00    // Usage(e2) -(Mute)
    0A B6 00    // Usage(b6) -(Scan Previous Track)
    0A B5 00    // Usage(b5) -(Scan Next Track)
    0A 8A 01    // Usage(18a) -(AL Email Reader)
    0A 92 01    // Usage(192) -(AL Calculator)
    0A 94 01    // Usage(194) -(AL Local Machine Browser)
    0A 21 02    // Usage(221) -(AC Search)
    0A 23 02    // Usage(223) -(AC Home)
    0A 24 02    // Usage(224) -(AC Back)
    0A 25 02    // Usage(225) -(AC Forward)
    0A 26 02    // Usage(226) -(AC Stop)
    0A 27 02    // Usage(227) -(AC Refresh)
    0A 2A 02    // Usage(22a) -(AC Bookmarks)
    95 12   // Report Count(12)
    75 01   // Report Size(1)
    81 02   // Input(2) // (Data, Variable, Absolute)
    95 01   // Report Count(1)
    75 06   // Report Size(6)
    81 01   // Input(1) // (Constant, Array, Absolute)
    C0  // End Collection
  05 09 // Usage Page(9) - Button
  09 01 // Usage(1) - (BUTTON 1)
  A1 01 // Collection(1) top Usage(90000)
    85 03   // Report ID(3)
    15 00   // Logical Minimum(0)
    25 01   // Logical maximum(1)
    0A 2C 00    // Usage(2c) - (BUTTON 44)
    0A 18 00    // Usage(18) - (BUTTON 24)
    0A 20 00    // Usage(20) - (BUTTON 32)
    0A 1F 00    // Usage(1f) - (BUTTON 31)
    0A 1C 00    // Usage(1c) - (BUTTON 28)
    0A 3D 00    // Usage(3d) - (BUTTON 61)
    0A 41 00    // Usage(41) - (BUTTON 65)
    0A 42 00    // Usage(42) - (BUTTON 66)
    0A 43 00    // Usage(43) - (BUTTON 67)
    0A 46 00    // Usage(46) - (BUTTON 70)
    95 0A   // Report Count(a)
    75 01   // Report Size(1)
    81 02   // Input(2) // (Data, Variable, Absolute)
    95 01   // Report Count(1)
    75 06   // Report Size(6)
    81 01   // Input(1) // (Constant, Array, Absolute)
    C0  // End Collection
parseInterface nb:0
 bInterfaceClass = 3
 bInterfaceSubClass = 1
    HID (BOOT)
 bProtocol = 1
    Keyboard
useEndpoint(0, 3, 2)
parseInterface nb:1
 bInterfaceClass = 3
 bInterfaceSubClass = 0
    HID
 bProtocol = 0
    None
New Debug device: VID:04ca PID:0027 [dev: 0x2400c714 - intf: 0]
USB host device(4ca:27) connected
Manufacturer: Lite-On Technology Corp.
Product: USB Multimedia Keyboard

Note: I tried to print out the speed of the device, but the method appears to always return false... From quick guessing I think should be HIGH for low speed? Would have hoped there were at least three values (LS, FS, HS), but it also appears like this library does not support High speed...

AndrewCapon commented 1 year ago

Without a hub this code is used:

void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
{
    USBHALHost_Private_t *priv = (USBHALHost_Private_t *)(hhcd->pData);
    USBHALHost *obj = priv->inst;
    void (USBHALHost::*func)(int hub, int port, bool lowSpeed, USBHostHub * hub_parent) = priv->deviceConnected;
    (obj->*func)(0, 1, 0, NULL);
}

the hub code has this:

                status = getPortStatus(port);
                USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);

                // if connection status has changed
                if (status & C_PORT_CONNECTION) {
                    if (status & PORT_CONNECTION) {
                        USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
                        host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
                    } else {
                        USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
                        host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
                    }

                    clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
                }
...

getPortStatus():

uint32_t USBHostHub::getPortStatus(uint8_t port)
{
    uint32_t st;
    host->controlRead(  dev,
                        USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
                        GET_STATUS,
                        0,
                        port,
                        (uint8_t *)&st,
                        4);
    return st;
}
AndrewCapon commented 1 year ago

It looks like it isn't straightforward to get the speed of the direct connection:

(if DP is pulled high -> FS, if DM is high -> LS).

I don't know what the timing for that being true is but I'm guessing not when HAL_HCD_Connect_Callback() is called.

KurtE commented 1 year ago

It looks like the other library (USBHostGiga) uses the lower level function:

USBH_SpeedTypeDef USBH_LL_GetSpeed(USBH_HandleTypeDef *phost)
{
  USBH_SpeedTypeDef speed = USBH_SPEED_FULL;

  switch (HAL_HCD_GetCurrentSpeed(phost->pData))
  {
  case 0 :
    speed = USBH_SPEED_HIGH;
    break;

  case 1 :
    speed = USBH_SPEED_FULL;
    break;

  case 2 :
    speed = USBH_SPEED_LOW;
    break;

  default:
   speed = USBH_SPEED_FULL;
    break;
  }
  return  speed;
}

The low level code then reads in the register OTG_HPRT and looks at the field:

Bits 18:17 PSPD[1:0]: Port speed Indicates the speed of the device attached to this port. 01: Full speed 10: Low speed 11: Reserved 00: High speed

KurtE commented 1 year ago

Making some progress... I am pretty sure a real solution might need to abstract some stuff... But I am detecting a low-speed device:

                        } else {
                            hub_unplugged = false;
                            #if defined(TARGET_GIGA)

                            #define USBx_BASE   USB1_OTG_HS_PERIPH_BASE
                            #define USBx_HPRT0      *(__IO uint32_t *)((uint32_t)USBx_BASE + USB_OTG_HOST_PORT_BASE)
                            uint8_t pspd = ((USBx_HPRT0 & USB_OTG_HPRT_PSPD) >> 17);
                            if (pspd == 2) {
                                usb_msg->lowSpeed = true;
                            }
                            printf("HPRT Speed: %u: Low speed? %u\n", pspd, usb_msg->lowSpeed );
                            #endif
                        }

                        if (((idx!=-1) && deviceInUse[idx] ) || ((idx == -1) && hub_unplugged)) {

And I pugged in a LS device (the keyboard) and likewise a Serial device, that is FS... And they were detect.

So then running the Keyboard test program mentioned in the original post here. And getting lots of Warnings output, and still now callbacks with the characters.

Starting Keyboard test...
No keyboard connected
*** DEVICE_CONNECTED_EVENT: 0 1 0 0x0
HPRT Speed: 2: Low speed? 1
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
got device
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
intf_class: 3
intf_subclass: 1
intf_protocol: 1
intf_nb: 0
intf_class: 3
intf_subclass: 0
intf_protocol: 0
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:89]small speed device on hub not supported
ret: 0
after enumerate

Now to see if that can be resolved...

AndrewCapon commented 1 year ago

That isn't a reassuring warning!

KurtE commented 1 year ago

Still working on it,

Starting Keyboard test...
No keyboard connected
*** DEVICE_CONNECTED_EVENT: 0 1 0 0x0
HPRT Speed: 2: Low speed? 1
0x2400ce0c 0 1 2 1
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 0 1 0 8)
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 0 2 0 8)
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 0 2 0 8)
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 1 2 0 8)
got device
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 1 2 0 8)
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 1 2 0 8)
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 1 2 0 8)
intf_class: 3
intf_subclass: 1
intf_protocol: 1
intf_nb: 0
** USBEndpoint::setSpeed(0x2400cea4, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400cea4 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 1 129 1 2 3 8)
** USBEndpoint::setSpeed(0x2400cea4, 1) **
intf_class: 3
intf_subclass: 0
intf_protocol: 0
** USBEndpoint::setSpeed(0x2400ce0c, 1) **
[USB_WARNING: c:\Users\kurte\Documents\Arduino\libraries\Arduino_USBHostMbed5\src\targets\TARGET_STM\USBEndpoint_STM.cpp:87]low speed device on hub not supported
0x2400ce0c 1 1 2 2
(SA)HAL_HCD_HC_Init(0x240012b4 0 0 1 2 0 8)
ret: 0
after enumerate
End of Setup

The calls to HAL_HCD_HC_init, are where the end points get setup and the speed is passed in.... 0=HS 1=FS 2=LS. I have most of them caught to pass in 2... But one more to go... Not sure if there are other things needed as well

But still no keystrokes

KurtE commented 1 year ago

@AndrewCapon @mjs513 - Making some progress on this... Still needs a lot of cleaning up. I pushed up a new branch: https://github.com/KurtE/Arduino_USBHostMbed5/tree/usb_host_fixes_lowspeed Which is based off of your usb_host_fixes.

/*
  USBHost Keyboard test

  The circuit:
   - Arduino GIGA

  This example code is in the public domain.
*/

#include <Arduino_USBHostMbed5.h>
#include <USBHostHID/USBHostKeyboard.h>
REDIRECT_STDOUT_TO(Serial)

USBHostKeyboard kbd;

// If you are using a Portenta Machine Control uncomment the following line
// mbed::DigitalOut otg(PB_14, 0);

void setup()
{
    Serial.begin(115200);
    while (!Serial && millis() < 5000) {}

    Serial.println("Starting Keyboard test...");

    // Enable the USBHost 
    pinMode(PA_15, OUTPUT);
    digitalWrite(PA_15, HIGH);

    // if you are using a Max Carrier uncomment the following line
    // start_hub();

    while (!kbd.connect()) {
      Serial.println("No keyboard connected");        
        delay(5000);
    }

    kbd.attach(&kbd_key_cb);
    kbd.attach(&kbd_keycode_cb);
    kbd.attachRelease(&kbd_key_release_cb);
    Serial.println("End of Setup");
}

void loop()
{
    delay(1000);
}

void kbd_key_cb(uint8_t key) {
  Serial.print("Key pressed: ");
  Serial.print(key, HEX);
  Serial.print("(");
  if ((key >= ' ') && (key <= '~')) Serial.write(key);
  Serial.println(")");
}

void kbd_key_release_cb(uint8_t key) {
  Serial.print("Key released: ");
  Serial.print(key, HEX);
  Serial.print("(");
  if ((key >= ' ') && (key <= '~')) Serial.write(key);
  Serial.println(")");
}

void kbd_keycode_cb(uint8_t keycode, uint8_t mod) {
  Serial.print("Keycode: ");
  Serial.print(keycode, HEX);
  Serial.print(" mod: ");
  Serial.println(mod, HEX);
}

Now getting data:

End of Setup
Key pressed: 61(a)
Keycode: 4 mod: 0
Key released: 61(a)
Key pressed: 61(a)
Keycode: 4 mod: 0
Key released: 61(a)
Key pressed: 73(s)
Keycode: 16 mod: 0
Key released: 73(s)
Key pressed: 61(a)
Keycode: 4 mod: 0
Key pressed: 73(s)
Keycode: 16 mod: 0
Key pressed: 64(d)
Keycode: 7 mod: 0
Key released: 61(a)
Key released: 64(d)
Key released: 73(s)
Key pressed: 61(a)
Keycode: 4 mod: 0
Key pressed: 73(s)
Keycode: 16 mod: 0
Key pressed: 64(d)

Some interesting things to check: The RXHandler code was (maybe is) being called back a lot with 0 bytes transferred. Not sure if that should be happening?

The USBHostKeyboard class is pretty limited and fragile. I did hack up their handler code to reasonably handle a keyboard BOOT format setup. First byte is modifiers, 2nd is ignored, and 3-8 are keycodes of keys currently pressed. I also added in callback for when released.

But their conversion from keycod to code is really limited and can go BOOM. That is it is a two dimension array static uint8_t keymap[4][0x39] = {

With the first dimension is modifier, which is 8 bits:

Bit | Bit Length | Description -- | -- | -- 0 | 1 | Left Ctrl. 1 | 1 | Left Shift. 2 | 1 | Left Alt. 3 | 1 | Left GUI (Windows/Super key.) 4 | 1 | Right Ctrl. 5 | 1 | Right Shift. 6 | 1 | Right Alt. 7 | 1 | Right GUI (Windows/Super key.)

So use the Right shift will index into the 32nd index for the first dimension. Or if you hit F12 that is keycode 0x45 which again is beyond the end of the table.

Also does not handle at all anything like Multimedia keys nor system keys. Also does not handle setting and display and using keyboard settings like caps lock ...

Not sure how far to take it, may extract out into my secondary library, like the USBSerial adapter class and the like. But at least something is working

`

AndrewCapon commented 1 year ago

Nice one.

rxhandler being called with 0 bytes, is that every 1 ms?

AndrewCapon commented 1 year ago

The keyboard is using USB interrupts:

if (dev && int_in) {
        host->interruptRead(dev, int_in, report, len_listen, false);
    }

So 1ms call to rxhandler, no data = 0 bytes.

mjs513 commented 1 year ago

Sorry for the late response but been a busy day today. Just retested with Kurt's updated branch with my the xbox, switch pro, and ps3 and they are all still working.