mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-25 17:25:16 +03:00
Refactor port handler (#3984)
* Refactor port handler and fix reconnect * Fix as per review * Don't auto-connect for virtual or manual * Fix auto-connect switch state * Move auto-connect title to the parent div The checkbox is "hidden" under the switchary library, so move to the parent to be able to show it. * Select active port when request permission port exists before * Fix retun value for webserial requestPemission
This commit is contained in:
parent
a6e3761c26
commit
ff83600a43
6 changed files with 228 additions and 386 deletions
|
@ -44,13 +44,15 @@
|
|||
</select>
|
||||
</div>
|
||||
<div id="auto-connect-and-baud">
|
||||
<div id="auto-connect-switch">
|
||||
<div
|
||||
id="auto-connect-switch"
|
||||
:title="value.autoConnect ? $t('autoConnectEnabled') : $t('autoConnectDisabled')"
|
||||
>
|
||||
<input
|
||||
id="auto-connect"
|
||||
class="auto_connect togglesmall"
|
||||
type="checkbox"
|
||||
:value="value.autoConnect"
|
||||
:title="value.autoConnect ? $t('autoConnectEnabled') : $t('autoConnectDisabled')"
|
||||
:checked="value.autoConnect"
|
||||
@change="onChangeAutoConnect"
|
||||
>
|
||||
<span class="auto_connect">
|
||||
|
|
|
@ -14,7 +14,6 @@ const DEFAULT_BAUDS = 115200;
|
|||
|
||||
const PortHandler = new function () {
|
||||
this.currentPorts = [];
|
||||
this.initialPorts = false;
|
||||
this.portPicker = {
|
||||
selectedPort: DEFAULT_PORT,
|
||||
selectedBauds: DEFAULT_BAUDS,
|
||||
|
@ -23,24 +22,29 @@ const PortHandler = new function () {
|
|||
autoConnect: getConfig('autoConnect').autoConnect,
|
||||
};
|
||||
this.portPickerDisabled = false;
|
||||
this.port_detected_callbacks = [];
|
||||
this.port_removed_callbacks = [];
|
||||
this.dfu_available = false;
|
||||
this.port_available = false;
|
||||
this.dfuAvailable = false;
|
||||
this.portAvailable = false;
|
||||
this.showAllSerialDevices = false;
|
||||
this.showVirtualMode = getConfig('showVirtualMode').showVirtualMode;
|
||||
this.showManualMode = getConfig('showManualMode').showManualMode;
|
||||
this.showAllSerialDevices = getConfig('showAllSerialDevices').showAllSerialDevices;
|
||||
};
|
||||
|
||||
PortHandler.initialize = function () {
|
||||
|
||||
EventBus.$on('ports-input:request-permission', this.askPermissionPort.bind(this));
|
||||
EventBus.$on('ports-input:request-permission', this.askSerialPermissionPort.bind(this));
|
||||
EventBus.$on('ports-input:change', this.onChangeSelectedPort.bind(this));
|
||||
|
||||
serial.addEventListener("addedDevice", this.check_serial_devices.bind(this));
|
||||
serial.addEventListener("removedDevice", this.check_serial_devices.bind(this));
|
||||
serial.addEventListener("addedDevice", (event) => this.addedSerialDevice(event.detail));
|
||||
serial.addEventListener("removedDevice", (event) => this.removedSerialDevice(event.detail));
|
||||
|
||||
this.reinitialize(); // just to prevent code redundancy
|
||||
if (!this.portAvailable) {
|
||||
this.check_usb_devices();
|
||||
}
|
||||
|
||||
if (!this.dfuAvailable) {
|
||||
this.addedSerialDevice();
|
||||
}
|
||||
};
|
||||
|
||||
PortHandler.setShowVirtualMode = function (showVirtualMode) {
|
||||
|
@ -53,57 +57,103 @@ PortHandler.setShowManualMode = function (showManualMode) {
|
|||
this.selectActivePort();
|
||||
};
|
||||
|
||||
PortHandler.reinitialize = function () {
|
||||
this.initialPorts = false;
|
||||
|
||||
this.showAllSerialDevices = getConfig('showAllSerialDevices').showAllSerialDevices;
|
||||
|
||||
this.check(); // start listening, check after TIMEOUT_CHECK ms
|
||||
};
|
||||
|
||||
PortHandler.check = function () {
|
||||
const self = this;
|
||||
|
||||
if (!self.port_available) {
|
||||
self.check_usb_devices();
|
||||
}
|
||||
|
||||
if (!self.dfu_available) {
|
||||
self.check_serial_devices();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PortHandler.check_serial_devices = function () {
|
||||
const self = this;
|
||||
|
||||
const updatePorts = function(cp) {
|
||||
|
||||
self.currentPorts = cp;
|
||||
|
||||
// auto-select port (only during initialization)
|
||||
if (!self.initialPorts) {
|
||||
self.updatePortSelect(self.currentPorts);
|
||||
self.selectActivePort();
|
||||
self.initialPorts = {...self.currentPorts};
|
||||
GUI.updateManualPortVisibility();
|
||||
self.detectPort();
|
||||
} else {
|
||||
self.removePort();
|
||||
self.detectPort();
|
||||
// already done in detectPort
|
||||
// self.selectActivePort();
|
||||
PortHandler.addedSerialDevice = function (device) {
|
||||
this.updateCurrentPortsList()
|
||||
.then(() => {
|
||||
const selectedPort = this.selectActivePort(device);
|
||||
if (!device || selectedPort === device.path) {
|
||||
// Send this event when the port handler auto selects a new device
|
||||
EventBus.$emit('port-handler:auto-select-device', selectedPort);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
serial.getDevices().then(updatePorts);
|
||||
PortHandler.removedSerialDevice = function (device) {
|
||||
this.updateCurrentPortsList()
|
||||
.then(() => {
|
||||
if (this.portPicker.selectedPort === device.path) {
|
||||
this.selectActivePort();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.onChangeSelectedPort = function(port) {
|
||||
this.portPicker.selectedPort = port;
|
||||
};
|
||||
|
||||
PortHandler.updateCurrentPortsList = function () {
|
||||
return serial.getDevices()
|
||||
.then((ports) => {
|
||||
ports = this.sortPorts(ports);
|
||||
this.currentPorts = ports;
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.sortPorts = function(ports) {
|
||||
return ports.sort(function(a, b) {
|
||||
return a.path.localeCompare(b.path, window.navigator.language, {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.askSerialPermissionPort = function() {
|
||||
serial.requestPermissionDevice()
|
||||
.then((port) => {
|
||||
// When giving permission to a new device, the port is selected in the handleNewDevice method, but if the user
|
||||
// selects a device that had already permission, or cancels the permission request, we need to select the port
|
||||
// so do it here too
|
||||
this.selectActivePort(port);
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.selectActivePort = function(suggestedDevice) {
|
||||
|
||||
// Return the same that is connected
|
||||
if (serial.connected) {
|
||||
return serial.getConnectedPort();
|
||||
}
|
||||
|
||||
let selectedPort;
|
||||
const deviceFilter = ['AT32', 'CP210', 'SPR', 'STM'];
|
||||
|
||||
if (suggestedDevice) {
|
||||
selectedPort = suggestedDevice.path;
|
||||
this.portAvailable = true;
|
||||
} else {
|
||||
for (let port of this.currentPorts) {
|
||||
const portName = port.displayName;
|
||||
const pathSelect = port.path;
|
||||
const deviceRecognized = deviceFilter.some(device => portName.includes(device));
|
||||
const legacyDeviceRecognized = portName.includes('usb');
|
||||
if (deviceRecognized || legacyDeviceRecognized) {
|
||||
selectedPort = pathSelect;
|
||||
this.portAvailable = true;
|
||||
console.log(`Porthandler detected device ${portName} on port: ${pathSelect}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedPort) {
|
||||
this.portAvailable = false;
|
||||
if (this.showVirtualMode) {
|
||||
selectedPort = "virtual";
|
||||
} else if (this.showManualMode) {
|
||||
selectedPort = "manual";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.portPicker.selectedPort = selectedPort || DEFAULT_PORT;
|
||||
console.log(`Porthandler default device is '${this.portPicker.selectedPort}'`);
|
||||
return selectedPort;
|
||||
};
|
||||
|
||||
/************************************
|
||||
// TODO all the methods from here need to be refactored or removed
|
||||
************************************/
|
||||
|
||||
PortHandler.check_usb_devices = function (callback) {
|
||||
|
||||
// TODO needs USB code refactor for web
|
||||
|
@ -144,243 +194,34 @@ PortHandler.check_usb_devices = function (callback) {
|
|||
|
||||
self.portPickerElement.val('DFU').trigger('change');
|
||||
self.setPortsInputWidth();
|
||||
self.dfu_available = true;
|
||||
self.dfuAvailable = true;
|
||||
}
|
||||
} else if (dfuElement.length) {
|
||||
dfuElement.remove();
|
||||
self.setPortsInputWidth();
|
||||
self.dfu_available = false;
|
||||
self.dfuAvailable = false;
|
||||
|
||||
if ($('option:selected', self.portPickerElement).val() !== 'DFU') {
|
||||
if (!(GUI.connected_to || GUI.connect_lock)) {
|
||||
FC.resetState();
|
||||
}
|
||||
|
||||
if (self.dfu_available) {
|
||||
if (self.dfuAvailable) {
|
||||
self.portPickerElement.trigger('change');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(self.dfu_available);
|
||||
callback(self.dfuAvailable);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.removePort = function() {
|
||||
const self = this;
|
||||
const removePorts = self.array_difference(self.initialPorts, self.currentPorts);
|
||||
|
||||
if (removePorts.length) {
|
||||
console.log(`PortHandler - Removed: ${JSON.stringify(removePorts)}`);
|
||||
self.port_available = false;
|
||||
// disconnect "UI" - routine can't fire during atmega32u4 reboot procedure !!!
|
||||
if (removePorts.some(port => port.path === GUI.connected_to)) {
|
||||
$('div.connect_controls a.connect').click();
|
||||
$('div.connect_controls a.connect.active').click();
|
||||
}
|
||||
// trigger callbacks (only after initialization)
|
||||
for (let i = (self.port_removed_callbacks.length - 1); i >= 0; i--) {
|
||||
const obj = self.port_removed_callbacks[i];
|
||||
|
||||
// remove timeout
|
||||
clearTimeout(obj.timer);
|
||||
|
||||
// trigger callback
|
||||
obj.code(removePorts);
|
||||
|
||||
// remove object from array
|
||||
const index = self.port_removed_callbacks.indexOf(obj);
|
||||
if (index > -1) {
|
||||
self.port_removed_callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
for (const port of removePorts) {
|
||||
self.initialPorts.splice(self.initialPorts.indexOf(port, 1));
|
||||
}
|
||||
self.updatePortSelect(self.initialPorts);
|
||||
}
|
||||
};
|
||||
|
||||
PortHandler.detectPort = function() {
|
||||
const self = this;
|
||||
const newPorts = self.array_difference(self.currentPorts, self.initialPorts);
|
||||
|
||||
if (newPorts.length) {
|
||||
self.updatePortSelect(self.currentPorts);
|
||||
console.log(`PortHandler - Found: ${JSON.stringify(newPorts)}`);
|
||||
|
||||
if (newPorts.length === 1) {
|
||||
this.portPicker.selectedPort = newPorts[0].path;
|
||||
} else {
|
||||
self.selectActivePort();
|
||||
}
|
||||
|
||||
self.port_available = true;
|
||||
|
||||
// auto-connect if enabled
|
||||
if (this.portPicker.autoConnect && !GUI.connecting_to && !GUI.connected_to && GUI.active_tab !== 'firmware_flasher') {
|
||||
// start connect procedure. We need firmware flasher protection over here
|
||||
$('div.connect_controls a.connect').click();
|
||||
}
|
||||
// trigger callbacks
|
||||
for (let i = (self.port_detected_callbacks.length - 1); i >= 0; i--) {
|
||||
const obj = self.port_detected_callbacks[i];
|
||||
|
||||
// remove timeout
|
||||
clearTimeout(obj.timer);
|
||||
|
||||
// trigger callback
|
||||
obj.code(newPorts);
|
||||
|
||||
// remove object from array
|
||||
const index = self.port_detected_callbacks.indexOf(obj);
|
||||
if (index > -1) {
|
||||
self.port_detected_callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
self.initialPorts = self.currentPorts;
|
||||
}
|
||||
};
|
||||
|
||||
PortHandler.sortPorts = function(ports) {
|
||||
return ports.sort(function(a, b) {
|
||||
return a.path.localeCompare(b.path, window.navigator.language, {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.updatePortSelect = function (ports) {
|
||||
ports = this.sortPorts(ports);
|
||||
this.currentPorts = ports;
|
||||
};
|
||||
|
||||
PortHandler.askPermissionPort = function() {
|
||||
serial.requestPermissionDevice().then(() => {
|
||||
this.check_serial_devices();
|
||||
}).catch(() => {
|
||||
// In the catch we call the check_serial_devices too to change the request permission option from the select for other
|
||||
this.check_serial_devices();
|
||||
});
|
||||
};
|
||||
|
||||
PortHandler.selectActivePort = function() {
|
||||
|
||||
let selectedPort;
|
||||
|
||||
const deviceFilter = ['AT32', 'CP210', 'SPR', 'STM'];
|
||||
for (let port of this.currentPorts) {
|
||||
const portName = port.displayName;
|
||||
if (portName) {
|
||||
const pathSelect = port.path;
|
||||
const deviceRecognized = deviceFilter.some(device => portName.includes(device));
|
||||
const legacyDeviceRecognized = portName.includes('usb');
|
||||
if (deviceRecognized || legacyDeviceRecognized) {
|
||||
selectedPort = pathSelect;
|
||||
this.port_available = true;
|
||||
console.log(`Porthandler detected device ${portName} on port: ${pathSelect}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedPort) {
|
||||
if (this.showVirtualMode) {
|
||||
selectedPort = "virtual";
|
||||
} else if (this.showManualMode) {
|
||||
selectedPort = "manual";
|
||||
}
|
||||
}
|
||||
|
||||
this.portPicker.selectedPort = selectedPort || DEFAULT_PORT;
|
||||
console.log(`Porthandler default device is '${this.portPicker.selectedPort}'`);
|
||||
};
|
||||
|
||||
PortHandler.port_detected = function(name, code, timeout, ignore_timeout) {
|
||||
const self = this;
|
||||
const obj = {'name': name,
|
||||
'code': code,
|
||||
'timeout': (timeout) ? timeout : 10000,
|
||||
};
|
||||
|
||||
if (!ignore_timeout) {
|
||||
obj.timer = setTimeout(function() {
|
||||
console.log(`PortHandler - timeout - ${obj.name}`);
|
||||
|
||||
// trigger callback
|
||||
code(false);
|
||||
|
||||
// remove object from array
|
||||
const index = self.port_detected_callbacks.indexOf(obj);
|
||||
if (index > -1) {
|
||||
self.port_detected_callbacks.splice(index, 1);
|
||||
}
|
||||
}, (timeout) ? timeout : 10000);
|
||||
} else {
|
||||
obj.timer = false;
|
||||
obj.timeout = false;
|
||||
}
|
||||
|
||||
this.port_detected_callbacks.push(obj);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
PortHandler.port_removed = function (name, code, timeout, ignore_timeout) {
|
||||
const self = this;
|
||||
const obj = {'name': name,
|
||||
'code': code,
|
||||
'timeout': (timeout) ? timeout : 10000,
|
||||
};
|
||||
|
||||
if (!ignore_timeout) {
|
||||
obj.timer = setTimeout(function () {
|
||||
console.log(`PortHandler - timeout - ${obj.name}`);
|
||||
|
||||
// trigger callback
|
||||
code(false);
|
||||
|
||||
// remove object from array
|
||||
const index = self.port_removed_callbacks.indexOf(obj);
|
||||
if (index > -1) {
|
||||
self.port_removed_callbacks.splice(index, 1);
|
||||
}
|
||||
}, (timeout) ? timeout : 10000);
|
||||
} else {
|
||||
obj.timer = false;
|
||||
obj.timeout = false;
|
||||
}
|
||||
|
||||
this.port_removed_callbacks.push(obj);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
// accepting single level array with "value" as key
|
||||
PortHandler.array_difference = function (firstArray, secondArray) {
|
||||
const cloneArray = [];
|
||||
|
||||
// create hardcopy
|
||||
for (let i = 0; i < firstArray.length; i++) {
|
||||
cloneArray.push(firstArray[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < secondArray.length; i++) {
|
||||
const elementExists = cloneArray.findIndex(element => element.path === secondArray[i].path);
|
||||
if (elementExists !== -1) {
|
||||
cloneArray.splice(elementExists, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return cloneArray;
|
||||
};
|
||||
|
||||
PortHandler.flush_callbacks = function () {
|
||||
let killed = 0;
|
||||
|
||||
for (let i = this.port_detected_callbacks.length - 1; i >= 0; i--) {
|
||||
for (let i = this.port_detected_callbacks?.length - 1; i >= 0; i--) {
|
||||
if (this.port_detected_callbacks[i].timer) {
|
||||
clearTimeout(this.port_detected_callbacks[i].timer);
|
||||
}
|
||||
|
@ -389,7 +230,7 @@ PortHandler.flush_callbacks = function () {
|
|||
killed++;
|
||||
}
|
||||
|
||||
for (let i = this.port_removed_callbacks.length - 1; i >= 0; i--) {
|
||||
for (let i = this.port_removed_callbacks?.length - 1; i >= 0; i--) {
|
||||
if (this.port_removed_callbacks[i].timer) {
|
||||
clearTimeout(this.port_removed_callbacks[i].timer);
|
||||
}
|
||||
|
@ -401,6 +242,4 @@ PortHandler.flush_callbacks = function () {
|
|||
return killed;
|
||||
};
|
||||
|
||||
// temp workaround till everything is in modules
|
||||
window.PortHandler = PortHandler;
|
||||
export default PortHandler;
|
||||
|
|
|
@ -136,7 +136,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
|
|||
// wait until board boots into bootloader mode
|
||||
// MacOs may need 5 seconds delay
|
||||
function waitForDfu() {
|
||||
if (PortHandler.dfu_available) {
|
||||
if (PortHandler.dfuAvailable) {
|
||||
console.log(`DFU available after ${failedAttempts / 10} seconds`);
|
||||
clearInterval(dfuWaitInterval);
|
||||
startFlashing();
|
||||
|
|
|
@ -36,6 +36,9 @@ let liveDataRefreshTimerId = false;
|
|||
|
||||
let isConnected = false;
|
||||
|
||||
const REBOOT_CONNECT_MAX_TIME_MS = 10000;
|
||||
let rebootTimestamp = 0;
|
||||
|
||||
const toggleStatus = function () {
|
||||
isConnected = !isConnected;
|
||||
};
|
||||
|
@ -50,99 +53,31 @@ function disconnectHandler(event) {
|
|||
}
|
||||
|
||||
export function initializeSerialBackend() {
|
||||
GUI.updateManualPortVisibility = function() {
|
||||
if(isWeb()) {
|
||||
return;
|
||||
}
|
||||
const selected_port = $('#port').val();
|
||||
|
||||
$('#port-override-option').toggle(selected_port === 'manual');
|
||||
|
||||
$('#firmware-virtual-option').toggle(selected_port === 'virtual');
|
||||
|
||||
$('#auto-connect-and-baud').toggle(selected_port !== 'DFU');
|
||||
};
|
||||
|
||||
GUI.updateManualPortVisibility();
|
||||
|
||||
// TODO move to Vue
|
||||
$('#port-override').change(function () {
|
||||
setConfig({'portOverride': $('#port-override').val()});
|
||||
});
|
||||
|
||||
// TODO move to Vue
|
||||
const data = getConfig('portOverride');
|
||||
if (data.portOverride) {
|
||||
$('#port-override').val(data.portOverride);
|
||||
}
|
||||
|
||||
EventBus.$on('ports-input:change', () => GUI.updateManualPortVisibility());
|
||||
$("div.connect_controls a.connect").on('click', connectDisconnect);
|
||||
|
||||
$("div.connect_controls a.connect").on('click', function () {
|
||||
|
||||
const selectedPort = PortHandler.portPicker.selectedPort;
|
||||
let portName;
|
||||
if (selectedPort === 'manual') {
|
||||
portName = $('#port-override').val();
|
||||
} else {
|
||||
portName = selectedPort;
|
||||
EventBus.$on('port-handler:auto-select-device', function(device) {
|
||||
if (!GUI.connected_to && !GUI.connecting_to
|
||||
&& ((PortHandler.portPicker.autoConnect && !["manual", "virtual"].includes(device))
|
||||
|| Date.now() - rebootTimestamp < REBOOT_CONNECT_MAX_TIME_MS)) {
|
||||
connectDisconnect();
|
||||
}
|
||||
});
|
||||
|
||||
if (!GUI.connect_lock && selectedPort !== 'none') {
|
||||
// GUI control overrides the user control
|
||||
|
||||
GUI.configuration_loaded = false;
|
||||
|
||||
const selected_baud = PortHandler.portPicker.selectedBauds;
|
||||
const selectedPort = portName;
|
||||
|
||||
if (selectedPort === 'DFU') {
|
||||
$('select#baud').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isConnected) {
|
||||
console.log(`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.virtualApiVersion = $('#firmware-version-dropdown').val();
|
||||
|
||||
// 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);
|
||||
serial.addEventListener('connect', connectHandler);
|
||||
|
||||
serial.removeEventListener('disconnect', disconnectHandler);
|
||||
serial.addEventListener('disconnect', disconnectHandler);
|
||||
|
||||
serial.connect(portName, { baudRate });
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($('div#flashbutton a.flash_state').hasClass('active') && $('div#flashbutton a.flash').hasClass('active')) {
|
||||
$('div#flashbutton a.flash_state').removeClass('active');
|
||||
$('div#flashbutton a.flash').removeClass('active');
|
||||
}
|
||||
GUI.timeout_kill_all();
|
||||
GUI.interval_kill_all();
|
||||
GUI.tab_switch_cleanup(() => GUI.tab_switch_in_progress = false);
|
||||
|
||||
function onFinishCallback() {
|
||||
finishClose(toggleStatus);
|
||||
}
|
||||
|
||||
mspHelper?.setArmingEnabled(true, false, onFinishCallback);
|
||||
}
|
||||
serial.addEventListener("removedDevice", (event) => {
|
||||
if (event.detail.path === GUI.connected_to) {
|
||||
connectDisconnect();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -158,24 +93,79 @@ export function initializeSerialBackend() {
|
|||
}
|
||||
});
|
||||
|
||||
// auto-connect
|
||||
const result = PortHandler.portPicker.autoConnect;
|
||||
if (result === undefined || result) {
|
||||
|
||||
$('input.auto_connect').prop('checked', true);
|
||||
$('input.auto_connect, span.auto_connect').prop('title', i18n.getMessage('autoConnectEnabled'));
|
||||
|
||||
$('select#baud').val(115200).prop('disabled', true);
|
||||
} else {
|
||||
|
||||
$('input.auto_connect').prop('checked', false);
|
||||
$('input.auto_connect, span.auto_connect').prop('title', i18n.getMessage('autoConnectDisabled'));
|
||||
}
|
||||
|
||||
PortHandler.initialize();
|
||||
PortUsage.initialize();
|
||||
}
|
||||
|
||||
function connectDisconnect() {
|
||||
const selectedPort = PortHandler.portPicker.selectedPort;
|
||||
let portName;
|
||||
if (selectedPort === 'manual') {
|
||||
portName = PortHandler.portPicker.portOverride;
|
||||
} else {
|
||||
portName = selectedPort;
|
||||
}
|
||||
|
||||
if (!GUI.connect_lock && selectedPort !== 'none') {
|
||||
// GUI control overrides the user control
|
||||
|
||||
GUI.configuration_loaded = false;
|
||||
|
||||
const selected_baud = PortHandler.portPicker.selectedBauds;
|
||||
const selectedPort = portName;
|
||||
|
||||
if (selectedPort === 'DFU') {
|
||||
$('select#baud').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isConnected) {
|
||||
console.log(`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.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);
|
||||
serial.addEventListener('connect', connectHandler);
|
||||
|
||||
serial.removeEventListener('disconnect', disconnectHandler);
|
||||
serial.addEventListener('disconnect', disconnectHandler);
|
||||
|
||||
serial.connect(portName, { baudRate });
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($('div#flashbutton a.flash_state').hasClass('active') && $('div#flashbutton a.flash').hasClass('active')) {
|
||||
$('div#flashbutton a.flash_state').removeClass('active');
|
||||
$('div#flashbutton a.flash').removeClass('active');
|
||||
}
|
||||
GUI.timeout_kill_all();
|
||||
GUI.interval_kill_all();
|
||||
GUI.tab_switch_cleanup(() => GUI.tab_switch_in_progress = false);
|
||||
|
||||
function onFinishCallback() {
|
||||
finishClose(toggleStatus);
|
||||
}
|
||||
|
||||
mspHelper?.setArmingEnabled(true, false, onFinishCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function finishClose(finishedCallback) {
|
||||
if (GUI.isCordova()) {
|
||||
UI_PHONES.reset();
|
||||
|
@ -228,7 +218,7 @@ function setConnectionTimeout() {
|
|||
if (!CONFIGURATOR.connectionValid) {
|
||||
gui_log(i18n.getMessage('noConfigurationReceived'));
|
||||
|
||||
$('div.connect_controls a.connect').click(); // disconnect
|
||||
connectDisconnect();
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
|
@ -396,7 +386,7 @@ function processCustomDefaults() {
|
|||
dialog.close();
|
||||
|
||||
GUI.timeout_add('disconnect', function () {
|
||||
$('div.connect_controls a.connect').click(); // disconnect
|
||||
connectDisconnect(); // disconnect
|
||||
}, 0);
|
||||
});
|
||||
|
||||
|
@ -469,7 +459,7 @@ function checkReportProblems() {
|
|||
|
||||
abort = true;
|
||||
GUI.timeout_remove('connecting'); // kill connecting timer
|
||||
$('div.connect_controls a.connect').click(); // disconnect
|
||||
connectDisconnect(); // disconnect
|
||||
}
|
||||
|
||||
if (!abort) {
|
||||
|
@ -792,6 +782,7 @@ export function reinitializeConnection(callback) {
|
|||
}, 500);
|
||||
}
|
||||
|
||||
rebootTimestamp = Date.now();
|
||||
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false);
|
||||
|
||||
gui_log(i18n.getMessage('deviceRebooting'));
|
||||
|
@ -805,3 +796,4 @@ export function reinitializeConnection(callback) {
|
|||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1112,6 +1112,7 @@ firmware_flasher.initialize = function (callback) {
|
|||
|
||||
if (status) {
|
||||
const catch_new_port = function () {
|
||||
// TODO modify by listen to a new event
|
||||
PortHandler.port_detected('flash_detected_device', function (resultPort) {
|
||||
const port = resultPort[0];
|
||||
|
||||
|
@ -1156,7 +1157,7 @@ firmware_flasher.initialize = function (callback) {
|
|||
|
||||
|
||||
firmware_flasher.isSerialPortAvailable = function() {
|
||||
return PortHandler.port_available && !GUI.connect_lock;
|
||||
return PortHandler.portAvailable && !GUI.connect_lock;
|
||||
};
|
||||
|
||||
firmware_flasher.updateDetectBoardButton = function() {
|
||||
|
@ -1437,7 +1438,7 @@ firmware_flasher.backupConfig = function (callback) {
|
|||
// Allow reboot after CLI exit
|
||||
const waitOnReboot = () => {
|
||||
const disconnect = setInterval(function() {
|
||||
if (PortHandler.port_available) {
|
||||
if (PortHandler.portAvailable) {
|
||||
console.log(`Connection ready for flashing in ${count / 10} seconds`);
|
||||
clearInterval(disconnect);
|
||||
if (callback) {
|
||||
|
|
|
@ -30,7 +30,7 @@ class WebSerial extends EventTarget {
|
|||
|
||||
this.logHead = "SERIAL: ";
|
||||
|
||||
this.port_counter = 0;
|
||||
this.portCounter = 0;
|
||||
this.ports = [];
|
||||
this.port = null;
|
||||
this.reader = null;
|
||||
|
@ -65,8 +65,7 @@ class WebSerial extends EventTarget {
|
|||
}
|
||||
|
||||
handleDisconnect() {
|
||||
this.removeEventListener('receive', this.handleReceiveBytes);
|
||||
this.dispatchEvent(new CustomEvent("disconnect", { detail: false }));
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
getConnectedPort() {
|
||||
|
@ -75,7 +74,7 @@ class WebSerial extends EventTarget {
|
|||
|
||||
createPort(port) {
|
||||
return {
|
||||
path: `D${this.port_counter++}`,
|
||||
path: `serial_${this.portCounter++}`,
|
||||
displayName: `Betaflight ${vendorIdNames[port.getInfo().usbVendorId]}`,
|
||||
vendorId: port.getInfo().usbVendorId,
|
||||
productId: port.getInfo().usbProductId,
|
||||
|
@ -88,21 +87,27 @@ class WebSerial extends EventTarget {
|
|||
filters: webSerialDevices,
|
||||
});
|
||||
|
||||
this.port_counter = 1;
|
||||
this.portCounter = 1;
|
||||
this.ports = ports.map(function (port) {
|
||||
return this.createPort(port);
|
||||
}, this);
|
||||
}
|
||||
|
||||
async requestPermissionDevice() {
|
||||
const permissionPort = await navigator.serial.requestPort({
|
||||
filters: webSerialDevices,
|
||||
});
|
||||
const found = this.ports.find(port => port.port === permissionPort);
|
||||
if (!found) {
|
||||
return this.handleNewDevice(permissionPort);
|
||||
let newPermissionPort = null;
|
||||
try {
|
||||
const userSelectedPort = await navigator.serial.requestPort({
|
||||
filters: webSerialDevices,
|
||||
});
|
||||
newPermissionPort = this.ports.find(port => port.port === userSelectedPort);
|
||||
if (!newPermissionPort) {
|
||||
newPermissionPort = this.handleNewDevice(userSelectedPort);
|
||||
}
|
||||
console.info("User selected device from permissions:", newPermissionPort.path);
|
||||
} catch (error) {
|
||||
console.error("User didn't select any device when requesting permission:", error);
|
||||
}
|
||||
return null;
|
||||
return newPermissionPort;
|
||||
}
|
||||
|
||||
async getDevices() {
|
||||
|
@ -123,13 +128,14 @@ class WebSerial extends EventTarget {
|
|||
|
||||
if (connectionInfo && !this.openCanceled) {
|
||||
this.connected = true;
|
||||
this.connectionId = connectionInfo.connectionId;
|
||||
this.connectionId = path;
|
||||
this.bitrate = options.baudRate;
|
||||
this.bytesReceived = 0;
|
||||
this.bytesSent = 0;
|
||||
this.failed = 0;
|
||||
this.openRequested = false;
|
||||
|
||||
this.port.addEventListener("disconnect", this.handleDisconnect.bind(this));
|
||||
this.addEventListener("receive", this.handleReceiveBytes);
|
||||
|
||||
console.log(
|
||||
|
@ -186,6 +192,7 @@ class WebSerial extends EventTarget {
|
|||
this.bytesSent = 0;
|
||||
|
||||
const doCleanup = async () => {
|
||||
this.removeEventListener('receive', this.handleReceiveBytes);
|
||||
if (this.reader) {
|
||||
// this.reader.cancel();
|
||||
this.reader.releaseLock();
|
||||
|
@ -196,6 +203,7 @@ class WebSerial extends EventTarget {
|
|||
this.writer = null;
|
||||
}
|
||||
if (this.port) {
|
||||
this.port.removeEventListener("disconnect", this.handleDisconnect.bind(this));
|
||||
await this.port.close();
|
||||
this.port = null;
|
||||
}
|
||||
|
@ -235,7 +243,7 @@ class WebSerial extends EventTarget {
|
|||
);
|
||||
}
|
||||
return {
|
||||
bytesSent: this.bytesSent,
|
||||
bytesSent: data.byteLength,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue