using System.IO;
using System.Text.Json;
namespace FirmwareFlasher;
/// 빌트인 모델 프로파일 + 폴더 flash.json 로더 + 앱 파일명 자동매칭.
public static class ProfileStore
{
static readonly JsonSerializerOptions JsonOpts = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
};
static FwRegion Boot(string off) => new() { File = "bootloader.bin", Offset = off, Kind = "bootloader" };
static FwRegion Part() => new() { File = "partition-table.bin", Offset = "0x10000", Kind = "support" };
static FwRegion Ota() => new() { File = "ota_data_initial.bin", Offset = "0x11000", Kind = "support" };
static FwRegion Www() => new() { File = "www_fs.bin", Offset = "0x420000", Kind = "support" };
static FwRegion AppAt(string off = "0x20000") => new() { App = true, Offset = off, Kind = "app" };
public static List BuiltIns() => new()
{
new FlashProfile
{
Name = "DB720 (ESP32-P4)", Chip = "esp32p4", Baud = 115200, NoStub = true, PerRegion = true,
ConnectAttempts = 30, FlashSize = "16MB", FlashMode = "dio", FlashFreq = "80m",
AppOnlyErasesOtadata = true,
Regions = { Boot("0x2000"), Part(), Ota(), Www(), AppAt() },
FlashPortHint = "303A:1001", ConsolePortHint = "10C4:EA60",
DownloadModeHint = "USB-JTAG 케이블 연결. 포트가 안 잡히면 케이블만 다시 꽂으면 됩니다(자동 감지).",
Notes = "secure_release · db250513 서명. 영역별 개별 호출(SDM). 부트로더(0x2000)는 이미 구워진 보드면 거부될 수 있음(정상 → 표준/앱만 사용).",
},
new FlashProfile
{
Name = "DB402S (ESP32-S3)", Chip = "esp32s3", Baud = 921600,
Regions = { Boot("0x0000"), Part(), Ota(), AppAt() },
ConsolePortHint = "10C4:EA60",
DownloadModeHint = "TTL(COM2) 연결. SW1 누른 상태에서 SW2 눌렀다 떼고 SW1 떼면 다운로드 모드 진입.",
Notes = "esp32-s3. 부트로더 offset 0x0000(중요). 스텁 921600 · 한 번에 기록. secure 보드는 부트로더(<0x8000) 거부 → --force 또는 앱만.",
},
new FlashProfile
{
Name = "DB400S (ESP32)", Chip = "esp32", Baud = 921600,
Regions = { Boot("0x1000"), Part(), Ota(), AppAt() },
ConsolePortHint = "10C4:EA60",
DownloadModeHint = "TTL(COM2) 연결. SW1 누른 상태에서 SW2 눌렀다 떼고 SW1 떼면 다운로드 모드 진입.",
Notes = "esp32 클래식. 부트로더 0x1000. 스텁 921600 · 한 번에. secure 보드는 부트로더(<0x8000) 거부 → --force 또는 앱만.",
},
new FlashProfile
{
Name = "DB400Q (ESP32)", Chip = "esp32", Baud = 921600,
Regions = { Boot("0x1000"), Part(), Ota(), AppAt() },
ConsolePortHint = "10C4:EA60",
DownloadModeHint = "TTL(COM2) 연결. SW1 누른 상태에서 SW2 눌렀다 떼고 SW1 떼면 다운로드 모드 진입.",
Notes = "esp32 클래식. DB400S와 동일 방식.",
},
new FlashProfile
{
Name = "DB300eM (ESP32)", Chip = "esp32", Baud = 921600,
Regions = { Boot("0x1000"), Part(), Ota(), AppAt() },
ConsolePortHint = "10C4:EA60",
DownloadModeHint = "TTL(COM2) 연결. JP1 점퍼핀 단락 후 전원 재인가하면 다운로드 모드 진입.",
Notes = "esp32 클래식. JP1 점퍼로 다운로드 진입. web OTA(IP 입력)도 가능.",
},
};
/// 폴더의 flash.json 을 읽는다(없으면 null).
public static FlashProfile? LoadFromFolder(string folder)
{
try
{
var p = Path.Combine(folder, "flash.json");
if (!File.Exists(p)) return null;
var prof = JsonSerializer.Deserialize(File.ReadAllText(p), JsonOpts);
if (prof is not null) prof.FromFile = true;
return prof;
}
catch { return null; }
}
/// 앱 bin 파일명(DIBD720…, DIBD402S… 등)으로 빌트인 프로파일을 추정.
public static FlashProfile? MatchByApp(IEnumerable appFileNames, List profiles)
{
// 더 구체적인 토큰을 먼저 (402S 가 400 보다, 400S 가 400 보다 우선)
(string token, string profileTag)[] map =
{
("402S", "DB402S"), ("400S", "DB400S"), ("400Q", "DB400Q"),
("300", "DB300"), ("720", "DB720"),
};
foreach (var name in appFileNames)
{
var up = name.ToUpperInvariant();
foreach (var (token, tag) in map)
if (up.Contains(token))
{
var hit = profiles.FirstOrDefault(p => p.Name.ToUpperInvariant().Contains(tag));
if (hit is not null) return hit;
}
}
return null;
}
}