Skip to content

Conversation

@ArcaneNibble
Copy link
Collaborator

This PR adds the WebUSB and Microsoft descriptors for the EV3. It also refactors the other USB drivers to use the newly-added usb_ch9.h structs, which is more readable than defining every byte manually.

@ArcaneNibble
Copy link
Collaborator Author

Note that I've only compile-tested this for platforms other than the EV3.

@coveralls
Copy link

coveralls commented Jul 23, 2025

Coverage Status

coverage: 56.967%. remained the same
when pulling 318f21d on ArcaneNibble:usb
into aecbe20 on pybricks:master.

@ArcaneNibble
Copy link
Collaborator Author

Just updated with all the changes.

While I was in here, I also unified and const-ified the USB string descriptors.

This might need @BertLindeman 's testing at some point since it touches every platform (make sure USB still works and still has correct manufacturer+product strings)

@BertLindeman
Copy link
Contributor

On git hash 0ac2a66:

NXT USB looks fine on linux mint Xia:

[Thu Jul 24 16:48:56 2025] usb 1-1.2: USB disconnect, device number 5
[Thu Jul 24 16:48:56 2025] usb 1-1.2: new full-speed USB device number 6 using ehci-pci
[Thu Jul 24 16:48:56 2025] usb 1-1.2: not running at top speed; connect to a high speed hub
[Thu Jul 24 16:49:02 2025] usb 1-1.2: New USB device found, idVendor=0694, idProduct=0002, bcdDevice= 2.00
[Thu Jul 24 16:49:02 2025] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Thu Jul 24 16:49:02 2025] usb 1-1.2: Product: NXT + Pybricks
[Thu Jul 24 16:49:02 2025] usb 1-1.2: Manufacturer: LEGO System A/S
[Thu Jul 24 16:49:20 2025] usb 1-1.2: USB disconnect, device number 6

On windows unknown:

image

What else usefull?
Problem code 0000002B
Class Guid: {36fc9e60-c465-11cf-8056-444553540000}


EV3 On windows looks OK:

image image

On linux mint strange.

At the linux machine it did not look ok.

[Thu Jul 24 17:03:35 2025] usb 1-1.2: USB disconnect, device number 11
[Thu Jul 24 17:03:45 2025] usb 1-1.2: new high-speed USB device number 12 using ehci-pci
[Thu Jul 24 17:03:45 2025] usb 1-1.2: device descriptor read/all, error -71
[Thu Jul 24 17:03:45 2025] usb 1-1.2: new high-speed USB device number 13 using ehci-pci
[Thu Jul 24 17:03:45 2025] usb 1-1.2: device descriptor read/all, error -71
[Thu Jul 24 17:03:45 2025] usb 1-1-port2: attempt power cycle
[Thu Jul 24 17:03:46 2025] usb 1-1.2: new high-speed USB device number 14 using ehci-pci
[Thu Jul 24 17:03:51 2025] usb 1-1.2: device descriptor read/8, error -110
[Thu Jul 24 17:04:06 2025] usb 1-1.2: device descriptor read/8, error -71
[Thu Jul 24 17:04:15 2025] usb 1-1.2: new high-speed USB device number 16 using ehci-pci
[Thu Jul 24 17:04:16 2025] usb 1-1.2: device descriptor read/all, error -71
[Thu Jul 24 17:04:16 2025] usb 1-1.2: new high-speed USB device number 17 using ehci-pci
[Thu Jul 24 17:04:16 2025] usb 1-1.2: device descriptor read/all, error -71
[Thu Jul 24 17:04:16 2025] usb 1-1-port2: attempt power cycle
[Thu Jul 24 17:04:16 2025] usb 1-1.2: new high-speed USB device number 18 using ehci-pci
[Thu Jul 24 17:04:22 2025] usb 1-1.2: device descriptor read/8, error -110
[Thu Jul 24 17:04:38 2025] usb 1-1.2: device descriptor read/8, error -110
[Thu Jul 24 17:04:38 2025] usb 1-1.2: new high-speed USB device number 19 using ehci-pci
[Thu Jul 24 17:04:43 2025] usb 1-1.2: device descriptor read/8, error -110
[Thu Jul 24 17:04:59 2025] usb 1-1.2: device descriptor read/8, error -110
[Thu Jul 24 17:04:59 2025] usb 1-1-port2: unable to enumerate USB device
[Thu Jul 24 17:05:56 2025] usb 1-1.2: new high-speed USB device number 20 using ehci-pci
[Thu Jul 24 17:05:56 2025] usb 1-1.2: New USB device found, idVendor=0694, idProduct=0005, bcdDevice= 2.00
[Thu Jul 24 17:05:56 2025] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[Thu Jul 24 17:05:56 2025] usb 1-1.2: Product: LEGO MINDSTORMS EV3 + Pybricks
[Thu Jul 24 17:05:56 2025] usb 1-1.2: Manufacturer: LEGO System A/S
[Thu Jul 24 17:05:56 2025] usb 1-1.2: SerialNumber: 0016535166E2
[Thu Jul 24 17:07:43 2025] usb 1-1.2: USB disconnect, device number 20

So after quit some time it was OK.
Strange....
One time I re-plugged the cable and it was OK, one time on another linux.
But also after many retries.

And I could not get it done for the third time.

@ArcaneNibble
Copy link
Collaborator Author

Serious question wrt EV3: Did you try turning it off and on again?

USB definitely doesn't come up correctly until after at least one full power cycle, but I have no idea why.

@BertLindeman
Copy link
Contributor

Serious question wrt EV3: Did you try turning it off and on again?

USB definitely doesn't come up correctly until after at least one full power cycle, but I have no idea why.

Yes I did a few times. I kept plugging and booting until I had a recognized usb on linux again.
But not completely corrrect as lsusb halfway gives up:

lsusb -d 0694:0005 -v

Bus 001 Device 053: ID 0694:0005 Lego Group Mindstorms EV3
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.10
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass       197 [unknown]
  bDeviceProtocol       245
  bMaxPacketSize0        64
  idVendor           0x0694 Lego Group
  idProduct          0x0005 Mindstorms EV3
  bcdDevice            2.00
  iManufacturer           1 LEGO System A/S
  iProduct                2 LEGO MINDSTORMS EV3 + Pybricks
  iSerial                 3 0016535166E2
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0020
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    197 [unknown]
      bInterfaceProtocol    245
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
cannot read device status, Resource temporarily unavailable (11)

@ArcaneNibble
Copy link
Collaborator Author

Wait...

using ehci-pci

What era of host PC is this? This isn't a USB 3.0 port.

@BertLindeman
Copy link
Contributor

Ehrm, is the EV3 USB 3 compatible?
This old beast is a Dell XPS 8300 doing its fileserver task for a long time.

@ArcaneNibble
Copy link
Collaborator Author

It's not USB 3 compatible, but USB 3 ports use a completely different driver interface (even if only talking to USB 2 devices) compared to a USB 2 port talking to a USB 2 device.

Totally different driver interface means a totally different possible set of bugs.

@ArcaneNibble
Copy link
Collaborator Author

not running at top speed; connect to a high speed hub

This is also wrong. The NXT should not support a device qualifier descriptor as it is not capable of high speed.

@BertLindeman
Copy link
Contributor

BertLindeman commented Jul 24, 2025

Better news: Another linux machine has one usb-3 port:


[do jul 24 18:06:18 2025] usb 3-2: new high-speed USB device number 3 using xhci_hcd
[do jul 24 18:06:18 2025] usb 3-2: New USB device found, idVendor=0694, idProduct=0005, bcdDevice= 2.00
[do jul 24 18:06:18 2025] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[do jul 24 18:06:18 2025] usb 3-2: Product: LEGO MINDSTORMS EV3 + Pybricks
[do jul 24 18:06:18 2025] usb 3-2: Manufacturer: LEGO System A/S
[do jul 24 18:06:18 2025] usb 3-2: SerialNumber: 0016535166E2

Seems a lot better.

[EDIT] The port is at the backside of the machine, so hard to plug-in.

@ArcaneNibble
Copy link
Collaborator Author

Ugh, if this is indeed an EHCI-specific issue this is going to be very unfun to debug...

@ArcaneNibble
Copy link
Collaborator Author

@BertLindeman can you try 1067b35 on NXT?

@ArcaneNibble
Copy link
Collaborator Author

