diff --git a/Global/Global.c b/Global/Global.c index f56fdd6..967a909 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -101,7 +101,7 @@ int16_t MIC_VOL_MAP[11]= {-9000,-7000,-5000,-3000,-1000,1000,3000,5000,7000,9000 uint8_t TOUCH_AREA_NUM = (sizeof(Touch_Areas)/sizeof(Touch_AreaTypeDef)); -const uint8_t Version[3] = {0,2,9}; /* major.minor.patch — 0.2.9: Finger bass PC=33; HIL harness + tm1617/adc inject hooks */ +const uint8_t Version[3] = {0,2,10}; /* major.minor.patch — 0.2.10: tone 0914 (BIN3 after 2.bin); autoclose label 关闭 */ uint8_t Led = 8; bool PressFlag = 0; diff --git a/UI/UI_global.c b/UI/UI_global.c index a2daf93..8004ed9 100644 --- a/UI/UI_global.c +++ b/UI/UI_global.c @@ -1321,9 +1321,9 @@ void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group) WHITE, c_top, c_bot, value_sz); }else { - /* 手册「不自动」;字库无「不」,界面用稿面「关机」 */ + /* 手册「不自动」;字库无「不」,界面显示「关闭」 */ LCD_ShowChinese_AutoAlign_Gradient(val_x1 + UI0902_TRI_L_W, val_x2 - UI0902_TRI_R_W, text_y, - (const uint8_t*)"\xB9\xD8\xBB\xFA", + (const uint8_t*)"\xB9\xD8\xB1\xD5", LCD_ALIGN_CENTER, WHITE, c_top, c_bot, value_sz); } UI_DrawTriRight((uint16_t)(val_x2 - UI0902_TRI_R_W), chev_cy); diff --git a/project/inc/ExtFlash_Tone_Addr.h b/project/inc/ExtFlash_Tone_Addr.h index 7eeab71..d3b9eb8 100644 --- a/project/inc/ExtFlash_Tone_Addr.h +++ b/project/inc/ExtFlash_Tone_Addr.h @@ -4,10 +4,10 @@ /* Auto-generated by tools/pack_extflash_tone_0903.py — do not hand-edit. */ /* W25Q128 absolute offsets. Boot logo display uses UI0902_BOOT_LOGO_ADDR. */ /* Tone resource pack has no in-bin version field; release tag = EXTFLASH_TONE_RES_VER. */ -#define EXTFLASH_TONE_RES_VER "0903" +#define EXTFLASH_TONE_RES_VER "0914" #define EXTFLASH_TONE_RES_VER_MAJOR 0 #define EXTFLASH_TONE_RES_VER_MINOR 9 -#define EXTFLASH_TONE_RES_VER_PATCH 3 +#define EXTFLASH_TONE_RES_VER_PATCH 14 #define EXTFLASH_LOGO_ADDR 0x00000000UL #define EXTFLASH_LOGO_SIZE 52080UL @@ -18,13 +18,13 @@ #define EXTFLASH_CHARGING_H 190 #define EXTFLASH_BIN1_RHYTHM_ADDR 0x0001B8F0UL -#define EXTFLASH_BIN1_RHYTHM_SIZE 530273UL +#define EXTFLASH_BIN1_RHYTHM_SIZE 509151UL #define EXTFLASH_BIN2_SONG_HAITIAN_ADDR 0x0009D07DUL -#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 41263UL +#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 41914UL -#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A71ACUL -#define EXTFLASH_BIN3_UNIVERSAL_SIZE 31854UL +#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A7437UL +#define EXTFLASH_BIN3_UNIVERSAL_SIZE 33815UL /* Convenience aliases used by UI ADDRESS */ #define FLASH_ADDR_MODE_NORMAL EXTFLASH_BIN1_RHYTHM_ADDR /* 普通 */ @@ -32,11 +32,11 @@ #define FLASH_ADDR_SONG_HAITIAN EXTFLASH_BIN2_SONG_HAITIAN_ADDR #define FLASH_ADDR_MODE_UNIVERSAL EXTFLASH_BIN3_UNIVERSAL_ADDR /* 万能 */ -/* Legacy AutoBand bank — not repacked in 0903; left unchanged in firmware */ +/* Legacy AutoBand bank — not repacked; may overlap 2.bin — do not enable until remapped */ #define FLASH_ADDR_AUTOBAND_LEGACY 0x0009EB5FUL -#define EXTFLASH_TONE_PACK_END 0x000AEE1AUL -#define EXTFLASH_TONE_PACK_SIZE 716314UL +#define EXTFLASH_TONE_PACK_END 0x000AF84EUL +#define EXTFLASH_TONE_PACK_SIZE 718926UL #define UI0902_RES_BASE_SAFE_GAP (0x00100000UL - EXTFLASH_TONE_PACK_END) #endif diff --git a/protocol/git_user_fw_ver.h b/protocol/git_user_fw_ver.h index 24b8b3c..7897a3a 100644 --- a/protocol/git_user_fw_ver.h +++ b/protocol/git_user_fw_ver.h @@ -1,16 +1,16 @@ /* Auto-generated by tools/gen_git_user_fw_ver.py — do not edit. - * git HEAD (dirty): 6da7d4d62737bd294dc42a3265e25b789b33e08c + * git HEAD (dirty): 7fa2f5f1c43ce40fcabb0b847dedd43618ac0875 * branch: develop → develop - * 01 0C wire: develop_6da7d4* + * 01 0C wire: develop_7fa2f5* */ #ifndef GIT_USER_FW_VER_H #define GIT_USER_FW_VER_H -#define GIT_COMMIT_ID_FULL "6da7d4d62737bd294dc42a3265e25b789b33e08c" +#define GIT_COMMIT_ID_FULL "7fa2f5f1c43ce40fcabb0b847dedd43618ac0875" #define GIT_BRANCH_NAME "develop" -#define GIT_COMMIT_SHORT6 "6da7d4" +#define GIT_COMMIT_SHORT6 "7fa2f5" #define GIT_DIRTY (1) -#define GIT_BUILD_ID "develop_6da7d4*" +#define GIT_BUILD_ID "develop_7fa2f5*" #define GIT_BUILD_ID_LEN 15u #endif /* GIT_USER_FW_VER_H */ diff --git a/tools/gen_local_song_names.py b/tools/gen_local_song_names.py index 5e76dbd..19c02f6 100644 --- a/tools/gen_local_song_names.py +++ b/tools/gen_local_song_names.py @@ -17,7 +17,9 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[1] REPO = ROOT.parent.parent -CSV_PATH = REPO / "Doc" / "音色文件" / "0903" / "local_songs.csv" +CSV_PATH = REPO / "Doc" / "音色文件" / "0914" / "local_songs.csv" +if not CSV_PATH.is_file(): + CSV_PATH = REPO / "Doc" / "音色文件" / "0903" / "local_songs.csv" OUT_HDR = ROOT / "project" / "inc" / "LocalSongNames.h" diff --git a/tools/pack_extflash_tone_0903.py b/tools/pack_extflash_tone_0903.py index 255d82c..15e6fc8 100644 --- a/tools/pack_extflash_tone_0903.py +++ b/tools/pack_extflash_tone_0903.py @@ -1,20 +1,19 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Pack external W25Q128 tone/logo image for K1 (0903). +"""Pack external W25Q128 tone/logo image for K1 (0914). -Layout (absolute W25Q128 offsets — BIN2/BIN3 are FIXED so FW addresses stay stable): +Layout (absolute W25Q128 offsets): 0x00000000 logo.bin (legacy pad; boot UI uses UI0902 full-screen logo) - 0x0000CB70 Charg.bin (legacy pad; charge UI uses UI0902_CHARGE_SCREEN full-screen) + 0x0000CB70 Charg.bin (legacy pad; charge UI uses UI0902_CHARGE_SCREEN) 0x0001B8F0 1.bin 普通/专业 31 rhythms - 0x0009D07D 2.bin 本地曲目(变长,尾部 0xFF 填到 BIN3;<=41KB) - 0x000A71AC 3.bin 万能模式(固定;勿随 2.bin 长度漂移) + 0x0009D07D 2.bin 本地曲目(变长,<=41KB) + after 2.bin 3.bin 万能模式(随 2.bin 长度后移;写入 ExtFlash_Tone_Addr.h) Outputs: - tools/out/extflash_tone_0903.bin - tools/out/extflash_tone_0903.res (same bytes, .res alias) - tools/out/extflash_ALL_tone0903_ui0902.res (tone + pad + ui0902, if ui pack present) + tools/out/extflash_tone_0914.bin / .res + tools/out/extflash_ALL_tone0914_ui0902.res project/inc/ExtFlash_Tone_Addr.h - Doc/音色文件/0903/FLASH_MAP.txt + Doc/音色文件/0914/FLASH_MAP.txt """ from __future__ import annotations @@ -26,25 +25,28 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[1] # firmware project root REPO = ROOT.parent.parent # 一诺国际吉他 OUT_DIR = ROOT / "tools" / "out" -OUT_BIN = OUT_DIR / "extflash_tone_0903.bin" -OUT_RES = OUT_DIR / "extflash_tone_0903.res" -OUT_ALL_RES = OUT_DIR / "extflash_ALL_tone0903_ui0902.res" +TONE_TAG = "0914" +OUT_BIN = OUT_DIR / f"extflash_tone_{TONE_TAG}.bin" +OUT_RES = OUT_DIR / f"extflash_tone_{TONE_TAG}.res" +OUT_ALL_RES = OUT_DIR / f"extflash_ALL_tone{TONE_TAG}_ui0902.res" +# Keep legacy alias names for older tools that still look for 0903 +OUT_BIN_LEGACY = OUT_DIR / "extflash_tone_0903.bin" +OUT_RES_LEGACY = OUT_DIR / "extflash_tone_0903.res" +OUT_ALL_LEGACY = OUT_DIR / "extflash_ALL_tone0903_ui0902.res" OUT_HDR = ROOT / "project" / "inc" / "ExtFlash_Tone_Addr.h" -OUT_MAP = REPO / "Doc" / "音色文件" / "0903" / "FLASH_MAP.txt" +OUT_MAP = REPO / "Doc" / "音色文件" / TONE_TAG / "FLASH_MAP.txt" UI0902_BIN = OUT_DIR / "ui0902_res.bin" -TONE_DIR = REPO / "Doc" / "音色文件" / "0903" +TONE_DIR = REPO / "Doc" / "音色文件" / TONE_TAG -# Fixed map — must match project/inc/ExtFlash_Tone_Addr.h consumed by firmware. OFF_LOGO = 0x00000000 OFF_CHARGING = 0x0000CB70 OFF_BIN1 = 0x0001B8F0 OFF_BIN2 = 0x0009D07D -OFF_BIN3 = 0x000A71AC # FIXED: never place 3.bin by concatenating after variable 2.bin +# BIN3 placed immediately after 2.bin (computed at pack time) UI0902_RES_BASE = 0x00100000 DAB_MAGIC = b"\xABDAB" MAX_SONG_BIN_BYTES = 41 * 1024 # 曲目文件(2.bin)硬上限 41KB -BIN2_SLOT_BYTES = OFF_BIN3 - OFF_BIN2 # 41263; must keep BIN3 fixed def find_ziliao() -> Path: @@ -76,28 +78,31 @@ def require_region_equals(blob: bytes, off: int, src: bytes, label: str) -> None def main() -> None: + if not TONE_DIR.is_dir(): + raise SystemExit(f"missing tone dir: {TONE_DIR}") + ziliao = find_ziliao() bin1_path = TONE_DIR / "1.bin" bin2_path = TONE_DIR / "2.bin" bin3_path = TONE_DIR / "3.bin" - parts = [ - ("LOGO", ziliao / "logo.bin", OFF_LOGO, "legacy pad; boot uses UI0902_BOOT_LOGO"), - ("CHARGING", ziliao / "Charg.bin", OFF_CHARGING, "legacy pad; UI uses UI0902_CHARGE_SCREEN"), - ("BIN1_RHYTHM", bin1_path, OFF_BIN1, "普通/专业 31 条节奏"), - ("BIN2_SONG_HAITIAN", bin2_path, OFF_BIN2, "本地曲目"), - ("BIN3_UNIVERSAL", bin3_path, OFF_BIN3, "万能模式(固定偏移)"), - ] + for p in (bin1_path, bin2_path, bin3_path): + if not p.is_file(): + raise SystemExit(f"missing {p}") bin2_data = bin2_path.read_bytes() if len(bin2_data) > MAX_SONG_BIN_BYTES: raise SystemExit( f"2.bin (曲目) too large: {len(bin2_data)} bytes > {MAX_SONG_BIN_BYTES} (41KB)" ) - if len(bin2_data) > BIN2_SLOT_BYTES: - raise SystemExit( - f"2.bin too large for fixed BIN3 slot: {len(bin2_data)} > {BIN2_SLOT_BYTES} " - f"(would shift 3.bin past 0x{OFF_BIN3:X})" - ) + + off_bin3 = OFF_BIN2 + len(bin2_data) + parts = [ + ("LOGO", ziliao / "logo.bin", OFF_LOGO, "legacy pad; boot uses UI0902_BOOT_LOGO"), + ("CHARGING", ziliao / "Charg.bin", OFF_CHARGING, "legacy pad; UI uses UI0902_CHARGE_SCREEN"), + ("BIN1_RHYTHM", bin1_path, OFF_BIN1, "普通/专业 31 条节奏"), + ("BIN2_SONG_HAITIAN", bin2_path, OFF_BIN2, "本地曲目"), + ("BIN3_UNIVERSAL", bin3_path, off_bin3, "万能模式(紧跟 2.bin 之后)"), + ] blobs: list[bytes] = [] cursor = 0 @@ -107,7 +112,7 @@ def main() -> None: if cursor > force_off: raise SystemExit( f"{name}: cursor 0x{cursor:X} past forced 0x{force_off:X} " - f"(previous blob too large; enlarge next fixed gap or shrink prior file)" + f"(previous blob too large)" ) if cursor < force_off: pad = force_off - cursor @@ -122,25 +127,33 @@ def main() -> None: OUT_DIR.mkdir(parents=True, exist_ok=True) packed = b"".join(blobs) OUT_BIN.write_bytes(packed) - OUT_RES.write_bytes(packed) # 总音色 .bin 同步为 .res + OUT_RES.write_bytes(packed) + OUT_BIN_LEGACY.write_bytes(packed) + OUT_RES_LEGACY.write_bytes(packed) by_name = {r[0]: r for r in rows if not r[0].startswith("(")} bin1_data = bin1_path.read_bytes() bin3_data = bin3_path.read_bytes() - # Hard integrity gates dab_ok(packed, OFF_BIN1, expect_cnt=31) dab_ok(packed, OFF_BIN2, expect_cnt=1) - dab_ok(packed, OFF_BIN3, expect_cnt=3) + dab_ok(packed, off_bin3, expect_cnt=3) if by_name["BIN1_RHYTHM"][1] != OFF_BIN1: raise SystemExit(f"BIN1 placed @0x{by_name['BIN1_RHYTHM'][1]:X} want 0x{OFF_BIN1:X}") if by_name["BIN2_SONG_HAITIAN"][1] != OFF_BIN2: raise SystemExit(f"BIN2 placed @0x{by_name['BIN2_SONG_HAITIAN'][1]:X} want 0x{OFF_BIN2:X}") - if by_name["BIN3_UNIVERSAL"][1] != OFF_BIN3: - raise SystemExit(f"BIN3 placed @0x{by_name['BIN3_UNIVERSAL'][1]:X} want 0x{OFF_BIN3:X}") + if by_name["BIN3_UNIVERSAL"][1] != off_bin3: + raise SystemExit(f"BIN3 placed @0x{by_name['BIN3_UNIVERSAL'][1]:X} want 0x{off_bin3:X}") + require_region_equals(packed, OFF_LOGO, (ziliao / "logo.bin").read_bytes(), "LOGO") + require_region_equals(packed, OFF_CHARGING, (ziliao / "Charg.bin").read_bytes(), "CHARGING") require_region_equals(packed, OFF_BIN1, bin1_data, "BIN1/1.bin") require_region_equals(packed, OFF_BIN2, bin2_data, "BIN2/2.bin") - require_region_equals(packed, OFF_BIN3, bin3_data, "BIN3/3.bin") + require_region_equals(packed, off_bin3, bin3_data, "BIN3/3.bin") + + if cursor > UI0902_RES_BASE: + raise SystemExit( + f"ERROR: tone pack end 0x{cursor:X} overflows UI0902 @ 0x{UI0902_RES_BASE:X}" + ) hdr = f"""#ifndef __EXTFLASH_TONE_ADDR_H #define __EXTFLASH_TONE_ADDR_H @@ -148,10 +161,10 @@ def main() -> None: /* Auto-generated by tools/pack_extflash_tone_0903.py — do not hand-edit. */ /* W25Q128 absolute offsets. Boot logo display uses UI0902_BOOT_LOGO_ADDR. */ /* Tone resource pack has no in-bin version field; release tag = EXTFLASH_TONE_RES_VER. */ -#define EXTFLASH_TONE_RES_VER "0903" +#define EXTFLASH_TONE_RES_VER "{TONE_TAG}" #define EXTFLASH_TONE_RES_VER_MAJOR 0 #define EXTFLASH_TONE_RES_VER_MINOR 9 -#define EXTFLASH_TONE_RES_VER_PATCH 3 +#define EXTFLASH_TONE_RES_VER_PATCH 14 #define EXTFLASH_LOGO_ADDR 0x{by_name['LOGO'][1]:08X}UL #define EXTFLASH_LOGO_SIZE {by_name['LOGO'][2]}UL @@ -167,7 +180,7 @@ def main() -> None: #define EXTFLASH_BIN2_SONG_HAITIAN_ADDR 0x{OFF_BIN2:08X}UL #define EXTFLASH_BIN2_SONG_HAITIAN_SIZE {by_name['BIN2_SONG_HAITIAN'][2]}UL -#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x{OFF_BIN3:08X}UL +#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x{off_bin3:08X}UL #define EXTFLASH_BIN3_UNIVERSAL_SIZE {by_name['BIN3_UNIVERSAL'][2]}UL /* Convenience aliases used by UI ADDRESS */ @@ -176,7 +189,7 @@ def main() -> None: #define FLASH_ADDR_SONG_HAITIAN EXTFLASH_BIN2_SONG_HAITIAN_ADDR #define FLASH_ADDR_MODE_UNIVERSAL EXTFLASH_BIN3_UNIVERSAL_ADDR /* 万能 */ -/* Legacy AutoBand bank — not repacked in 0903; left unchanged in firmware */ +/* Legacy AutoBand bank — not repacked; may overlap 2.bin — do not enable until remapped */ #define FLASH_ADDR_AUTOBAND_LEGACY 0x0009EB5FUL #define EXTFLASH_TONE_PACK_END 0x{cursor:08X}UL @@ -188,12 +201,13 @@ def main() -> None: OUT_HDR.write_text(hdr, encoding="utf-8", newline="\n") map_lines = [ - "K1 external Flash map — tone pack 0903", + f"K1 external Flash map — tone pack {TONE_TAG}", f"Packed file: Code/.../tools/out/{OUT_BIN.name} ({len(packed)} bytes)", f"Also: {OUT_RES.name}; ALL.res when ui0902_res.bin present", - f"Ends at 0x{cursor:X}; UI0902_RES_BASE=0x00100000; free gap={0x100000 - cursor} bytes", + f"Ends at 0x{cursor:X}; UI0902_RES_BASE=0x00100000; free gap={UI0902_RES_BASE - cursor} bytes", "", - "NOTE: BIN3 is FIXED at 0x000A71AC. 2.bin must be <= 41KB and <= slot 41263 bytes.", + f"NOTE: BIN3 follows 2.bin @ 0x{off_bin3:X} (2.bin grew past old fixed 0xA71AC).", + " 2.bin must be <= 41KB; LOGO/CHARG/BIN1/BIN2 offsets remain fixed.", "", f"{'Name':<22} {'Offset':>10} {'Size':>10} Note", "-" * 72, @@ -205,17 +219,16 @@ def main() -> None: "Firmware ADDRESS mapping:", " 普通/专业 -> FLASH_ADDR_MODE_NORMAL/EXPERT (1.bin @ 0x1B8F0)", " 本地曲目 -> FLASH_ADDR_SONG_HAITIAN (2.bin @ 0x9D07D, max 41KB)", - " 万能 -> FLASH_ADDR_MODE_UNIVERSAL (3.bin @ 0xA71AC FIXED)", - " AutoBand -> FLASH_ADDR_AUTOBAND_LEGACY 0x9EB5F (unchanged; overlaps 2.bin region — do not enable until remapped)", + f" 万能 -> FLASH_ADDR_MODE_UNIVERSAL (3.bin @ 0x{off_bin3:X})", " Boot logo -> UI0902_BOOT_LOGO_ADDR (full-screen); packed logo.bin only pads 0x0..0xCB70", - " Charging -> EXTFLASH_CHARGING_ADDR", + " Charging -> EXTFLASH_CHARGING_ADDR (legacy pad) / UI0902_CHARGE_SCREEN", "", - "Add a local song:", - " 1. Pack the new preset into 2.bin (must stay <= 41KB / 41263 slot)", - " 2. Append a row to local_songs.csv (index,code,name)", - " 3. python tools/pack_extflash_tone_0903.py (also regenerates LocalSongNames.h)", - " 4. Rebuild firmware and flash MCU + ExtFlash ALL.res", + "Rebuild after pack:", + " 1. python tools/pack_extflash_tone_0903.py", + " 2. Rebuild MCU (ExtFlash_Tone_Addr.h updated)", + " 3. Flash MCU + ExtFlash ALL.res", ] + OUT_MAP.parent.mkdir(parents=True, exist_ok=True) OUT_MAP.write_text("\n".join(map_lines) + "\n", encoding="utf-8", newline="\n") print(f"Wrote {OUT_BIN} ({len(packed)} bytes)") @@ -224,32 +237,42 @@ def main() -> None: print(f"Wrote {OUT_MAP}") for name, off, size, note in rows: print(f" 0x{off:08X} {size:8d} {name} {note}") - if cursor > UI0902_RES_BASE: - raise SystemExit("ERROR: pack overflows into UI0902_RES_BASE") print(f"OK: {UI0902_RES_BASE - cursor} bytes free before UI0902 @ 0x{UI0902_RES_BASE:X}") - print("OK: BIN1/BIN2/BIN3 present at fixed addresses and match source files") - print(f"OK: 2.bin size {len(bin2_data)} <= 41KB ({MAX_SONG_BIN_BYTES})") + print("OK: LOGO/CHARG/BIN1/BIN2/BIN3 present and match source files") + print(f"OK: 2.bin size {len(bin2_data)} <= 41KB; BIN3 @ 0x{off_bin3:X}") if UI0902_BIN.is_file(): ui = UI0902_BIN.read_bytes() all_res = packed + (b"\xFF" * (UI0902_RES_BASE - len(packed))) + ui require_region_equals(all_res, OFF_BIN1, bin1_data, "ALL.res BIN1") require_region_equals(all_res, OFF_BIN2, bin2_data, "ALL.res BIN2") - require_region_equals(all_res, OFF_BIN3, bin3_data, "ALL.res BIN3") + require_region_equals(all_res, off_bin3, bin3_data, "ALL.res BIN3") dab_ok(all_res, OFF_BIN1, 31) dab_ok(all_res, OFF_BIN2, 1) - dab_ok(all_res, OFF_BIN3, 3) + dab_ok(all_res, off_bin3, 3) + # UI0902 magic/presence: non-empty and starts within expected region + if len(ui) < 1024: + raise SystemExit(f"UI0902 pack suspiciously small: {len(ui)}") OUT_ALL_RES.write_bytes(all_res) - # Mirror under repo tools/out for publish/consumers + OUT_ALL_LEGACY.write_bytes(all_res) repo_out = REPO / "tools" / "out" repo_out.mkdir(parents=True, exist_ok=True) (repo_out / OUT_ALL_RES.name).write_bytes(all_res) + (repo_out / OUT_ALL_LEGACY.name).write_bytes(all_res) (repo_out / OUT_RES.name).write_bytes(packed) - print(f"Wrote {OUT_ALL_RES} ({len(all_res)} bytes) — verified 1/2/3.bin") + (repo_out / OUT_RES_LEGACY.name).write_bytes(packed) + print(f"Wrote {OUT_ALL_RES} ({len(all_res)} bytes) — verified logo/charg/1/2/3 + UI0902") else: print(f"WARN: {UI0902_BIN} missing; skipped ALL.res") + # Prefer 0914 CSV; fall back to 0903 + csv_0914 = TONE_DIR / "local_songs.csv" gen = ROOT / "tools" / "gen_local_song_names.py" + if not csv_0914.is_file(): + src = REPO / "Doc" / "音色文件" / "0903" / "local_songs.csv" + if src.is_file(): + csv_0914.write_bytes(src.read_bytes()) + print(f"Copied {src.name} -> {csv_0914}") r = subprocess.run([sys.executable, str(gen)], check=False) if r.returncode != 0: raise SystemExit(f"gen_local_song_names.py failed ({r.returncode})") diff --git a/tools/publish_k1_release.py b/tools/publish_k1_release.py index 1233919..d5c684a 100644 --- a/tools/publish_k1_release.py +++ b/tools/publish_k1_release.py @@ -11,6 +11,7 @@ Boot must also be updated so USB IAP wait screen can show UI0902_FLASH_MODE. from __future__ import annotations import hashlib +import re import shutil import subprocess import zipfile @@ -29,14 +30,15 @@ BOOT_BIN = ( / "Exe" / "AT32F403ARCT7_BOOT.bin" ) -TONE_BIN = PROJ / "tools" / "out" / "extflash_tone_0903.bin" +TONE_RES_VER = "0914" +TONE_BIN = PROJ / "tools" / "out" / f"extflash_tone_{TONE_RES_VER}.bin" UI0902_BIN = PROJ / "tools" / "out" / "ui0902_res.bin" -MAP_TXT = REPO / "Doc" / "音色文件" / "0903" / "FLASH_MAP.txt" +MAP_TXT = REPO / "Doc" / "音色文件" / TONE_RES_VER / "FLASH_MAP.txt" +TONE_HDR = PROJ / "project" / "inc" / "ExtFlash_Tone_Addr.h" IAP_DIR = REPO / "升级" / "MCU主控升级" OUT_ROOT = REPO / "tools" / "out" -FW_VER = "0.2.9" -TONE_RES_VER = "0903" +FW_VER = "0.2.10" UI0902_RES_BASE = 0x00100000 BOOT_FLASH_ADDR = 0x08000000 APP_FLASH_ADDR = 0x08008000 @@ -69,31 +71,63 @@ def build_combined_extflash(tone: bytes, ui: bytes) -> bytes: return tone + (b"\xFF" * pad) + ui -def verify_tone_layout(tone: bytes, check_sources: bool = True) -> None: - """Refuse to ship ALL.res if 1/2/3.bin missing, shifted, or content mismatch.""" - dab = b"\xABDAB" - sources = { - "BIN1": (0x0001B8F0, 31, REPO / "Doc" / "音色文件" / "0903" / "1.bin"), - "BIN2": (0x0009D07D, 1, REPO / "Doc" / "音色文件" / "0903" / "2.bin"), - "BIN3": (0x000A71AC, 3, REPO / "Doc" / "音色文件" / "0903" / "3.bin"), +def read_tone_addrs() -> dict[str, int]: + text = TONE_HDR.read_text(encoding="utf-8", errors="replace") + def grab(name: str) -> int: + m = re.search(rf"#define\s+{name}\s+0x([0-9A-Fa-f]+)UL", text) + if not m: + raise SystemExit(f"missing {name} in {TONE_HDR}") + return int(m.group(1), 16) + return { + "LOGO": grab("EXTFLASH_LOGO_ADDR"), + "CHARGING": grab("EXTFLASH_CHARGING_ADDR"), + "BIN1": grab("EXTFLASH_BIN1_RHYTHM_ADDR"), + "BIN2": grab("EXTFLASH_BIN2_SONG_HAITIAN_ADDR"), + "BIN3": grab("EXTFLASH_BIN3_UNIVERSAL_ADDR"), } - for name, (off, want_cnt, src_path) in sources.items(): + + +def verify_tone_layout(tone: bytes, check_sources: bool = True) -> None: + """Refuse to ship ALL.res if logo/charg/1/2/3.bin missing, shifted, or mismatch.""" + dab = b"\xABDAB" + addrs = read_tone_addrs() + tone_dir = REPO / "Doc" / "音色文件" / TONE_RES_VER + ziliao = None + for p in REPO.iterdir(): + if p.is_dir() and (p / "logo.bin").is_file() and (p / "Charg.bin").is_file(): + ziliao = p + break + if ziliao is None: + raise SystemExit("logo.bin/Charg.bin not found under repo") + + sources = [ + ("LOGO", addrs["LOGO"], None, ziliao / "logo.bin"), + ("CHARGING", addrs["CHARGING"], None, ziliao / "Charg.bin"), + ("BIN1", addrs["BIN1"], 31, tone_dir / "1.bin"), + ("BIN2", addrs["BIN2"], 1, tone_dir / "2.bin"), + ("BIN3", addrs["BIN3"], 3, tone_dir / "3.bin"), + ] + for name, off, want_cnt, src_path in sources: if off + 16 > len(tone): raise SystemExit(f"verify {name}: tone pack too short for 0x{off:X}") - magic = tone[off : off + 4] - cnt = int.from_bytes(tone[off + 12 : off + 16], "little") - if magic != dab or cnt != want_cnt: - raise SystemExit( - f"verify {name} @0x{off:X} failed: magic={magic.hex()} cnt={cnt} " - f"(want ABDAB/{want_cnt}). Re-run pack_extflash_tone_0903.py." - ) + if want_cnt is not None: + magic = tone[off : off + 4] + cnt = int.from_bytes(tone[off + 12 : off + 16], "little") + if magic != dab or cnt != want_cnt: + raise SystemExit( + f"verify {name} @0x{off:X} failed: magic={magic.hex()} cnt={cnt} " + f"(want ABDAB/{want_cnt}). Re-run pack_extflash_tone_0903.py." + ) if check_sources and src_path.is_file(): src = src_path.read_bytes() if name == "BIN2" and len(src) > 41 * 1024: raise SystemExit(f"verify BIN2: source 2.bin {len(src)} > 41KB") if tone[off : off + len(src)] != src: raise SystemExit(f"verify {name}: content @0x{off:X} != {src_path}") - print("verify tone layout: BIN1/BIN2/BIN3 addresses + content OK") + print( + "verify tone layout: LOGO/CHARG/BIN1/BIN2/BIN3 OK " + f"(BIN3@0x{addrs['BIN3']:X})" + ) def main() -> None: @@ -102,9 +136,17 @@ def main() -> None: if not EXE_BIN.is_file(): raise SystemExit(f"missing MCU bin: {EXE_BIN}") if not TONE_BIN.is_file(): - raise SystemExit(f"missing tone pack: {TONE_BIN} (run pack_extflash_tone_0903.py)") + # fallback legacy alias written by packer + legacy = PROJ / "tools" / "out" / "extflash_tone_0903.bin" + if legacy.is_file(): + global TONE_BIN + TONE_BIN = legacy + else: + raise SystemExit(f"missing tone pack: {TONE_BIN} (run pack_extflash_tone_0903.py)") if not UI0902_BIN.is_file(): raise SystemExit(f"missing UI0902 pack: {UI0902_BIN} (run gen_ui0902_assets.py)") + if not TONE_HDR.is_file(): + raise SystemExit(f"missing {TONE_HDR}") iap = IAP_DIR / "SoundWalkerIAP.exe" guide = IAP_DIR / "升级步骤.docx" @@ -126,12 +168,15 @@ def main() -> None: tone_data = TONE_BIN.read_bytes() verify_tone_layout(tone_data) ui_data = UI0902_BIN.read_bytes() + if len(ui_data) < 1024: + raise SystemExit(f"UI0902 pack too small: {len(ui_data)}") combined = build_combined_extflash(tone_data, ui_data) - verify_tone_layout(combined) # same offsets in ALL.res + verify_tone_layout(combined) + addrs = read_tone_addrs() boot_name = f"AT32F403ARCT7_BOOT_v{FW_VER}_{stamp}.bin" mcu_name = f"YNGJ-GT1-M_MCU_v{FW_VER}_{stamp}.bin" - comb_name = f"extflash_ALL_tone0903_ui0902_{stamp}.res" + comb_name = f"extflash_ALL_tone{TONE_RES_VER}_ui0902_{stamp}.res" boot_dst = pkg / boot_name mcu_dst = pkg / mcu_name @@ -147,9 +192,8 @@ def main() -> None: shutil.copy2(boot_dst, OUT_ROOT / boot_name) shutil.copy2(mcu_dst, OUT_ROOT / mcu_name) - shutil.copy2(comb_dst, OUT_ROOT / "extflash_ALL_tone0903_ui0902.res") - # Keep build intermediates under tools/out for local rebuilds; not shipped in package. - (OUT_ROOT / "extflash_tone_0903.res").write_bytes(tone_data) + shutil.copy2(comb_dst, OUT_ROOT / f"extflash_ALL_tone{TONE_RES_VER}_ui0902.res") + (OUT_ROOT / f"extflash_tone_{TONE_RES_VER}.res").write_bytes(tone_data) (OUT_ROOT / "extflash_ui0902.res").write_bytes(ui_data) readme = pkg / "README.txt" @@ -176,7 +220,8 @@ def main() -> None: "", "外部 Flash 分区:", " 0x00000000 音色/充电图 (toneRes)", - " logo pad + Charg@0xCB70 + 1.bin@0x1B8F0 + 2.bin@0x9D07D + 3.bin@0xA71AC(FIXED)", + f" logo@0x{addrs['LOGO']:X} + Charg@0x{addrs['CHARGING']:X} + " + f"1.bin@0x{addrs['BIN1']:X} + 2.bin@0x{addrs['BIN2']:X} + 3.bin@0x{addrs['BIN3']:X}", " 0x00100000 UI0902 图片 (模式选择、开机 Logo、充电、烧录模式、设置/调音台等)", " 0x001D2000 UI0902_FLASH_MODE 烧录模式全屏图(Boot 读取)", "", @@ -189,9 +234,8 @@ def main() -> None: "", "说明:", " - Boot 进入 USB IAP 时显示 UI0902_FLASH_MODE;资源未烧录时白字黑底兜底。", - " - 烧录模式图来源:K1标准界面图 0904/烧录模式.png。", " - 开机全屏 Logo、关机充电全屏画面在 UI0902,不在音色包里的 logo.bin/Charg.bin 占位。", - " - AutoBand 0x9EB5F 本版未重排。", + f" - 本包音色来源 Doc/音色文件/{TONE_RES_VER}/;BIN3 随 2.bin 长度后移。", "", "附件: SoundWalkerIAP.exe / 升级步骤.docx / FLASH_MAP.txt", "",