Skip to content

Commit 2d36e62

Browse files
authored
Serial refactor part 2 (#4404)
* Serial refactor part 2 * Fix callback * Fix some sonar complaints * Does no longer block dfu * Excempt presets * Add interval for reboot dialog * Update message after review Vitroid
1 parent c842b9d commit 2d36e62

File tree

6 files changed

+400
-133
lines changed

6 files changed

+400
-133
lines changed

locales/en/messages.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@
320320
"configuratorUpdateWebsite": {
321321
"message": "Go to Release Website"
322322
},
323+
"rebootFlightController": {
324+
"message": "Rebooting flight controller, reconnect when ready"
325+
},
326+
"rebootFlightControllerReady": {
327+
"message": "Flight Controller is ready"
328+
},
323329
"deviceRebooting": {
324330
"message": "Device - <span class=\"message-negative\">Rebooting</span>"
325331
},

src/js/port_handler.js

Lines changed: 158 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { get as getConfig } from "./ConfigStorage";
22
import { EventBus } from "../components/eventBus";
33
import { serial } from "./serial.js";
44
import WEBUSBDFU from "./protocols/webusbdfu";
5-
import WebBluetooth from "./protocols/WebBluetooth.js";
65
import { reactive } from "vue";
76

87
const DEFAULT_PORT = "noselection";
@@ -35,44 +34,42 @@ const PortHandler = new (function () {
3534
})();
3635

3736
PortHandler.initialize = function () {
38-
EventBus.$on("ports-input:request-permission-bluetooth", this.askBluetoothPermissionPort.bind(this));
39-
EventBus.$on("ports-input:request-permission", this.askSerialPermissionPort.bind(this));
37+
EventBus.$on("ports-input:request-permission-bluetooth", () => this.requestDevicePermission("bluetooth"));
38+
EventBus.$on("ports-input:request-permission", () => this.requestDevicePermission("serial"));
4039
EventBus.$on("ports-input:change", this.onChangeSelectedPort.bind(this));
4140

4241
// Use serial for all protocol events
4342
serial.addEventListener("addedDevice", (event) => {
4443
const detail = event.detail;
4544

46-
// Determine the device type based on its properties
4745
if (detail?.path?.startsWith("bluetooth")) {
48-
this.addedBluetoothDevice(detail);
49-
} else if (detail?.path?.startsWith("usb_")) {
50-
this.addedUsbDevice(detail);
46+
this.handleDeviceAdded(detail, "bluetooth");
5147
} else {
52-
this.addedSerialDevice(detail);
48+
this.handleDeviceAdded(detail, "serial");
5349
}
5450
});
5551

5652
serial.addEventListener("removedDevice", (event) => {
57-
const detail = event.detail;
58-
59-
// Determine the device type based on its properties
60-
if (detail?.path?.startsWith("bluetooth")) {
61-
this.removedBluetoothDevice(detail);
62-
} else if (detail?.path?.startsWith("usb_")) {
63-
// Handle USB device removal if needed
64-
} else {
65-
this.removedSerialDevice(detail);
66-
}
53+
this.removedSerialDevice(event.detail);
6754
});
6855

6956
// Keep USB listener separate as it's not part of the serial protocols
7057
WEBUSBDFU.addEventListener("addedDevice", (event) => this.addedUsbDevice(event.detail));
7158

72-
// Initial device discovery
73-
this.addedSerialDevice();
74-
this.addedBluetoothDevice();
75-
this.addedUsbDevice();
59+
// Initial device discovery using the serial facade
60+
this.refreshAllDeviceLists();
61+
};
62+
63+
// Refactored refreshAllDeviceLists to use updateDeviceList
64+
PortHandler.refreshAllDeviceLists = async function () {
65+
// Update all device lists in parallel
66+
return Promise.all([
67+
this.updateDeviceList("serial"),
68+
this.updateDeviceList("bluetooth"),
69+
this.updateDeviceList("usb"),
70+
]).then(() => {
71+
this.selectActivePort();
72+
});
7673
};
7774

7875
PortHandler.setShowVirtualMode = function (showVirtualMode) {
@@ -89,44 +86,40 @@ PortHandler.setShowAllSerialDevices = function (showAllSerialDevices) {
8986
this.showAllSerialDevices = showAllSerialDevices;
9087
};
9188

92-
PortHandler.addedSerialDevice = function (device) {
93-
this.updateCurrentSerialPortsList().then(() => {
94-
const selectedPort = this.selectActivePort(device);
95-
if (!device || selectedPort === device.path) {
96-
// Send this event when the port handler auto selects a new device
97-
EventBus.$emit("port-handler:auto-select-serial-device", selectedPort);
98-
}
99-
});
100-
};
101-
10289
PortHandler.removedSerialDevice = function (device) {
103-
this.updateCurrentSerialPortsList().then(() => {
104-
if (this.portPicker.selectedPort === device.path) {
90+
console.log(`${this.logHead} Device removal event received:`, device);
91+
92+
// Get device path safely
93+
const devicePath = device?.path || (typeof device === "string" ? device : null);
94+
95+
if (!devicePath) {
96+
console.warn(`${this.logHead} Device removal event missing path information`, device);
97+
// Still update ports, but don't try to use the undefined path
98+
this.updateDeviceList("serial").then(() => {
10599
this.selectActivePort();
106-
}
107-
});
108-
};
100+
});
101+
return;
102+
}
109103

110-
PortHandler.addedBluetoothDevice = function (device) {
111-
this.updateCurrentBluetoothPortsList().then(() => {
112-
const selectedPort = this.selectActivePort(device);
113-
if (!device || selectedPort === device.path) {
114-
// Send this event when the port handler auto selects a new device
115-
EventBus.$emit("port-handler:auto-select-bluetooth-device", selectedPort);
116-
}
117-
});
118-
};
104+
// Update the appropriate ports list based on the device type
105+
const updatePromise = devicePath.startsWith("bluetooth")
106+
? this.updateDeviceList("bluetooth")
107+
: this.updateDeviceList("serial");
119108

120-
PortHandler.removedBluetoothDevice = function (device) {
121-
this.updateCurrentBluetoothPortsList().then(() => {
122-
if (this.portPicker.selectedPort === device.path) {
109+
const wasSelectedPort = this.portPicker.selectedPort === devicePath;
110+
111+
updatePromise.then(() => {
112+
if (wasSelectedPort) {
123113
this.selectActivePort();
114+
115+
// Send event for UI components that might need to update
116+
EventBus.$emit("port-handler:device-removed", devicePath);
124117
}
125118
});
126119
};
127120

128121
PortHandler.addedUsbDevice = function (device) {
129-
this.updateCurrentUsbPortsList().then(() => {
122+
this.updateDeviceList("usb").then(() => {
130123
const selectedPort = this.selectActivePort(device);
131124
if (!device || selectedPort === device.path) {
132125
// Send this event when the port handler auto selects a new device
@@ -139,30 +132,28 @@ PortHandler.onChangeSelectedPort = function (port) {
139132
this.portPicker.selectedPort = port;
140133
};
141134

142-
PortHandler.updateCurrentSerialPortsList = async function () {
143-
const ports = await serial.getDevices();
144-
const orderedPorts = this.sortPorts(ports);
145-
this.portAvailable = orderedPorts.length > 0;
146-
console.log(`${this.logHead} Found serial port`, orderedPorts);
147-
this.currentSerialPorts = [...orderedPorts];
148-
};
149-
150-
PortHandler.updateCurrentUsbPortsList = async function () {
151-
const ports = await WEBUSBDFU.getDevices();
152-
const orderedPorts = this.sortPorts(ports);
153-
this.dfuAvailable = orderedPorts.length > 0;
154-
console.log(`${this.logHead} Found DFU port`, orderedPorts);
155-
this.currentUsbPorts = [...orderedPorts];
156-
};
157-
158-
PortHandler.updateCurrentBluetoothPortsList = async function () {
159-
if (WebBluetooth.bluetooth) {
160-
const ports = await WebBluetooth.getDevices();
161-
const orderedPorts = this.sortPorts(ports);
162-
this.bluetoothAvailable = orderedPorts.length > 0;
163-
console.log(`${this.logHead} Found bluetooth port`, orderedPorts);
164-
this.currentBluetoothPorts = [...orderedPorts];
165-
}
135+
/**
136+
* Request permission for a device of the specified type
137+
* @param {string} deviceType - Type of device ('serial' or 'bluetooth')
138+
*/
139+
PortHandler.requestDevicePermission = function (deviceType = "serial") {
140+
// Determine whether to show all devices based on device type
141+
const showAllDevices = deviceType === "serial" ? this.showAllSerialDevices : false;
142+
143+
// Use serial facade to request permission
144+
serial
145+
.requestPermissionDevice(showAllDevices, deviceType)
146+
.then((port) => {
147+
if (port) {
148+
console.log(`${this.logHead} Permission granted for ${deviceType} device:`, port);
149+
this.selectActivePort(port);
150+
} else {
151+
console.log(`${this.logHead} Permission request cancelled or failed for ${deviceType}`);
152+
}
153+
})
154+
.catch((error) => {
155+
console.error(`${this.logHead} Error requesting permission for ${deviceType}:`, error);
156+
});
166157
};
167158

168159
PortHandler.sortPorts = function (ports) {
@@ -174,31 +165,11 @@ PortHandler.sortPorts = function (ports) {
174165
});
175166
};
176167

177-
PortHandler.askBluetoothPermissionPort = function () {
178-
if (WebBluetooth.bluetooth) {
179-
WebBluetooth.requestPermissionDevice().then((port) => {
180-
// When giving permission to a new device, the port is selected in the handleNewDevice method, but if the user
181-
// selects a device that had already permission, or cancels the permission request, we need to select the port
182-
// so do it here too
183-
this.selectActivePort(port);
184-
});
185-
}
186-
};
187-
188-
PortHandler.askSerialPermissionPort = function () {
189-
serial.requestPermissionDevice(this.showAllSerialDevices).then((port) => {
190-
// When giving permission to a new device, the port is selected in the handleNewDevice method, but if the user
191-
// selects a device that had already permission, or cancels the permission request, we need to select the port
192-
// so do it here too
193-
this.selectActivePort(port);
194-
});
195-
};
196-
197-
PortHandler.selectActivePort = function (suggestedDevice) {
168+
PortHandler.selectActivePort = function (suggestedDevice = false) {
198169
const deviceFilter = ["AT32", "CP210", "SPR", "STM"];
199170
let selectedPort;
200171

201-
// Return the same that is connected to serial
172+
// First check for active connections
202173
if (serial.connected) {
203174
selectedPort = this.currentSerialPorts.find((device) => device === serial.getConnectedPort());
204175
}
@@ -208,10 +179,22 @@ PortHandler.selectActivePort = function (suggestedDevice) {
208179
selectedPort = this.currentUsbPorts.find((device) => device === WEBUSBDFU.getConnectedPort());
209180
}
210181

211-
// Return the same that is connected to bluetooth
212-
if (WebBluetooth.device) {
213-
selectedPort = this.currentBluetoothPorts.find((device) => device === WebBluetooth.getConnectedPort());
214-
}
182+
// If there is a connection, return it
183+
// if (selectedPort) {
184+
// console.log(`${this.logHead} Using connected device: ${selectedPort.path}`);
185+
// selectedPort = selectedPort.path;
186+
// return selectedPort;
187+
// }
188+
189+
// If there is no connection, check for the last used device
190+
// Check if the device is already connected
191+
// if (this.portPicker.selectedPort && this.portPicker.selectedPort !== DEFAULT_PORT) {
192+
// selectedPort = this.currentSerialPorts.find((device) => device.path === this.portPicker.selectedPort);
193+
// if (selectedPort) {
194+
// console.log(`${this.logHead} Using previously selected device: ${selectedPort.path}`);
195+
// return selectedPort.path;
196+
// }
197+
// }
215198

216199
// Return the suggested device (the new device that has been detected)
217200
if (!selectedPort && suggestedDevice) {
@@ -269,6 +252,81 @@ PortHandler.selectActivePort = function (suggestedDevice) {
269252
return selectedPort;
270253
};
271254

255+
// Create a unified handler for device addition
256+
PortHandler.handleDeviceAdded = function (device, deviceType) {
257+
if (!device) {
258+
console.warn(`${this.logHead} Invalid ${deviceType} device added event`);
259+
return;
260+
}
261+
262+
console.log(`${this.logHead} ${deviceType} device added:`, device);
263+
264+
// Update the appropriate device list
265+
const updatePromise =
266+
deviceType === "bluetooth" ? this.updateDeviceList("bluetooth") : this.updateDeviceList("serial");
267+
268+
updatePromise.then(() => {
269+
const selectedPort = this.selectActivePort(device);
270+
271+
if (selectedPort === device.path) {
272+
// Emit an event with the proper type for backward compatibility
273+
EventBus.$emit(`port-handler:auto-select-${deviceType}-device`, selectedPort);
274+
}
275+
});
276+
};
277+
278+
/**
279+
* Update device list with common implementation
280+
* @param {string} deviceType - Type of device ('serial', 'bluetooth', 'usb')
281+
* @returns {Promise} - Promise that resolves after updating the ports list
282+
*/
283+
PortHandler.updateDeviceList = async function (deviceType) {
284+
let ports = [];
285+
286+
try {
287+
switch (deviceType) {
288+
case "bluetooth":
289+
ports = await serial.getDevices("bluetooth");
290+
break;
291+
case "usb":
292+
ports = await WEBUSBDFU.getDevices();
293+
break;
294+
case "serial":
295+
default:
296+
ports = await serial.getDevices("serial");
297+
break;
298+
}
299+
300+
// Sort the ports
301+
const orderedPorts = this.sortPorts(ports);
302+
303+
// Update the appropriate properties based on device type
304+
switch (deviceType) {
305+
case "bluetooth":
306+
this.bluetoothAvailable = orderedPorts.length > 0;
307+
this.currentBluetoothPorts = [...orderedPorts];
308+
console.log(`${this.logHead} Found bluetooth port(s)`, orderedPorts);
309+
break;
310+
case "usb":
311+
this.dfuAvailable = orderedPorts.length > 0;
312+
this.currentUsbPorts = [...orderedPorts];
313+
console.log(`${this.logHead} Found DFU port(s)`, orderedPorts);
314+
break;
315+
case "serial":
316+
default:
317+
this.portAvailable = orderedPorts.length > 0;
318+
this.currentSerialPorts = [...orderedPorts];
319+
console.log(`${this.logHead} Found serial port(s)`, orderedPorts);
320+
break;
321+
}
322+
323+
return orderedPorts;
324+
} catch (error) {
325+
console.error(`${this.logHead} Error updating ${deviceType} devices:`, error);
326+
return [];
327+
}
328+
};
329+
272330
// We need to explicit make it reactive. If not, Vue3 does not detect correctly changes in array properties
273331
// like currentSerialPorts, currentUsbPorts, currentBluetoothPorts
274332
export default reactive(PortHandler);

src/js/protocols/WebSerial.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ class WebSerial extends EventTarget {
272272

273273
if (this.reader) {
274274
await this.reader.cancel();
275-
this.reader.releaseLock();
275+
await this.reader.releaseLock();
276276
this.reader = null;
277277
}
278278

0 commit comments

Comments
 (0)