Skip to content

Commit 021cda9

Browse files
committed
Projects - use BIN file for DFU
1 parent d535b56 commit 021cda9

File tree

1 file changed

+110
-91
lines changed

1 file changed

+110
-91
lines changed

app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java

Lines changed: 110 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)