Skip to content

Conversation

@ArcaneNibble
Copy link
Collaborator

This fully implements the rest of the Pybricks USB protocol, allowing pybricksdev to run.

Screen Shot 2025-07-30 at 10 56 25 PM

@coveralls
Copy link

coveralls commented Jul 30, 2025

Coverage Status

coverage: 56.982% (+0.02%) from 56.967%
when pulling 0198f7b on ArcaneNibble:usb
into ccafa60 on pybricks:master.

@ArcaneNibble
Copy link
Collaborator Author

With this in place (and possibly some fixes in pybricksdev? I was noticing some strange issues) we might be able to call this an early alpha release?

@dlech
Copy link
Member

dlech commented Jul 31, 2025

and possibly some fixes in pybricksdev?

Can you elaborate? (Or send a PR)

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.

Not the most thorough review and I won't be able to test until sometime next week, but looks pretty good to me.

static uint32_t prev_status_flags = ~0;
static uint32_t new_status_flags = 0;

(void)ep1_tx_stdout_buf;
Copy link
Member

Choose a reason for hiding this comment

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

What is this for?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This silences a build failure due to warnings-treated-as-errors in the intermediate commit. This is because the variable is never used until stdout is implemented.


// Handle timeouts
is_transmitting = usb_tx_response_is_not_ready || usb_tx_status_is_not_ready || usb_tx_stdout_is_not_ready;
if (was_transmitting && is_transmitting) {
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps can use pbio_oneshot()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The reason I am not is because the code needs to handle both the rising edge case and the "continuously active" case.

// Handle timeouts
is_transmitting = usb_tx_response_is_not_ready || usb_tx_status_is_not_ready || usb_tx_stdout_is_not_ready;
if (was_transmitting && is_transmitting) {
if (pbio_os_timer_is_expired(&tx_timeout_timer)) {
Copy link
Member

Choose a reason for hiding this comment

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

Are we checking for timeout before setting the timer?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, the timer gets set in the else if later, which this code has to pass through before both flags can become true.

@laurensvalk
Copy link
Member

laurensvalk commented Jul 31, 2025

Amazing!

and possibly some fixes in pybricksdev? I was noticing some strange issues

At a glance, Pybricksdev seems to still always start slot 0 rather than start the selected slot. So code loaded to other slots does not appear to run. It does run if you start them with the button.

With this in place (...) we might be able to call this an early alpha release?

Let's wait a while. Anyone who is able to run it in the current state is probably also able to grab the nightly release.

I'd like to turn off some of the developer hacks (the hard reset; sensor 1 disabled, repl on 0) and get the official devices enabled (except I2C).

With the rapid progress here, I think I'll put aside some of the internal BLE refactoring and return focus to EV3 sensors and UX.


I was also occasionally getting this:

  File "/home/laurens/git-pybricks/pybricksdev/pybricksdev/connections/pybricks.py", line 612, in run
    await self.start_user_program()
  File "/home/laurens/git-pybricks/pybricksdev/pybricksdev/connections/pybricks.py", line 503, in start_user_program
    await self.write_gatt_char(
  File "/home/laurens/git-pybricks/pybricksdev/pybricksdev/connections/pybricks.py", line 947, in write_gatt_char
    await self._send_message(bytes([PybricksUsbOutEpMessageType.COMMAND]) + data)
  File "/home/laurens/git-pybricks/pybricksdev/pybricksdev/connections/pybricks.py", line 933, in _send_message
    raise RuntimeError(f"Write failed: {reply[0]}")

@ArcaneNibble
Copy link
Collaborator Author

Forgot to reply to this, but

pybricksdev seems to still always start slot 0

seems to describe the bulk of the strangeness I was experiencing. The other issues included:

  • download doesn't seem to work (OSError: Could not find hub.)
  • run doesn't seem to work if the hub is in REPL mode (RuntimeError: Write failed: 129)

I have cleaned up most of the review comments though.

@laurensvalk
Copy link
Member

laurensvalk commented Aug 4, 2025

Forgot to reply to this, but

pybricksdev seems to still always start slot 0

seems to describe the bulk of the strangeness I was experiencing.

This is happening because pybricksdev is not getting the status update until after starting the program. See pybricks/support#2306 So we could fix this in Pybricksdev, but it also sounds like the EV3 firmware is doing something slightly different than SPIKE?

@laurensvalk
Copy link
Member

Would you say we should merge it and further improve later? This has worked well for the SPI flash/adc code, so I'm happy to go this way here too.

It would be pretty useful to have #361, #363, #364 merged to facilitate other developments.

@ArcaneNibble
Copy link
Collaborator Author

Yes, I was hoping to merge these first and then make fixes as needed. I was waiting for @dlech to get back, unless you want to go ahead and click the button.

These transfers allow reading "characteristics" which would otherwise
be exchanged over BLE GATT. They contain information about the firmware
version and hub capabilities.

Also move the bRequest values into pbio/protocol.h so they can be shared
In order to be able to detect disconnection, we cannot force device mode
in the PHY. Forcing device mode overrides the analog comparators used to
detect VBUS.

Not forcing device mode should be fine because device mode is the default
(enabling host mode requires setting DEVCTL.SESSION explicitly, and the
ID pin is explicitly disconnected on the EV3 PCB.)
This handles Pybricks commands, status flag reporting, and timeouts.

stdout is not yet handled.
This replaces the old stopgap stdout logic with stdio over USB
Without this timer, if the hub state doesn't change and the user program
doesn't output anything, the hub won't be able to detect that the
host software has closed (because it never sends anything which could time out).

Keeping this state reasonably up-to-date is important for the hub
auto-power-off functionality.
@laurensvalk laurensvalk merged commit 0198f7b into pybricks:master Aug 5, 2025
17 checks passed
@laurensvalk
Copy link
Member

Done, thanks! Yes, let's build on this in follow up commits as needed.

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