1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-24 00:35:26 +03:00

Add bluetooth support (#4024)

* Add bluetooth support

* Add new files

* CLI now works over BT

* Fix MSP over bluetooth

* Cleanup

* More cleanup

* Fix bind for disconnect

* Rename port to device

* Reboot does not trigger event gattserverdisconnected

* Fix dual permission request

* Increase minimum MSP timeout for PWA

* Small refactor

* Reboot

* Do not crash when bluetooth flag is disabled

* Cleanup excessive logging

* Abstract navigator
This commit is contained in:
Mark Haslinghuis 2024-06-28 20:02:32 +02:00 committed by GitHub
parent 91dab8750e
commit 5a3f06f890
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 512 additions and 38 deletions

View file

@ -24,7 +24,6 @@ import CryptoES from "crypto-es";
import $ from 'jquery';
import BuildApi from "./BuildApi";
import { isWeb } from "./utils/isWeb";
import { serialShim } from "./serial_shim.js";
import { EventBus } from "../components/eventBus";
@ -64,6 +63,18 @@ export function initializeSerialBackend() {
}
});
EventBus.$on('port-handler:auto-select-bluetooth-device', function(device) {
if (!GUI.connected_to && !GUI.connecting_to && GUI.active_tab !== 'firmware_flasher'
&& ((PortHandler.portPicker.autoConnect && !["manual", "virtual"].includes(device))
|| Date.now() - rebootTimestamp < REBOOT_CONNECT_MAX_TIME_MS)) {
connectDisconnect();
}
});
// Using serialShim for serial and bluetooth we don't know which event we need before we connect
// Perhaps we should implement a Connection class that handles the connection and events for bluetooth, serial and sockets
// TODO: use event gattserverdisconnected for save and reboot and device removal.
serial.addEventListener("removedDevice", (event) => {
if (event.detail.path === GUI.connected_to) {
connectDisconnect();
@ -88,39 +99,39 @@ export function initializeSerialBackend() {
function connectDisconnect() {
const selectedPort = PortHandler.portPicker.selectedPort;
let portName;
if (selectedPort === 'manual') {
portName = PortHandler.portPicker.portOverride;
} else {
portName = selectedPort;
}
const portName = selectedPort === 'manual' ? PortHandler.portPicker.portOverride : selectedPort;
if (!GUI.connect_lock && selectedPort !== 'noselection' && !selectedPort.path?.startsWith('usb_')) {
// GUI control overrides the user control
GUI.configuration_loaded = false;
const selected_baud = PortHandler.portPicker.selectedBauds;
const baudRate = PortHandler.portPicker.selectedBauds;
const selectedPort = portName;
if (!isConnected) {
console.log(`Connecting to: ${portName}`);
// prevent connection when we do not have permission
if (selectedPort.startsWith('requestpermission')) {
return;
}
console.log(`[SERIAL-BACKEND] Connecting to: ${portName}`);
GUI.connecting_to = portName;
// lock port select & baud while we are connecting / connected
PortHandler.portPickerDisabled = true;
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
const baudRate = selected_baud;
if (selectedPort === 'virtual') {
CONFIGURATOR.virtualMode = true;
CONFIGURATOR.virtualMode = selectedPort === 'virtual';
CONFIGURATOR.bluetoothMode = selectedPort.startsWith('bluetooth');
if (CONFIGURATOR.virtualMode) {
CONFIGURATOR.virtualApiVersion = PortHandler.portPicker.virtualMspVersion;
// Hack to get virtual working on the web
serial = serialShim();
serial.connect('virtual', {}, onOpenVirtual);
} else {
CONFIGURATOR.virtualMode = false;
serial = serialShim();
// Explicitly disconnect the event listeners before attaching the new ones.
serial.removeEventListener('connect', connectHandler);
@ -163,6 +174,7 @@ function finishClose(finishedCallback) {
$('#dialogResetToCustomDefaults')[0].close();
}
// serialShim calls the disconnect method for selected connection type.
serial.disconnect(onClosed);
MSP.disconnect_cleanup();
@ -262,18 +274,16 @@ function onOpen(openInfo) {
result = getConfig('expertMode')?.expertMode ?? false;
$('input[name="expertModeCheckbox"]').prop('checked', result).trigger('change');
if(isWeb()) {
serial.removeEventListener('receive', read_serial_adapter);
serial.addEventListener('receive', read_serial_adapter);
} else {
serial.onReceive.addListener(read_serial);
}
// serialShim adds event listener for selected connection type
serial.removeEventListener('receive', read_serial_adapter);
serial.addEventListener('receive', read_serial_adapter);
setConnectionTimeout();
FC.resetState();
mspHelper = new MspHelper();
MSP.listen(mspHelper.process_data.bind(mspHelper));
MSP.timeout = 250;
console.log(`Requesting configuration data`);
console.log(`[SERIAL-BACKEND] Requesting configuration data`);
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, function () {
gui_log(i18n.getMessage('apiVersionReceived', FC.CONFIG.apiVersion));
@ -642,11 +652,7 @@ function onConnect() {
}
function onClosed(result) {
if (result) { // All went as expected
gui_log(i18n.getMessage('serialPortClosedOk'));
} else { // Something went wrong
gui_log(i18n.getMessage('serialPortClosedFail'));
}
gui_log(i18n.getMessage(result ? 'serialPortClosedOk' : 'serialPortClosedFail'));
$('#tabs ul.mode-connected').hide();
$('#tabs ul.mode-connected-cli').hide();
@ -760,7 +766,7 @@ function startLiveDataRefreshTimer() {
export function reinitializeConnection(callback) {
// In virtual mode reconnect when autoconnect is enabled
if (PortHandler.portPicker.selectedPort === 'virtual' && PortHandler.portPicker.autoConnect) {
if (CONFIGURATOR.virtualMode && PortHandler.portPicker.autoConnect) {
return setTimeout(function() {
$('a.connect').trigger('click');
}, 500);
@ -769,6 +775,11 @@ export function reinitializeConnection(callback) {
rebootTimestamp = Date.now();
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false);
if (CONFIGURATOR.bluetoothMode) {
// Bluetooth devices are not disconnected when rebooting
connectDisconnect();
}
gui_log(i18n.getMessage('deviceRebooting'));
// wait for the device to reboot