mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-25 17:25:16 +03:00
Add websocket support and fix port override (#4187)
* Add websocket support * remove waitforconnection
This commit is contained in:
parent
6908b7efb8
commit
36ccc26acc
5 changed files with 182 additions and 17 deletions
|
@ -1,8 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
v-if="isManual"
|
||||||
id="port-override-option"
|
id="port-override-option"
|
||||||
style="display: none"
|
|
||||||
:style="{ display: isManual ? 'flex' : 'none' }"
|
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
for="port-override"
|
for="port-override"
|
||||||
|
@ -10,30 +9,40 @@
|
||||||
<input
|
<input
|
||||||
id="port-override"
|
id="port-override"
|
||||||
type="text"
|
type="text"
|
||||||
value="/dev/rfcomm0"
|
:value="value"
|
||||||
|
@change="inputValueChanged($event)"
|
||||||
></label>
|
></label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { set as setConfig } from '../../js/ConfigStorage';
|
import { set as setConfig } from "../../js/ConfigStorage";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
isManual: {
|
value: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: true,
|
default: '/dev/rfcomm0',
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
isManual: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
inputValueChanged(event) {
|
||||||
|
setConfig({'portOverride': event.target.value});
|
||||||
|
this.$emit('input', event.target.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#port-override-option {
|
#port-override-option {
|
||||||
label {
|
label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,6 +11,8 @@ const CONFIGURATOR = {
|
||||||
|
|
||||||
connectionValid: false,
|
connectionValid: false,
|
||||||
connectionValidCliOnly: false,
|
connectionValidCliOnly: false,
|
||||||
|
bluetoothMode: false,
|
||||||
|
manualMode: false,
|
||||||
virtualMode: false,
|
virtualMode: false,
|
||||||
virtualApiVersion: '0.0.1',
|
virtualApiVersion: '0.0.1',
|
||||||
cliActive: false,
|
cliActive: false,
|
||||||
|
|
132
src/js/protocols/websocket.js
Normal file
132
src/js/protocols/websocket.js
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
class WebsocketSerial extends EventTarget {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.connected = false;
|
||||||
|
this.connectionInfo = null;
|
||||||
|
|
||||||
|
this.bitrate = 0;
|
||||||
|
this.bytesSent = 0;
|
||||||
|
this.bytesReceived = 0;
|
||||||
|
this.failed = 0;
|
||||||
|
|
||||||
|
this.logHead = "[WEBSOCKET] ";
|
||||||
|
|
||||||
|
this.address = "ws://localhost:5761";
|
||||||
|
|
||||||
|
this.ws = null;
|
||||||
|
|
||||||
|
this.connect = this.connect.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReceiveBytes(info) {
|
||||||
|
this.bytesReceived += info.detail.byteLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDisconnect() {
|
||||||
|
this.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
createPort(url) {
|
||||||
|
this.address = url;
|
||||||
|
return {
|
||||||
|
path: url,
|
||||||
|
displayName: `Betaflight SITL`,
|
||||||
|
vendorId: 0,
|
||||||
|
productId: 0,
|
||||||
|
port: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getConnectedPort() {
|
||||||
|
return {
|
||||||
|
path: this.address,
|
||||||
|
displayName: `Betaflight SITL`,
|
||||||
|
vendorId: 0,
|
||||||
|
productId: 0,
|
||||||
|
port: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDevices() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async blob2uint(blob) {
|
||||||
|
const buffer = await new Response(blob).arrayBuffer();
|
||||||
|
return new Uint8Array(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(path, options) {
|
||||||
|
this.address = path;
|
||||||
|
console.log(`${this.logHead} Connecting to ${this.address}`);
|
||||||
|
|
||||||
|
this.ws = new WebSocket(this.address, "wsSerial");
|
||||||
|
let socket = this;
|
||||||
|
|
||||||
|
this.ws.onopen = function(e) {
|
||||||
|
console.log(`${socket.logHead} Connected: `, e);
|
||||||
|
socket.connected = true;
|
||||||
|
socket.dispatchEvent(
|
||||||
|
new CustomEvent("connect", { detail: {
|
||||||
|
socketId: socket.address,
|
||||||
|
}}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onclose = function(e) {
|
||||||
|
console.log(`${socket.logHead} Connection closed: `, e);
|
||||||
|
|
||||||
|
socket.disconnect(() => {
|
||||||
|
socket.dispatchEvent(new CustomEvent("disconnect", this.disconnect.bind(this)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onerror = function(e) {
|
||||||
|
console.error(`${socket.logHead} Connection error: `, e);
|
||||||
|
|
||||||
|
socket.disconnect(() => {
|
||||||
|
socket.dispatchEvent(new CustomEvent("disconnect", this.disconnect.bind(this)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onmessage = async function(msg) {
|
||||||
|
let uint8Chunk = await socket.blob2uint(msg.data);
|
||||||
|
socket.dispatchEvent(
|
||||||
|
new CustomEvent("receive", { detail: uint8Chunk }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect() {
|
||||||
|
this.connected = false;
|
||||||
|
this.bytesReceived = 0;
|
||||||
|
this.bytesSent = 0;
|
||||||
|
|
||||||
|
if (this.ws) {
|
||||||
|
try {
|
||||||
|
this.ws.close();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`${this.logHead}Failed to close socket: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(data, cb) {
|
||||||
|
if (this.ws) {
|
||||||
|
try {
|
||||||
|
this.ws.send(data);
|
||||||
|
this.bytesSent += data.byteLength;
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
console.error(`${this.logHead}Failed to send data e: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
bytesSent: data.byteLength,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new WebsocketSerial();
|
|
@ -107,7 +107,6 @@ function connectDisconnect() {
|
||||||
GUI.configuration_loaded = false;
|
GUI.configuration_loaded = false;
|
||||||
|
|
||||||
const baudRate = PortHandler.portPicker.selectedBauds;
|
const baudRate = PortHandler.portPicker.selectedBauds;
|
||||||
const selectedPort = portName;
|
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
// prevent connection when we do not have permission
|
// prevent connection when we do not have permission
|
||||||
|
@ -124,6 +123,7 @@ function connectDisconnect() {
|
||||||
|
|
||||||
CONFIGURATOR.virtualMode = selectedPort === 'virtual';
|
CONFIGURATOR.virtualMode = selectedPort === 'virtual';
|
||||||
CONFIGURATOR.bluetoothMode = selectedPort.startsWith('bluetooth');
|
CONFIGURATOR.bluetoothMode = selectedPort.startsWith('bluetooth');
|
||||||
|
CONFIGURATOR.manualMode = selectedPort === 'manual';
|
||||||
|
|
||||||
if (CONFIGURATOR.virtualMode) {
|
if (CONFIGURATOR.virtualMode) {
|
||||||
CONFIGURATOR.virtualApiVersion = PortHandler.portPicker.virtualMspVersion;
|
CONFIGURATOR.virtualApiVersion = PortHandler.portPicker.virtualMspVersion;
|
||||||
|
@ -131,6 +131,16 @@ function connectDisconnect() {
|
||||||
// Hack to get virtual working on the web
|
// Hack to get virtual working on the web
|
||||||
serial = serialShim();
|
serial = serialShim();
|
||||||
serial.connect(onOpenVirtual);
|
serial.connect(onOpenVirtual);
|
||||||
|
} else if (selectedPort === 'manual') {
|
||||||
|
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 {
|
} else {
|
||||||
CONFIGURATOR.virtualMode = false;
|
CONFIGURATOR.virtualMode = false;
|
||||||
serial = serialShim();
|
serial = serialShim();
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
import CONFIGURATOR from "./data_storage";
|
import CONFIGURATOR from "./data_storage";
|
||||||
import serialWeb from "./webSerial.js";
|
import serialWeb from "./webSerial.js";
|
||||||
import BT from "./protocols/bluetooth.js";
|
import BT from "./protocols/bluetooth.js";
|
||||||
|
import websocketSerial from "./protocols/websocket.js";
|
||||||
import virtualSerial from "./virtualSerial.js";
|
import virtualSerial from "./virtualSerial.js";
|
||||||
|
|
||||||
export let serialShim = () => CONFIGURATOR.virtualMode ? virtualSerial: CONFIGURATOR.bluetoothMode ? BT : serialWeb;
|
export const serialShim = () => {
|
||||||
|
if (CONFIGURATOR.virtualMode) {
|
||||||
|
return virtualSerial;
|
||||||
|
}
|
||||||
|
if (CONFIGURATOR.manualMode) {
|
||||||
|
return websocketSerial;
|
||||||
|
}
|
||||||
|
if (CONFIGURATOR.bluetoothMode) {
|
||||||
|
return BT;
|
||||||
|
}
|
||||||
|
return serialWeb;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue