@@ -230,10 +230,6 @@ function* loadFirmware(
230230
231231 const firmwareBase = yield * call ( ( ) => reader . readFirmwareBase ( ) ) ;
232232 const metadata = yield * call ( ( ) => reader . readMetadata ( ) ) ;
233- let checksum : number | undefined = undefined ;
234- let checksum_size = 4 ;
235- let firmware : Uint8Array | undefined = undefined ;
236- let firmwareView : DataView | undefined = undefined ;
237233
238234 // v1.x allows appending main.py to firmware, later versions do not
239235 if ( metadataIsV100 ( metadata ) || metadataIsV110 ( metadata ) ) {
@@ -285,8 +281,8 @@ function* loadFirmware(
285281 mpy . data . length +
286282 fmod ( - mpy . data . length , 4 ) ;
287283
288- firmware = new Uint8Array ( checksumOffset + 4 ) ;
289- firmwareView = new DataView ( firmware . buffer ) ;
284+ const firmware = new Uint8Array ( checksumOffset + 4 ) ;
285+ const firmwareView = new DataView ( firmware . buffer ) ;
290286
291287 if ( firmware . length > metadata [ 'max-firmware-size' ] ) {
292288 // FIXME: we should return error/throw instead
@@ -312,7 +308,7 @@ function* loadFirmware(
312308 }
313309 }
314310
315- checksum = ( function ( ) {
311+ const checksum = ( function ( ) {
316312 switch ( metadata [ 'checksum-type' ] ) {
317313 case 'sum' :
318314 return sumComplement32 (
@@ -348,14 +344,14 @@ function* loadFirmware(
348344 }
349345
350346 // v2.x supports setting the checksum size to 0 to indicate no checksum
351- else {
347+ {
352348 const metadataV2 = metadata as FirmwareMetadataV200 ;
353- checksum_size = metadataV2 [ 'checksum-size' ] ;
349+ const checksum_size = metadataV2 [ 'checksum-size' ] ;
354350
355- // TODO: v2.x supports setting checksum size, prior it was a fixed 4 bytes
356- firmware = new Uint8Array ( firmwareBase . length + checksum_size ) ;
357- firmwareView = new DataView ( firmware . buffer ) ;
358- checksum = ( function ( ) {
351+ // TODO: v2.x supports setting checksum size, prior it was a fixed 4 bytes - check if it 4 or checksum_size
352+ const firmware = new Uint8Array ( firmwareBase . length + 4 ) ;
353+ const firmwareView = new DataView ( firmware . buffer ) ;
354+ const checksum = ( function ( ) {
359355 switch ( metadata [ 'checksum-type' ] ) {
360356 case 'sum' :
361357 console . log ( 'computing sum' ) ;
@@ -381,28 +377,28 @@ function* loadFirmware(
381377 metadataV2 [ 'hub-name-offset' ] ,
382378 ) ;
383379 }
384- }
385380
386- if ( checksum === undefined ) {
387- // FIXME: we should return error/throw instead
388- yield * put (
389- didFailToFinish (
390- FailToFinishReasonType . BadMetadata ,
391- 'checksum-type' ,
392- MetadataProblem . NotSupported ,
393- ) ,
394- ) ;
395- yield * disconnectAndCancel ( ) ;
381+ if ( checksum === undefined ) {
382+ // FIXME: we should return error/throw instead
383+ yield * put (
384+ didFailToFinish (
385+ FailToFinishReasonType . BadMetadata ,
386+ 'checksum-type' ,
387+ MetadataProblem . NotSupported ,
388+ ) ,
389+ ) ;
390+ yield * disconnectAndCancel ( ) ;
396391
397- // istanbul ignore next: needed for typescript flow
398- throw new Error ( 'unreachable' ) ;
399- }
392+ // istanbul ignore next: needed for typescript flow
393+ throw new Error ( 'unreachable' ) ;
394+ }
400395
401- if ( checksum_size ) {
402- firmwareView . setUint32 ( firmwareBase . length , checksum , true ) ;
403- }
396+ if ( checksum_size ) {
397+ firmwareView . setUint32 ( firmwareBase . length , checksum , true ) ;
398+ }
404399
405- return { firmware, deviceId : metadata [ 'device-id' ] } ;
400+ return { firmware, deviceId : metadata [ 'device-id' ] } ;
401+ }
406402}
407403
408404/**
@@ -417,6 +413,7 @@ function* handleFlashFirmware(action: ReturnType<typeof flashFirmware>): Generat
417413 if ( action . data !== null ) {
418414 ( { firmware, deviceId } = yield * loadFirmware ( action . data , action . hubName ) ) ;
419415 }
416+ console . log ( '>>> deviceId' , deviceId , 'firmware' , firmware , action . data ) ;
420417
421418 yield * put ( connect ( ) ) ;
422419 const connectResult = yield * take ( [ didConnect , didFailToConnect ] ) ;
@@ -604,6 +601,7 @@ function* handleFlashFirmware(action: ReturnType<typeof flashFirmware>): Generat
604601 }
605602
606603 if ( flash . checksum !== runningChecksum ) {
604+ console . error ( '>>>> checksum' , flash . checksum , runningChecksum ) ;
607605 // istanbul ignore next
608606 if ( process . env . NODE_ENV !== 'test' ) {
609607 console . error (
@@ -941,16 +939,28 @@ function* handleInstallPybricks(): Generator {
941939 ) ;
942940 }
943941 break ;
944- case 'usb-ev3' :
945- {
942+ case 'usb-ev3' : {
943+ try {
946944 const { firmware } = yield * loadFirmware (
947945 accepted . firmwareZip ,
948946 accepted . hubName ,
949947 ) ;
950948
951949 yield * put ( firmwareFlashEV3 ( firmware . buffer as ArrayBuffer ) ) ;
950+ } catch ( err ) {
951+ // istanbul ignore if
952+ if ( process . env . NODE_ENV !== 'test' ) {
953+ console . error ( err ) ;
954+ }
955+
956+ yield * put (
957+ alertsShowAlert ( 'alerts' , 'unexpectedError' , {
958+ error : ensureError ( err ) ,
959+ } ) ,
960+ ) ;
952961 }
953962 break ;
963+ }
954964 }
955965}
956966
@@ -1021,7 +1031,9 @@ function* handleRestoreOfficialDfu(
10211031 }
10221032
10231033 yield * put (
1024- alertsShowAlert ( 'alerts' , 'unexpectedError' , { error : ensureError ( err ) } ) ,
1034+ alertsShowAlert ( 'alerts' , 'unexpectedError' , {
1035+ error : ensureError ( err ) ,
1036+ } ) ,
10251037 ) ;
10261038 yield * put ( firmwareDidFailToRestoreOfficialDfu ( ) ) ;
10271039 }
@@ -1137,6 +1149,9 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
11371149 ) ;
11381150
11391151 // Create a task that forwards matching actions to our channel
1152+ // Sending the command and setting up the listener are not atomic,
1153+ // so we might receive the reply before we start listening. To handle
1154+ // this, we keep listening until we find the matching reply.
11401155 const forwardTask = yield * fork ( function * ( ) {
11411156 while ( true ) {
11421157 const action = yield * take ( firmwareDidReceiveEV3Reply ) ;
@@ -1147,59 +1162,62 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
11471162 }
11481163 } ) ;
11491164
1150- // Send the command
1151- const dataBuffer = new Uint8Array ( ( payload ?. byteLength ?? 0 ) + 6 ) ;
1152- const data = new DataView ( dataBuffer . buffer ) ;
1153-
1154- data . setInt16 ( 0 , ( payload ?. byteLength ?? 0 ) + 4 , true ) ;
1155- data . setInt16 ( 2 , 0 , true ) ; // TODO: reply number
1156- data . setUint8 ( 4 , 0x01 ) ; // system command w/ reply
1157- data . setUint8 ( 5 , command ) ;
1158- if ( payload ) {
1159- dataBuffer . set ( payload , 6 ) ;
1160- }
1165+ try {
1166+ // Send the command
1167+ const dataBuffer = new Uint8Array ( ( payload ?. byteLength ?? 0 ) + 6 ) ;
1168+ const data = new DataView ( dataBuffer . buffer ) ;
1169+
1170+ data . setInt16 ( 0 , ( payload ?. byteLength ?? 0 ) + 4 , true ) ;
1171+ data . setInt16 ( 2 , 0 , true ) ; // TODO: reply number
1172+ data . setUint8 ( 4 , 0x01 ) ; // system command w/ reply
1173+ data . setUint8 ( 5 , command ) ;
1174+ if ( payload ) {
1175+ dataBuffer . set ( payload , 6 ) ;
1176+ }
11611177
1162- const [ , sendError ] = yield * call ( ( ) => maybe ( hidDevice . sendReport ( 0 , data ) ) ) ;
1178+ const [ , sendError ] = yield * call ( ( ) =>
1179+ maybe ( hidDevice . sendReport ( 0 , data ) ) ,
1180+ ) ;
11631181
1164- if ( sendError ) {
1165- yield * cancel ( forwardTask ) ;
1166- return [ undefined , sendError ] ;
1167- }
1182+ if ( sendError ) {
1183+ return [ undefined , sendError ] ;
1184+ }
11681185
1169- const { reply, timeout } = yield * race ( {
1170- reply : take ( replyChannel ) ,
1171- timeout : delay ( 15000 ) ,
1172- } ) ;
1186+ const { reply, timeout } = yield * race ( {
1187+ reply : take ( replyChannel ) ,
1188+ timeout : delay ( 5000 ) ,
1189+ } ) ;
11731190
1174- // Always clean up
1175- yield * cancel ( forwardTask ) ;
1176- yield * call ( ( ) => replyChannel . close ( ) ) ;
1191+ if ( timeout ) {
1192+ return [ undefined , new Error ( 'Timeout waiting for EV3 reply' ) ] ;
1193+ }
11771194
1178- if ( timeout ) {
1179- return [ undefined , new Error ( 'Timeout waiting for EV3 reply' ) ] ;
1180- }
1195+ defined ( reply ) ;
11811196
1182- defined ( reply ) ;
1197+ if ( reply . replyCommand !== command ) {
1198+ return [
1199+ undefined ,
1200+ new Error (
1201+ `EV3 reply command mismatch: expected ${ command } , got ${ reply . replyCommand } ` ,
1202+ ) ,
1203+ ] ;
1204+ }
11831205
1184- if ( reply . replyCommand !== command ) {
1185- return [
1186- undefined ,
1187- new Error (
1188- `EV3 reply command mismatch: expected ${ command } , got ${ reply . replyCommand } ` ,
1189- ) ,
1190- ] ;
1191- }
1206+ if ( reply . status !== 0 ) {
1207+ return [
1208+ undefined ,
1209+ new Error (
1210+ `EV3 reply status error: ${ reply . status } for command ${ command } ` ,
1211+ ) ,
1212+ ] ;
1213+ }
11921214
1193- if ( reply . status !== 0 ) {
1194- return [
1195- undefined ,
1196- new Error (
1197- `EV3 reply status error: ${ reply . status } for command ${ command } ` ,
1198- ) ,
1199- ] ;
1215+ return [ new DataView ( reply . payload ) , undefined ] ;
1216+ } finally {
1217+ // Always clean up
1218+ yield * cancel ( forwardTask ) ;
1219+ yield * call ( ( ) => replyChannel . close ( ) ) ;
12001220 }
1201-
1202- return [ new DataView ( reply . payload ) , undefined ] ;
12031221 }
12041222
12051223 const [ version , versionError ] = yield * sendCommand ( 0xf6 ) ; // get version
@@ -1373,7 +1391,9 @@ function* handleRestoreOfficialEV3(
13731391 }
13741392
13751393 yield * put (
1376- alertsShowAlert ( 'alerts' , 'unexpectedError' , { error : ensureError ( err ) } ) ,
1394+ alertsShowAlert ( 'alerts' , 'unexpectedError' , {
1395+ error : ensureError ( err ) ,
1396+ } ) ,
13771397 ) ;
13781398 yield * put ( firmwareDidFailToRestoreOfficialEV3 ( ) ) ;
13791399 }
0 commit comments