Skip to content

Commit

Permalink
Make port_handler work with PWA
Browse files Browse the repository at this point in the history
  • Loading branch information
McGiverGim committed May 15, 2024
1 parent 66e822d commit 61904e8
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 25 deletions.
4 changes: 4 additions & 0 deletions locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
"message": "Virtual Mode (Experimental)",
"description": "Configure a Virtual Flight Controller without the need of a physical FC."
},
"portsSelectPermission": {
"message": "--- I can't find my device ---",
"description": "Option in the port selection dropdown to allow the user to give permissions to the system to access the device."
},
"virtualMSPVersion": {
"message": "Virtual Firmware Version"
},
Expand Down
74 changes: 60 additions & 14 deletions src/js/port_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import FC from "./fc";
import { i18n } from "./localization";
import { generateVirtualApiVersions, getTextWidth } from './utils/common';
import { get as getConfig } from "./ConfigStorage";
import serial from "./serial";
import MdnsDiscovery from "./mdns_discovery";
import { isWeb } from "./utils/isWeb";
import { serialShim } from "./serial_shim.js";

const serial = serialShim();

const TIMEOUT_CHECK = 500 ; // With 250 it seems that it produces a memory leak and slowdown in some versions, reason unknown

Expand All @@ -32,13 +34,7 @@ const PortHandler = new function () {
PortHandler.initialize = function () {
const self = this;

// currently web build doesn't need port handler,
// so just bail out.
if (isWeb()) {
return 'not implemented';
}

const portPickerElementSelector = "div#port-picker #port";
const portPickerElementSelector = "div#port-picker #port, div.web-port-picker #port";
self.portPickerElement = $(portPickerElementSelector);
self.selectList = document.querySelector(portPickerElementSelector);
self.initialWidth = self.selectList.offsetWidth + 12;
Expand Down Expand Up @@ -79,15 +75,29 @@ PortHandler.check = function () {
self.check_serial_devices();
}

self.usbCheckLoop = setTimeout(() => {
self.check();
}, TIMEOUT_CHECK);
if (isWeb()) {
serial.addEventListener("addedDevice", (e) => {
this.check_serial_devices();
});

serial.addEventListener("removedDevice", (e) => {
this.check_serial_devices();
});

this.check_serial_devices();

} else {
self.usbCheckLoop = setTimeout(() => {
self.check();
}, TIMEOUT_CHECK);
}

};

PortHandler.check_serial_devices = function () {
const self = this;

serial.getDevices(function(cp) {
const updatePorts = function(cp) {
self.currentPorts = [];

if (self.useMdnsBrowser) {
Expand Down Expand Up @@ -116,10 +126,21 @@ PortHandler.check_serial_devices = function () {
self.removePort();
self.detectPort();
}
});
};

if (isWeb()) {
serial.getDevices().then(updatePorts);
} else {
serial.getDevices(updatePorts);
}
};

PortHandler.check_usb_devices = function (callback) {

if (isWeb()) {
return;
}

const self = this;

chrome.usb.getDevices(usbDevices, function (result) {
Expand Down Expand Up @@ -321,10 +342,35 @@ PortHandler.updatePortSelect = function (ports) {
this.addNoPortSelection();
}

if (isWeb()) {
const askpermission = 'askpermission';
this.portPickerElement.append($("<option/>", {
value: askpermission,
text: i18n.getMessage('portsSelectPermission'),
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
//data: {isShowPermission: true},
}));

this.portPickerElement.on("change", e => {
if (e.target.value === askpermission) {
this.askPermissionPort();
}
e.target.value = e.target.options[0].value;
});
}

this.setPortsInputWidth();
this.currentPorts = ports;
};

PortHandler.askPermissionPort = function() {
serial.requestPermissionDevice().then(() => {
this.check_serial_devices();
});
}

PortHandler.selectActivePort = function() {
const ports = this.currentPorts;
const OS = GUI.operating_system;
Expand Down Expand Up @@ -366,7 +412,7 @@ PortHandler.setPortsInputWidth = function() {

width = (width > this.initialWidth) ? width : this.initialWidth;

const portsInput = document.querySelector("div#port-picker #portsinput");
const portsInput = document.querySelector("div#port-picker #portsinput, div.web-port-picker #portsinput");
portsInput.style.width = `${width}px`;
};

Expand Down
16 changes: 8 additions & 8 deletions src/js/serial_backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function initializeSerialBackend() {
$('#port-override').val(data.portOverride);
}

$('div#port-picker #port').change(function (target) {
$('div#port-picker #port, div.web-port-picker #port').change(function (target) {
GUI.updateManualPortVisibility();
});

Expand All @@ -85,15 +85,15 @@ export function initializeSerialBackend() {
if (selectedPort === 'manual') {
portName = $('#port-override').val();
} else {
portName = String($('div#port-picker #port').val());
portName = String($('div.web-port-picker #port').val());
}

if (!GUI.connect_lock && selectedPort !== 'none') {
// GUI control overrides the user control

GUI.configuration_loaded = false;

const selected_baud = parseInt($('div#port-picker #baud').val());
const selected_baud = parseInt($('div#port-picker #baud, div.web-port-picker #baud').val());
const selectedPort = $('#port').val();

if (selectedPort === 'DFU') {
Expand All @@ -106,7 +106,7 @@ export function initializeSerialBackend() {
GUI.connecting_to = portName;

// lock port select & baud while we are connecting / connected
$('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, div.web-port-picker #port, div.web-port-picker #baud, div.web-port-picker #delay').prop('disabled', true);
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));

const baudRate = parseInt($('#baud').val());
Expand All @@ -127,7 +127,7 @@ export function initializeSerialBackend() {
serial.removeEventListener('disconnect', disconnectHandler);
serial.addEventListener('disconnect', disconnectHandler);

serial.connect({ baudRate });
serial.connect(portName, { baudRate });
} else {
serial.connect(portName, { bitrate: selected_baud }, onOpen);
toggleStatus();
Expand Down Expand Up @@ -230,8 +230,8 @@ function finishClose(finishedCallback) {
$('#dialogReportProblems-closebtn').click();

// unlock port select & baud
$('div#port-picker #port').prop('disabled', false);
if (!GUI.auto_connect) $('div#port-picker #baud').prop('disabled', false);
$('div#port-picker #port, div.web-port-picker #port').prop('disabled', false);
if (!GUI.auto_connect) $('div#port-picker #baud, div.web-port-picker #baud').prop('disabled', false);

// reset connect / disconnect button
$('div.connect_controls a.connect').removeClass('active');
Expand Down Expand Up @@ -275,7 +275,7 @@ function abortConnection() {
$('div#connectbutton a.connect').removeClass('active');

// unlock port select & baud
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', false);
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay, div.web-port-picker #port, div.web-port-picker #baud, div.web-port-picker #delay').prop('disabled', false);

// reset data
isConnected = false;
Expand Down
44 changes: 41 additions & 3 deletions src/js/webSerial.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@ class WebSerial extends EventTarget {

this.logHead = "SERIAL: ";

this.port_counter = 0;
this.ports = null;
this.port = null;
this.reader = null;
this.writer = null;
this.reading = false;

this.connect = this.connect.bind(this);

navigator.serial.addEventListener("connect", device => {
this.dispatchEvent(new CustomEvent("addedDevice", { detail: device.target }));
});

navigator.serial.addEventListener("disconnect", device => {
this.dispatchEvent(new CustomEvent("removedDevice", { detail: device.target }));
});
}

handleReceiveBytes(info) {
Expand All @@ -47,13 +57,41 @@ class WebSerial extends EventTarget {
this.removeEventListener('disconnect', this.handleDisconnect);
}

async connect(options) {
this.openRequested = true;
this.port = await navigator.serial.requestPort({
async requestPermissionDevice() {
const permissionPort = await navigator.serial.requestPort({
filters: webSerialDevices,
});

return permissionPort;
};

async getDevices() {

const ports = await navigator.serial.getPorts({
filters: webSerialDevices,
});

this.port_counter = 0;
this.ports = ports.map(function (port, index) {
return {
path: `${this.port_counter++}`,
displayName: `Betaflight Flight Controller`,
vendorId: port.vendorId,
productId: port.productId,
port: port,
};
}, this);

return this.ports;
}

async connect(path, options) {
this.openRequested = true;

this.port = this.ports.find(device => device.path === path).port;

await this.port.open(options);

const connectionInfo = this.port.getInfo();
this.connectionInfo = connectionInfo;
this.writer = this.port.writable.getWriter();
Expand Down

0 comments on commit 61904e8

Please sign in to comment.