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>
<div
v-if="isManual"
id="port-override-option"
style="display: none"
:style="{ display: isManual ? 'flex' : 'none' }"
>
<label
for="port-override"
@ -10,21 +9,31 @@
<input
id="port-override"
type="text"
value="/dev/rfcomm0"
:value="value"
@change="inputValueChanged($event)"
></label>
</div>
</template>
<script>
import { set as setConfig } from '../../js/ConfigStorage';
import { set as setConfig } from "../../js/ConfigStorage";
export default {
props: {
value: {
type: String,
default: '/dev/rfcomm0',
},
isManual: {
type: Boolean,
default: true,
},
},
methods: {
inputValueChanged(event) {
setConfig({'portOverride': event.target.value});
this.$emit('input', event.target.value);
},
},
};
</script>

View file

@ -11,6 +11,8 @@ const CONFIGURATOR = {
connectionValid: false,
connectionValidCliOnly: false,
bluetoothMode: false,
manualMode: false,
virtualMode: false,
virtualApiVersion: '0.0.1',
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;
const baudRate = PortHandler.portPicker.selectedBauds;
const selectedPort = portName;
if (!isConnected) {
// prevent connection when we do not have permission
@ -124,6 +123,7 @@ function connectDisconnect() {
CONFIGURATOR.virtualMode = selectedPort === 'virtual';
CONFIGURATOR.bluetoothMode = selectedPort.startsWith('bluetooth');
CONFIGURATOR.manualMode = selectedPort === 'manual';
if (CONFIGURATOR.virtualMode) {
CONFIGURATOR.virtualApiVersion = PortHandler.portPicker.virtualMspVersion;
@ -131,6 +131,16 @@ function connectDisconnect() {
// Hack to get virtual working on the web
serial = serialShim();
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 {
CONFIGURATOR.virtualMode = false;
serial = serialShim();

View file

@ -1,6 +1,18 @@
import CONFIGURATOR from "./data_storage";
import serialWeb from "./webSerial.js";
import BT from "./protocols/bluetooth.js";
import websocketSerial from "./protocols/websocket.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;
};