diff --git a/src/protocols/bootloader.ts b/src/protocols/bootloader.ts index c454e7d9..054da259 100644 --- a/src/protocols/bootloader.ts +++ b/src/protocols/bootloader.ts @@ -94,9 +94,7 @@ export function createProgramFlashRequest( payload: ArrayBuffer, ): Uint8Array { const size = payload.byteLength; - if (size > MaxProgramFlashSize) { - throw Error('payload is bigger than MaxProgramFlashSize'); - } + assert(size <= MaxProgramFlashSize, 'payload is bigger than MaxProgramFlashSize'); const msg = new Uint8Array(size + 6); const view = new DataView(msg.buffer); view.setUint8(0, Command.ProgramFlash); diff --git a/src/sagas/bootloader.test.ts b/src/sagas/bootloader.test.ts index 2d9b8991..b3210527 100644 --- a/src/sagas/bootloader.test.ts +++ b/src/sagas/bootloader.test.ts @@ -1,9 +1,152 @@ import { Action } from 'redux'; import { runSaga, stdChannel } from 'redux-saga'; -import { BootloaderResponseActionType, didReceive } from '../actions/bootloader'; +import { + BootloaderChecksumRequestAction, + BootloaderChecksumResponseAction, + BootloaderConnectionActionType, + BootloaderDisconnectRequestAction, + BootloaderEraseRequestAction, + BootloaderEraseResponseAction, + BootloaderErrorResponseAction, + BootloaderInfoRequestAction, + BootloaderInfoResponseAction, + BootloaderInitRequestAction, + BootloaderInitResponseAction, + BootloaderProgramRequestAction, + BootloaderProgramResponseAction, + BootloaderRebootRequestAction, + BootloaderRequestActionType, + BootloaderResponseActionType, + BootloaderStateRequestAction, + BootloaderStateResponseAction, + didReceive, +} from '../actions/bootloader'; import { Command, HubType, ProtectionLevel, Result } from '../protocols/bootloader'; import bootloader from './bootloader'; +describe('message encoder', () => { + test.each([ + [ + 'erase', + { + type: BootloaderRequestActionType.Erase, + } as BootloaderEraseRequestAction, + [ + 0x11, // erase command + ], + ], + [ + 'program', + { + type: BootloaderRequestActionType.Program, + address: 0x08005000, + payload: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]) + .buffer, + } as BootloaderProgramRequestAction, + [ + 0x22, // program command + 0x12, // message size (payload size + 4) + 0x00, // offset LSB + 0x50, // . + 0x00, // . + 0x08, // offset MSB + 0x01, // payload[0] + 0x02, // payload[1] + 0x03, // payload[2] + 0x04, // payload[3] + 0x05, // payload[4] + 0x06, // payload[5] + 0x07, // payload[6] + 0x08, // payload[7] + 0x09, // payload[8] + 0x0a, // payload[9] + 0x0b, // payload[10] + 0x0c, // payload[11] + 0x0d, // payload[12] + 0x0e, // payload[13] + ], + ], + [ + 'reboot', + { + type: BootloaderRequestActionType.Reboot, + } as BootloaderRebootRequestAction, + [ + 0x33, // reboot command + ], + ], + [ + 'init', + { + type: BootloaderRequestActionType.Init, + firmwareSize: 100000, + } as BootloaderInitRequestAction, + [ + 0x44, // init command + 0xa0, // size LSB + 0x86, // . + 0x01, // . + 0x00, // size MSB + ], + ], + [ + 'info', + { + type: BootloaderRequestActionType.Info, + } as BootloaderInfoRequestAction, + [ + 0x55, // info command + ], + ], + [ + 'checksum', + { + type: BootloaderRequestActionType.Checksum, + } as BootloaderChecksumRequestAction, + [ + 0x66, // checksum command + ], + ], + [ + 'state', + { + type: BootloaderRequestActionType.State, + } as BootloaderStateRequestAction, + [ + 0x77, // state command + ], + ], + [ + 'disconnect', + { + type: BootloaderRequestActionType.Disconnect, + } as BootloaderDisconnectRequestAction, + [ + 0x88, // disconnect command + ], + ], + ])('encode %s request', async (_n, request, expected) => { + const channel = stdChannel(); + const dispatched = new Array(); + const task = runSaga( + { + channel, + dispatch: (action: Action) => dispatched.push(action), + }, + bootloader, + ); + channel.put(request); + task.cancel(); + await task.toPromise(); + const message = new Uint8Array(expected); + expect(dispatched[0]).toEqual({ + type: BootloaderConnectionActionType.Send, + data: message, + withResponse: false, + }); + }); +}); + describe('message decoder', () => { test.each([ [ @@ -15,7 +158,7 @@ describe('message decoder', () => { { type: BootloaderResponseActionType.Erase, result: Result.Error, - }, + } as BootloaderEraseResponseAction, ], [ 'flash', @@ -31,7 +174,7 @@ describe('message decoder', () => { type: BootloaderResponseActionType.Program, checksum: 0xaa, count: 100000, - }, + } as BootloaderProgramResponseAction, ], [ 'init', @@ -42,7 +185,7 @@ describe('message decoder', () => { { type: BootloaderResponseActionType.Init, result: Result.Error, - }, + } as BootloaderInitResponseAction, ], [ 'info', @@ -68,7 +211,7 @@ describe('message decoder', () => { startAddress: 0x08005000, endAddress: 0x0801f7ff, hubType: HubType.MoveHub, - }, + } as BootloaderInfoResponseAction, ], [ 'checksum', @@ -79,7 +222,7 @@ describe('message decoder', () => { { type: BootloaderResponseActionType.Checksum, checksum: 0xaa, - }, + } as BootloaderChecksumResponseAction, ], [ 'state', @@ -90,7 +233,7 @@ describe('message decoder', () => { { type: BootloaderResponseActionType.State, level: ProtectionLevel.Level2, - }, + } as BootloaderStateResponseAction, ], [ 'error', @@ -104,7 +247,7 @@ describe('message decoder', () => { { type: BootloaderResponseActionType.Error, command: Command.GetFlashState, - }, + } as BootloaderErrorResponseAction, ], ])('decode %s response', async (_n, message, expected) => { const response = new Uint8Array(message);