ArcaneNibble commented Jul 24, 2025

Erm, a bit of a weird question, but can you try the EV3 on one of the rear USB ports on the XPS 8300? I want to rule out that it's not a physical or signal integrity issue with aging hardware.

@BertLindeman
Copy link
Contributor

The rear port is another server (called mumba) the XPS 8300 is mammoet.

First the NXT on a usb-2 port: Direct OK even without reboot:

[Thu Jul 24 19:04:03 2025] usb 1-1.2: new full-speed USB device number 56 using ehci-pci
[Thu Jul 24 19:04:09 2025] usb 1-1.2: New USB device found, idVendor=0694, idProduct=0002, bcdDevice= 2.00
[Thu Jul 24 19:04:09 2025] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Thu Jul 24 19:04:09 2025] usb 1-1.2: Product: NXT + Pybricks
[Thu Jul 24 19:04:09 2025] usb 1-1.2: Manufacturer: LEGO System A/S
[Thu Jul 24 19:04:24 2025] usb 1-1.2: USB disconnect, device number 56
[Thu Jul 24 19:04:25 2025] usb 1-1.2: new full-speed USB device number 57 using ehci-pci
[Thu Jul 24 19:04:30 2025] usb 1-1.2: New USB device found, idVendor=0694, idProduct=0002, bcdDevice= 2.00
[Thu Jul 24 19:04:30 2025] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Thu Jul 24 19:04:30 2025] usb 1-1.2: Product: NXT + Pybricks
[Thu Jul 24 19:04:30 2025] usb 1-1.2: Manufacturer: LEGO System A/S

Next the EV3 at git hash 57ac538 on a linux usb-3 port:

ew high-speed USB device number 5 using xhci_hcd
[do jul 24 19:10:23 2025] usb 3-2: New USB device found, idVendor=0694, idProduct=0005, bcdDevice= 2.00
[do jul 24 19:10:23 2025] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[do jul 24 19:10:23 2025] usb 3-2: Product: LEGO MINDSTORMS EV3 + Pybricks
[do jul 24 19:10:23 2025] usb 3-2: Manufacturer: LEGO System A/S
[do jul 24 19:10:23 2025] usb 3-2: SerialNumber: 0016535166E2

and lsusb -d 0694:0005 -v

Bus 003 Device 005: ID 0694:0005 Lego Group Mindstorms EV3
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.10
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass       197 [unknown]
  bDeviceProtocol       245
  bMaxPacketSize0        64
  idVendor           0x0694 Lego Group
  idProduct          0x0005 Mindstorms EV3
  bcdDevice            2.00
  iManufacturer           1 LEGO System A/S
  iProduct                2 LEGO MINDSTORMS EV3 + Pybricks
  iSerial                 3 0016535166E2
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0020
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    197 [unknown]
      bInterfaceProtocol    245
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Binary Object Store Descriptor:
  bLength                 5
  bDescriptorType        15
  wTotalLength       0x0039
  bNumDeviceCaps          2
  Platform Device Capability:
    bLength                24
    bDescriptorType        16
    bDevCapabilityType      5
    bReserved               0
    PlatformCapabilityUUID    {3408b638-09a9-47a0-8bfd-a0768815b665}
      WebUSB:
        bcdVersion    1.00
        bVendorCode      0
        iLandingPage     1 https://code.pybricks.com
  Platform Device Capability:
    bLength                28
    bDescriptorType        16
    bDevCapabilityType      5
    bReserved               0
    PlatformCapabilityUUID    {d8dd60df-4589-4cc7-9cd2-659d9e648a9f}
    CapabilityData[0]    0x00
    CapabilityData[1]    0x00
    CapabilityData[2]    0x03
    CapabilityData[3]    0x06
    CapabilityData[4]    0xa2
    CapabilityData[5]    0x00
    CapabilityData[6]    0x01
    CapabilityData[7]    0x00
Device Status:     0x0001
  Self Powered

Looks a bit better ;-)

@BertLindeman
Copy link
Contributor

BertLindeman commented Jul 24, 2025

is it usefull to try the EV3 too at githash 57ac538 on usb-2 and usb-3?

The port I tested the EV3 on (front usb port) is the port I constantly use to flash the bricks with.
And the back ports of mammoet are near impossible to reach.

[EDIT]
There is a set of top usb ports on the XPS 8300 that one does the same for EV3.

The NXT at this githash 57ac538 on windows still not ok.

@ArcaneNibble
Copy link
Collaborator Author

Hmm okay, I'm not sure what the problem is here. Might defer this for now, since it works on some systems?

@dlech any ideas?

Copy link
Member

@dlech dlech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just been testing NXT so far. There is one issue I can't figure out. When the descriptors we are sending have a size that is a multiple of MAX_EP0_SIZE (8), then the OUT ACK isn't sent when we are done sending the data. I think this is what is causing Windows to fail to enumerate the device. This happens for the configuration descriptor and string descriptor #1.

@dlech
Copy link
Member

dlech commented Jul 25, 2025

There is one issue I can't figure out.

OK, figured it out.

diff --git a/lib/pbio/drv/usb/usb_nxt.c b/lib/pbio/drv/usb/usb_nxt.c
index 13d52e761..364a6e608 100644
--- a/lib/pbio/drv/usb/usb_nxt.c
+++ b/lib/pbio/drv/usb/usb_nxt.c
@@ -286,7 +286,7 @@ static void pbdrv_usb_nxt_write_data(int endpoint, const void *ptr_, uint32_t le
     /* If there is more data than can fit in a single packet, queue the
      * rest up.
      */
-    if (length > packet_size) {
+    if (length >= packet_size) {
         length -= packet_size;
         pbdrv_usb_nxt_state.tx_data[tx] = (uint8_t *)(ptr + packet_size);
         pbdrv_usb_nxt_state.tx_len[tx] = length;
@@ -757,8 +757,7 @@ static void pbdrv_usb_nxt_isr(void) {
             }
 
             /* and we will send the following data */
-            if (pbdrv_usb_nxt_state.tx_len[endpoint] > 0
-                && pbdrv_usb_nxt_state.tx_data[endpoint] != NULL) {
+            if (pbdrv_usb_nxt_state.tx_data[endpoint] != NULL) {
                 pbdrv_usb_nxt_write_data(endpoint, pbdrv_usb_nxt_state.tx_data[endpoint],
                     pbdrv_usb_nxt_state.tx_len[endpoint]);
             } else {

This forces setting the AT91C_UDP_TXPKTRDY flag one more time without pushing any more data to AT91C_UDP_FDR[endpoint].

@dlech
Copy link
Member

dlech commented Jul 25, 2025

Ugh, if this is indeed an EHCI-specific issue this is going to be very unfun to debug...

I found a chrombook with a USB 2 host port and did some sniffing.

For starters, we aren't handling this SETUP request on EV3:

image

And we don't seem to be sending a stall in response as we should for messages we can't handle.

break;
switch (setup_pkt.s.bmRequestType & BM_REQ_TYPE_MASK) {
case BM_REQ_TYPE_STANDARD:
switch (setup_pkt.s.bmRequestType & BM_REQ_RECIP_MASK) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a recipient mask check at this level on stm32 or nxt. I think this could be part of the issues with EV3.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this request is being directed at the EV3's USB address?

This is a hub request.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am seeing a stall in response to the packet shown

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not too sure. I can try again tonight.

@ArcaneNibble
Copy link
Collaborator Author

ArcaneNibble commented Jul 25, 2025

@BertLindeman could you please retest d812e58 5dc16e7 on NXT on Windows?

This should be less error-prone compared to manually declaring each byte.
Although these are not standard USB descriptors, Pybricks does require them,
and they logically fit in with the rest of the descriptor definitions in this file.
This allows for more friendly device setup when connecting to a computer.
These descriptors are expected to be the same on all devices,
so moving them to a new file reduces duplicate code.
This changes pbdrv_usb_nxt_write_data to accept a void *,
which removes a lot of ugly casting.

It also adds a note that a serial number should be implemented in the future
These descriptors are not referenced and thus can never be retrieved.
@BertLindeman
Copy link
Contributor

Sure, A bit later, just home from "work"

Now that we have C11 enabled, we can declare these directly as UTF-16 strings
and embed them as constant data. This deduplicates code for manually laying out
the string descriptors.
The device qualifier descriptor is used to indicate that a USB 2.0 HS
device performs differently from when it is functioning as a FS device.
The NXT is not capable of high speed, so it should not implement this.
@BertLindeman
Copy link
Contributor

Using github for a long time for browsing only most of the time.
Mostly I get the firmware from pybricks-micropython actions menu.

Can you remind me how I get best from d812e58

to a build e.g.

[USB driver cleanups and descriptors for EV3](https://github.com/pybricks/pybricks-micropython/actions/runs/16525789598)
Build #4056: Pull request https://github.com/pybricks/pybricks-micropython/pull/355 synchronize by [ArcaneNibble](https://github.com/ArcaneNibble)
[ArcaneNibble:usb](https://github.com/ArcaneNibble/pybricks-micropython/tree/refs/heads/usb)	

@ArcaneNibble
Copy link
Collaborator Author

Since it's the latest version of this PR, I normally do:

git fetch origin pull/355/head
git checkout FETCH_HEAD

or you can wait for the slooooow CI process to finish

@BertLindeman
Copy link
Contributor

Since it's the latest version of this PR, I normally do:

git fetch origin pull/355/head
git checkout FETCH_HEAD

or you can wait for the slooooow CI process to finish

OK as dinner is ready I'll wait for the slooooooooooooooooow CI process.

@BertLindeman
Copy link
Contributor

BertLindeman commented Jul 25, 2025

Needed to flash twice (first time no activity on the display) on linux mint.

USB at once OK on linux.

USB to win11 👍

image

No idea where I might see that device in device manager.
Or how to use (posing ignorant 😄 )

[EDIT]
I do not hear a click on the NXT boot from the speaker.

@ArcaneNibble
Copy link
Collaborator Author

Awesome, looks like the ZLP fix indeed fixes the NXT on Windows!

This should all be good now other than the EV3 EHCI(?) issue, which we need to either defer or try and chase down.

@dlech
Copy link
Member

dlech commented Jul 25, 2025

Yeah, I think this is ready to merge. Just one last request. We should squash "pbio/drv/usb/usb_nxt.c: Remove extra null packet in configuration descriptor" into "pbio/drv/usb/usb_nxt.c: Fix ZLPs on the control pipe" as we now know the reason for it - the config descriptor is 32 bytes (multiple of 8) and so hit the bug that that we fixed.

This is needed to correctly indicate end of descriptor when the
descriptor size is an exact multiple of the endpoint packet size.
This fixes enumeration issues on Windows.

Removes the former TODO in the configuration descriptor handling.
It is not needed and was masking this issue.
@BertLindeman
Copy link
Contributor

One remark now I get the EV3 on this same firmware on windows:

I see the device as:
image

Will verify again, but did not see the NXT as such but as LEGO device:
image

Not sure if this is a problem though.

@ArcaneNibble
Copy link
Collaborator Author

@dlech squashed

@BertLindeman This looks like something which might be caused by having the stock Lego drivers and software installed (do you have that installed?)

We might want to look into if it causes any actual problems.

@dlech
Copy link
Member

dlech commented Jul 25, 2025

the stock Lego drivers

That is my guess too. If you double-click on the device to open the properties, we can see which driver it is using. It could be using the correct driver now and just have some other info left over from the Windows registry that is changing the name and category.

@ArcaneNibble
Copy link
Collaborator Author

Incidentally, do we want to intentionally put Pybricks devices in a "LEGO Devices" category? Can you do that with additional Microsoft descriptor registry entries?

@BertLindeman
Copy link
Contributor

BertLindeman commented Jul 25, 2025

Correct:
image

More:
image

image

There is so much more in the details, I do not know waht to show....

@BertLindeman
Copy link
Contributor

Good news: I requested my wife to help pybricks and she plugged-in the NXT on her rather new win11. She never installs LEGO drivers.

The NXT correctly recognized as USB device.

@dlech
Copy link
Member

dlech commented Jul 25, 2025

The winusb.sys is what we want to see, so I don't expect we will have an issue if people have the LEGO driver installed.

@dlech dlech merged commit 85b7340 into pybricks:master Jul 25, 2025
17 checks passed
@BertLindeman
Copy link
Contributor

Will keep the LEGO packages and driver. If I ask nicely I can use my wife's PC.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants