From 6f06bca60d9a3854cf4b8d377b1842e21a9740d3 Mon Sep 17 00:00:00 2001 From: Jae Gangemi Date: Sun, 19 Apr 2026 16:02:26 -0600 Subject: [PATCH] feat: expose BootloaderFlashOffset on Flasher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The chip Definition struct already tracks BootloaderFlashOffset per target (0x0 for ESP32-S3/C3/C6/H2/C2, 0x1000 for ESP32/S2, 0x2000 for ESP32-C5/P4-Rev1). Expose it through a public accessor so library callers can validate image offsets without duplicating the chip→offset mapping. Returns (0, false) when the chip has not been detected yet, matching the sentinel pattern used by ChipType() (returns ChipAuto) and ChipName() (returns "Unknown"). --- pkg/espflasher/flasher.go | 10 ++++++++++ pkg/espflasher/flasher_test.go | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pkg/espflasher/flasher.go b/pkg/espflasher/flasher.go index 32ea28a..ce61fe3 100644 --- a/pkg/espflasher/flasher.go +++ b/pkg/espflasher/flasher.go @@ -253,6 +253,16 @@ func (f *Flasher) ChipName() string { return "Unknown" } +// BootloaderFlashOffset returns the flash offset where the bootloader image +// lives for the connected chip. Returns (0, false) if the chip has not been +// detected yet (e.g. connect() has not completed). +func (f *Flasher) BootloaderFlashOffset() (uint32, bool) { + if f.chip == nil { + return 0, false + } + return f.chip.BootloaderFlashOffset, true +} + // connect performs the bootloader connection sequence: // reset → sync → detect chip. func (f *Flasher) connect() error { diff --git a/pkg/espflasher/flasher_test.go b/pkg/espflasher/flasher_test.go index 99b9dd0..705482a 100644 --- a/pkg/espflasher/flasher_test.go +++ b/pkg/espflasher/flasher_test.go @@ -219,6 +219,29 @@ func TestFlasherChipName(t *testing.T) { } } +func TestFlasherBootloaderFlashOffset(t *testing.T) { + // ESP32: 0x1000 + f := &Flasher{chip: defESP32, opts: DefaultOptions()} + off, ok := f.BootloaderFlashOffset() + if !ok || off != 0x1000 { + t.Errorf("ESP32 BootloaderFlashOffset() = (0x%X, %v), want (0x1000, true)", off, ok) + } + + // ESP32-S3: 0x0 + f2 := &Flasher{chip: defESP32S3, opts: DefaultOptions()} + off, ok = f2.BootloaderFlashOffset() + if !ok || off != 0x0 { + t.Errorf("ESP32-S3 BootloaderFlashOffset() = (0x%X, %v), want (0x0, true)", off, ok) + } + + // Chip not detected yet: returns (0, false) + f3 := &Flasher{opts: DefaultOptions()} + off, ok = f3.BootloaderFlashOffset() + if ok || off != 0 { + t.Errorf("undetected BootloaderFlashOffset() = (0x%X, %v), want (0x0, false)", off, ok) + } +} + func TestFlashImagePatchesHeader(t *testing.T) { // Verify that FlashImage calls patchImageHeader by checking that an // invalid flash mode causes an error.