Skip to content

Commit 4a9d74d

Browse files
committed
lock / timeout fixes
1 parent 7c35afa commit 4a9d74d

File tree

2 files changed

+102
-36
lines changed

2 files changed

+102
-36
lines changed

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
apply plugin: 'com.android.library'
22

33
android {
4-
compileSdkVersion 23
4+
compileSdkVersion 29
55

66
defaultConfig {
7-
minSdkVersion 21
8-
targetSdkVersion 22
7+
minSdkVersion 19
8+
targetSdkVersion 29
99
}
1010

1111
buildTypes {

src/main/java/org/microbit/android/partialflashing/PartialFlashingBaseService.java

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,23 @@
1212
import android.bluetooth.BluetoothManager;
1313
import android.bluetooth.BluetoothProfile;
1414
import android.content.BroadcastReceiver;
15-
import android.content.ComponentName;
1615
import android.content.Context;
1716
import android.content.Intent;
1817
import android.content.IntentFilter;
18+
import android.os.Handler;
1919
import android.os.SystemClock;
20-
import android.support.annotation.Nullable;
21-
import android.support.v4.content.LocalBroadcastManager;
22-
import android.text.style.UpdateLayout;
2320
import android.util.Log;
24-
import android.util.TimingLogger;
2521

26-
import org.microbit.android.partialflashing.HexUtils;
22+
import androidx.annotation.Nullable;
23+
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
2724

2825
import java.io.IOException;
26+
import java.lang.reflect.Method;
2927
import java.util.Arrays;
30-
import java.util.Timer;
3128
import java.util.UUID;
3229

30+
import static android.bluetooth.BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
31+
3332
/**
3433
* A class to communicate with and flash the micro:bit without having to transfer the entire HEX file
3534
* Created by samkent on 07/11/2017.
@@ -40,9 +39,11 @@ public abstract class PartialFlashingBaseService extends IntentService {
4039

4140
public static final UUID PARTIAL_FLASH_CHARACTERISTIC = UUID.fromString("e97d3b10-251d-470a-a062-fa1922dfa9a8");
4241
public static final UUID PARTIAL_FLASHING_SERVICE = UUID.fromString("e97dd91d-251d-470a-a062-fa1922dfa9a8");
43-
4442
public static final String PXT_MAGIC = "708E3B92C615A841C49866C975EE5197";
4543

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+
4647
private final static String TAG = PartialFlashingBaseService.class.getSimpleName();
4748

4849
public static final String BROADCAST_ACTION = "org.microbit.android.partialflashing.broadcast.BROADCAST_ACTION";
@@ -54,6 +55,7 @@ public abstract class PartialFlashingBaseService extends IntentService {
5455
private int mConnectionState = STATE_DISCONNECTED;
5556
private BluetoothDevice device;
5657
BluetoothGattService Service;
58+
BluetoothGattService dfuService;
5759

5860
BluetoothGattCharacteristic partialFlashCharacteristic;
5961

@@ -67,7 +69,6 @@ public abstract class PartialFlashingBaseService extends IntentService {
6769
// Used to lock the program state while we wait for a Bluetooth operation to complete
6870
private static final boolean BLE_WAITING = false;
6971
private static final boolean BLE_READY = true;
70-
private boolean bluetoothStatus = BLE_WAITING;
7172

7273
private static final int STATE_DISCONNECTED = 0;
7374
private static final int STATE_CONNECTING = 1;
@@ -128,7 +129,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status,
128129
mConnectionState = STATE_CONNECTED;
129130
Log.i(TAG, "Connected to GATT server.");
130131
Log.i(TAG, "Attempting to start service discovery:" +
131-
mBluetoothGatt.discoverServices());
132+
gatt.discoverServices());
132133

133134
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
134135
intentAction = ACTION_GATT_DISCONNECTED;
@@ -146,23 +147,30 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
146147
Log.w(TAG, "onServicesDiscovered received: " + status);
147148
}
148149

149-
Service = mBluetoothGatt.getService(PARTIAL_FLASHING_SERVICE);
150+
Service = gatt.getService(PARTIAL_FLASHING_SERVICE);
150151
if (Service == null) {
151-
Log.e(TAG, "service not found!");
152+
Log.e(TAG, "pf service not found!");
152153
}
153-
bluetoothStatus = BLE_READY;
154154

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+
}
155163
}
156164

157165
@Override
158166
// Result of a characteristic read operation
159167
public void onCharacteristicRead(BluetoothGatt gatt,
160168
BluetoothGattCharacteristic characteristic,
161169
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();
164173
}
165-
166174
}
167175

168176
@Override
@@ -172,11 +180,13 @@ public void onCharacteristicWrite(BluetoothGatt gatt,
172180
if(status == BluetoothGatt.GATT_SUCCESS) {
173181
// Success
174182
Log.v(TAG, "GATT status: Success");
175-
bluetoothStatus = BLE_READY;
176183
} else {
177184
// TODO Attempt to resend?
178185
Log.v(TAG, "GATT status:" + Integer.toString(status));
179186
}
187+
synchronized (lock) {
188+
lock.notifyAll();
189+
}
180190
}
181191

182192
@Override
@@ -221,9 +231,13 @@ public void onDescriptorWrite (BluetoothGatt gatt,
221231
int status){
222232
if(status == BluetoothGatt.GATT_SUCCESS) {
223233
Log.v(TAG, "Descriptor success");
224-
bluetoothStatus = BLE_READY;
225234
}
226235
Log.v(TAG, "GATT: " + gatt.toString() + ", Desc: " + descriptor.toString() + ", Status: " + status);
236+
237+
synchronized (lock) {
238+
lock.notifyAll();
239+
}
240+
227241
}
228242

229243
};
@@ -277,16 +291,17 @@ public Boolean writePartialFlash(byte data[]){
277291

278292

279293
public Boolean attemptPartialFlash(String filePath) {
280-
Log.v(TAG, "Flashing: filePath");
294+
Log.v(TAG, "Flashing: " + filePath);
281295
long startTime = SystemClock.elapsedRealtime();
282296

283297
int count = 0;
284298
int progressBar = 0;
285299
int numOfLines = 0;
300+
286301
try {
287302

288303
Log.v(TAG, "attemptPartialFlash()");
289-
304+
Log.v(TAG, filePath);
290305
HexUtils hex = new HexUtils(filePath);
291306
int magicIndex = hex.searchForData(PXT_MAGIC);
292307
if (magicIndex > -1) {
@@ -310,8 +325,14 @@ public Boolean attemptPartialFlash(String filePath) {
310325
int packetNum = 0;
311326
int lineCount = 0;
312327
while(true){
328+
// Timeout if total is > 60 seconds
329+
if(SystemClock.elapsedRealtime() - startTime > 60000) return false;
330+
313331
// Get next data to write
314332
hexData = hex.getDataFromIndex(magicIndex + lineCount);
333+
334+
Log.v(TAG, hexData);
335+
315336
// Check if EOF
316337
if(hex.getRecordTypeFromIndex(magicIndex + lineCount) != 0) break;
317338

@@ -343,12 +364,20 @@ public Boolean attemptPartialFlash(String filePath) {
343364
int percent = Math.round((float)100 * ((float)(lineCount) / (float)(numOfLines)));
344365
sendProgressBroadcast(percent);
345366

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+
}
348376

349-
// Reset to waiting state
350377
packetState = PACKET_STATE_WAITING;
351378

379+
Log.v(TAG, "/Wait for notification");
380+
352381
} else {
353382
Thread.sleep(3);
354383
}
@@ -367,6 +396,8 @@ public Boolean attemptPartialFlash(String filePath) {
367396

368397
}
369398

399+
400+
370401
// Write End of Flash packet
371402
byte[] endOfFlashPacket = {(byte)0x02};
372403
writePartialFlash(endOfFlashPacket);
@@ -389,6 +420,7 @@ public Boolean attemptPartialFlash(String filePath) {
389420
e.printStackTrace();
390421
}
391422

423+
392424
return true;
393425
}
394426

@@ -421,7 +453,7 @@ private static byte[] recordToByteArray(String hexString, int offset, int packet
421453
*
422454
* @return <code>true</code> if initialization was successful
423455
*/
424-
private boolean initialize(String deviceId) {
456+
private boolean initialize(String deviceId) throws InterruptedException {
425457
// For API level 18 and above, get a reference to BluetoothAdapter through
426458
// BluetoothManager.
427459
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
@@ -452,7 +484,10 @@ private boolean initialize(String deviceId) {
452484
return false;
453485
}
454486

455-
while(!bluetoothStatus);
487+
synchronized (lock) {
488+
lock.wait(2000);
489+
}
490+
456491
// Get Characteristic
457492
partialFlashCharacteristic = Service.getCharacteristic(PARTIAL_FLASH_CHARACTERISTIC);
458493

@@ -466,17 +501,18 @@ private boolean initialize(String deviceId) {
466501

467502
// Set up BLE priority
468503
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");
470505
} else {
471506
Log.v(TAG, "High priority");
472507
}
473508

474509
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);
476512

477-
bluetoothStatus = BLE_WAITING;
478-
mBluetoothGatt.writeDescriptor(descriptor);
479-
while(!bluetoothStatus);
513+
synchronized (lock) {
514+
lock.wait(2000);
515+
}
480516

481517
return true;
482518
}
@@ -491,18 +527,48 @@ protected void onHandleIntent(@Nullable Intent intent) {
491527
final String deviceAddress = intent.getStringExtra("deviceAddress");
492528

493529
Log.v(TAG, "Initialise");
494-
initialize(deviceAddress);
530+
try {
531+
initialize(deviceAddress);
532+
} catch (InterruptedException e) {
533+
e.printStackTrace();
534+
}
495535
Log.v(TAG, "/Initialise");
496536
readMemoryMap();
497537
// If fails attempt full flash
498-
if(!attemptPartialFlash(filePath))
538+
if(!attemptPartialFlash(filePath) || Service == null)
499539
{
500540
Log.v(TAG, "Partial Flashing not possible");
501541

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+
502567
final Intent broadcast = new Intent(BROADCAST_PF_FAILED);
503568

504569
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
505570
}
571+
Log.v(TAG, "onHandleIntent End");
506572
}
507573

508574
/*
@@ -518,7 +584,6 @@ private Boolean readMemoryMap() {
518584
// Request Region
519585
byte[] payload = {REGION_INFO_COMMAND, (byte)i};
520586
partialFlashCharacteristic.setValue(payload);
521-
bluetoothStatus = BLE_WAITING;
522587
notificationReceived = false;
523588
status = mBluetoothGatt.writeCharacteristic(partialFlashCharacteristic);
524589
Log.v(TAG, "Request Region " + i);
@@ -559,6 +624,7 @@ public void onReceive(Context context, final Intent intent) {
559624
@Override
560625
public void onDestroy() {
561626
super.onDestroy();
627+
Log.v(TAG, "onDestroy");
562628
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
563629
manager.unregisterReceiver(broadcastReceiver);
564630
}

0 commit comments

Comments
 (0)