mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-25 17:25:16 +03:00
Make port_handler work with PWA (#3958)
* Make port_handler work with PWA * Modify the port_handler more the Vue way * Fixes after review * Fix request permission option not being deselected * Hide baud selection in port picker if virtual port * Added port override option for manual * Fix virtual port state when loading the page * Fix request permission adds the same device several times * Fix automatic selection of device under Linux
This commit is contained in:
parent
b91698d0f4
commit
fce0c8305b
12 changed files with 246 additions and 166 deletions
|
@ -62,6 +62,10 @@
|
|||
"message": "Virtual Mode (Experimental)",
|
||||
"description": "Configure a Virtual Flight Controller without the need of a physical FC."
|
||||
},
|
||||
"portsSelectPermission": {
|
||||
"message": "--- I can't find my device ---",
|
||||
"description": "Option in the port selection dropdown to allow the user to give permissions to the system to access the device."
|
||||
},
|
||||
"virtualMSPVersion": {
|
||||
"message": "Virtual Firmware Version"
|
||||
},
|
||||
|
|
|
@ -13,6 +13,7 @@ import StatusBar from "./status-bar/StatusBar.vue";
|
|||
import BatteryIcon from "./quad-status/BatteryIcon.vue";
|
||||
import FC from '../js/fc.js';
|
||||
import MSP from '../js/msp.js';
|
||||
import PortHandler from '../js/port_handler.js';
|
||||
import PortUsage from '../js/port_usage.js';
|
||||
import PortPicker from './port-picker/PortPicker.vue';
|
||||
import CONFIGURATOR from '../js/data_storage.js';
|
||||
|
@ -26,6 +27,7 @@ const betaflightModel = {
|
|||
FC,
|
||||
MSP,
|
||||
PortUsage,
|
||||
PortHandler,
|
||||
};
|
||||
|
||||
i18next.on('initialized', function() {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<div
|
||||
id="firmware-virtual-option"
|
||||
:style="{ display: isVirtual ? 'block' : 'none' }"
|
||||
>
|
||||
<div class="dropdown dropdown-dark">
|
||||
<select
|
||||
id="firmware-version-dropdown"
|
||||
class="dropdown-select"
|
||||
:title="$t('virtualMSPVersion')"
|
||||
v-model="value"
|
||||
>
|
||||
<option
|
||||
v-for="(version, index) in firmwareVersions"
|
||||
|
@ -24,9 +24,9 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
isVirtual: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
value: {
|
||||
type: String,
|
||||
default: "1.46.0",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
@ -50,7 +50,7 @@ export default {
|
|||
width: 180px;
|
||||
margin-right: 15px;
|
||||
margin-top: 0px;
|
||||
display: none;
|
||||
display: block;
|
||||
}
|
||||
.dropdown {
|
||||
display: inline-block;
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
<template>
|
||||
<div
|
||||
id="port-override-option"
|
||||
style="display: none"
|
||||
:style="{ display: isManual ? 'flex' : 'none' }"
|
||||
>
|
||||
<div id="port-override-option">
|
||||
<label
|
||||
for="port-override"
|
||||
><span>{{ $t("portOverrideText") }}</span>
|
||||
<input
|
||||
id="port-override"
|
||||
type="text"
|
||||
value="/dev/rfcomm0"
|
||||
v-model="value"
|
||||
></label>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -18,6 +14,10 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: "/dev/rfcomm0",
|
||||
},
|
||||
isManual: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
@ -29,14 +29,15 @@ export default {
|
|||
#port-override-option {
|
||||
font-family: "Open Sans", "Segoe UI", Tahoma, sans-serif;
|
||||
font-size: 12px;
|
||||
margin-top: 16px;
|
||||
margin-top: 4px;
|
||||
margin-right: 15px;
|
||||
label {
|
||||
background-color: #2b2b2b;
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
color: var(--subtleAccent);
|
||||
}
|
||||
};
|
||||
display: block;
|
||||
}
|
||||
|
||||
#port-override-option label {
|
||||
|
|
|
@ -1,24 +1,50 @@
|
|||
<template>
|
||||
<div class="web-port-picker">
|
||||
<FirmwareVirtualOption :is-virtual="port === 'virtual'" />
|
||||
<PortsInput v-model="port" />
|
||||
<PortOverrideOption
|
||||
v-if="value.selectedPort === 'manual'"
|
||||
v-model="value.portOverride"
|
||||
/>
|
||||
<FirmwareVirtualOption
|
||||
v-if="value.selectedPort === 'virtual'"
|
||||
v-model="value.virtualMspVersion"
|
||||
/>
|
||||
<PortsInput
|
||||
v-model="value"
|
||||
:connected-devices="connectedDevices"
|
||||
:disabled="disabled" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortOverrideOption from "./PortOverrideOption.vue";
|
||||
import FirmwareVirtualOption from "./FirmwareVirtualOption.vue";
|
||||
import PortsInput from "./PortsInput.vue";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: {
|
||||
selectedPort: "manual",
|
||||
selectedBaud: 115200,
|
||||
portOverride: "/dev/rfcomm0",
|
||||
virtualMspVersion: "1.46.0",
|
||||
},
|
||||
},
|
||||
connectedDevices: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
PortOverrideOption,
|
||||
FirmwareVirtualOption,
|
||||
PortsInput,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
port: 'manual',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
id="port"
|
||||
class="dropdown-select"
|
||||
:title="$t('firmwareFlasherManualPort')"
|
||||
@value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
:disabled="disabled"
|
||||
v-model="value.selectedPort"
|
||||
@change="onChange"
|
||||
>
|
||||
<option value="manual">
|
||||
{{ $t("portsSelectManual") }}
|
||||
|
@ -20,16 +21,29 @@
|
|||
>
|
||||
{{ $t("portsSelectVirtual") }}
|
||||
</option>
|
||||
<option
|
||||
v-for="connectedDevice in connectedDevices"
|
||||
:key="connectedDevice.path"
|
||||
:value="connectedDevice.path"
|
||||
>
|
||||
{{ connectedDevice.displayName }}
|
||||
</option>
|
||||
<option value="requestpermission">
|
||||
{{ $t("portsSelectPermission") }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="auto-connect-and-baud">
|
||||
<div id="baudselect">
|
||||
<div id="baudselect"
|
||||
v-if="value.selectedPort !== 'virtual'"
|
||||
>
|
||||
<div class="dropdown dropdown-dark">
|
||||
<select
|
||||
id="baud"
|
||||
v-model="selectedBaudRate"
|
||||
v-model="value.selectedBauds"
|
||||
class="dropdown-select"
|
||||
:title="$t('firmwareFlasherBaudRate')"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<option
|
||||
v-for="baudRate in baudRates"
|
||||
|
@ -52,15 +66,25 @@ import { EventBus } from '../eventBus';
|
|||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: 'manual',
|
||||
type: Object,
|
||||
default: {
|
||||
selectedPort: 'manual',
|
||||
selectedBaud: 115200,
|
||||
},
|
||||
},
|
||||
connectedDevices: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showVirtual: false,
|
||||
selectedBaudRate: "115200",
|
||||
baudRates: [
|
||||
{ value: "1000000", label: "1000000" },
|
||||
{ value: "500000", label: "500000" },
|
||||
|
@ -80,13 +104,23 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
EventBus.$on('config-storage:set', this.setShowVirtual);
|
||||
this.setShowVirtual('showVirtualMode');
|
||||
},
|
||||
destroyed() {
|
||||
EventBus.$off('config-storage:set', this.setShowVirtual);
|
||||
},
|
||||
methods: {
|
||||
setShowVirtual() {
|
||||
setShowVirtual(element) {
|
||||
if (element === 'showVirtualMode') {
|
||||
this.showVirtual = getConfig('showVirtualMode').showVirtualMode;
|
||||
}
|
||||
},
|
||||
onChange(event) {
|
||||
if (event.target.value === 'requestpermission') {
|
||||
EventBus.$emit('ports-input:request-permission');
|
||||
} else {
|
||||
EventBus.$emit('ports-input:change', event.target.value);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
:firmware-id="FC.CONFIG.flightControllerIdentifier"
|
||||
:hardware-id="FC.CONFIG.hardwareName"
|
||||
></betaflight-logo>
|
||||
<port-picker></port-picker>
|
||||
<port-picker
|
||||
v-model="PortHandler.portPicker"
|
||||
:connected-devices="PortHandler.currentPorts"
|
||||
:disabled="PortHandler.portPickerDisabled"
|
||||
></port-picker>
|
||||
<div class="header-wrapper">
|
||||
<div id="quad-status_wrapper">
|
||||
<battery-icon
|
||||
|
|
|
@ -45,7 +45,7 @@ export function set(input) {
|
|||
tmpObj[element] = input[element];
|
||||
try {
|
||||
localStorage.setItem(element, JSON.stringify(tmpObj));
|
||||
EventBus.$emit(`config-storage:set`, 'element');
|
||||
EventBus.$emit('config-storage:set', element);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,28 @@
|
|||
import GUI, { TABS } from "./gui";
|
||||
import FC from "./fc";
|
||||
import { i18n } from "./localization";
|
||||
import { generateVirtualApiVersions, getTextWidth } from './utils/common';
|
||||
import { get as getConfig } from "./ConfigStorage";
|
||||
import serial from "./serial";
|
||||
import MdnsDiscovery from "./mdns_discovery";
|
||||
import { isWeb } from "./utils/isWeb";
|
||||
import { usbDevices } from "./usb_devices";
|
||||
import { serialShim } from "./serial_shim.js";
|
||||
import { EventBus } from "../components/eventBus";
|
||||
|
||||
const TIMEOUT_CHECK = 500 ; // With 250 it seems that it produces a memory leak and slowdown in some versions, reason unknown
|
||||
const serial = serialShim();
|
||||
|
||||
const DEFAULT_PORT = 'manual';
|
||||
const DEFAULT_BAUDS = 115200;
|
||||
|
||||
const PortHandler = new function () {
|
||||
this.currentPorts = [];
|
||||
this.initialPorts = false;
|
||||
this.portPicker = {
|
||||
selectedPort: DEFAULT_PORT,
|
||||
selectedBauds: DEFAULT_BAUDS,
|
||||
portOverride: "/dev/rfcomm0",
|
||||
virtualMspVersion: "1.46.0",
|
||||
};
|
||||
this.portPickerDisabled = false;
|
||||
this.port_detected_callbacks = [];
|
||||
this.port_removed_callbacks = [];
|
||||
this.dfu_available = false;
|
||||
|
@ -24,21 +34,13 @@ const PortHandler = new function () {
|
|||
};
|
||||
|
||||
PortHandler.initialize = function () {
|
||||
const self = this;
|
||||
|
||||
// currently web build doesn't need port handler,
|
||||
// so just bail out.
|
||||
if (isWeb()) {
|
||||
return 'not implemented';
|
||||
}
|
||||
EventBus.$on('ports-input:request-permission', this.askPermissionPort.bind(this));
|
||||
EventBus.$on('ports-input:change', this.onChangeSelectedPort.bind(this));
|
||||
|
||||
const portPickerElementSelector = "div#port-picker #port";
|
||||
self.portPickerElement = $(portPickerElementSelector);
|
||||
self.selectList = document.querySelector(portPickerElementSelector);
|
||||
self.initialWidth = self.selectList.offsetWidth + 12;
|
||||
serial.addEventListener("addedDevice", this.check_serial_devices.bind(this));
|
||||
|
||||
// fill dropdown with version numbers
|
||||
generateVirtualApiVersions();
|
||||
serial.addEventListener("removedDevice", this.check_serial_devices.bind(this));
|
||||
|
||||
this.reinitialize(); // just to prevent code redundancy
|
||||
};
|
||||
|
@ -73,15 +75,15 @@ PortHandler.check = function () {
|
|||
self.check_serial_devices();
|
||||
}
|
||||
|
||||
self.usbCheckLoop = setTimeout(() => {
|
||||
self.check();
|
||||
}, TIMEOUT_CHECK);
|
||||
|
||||
this.check_serial_devices();
|
||||
|
||||
};
|
||||
|
||||
PortHandler.check_serial_devices = function () {
|
||||
const self = this;
|
||||
|
||||
serial.getDevices(function(cp) {
|
||||
const updatePorts = function(cp) {
|
||||
self.currentPorts = [];
|
||||
|
||||
if (self.useMdnsBrowser) {
|
||||
|
@ -109,11 +111,25 @@ PortHandler.check_serial_devices = function () {
|
|||
} else {
|
||||
self.removePort();
|
||||
self.detectPort();
|
||||
self.selectActivePort();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
serial.getDevices().then(updatePorts);
|
||||
};
|
||||
|
||||
PortHandler.onChangeSelectedPort = function(port) {
|
||||
this.portPicker.selectedPort = port;
|
||||
};
|
||||
|
||||
PortHandler.check_usb_devices = function (callback) {
|
||||
|
||||
// TODO needs USB code refactor for web
|
||||
if (isWeb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
|
||||
chrome.usb.getDevices(usbDevices, function (result) {
|
||||
|
@ -137,7 +153,7 @@ PortHandler.check_usb_devices = function (callback) {
|
|||
}));
|
||||
|
||||
self.portPickerElement.append($('<option/>', {
|
||||
value: 'manual',
|
||||
value: DEFAULT_PORT,
|
||||
text: i18n.getMessage('portsSelectManual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
|
@ -203,7 +219,6 @@ PortHandler.removePort = function() {
|
|||
self.initialPorts.splice(self.initialPorts.indexOf(port, 1));
|
||||
}
|
||||
self.updatePortSelect(self.initialPorts);
|
||||
self.portPickerElement.trigger('change');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -216,8 +231,8 @@ PortHandler.detectPort = function() {
|
|||
console.log(`PortHandler - Found: ${JSON.stringify(newPorts)}`);
|
||||
|
||||
if (newPorts.length === 1) {
|
||||
self.portPickerElement.val(newPorts[0].path);
|
||||
} else if (newPorts.length > 1) {
|
||||
this.portPicker.selectedPort = newPorts[0].path;
|
||||
} else {
|
||||
self.selectActivePort();
|
||||
}
|
||||
|
||||
|
@ -227,8 +242,6 @@ PortHandler.detectPort = function() {
|
|||
TABS.firmware_flasher.boardNeedsVerification = true;
|
||||
}
|
||||
|
||||
self.portPickerElement.trigger('change');
|
||||
|
||||
// auto-connect if enabled
|
||||
if (GUI.auto_connect && !GUI.connecting_to && !GUI.connected_to && GUI.active_tab !== 'firmware_flasher') {
|
||||
// start connect procedure. We need firmware flasher protection over here
|
||||
|
@ -263,105 +276,39 @@ PortHandler.sortPorts = function(ports) {
|
|||
});
|
||||
};
|
||||
|
||||
PortHandler.addNoPortSelection = function() {
|
||||
if (!this.showVirtualMode && !this.showManualMode) {
|
||||
this.portPickerElement.append($("<option/>", {
|
||||
value: 'none',
|
||||
text: i18n.getMessage('portsSelectNone'),
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
PortHandler.updatePortSelect = function (ports) {
|
||||
ports = this.sortPorts(ports);
|
||||
this.portPickerElement.empty();
|
||||
|
||||
for (const port of ports) {
|
||||
const portText = port.displayName ? `${port.path} - ${port.displayName}` : port.path;
|
||||
|
||||
this.portPickerElement.append($("<option/>", {
|
||||
value: port.path,
|
||||
text: portText,
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isManual: false},
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.showVirtualMode) {
|
||||
this.portPickerElement.append($("<option/>", {
|
||||
value: 'virtual',
|
||||
text: i18n.getMessage('portsSelectVirtual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isVirtual: true},
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.showManualMode) {
|
||||
this.portPickerElement.append($("<option/>", {
|
||||
value: 'manual',
|
||||
text: i18n.getMessage('portsSelectManual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isManual: true},
|
||||
}));
|
||||
}
|
||||
|
||||
if (!ports.length) {
|
||||
this.addNoPortSelection();
|
||||
}
|
||||
|
||||
this.setPortsInputWidth();
|
||||
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() {
|
||||
const ports = this.currentPorts;
|
||||
const OS = GUI.operating_system;
|
||||
let selectedPort;
|
||||
for (let i = 0; i < ports.length; i++) {
|
||||
const portName = ports[i].displayName;
|
||||
if (portName) {
|
||||
const pathSelect = ports[i].path;
|
||||
const isWindows = (OS === 'Windows');
|
||||
const isTty = pathSelect.includes('tty');
|
||||
const deviceFilter = ['AT32', 'CP210', 'SPR', 'STM32'];
|
||||
const deviceFilter = ['AT32', 'CP210', 'SPR', 'STM'];
|
||||
const deviceRecognized = deviceFilter.some(device => portName.includes(device));
|
||||
const legacyDeviceRecognized = portName.includes('usb');
|
||||
if (isWindows && deviceRecognized || isTty && (deviceRecognized || legacyDeviceRecognized)) {
|
||||
this.portPickerElement.val(pathSelect);
|
||||
if (deviceRecognized || legacyDeviceRecognized) {
|
||||
selectedPort = pathSelect;
|
||||
this.port_available = true;
|
||||
console.log(`Porthandler detected device ${portName} on port: ${pathSelect}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PortHandler.setPortsInputWidth = function() {
|
||||
|
||||
function findMaxLengthOption(selectEl) {
|
||||
let max = 0;
|
||||
|
||||
$(selectEl.options).each(function () {
|
||||
const textSize = getTextWidth(this.textContent);
|
||||
if (textSize > max) {
|
||||
max = textSize;
|
||||
}
|
||||
});
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
const correction = 32; // account for up/down button and spacing
|
||||
let width = findMaxLengthOption(this.selectList) + correction;
|
||||
|
||||
width = (width > this.initialWidth) ? width : this.initialWidth;
|
||||
|
||||
const portsInput = document.querySelector("div#port-picker #portsinput");
|
||||
portsInput.style.width = `${width}px`;
|
||||
this.portPicker.selectedPort = selectedPort || DEFAULT_PORT;
|
||||
};
|
||||
|
||||
PortHandler.port_detected = function(name, code, timeout, ignore_timeout) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import BuildApi from "./BuildApi";
|
|||
|
||||
import { isWeb } from "./utils/isWeb";
|
||||
import { serialShim } from "./serial_shim.js";
|
||||
import { EventBus } from "../components/eventBus";
|
||||
|
||||
let serial = serialShim();
|
||||
|
||||
|
@ -73,19 +74,16 @@ export function initializeSerialBackend() {
|
|||
$('#port-override').val(data.portOverride);
|
||||
}
|
||||
|
||||
$('div#port-picker #port').change(function (target) {
|
||||
GUI.updateManualPortVisibility();
|
||||
});
|
||||
|
||||
EventBus.$on('ports-input:change', () => GUI.updateManualPortVisibility());
|
||||
|
||||
$("div.connect_controls a.connect").on('click', function () {
|
||||
|
||||
const selectedPort = $('#port').val();
|
||||
const selectedPort = PortHandler.portPicker.selectedPort;
|
||||
let portName;
|
||||
if (selectedPort === 'manual') {
|
||||
portName = $('#port-override').val();
|
||||
} else {
|
||||
portName = String($('div#port-picker #port').val());
|
||||
portName = selectedPort;
|
||||
}
|
||||
|
||||
if (!GUI.connect_lock && selectedPort !== 'none') {
|
||||
|
@ -93,8 +91,8 @@ export function initializeSerialBackend() {
|
|||
|
||||
GUI.configuration_loaded = false;
|
||||
|
||||
const selected_baud = parseInt($('div#port-picker #baud').val());
|
||||
const selectedPort = $('#port').val();
|
||||
const selected_baud = PortHandler.portPicker.selectedBauds;
|
||||
const selectedPort = portName;
|
||||
|
||||
if (selectedPort === 'DFU') {
|
||||
$('select#baud').hide();
|
||||
|
@ -106,10 +104,10 @@ export function initializeSerialBackend() {
|
|||
GUI.connecting_to = portName;
|
||||
|
||||
// lock port select & baud while we are connecting / connected
|
||||
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
|
||||
PortHandler.portPickerDisabled = true;
|
||||
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
|
||||
|
||||
const baudRate = parseInt($('#baud').val());
|
||||
const baudRate = selected_baud;
|
||||
if (selectedPort === 'virtual') {
|
||||
CONFIGURATOR.virtualMode = true;
|
||||
CONFIGURATOR.virtualApiVersion = $('#firmware-version-dropdown').val();
|
||||
|
@ -117,7 +115,7 @@ export function initializeSerialBackend() {
|
|||
// Hack to get virtual working on the web
|
||||
serial = serialShim();
|
||||
serial.connect('virtual', {}, onOpenVirtual);
|
||||
} else if (isWeb()) {
|
||||
} else {
|
||||
CONFIGURATOR.virtualMode = false;
|
||||
serial = serialShim();
|
||||
// Explicitly disconnect the event listeners before attaching the new ones.
|
||||
|
@ -127,10 +125,7 @@ export function initializeSerialBackend() {
|
|||
serial.removeEventListener('disconnect', disconnectHandler);
|
||||
serial.addEventListener('disconnect', disconnectHandler);
|
||||
|
||||
serial.connect({ baudRate });
|
||||
} else {
|
||||
serial.connect(portName, { bitrate: selected_baud }, onOpen);
|
||||
toggleStatus();
|
||||
serial.connect(portName, { baudRate });
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -230,8 +225,7 @@ function finishClose(finishedCallback) {
|
|||
$('#dialogReportProblems-closebtn').click();
|
||||
|
||||
// unlock port select & baud
|
||||
$('div#port-picker #port').prop('disabled', false);
|
||||
if (!GUI.auto_connect) $('div#port-picker #baud').prop('disabled', false);
|
||||
PortHandler.portPickerDisabled = false;
|
||||
|
||||
// reset connect / disconnect button
|
||||
$('div.connect_controls a.connect').removeClass('active');
|
||||
|
@ -275,7 +269,7 @@ function abortConnection() {
|
|||
$('div#connectbutton a.connect').removeClass('active');
|
||||
|
||||
// unlock port select & baud
|
||||
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', false);
|
||||
PortHandler.portPickerDisabled = false;
|
||||
|
||||
// reset data
|
||||
isConnected = false;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
export const vendorIdNames = {
|
||||
1027: "FTDI",
|
||||
1155: "STM Electronics",
|
||||
4292: "Silicon Labs",
|
||||
0x2e3c: "AT32",
|
||||
};
|
||||
|
||||
export const serialDevices = [
|
||||
{ vendorId: 1027, productId: 24577 }, // FT232R USB UART
|
||||
{ vendorId: 1155, productId: 22336 }, // STM Electronics Virtual COM Port
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { webSerialDevices } from "./serial_devices";
|
||||
import { webSerialDevices, vendorIdNames } from "./serial_devices";
|
||||
|
||||
async function* streamAsyncIterable(reader, keepReadingFlag) {
|
||||
try {
|
||||
|
@ -30,12 +30,34 @@ class WebSerial extends EventTarget {
|
|||
|
||||
this.logHead = "SERIAL: ";
|
||||
|
||||
this.port_counter = 0;
|
||||
this.ports = [];
|
||||
this.port = null;
|
||||
this.reader = null;
|
||||
this.writer = null;
|
||||
this.reading = false;
|
||||
|
||||
this.connect = this.connect.bind(this);
|
||||
|
||||
navigator.serial.addEventListener("connect", e => this.handleNewDevice(e.target));
|
||||
navigator.serial.addEventListener("disconnect", e => this.handleRemovedDevice(e.target));
|
||||
|
||||
this.loadDevices();
|
||||
}
|
||||
|
||||
handleNewDevice(device) {
|
||||
|
||||
const added = this.createPort(device);
|
||||
this.ports.push(added);
|
||||
this.dispatchEvent(new CustomEvent("addedDevice", { detail: added }));
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
handleRemovedDevice(device) {
|
||||
const removed = this.ports.find(port => port.port === device);
|
||||
this.ports = this.ports.filter(port => port.port !== device);
|
||||
this.dispatchEvent(new CustomEvent("removedDevice", { detail: removed }));
|
||||
}
|
||||
|
||||
handleReceiveBytes(info) {
|
||||
|
@ -44,16 +66,56 @@ class WebSerial extends EventTarget {
|
|||
|
||||
handleDisconnect() {
|
||||
this.removeEventListener('receive', this.handleReceiveBytes);
|
||||
this.removeEventListener('disconnect', this.handleDisconnect);
|
||||
this.dispatchEvent(new CustomEvent("disconnect", { detail: false }));
|
||||
}
|
||||
|
||||
async connect(options) {
|
||||
this.openRequested = true;
|
||||
this.port = await navigator.serial.requestPort({
|
||||
getConnectedPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
createPort(port) {
|
||||
return {
|
||||
path: `D${this.port_counter}`,
|
||||
displayName: `Betaflight ${vendorIdNames[port.getInfo().usbVendorId]}`,
|
||||
vendorId: port.getInfo().usbVendorId,
|
||||
productId: port.getInfo().usbProductId,
|
||||
port: port,
|
||||
};
|
||||
}
|
||||
|
||||
async loadDevices() {
|
||||
const ports = await navigator.serial.getPorts({
|
||||
filters: webSerialDevices,
|
||||
});
|
||||
|
||||
this.port_counter = 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 === device);
|
||||
if (!found) {
|
||||
return this.handleNewDevice(permissionPort);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
async getDevices() {
|
||||
return this.ports;
|
||||
}
|
||||
|
||||
async connect(path, options) {
|
||||
this.openRequested = true;
|
||||
|
||||
this.port = this.ports.find(device => device.path === path).port;
|
||||
|
||||
await this.port.open(options);
|
||||
|
||||
const connectionInfo = this.port.getInfo();
|
||||
this.connectionInfo = connectionInfo;
|
||||
this.writer = this.port.writable.getWriter();
|
||||
|
@ -69,7 +131,6 @@ class WebSerial extends EventTarget {
|
|||
this.openRequested = false;
|
||||
|
||||
this.addEventListener("receive", this.handleReceiveBytes);
|
||||
this.addEventListener('disconnect', this.handleDisconnect);
|
||||
|
||||
console.log(
|
||||
`${this.logHead} Connection opened with ID: ${connectionInfo.connectionId}, Baud: ${options.baudRate}`,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue