aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/routes/(app)/pos/+page.svelte40
1 files changed, 34 insertions, 6 deletions
diff --git a/src/routes/(app)/pos/+page.svelte b/src/routes/(app)/pos/+page.svelte
index eb074b1a..5a11d148 100644
--- a/src/routes/(app)/pos/+page.svelte
+++ b/src/routes/(app)/pos/+page.svelte
@@ -1,5 +1,6 @@
<script>
import { enhance } from "$app/forms";
+ import { onDestroy } from "svelte";
import { ESPLoader, Transport } from "esptool-js";
import { hex } from "@scure/base";
@@ -77,15 +78,30 @@
portInfo = (await device.getInfo?.()) ? JSON.stringify(await device.getInfo()) : "Connected";
} catch (e) {
console.log(e);
- connected = false;
+ // A failed connect must not leave the port claimed: the browser keeps
+ // it open until someone calls close(), and the chip may already be
+ // sitting in the ROM download mode.
+ await resetDevice();
}
};
+ // Close the serial port and forget it. The browser holds a port open until
+ // it is explicitly closed — navigating away does not release it.
+ let releasePort = async () => {
+ try {
+ await transport?.disconnect();
+ } catch (e) {}
+ transport = undefined;
+ esploader = undefined;
+ connected = false;
+ };
+
// Pulse RTS to hard-reset the chip out of the ROM bootloader so it boots
// the app with the new flash contents. Same sequence esptool.py uses
// ("Hard resetting via RTS pin"); on the C3's USB-JTAG-serial port RTS
// drives EN, so the device re-enumerates and must be reconnected.
let resetDevice = async () => {
+ if (!transport) return;
try {
await transport.setDTR(false);
await transport.setRTS(true);
@@ -94,14 +110,25 @@
} catch (e) {
console.warn("reset failed", e);
}
- try {
- await transport.disconnect();
- } catch (e) {}
- esploader = undefined;
- connected = false;
+ await releasePort();
portInfo = "Device reset. Reconnect to flash again.";
};
+ // Connecting parks the chip in the ROM download mode (esptool stub loaded,
+ // app not running). Until it is hard-reset the OLED keeps whatever the app
+ // last drew and the keypad is dead, so it looks frozen rather than
+ // "in flashing mode". Leaving the page — SPA navigation, reload, or tab
+ // close — must therefore reset the device and release the port; neither
+ // happens on its own.
+ onDestroy(() => {
+ resetDevice();
+ });
+ $effect(() => {
+ const onHide = () => resetDevice();
+ window.addEventListener("pagehide", onHide);
+ return () => window.removeEventListener("pagehide", onHide);
+ });
+
let flashConfig = async () => {
if (!esploader || !bytes) return;
if (bytes.length !== 0x20000) {
@@ -253,6 +280,7 @@
<div class="flex gap-2 justify-center">
<button class="btn" class:btn-neutral={tab === "config"} onclick={() => (tab = "config")}>Flash config</button>
<button class="btn" class:btn-neutral={tab === "firmware"} onclick={() => (tab = "firmware")}>Flash firmware</button>
+ <button class="btn" onclick={resetDevice} title="Reset the device into its app and release the serial port">Disconnect</button>
</div>
{#if tab === "config"}