Skip to content

Commit 8bb4ca4

Browse files
committed
Reduce load in write III
1 parent 1d30acf commit 8bb4ca4

File tree

2 files changed

+54
-46
lines changed

2 files changed

+54
-46
lines changed

android/app/src/main/java/betaflight/configurator/protocols/bluetooth/BetaflightBluetoothPlugin.java

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,12 @@ private static final class DiscoveredDevice {
105105
private Runnable connectTimeoutRunnable;
106106
private PluginCall pendingConnectCall;
107107
private String connectedDeviceId;
108+
109+
// Cached per connection
108110
private BluetoothGattCharacteristic writeCharacteristic = null;
109111
private boolean writeNoResponseSupported = false;
112+
private int cachedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
113+
110114
private final Queue<PluginCall> pendingStartNotificationCalls = new ConcurrentLinkedQueue<>();
111115
private volatile boolean servicesDiscovered = false;
112116

@@ -328,32 +332,19 @@ public void disconnect(PluginCall call) {
328332
@PluginMethod
329333
public void write(PluginCall call) {
330334
if (!ensureConnected(call)) return;
331-
332335
final BluetoothGatt gatt = bluetoothGatt;
333336
if (gatt == null || !servicesDiscovered) { call.reject("Not connected"); return; }
334337

335338
final BluetoothGattCharacteristic target = writeCharacteristic;
336339
if (target == null) { call.reject("Write characteristic not available"); return; }
337340

338-
// Params and payload decode only
339341
final String value = call.getString("value", call.getString("data"));
340342
final String encoding = call.getString("encoding", "base64");
341-
final boolean withoutResponse = call.getBoolean("withoutResponse", false);
342-
343343
final byte[] payload;
344-
try {
345-
payload = decodePayload(value, encoding);
346-
} catch (IllegalArgumentException ex) {
347-
call.reject("Failed to decode payload: " + ex.getMessage());
348-
return;
349-
}
350-
351-
// Minimal branch based on cached capability (no property reads here)
352-
final int writeType = (withoutResponse && writeNoResponseSupported)
353-
? BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
354-
: BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
344+
try { payload = decodePayload(value, encoding); }
345+
catch (IllegalArgumentException ex) { call.reject("Failed to decode payload: " + ex.getMessage()); return; }
355346

356-
final boolean ok = submitWrite(gatt, target, payload, writeType);
347+
final boolean ok = submitWrite(gatt, target, payload, cachedWriteType);
357348
if (ok) {
358349
JSObject result = new JSObject();
359350
result.put("bytesSent", payload.length);
@@ -646,6 +637,7 @@ private void cleanupGatt() {
646637
bluetoothGatt = null;
647638
writeCharacteristic = null;
648639
writeNoResponseSupported = false;
640+
cachedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
649641
connectedDeviceId = null;
650642
servicesDiscovered = false;
651643
}
@@ -948,6 +940,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState
948940
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
949941
connectionState.set(ConnectionState.DISCONNECTED);
950942
cleanupGatt();
943+
// notifyConnectionState("disconnected", null);
951944
failConnect(status == BluetoothGatt.GATT_SUCCESS ? "Disconnected" : "Connect status: " + status);
952945
}
953946
}
@@ -959,33 +952,29 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
959952

960953
writeCharacteristic = null;
961954
writeNoResponseSupported = false;
955+
cachedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
962956

963957
try {
964958
for (BluetoothGattService svc : gatt.getServices()) {
965-
BluetoothGattCharacteristic preferred = null;
966-
BluetoothGattCharacteristic fallback = null;
967-
959+
BluetoothGattCharacteristic preferred = null, fallback = null;
968960
for (BluetoothGattCharacteristic ch : svc.getCharacteristics()) {
969-
final int props = ch.getProperties();
970-
if ((props & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) {
971-
preferred = ch; // best option
972-
break;
973-
}
974-
if (fallback == null && (props & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) {
975-
fallback = ch;
976-
}
961+
int props = ch.getProperties();
962+
if ((props & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) { preferred = ch; break; }
963+
if (fallback == null && (props & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) fallback = ch;
977964
}
978-
979-
final BluetoothGattCharacteristic chosen = (preferred != null) ? preferred : fallback;
965+
BluetoothGattCharacteristic chosen = (preferred != null) ? preferred : fallback;
980966
if (chosen != null) {
981967
writeCharacteristic = chosen;
982968
writeNoResponseSupported =
983-
(chosen.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0;
969+
(chosen.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0;
970+
cachedWriteType = writeNoResponseSupported
971+
? BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
972+
: BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
984973
break;
985974
}
986975
}
987976
} catch (Exception ignored) {
988-
// leave writeCharacteristic null; write() will report unavailable
977+
// leave writeCharacteristic null; write() will reject
989978
}
990979

991980
flushPendingStartNotificationCalls();

src/js/msp/MSPHelper.js

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2933,30 +2933,49 @@ MspHelper.prototype.sendSerialConfig = function (callback) {
29332933
};
29342934

29352935
MspHelper.prototype.writeConfiguration = function (reboot, callback) {
2936-
if (reboot) {
2937-
GUI.interval_kill_all(); // stop status_pull and other tab timers immediately
2938-
MSP.callbacks_cleanup(); // drop any stale callbacks
2936+
// Quiet background traffic to avoid queue starvation on BLE
2937+
try {
2938+
GUI.interval_kill_all();
2939+
MSP.callbacks_cleanup();
2940+
} catch (e) {
2941+
console.warn("writeConfiguration: pre-save quieting failed:", e);
29392942
}
29402943

2941-
// We need some protection when testing motors on motors tab
2942-
if (!FC.CONFIG.armingDisabled) {
2943-
this.setArmingEnabled(false, false);
2944-
}
2944+
const sendEeprom = () => {
2945+
let finished = false;
2946+
const finish = () => {
2947+
if (finished) return;
2948+
finished = true;
29452949

2946-
setTimeout(function () {
2947-
MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () {
2948-
gui_log(i18n.getMessage("configurationEepromSaved"));
2949-
console.log("Configuration saved to EEPROM");
29502950
if (reboot) {
29512951
GUI.tab_switch_cleanup(function () {
29522952
return reinitializeConnection();
29532953
});
29542954
}
2955-
if (callback) {
2956-
callback();
2957-
}
2955+
if (callback) callback();
2956+
};
2957+
2958+
// Fallback in case the EEPROM ack is missed under BLE load
2959+
const fallbackTimer = setTimeout(() => {
2960+
console.warn("MSP_EEPROM_WRITE ack timeout; proceeding to reboot via fallback.");
2961+
finish();
2962+
}, 3000); // conservative for Android BLE
2963+
2964+
MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () {
2965+
clearTimeout(fallbackTimer);
2966+
gui_log(i18n.getMessage("configurationEepromSaved"));
2967+
console.log("Configuration saved to EEPROM");
2968+
finish();
29582969
});
2959-
}, 200); // 200ms delay before sending MSP_EEPROM_WRITE to ensure that all settings have been received
2970+
};
2971+
2972+
// Keep your arming safety, but don’t block on it
2973+
if (!FC.CONFIG.armingDisabled) {
2974+
this.setArmingEnabled(false, false);
2975+
setTimeout(sendEeprom, 200); // current delay retained
2976+
} else {
2977+
setTimeout(sendEeprom, 200);
2978+
}
29602979
};
29612980

29622981
let mspHelper;

0 commit comments

Comments
 (0)