@@ -1219,73 +1219,115 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12191219
12201220 defined ( version ) ;
12211221
1222- console . debug (
1223- `EV3 bootloader version: ${ version . getUint32 (
1224- 0 ,
1225- true ,
1226- ) } , HW version: ${ version . getUint32 ( 4 , true ) } `,
1227- ) ;
1222+ // For reasons that we do not currently understand, some EV3s do not return
1223+ // anything to our GetVersion command. We don't actually use the version
1224+ // for anything so we will just ignore this error.
1225+ try {
1226+ console . debug (
1227+ `EV3 bootloader version: ${ version . getUint32 (
1228+ 0 ,
1229+ true ,
1230+ ) } , HW version: ${ version . getUint32 ( 4 , true ) } `,
1231+ ) ;
1232+ } catch ( err ) {
1233+ console . error ( `Failed to parse ev3 version response: ${ ensureError ( err ) } ` ) ;
1234+ }
12281235
12291236 // FIXME: should be called much earlier.
12301237 yield * put ( didStart ( ) ) ;
12311238
12321239 const sectorSize = 64 * 1024 ; // flash memory sector size
12331240 const maxPayloadSize = 1018 ; // maximum payload size for EV3 commands
12341241
1235- for ( let i = 0 ; i < action . firmware . byteLength ; i += sectorSize ) {
1236- const sectorData = action . firmware . slice ( i , i + sectorSize ) ;
1237- assert ( sectorData . byteLength <= sectorSize , 'sector data too large' ) ;
1242+ console . info ( `Firmware size: ${ action . firmware . byteLength } bytes` ) ;
1243+
1244+ // Apparently, erasing a span of the flash creates some sort of record in
1245+ // the EV3, and we can only write within a given erase span. Writes that
1246+ // cross the boundary will hang. To avoid this, we erase the whole firmware
1247+ // range at once.
1248+ const numSectors = Math . ceil ( action . firmware . byteLength / sectorSize ) ;
1249+ const erasePayload = new DataView ( new ArrayBuffer ( 8 ) ) ;
1250+ erasePayload . setUint32 ( 0 , 0 , true ) ; // start address
1251+ erasePayload . setUint32 ( 4 , numSectors * sectorSize , true ) ; // size
1252+ console . debug (
1253+ `Erasing bytes [0x${ ( 0 ) . toString ( 16 ) } , 0x${ ( numSectors * sectorSize ) . toString (
1254+ 16 ,
1255+ ) } )`,
1256+ ) ;
1257+
1258+ yield * put (
1259+ alertsShowAlert (
1260+ 'firmware' ,
1261+ 'flashProgress' ,
1262+ {
1263+ action : 'erase' ,
1264+ progress : undefined ,
1265+ } ,
1266+ firmwareBleProgressToastId ,
1267+ true ,
1268+ ) ,
1269+ ) ;
1270+
1271+ const [ , eraseError ] = yield * sendCommand (
1272+ 0xf0 ,
1273+ new Uint8Array ( erasePayload . buffer ) ,
1274+ ) ;
1275+
1276+ if ( eraseError ) {
1277+ yield * put (
1278+ alertsShowAlert ( 'alerts' , 'unexpectedError' , {
1279+ error : eraseError ,
1280+ } ) ,
1281+ ) ;
1282+ // FIXME: should have a better error reason
1283+ yield * put ( didFailToFinish ( FailToFinishReasonType . Unknown , eraseError ) ) ;
1284+ yield * put ( firmwareDidFailToFlashEV3 ( ) ) ;
1285+ yield * cleanup ( ) ;
1286+ return ;
1287+ }
1288+
1289+ // If we don't write an exact multiple of the sector size, the flash process
1290+ // will hang on the last write we send.
1291+ let firmware = action . firmware ;
1292+ if ( firmware . byteLength !== numSectors * sectorSize ) {
1293+ const paddedFirmware = new Uint8Array ( numSectors * sectorSize ) ;
1294+ paddedFirmware . set ( new Uint8Array ( firmware ) , 0 ) ;
1295+ firmware = paddedFirmware . buffer ;
1296+ }
12381297
1239- const erasePayload = new DataView ( new ArrayBuffer ( 8 ) ) ;
1240- erasePayload . setUint32 ( 0 , i , true ) ;
1241- erasePayload . setUint32 ( 4 , sectorData . byteLength , true ) ;
1242- const [ , eraseError ] = yield * sendCommand (
1243- 0xf0 ,
1244- new Uint8Array ( erasePayload . buffer ) ,
1298+ for ( let i = 0 ; i < firmware . byteLength ; i += maxPayloadSize ) {
1299+ const writeLength = Math . min ( maxPayloadSize , firmware . byteLength - i ) ;
1300+ const payload = firmware . slice ( i , i + writeLength ) ;
1301+ console . debug (
1302+ `Programming bytes [0x${ i . toString ( 16 ) } , 0x${ ( i + writeLength ) . toString (
1303+ 16 ,
1304+ ) } )`,
12451305 ) ;
12461306
1247- if ( eraseError ) {
1307+ const [ , sendError ] = yield * sendCommand ( 0xf2 , new Uint8Array ( payload ) ) ;
1308+ if ( sendError ) {
12481309 yield * put (
12491310 alertsShowAlert ( 'alerts' , 'unexpectedError' , {
1250- error : eraseError ,
1311+ error : sendError ,
12511312 } ) ,
12521313 ) ;
12531314 // FIXME: should have a better error reason
1254- yield * put ( didFailToFinish ( FailToFinishReasonType . Unknown , eraseError ) ) ;
1315+ yield * put ( didFailToFinish ( FailToFinishReasonType . Unknown , sendError ) ) ;
12551316 yield * put ( firmwareDidFailToFlashEV3 ( ) ) ;
12561317 yield * cleanup ( ) ;
12571318 return ;
12581319 }
12591320
1260- for ( let j = 0 ; j < sectorData . byteLength ; j += maxPayloadSize ) {
1261- const payload = sectorData . slice ( j , j + maxPayloadSize ) ;
1262-
1263- const [ , sendError ] = yield * sendCommand ( 0xf2 , new Uint8Array ( payload ) ) ;
1264- if ( sendError ) {
1265- yield * put (
1266- alertsShowAlert ( 'alerts' , 'unexpectedError' , {
1267- error : sendError ,
1268- } ) ,
1269- ) ;
1270- // FIXME: should have a better error reason
1271- yield * put ( didFailToFinish ( FailToFinishReasonType . Unknown , sendError ) ) ;
1272- yield * put ( firmwareDidFailToFlashEV3 ( ) ) ;
1273- yield * cleanup ( ) ;
1274- return ;
1275- }
1276- }
1277-
1278- yield * put (
1279- didProgress ( ( i + sectorData . byteLength ) / action . firmware . byteLength ) ,
1280- ) ;
1321+ const progress = ( i + writeLength ) / firmware . byteLength ;
1322+ yield * put ( didProgress ( progress ) ) ;
12811323
12821324 yield * put (
12831325 alertsShowAlert (
12841326 'firmware' ,
12851327 'flashProgress' ,
12861328 {
12871329 action : 'flash' ,
1288- progress : ( i + sectorData . byteLength ) / action . firmware . byteLength ,
1330+ progress : progress ,
12891331 } ,
12901332 firmwareBleProgressToastId ,
12911333 true ,
0 commit comments