@@ -157,7 +157,7 @@ public class ProjectActivity extends Activity implements View.OnClickListener, B
157157 private boolean minimumPermissionsGranted ;
158158
159159 private boolean inMakeCodeActionFlash = false ;
160- private String applicationHexAbsolutePath ;
160+ private int applicationSize ;
161161 private int prepareToFlashResult ;
162162
163163
@@ -1246,6 +1246,22 @@ protected void popupFailedToCreateFiles() {
12461246 popupClickFlashComplete , popupClickFlashComplete );
12471247 }
12481248
1249+ public String getCachePathAppHex () {
1250+ return this .getCacheDir () + "/application.hex" ;
1251+ }
1252+
1253+ public String getCachePathAppBin () {
1254+ return this .getCacheDir () + "/application.bin" ;
1255+ }
1256+
1257+ public String getCachePathAppDat () {
1258+ return this .getCacheDir () + "/application.dat" ;
1259+ }
1260+
1261+ public String getCachePathAppZip () {
1262+ return this .getCacheDir () + "/update.zip" ;
1263+ }
1264+
12491265 protected int prepareToFlash () {
12501266 logi ("prepareToFlash" );
12511267
@@ -1264,27 +1280,33 @@ protected int prepareToFlash() {
12641280// hexAbsolutePath = oldret[0];
12651281// int oldapplicationSize = Integer.parseInt(oldret[1]);
12661282
1267- String [] ret = universalHexToDFU (mProgramToSend .filePath , hardwareType );
1268- applicationHexAbsolutePath = ret [0 ];
1269- int applicationSize = Integer .parseInt (ret [1 ]);
1283+ applicationSize = universalHexToDFU ( mProgramToSend .filePath , hardwareType );
12701284
1271- if (applicationSize == - 1 ) {
1272- // V1 Hex on a V2
1285+ if ( applicationSize <= 0 ) {
1286+ // incompatible hex
12731287 return 1 ;
12741288 }
12751289
1276- // If V2 create init packet
1277- String initPacketAbsolutePath = "-1" ;
1278- if (hardwareType == MICROBIT_V2 ) {
1279- try {
1280- initPacketAbsolutePath = createDFUInitPacket (applicationSize );
1281- String [] files = new String []{initPacketAbsolutePath , applicationHexAbsolutePath };
1282- createDFUZip (files );
1283- } catch (IOException e ) {
1284- Log .v (TAG , "Failed to create init packet" );
1285- e .printStackTrace ();
1290+ try {
1291+ applicationSize = createAppBin ( hardwareType );
1292+ if ( applicationSize <= 0 ) {
12861293 return 2 ;
12871294 }
1295+
1296+ if ( hardwareType == MICROBIT_V2 ) {
1297+ // If V2 create init packet and zip package
1298+ if ( !createAppDat (applicationSize )) {
1299+ return 2 ;
1300+ }
1301+ String [] files = new String []{ getCachePathAppDat (), getCachePathAppBin ()};
1302+ if ( !createDFUZip (files )) {
1303+ return 2 ;
1304+ }
1305+ }
1306+ } catch (IOException e ) {
1307+ Log .v (TAG , "Failed to create init packet" );
1308+ e .printStackTrace ();
1309+ return 2 ;
12881310 }
12891311
12901312 return 0 ;
@@ -1306,7 +1328,7 @@ public void startDFUFlash() {
13061328
13071329 // Start DFU Service
13081330 Log .v (TAG , "Start Full DFU" );
1309- Log .v (TAG , "DFU hex : " + applicationHexAbsolutePath );
1331+ Log .v (TAG , "DFU bin : " + getCachePathAppBin () );
13101332 if (hardwareType == MICROBIT_V2 ) {
13111333 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
13121334 DfuServiceInitiator .createDfuNotificationChannel (this );
@@ -1321,7 +1343,7 @@ public void startDFUFlash() {
13211343 .setRestoreBond (true )
13221344 .setKeepBond (true )
13231345 .setForeground (true )
1324- .setZip (this . getCacheDir () + "/update.zip" );
1346+ .setZip ( getCachePathAppZip () );
13251347 final DfuServiceController controller = starter .start (this , DfuService .class );
13261348 } else {
13271349 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
@@ -1332,7 +1354,7 @@ public void startDFUFlash() {
13321354 .setKeepBond (true )
13331355 .setForceDfu (true )
13341356 .setPacketsReceiptNotificationsEnabled (true )
1335- .setBinOrHex (DfuBaseService .TYPE_APPLICATION , applicationHexAbsolutePath );
1357+ .setBinOrHex (DfuBaseService .TYPE_APPLICATION , getCachePathAppBin () );
13361358 final DfuServiceController controller = starter .start (this , DfuService .class );
13371359 }
13381360 }
@@ -1351,7 +1373,7 @@ protected void startPartialFlash() {
13511373 }
13521374 service = new Intent (application , PartialFlashingService .class );
13531375 service .putExtra ("deviceAddress" , currentMicrobit .mAddress );
1354- service .putExtra ("filepath" , applicationHexAbsolutePath ); // a path or URI must be provided.
1376+ service .putExtra ("filepath" , getCachePathAppHex () ); // a path or URI must be provided.
13551377 service .putExtra ("hardwareType" , hardwareType ); // a path or URI must be provided.
13561378 service .putExtra ("pf" , true ); // Enable partial flashing
13571379 application .startService (service );
@@ -1362,16 +1384,16 @@ protected void startPartialFlash() {
13621384 /**
13631385 * Create zip for DFU
13641386 */
1365- private String createDFUZip (String [] srcFiles ) throws IOException {
1387+ private boolean createDFUZip (String [] srcFiles ) throws IOException {
13661388 byte [] buffer = new byte [1024 ];
13671389
1368- File zipFile = new File (this . getCacheDir () + "/update.zip" );
1390+ File zipFile = new File ( getCachePathAppZip () );
13691391 if (zipFile .exists ()) {
13701392 zipFile .delete ();
13711393 }
13721394 zipFile .createNewFile ();
13731395
1374- FileOutputStream fileOutputStream = new FileOutputStream (this . getCacheDir () + "/update.zip" );
1396+ FileOutputStream fileOutputStream = new FileOutputStream ( getCachePathAppZip () );
13751397 ZipOutputStream zipOutputStream = new ZipOutputStream (fileOutputStream );
13761398
13771399 for (int i =0 ; i < srcFiles .length ; i ++) {
@@ -1393,105 +1415,102 @@ private String createDFUZip(String[] srcFiles ) throws IOException {
13931415 // close the ZipOutputStream
13941416 zipOutputStream .close ();
13951417
1396- return this . getCacheDir () + "/update.zip" ;
1418+ return true ;
13971419 }
13981420
13991421 /**
14001422 * Create DFU init packet from HEX
1401- * @param hexLength
1423+ * @param appSize
14021424 */
1403- private String createDFUInitPacket (int hexLength ) throws IOException {
1404- ByteArrayOutputStream outputInitPacket ;
1405- outputInitPacket = new ByteArrayOutputStream ();
1406-
1407- Log .v (TAG , "DFU App Length: " + hexLength );
1408-
1409- outputInitPacket .write ("microbit_app" .getBytes ()); // "microbit_app"
1410- outputInitPacket .write (new byte []{0x1 , 0 , 0 , 0 }); // Init packet version
1411- outputInitPacket .write (ByteBuffer .allocate (4 ).order (ByteOrder .LITTLE_ENDIAN ).putInt (hexLength ).array ()); // App size
1412- outputInitPacket .write (new byte []{0 , 0 , 0 , 0x0 }); // Hash Size. 0: Ignore Hash
1413- outputInitPacket .write (new byte []{
1414- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1415- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1416- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1417- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
1418- }); // Hash
1425+ private boolean createAppDat ( int appSize ) throws IOException {
1426+ Log .v (TAG , "createAppDat " + appSize );
1427+
1428+ //typedef struct {
1429+ // uint8_t magic[12]; // identify this struct "microbit_app"
1430+ // uint32_t version; // version of this struct == 1
1431+ // uint32_t app_size; // only used for DFU_FW_TYPE_APPLICATION
1432+ // uint32_t hash_size; // 32 => DFU_HASH_TYPE_SHA256 or zero to bypass hash check
1433+ // uint8_t hash_bytes[32]; // hash of whole DFU download
1434+ //} microbit_dfu_app_t;
1435+ byte [] magic = "microbit_app" .getBytes ();
1436+ byte [] sizeLE = ByteBuffer .allocate (4 ).order (ByteOrder .LITTLE_ENDIAN ).putInt ( appSize ).array ();
1437+ byte [] dat = new byte [ 56 ];
1438+ Arrays .fill ( dat , (byte ) 0 );
1439+ System .arraycopy ( magic , 0 , dat , 0 , magic .length );
1440+ dat [ 12 ] = 1 ;
1441+ System .arraycopy ( sizeLE , 0 , dat , 16 , 4 );
14191442
14201443 // Write to temp file
1421- File initPacket = new File (this . getCacheDir () + "/application.dat" );
1422- if (initPacket .exists ()) {
1423- initPacket .delete ();
1444+ File datFile = new File ( getCachePathAppDat () );
1445+ if ( datFile .exists ()) {
1446+ datFile .delete ();
14241447 }
1425- initPacket .createNewFile ();
1448+ if ( !FileUtils .writeBytesToFile ( datFile , dat )) {
1449+ return false ;
1450+ }
1451+ return true ;
1452+ }
14261453
1427- FileOutputStream outputStream ;
1428- outputStream = new FileOutputStream (initPacket );
1429- outputStream .write (outputInitPacket .toByteArray ());
1430- outputStream .flush ();
1454+ /**
1455+ * Create App BIN from HEX
1456+ */
1457+ private int createAppBin ( int hardwareType ) throws IOException {
1458+ File appHexFile = new File ( getCachePathAppHex ());
1459+ File appBinFile = new File ( getCachePathAppBin ());
14311460
1432- // Should return from here
1433- return initPacket .getAbsolutePath ();
1461+ byte [] appHex = FileUtils .readBytesFromFile ( appHexFile );
1462+ if ( appHex == null ) {
1463+ return -1 ;
1464+ }
1465+ irmHexUtils hexUtils = new irmHexUtils ();
1466+ int hexBlock = hardwareType == MICROBIT_V1
1467+ ? irmHexUtils .irmHexBlock01
1468+ : irmHexUtils .irmHexBlock03 ;
1469+ if ( !hexUtils .applicationHexToData ( appHex , hexBlock )) {
1470+ return -1 ;
1471+ }
1472+ if ( !FileUtils .writeBytesToFile ( appBinFile , hexUtils .resultData )) {
1473+ return -1 ;
1474+ }
1475+ return hexUtils .resultData .length ;
14341476 }
14351477
14361478 /**
14371479 * Process Universal Hex
14381480 * @return
14391481 */
1440- private String [] universalHexToDFU (String inputPath , int hardwareType ) {
1482+ private int universalHexToDFU ( String inputPath , int hardwareType ) {
14411483 logi ("universalHexToDFU" );
14421484 try {
1443- FileInputStream fis = new FileInputStream (inputPath );
1444- int fileSize = Integer .valueOf (FileUtils .getFileSize (inputPath ));
1445- byte [] bs = new byte [fileSize ];
1446- int i = 0 ;
1447- i = fis .read (bs );
1448-
1449- logi ("universalHexToDFU - read file" );
1485+ File inputHexFile = new File ( inputPath );
1486+ byte [] inputHex = FileUtils .readBytesFromFile ( inputHexFile );
1487+ if ( inputHex == null ) {
1488+ return -1 ;
1489+ }
1490+ logi ("universalHexToDFU - file read" );
14501491
14511492 irmHexUtils irmHexUtil = new irmHexUtils ();
14521493 int hexBlock = hardwareType == MICROBIT_V1
14531494 ? irmHexUtils .irmHexBlock01
14541495 : irmHexUtils .irmHexBlock03 ;
1455- if ( !irmHexUtil .universalHexToApplicationHex ( bs , hexBlock )) {
1456- return new String []{ "-1" , "-1" } ;
1496+ if ( !irmHexUtil .universalHexToApplicationHex ( inputHex , hexBlock )) {
1497+ return - 1 ;
14571498 }
1458- byte [] dataHex = irmHexUtil .resultHex ;
1459- int application_size = irmHexUtil .resultDataSize ;
14601499 logi ("universalHexToDFU - Finished parsing HEX" );
14611500
1462- try {
1463- File hexToFlash = new File (this .getCacheDir () + "/application.hex" );
1464- if (hexToFlash .exists ()) {
1465- hexToFlash .delete ();
1466- }
1467- hexToFlash .createNewFile ();
1468-
1469- FileOutputStream outputStream = new FileOutputStream (hexToFlash );
1470- outputStream .write ( dataHex );
1471- outputStream .flush ();
1472-
1473- // Should return from here
1474- Log .v (TAG , hexToFlash .getAbsolutePath ());
1475- String [] ret = new String [2 ];
1476- ret [0 ] = hexToFlash .getAbsolutePath ();
1477- ret [1 ] = Integer .toString (application_size );
1478-
1479- logi ("universalHexToDFU - Finished" );
1480- return ret ;
1481- } catch (IOException e ) {
1482- e .printStackTrace ();
1501+ File hexFile = new File ( getCachePathAppHex ());
1502+ if ( !FileUtils .writeBytesToFile ( hexFile , irmHexUtil .resultHex )) {
1503+ return -1 ;
14831504 }
1505+ // Should return from here
1506+ logi ("universalHexToDFU - Finished" );
1507+ return irmHexUtil .resultDataSize ;
14841508
1485- } catch (FileNotFoundException e ) {
1486- Log .e (TAG , "File not found." );
1487- e .printStackTrace ();
1488- } catch (IOException e ) {
1489- Log .e (TAG , "IO Exception." );
1509+ } catch ( Exception e ) {
14901510 e .printStackTrace ();
14911511 }
1492-
14931512 // Should not reach this
1494- return new String []{ "-1" , "-1" } ;
1513+ return - 1 ;
14951514 }
14961515
14971516// /**
0 commit comments