mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-25 17:25:16 +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:
parent
8499939bdf
commit
18eb8dd1b2
11 changed files with 116 additions and 165 deletions
2
src/components/eventBus.js
Normal file
2
src/components/eventBus.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
import Vue from "vue";
|
||||
export const EventBus = new Vue();
|
|
@ -14,6 +14,7 @@ import BatteryIcon from "./quad-status/BatteryIcon.vue";
|
|||
import FC from '../js/fc.js';
|
||||
import MSP from '../js/msp.js';
|
||||
import PortUsage from '../js/port_usage.js';
|
||||
import PortPicker from './port-picker/PortPicker.vue';
|
||||
import CONFIGURATOR from '../js/data_storage.js';
|
||||
|
||||
// Most of the global objects can go here at first.
|
||||
|
@ -44,6 +45,7 @@ i18next.on('initialized', function() {
|
|||
BetaflightLogo,
|
||||
StatusBar,
|
||||
BatteryIcon,
|
||||
PortPicker,
|
||||
},
|
||||
data: betaflightModel,
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
>
|
||||
<div class="dropdown dropdown-dark">
|
||||
<select
|
||||
id="firmware-version-dropdown"
|
||||
class="dropdown-select"
|
||||
:title="$t('virtualMSPVersion')"
|
||||
>
|
||||
|
@ -43,12 +44,12 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
#firmware-virtual-option {
|
||||
height: 76px;
|
||||
width: 180px;
|
||||
margin-right: 15px;
|
||||
margin-top: 16px;
|
||||
margin-top: 0px;
|
||||
display: none;
|
||||
}
|
||||
.dropdown {
|
||||
|
@ -148,19 +149,6 @@ export default {
|
|||
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 {
|
||||
background: #636363; /* NEW2 */
|
||||
background: #3e403f; /* NEW */
|
||||
|
|
30
src/components/port-picker/PortPicker.vue
Normal file
30
src/components/port-picker/PortPicker.vue
Normal 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>
|
|
@ -8,48 +8,21 @@
|
|||
id="port"
|
||||
class="dropdown-select"
|
||||
:title="$t('firmwareFlasherManualPort')"
|
||||
@value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<option value="virtual">
|
||||
{{ $t("portsSelectVirtual") }}
|
||||
</option>
|
||||
<option value="manual">
|
||||
{{ $t("portsSelectManual") }}
|
||||
</option>
|
||||
<option
|
||||
v-if="showVirtual"
|
||||
value="virtual"
|
||||
>
|
||||
{{ $t("portsSelectVirtual") }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<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 class="dropdown dropdown-dark">
|
||||
<select
|
||||
|
@ -57,7 +30,6 @@
|
|||
v-model="selectedBaudRate"
|
||||
class="dropdown-select"
|
||||
:title="$t('firmwareFlasherBaudRate')"
|
||||
:disabled="isAutoConnect"
|
||||
>
|
||||
<option
|
||||
v-for="baudRate in baudRates"
|
||||
|
@ -74,10 +46,20 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { get as getConfig } from '../../js/ConfigStorage';
|
||||
import { EventBus } from '../eventBus';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: 'manual',
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isAutoConnect: false,
|
||||
showVirtual: false,
|
||||
selectedBaudRate: "115200",
|
||||
baudRates: [
|
||||
{ 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>
|
||||
<style scoped>
|
||||
|
@ -173,55 +166,6 @@ export default {
|
|||
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 {
|
||||
width: 80px;
|
||||
float: right;
|
||||
|
|
|
@ -26,54 +26,7 @@
|
|||
:firmware-id="FC.CONFIG.flightControllerIdentifier"
|
||||
:hardware-id="FC.CONFIG.hardwareName"
|
||||
></betaflight-logo>
|
||||
<div id="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>
|
||||
<port-picker></port-picker>
|
||||
<div class="header-wrapper">
|
||||
<div id="quad-status_wrapper">
|
||||
<battery-icon
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { EventBus } from "../components/eventBus";
|
||||
|
||||
/**
|
||||
* Gets one or more items from localStorage
|
||||
* @param {string | string[]} key string or array of strings
|
||||
|
@ -43,6 +45,7 @@ export function set(input) {
|
|||
tmpObj[element] = input[element];
|
||||
try {
|
||||
localStorage.setItem(element, JSON.stringify(tmpObj));
|
||||
EventBus.$emit(`config-storage:set`, 'element');
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,9 @@ import CONFIGURATOR from "./data_storage.js";
|
|||
import serialNWJS from "./serial.js";
|
||||
import serialWeb from "./webSerial.js";
|
||||
import { isWeb } from "./utils/isWeb.js";
|
||||
import { serialShim } from "./serial_shim.js";
|
||||
|
||||
const serial = isWeb() ? serialWeb : serialNWJS;
|
||||
const serial = serialShim();
|
||||
|
||||
const MSP = {
|
||||
symbols: {
|
||||
|
|
|
@ -135,12 +135,18 @@ PortHandler.check_usb_devices = function (callback) {
|
|||
self.portPickerElement.append($('<option/>', {
|
||||
value: "DFU",
|
||||
text: usbText,
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isDFU: true},
|
||||
}));
|
||||
|
||||
self.portPickerElement.append($('<option/>', {
|
||||
value: 'manual',
|
||||
text: i18n.getMessage('portsSelectManual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isManual: true},
|
||||
}));
|
||||
|
||||
|
@ -153,7 +159,7 @@ PortHandler.check_usb_devices = function (callback) {
|
|||
self.setPortsInputWidth();
|
||||
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)) {
|
||||
FC.resetState();
|
||||
}
|
||||
|
@ -282,6 +288,9 @@ PortHandler.updatePortSelect = function (ports) {
|
|||
this.portPickerElement.append($("<option/>", {
|
||||
value: ports[i].path,
|
||||
text: portText,
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isManual: false},
|
||||
}));
|
||||
}
|
||||
|
@ -290,6 +299,9 @@ PortHandler.updatePortSelect = function (ports) {
|
|||
this.portPickerElement.append($("<option/>", {
|
||||
value: 'virtual',
|
||||
text: i18n.getMessage('portsSelectVirtual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isVirtual: true},
|
||||
}));
|
||||
}
|
||||
|
@ -297,6 +309,9 @@ PortHandler.updatePortSelect = function (ports) {
|
|||
this.portPickerElement.append($("<option/>", {
|
||||
value: 'manual',
|
||||
text: i18n.getMessage('portsSelectManual'),
|
||||
/**
|
||||
* @deprecated please avoid using `isDFU` and friends for new code.
|
||||
*/
|
||||
data: {isManual: true},
|
||||
}));
|
||||
|
||||
|
|
|
@ -24,11 +24,10 @@ import CryptoES from "crypto-es";
|
|||
import $ from 'jquery';
|
||||
import BuildApi from "./BuildApi";
|
||||
|
||||
import serialNWJS from "./serial.js";
|
||||
import serialWeb from "./webSerial.js";
|
||||
import { isWeb } from "./utils/isWeb";
|
||||
import { serialShim } from "./serial_shim.js";
|
||||
|
||||
const serial = isWeb() ? serialWeb : serialNWJS;
|
||||
let serial = serialShim();
|
||||
|
||||
let mspHelper;
|
||||
let connectionTimestamp;
|
||||
|
@ -51,21 +50,25 @@ function disconnectHandler(event) {
|
|||
|
||||
export function initializeSerialBackend() {
|
||||
GUI.updateManualPortVisibility = function() {
|
||||
const selected_port = $('div#port-picker #port option:selected');
|
||||
if (selected_port.data().isManual) {
|
||||
if(isWeb()) {
|
||||
return;
|
||||
}
|
||||
const selected_port = $('#port').val();
|
||||
|
||||
if (selected_port === 'manual') {
|
||||
$('#port-override-option').show();
|
||||
}
|
||||
else {
|
||||
$('#port-override-option').hide();
|
||||
}
|
||||
if (selected_port.data().isVirtual) {
|
||||
if (selected_port === 'virtual') {
|
||||
$('#firmware-virtual-option').show();
|
||||
}
|
||||
else {
|
||||
$('#firmware-virtual-option').hide();
|
||||
}
|
||||
|
||||
$('#auto-connect-and-baud').toggle(!selected_port.data().isDFU);
|
||||
$('#auto-connect-and-baud').toggle(selected_port !== 'DFU');
|
||||
};
|
||||
|
||||
GUI.updateManualPortVisibility();
|
||||
|
@ -86,9 +89,9 @@ export function initializeSerialBackend() {
|
|||
|
||||
$("div.connect_controls a.connect").on('click', function () {
|
||||
|
||||
const selectedPort = $('div#port-picker #port option:selected');
|
||||
const selectedPort = $('#port').val();
|
||||
let portName;
|
||||
if (selectedPort.data().isManual) {
|
||||
if (selectedPort === 'manual') {
|
||||
portName = $('#port-override').val();
|
||||
} else {
|
||||
portName = String($('div#port-picker #port').val());
|
||||
|
@ -100,9 +103,9 @@ export function initializeSerialBackend() {
|
|||
GUI.configuration_loaded = false;
|
||||
|
||||
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();
|
||||
} else if (portName !== '0') {
|
||||
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.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
|
||||
|
||||
const baudRate = parseInt($('div#port-picker #baud').val());
|
||||
if (selectedPort.data().isVirtual) {
|
||||
const baudRate = parseInt($('#baud').val());
|
||||
if (selectedPort === 'virtual') {
|
||||
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);
|
||||
} else if (isWeb()) {
|
||||
CONFIGURATOR.virtualMode = false;
|
||||
serial = serialShim();
|
||||
// Explicitly disconnect the event listeners before attaching the new ones.
|
||||
serial.removeEventListener('connect', connectHandler);
|
||||
serial.addEventListener('connect', connectHandler);
|
||||
|
|
6
src/js/serial_shim.js
Normal file
6
src/js/serial_shim.js
Normal 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;
|
Loading…
Add table
Add a link
Reference in a new issue