aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-09-11 16:01:17 -0700
committerAdam Soltys <[email protected]>2025-09-11 16:03:00 -0700
commit934f87270369cd294626cf5142817edcac6c3a6c (patch)
treea39f6da68adaa3710d63d0f696165e73b7607677
parenta12405211124d47fda1b658ef7e143751c922735 (diff)
downloadcoinos-ui-934f87270369cd294626cf5142817edcac6c3a6c.tar.gz
coinos-ui-934f87270369cd294626cf5142817edcac6c3a6c.zip
pos route
-rw-r--r--src/routes/(app)/pos/+page.server.ts21
-rw-r--r--src/routes/(app)/pos/+page.svelte105
2 files changed, 126 insertions, 0 deletions
diff --git a/src/routes/(app)/pos/+page.server.ts b/src/routes/(app)/pos/+page.server.ts
new file mode 100644
index 00000000..f7a3fda3
--- /dev/null
+++ b/src/routes/(app)/pos/+page.server.ts
@@ -0,0 +1,21 @@
+import { PUBLIC_COINOS_URL } from "$env/static/public";
+import { fd } from "$lib/utils";
+import { hex } from "@scure/base";
+
+export const actions = {
+ default: async ({ fetch, request }) => {
+ const body = await fd(request);
+ console.log("POSTING", body);
+ const res = await fetch(`${PUBLIC_COINOS_URL}/flash`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ "content-type": "application/json",
+ accept: "application/octet-stream",
+ },
+ });
+
+ const buf = new Uint8Array(await res.arrayBuffer());
+ return { data: hex.encode(buf) };
+ },
+};
diff --git a/src/routes/(app)/pos/+page.svelte b/src/routes/(app)/pos/+page.svelte
new file mode 100644
index 00000000..760a89b4
--- /dev/null
+++ b/src/routes/(app)/pos/+page.svelte
@@ -0,0 +1,105 @@
+<script>
+ import { enhance } from "$app/forms";
+ import { ESPLoader, Transport } from "esptool-js";
+ import { hex } from "@scure/base";
+
+ function bs(uint8Array) {
+ let binaryString = "";
+ const chunkSize = 0x8000; // 32,768 bytes (safe limit)
+
+ for (let i = 0; i < uint8Array.length; i += chunkSize) {
+ const chunk = uint8Array.subarray(i, i + chunkSize);
+ binaryString += String.fromCharCode(...chunk);
+ }
+
+ return binaryString;
+ }
+
+ let { form } = $props();
+
+ const address = 0x3d0000;
+ const baudrate = 921600;
+
+ let file = $state();
+ let ssid = $state();
+ let key = $state();
+ let token = $state();
+ let esploader = $state();
+ let data = $derived(form ? hex.decode(form.data) : undefined);
+
+ let chip, transport;
+ // let data = $state();
+ let connect = async () => {
+ try {
+ let device = await navigator.serial.requestPort({});
+ transport = new Transport(device, true);
+
+ esploader = new ESPLoader({
+ transport,
+ baudrate,
+ });
+
+ chip = await esploader.main();
+ } catch (e) {
+ console.log(e);
+ }
+ };
+
+ let progress = $state();
+ let flash = async () => {
+ let fileArray = [{ data: bs(data), address }];
+
+ const flashOptions = {
+ fileArray,
+ flashSize: "keep",
+ eraseAll: false,
+ compress: true,
+ reportProgress: (fileIndex, written, total) => {
+ progress = parseInt((written / total) * 100);
+ },
+ };
+
+ await esploader.writeFlash(flashOptions);
+ };
+</script>
+
+<div class="container px-4 max-w-lg mx-auto space-y-5 mt-20">
+ <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold">
+ Flash config
+ </h1>
+
+ {#if esploader}
+ {#if data}
+ {#if progress}
+ <div class="text-center text-2xl">Done!</div>
+ {:else}
+ <div>Generated config file (<b>{data.length * 2} bytes</b>)</div>
+ <button class="btn" onclick={flash}>Flash</button>
+ {/if}
+ {:else}
+ <form method="POST" use:enhance class="space-y-2">
+ <input
+ name="ssid"
+ bind:value={ssid}
+ placeholder="Wifi SSID"
+ class="input"
+ />
+ <input
+ name="key"
+ bind:value={key}
+ placeholder="Wifi password"
+ class="input"
+ />
+ <input
+ name="token"
+ bind:value={token}
+ placeholder="Coinos API token"
+ class="input"
+ />
+ <button type="submit" class="btn">Generate Config</button>
+ </form>
+ {/if}
+ {:else}
+ <button class="btn" onclick={connect}>Connect</button>
+ {/if}
+</div>