Skip to content

Commit 292093a

Browse files
authored
Fix firmware flasher event cleanup (#4667)
* Fix firmware flasher events * CR review * CR review II * CR review III * Reduce
1 parent 3e5bc26 commit 292093a

File tree

1 file changed

+144
-15
lines changed

1 file changed

+144
-15
lines changed

src/js/tabs/firmware_flasher.js

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { EventBus } from "../../components/eventBus";
2121
import { ispConnected } from "../utils/connection.js";
2222
import FC from "../fc";
2323

24+
const PORT_CHANGE_DEBOUNCE_MS = 500;
25+
2426
const firmware_flasher = {
2527
targets: null,
2628
buildApi: new BuildApi(),
@@ -40,6 +42,115 @@ const firmware_flasher = {
4042
// Properties to preserve firmware state during flashing
4143
preFlashingMessage: null,
4244
preFlashingMessageType: null,
45+
// Single debounce timer shared across instances
46+
portChangeTimer: null,
47+
logHead: "[FIRMWARE_FLASHER]",
48+
// Event handlers to allow removal on tab change
49+
detectedUsbDevice: function (device) {
50+
const isFlashOnConnect = $("input.flash_on_connect").is(":checked");
51+
52+
console.log(`${firmware_flasher.logHead} Detected USB device:`, device);
53+
console.log(
54+
`${firmware_flasher.logHead} Reboot mode: %s, flash on connect`,
55+
STM32.rebootMode,
56+
isFlashOnConnect,
57+
);
58+
59+
// If another operation is in progress, ignore port events (unless we're resuming from a reboot)
60+
if (GUI.connect_lock && !STM32.rebootMode) {
61+
console.log(`${firmware_flasher.logHead} Port event ignored due to active operation (connect_lock)`);
62+
return;
63+
}
64+
65+
// Proceed if we're resuming a reboot sequence or if flash-on-connect is enabled and no operation is active
66+
if (STM32.rebootMode || isFlashOnConnect) {
67+
const wasReboot = !!STM32.rebootMode;
68+
STM32.rebootMode = 0;
69+
// Only clear the global connect lock when we are resuming from a reboot
70+
// so we don't accidentally interrupt another active operation.
71+
if (wasReboot) {
72+
GUI.connect_lock = false;
73+
}
74+
firmware_flasher.startFlashing?.();
75+
}
76+
},
77+
detectedSerialDevice: function (device) {
78+
console.log(`${firmware_flasher.logHead} Detected serial device:`, device);
79+
80+
// If another operation is in progress, ignore port events.
81+
if (GUI.connect_lock) {
82+
console.log(
83+
`${firmware_flasher.logHead} Serial device event ignored due to active operation (connect_lock)`,
84+
);
85+
return;
86+
}
87+
88+
const isFlashOnConnect = $("input.flash_on_connect").is(":checked");
89+
90+
// If flash-on-connect is enabled, trigger startFlashing (if available) instead
91+
// of running AutoDetect.verifyBoard(), mirroring the onPortChange logic.
92+
if (isFlashOnConnect) {
93+
firmware_flasher.startFlashing?.();
94+
return;
95+
}
96+
97+
try {
98+
AutoDetect.verifyBoard();
99+
} catch (e) {
100+
console.warn(`${firmware_flasher.logHead} AutoDetect.verifyBoard threw:`, e);
101+
}
102+
},
103+
onPortChange: function (port) {
104+
// Clear any pending debounce timer so rapid port events don't re-enter the handler.
105+
if (firmware_flasher.portChangeTimer) {
106+
clearTimeout(firmware_flasher.portChangeTimer);
107+
firmware_flasher.portChangeTimer = null;
108+
}
109+
110+
console.log(`${firmware_flasher.logHead} Port changed to:`, port);
111+
112+
if (GUI.connect_lock) {
113+
console.log(`${firmware_flasher.logHead} Port change ignored during active operation (connect_lock set)`);
114+
return;
115+
}
116+
117+
// Auto-detect board when port changes and we're on firmware flasher tab
118+
if (port && port !== "0" && $("input.flash_on_connect").is(":checked") === false && !STM32.rebootMode) {
119+
console.log(`${firmware_flasher.logHead} Auto-detecting board for port change (debounced)`);
120+
121+
// Debounced verification: re-check connect lock when the timeout fires
122+
firmware_flasher.portChangeTimer = setTimeout(() => {
123+
firmware_flasher.portChangeTimer = null;
124+
if (GUI.connect_lock) {
125+
console.log(`${firmware_flasher.logHead} Skipping auto-detect due to active operation at timeout`);
126+
return;
127+
}
128+
try {
129+
AutoDetect.verifyBoard();
130+
} catch (e) {
131+
console.warn(`${firmware_flasher.logHead} AutoDetect.verifyBoard threw (debounced):`, e);
132+
}
133+
}, PORT_CHANGE_DEBOUNCE_MS);
134+
} else if (!port || port === "0") {
135+
if (!GUI.connect_lock) {
136+
console.log(`${firmware_flasher.logHead} Clearing board selection - no port selected`);
137+
$('select[name="board"]').val("0").trigger("change");
138+
} else {
139+
console.log(`${firmware_flasher.logHead} Not clearing board selection because operation in progress`);
140+
}
141+
}
142+
},
143+
onDeviceRemoved: function (devicePath) {
144+
console.log(`${firmware_flasher.logHead} Device removed:`, devicePath);
145+
146+
// Avoid clearing when removal is expected during flashing/reboot
147+
if (GUI.connect_lock || STM32.rebootMode) {
148+
return;
149+
}
150+
151+
$('select[name="board"]').val("0").trigger("change");
152+
firmware_flasher.clearBufferedFirmware?.();
153+
},
43154
};
44155

45156
firmware_flasher.initialize = async function (callback) {
@@ -60,8 +171,6 @@ firmware_flasher.initialize = async function (callback) {
60171
self.intel_hex = undefined;
61172
self.parsed_hex = undefined;
62173

63-
self.logHead = "[FIRMWARE_FLASHER]";
64-
65174
function getExtension(key) {
66175
if (!key) {
67176
return undefined;
@@ -742,20 +851,16 @@ firmware_flasher.initialize = async function (callback) {
742851
return output.join("").split("\n");
743852
}
744853

745-
function detectedUsbDevice(device) {
746-
const isFlashOnConnect = $("input.flash_on_connect").is(":checked");
854+
// Expose the local startFlashing implementation to module callers/tests so
855+
// module-scoped handlers can safely call firmware_flasher.startFlashing()
856+
// even if those callers ran before initialize() completed.
857+
firmware_flasher.startFlashing = startFlashing;
858+
firmware_flasher.clearBufferedFirmware = clearBufferedFirmware;
747859

748-
console.log(`${self.logHead} Detected USB device:`, device);
749-
console.log(`${self.logHead} Reboot mode: %s, flash on connect`, STM32.rebootMode, isFlashOnConnect);
750-
751-
if (STM32.rebootMode || isFlashOnConnect) {
752-
STM32.rebootMode = 0;
753-
GUI.connect_lock = false;
754-
startFlashing();
755-
}
756-
}
757-
758-
EventBus.$on("port-handler:auto-select-usb-device", detectedUsbDevice);
860+
EventBus.$on("port-handler:auto-select-usb-device", firmware_flasher.detectedUsbDevice);
861+
EventBus.$on("port-handler:auto-select-serial-device", firmware_flasher.detectedSerialDevice);
862+
EventBus.$on("ports-input:change", firmware_flasher.onPortChange);
863+
EventBus.$on("port-handler:device-removed", firmware_flasher.onDeviceRemoved);
759864

760865
async function saveFirmware() {
761866
const fileType = self.firmware_type;
@@ -1472,6 +1577,12 @@ firmware_flasher.initialize = async function (callback) {
14721577
$("a.exit_dfu").removeClass("disabled");
14731578
}
14741579

1580+
const isFlashOnConnect = $("input.flash_on_connect").is(":checked");
1581+
if (PortHandler.portAvailable && !isFlashOnConnect) {
1582+
console.log(`${self.logHead} 💥 Auto-detecting board for already connected device`);
1583+
AutoDetect.verifyBoard();
1584+
}
1585+
14751586
GUI.content_ready(callback);
14761587
}
14771588

@@ -1490,6 +1601,24 @@ firmware_flasher.cleanup = function (callback) {
14901601
$(document).unbind("keypress");
14911602
$(document).off("click", "span.progressLabel a");
14921603

1604+
const cleanupHandler = (evt, property) => {
1605+
const handler = firmware_flasher[property];
1606+
if (handler) {
1607+
EventBus.$off(evt, handler);
1608+
}
1609+
};
1610+
1611+
cleanupHandler("port-handler:auto-select-usb-device", "detectedUsbDevice");
1612+
cleanupHandler("port-handler:auto-select-serial-device", "detectedSerialDevice");
1613+
cleanupHandler("ports-input:change", "onPortChange");
1614+
cleanupHandler("port-handler:device-removed", "onDeviceRemoved");
1615+
1616+
// Clear any pending debounce timer so it cannot fire after cleanup
1617+
if (firmware_flasher.portChangeTimer) {
1618+
clearTimeout(firmware_flasher.portChangeTimer);
1619+
firmware_flasher.portChangeTimer = null;
1620+
}
1621+
14931622
if (callback) callback();
14941623
};
14951624

0 commit comments

Comments
 (0)