From 04697e9afa2da7b31676cfb4148f64d3180deca3 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 4 Jan 2026 21:02:51 +0000 Subject: [PATCH] firmware/ev3: allow buggy replies from EV3 bootloader Add a hack to not fail if the EV3 bootloader sends an echo of the request instead of the expected response. There is a known compatibility issue with the EV3 bootloader USB and, e.g. Windows with USB 3.0 ports. This apparently causes a race condition where commands that don't take long to process before sending a response will have the request echoed back instead of receiving the actual response. If this happens, we can ignore it and assume the command was successful. It just won't work, e.g. for the version command since that has a payload in the response. --- src/firmware/sagas.ts | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/firmware/sagas.ts b/src/firmware/sagas.ts index 946b1447..93865685 100644 --- a/src/firmware/sagas.ts +++ b/src/firmware/sagas.ts @@ -1107,16 +1107,33 @@ function* handleFlashEV3(action: ReturnType): Generator continue; // ignore empty reports } - const length = event.data.getInt16(0, true); + let length = event.data.getInt16(0, true); const replyNumber = event.data.getInt16(2, true); - const messageType = event.data.getUint8(4); + let messageType = event.data.getUint8(4); const replyCommand = event.data.getUint8(5); - const status = event.data.getUint8(6); - const payload = event.data.buffer.slice(7, 7 + length + 2); + let status = event.data.getUint8(6); + let payload = event.data.buffer.slice(7, 7 + length + 2); - console.debug( - `EV3 reply: length=${length}, replyNumber=${replyNumber}, messageType=${messageType}, replyCommand=${replyCommand}, status=${status}, payload=${payload}`, - ); + if (messageType === 0x01) { + // HACK: This works around a strange bug that can be triggered + // e.g. by USB 3.0 on Windows. Sometimes the EV3 bootloader will + // send the request back instead of the reply. In this case, + // fake the reply to avoid protocol errors. This seems to work + // as long as we aren't sending commands that have a reply + // with a payload (like reading version or checksum) + + console.warn( + `Bad EV3 reply: length=${length}, replyNumber=${replyNumber}, messageType=${messageType}, replyCommand=${replyCommand}, status=${status}`, + ); + length = 5; + messageType = 0x03; + status = 0x00; + payload = new ArrayBuffer(0); + + console.info( + `Fixed EV3 reply: length=${length}, replyNumber=${replyNumber}, messageType=${messageType}, replyCommand=${replyCommand}, status=${status}`, + ); + } yield* put( firmwareDidReceiveEV3Reply(