1
0
Fork 0
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:
Mark Haslinghuis 2024-10-03 20:03:06 +02:00 committed by GitHub
parent 6908b7efb8
commit 36ccc26acc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 182 additions and 17 deletions

View file

@ -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>

View file

@ -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,

View 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();

View file

@ -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();

View file

@ -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;
};