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

Feat/web virtual mode (#3882)

* feat: add virtual mode on web

* feat: only show msp virtual version on virtual mode selection

* feat: update port selection to update the options
This commit is contained in:
Tomas Chmelevskij 2024-04-28 19:51:41 +02:00 committed by GitHub
parent 8499939bdf
commit 18eb8dd1b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 116 additions and 165 deletions

View file

@ -0,0 +1,2 @@
import Vue from "vue";
export const EventBus = new Vue();

View file

@ -14,6 +14,7 @@ import BatteryIcon from "./quad-status/BatteryIcon.vue";
import FC from '../js/fc.js'; import FC from '../js/fc.js';
import MSP from '../js/msp.js'; import MSP from '../js/msp.js';
import PortUsage from '../js/port_usage.js'; import PortUsage from '../js/port_usage.js';
import PortPicker from './port-picker/PortPicker.vue';
import CONFIGURATOR from '../js/data_storage.js'; import CONFIGURATOR from '../js/data_storage.js';
// Most of the global objects can go here at first. // Most of the global objects can go here at first.
@ -44,6 +45,7 @@ i18next.on('initialized', function() {
BetaflightLogo, BetaflightLogo,
StatusBar, StatusBar,
BatteryIcon, BatteryIcon,
PortPicker,
}, },
data: betaflightModel, data: betaflightModel,
}); });

View file

@ -5,6 +5,7 @@
> >
<div class="dropdown dropdown-dark"> <div class="dropdown dropdown-dark">
<select <select
id="firmware-version-dropdown"
class="dropdown-select" class="dropdown-select"
:title="$t('virtualMSPVersion')" :title="$t('virtualMSPVersion')"
> >
@ -43,12 +44,12 @@ export default {
}; };
</script> </script>
<style> <style scoped>
#firmware-virtual-option { #firmware-virtual-option {
height: 76px; height: 76px;
width: 180px; width: 180px;
margin-right: 15px; margin-right: 15px;
margin-top: 16px; margin-top: 0px;
display: none; display: none;
} }
.dropdown { .dropdown {
@ -148,19 +149,6 @@ export default {
cursor: pointer; cursor: pointer;
} }
/* Fix for IE 8 putting the arrows behind the select element. */
.lt-ie9 .dropdown {
z-index: 1;
}
.lt-ie9 .dropdown-select {
z-index: -1;
}
.lt-ie9 .dropdown-select:focus {
z-index: 3;
}
.dropdown-dark { .dropdown-dark {
background: #636363; /* NEW2 */ background: #636363; /* NEW2 */
background: #3e403f; /* NEW */ background: #3e403f; /* NEW */

View file

@ -0,0 +1,30 @@
<template>
<div class="web-port-picker">
<FirmwareVirtualOption :is-virtual="port === 'virtual'" />
<PortsInput v-model="port" />
</div>
</template>
<script>
import FirmwareVirtualOption from "./FirmwareVirtualOption.vue";
import PortsInput from "./PortsInput.vue";
export default {
components: {
FirmwareVirtualOption,
PortsInput,
},
data() {
return {
port: 'manual',
};
},
};
</script>
<style scoped>
.web-port-picker {
display: flex;
margin-left: auto;
}
</style>

View file

@ -8,48 +8,21 @@
id="port" id="port"
class="dropdown-select" class="dropdown-select"
:title="$t('firmwareFlasherManualPort')" :title="$t('firmwareFlasherManualPort')"
@value="value"
@input="$emit('input', $event.target.value)"
> >
<option value="virtual">
{{ $t("portsSelectVirtual") }}
</option>
<option value="manual"> <option value="manual">
{{ $t("portsSelectManual") }} {{ $t("portsSelectManual") }}
</option> </option>
<option
v-if="showVirtual"
value="virtual"
>
{{ $t("portsSelectVirtual") }}
</option>
</select> </select>
</div> </div>
<div id="auto-connect-and-baud"> <div id="auto-connect-and-baud">
<div id="auto-connect-switch">
<label style="display: flex; align-items: baseline">
<input
type="checkbox"
class="auto_connect"
title="Auto-Connect: Enabled - Configurator automatically tries to connect when new port is detected"
style="display: none"
data-switchery="true"
>
<span
class="switchery switchery-small"
:style="{
backgroundColor: isAutoConnect
? '#ffbb00'
: '#858585',
}"
>
<small
:style="{
left: isAutoConnect ? '10px' : '0px',
transition: 'ease-in-out 0.2s',
}"
@click="isAutoConnect = !isAutoConnect"
/></span>
<span
i18n="autoConnect"
class="auto_connect"
title="Auto-Connect: Enabled - Configurator automatically tries to connect when new port is detected"
>{{ $t("autoConnect") }}
</span>
</label>
</div>
<div id="baudselect"> <div id="baudselect">
<div class="dropdown dropdown-dark"> <div class="dropdown dropdown-dark">
<select <select
@ -57,7 +30,6 @@
v-model="selectedBaudRate" v-model="selectedBaudRate"
class="dropdown-select" class="dropdown-select"
:title="$t('firmwareFlasherBaudRate')" :title="$t('firmwareFlasherBaudRate')"
:disabled="isAutoConnect"
> >
<option <option
v-for="baudRate in baudRates" v-for="baudRate in baudRates"
@ -74,10 +46,20 @@
</template> </template>
<script> <script>
import { get as getConfig } from '../../js/ConfigStorage';
import { EventBus } from '../eventBus';
export default { export default {
props: {
value: {
type: String,
default: 'manual',
},
},
data() { data() {
return { return {
isAutoConnect: false, showVirtual: false,
selectedBaudRate: "115200", selectedBaudRate: "115200",
baudRates: [ baudRates: [
{ value: "1000000", label: "1000000" }, { value: "1000000", label: "1000000" },
@ -96,6 +78,17 @@ export default {
], ],
}; };
}, },
mounted() {
EventBus.$on('config-storage:set', this.setShowVirtual);
},
destroyed() {
EventBus.$off('config-storage:set', this.setShowVirtual);
},
methods: {
setShowVirtual() {
this.showVirtual = getConfig('showVirtualMode').showVirtualMode;
},
},
}; };
</script> </script>
<style scoped> <style scoped>
@ -173,55 +166,6 @@ export default {
float: right; float: right;
} }
#auto-connect-switch {
width: 110px;
float: left;
margin-top: 4px;
margin-right: 20px;
}
.auto_connect {
color: var(--subtleAccent);
font-family: "Open Sans", "Segoe UI", Tahoma, sans-serif;
font-size: 12px;
}
.switchery {
height: 14px;
width: 45px;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
box-sizing: content-box;
background-clip: content-box;
cursor: pointer;
display: inline-block;
position: relative;
vertical-align: middle;
}
.switchery-small {
border-radius: 20px;
height: 10px;
width: 20px;
margin-right: 5px;
background-color: var(--switcherysecond);
transition: border 0.3s ease 0s, box-shadow 0.3s ease 0s,
background-color 0.5s ease 0s;
}
.switchery small {
background: #fff;
border-radius: 100%;
box-shadow: 0 1px 3px rgb(0 0 0 / 40%);
height: 10px;
width: 10px;
position: absolute;
top: 0;
}
#baudselect { #baudselect {
width: 80px; width: 80px;
float: right; float: right;

View file

@ -26,54 +26,7 @@
:firmware-id="FC.CONFIG.flightControllerIdentifier" :firmware-id="FC.CONFIG.flightControllerIdentifier"
:hardware-id="FC.CONFIG.hardwareName" :hardware-id="FC.CONFIG.hardwareName"
></betaflight-logo> ></betaflight-logo>
<div id="port-picker"> <port-picker></port-picker>
<div id="port-override-option">
<label for="port-override">
<span i18n="portOverrideText">Port:</span>
<input id="port-override" type="text" value="/dev/rfcomm0"/>
</label>
</div>
<div id="firmware-virtual-option">
<div class="dropdown dropdown-dark">
<select id="firmware-version-dropdown" class="dropdown-select" i18n_title="virtualMSPVersion"></select>
</div>
</div>
<div id="portsinput" style="display: none">
<div class="dropdown dropdown-dark">
<select class="dropdown-select" id="port" i18n_title="firmwareFlasherManualPort">
<option value="loading" i18n="serialPortLoading">Loading</option>
<!-- port list gets generated here -->
</select>
</div>
<div id="auto-connect-and-baud">
<div id="auto-connect-switch">
<label>
<input class="auto_connect togglesmall" type="checkbox"/>
<span class="auto_connect" i18n="autoConnect"></span>
</label>
</div>
<div id="baudselect">
<div class="dropdown dropdown-dark">
<select class="dropdown-select" id="baud" i18n_title="firmwareFlasherBaudRate">
<option value="1000000">1000000</option>
<option value="500000">500000</option>
<option value="250000">250000</option>
<option value="115200" selected="selected">115200</option>
<option value="57600">57600</option>
<option value="38400">38400</option>
<option value="28800">28800</option>
<option value="19200">19200</option>
<option value="14400">14400</option>
<option value="9600">9600</option>
<option value="4800">4800</option>
<option value="2400">2400</option>
<option value="1200">1200</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="header-wrapper"> <div class="header-wrapper">
<div id="quad-status_wrapper"> <div id="quad-status_wrapper">
<battery-icon <battery-icon

View file

@ -1,3 +1,5 @@
import { EventBus } from "../components/eventBus";
/** /**
* Gets one or more items from localStorage * Gets one or more items from localStorage
* @param {string | string[]} key string or array of strings * @param {string | string[]} key string or array of strings
@ -43,6 +45,7 @@ export function set(input) {
tmpObj[element] = input[element]; tmpObj[element] = input[element];
try { try {
localStorage.setItem(element, JSON.stringify(tmpObj)); localStorage.setItem(element, JSON.stringify(tmpObj));
EventBus.$emit(`config-storage:set`, 'element');
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View file

@ -3,8 +3,9 @@ import CONFIGURATOR from "./data_storage.js";
import serialNWJS from "./serial.js"; import serialNWJS from "./serial.js";
import serialWeb from "./webSerial.js"; import serialWeb from "./webSerial.js";
import { isWeb } from "./utils/isWeb.js"; import { isWeb } from "./utils/isWeb.js";
import { serialShim } from "./serial_shim.js";
const serial = isWeb() ? serialWeb : serialNWJS; const serial = serialShim();
const MSP = { const MSP = {
symbols: { symbols: {

View file

@ -135,12 +135,18 @@ PortHandler.check_usb_devices = function (callback) {
self.portPickerElement.append($('<option/>', { self.portPickerElement.append($('<option/>', {
value: "DFU", value: "DFU",
text: usbText, text: usbText,
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isDFU: true}, data: {isDFU: true},
})); }));
self.portPickerElement.append($('<option/>', { self.portPickerElement.append($('<option/>', {
value: 'manual', value: 'manual',
text: i18n.getMessage('portsSelectManual'), text: i18n.getMessage('portsSelectManual'),
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isManual: true}, data: {isManual: true},
})); }));
@ -153,7 +159,7 @@ PortHandler.check_usb_devices = function (callback) {
self.setPortsInputWidth(); self.setPortsInputWidth();
self.dfu_available = false; self.dfu_available = false;
} }
if (!$('option:selected', self.portPickerElement).data().isDFU) { if ($('option:selected', self.portPickerElement).val() !== 'DFU') {
if (!(GUI.connected_to || GUI.connect_lock)) { if (!(GUI.connected_to || GUI.connect_lock)) {
FC.resetState(); FC.resetState();
} }
@ -282,6 +288,9 @@ PortHandler.updatePortSelect = function (ports) {
this.portPickerElement.append($("<option/>", { this.portPickerElement.append($("<option/>", {
value: ports[i].path, value: ports[i].path,
text: portText, text: portText,
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isManual: false}, data: {isManual: false},
})); }));
} }
@ -290,6 +299,9 @@ PortHandler.updatePortSelect = function (ports) {
this.portPickerElement.append($("<option/>", { this.portPickerElement.append($("<option/>", {
value: 'virtual', value: 'virtual',
text: i18n.getMessage('portsSelectVirtual'), text: i18n.getMessage('portsSelectVirtual'),
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isVirtual: true}, data: {isVirtual: true},
})); }));
} }
@ -297,6 +309,9 @@ PortHandler.updatePortSelect = function (ports) {
this.portPickerElement.append($("<option/>", { this.portPickerElement.append($("<option/>", {
value: 'manual', value: 'manual',
text: i18n.getMessage('portsSelectManual'), text: i18n.getMessage('portsSelectManual'),
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isManual: true}, data: {isManual: true},
})); }));

View file

@ -24,11 +24,10 @@ import CryptoES from "crypto-es";
import $ from 'jquery'; import $ from 'jquery';
import BuildApi from "./BuildApi"; import BuildApi from "./BuildApi";
import serialNWJS from "./serial.js";
import serialWeb from "./webSerial.js";
import { isWeb } from "./utils/isWeb"; import { isWeb } from "./utils/isWeb";
import { serialShim } from "./serial_shim.js";
const serial = isWeb() ? serialWeb : serialNWJS; let serial = serialShim();
let mspHelper; let mspHelper;
let connectionTimestamp; let connectionTimestamp;
@ -51,21 +50,25 @@ function disconnectHandler(event) {
export function initializeSerialBackend() { export function initializeSerialBackend() {
GUI.updateManualPortVisibility = function() { GUI.updateManualPortVisibility = function() {
const selected_port = $('div#port-picker #port option:selected'); if(isWeb()) {
if (selected_port.data().isManual) { return;
}
const selected_port = $('#port').val();
if (selected_port === 'manual') {
$('#port-override-option').show(); $('#port-override-option').show();
} }
else { else {
$('#port-override-option').hide(); $('#port-override-option').hide();
} }
if (selected_port.data().isVirtual) { if (selected_port === 'virtual') {
$('#firmware-virtual-option').show(); $('#firmware-virtual-option').show();
} }
else { else {
$('#firmware-virtual-option').hide(); $('#firmware-virtual-option').hide();
} }
$('#auto-connect-and-baud').toggle(!selected_port.data().isDFU); $('#auto-connect-and-baud').toggle(selected_port !== 'DFU');
}; };
GUI.updateManualPortVisibility(); GUI.updateManualPortVisibility();
@ -86,9 +89,9 @@ export function initializeSerialBackend() {
$("div.connect_controls a.connect").on('click', function () { $("div.connect_controls a.connect").on('click', function () {
const selectedPort = $('div#port-picker #port option:selected'); const selectedPort = $('#port').val();
let portName; let portName;
if (selectedPort.data().isManual) { if (selectedPort === 'manual') {
portName = $('#port-override').val(); portName = $('#port-override').val();
} else { } else {
portName = String($('div#port-picker #port').val()); portName = String($('div#port-picker #port').val());
@ -100,9 +103,9 @@ export function initializeSerialBackend() {
GUI.configuration_loaded = false; GUI.configuration_loaded = false;
const selected_baud = parseInt($('div#port-picker #baud').val()); const selected_baud = parseInt($('div#port-picker #baud').val());
const selectedPort = $('div#port-picker #port option:selected'); const selectedPort = $('#port').val();
if (selectedPort.data().isDFU) { if (selectedPort === 'DFU') {
$('select#baud').hide(); $('select#baud').hide();
} else if (portName !== '0') { } else if (portName !== '0') {
if (!isConnected) { if (!isConnected) {
@ -113,13 +116,17 @@ export function initializeSerialBackend() {
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true); $('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting')); $('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
const baudRate = parseInt($('div#port-picker #baud').val()); const baudRate = parseInt($('#baud').val());
if (selectedPort.data().isVirtual) { if (selectedPort === 'virtual') {
CONFIGURATOR.virtualMode = true; CONFIGURATOR.virtualMode = true;
CONFIGURATOR.virtualApiVersion = $('#firmware-version-dropdown :selected').val(); CONFIGURATOR.virtualApiVersion = $('#firmware-version-dropdown').val();
// Hack to get virtual working on the web
serial = serialShim();
serial.connect('virtual', {}, onOpenVirtual); serial.connect('virtual', {}, onOpenVirtual);
} else if (isWeb()) { } else if (isWeb()) {
CONFIGURATOR.virtualMode = false;
serial = serialShim();
// Explicitly disconnect the event listeners before attaching the new ones. // Explicitly disconnect the event listeners before attaching the new ones.
serial.removeEventListener('connect', connectHandler); serial.removeEventListener('connect', connectHandler);
serial.addEventListener('connect', connectHandler); serial.addEventListener('connect', connectHandler);

6
src/js/serial_shim.js Normal file
View file

@ -0,0 +1,6 @@
import CONFIGURATOR from "./data_storage";
import serialNWJS from "./serial.js";
import serialWeb from "./webSerial.js";
import { isWeb } from "./utils/isWeb";
export let serialShim = () => CONFIGURATOR.virtualMode ? serialNWJS : isWeb() ? serialWeb : serialNWJS;