feat: add LilyGo T-Beam and T-Beam Supreme board support
This commit is contained in:
6 files changed
+64
-8
No files matched your search
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
let { selected, onselect }: Props = $props();
|
let { selected, onselect }: Props = $props();
|
||||||
|
|
||||||
|
const esp32Boards = boards.filter((b) => b.family === "esp32");
|
||||||
const espBoards = boards.filter((b) => b.family === "esp32s3");
|
const espBoards = boards.filter((b) => b.family === "esp32s3");
|
||||||
const rpBoards = boards.filter((b) => b.family === "rp2040");
|
const rpBoards = boards.filter((b) => b.family === "rp2040");
|
||||||
const nrfBoards = boards.filter((b) => b.family === "nrf52840");
|
const nrfBoards = boards.filter((b) => b.family === "nrf52840");
|
||||||
@@ -39,6 +40,23 @@
|
|||||||
<div>
|
<div>
|
||||||
<h3 class="font-mono text-sm text-text-muted mb-3 uppercase tracking-wider">Select Board</h3>
|
<h3 class="font-mono text-sm text-text-muted mb-3 uppercase tracking-wider">Select Board</h3>
|
||||||
|
|
||||||
|
<p class="text-xs text-text-dim mb-2 font-mono">ESP32</p>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
||||||
|
{#each esp32Boards as board}
|
||||||
|
<button
|
||||||
|
class="text-left bg-bg-card border p-4 rounded transition-all cursor-pointer
|
||||||
|
{selected?.id === board.id
|
||||||
|
? 'border-accent shadow-[0_0_12px_oklch(from_var(--color-accent)_l_c_h_/_0.15)]'
|
||||||
|
: 'border-border hover:border-border-bright'}"
|
||||||
|
onclick={() => onselect(board)}
|
||||||
|
>
|
||||||
|
<div class="font-mono font-medium text-text text-sm">{board.name}</div>
|
||||||
|
<div class="text-xs text-text-muted mt-1">{board.mcu} · {board.radio}</div>
|
||||||
|
<div class="text-xs {badgeColor(board)} mt-2 font-mono">{badgeText(board)}</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="text-xs text-text-dim mb-2 font-mono">ESP32-S3</p>
|
<p class="text-xs text-text-dim mb-2 font-mono">ESP32-S3</p>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
||||||
{#each espBoards as board}
|
{#each espBoards as board}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
let session;
|
let session;
|
||||||
try {
|
try {
|
||||||
session = await connect(callbacks);
|
session = await connect(callbacks, board.family === "esp32" ? "esp32" : "esp32s3");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof DOMException && err.name === "NotFoundError"
|
const msg = err instanceof DOMException && err.name === "NotFoundError"
|
||||||
? "Port selection cancelled."
|
? "Port selection cancelled."
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
{#if selectedBoard && selectedRelease}
|
{#if selectedBoard && selectedRelease}
|
||||||
<div class="border-t border-border pt-8">
|
<div class="border-t border-border pt-8">
|
||||||
<h3 class="font-mono text-sm text-text-muted mb-3 uppercase tracking-wider">
|
<h3 class="font-mono text-sm text-text-muted mb-3 uppercase tracking-wider">
|
||||||
{#if selectedBoard.family === "esp32s3"}
|
{#if (selectedBoard.family === "esp32" || selectedBoard.family === "esp32s3")}
|
||||||
Flash Firmware
|
Flash Firmware
|
||||||
{:else}
|
{:else}
|
||||||
Download Firmware
|
Download Firmware
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selectedBoard.family === "esp32s3"}
|
{#if (selectedBoard.family === "esp32" || selectedBoard.family === "esp32s3")}
|
||||||
<EspFlashFlow board={selectedBoard} release={selectedRelease} />
|
<EspFlashFlow board={selectedBoard} release={selectedRelease} />
|
||||||
{:else}
|
{:else}
|
||||||
<Uf2DownloadFlow board={selectedBoard} release={selectedRelease} />
|
<Uf2DownloadFlow board={selectedBoard} release={selectedRelease} />
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import type { BoardDef } from "./types";
|
import type { BoardDef } from "./types";
|
||||||
|
|
||||||
export const boards: BoardDef[] = [
|
export const boards: BoardDef[] = [
|
||||||
|
{
|
||||||
|
id: "lilygo_tbeam",
|
||||||
|
name: "LilyGo T-Beam (classic)",
|
||||||
|
mcu: "ESP32",
|
||||||
|
radio: "SX1276",
|
||||||
|
family: "esp32",
|
||||||
|
flashMethod: "web-serial",
|
||||||
|
assetPattern: "donglora-lilygo_tbeam-v{version}.bin",
|
||||||
|
notes:
|
||||||
|
"Original T-Beam with ESP32 + SX1276 + SSD1306 OLED + AXP192 PMIC. Flashes over the on-board CP2102 USB-to-UART bridge. Clients connect via serial (BLE planned).",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "elecrow_thinknode_m2",
|
id: "elecrow_thinknode_m2",
|
||||||
name: "ELECROW ThinkNode-M2",
|
name: "ELECROW ThinkNode-M2",
|
||||||
@@ -43,6 +54,17 @@ export const boards: BoardDef[] = [
|
|||||||
flashMethod: "web-serial",
|
flashMethod: "web-serial",
|
||||||
assetPattern: "donglora-heltec_v4-v{version}.bin",
|
assetPattern: "donglora-heltec_v4-v{version}.bin",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "lilygo_tbeam_supreme",
|
||||||
|
name: "LilyGo T-Beam S3 Supreme",
|
||||||
|
mcu: "ESP32-S3",
|
||||||
|
radio: "SX1262",
|
||||||
|
family: "esp32s3",
|
||||||
|
flashMethod: "web-serial",
|
||||||
|
assetPattern: "donglora-lilygo_tbeam_supreme-v{version}.bin",
|
||||||
|
notes:
|
||||||
|
"T-Beam Supreme with ESP32-S3 + SX1262 + SH1106 OLED + AXP2101 PMIC. Flashes over native USB CDC-ACM — no UART bridge.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "rak_wisblock_4631",
|
id: "rak_wisblock_4631",
|
||||||
name: "RAK WisBlock 4631",
|
name: "RAK WisBlock 4631",
|
||||||
|
|||||||
+20
-4
@@ -1,5 +1,7 @@
|
|||||||
import type { FlashProgress } from "./types";
|
import type { FlashProgress } from "./types";
|
||||||
|
|
||||||
|
export type EspChipFamily = "esp32" | "esp32s3";
|
||||||
|
|
||||||
export function isWebSerialSupported(): boolean {
|
export function isWebSerialSupported(): boolean {
|
||||||
return typeof navigator !== "undefined" && "serial" in navigator;
|
return typeof navigator !== "undefined" && "serial" in navigator;
|
||||||
}
|
}
|
||||||
@@ -19,7 +21,20 @@ async function loadEsptool() {
|
|||||||
return { ESPLoader: mod.ESPLoader, Transport: mod.Transport };
|
return { ESPLoader: mod.ESPLoader, Transport: mod.Transport };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function connect(callbacks: FlashCallbacks): Promise<FlashSession> {
|
function chipFamilyLabel(family: EspChipFamily): string {
|
||||||
|
return family === "esp32s3" ? "ESP32-S3" : "ESP32";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isChipCompatible(detected: string, expected: EspChipFamily): boolean {
|
||||||
|
if (expected === "esp32s3") return detected.includes("ESP32-S3");
|
||||||
|
// Classic ESP32: esptool-js reports "ESP32". Exclude S2/S3/C3/C6/H2/P4 variants.
|
||||||
|
return /^ESP32(?![-\s]?(S|C|H|P)\d)/i.test(detected);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function connect(
|
||||||
|
callbacks: FlashCallbacks,
|
||||||
|
expectedChip: EspChipFamily,
|
||||||
|
): Promise<FlashSession> {
|
||||||
if (!isWebSerialSupported()) {
|
if (!isWebSerialSupported()) {
|
||||||
throw new Error("Web Serial API is not supported in this browser. Use Chrome, Edge, or Opera.");
|
throw new Error("Web Serial API is not supported in this browser. Use Chrome, Edge, or Opera.");
|
||||||
}
|
}
|
||||||
@@ -45,16 +60,17 @@ export async function connect(callbacks: FlashCallbacks): Promise<FlashSession>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
callbacks.onLog("Connecting to ESP32...");
|
const expectedLabel = chipFamilyLabel(expectedChip);
|
||||||
|
callbacks.onLog(`Connecting to ${expectedLabel}...`);
|
||||||
callbacks.onProgress({ phase: "Connecting", percent: 0, message: "Detecting chip..." });
|
callbacks.onProgress({ phase: "Connecting", percent: 0, message: "Detecting chip..." });
|
||||||
await loader.main();
|
await loader.main();
|
||||||
|
|
||||||
const chip = loader.chip.CHIP_NAME;
|
const chip = loader.chip.CHIP_NAME;
|
||||||
callbacks.onLog(`Detected: ${chip}`);
|
callbacks.onLog(`Detected: ${chip}`);
|
||||||
|
|
||||||
if (!chip.includes("ESP32-S3")) {
|
if (!isChipCompatible(chip, expectedChip)) {
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
throw new Error(`Expected ESP32-S3 but detected ${chip}. Make sure you selected the correct board.`);
|
throw new Error(`Expected ${expectedLabel} but detected ${chip}. Make sure you selected the correct board.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { transport, loader };
|
return { transport, loader };
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
export type BoardFamily = "esp32s3" | "nrf52840" | "rp2040";
|
export type BoardFamily = "esp32" | "esp32s3" | "nrf52840" | "rp2040";
|
||||||
export type FlashMethod = "web-serial" | "uf2" | "download-only";
|
export type FlashMethod = "web-serial" | "uf2" | "download-only";
|
||||||
|
|
||||||
export interface BoardDef {
|
export interface BoardDef {
|
||||||
|
|||||||
Reference in new issue
Block a user