From 37a3967f3a64f2276af41fcb113b0dabcecd601c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 13 Jun 2020 00:31:56 -0500 Subject: [PATCH] fix race condition when flashing firmware On Windows, we can get the GATT notification from the bootloader before Windows says we are done writing to the characteristic. This was observed on the erase and checksum messages with the Control+ hub. --- src/sagas/flash-firmware.ts | 49 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/sagas/flash-firmware.ts b/src/sagas/flash-firmware.ts index bbabb78b..926170de 100644 --- a/src/sagas/flash-firmware.ts +++ b/src/sagas/flash-firmware.ts @@ -4,7 +4,16 @@ import cPlusHubZip from '@pybricks/firmware/build/cplushub.zip'; import moveHubZip from '@pybricks/firmware/build/movehub.zip'; import JSZip from 'jszip'; -import { Effect, call, delay, put, race, take, takeEvery } from 'redux-saga/effects'; +import { + Effect, + all, + call, + delay, + put, + race, + take, + takeEvery, +} from 'redux-saga/effects'; import { Action } from '../actions'; import { FlashFirmwareActionType, @@ -194,10 +203,10 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator { } const infoAction = (yield put(infoRequest())) as BootloaderInfoRequestAction; - yield waitForDidSend(infoAction.id); - const info = (yield waitForResponse( - BootloaderResponseActionType.Info, - )) as WaitResponse; + const [, info] = (yield all([ + waitForDidSend(infoAction.id), + waitForResponse(BootloaderResponseActionType.Info), + ])) as [BootloaderDidRequestAction, WaitResponse]; if (!info[0]) { throw Error(`failed to get info: ${info}`); } @@ -255,11 +264,10 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator { } const eraseAction = (yield put(eraseRequest())) as BootloaderEraseRequestAction; - yield waitForDidSend(eraseAction.id); - const erase = (yield waitForResponse( - BootloaderResponseActionType.Erase, - 5000, - )) as WaitResponse; + const [, erase] = (yield all([ + waitForDidSend(eraseAction.id), + waitForResponse(BootloaderResponseActionType.Erase, 5000), + ])) as [BootloaderDidRequestAction, WaitResponse]; if (!erase[0] || erase[0].result) { // TODO: proper error handling throw Error(`Failed to erase: ${erase}`); @@ -268,10 +276,10 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator { const initAction = (yield put( initRequest(firmware.length), )) as BootloaderInitRequestAction; - yield waitForDidSend(initAction.id); - const init = (yield waitForResponse( - BootloaderResponseActionType.Init, - )) as WaitResponse; + const [, init] = (yield all([ + waitForDidSend(initAction.id), + waitForResponse(BootloaderResponseActionType.Init), + ])) as [BootloaderDidRequestAction, WaitResponse]; if (!init[0] || init[0].result) { // TODO: proper error handling throw Error(`Failed to init: ${init}`); @@ -295,12 +303,13 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator { const checksumAction = (yield put( checksumRequest(), )) as BootloaderChecksumRequestAction; - yield waitForDidSend(checksumAction.id); - - const checksum = (yield waitForResponse( - BootloaderResponseActionType.Checksum, - 5000, - )) as WaitResponse; + const [, checksum] = (yield all([ + waitForDidSend(checksumAction.id), + waitForResponse(BootloaderResponseActionType.Checksum, 5000), + ])) as [ + BootloaderDidRequestAction, + WaitResponse, + ]; if (!checksum[0]) { // TODO: proper error handling throw Error(`Failed to get checksum: ${checksum}`);