Skip to content

Retry the first handshake after USB re-enumeration #10

Description

@X-F-R

Context

Arm.connect() (src/litearm/arm.py:883) builds the session and then performs one handshake:

# 握手: 固件版本
self._raw_write(P.CMD_GET_FIRMWARE)
try:
    _, verp = self._a.expect(P.RSP_FIRMWARE, 1.5, "get_firmware",
                             echo_cmd=P.CMD_GET_FIRMWARE)
    self.firmware = verp.decode(errors="replace").strip()
except Exception:
    self.close()
    raise

One write, one 1.5 s window, then close() and re-raise. There is no retry anywhere in the function.

Expected

After a USB re-enumeration the first connect() succeeds, the same as any other connect().

Actual

After the board re-enumerates — re-plugging the cable, or re-attaching USB passthrough to a VM — the first handshake goes unanswered and connect() raises. Calling it again a second or two later always works.

Measured on hardware: across four re-plugs in one session, the first connection failed every time and every retry succeeded. It never happened on a link that had stayed up.

The cost is not the retry itself, it is the diagnosis. The failure presents as a firmware that is not answering, so the natural response is to check the cable, the permissions and the firmware — none of which is the problem. connect() has already established that the port opened and the reader thread is running; what is missing is only that the firmware needed a moment after enumeration.

Reproduce

On a board where the USB link has just been re-established:

arm = litearm.Arm()
try:
    arm.connect()          # raises: get_firmware 无应答
except litearm.MotionTimeoutError:
    time.sleep(1.5)
    arm.connect()          # succeeds

I did not run this against the Python implementation; it is how the C++ port behaves, and the C++ port kept this function's structure on purpose so the two stay comparable.

Suggested direction

A short bounded retry of the handshake inside connect() — the port is already open at that point, so the retry is cheap and has no side effects. The sub-connect() behaviour is otherwise correct: FirmwareMismatchError and the version checks should not be retried, only the missing reply.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions