Skip to content

Commit

Permalink
Add web API support for flashing (#3996)
Browse files Browse the repository at this point in the history
* add web API support for flashing

* Fixes per review

* Refactor some function
  • Loading branch information
haslinghuis authored Jun 3, 2024
1 parent 8a6f314 commit ac27e8f
Show file tree
Hide file tree
Showing 7 changed files with 1,067 additions and 2,241 deletions.
112 changes: 70 additions & 42 deletions src/js/msp/MSPConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,40 @@ import MSP from "../msp";
import FC from "../fc";
import MSPCodes from "./MSPCodes";
import CONFIGURATOR from "../data_storage";
import serial from "../serial";
import serial from "../webSerial";
import { gui_log } from "../gui_log";

/**
* This seems to be mainly used in firmware flasher parts.
*/
const MSPConnectorImpl = function () {
this.baud = undefined;
this.port = undefined;
this.onConnectCallback = undefined;
this.onTimeoutCallback = undefined;
this.onDisconnectCallback = undefined;
};

MSPConnectorImpl.prototype.connect = function (port, baud, onConnectCallback, onTimeoutCallback, onFailureCallback) {

const self = this;
self.port = port;
self.baud = baud;
self.onConnectCallback = onConnectCallback;
self.onTimeoutCallback = onTimeoutCallback;
self.onFailureCallback = onFailureCallback;

serial.connect(self.port, {bitrate: self.baud}, function (openInfo) {
if (openInfo) {
const disconnectAndCleanup = function() {
serial.disconnect(function(result) {
console.log('Disconnected');

MSP.clearListeners();
function readSerialAdapter(e) {
read_serial(e.detail.buffer);
}

self.onTimeoutCallback();
});
function disconnectAndCleanup() {
serial.disconnect((result) => {
console.log('Disconnected', result);

MSP.disconnect_cleanup();
};
MSP.clearListeners();

this.onTimeoutCallback();
});

MSP.disconnect_cleanup();
}

class MSPConnectorImpl {
constructor() {
this.baud = undefined;
this.port = undefined;
this.onConnectCallback = undefined;
this.onTimeoutCallback = undefined;
this.onDisconnectCallback = undefined;
}

handleConnect(openInfo) {
if (openInfo) {
FC.resetState();

// disconnect after 10 seconds with error if we don't get IDENT data
Expand All @@ -54,37 +51,68 @@ MSPConnectorImpl.prototype.connect = function (port, baud, onConnectCallback, on
}
}, 10000);

serial.onReceive.addListener(read_serial);
serial.removeEventListener('receive', readSerialAdapter);
serial.addEventListener('receive', readSerialAdapter);

const mspHelper = new MspHelper();
MSP.listen(mspHelper.process_data.bind(mspHelper));

MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, function () {
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, () => {
CONFIGURATOR.connectionValid = true;

GUI.timeout_remove('msp_connector');
console.log('Connected');

self.onConnectCallback();
this.onConnectCallback();
});
} else {
gui_log(i18n.getMessage('serialPortOpenFail'));
self.onFailureCallback();
this.onFailureCallback();
}
});
};
}

handleDisconnect (detail) {
console.log('Disconnected', detail);

serial.removeEventListener('receive', readSerialAdapter);

MSPConnectorImpl.prototype.disconnect = function(onDisconnectCallback) {
self.onDisconnectCallback = onDisconnectCallback;
// Calling in case event listeners were not removed
serial.removeEventListener('connect', (e) => this.handleConnect(e.detail));
serial.removeEventListener('disconnect', (e) => this.handleDisconnect(e));

serial.disconnect(function (result) {
MSP.clearListeners();
console.log('Disconnected');
MSP.disconnect_cleanup();
}

self.onDisconnectCallback(result);
});
connect(port, baud, onConnectCallback, onTimeoutCallback, onFailureCallback) {

MSP.disconnect_cleanup();
};
this.port = port;
this.baud = baud;
this.onConnectCallback = onConnectCallback;
this.onTimeoutCallback = onTimeoutCallback;
this.onFailureCallback = onFailureCallback;

serial.removeEventListener('connect', (e) => this.handleConnect(e.detail));
serial.addEventListener('connect', (e) => this.handleConnect(e.detail), { once: true });

serial.removeEventListener('disconnect', (e) => this.handleDisconnect(e));
serial.addEventListener('disconnect', (e) => this.handleDisconnect(e), { once: true });

serial.connect(this.port, { baudRate: this.baud });
}

disconnect(onDisconnectCallback) {
this.onDisconnectCallback = onDisconnectCallback;

serial.disconnect((result) => {
MSP.clearListeners();
console.log('Disconnected', result);

this.onDisconnectCallback(result);
});

MSP.disconnect_cleanup();
}
}

export default MSPConnectorImpl;
104 changes: 14 additions & 90 deletions src/js/port_handler.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import GUI from "./gui";
import FC from "./fc";
import { i18n } from "./localization";
import { get as getConfig } from "./ConfigStorage";
import { isWeb } from "./utils/isWeb";
import { usbDevices } from "./usb_devices";
import { serialShim } from "./serial_shim.js";
import { usbShim } from "./usb_shim.js";
import { EventBus } from "../components/eventBus";

const serial = serialShim();
const usb = usbShim();
import serial from "./webSerial";
import usb from "./protocols/webusbdfu";

const DEFAULT_PORT = 'noselection';
const DEFAULT_BAUDS = 115200;
Expand Down Expand Up @@ -92,22 +84,18 @@ PortHandler.onChangeSelectedPort = function(port) {
this.portPicker.selectedPort = port;
};

PortHandler.updateCurrentSerialPortsList = function () {
return serial.getDevices()
.then((ports) => {
const orderedPorts = this.sortPorts(ports);
this.portAvailable = orderedPorts.length > 0;
this.currentSerialPorts = orderedPorts;
});
PortHandler.updateCurrentSerialPortsList = async function () {
const ports = await serial.getDevices();
const orderedPorts = this.sortPorts(ports);
this.portAvailable = orderedPorts.length > 0;
this.currentSerialPorts = orderedPorts;
};

PortHandler.updateCurrentUsbPortsList = function () {
return usb.getDevices()
.then((ports) => {
const orderedPorts = this.sortPorts(ports);
this.dfuAvailable = orderedPorts.length > 0;
this.currentUsbPorts = orderedPorts;
});
PortHandler.updateCurrentUsbPortsList = async function () {
const ports = await usb.getDevices();
const orderedPorts = this.sortPorts(ports);
this.dfuAvailable = orderedPorts.length > 0;
this.currentUsbPorts = orderedPorts;
};

PortHandler.sortPorts = function(ports) {
Expand Down Expand Up @@ -149,15 +137,15 @@ PortHandler.selectActivePort = function(suggestedDevice) {
selectedPort = suggestedDevice.path;
}

// Return some serial port that is recognized by the filter
// Return some usb port that is recognized by the filter
if (!selectedPort) {
selectedPort = this.currentUsbPorts.find(device => deviceFilter.some(filter => device.displayName.includes(filter)));
if (selectedPort) {
selectedPort = selectedPort.path;
}
}

// Return some usb port that is recognized by the filter
// Return some serial port that is recognized by the filter
if (!selectedPort) {
selectedPort = this.currentSerialPorts.find(device => deviceFilter.some(filter => device.displayName.includes(filter)));
if (selectedPort) {
Expand Down Expand Up @@ -186,70 +174,6 @@ PortHandler.selectActivePort = function(suggestedDevice) {
// TODO all the methods from here need to be refactored or removed
************************************/

PortHandler.check_usb_devices = function (callback) {

// TODO needs USB code refactor for web
if (isWeb()) {
return;
}

const self = this;

chrome.usb.getDevices(usbDevices, function (result) {

const dfuElement = self.portPickerElement.children("[value='DFU']");
if (result.length) {
// Found device in DFU mode, add it to the list
if (!dfuElement.length) {
self.portPickerElement.empty();

const productName = result[0].productName;
const usbText = productName ? `DFU - ${productName}` : 'DFU';

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: DEFAULT_PORT,
text: i18n.getMessage('portsSelectManual'),
/**
* @deprecated please avoid using `isDFU` and friends for new code.
*/
data: {isManual: true},
}));

self.portPickerElement.val('DFU').trigger('change');
self.setPortsInputWidth();
self.dfuAvailable = true;
}
} else if (dfuElement.length) {
dfuElement.remove();
self.setPortsInputWidth();
self.dfuAvailable = false;

if ($('option:selected', self.portPickerElement).val() !== 'DFU') {
if (!(GUI.connected_to || GUI.connect_lock)) {
FC.resetState();
}

if (self.dfuAvailable) {
self.portPickerElement.trigger('change');
}
}
}

if (callback) {
callback(self.dfuAvailable);
}
});
};

PortHandler.flush_callbacks = function () {
let killed = 0;

Expand Down
Loading

0 comments on commit ac27e8f

Please sign in to comment.