From 953ebc40caf85ea66e32f250de07857a5c1f67eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Henrique=20Guard=C3=A3o=20Gandarez?= Date: Thu, 12 Mar 2026 11:35:46 -0300 Subject: [PATCH] Add support for esp32-c6-lcd-1.47 by Waveshare --- README.md | 1 + pkg/espflasher/flasher.go | 1 + pkg/espflasher/flasher_test.go | 153 +++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) diff --git a/README.md b/README.md index de78816..4cc5cdc 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ A Go command-line tool and library for flashing firmware to Espressif ESP8266 an - ESP32-C2 (ESP8684) - ESP32-C3 - ESP32-C6 +- ESP32-C6-LCD-1.47 by Waveshare - ESP32-H2 ## CLI Tool diff --git a/pkg/espflasher/flasher.go b/pkg/espflasher/flasher.go index f9107e3..0eec6fa 100644 --- a/pkg/espflasher/flasher.go +++ b/pkg/espflasher/flasher.go @@ -260,6 +260,7 @@ func (f *Flasher) detectChip() (*chipDef, error) { {0x6F51306F, defESP32C2}, // ESP32-C2 {0x1B31506F, defESP32C3}, // ESP32-C3 {0x0DA1806F, defESP32C6}, // ESP32-C6 + {0x2CE0806F, defESP32C6}, // ESP32-C6-LCD-1.47 by Waveshare {0xD7B73E80, defESP32H2}, // ESP32-H2 {0x09, defESP32S3}, // ESP32-S3 returns chip_id } diff --git a/pkg/espflasher/flasher_test.go b/pkg/espflasher/flasher_test.go index 24ad4d7..af7b3ec 100644 --- a/pkg/espflasher/flasher_test.go +++ b/pkg/espflasher/flasher_test.go @@ -2,6 +2,8 @@ package espflasher import ( "bytes" + "encoding/binary" + "errors" "fmt" "testing" ) @@ -256,6 +258,157 @@ func TestDetectFlashSizeNilChip(t *testing.T) { } } +// makeReadRegResponse creates a SLIP-encoded response for a readReg command +// that returns the given 32-bit value. +func makeReadRegResponse(value uint32) []byte { + resp := make([]byte, 10) + resp[0] = respDirectionResp + resp[1] = cmdReadReg + binary.LittleEndian.PutUint16(resp[2:4], 2) // data len = 2 (status bytes) + binary.LittleEndian.PutUint32(resp[4:8], value) + resp[8] = 0x00 // status OK + resp[9] = 0x00 // error 0 + return slipEncode(resp) +} + +func TestDetectChipOlderChipsByMagic(t *testing.T) { + tests := []struct { + name string + magic uint32 + wantChip ChipType + }{ + {"ESP8266", 0xFFF0C101, ChipESP8266}, + {"ESP32", 0x00F01D83, ChipESP32}, + {"ESP32-S2", 0x000007C6, ChipESP32S2}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + respData := makeReadRegResponse(tt.magic) + mock := &mockPort{ + readFunc: func(p []byte) (int, error) { + n := copy(p, respData) + respData = respData[n:] + return n, nil + }, + } + c := &conn{ + port: mock, + reader: newSlipReader(mock), + } + f := &Flasher{ + opts: DefaultOptions(), + conn: c, + } + + def, err := f.detectChip() + if err != nil { + t.Fatalf("detectChip() error: %v", err) + } + if def.ChipType != tt.wantChip { + t.Errorf("detectChip() = %v, want %v", def.ChipType, tt.wantChip) + } + }) + } +} + +func TestDetectChipNewerChipsByMagic(t *testing.T) { + tests := []struct { + name string + magic uint32 + wantChip ChipType + }{ + {"ESP32-C2", 0x6F51306F, ChipESP32C2}, + {"ESP32-C3", 0x1B31506F, ChipESP32C3}, + {"ESP32-C6", 0x0DA1806F, ChipESP32C6}, + {"ESP32-C6-Waveshare", 0x2CE0806F, ChipESP32C6}, + {"ESP32-H2", 0xD7B73E80, ChipESP32H2}, + {"ESP32-S3", 0x09, ChipESP32S3}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + respData := makeReadRegResponse(tt.magic) + mock := &mockPort{ + readFunc: func(p []byte) (int, error) { + n := copy(p, respData) + respData = respData[n:] + return n, nil + }, + } + c := &conn{ + port: mock, + reader: newSlipReader(mock), + } + f := &Flasher{ + opts: DefaultOptions(), + conn: c, + } + + def, err := f.detectChip() + if err != nil { + t.Fatalf("detectChip() error: %v", err) + } + if def.ChipType != tt.wantChip { + t.Errorf("detectChip() = %v, want %v", def.ChipType, tt.wantChip) + } + }) + } +} + +func TestDetectChipUnknownMagic(t *testing.T) { + respData := makeReadRegResponse(0xDEADBEEF) + mock := &mockPort{ + readFunc: func(p []byte) (int, error) { + n := copy(p, respData) + respData = respData[n:] + return n, nil + }, + } + c := &conn{ + port: mock, + reader: newSlipReader(mock), + } + f := &Flasher{ + opts: DefaultOptions(), + conn: c, + } + + _, err := f.detectChip() + if err == nil { + t.Fatal("detectChip() should return error for unknown magic") + } + + var chipErr *ChipDetectError + if !errors.As(err, &chipErr) { + t.Fatalf("expected ChipDetectError, got %T: %v", err, err) + } + if chipErr.MagicValue != 0xDEADBEEF { + t.Errorf("ChipDetectError.MagicValue = 0x%08X, want 0xDEADBEEF", chipErr.MagicValue) + } +} + +func TestDetectChipReadRegError(t *testing.T) { + mock := &mockPort{ + readFunc: func(p []byte) (int, error) { + return 0, errors.New("serial port disconnected") + }, + } + c := &conn{ + port: mock, + reader: newSlipReader(mock), + } + f := &Flasher{ + opts: DefaultOptions(), + conn: c, + } + + _, err := f.detectChip() + if err == nil { + t.Fatal("detectChip() should return error when readReg fails") + } +} + func TestFlashSizeFromJEDECMatchesChipSizes(t *testing.T) { // Verify that all JEDEC-detected sizes are present in at least one chip's // FlashSizes map.