diff --git a/src/sagas/flash-firmware.test.ts b/src/sagas/flash-firmware.test.ts index f0e95a85..a92911f0 100644 --- a/src/sagas/flash-firmware.test.ts +++ b/src/sagas/flash-firmware.test.ts @@ -40,6 +40,7 @@ import { } from '../actions/lwp3-bootloader'; import { didCompile, didFailToCompile } from '../actions/mpy'; import { HubType, Result } from '../protocols/lwp3-bootloader'; +import { BootloaderConnectionState } from '../reducers/bootloader'; import { createCountFunc } from '../utils/iter'; import flashFirmware from './flash-firmware'; @@ -86,6 +87,9 @@ describe('flashFirmware', () => { let action = await saga.take(); expect(action).toEqual(connect()); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Connected }, + }); saga.put(didConnect()); // then find out what kind of hub it is @@ -278,6 +282,9 @@ describe('flashFirmware', () => { let action = await saga.take(); expect(action).toEqual(connect()); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Connected }, + }); saga.put(didConnect()); // then find out what kind of hub it is @@ -289,6 +296,9 @@ describe('flashFirmware', () => { // hub disconnects before replying + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + }); saga.put(didDisconnect()); // should get a failure to start @@ -338,6 +348,9 @@ describe('flashFirmware', () => { let action = await saga.take(); expect(action).toEqual(connect()); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Connected }, + }); saga.put(didConnect()); // then find out what kind of hub it is @@ -417,6 +430,9 @@ describe('flashFirmware', () => { action = await saga.take(); expect(action).toEqual(connect()); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Connected }, + }); saga.put(didConnect()); // then find out what kind of hub it is @@ -526,7 +542,10 @@ describe('flashFirmware', () => { nextMessageId: createCountFunc(), }); - saga.setState({ settings: { flashCurrentProgram: false } }); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + settings: { flashCurrentProgram: false }, + }); // saga is triggered by this action @@ -571,7 +590,10 @@ describe('flashFirmware', () => { nextMessageId: createCountFunc(), }); - saga.setState({ settings: { flashCurrentProgram: false } }); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + settings: { flashCurrentProgram: false }, + }); // saga is triggered by this action @@ -636,6 +658,12 @@ describe('flashFirmware', () => { } `); + // this triggers a failure + + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + }); + saga.put(didFailToCompile(['test'])); // compiler error should trigger firmware flash failure @@ -691,6 +719,10 @@ describe('flashFirmware', () => { } `); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + }); + const mpySize = 20; const mpyBinaryData = new Uint8Array(mpySize); saga.put(didCompile(mpyBinaryData)); @@ -749,6 +781,10 @@ describe('flashFirmware', () => { } `); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Disconnected }, + }); + const mpySize = 20; const mpyBinaryData = new Uint8Array(mpySize); saga.put(didCompile(mpyBinaryData)); @@ -810,6 +846,9 @@ describe('flashFirmware', () => { let action = await saga.take(); expect(action).toEqual(connect()); + saga.setState({ + bootloader: { connection: BootloaderConnectionState.Connected }, + }); saga.put(didConnect()); // then find out what kind of hub it is diff --git a/src/sagas/flash-firmware.ts b/src/sagas/flash-firmware.ts index 29e90597..5c2cb0f3 100644 --- a/src/sagas/flash-firmware.ts +++ b/src/sagas/flash-firmware.ts @@ -63,6 +63,7 @@ import { import * as notification from '../actions/notification'; import { MaxProgramFlashSize } from '../protocols/lwp3-bootloader'; import { RootState } from '../reducers'; +import { BootloaderConnectionState } from '../reducers/bootloader'; import { defined, maybe } from '../utils'; import { fmod, sumComplement32 } from '../utils/math'; @@ -72,14 +73,33 @@ const firmwareZipMap = new Map([ [HubType.MoveHub, moveHubZip], ]); +/** + * Disconnects the BLE if we are connected and cancels the task (including the + * parent task). + */ +function* disconnectAndCancel(): SagaGenerator { + const connection = yield* select((s: RootState) => s.bootloader.connection); + + if (connection === BootloaderConnectionState.Connected) { + yield* put(disconnect()); + } + + yield* cancel(); + + // HACK: cancel effect doesn't return, so we need this to make typescript + // happy about the never return type. + + // istanbul ignore next: not reachable + throw undefined; +} + function* waitForDidRequest(id: number): SagaGenerator { const request = yield* take( (a: Action) => a.type === BootloaderDidRequestType && a.id === id, ); if (request.err) { yield* put(didFailToFinish(FailToFinishReasonType.BleError, request.err)); - yield* put(disconnect()); - yield* cancel(); + yield* disconnectAndCancel(); } return request; @@ -103,16 +123,14 @@ function* waitForResponse( if (timedOut) { yield* put(didFailToFinish(FailToFinishReasonType.TimedOut)); - yield* put(disconnect()); - yield* cancel(); + yield* disconnectAndCancel(); } if (error) { yield* put( didFailToFinish(FailToFinishReasonType.HubError, HubError.UnknownCommand), ); - yield* put(disconnect()); - cancel(); + yield* disconnectAndCancel(); } defined(response); @@ -150,7 +168,7 @@ function* loadFirmware( } else { yield* put(didFailToFinish(FailToFinishReasonType.Unknown, readerErr)); } - yield* cancel(); + yield* disconnectAndCancel(); } defined(reader); @@ -171,7 +189,7 @@ function* loadFirmware( MetadataProblem.NotSupported, ), ); - yield* cancel(); + yield* disconnectAndCancel(); } yield* put(compile(program, metadata['mpy-cross-options'])); @@ -182,7 +200,7 @@ function* loadFirmware( if (mpyFail) { yield* put(didFailToFinish(FailToFinishReasonType.FailedToCompile)); - yield* cancel(); + yield* disconnectAndCancel(); } defined(mpy); @@ -196,7 +214,7 @@ function* loadFirmware( if (firmware.length > metadata['max-firmware-size']) { yield* put(didFailToFinish(FailToFinishReasonType.FirmwareSize)); - yield* cancel(); + yield* disconnectAndCancel(); } firmware.set(firmwareBase); @@ -211,7 +229,7 @@ function* loadFirmware( MetadataProblem.NotSupported, ), ); - yield* cancel(); + yield* disconnectAndCancel(); } firmwareView.setUint32( @@ -236,7 +254,7 @@ function* disconnectMonitor(): SagaGenerator { if (disconnected) { yield* put(didFailToFinish(FailToFinishReasonType.Disconnected)); - yield* cancel(); + yield* disconnectAndCancel(); } }