12
12
import android .bluetooth .BluetoothManager ;
13
13
import android .bluetooth .BluetoothProfile ;
14
14
import android .content .BroadcastReceiver ;
15
- import android .content .ComponentName ;
16
15
import android .content .Context ;
17
16
import android .content .Intent ;
18
17
import android .content .IntentFilter ;
18
+ import android .os .Handler ;
19
19
import android .os .SystemClock ;
20
- import android .support .annotation .Nullable ;
21
- import android .support .v4 .content .LocalBroadcastManager ;
22
- import android .text .style .UpdateLayout ;
23
20
import android .util .Log ;
24
- import android .util .TimingLogger ;
25
21
26
- import org .microbit .android .partialflashing .HexUtils ;
22
+ import androidx .annotation .Nullable ;
23
+ import androidx .localbroadcastmanager .content .LocalBroadcastManager ;
27
24
28
25
import java .io .IOException ;
26
+ import java .lang .reflect .Method ;
29
27
import java .util .Arrays ;
30
- import java .util .Timer ;
31
28
import java .util .UUID ;
32
29
30
+ import static android .bluetooth .BluetoothGattDescriptor .ENABLE_NOTIFICATION_VALUE ;
31
+
33
32
/**
34
33
* A class to communicate with and flash the micro:bit without having to transfer the entire HEX file
35
34
* Created by samkent on 07/11/2017.
@@ -40,9 +39,11 @@ public abstract class PartialFlashingBaseService extends IntentService {
40
39
41
40
public static final UUID PARTIAL_FLASH_CHARACTERISTIC = UUID .fromString ("e97d3b10-251d-470a-a062-fa1922dfa9a8" );
42
41
public static final UUID PARTIAL_FLASHING_SERVICE = UUID .fromString ("e97dd91d-251d-470a-a062-fa1922dfa9a8" );
43
-
44
42
public static final String PXT_MAGIC = "708E3B92C615A841C49866C975EE5197" ;
45
43
44
+ private static final UUID MICROBIT_DFU_SERVICE = UUID .fromString ("e95d93b0-251d-470a-a062-fa1922dfa9a8" );
45
+ private static final UUID MICROBIT_DFU_CHARACTERISTIC = UUID .fromString ("e95d93b1-251d-470a-a062-fa1922dfa9a8" );
46
+
46
47
private final static String TAG = PartialFlashingBaseService .class .getSimpleName ();
47
48
48
49
public static final String BROADCAST_ACTION = "org.microbit.android.partialflashing.broadcast.BROADCAST_ACTION" ;
@@ -54,6 +55,7 @@ public abstract class PartialFlashingBaseService extends IntentService {
54
55
private int mConnectionState = STATE_DISCONNECTED ;
55
56
private BluetoothDevice device ;
56
57
BluetoothGattService Service ;
58
+ BluetoothGattService dfuService ;
57
59
58
60
BluetoothGattCharacteristic partialFlashCharacteristic ;
59
61
@@ -67,7 +69,6 @@ public abstract class PartialFlashingBaseService extends IntentService {
67
69
// Used to lock the program state while we wait for a Bluetooth operation to complete
68
70
private static final boolean BLE_WAITING = false ;
69
71
private static final boolean BLE_READY = true ;
70
- private boolean bluetoothStatus = BLE_WAITING ;
71
72
72
73
private static final int STATE_DISCONNECTED = 0 ;
73
74
private static final int STATE_CONNECTING = 1 ;
@@ -128,7 +129,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status,
128
129
mConnectionState = STATE_CONNECTED ;
129
130
Log .i (TAG , "Connected to GATT server." );
130
131
Log .i (TAG , "Attempting to start service discovery:" +
131
- mBluetoothGatt .discoverServices ());
132
+ gatt .discoverServices ());
132
133
133
134
} else if (newState == BluetoothProfile .STATE_DISCONNECTED ) {
134
135
intentAction = ACTION_GATT_DISCONNECTED ;
@@ -146,23 +147,30 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
146
147
Log .w (TAG , "onServicesDiscovered received: " + status );
147
148
}
148
149
149
- Service = mBluetoothGatt .getService (PARTIAL_FLASHING_SERVICE );
150
+ Service = gatt .getService (PARTIAL_FLASHING_SERVICE );
150
151
if (Service == null ) {
151
- Log .e (TAG , "service not found!" );
152
+ Log .e (TAG , "pf service not found!" );
152
153
}
153
- bluetoothStatus = BLE_READY ;
154
154
155
+ dfuService = gatt .getService (MICROBIT_DFU_SERVICE );
156
+ if (dfuService == null ) {
157
+ Log .e (TAG , "dfu service not found!" );
158
+ }
159
+
160
+ synchronized (lock ) {
161
+ lock .notifyAll ();
162
+ }
155
163
}
156
164
157
165
@ Override
158
166
// Result of a characteristic read operation
159
167
public void onCharacteristicRead (BluetoothGatt gatt ,
160
168
BluetoothGattCharacteristic characteristic ,
161
169
int status ) {
162
- if (status == BluetoothGatt .GATT_SUCCESS ) {
163
- bluetoothStatus = BLE_READY ;
170
+ Log .v (TAG , String .valueOf (status ));
171
+ synchronized (lock ) {
172
+ lock .notifyAll ();
164
173
}
165
-
166
174
}
167
175
168
176
@ Override
@@ -172,11 +180,13 @@ public void onCharacteristicWrite(BluetoothGatt gatt,
172
180
if (status == BluetoothGatt .GATT_SUCCESS ) {
173
181
// Success
174
182
Log .v (TAG , "GATT status: Success" );
175
- bluetoothStatus = BLE_READY ;
176
183
} else {
177
184
// TODO Attempt to resend?
178
185
Log .v (TAG , "GATT status:" + Integer .toString (status ));
179
186
}
187
+ synchronized (lock ) {
188
+ lock .notifyAll ();
189
+ }
180
190
}
181
191
182
192
@ Override
@@ -221,9 +231,13 @@ public void onDescriptorWrite (BluetoothGatt gatt,
221
231
int status ){
222
232
if (status == BluetoothGatt .GATT_SUCCESS ) {
223
233
Log .v (TAG , "Descriptor success" );
224
- bluetoothStatus = BLE_READY ;
225
234
}
226
235
Log .v (TAG , "GATT: " + gatt .toString () + ", Desc: " + descriptor .toString () + ", Status: " + status );
236
+
237
+ synchronized (lock ) {
238
+ lock .notifyAll ();
239
+ }
240
+
227
241
}
228
242
229
243
};
@@ -277,16 +291,17 @@ public Boolean writePartialFlash(byte data[]){
277
291
278
292
279
293
public Boolean attemptPartialFlash (String filePath ) {
280
- Log .v (TAG , "Flashing: filePath" );
294
+ Log .v (TAG , "Flashing: " + filePath );
281
295
long startTime = SystemClock .elapsedRealtime ();
282
296
283
297
int count = 0 ;
284
298
int progressBar = 0 ;
285
299
int numOfLines = 0 ;
300
+
286
301
try {
287
302
288
303
Log .v (TAG , "attemptPartialFlash()" );
289
-
304
+ Log . v ( TAG , filePath );
290
305
HexUtils hex = new HexUtils (filePath );
291
306
int magicIndex = hex .searchForData (PXT_MAGIC );
292
307
if (magicIndex > -1 ) {
@@ -310,8 +325,14 @@ public Boolean attemptPartialFlash(String filePath) {
310
325
int packetNum = 0 ;
311
326
int lineCount = 0 ;
312
327
while (true ){
328
+ // Timeout if total is > 60 seconds
329
+ if (SystemClock .elapsedRealtime () - startTime > 60000 ) return false ;
330
+
313
331
// Get next data to write
314
332
hexData = hex .getDataFromIndex (magicIndex + lineCount );
333
+
334
+ Log .v (TAG , hexData );
335
+
315
336
// Check if EOF
316
337
if (hex .getRecordTypeFromIndex (magicIndex + lineCount ) != 0 ) break ;
317
338
@@ -343,12 +364,20 @@ public Boolean attemptPartialFlash(String filePath) {
343
364
int percent = Math .round ((float )100 * ((float )(lineCount ) / (float )(numOfLines )));
344
365
sendProgressBroadcast (percent );
345
366
346
- while (packetState == PACKET_STATE_WAITING );
347
- Log .v (TAG , "/Wait for notification" );
367
+ long timeout = SystemClock .elapsedRealtime ();
368
+ while (packetState == PACKET_STATE_WAITING ) {
369
+ synchronized (lock ) {
370
+ lock .wait (1 );
371
+ }
372
+
373
+ // Timeout if longer than 5 seconds
374
+ if ((SystemClock .elapsedRealtime () - timeout ) > 5000 ) return false ;
375
+ }
348
376
349
- // Reset to waiting state
350
377
packetState = PACKET_STATE_WAITING ;
351
378
379
+ Log .v (TAG , "/Wait for notification" );
380
+
352
381
} else {
353
382
Thread .sleep (3 );
354
383
}
@@ -367,6 +396,8 @@ public Boolean attemptPartialFlash(String filePath) {
367
396
368
397
}
369
398
399
+
400
+
370
401
// Write End of Flash packet
371
402
byte [] endOfFlashPacket = {(byte )0x02 };
372
403
writePartialFlash (endOfFlashPacket );
@@ -389,6 +420,7 @@ public Boolean attemptPartialFlash(String filePath) {
389
420
e .printStackTrace ();
390
421
}
391
422
423
+
392
424
return true ;
393
425
}
394
426
@@ -421,7 +453,7 @@ private static byte[] recordToByteArray(String hexString, int offset, int packet
421
453
*
422
454
* @return <code>true</code> if initialization was successful
423
455
*/
424
- private boolean initialize (String deviceId ) {
456
+ private boolean initialize (String deviceId ) throws InterruptedException {
425
457
// For API level 18 and above, get a reference to BluetoothAdapter through
426
458
// BluetoothManager.
427
459
mBluetoothManager = (BluetoothManager ) getSystemService (Context .BLUETOOTH_SERVICE );
@@ -452,7 +484,10 @@ private boolean initialize(String deviceId) {
452
484
return false ;
453
485
}
454
486
455
- while (!bluetoothStatus );
487
+ synchronized (lock ) {
488
+ lock .wait (2000 );
489
+ }
490
+
456
491
// Get Characteristic
457
492
partialFlashCharacteristic = Service .getCharacteristic (PARTIAL_FLASH_CHARACTERISTIC );
458
493
@@ -466,17 +501,18 @@ private boolean initialize(String deviceId) {
466
501
467
502
// Set up BLE priority
468
503
if (mBluetoothGatt .requestConnectionPriority (BluetoothGatt .CONNECTION_PRIORITY_HIGH )){
469
- Log .e (TAG , "Failed to set up priority" );
504
+ Log .w (TAG , "Failed to set up priority" );
470
505
} else {
471
506
Log .v (TAG , "High priority" );
472
507
}
473
508
474
509
BluetoothGattDescriptor descriptor = partialFlashCharacteristic .getDescriptor (CLIENT_CHARACTERISTIC_CONFIG );
475
- descriptor .setValue (BluetoothGattDescriptor .ENABLE_NOTIFICATION_VALUE );
510
+ descriptor .setValue (ENABLE_NOTIFICATION_VALUE );
511
+ boolean res = mBluetoothGatt .writeDescriptor (descriptor );
476
512
477
- bluetoothStatus = BLE_WAITING ;
478
- mBluetoothGatt . writeDescriptor ( descriptor );
479
- while (! bluetoothStatus );
513
+ synchronized ( lock ) {
514
+ lock . wait ( 2000 );
515
+ }
480
516
481
517
return true ;
482
518
}
@@ -491,18 +527,48 @@ protected void onHandleIntent(@Nullable Intent intent) {
491
527
final String deviceAddress = intent .getStringExtra ("deviceAddress" );
492
528
493
529
Log .v (TAG , "Initialise" );
494
- initialize (deviceAddress );
530
+ try {
531
+ initialize (deviceAddress );
532
+ } catch (InterruptedException e ) {
533
+ e .printStackTrace ();
534
+ }
495
535
Log .v (TAG , "/Initialise" );
496
536
readMemoryMap ();
497
537
// If fails attempt full flash
498
- if (!attemptPartialFlash (filePath ))
538
+ if (!attemptPartialFlash (filePath ) || Service == null )
499
539
{
500
540
Log .v (TAG , "Partial Flashing not possible" );
501
541
542
+ // Write Characteristic to enter DFU mode
543
+ BluetoothGattCharacteristic microbitDFUCharacteristic = dfuService .getCharacteristic (MICROBIT_DFU_CHARACTERISTIC );
544
+ byte payload [] = {0x01 };
545
+ microbitDFUCharacteristic .setValue (payload );
546
+ boolean status = mBluetoothGatt .writeCharacteristic (microbitDFUCharacteristic );
547
+ Log .v (TAG , "MicroBitDFU :: Enter DFU Result " + status );
548
+
549
+ // Wait
550
+ try {
551
+ Thread .sleep (500 );
552
+ } catch (InterruptedException e ) {
553
+ e .printStackTrace ();
554
+ }
555
+
556
+ // Refresh services
557
+ try {
558
+ // BluetoothGatt gatt
559
+ final Method refresh = mBluetoothGatt .getClass ().getMethod ("refresh" );
560
+ if (refresh != null ) {
561
+ refresh .invoke (mBluetoothGatt );
562
+ }
563
+ } catch (Exception e ) {
564
+ // Log it
565
+ }
566
+
502
567
final Intent broadcast = new Intent (BROADCAST_PF_FAILED );
503
568
504
569
LocalBroadcastManager .getInstance (this ).sendBroadcast (broadcast );
505
570
}
571
+ Log .v (TAG , "onHandleIntent End" );
506
572
}
507
573
508
574
/*
@@ -518,7 +584,6 @@ private Boolean readMemoryMap() {
518
584
// Request Region
519
585
byte [] payload = {REGION_INFO_COMMAND , (byte )i };
520
586
partialFlashCharacteristic .setValue (payload );
521
- bluetoothStatus = BLE_WAITING ;
522
587
notificationReceived = false ;
523
588
status = mBluetoothGatt .writeCharacteristic (partialFlashCharacteristic );
524
589
Log .v (TAG , "Request Region " + i );
@@ -559,6 +624,7 @@ public void onReceive(Context context, final Intent intent) {
559
624
@ Override
560
625
public void onDestroy () {
561
626
super .onDestroy ();
627
+ Log .v (TAG , "onDestroy" );
562
628
final LocalBroadcastManager manager = LocalBroadcastManager .getInstance (this );
563
629
manager .unregisterReceiver (broadcastReceiver );
564
630
}
0 commit comments