Skip to content

Commit

Permalink
Pair - wait for disconnect; Flash - restart after bonding (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
martinwork authored Jul 10, 2024
1 parent be90a8e commit e579722
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ public void run() {
popupPairingFailed();
}
break;
case AlreadyPaired:
// micro:bit seems to need reset even if already paired
case Paired:
handlePairingSuccessful();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ protected void onActivityResultPairing(int requestCode, int resultCode, Intent d
case REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET:
if (resultCode == RESULT_OK) {
// micro:bit should still be in Bluetooth mode
flashingChecks( true);
flashingChecks( false);
} else {
onFlashComplete();
}
Expand Down Expand Up @@ -2094,7 +2094,6 @@ public void onClick(View v) {
}
}, popupClickFlashComplete);
} else if(intent.getAction().equals(PartialFlashingService.BROADCAST_ERROR)) {
MBApp.getAppState().eventPairSendError();
final int errorCode = intent.getIntExtra(PartialFlashingService.EXTRA_DATA, 0);
String error_message = getString(R.string.connection_failed);

Expand All @@ -2108,9 +2107,16 @@ public void onClick(View v) {
case PartialFlashingService.ERROR_DFU_MODE:
error_message = getString(R.string.reset_to_dfu_mode_failed);
break;
case PartialFlashingService.ERROR_BROKEN:
error_message = getString(R.string.connection_broken);
break;
case PartialFlashingService.ERROR_BONDED:
restartPurpose();
return;
}

logi("PFResultReceiver.onReceive() :: " + error_message + " code " + errorCode);
MBApp.getAppState().eventPairSendError();

PopUp.show( error_message + "\n\n" + getString(R.string.retry),
getString(R.string.flashing_failed_title),
Expand Down Expand Up @@ -2400,6 +2406,10 @@ public void onClick(View v) {
error_message = getString(R.string.dfu_error_CODE, error_message);
break;
default:
if ( errorCode == DfuBaseService.ERROR_DEVICE_NOT_BONDED) {
restartPurpose();
return;
}
if ( errorCode == 0) {
error_message = getString(R.string.not_found);
} else {
Expand Down
103 changes: 88 additions & 15 deletions app/src/main/java/com/samsung/microbit/utils/BLEPair.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,16 @@ public class BLEPair implements BluetoothAdapter.LeScanCallback {
// Android 13 - I have seen 4 status 133s before a good connect and pair
private int pairChecks = 0;
private int pairTries = 0;
private Boolean scanning = false;
private Boolean pairing = false;
private boolean scanning = false;
private boolean pairing = false;
private boolean waitingForDisconnect = false;
private boolean wasNotBonded = false;

public enum enumResult {
None,
Found,
Connected,
AlreadyPaired,
Paired,
TimeoutScan,
TimeoutConnect,
Expand Down Expand Up @@ -165,16 +168,49 @@ private void signalProgress( enumResult state) {
}

@SuppressLint("MissingPermission")
private void signalResultPairedIfBondedAndHardwareVersionDiscovered() {
if (resultDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
// Wait for service discovery to set resultHardwareVersion
logi("Bonded resultHardwareVersion " + resultHardwareVersion);
if ( resultHardwareVersion > 0) {
signalResult(enumResult.Paired);
}
private boolean bondedAndHardwareVersionDiscovered() {
logi("bondedAndHardwareVersionDiscovered state " + resultDevice.getBondState() + " resultHardwareVersion " + resultHardwareVersion);
if ( resultDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
wasNotBonded = true;
return false;
}
// Wait for service discovery to set resultHardwareVersion
if ( resultHardwareVersion <= 0) {
return false;
}
return true;
}

@SuppressLint("MissingPermission")
private boolean startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered() {
if ( !bondedAndHardwareVersionDiscovered()) {
return false;
}
// Wait for micro:bit to disconnect
waitingForDisconnect = true;
delayStopAll();
delayStart( delayCallbackWaitingForDisconnect, 6000);
logi("Start waiting for disconnect");
return true;
}

private void onDisconnect() {
// If actually pairing, micro:bit will break the connection
// Allow time for tick to appear
logi("onDisconnect");
if ( bondedAndHardwareVersionDiscovered()) {
delayStopAll();
delayStart( delayCallbackSignalResultPaired, 300);
} else if ( waitingForDisconnect) {
delayStopAll();
delayStart( delayCallbackSignalResultPaired, 300);
} else {
logi("ERROR - disconnected");
logi("Prepare delayed retry");
gattState = enumGattState.Error;
delayStart( delayCallbackConnect, 1000);
}
}
private void logi(String message) {
if(DEBUG) {
Log.i(TAG, "### " + Thread.currentThread().getId() + " # " + message);
Expand Down Expand Up @@ -248,13 +284,15 @@ public void run() {
}
}
};

private final Runnable delayCallbackCheck = new Runnable() {
@Override
public void run() {
logi("delayCallbackCheck pairChecks " + pairChecks);
if (pairing) {
signalResultPairedIfBondedAndHardwareVersionDiscovered();
if ( startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered()) {
return;
}
if ( pairChecks > 0) {
// We are connected and polling for bonding
pairChecks -= 1;
Expand All @@ -266,6 +304,22 @@ public void run() {
}
};

private final Runnable delayCallbackWaitingForDisconnect = new Runnable() {
@Override
public void run() {
logi("delayCallbackWaitingForDisconnect wasNotBonded = " + wasNotBonded);
signalResult( wasNotBonded ? enumResult.Paired : enumResult.AlreadyPaired);
}
};

private final Runnable delayCallbackSignalResultPaired = new Runnable() {
@Override
public void run() {
logi("delayCallbackSignalResultPaired wasNotBonded = " + wasNotBonded);
signalResult( wasNotBonded ? enumResult.Paired : enumResult.AlreadyPaired);
}
};

private void delayStopAll()
{
logi("delayStopAll");
Expand All @@ -275,6 +329,8 @@ private void delayStopAll()
mainLooperHandler.removeCallbacks( delayCallbackDiscover);
mainLooperHandler.removeCallbacks( delayCallbackBond);
mainLooperHandler.removeCallbacks( delayCallbackCheck);
mainLooperHandler.removeCallbacks( delayCallbackWaitingForDisconnect);
mainLooperHandler.removeCallbacks( delayCallbackSignalResultPaired);
}

private void delayStop( Runnable callback)
Expand Down Expand Up @@ -460,8 +516,17 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState
return;
}

if ( gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDED) {
wasNotBonded = true;
}

logi("onConnectionStateChange " + newState + " status " + status);
if ( status != 0) {
if ( status != BluetoothGatt.GATT_SUCCESS) {
if ( newState == STATE_DISCONNECTED) {
onDisconnect();
return;
}
delayStopAll();
pairStop();
logi("ERROR - status");
logi("Prepare for retry after a short delay");
Expand All @@ -487,6 +552,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState
// about 600ms after establishing connection. Values 600 - 1600ms should be OK.
} else {
logi("calling discoverServices()");
wasNotBonded = true;
gattState = enumGattState.WaitingForServices;
boolean success = gatt.discoverServices();
if (!success) {
Expand All @@ -502,7 +568,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState
else if( newState == STATE_DISCONNECTED) {
// If actually pairing, micro:bit will break the connection
logi("STATE_DISCONNECTED");
delayStartCheck();
onDisconnect();
}
}

Expand Down Expand Up @@ -537,7 +603,10 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {

gattState = enumGattState.ServicesDiscovered;

if (resultDevice.getBondState() == BluetoothDevice.BOND_NONE) {
if ( startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered())
return;

if ( resultDevice.getBondState() == BluetoothDevice.BOND_NONE) {
logi("Delay calling createBond() to wait for bonding to start automatically");
delayStart( delayCallbackBond, 1500);
}
Expand Down Expand Up @@ -571,6 +640,7 @@ private Boolean pairConnect() {

paramCallback.BLEPairGetActivity().registerReceiver( pairReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));

waitingForDisconnect = false;
resultHardwareVersion = 0;
gattState = enumGattState.Connecting;
pairing = true;
Expand Down Expand Up @@ -643,13 +713,16 @@ public void onReceive(Context context, Intent intent) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
logi("pairReceiver -" + " name = " + name + " addr = " + addr + " state = " + state + " prevState = " + prevState);
if ( state != BluetoothDevice.BOND_BONDED && prevState != BluetoothDevice.BOND_BONDED) {
wasNotBonded = true;
}
if (name == null || name.isEmpty() || addr.isEmpty()) {
return;
}
// Check the changed device is the one we are trying to pair
if ( pairing && nameIsMicrobitWithCode(device.getName(), paramCallback.BLEPairGetDeviceCode())) {
if (state == BluetoothDevice.BOND_BONDED) {
signalResultPairedIfBondedAndHardwareVersionDiscovered();
startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@
<string name="connection_failed">Unable to connect</string>
<string name="reconnection_failed">Unable to reconnect</string>
<string name="reset_to_dfu_mode_failed">Unable to reset to DFU mode</string>
<string name="connection_broken">Connection lost</string>
<string name="retry">Retry?</string>
<string name="menu_import">Import</string>
<string name="menu_export">Export</string>
Expand Down
2 changes: 1 addition & 1 deletion pfLibrary

0 comments on commit e579722

Please sign in to comment.