diff --git a/APP/app_log.c b/APP/app_log.c index d9af5ba..4f1e2eb 100644 --- a/APP/app_log.c +++ b/APP/app_log.c @@ -14,13 +14,15 @@ static char s_debug_level = 'D'; static char s_cmd_buf[48]; static uint8_t s_cmd_len; -/* RTT 二进制烧录:将 ui0902_res.bin 写到 W25Q128 @ UI0902_RES_BASE */ +/* RTT 二进制烧录:写到 W25Q128(ui0902 或本地曲目) */ static uint8_t s_flash_mode; +static uint32_t s_flash_base; static uint32_t s_flash_addr; static uint32_t s_flash_remain; static uint32_t s_flash_last_sector; static uint16_t s_flash_page_len; static uint8_t s_flash_page[256]; +static char s_flash_ok_tag[24]; uint8_t app_log_flash_busy(void) { @@ -61,7 +63,7 @@ static void app_log_flash_feed(const uint8_t *data, unsigned len) unsigned i; for (i = 0; i < len && s_flash_remain > 0U; i++) { - if (s_flash_page_len == 0U && s_flash_addr == UI0902_RES_BASE && i == 0U) { + if (s_flash_page_len == 0U && s_flash_addr == s_flash_base && i == 0U) { SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_RX\n"); } s_flash_page[s_flash_page_len++] = data[i]; @@ -73,34 +75,42 @@ static void app_log_flash_feed(const uint8_t *data, unsigned len) if (s_flash_remain == 0U && s_flash_mode) { s_flash_mode = 0U; - SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_OK\n"); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, s_flash_ok_tag); UI_DrawModeSelectScreen(); } } -static void app_log_flash_start(uint32_t size) +static void app_log_flash_start_at(uint32_t base, uint32_t size, const char *go_tag, const char *ok_tag) { - char msg[64]; + char msg[80]; if (size == 0U || size > (2U * 1024U * 1024U)) { - SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_ERR size\n"); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERR size\n"); return; } s_flash_mode = 1U; - s_flash_addr = UI0902_RES_BASE; + s_flash_base = base; + s_flash_addr = base; s_flash_remain = size; s_flash_last_sector = 0xFFFFFFFFUL; s_flash_page_len = 0U; s_cmd_len = 0U; s_cmd_buf[0] = '\0'; + strncpy(s_flash_ok_tag, ok_tag, sizeof(s_flash_ok_tag) - 1U); + s_flash_ok_tag[sizeof(s_flash_ok_tag) - 1U] = '\0'; snprintf(msg, sizeof(msg), - "FLASH_UI0902_GO base=0x%08lX size=%lu\n", - (unsigned long)UI0902_RES_BASE, (unsigned long)size); + "%s base=0x%08lX size=%lu\n", + go_tag, (unsigned long)base, (unsigned long)size); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, msg); } +static void app_log_flash_start(uint32_t size) +{ + app_log_flash_start_at(UI0902_RES_BASE, size, "FLASH_UI0902_GO", "FLASH_UI0902_OK\n"); +} + static void app_log_slot_store(const char *line) { uint16_t idx = s_head; @@ -264,6 +274,106 @@ uint8_t app_log_try_command(const char *cmd) app_log_flash_start(size); return 1U; } + if (strncmp(cmd, "flash haitian ", 14) == 0) { + uint32_t size = (uint32_t)strtoul(cmd + 14, NULL, 10); + app_log_flash_start_at(FLASH_ADDR_SONG_HAITIAN, size, + "FLASH_HAITIAN_GO", "FLASH_HAITIAN_OK\n"); + return 1U; + } + if (strncmp(cmd, "tone status", 11) == 0) { + uint8_t hdr[16]; + uint8_t name[40]; + uint8_t cur_hdr[16]; + char *pname; + char line[192]; + const char *map; + W25Q128_Read(hdr, FLASH_ADDR_SONG_HAITIAN, 16); + W25Q128_Read(name, FLASH_ADDR_SONG_HAITIAN + 1280 + 4, 32); + name[32] = 0; + W25Q128_Read(cur_hdr, (uint32_t)ADDRESS, 16); + pname = AutoBandTop1_GetPresetName(); + if (ADDRESS == EXTFLASH_BIN1_RHYTHM_ADDR) + map = "BIN1_RHYTHM"; + else if (ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) + map = "BIN2_SONG_HAITIAN"; + else if (ADDRESS == EXTFLASH_BIN3_UNIVERSAL_ADDR) + map = "BIN3_UNIVERSAL"; + else + map = "UNKNOWN"; + snprintf(line, sizeof(line), + "TONE tab=%u sw=%u addr=0x%08lX map=%s songidx=%u rhyt=%u\n", + (unsigned)mGuiData[GUI_TAB_INDEX].Current, + (unsigned)mGuiData[GUI_AUTOBAND_SW].Current, + (unsigned long)ADDRESS, map, + (unsigned)ParamGuiData[EXPRESS_MODE_PARAM].Current, + (unsigned)ParamGuiData[SONG_MODE_PARAM].Current); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + snprintf(line, sizeof(line), + "TONE map BIN1=0x%08lX BIN2=0x%08lX BIN3=0x%08lX\n", + (unsigned long)EXTFLASH_BIN1_RHYTHM_ADDR, + (unsigned long)EXTFLASH_BIN2_SONG_HAITIAN_ADDR, + (unsigned long)EXTFLASH_BIN3_UNIVERSAL_ADDR); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + snprintf(line, sizeof(line), + "TONE @ADDRESS magic=%02X%02X%02X%02X cnt=%lu\n", + cur_hdr[0], cur_hdr[1], cur_hdr[2], cur_hdr[3], + (unsigned long)(cur_hdr[12] | (cur_hdr[13] << 8) | + (cur_hdr[14] << 16) | (cur_hdr[15] << 24))); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + snprintf(line, sizeof(line), + "TONE @BIN2 magic=%02X%02X%02X%02X max=%lu cnt=%lu name=%.16s\n", + hdr[0], hdr[1], hdr[2], hdr[3], + (unsigned long)(hdr[8] | (hdr[9] << 8) | (hdr[10] << 16) | (hdr[11] << 24)), + (unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)), + (char *)name); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + snprintf(line, sizeof(line), + "TONE loaded name=%s count=%d\n", + pname ? pname : "(null)", + AutoBandTop1_GetPresetItemCount()); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + return 1U; + } + if (strncmp(cmd, "tone reload", 11) == 0) { + char line[96]; + UI_ReloadTonePreset(); + snprintf(line, sizeof(line), + "TONE_RELOAD addr=0x%08lX name=%s\n", + (unsigned long)ADDRESS, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)"); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + return 1U; + } + if (strncmp(cmd, "tone local", 10) == 0) { + char line[128]; + int ret; + mGuiData[GUI_TAB_INDEX].Current = 1; /* 专业 */ + mGuiData[GUI_AUTOBAND_SW].Current = 1; /* 本地曲目 */ + ParamGuiData[EXPRESS_MODE_PARAM].Current = 0; + UI_ApplyToneAddress(); + AutoBandTop1_Stop(); + StartFlag = 0; + ret = AutoBandTop1_LoadPresetItemFromFlash(0); + snprintf(line, sizeof(line), + "TONE_LOCAL ret=%d addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n", + ret, (unsigned long)ADDRESS, + (unsigned long)EXTFLASH_BIN2_SONG_HAITIAN_ADDR, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)", + AutoBandTop1_GetPresetItemCount(), + (ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) ? "OK" : "MISMATCH"); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); + return 1U; + } + if (strncmp(cmd, "tone pick", 9) == 0) { + /* 模拟专业+本地曲目拨片(无和弦板) */ + mGuiData[GUI_TAB_INDEX].Current = 1; + mGuiData[GUI_AUTOBAND_SW].Current = 1; + KEY_ID_1629 = 0; /* 走默认和弦兜底 */ + StartFlag = 0; + Pick_Handle(); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_PICK_DONE\n"); + return 1U; + } if (strncmp(cmd, "flash erase chip", 16) == 0) { SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_BEGIN\n"); LOG_I("FLASH", "W25Q128 chip erase start"); diff --git a/Global/Global.c b/Global/Global.c index 133cfdb..fef79ed 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,2}; /* major.minor.patch — 0.2.2: BT persist, settings icon focus, auto-off UI */ +const uint8_t Version[3] = {0,2,3}; /* major.minor.patch — 0.2.3: local song HKTK load/play + tone addr logs */ uint8_t Led = 8; bool PressFlag = 0; @@ -775,21 +775,48 @@ void Pick_Handle() break; case 2: - if(StartFlag == 0) //当播放了之后,拨片不再起作用 + /* 普通:节奏/本地曲目均用 StartWithNote;切库后允许再次拨片起奏 */ + if (StartFlag == 0 || mGuiData[GUI_AUTOBAND_SW].Current) { StartFlag = 1; + AutoBandTop1_Stop(); AutoBandTop1_SetLoopMode(0,1); + AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current); + /* 起调必须用 0x3C+移调;勿用和弦音区 MIDI(如 48),否则本地曲目起奏异常 */ midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current; AutoBandTop1_StartWithNote(midi); AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt); + if (mGuiData[GUI_AUTOBAND_SW].Current) + LOG_I("pick", "local/normal root=%u name=%s", midi, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?"); } break; case 1: StartFlag = 1; - AutoBandTop1_SetPiecePlayMode(1,0,1920); - AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt); - AutoBandTop1_SetLoopMode(0,1); + if (mGuiData[GUI_AUTOBAND_SW].Current) + { + /* 本地曲目:与普通模式同一套起奏(0x3C 根音 + 和弦音) */ + AutoBandTop1_Stop(); + AutoBandTop1_SetLoopMode(0,1); + AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current); + midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current; + AutoBandTop1_StartWithNote(midi); + AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt); + LOG_I("pick", "local/expert root=%u name=%s sw=%u tab=%u", + midi, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)mGuiData[GUI_AUTOBAND_SW].Current, + (unsigned)mGuiData[GUI_TAB_INDEX].Current); + } + else + { + AutoBandTop1_SetPiecePlayMode(1,0,1920); + AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt); + AutoBandTop1_SetLoopMode(0,1); + LOG_I("pick", "expert/rhythm piece name=%s", + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?"); + } break; case 0: StartFlag = 1; diff --git a/MyCode/App_Auto.c b/MyCode/App_Auto.c index 619e76a..492beb0 100644 --- a/MyCode/App_Auto.c +++ b/MyCode/App_Auto.c @@ -13,7 +13,7 @@ #include #include "includes.h" MidiFifoSeq_t m_MidiSendFifo; -#define PRESET_BUFFER_SIZE (1024*40) +#define PRESET_BUFFER_SIZE (1024*41) /* 2s.res compressed HKTK preset 39760 bytes */ static int m_presetCount = 0; static uint8_t pStoreBuffer[PRESET_BUFFER_SIZE]; //static uint8_t* pStoreBuffer; @@ -76,9 +76,60 @@ static void Func_CallBack_PitchWheel(int channel,int cc,int value) mymidififo_InQueue(&m_MidiSendFifo,&midimsg); } +/* Flash Map 0903:对照 ExtFlash_Tone_Addr.h / Doc/.../FLASH_MAP.txt */ +static const char *ToneFlashMapBank(uint32_t abs) +{ + if (abs >= EXTFLASH_BIN1_RHYTHM_ADDR && + abs < EXTFLASH_BIN1_RHYTHM_ADDR + EXTFLASH_BIN1_RHYTHM_SIZE) + return "BIN1_RHYTHM"; + if (abs >= EXTFLASH_BIN2_SONG_HAITIAN_ADDR && + abs < EXTFLASH_BIN2_SONG_HAITIAN_ADDR + EXTFLASH_BIN2_SONG_HAITIAN_SIZE) + return "BIN2_SONG_HAITIAN"; + if (abs >= EXTFLASH_BIN3_UNIVERSAL_ADDR && + abs < EXTFLASH_BIN3_UNIVERSAL_ADDR + EXTFLASH_BIN3_UNIVERSAL_SIZE) + return "BIN3_UNIVERSAL"; + if (abs >= FLASH_ADDR_AUTOBAND_LEGACY && + abs < FLASH_ADDR_AUTOBAND_LEGACY + 0x10000UL) + return "LEGACY_AUTOBAND"; + return "OUT_OF_MAP"; +} + +static uint32_t s_flash_rd_last_base = 0xFFFFFFFFu; +static uint16_t s_flash_rd_log_cnt = 0; + static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput) { - W25Q128_Read(pOutput, (uint32_t)ADDRESS+address, length); + uint32_t base = (uint32_t)ADDRESS; + uint32_t abs = base + (uint32_t)address; + const char *bank; + + if (base != s_flash_rd_last_base) { + s_flash_rd_last_base = base; + s_flash_rd_log_cnt = 0; + LOG_I("FLASH_RD", "bank base=0x%08X map=%s (BIN1=0x%08X BIN2=0x%08X BIN3=0x%08X)", + (unsigned)base, + ToneFlashMapBank(base), + (unsigned)EXTFLASH_BIN1_RHYTHM_ADDR, + (unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR, + (unsigned)EXTFLASH_BIN3_UNIVERSAL_ADDR); + } + + bank = ToneFlashMapBank(abs); + /* 加载阶段打印前若干次 + 每次 offset==0;避免播放期刷屏 */ + if (s_flash_rd_log_cnt < 16u || address == 0) { + LOG_I("FLASH_RD", "abs=0x%08X off=%d len=%d map=%s", + (unsigned)abs, address, length, bank); + if (s_flash_rd_log_cnt < 0xFFFFu) + s_flash_rd_log_cnt++; + if (s_flash_rd_log_cnt == 16u) + LOG_I("FLASH_RD", "further reads omitted (same base)"); + } else if (bank[0] == 'O') { + /* 读到 Map 外:始终告警 */ + LOG_W("FLASH_RD", "OUT_OF_MAP abs=0x%08X off=%d len=%d base=0x%08X", + (unsigned)abs, address, length, (unsigned)base); + } + + W25Q128_Read(pOutput, abs, length); return 0; } // @@ -97,11 +148,14 @@ void App_Auto_Init(void) int ret = AutoBandTop1_LoadPresetItemFromFlash(0); if (ret != 0) { - LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X", - ret, (unsigned)ADDRESS); + LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s", + ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS)); } else { + LOG_I("AUTO", "LoadPreset ok name=%s addr=0x%08X map=%s", + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS)); AutoBandTop1_ChangeBPM(mGuiData[1].Current); } } diff --git a/UI/UI_SongMode.c b/UI/UI_SongMode.c index 6ba6527..c17efb4 100644 --- a/UI/UI_SongMode.c +++ b/UI/UI_SongMode.c @@ -178,12 +178,21 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value) show_Param(&UI_Label[GUI_MODE_PARAM], pCurData); UI_ApplyToneAddress(); + int ret = 0; if (tab == 0) - AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); + ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); else if (mGuiData[GUI_AUTOBAND_SW].Current) - AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current); + ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current); else - AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); + ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); + if (ret != 0) + LOG_E("tone", "load preset failed tab=%d sw=%d ret=%d addr=0x%08X", + tab, mGuiData[GUI_AUTOBAND_SW].Current, ret, (unsigned)ADDRESS); + else + LOG_I("tone", "load preset ok tab=%d sw=%d name=%s addr=0x%08X", + tab, mGuiData[GUI_AUTOBAND_SW].Current, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)ADDRESS); if (tab == 0) nvm->param.Param3 = ParamGuiData[ALL_MODE_PARAM].Current; @@ -216,7 +225,11 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value) /* 万能无节奏/本地 TAB,忽略该触控 */ if (mGuiData[GUI_TAB_INDEX].Current == 0) return; + if (mGuiData[ID].Current == value) + return; mGuiData[ID].Current = value; + StartFlag = 0; + AutoBandTop1_Stop(); UI_ReloadTonePreset(); if (!UI_SetFocus(GUI_MODE_PARAM)) label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM],&mGuiData[GUI_MODE_PARAM]); diff --git a/UI/UI_global.c b/UI/UI_global.c index d0a02c1..623d694 100644 --- a/UI/UI_global.c +++ b/UI/UI_global.c @@ -112,36 +112,66 @@ void CallUI_RestoreSelect(void) { /* 音师:万能→3.bin;普通/专业:节奏→1.bin、本地曲目→2.bin */ void UI_ApplyToneAddress(void) { + uint32_t expect = 0; + const char *map_name = "?"; + switch (mGuiData[GUI_TAB_INDEX].Current) { case 0: /* 万能:和弦走向库 */ ADDRESS = FLASH_ADDR_MODE_UNIVERSAL; - return; + expect = EXTFLASH_BIN3_UNIVERSAL_ADDR; + map_name = "BIN3_UNIVERSAL"; + break; case 1: /* 专业 */ - if (mGuiData[GUI_AUTOBAND_SW].Current) + if (mGuiData[GUI_AUTOBAND_SW].Current) { ADDRESS = FLASH_ADDR_SONG_HAITIAN; - else + expect = EXTFLASH_BIN2_SONG_HAITIAN_ADDR; + map_name = "BIN2_SONG_HAITIAN"; + } else { ADDRESS = FLASH_ADDR_MODE_EXPERT; - return; + expect = EXTFLASH_BIN1_RHYTHM_ADDR; + map_name = "BIN1_RHYTHM"; + } + break; case 2: /* 普通 */ - if (mGuiData[GUI_AUTOBAND_SW].Current) + if (mGuiData[GUI_AUTOBAND_SW].Current) { ADDRESS = FLASH_ADDR_SONG_HAITIAN; - else + expect = EXTFLASH_BIN2_SONG_HAITIAN_ADDR; + map_name = "BIN2_SONG_HAITIAN"; + } else { ADDRESS = FLASH_ADDR_MODE_NORMAL; - return; + expect = EXTFLASH_BIN1_RHYTHM_ADDR; + map_name = "BIN1_RHYTHM"; + } + break; default: ADDRESS = FLASH_ADDR_MODE_UNIVERSAL; - return; + expect = EXTFLASH_BIN3_UNIVERSAL_ADDR; + map_name = "BIN3_UNIVERSAL"; + break; } + + LOG_I("tone", "ADDRESS=0x%08X map=%s expect=0x%08X tab=%u sw=%u %s", + (unsigned)ADDRESS, map_name, (unsigned)expect, + (unsigned)mGuiData[GUI_TAB_INDEX].Current, + (unsigned)mGuiData[GUI_AUTOBAND_SW].Current, + (ADDRESS == expect) ? "OK" : "MISMATCH"); } void UI_ReloadTonePreset(void) { UI_ApplyToneAddress(); + /* 换库前先停,避免播放中改 relocate 指针 */ + AutoBandTop1_Stop(); + StartFlag = 0; /* 万能:和弦走向 */ if (mGuiData[GUI_TAB_INDEX].Current == 0) { - AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); + int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); + LOG_I("tone", "load universal idx=%d ret=%d name=%s addr=0x%08X map=BIN3@0x%08X", + ParamGuiData[ALL_MODE_PARAM].Current, ret, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)ADDRESS, (unsigned)EXTFLASH_BIN3_UNIVERSAL_ADDR); return; } /* 普通/专业:本地曲目或节奏类型 */ @@ -151,7 +181,18 @@ void UI_ReloadTonePreset(void) local->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0; if (local->Current > local->Max) local->Current = local->Max; - AutoBandTop1_LoadPresetItemFromFlash(local->Current); + int ret = AutoBandTop1_LoadPresetItemFromFlash(local->Current); + if (ret != 0) + LOG_E("tone", "load local song idx=%d failed ret=%d addr=0x%08X map=BIN2@0x%08X", + local->Current, ret, (unsigned)ADDRESS, + (unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR); + else + LOG_I("tone", "local song idx=%d name=%s addr=0x%08X map=BIN2@0x%08X %s", + local->Current, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)ADDRESS, + (unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR, + (ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) ? "OK" : "MISMATCH"); { int bin_n = AutoBandTop1_GetPresetItemCount(); if (bin_n != LOCAL_SONG_COUNT) @@ -159,7 +200,16 @@ void UI_ReloadTonePreset(void) } return; } - AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); + { + int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); + LOG_I("tone", "load rhythm idx=%d ret=%d name=%s addr=0x%08X map=BIN1@0x%08X %s", + ParamGuiData[SONG_MODE_PARAM].Current, ret, + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)ADDRESS, + (unsigned)EXTFLASH_BIN1_RHYTHM_ADDR, + (ADDRESS == EXTFLASH_BIN1_RHYTHM_ADDR) ? "OK" : "MISMATCH"); + (void)ret; + } } static uint8_t s_ui_focus_id = UI_FOCUS_NONE; diff --git a/project/inc/ExtFlash_Tone_Addr.h b/project/inc/ExtFlash_Tone_Addr.h index 188cc71..cd3050c 100644 --- a/project/inc/ExtFlash_Tone_Addr.h +++ b/project/inc/ExtFlash_Tone_Addr.h @@ -21,9 +21,9 @@ #define EXTFLASH_BIN1_RHYTHM_SIZE 530317UL #define EXTFLASH_BIN2_SONG_HAITIAN_ADDR 0x0009D07DUL -#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 46474UL +#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 41040UL -#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A8607UL +#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A70CDUL #define EXTFLASH_BIN3_UNIVERSAL_SIZE 31854UL /* Convenience aliases used by UI ADDRESS */ @@ -35,8 +35,8 @@ /* Legacy AutoBand bank — not repacked in 0903; left unchanged in firmware */ #define FLASH_ADDR_AUTOBAND_LEGACY 0x0009EB5FUL -#define EXTFLASH_TONE_PACK_END 0x000B0275UL -#define EXTFLASH_TONE_PACK_SIZE 721525UL +#define EXTFLASH_TONE_PACK_END 0x000AED3BUL +#define EXTFLASH_TONE_PACK_SIZE 716091UL #define UI0902_RES_BASE_SAFE_GAP (0x00100000UL - EXTFLASH_TONE_PACK_END) #endif diff --git a/rt-thread/bsp/_template/board.c b/rt-thread/bsp/_template/board.c index 46cf0d7..539bf48 100644 --- a/rt-thread/bsp/_template/board.c +++ b/rt-thread/bsp/_template/board.c @@ -17,7 +17,7 @@ * Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP * the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes */ -#define RT_HEAP_SIZE (20*1024) +#define RT_HEAP_SIZE (19*1024) /* 20KB-1KB to fit 41KB preset buffer in 96KB RAM */ static rt_uint8_t rt_heap[RT_HEAP_SIZE]; RT_WEAK void *rt_heap_begin_get(void) diff --git a/tools/_do_flash_mcu_now.py b/tools/_do_flash_mcu_now.py new file mode 100644 index 0000000..1e23c4b --- /dev/null +++ b/tools/_do_flash_mcu_now.py @@ -0,0 +1,60 @@ +import subprocess, shutil, os, time + +base = os.path.join(r"C:\Users\qjyu\Documents\SoundWalker", "一诺国际吉他", + r"Code\YNGJ-GT1-M - AT32F403ARCT7") +stage = r"C:\Temp\k1flash" +os.makedirs(stage, exist_ok=True) + +out_src = os.path.join(base, r"project\IAR_V7.4\YNGJ-GT1-M\Exe\YNGJ-GT1-M.out") +out_dst = os.path.join(stage, "YNGJ-GT1-M.out") +with open(out_src, "rb") as a, open(out_dst, "wb") as b: + shutil.copyfileobj(a, b) +print("copied", os.path.getsize(out_dst), flush=True) + +gen_src = os.path.join(base, r"project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.general.xcl") +drv_src = os.path.join(base, r"project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.driver.xcl") +lines = open(gen_src, encoding="utf-8", errors="replace").read().splitlines() +new = [] +for ln in lines: + new.append(f'"{out_dst}" ' if (".out" in ln and "YNGJ" in ln) else ln) +open(os.path.join(stage, "general.xcl"), "w", encoding="utf-8", newline="\n").write("\n".join(new) + "\n") +shutil.copy2(drv_src, os.path.join(stage, "driver.xcl")) + +for n in ("cspybat.exe", "CSpyBat.exe", "JLink.exe", "IarIdePm.exe", + "JLinkGUIServer.exe", "JLinkRTTClient.exe", "JFlash.exe"): + subprocess.run(["taskkill", "/F", "/IM", n], capture_output=True) +time.sleep(1.5) + +# Force Artery AT32F403ACx (RCT7) — avoid Cortex-M4 / wrong-chip popup +drv_path = os.path.join(stage, "driver.xcl") +drv_lines = open(drv_path, encoding="utf-8", errors="replace").read().splitlines() +forced = [] +for ln in drv_lines: + if ln.strip().startswith("--jlink_device"): + continue + forced.append(ln) +forced.append('--jlink_device=AT32F403AC') +open(drv_path, "w", encoding="utf-8", newline="\n").write("\n".join(forced) + "\n") +print("driver device forced: AT32F403AC", flush=True) + +cspy = r"C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.3\common\bin\cspybat.exe" +cmd = [cspy, "-f", os.path.join(stage, "general.xcl"), + f"--debug_file={out_dst}", "--download_only", "--backend", + "-f", drv_path] +logp = os.path.join(stage, "cspy.log") +print("cspybat start (AT32F403AC / FlashAT32F403ARCT7)", flush=True) +with open(logp, "w", encoding="utf-8", errors="replace") as log: + r = subprocess.run(cmd, stdout=log, stderr=subprocess.STDOUT, timeout=180) +print("cspy exit", r.returncode, flush=True) +print(open(logp, encoding="utf-8", errors="replace").read()[-2000:]) +if r.returncode != 0: + raise SystemExit(r.returncode) + +jlink = r"C:\Program Files\SEGGER\JLink_V818\JLink.exe" +reset = os.path.join(base, r"tools\reset_run.jlink") +print("reset AT32F403AC", flush=True) +subprocess.run([jlink, "-Device", "AT32F403AC", "-If", "SWD", + "-Speed", "4000", "-AutoConnect", "1", + "-CommandFile", reset], capture_output=True, timeout=30) +time.sleep(3) +print("Done", flush=True) diff --git a/tools/assets_0902/05_设置图标/0907/HUB_ICON_SIZES.txt b/tools/assets_0902/05_设置图标/0907/HUB_ICON_SIZES.txt new file mode 100644 index 0000000..9c64720 --- /dev/null +++ b/tools/assets_0902/05_设置图标/0907/HUB_ICON_SIZES.txt @@ -0,0 +1,2 @@ +gImage_mixer 34x33 +gImage_SystemSetting 33x33 diff --git a/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-13.png b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-13.png new file mode 100644 index 0000000..bcaaf5a Binary files /dev/null and b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-13.png differ diff --git a/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-14.png b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-14.png new file mode 100644 index 0000000..1934b03 Binary files /dev/null and b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-14.png differ diff --git a/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-15.png b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-15.png new file mode 100644 index 0000000..fad2847 Binary files /dev/null and b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-15.png differ diff --git a/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-16.png b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-16.png new file mode 100644 index 0000000..4e074ec Binary files /dev/null and b/tools/assets_0902/05_设置图标/0907/K1 触摸屏界面 0902-16.png differ diff --git a/tools/assets_0902/09_烧录模式/烧录模式-240x320.png b/tools/assets_0902/09_烧录模式/烧录模式-240x320.png new file mode 100644 index 0000000..f2f91da Binary files /dev/null and b/tools/assets_0902/09_烧录模式/烧录模式-240x320.png differ diff --git a/tools/flash_haitian_res.py b/tools/flash_haitian_res.py new file mode 100644 index 0000000..eabb329 --- /dev/null +++ b/tools/flash_haitian_res.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +"""Flash Doc/音色文件/0907/2.res (or --bin) to W25Q128 @ FLASH_ADDR_SONG_HAITIAN via RTT.""" + +from __future__ import annotations + +import argparse +import os +import sys +import time + +DEFAULT_DEVICES = ("Cortex-M4", "AT32F403AC", "AT32F403A") +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +REPO = os.path.dirname(os.path.dirname(ROOT)) +DEFAULT_BIN = os.path.join(REPO, "Doc", "音色文件", "0907", "2.res") +FLASH_ADDR_SONG_HAITIAN = 0x0009D07D + + +def connect_jlink(device: str): + import pylink + + jlink = pylink.JLink() + jlink.open() + try: + jlink.exec_command("HideDeviceSelection = 1") + except Exception: + pass + jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) + + last_error = None + for candidate in (device, *DEFAULT_DEVICES): + try: + try: + jlink.exec_command(f"Device = {candidate}") + except Exception: + pass + jlink.connect(candidate) + print(f"Connected as {candidate}") + return jlink + except Exception as exc: + last_error = exc + jlink.close() + raise SystemExit(f"Failed to connect J-Link: {last_error}") + + +def find_rtt_control_block(jlink, ram_base: int = 0x20000000, ram_size: int = 0x18000): + needle = b"SEGGER RTT" + chunk = 0x1000 + was_halted = jlink.halted() + if not was_halted: + jlink.halt() + try: + for off in range(0, ram_size, chunk): + data = bytes(jlink.memory_read8(ram_base + off, min(chunk, ram_size - off))) + idx = data.find(needle) + if idx >= 0: + return ram_base + off + idx + finally: + if not was_halted: + if hasattr(jlink, "restart"): + jlink.restart() + else: + jlink.go() + time.sleep(0.1) + return None + + +def rtt_read_text(jlink, timeout_s: float = 0.2) -> str: + deadline = time.time() + timeout_s + chunks: list[bytes] = [] + while time.time() < deadline: + try: + data = bytes(jlink.rtt_read(0, 512) or []) + except Exception: + data = b"" + if data: + chunks.append(data) + deadline = time.time() + timeout_s + else: + time.sleep(0.02) + return b"".join(chunks).decode("ascii", errors="replace") + + +def wait_for(jlink, marker: str, timeout_s: float = 30.0) -> str: + deadline = time.time() + timeout_s + buf = "" + while time.time() < deadline: + buf += rtt_read_text(jlink, 0.15) + if marker in buf: + return buf + raise SystemExit(f"Timeout waiting for {marker!r}\n--- RTT ---\n{buf[-800:]}") + + +def send_bytes(jlink, payload: bytes) -> None: + off = 0 + while off < len(payload): + try: + n = jlink.rtt_write(0, list(payload[off : off + 64])) + except Exception: + time.sleep(0.05) + continue + if n is None or n <= 0: + time.sleep(0.02) + continue + off += n + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--bin", default=DEFAULT_BIN) + parser.add_argument("--device", default="Cortex-M4") + parser.add_argument("--no-reset", action="store_true") + args = parser.parse_args() + + if not os.path.isfile(args.bin): + raise SystemExit(f"missing bin: {args.bin}") + + data = open(args.bin, "rb").read() + size = len(data) + print(f"bin={args.bin} size={size} addr=0x{FLASH_ADDR_SONG_HAITIAN:08X}") + + jlink = connect_jlink(args.device) + try: + cb = find_rtt_control_block(jlink) + if cb is None: + raise SystemExit("RTT control block not found") + print(f"RTT CB @ 0x{cb:08X}") + jlink.rtt_start(cb) + time.sleep(0.3) + _ = rtt_read_text(jlink, 0.3) + + if not args.no_reset: + print("hardware reset...") + jlink.reset(halt=False) + time.sleep(3.5) + try: + jlink.rtt_stop() + except Exception: + pass + cb = find_rtt_control_block(jlink) + if cb is None: + raise SystemExit("RTT CB missing after reset") + print(f"RTT CB @ 0x{cb:08X}") + jlink.rtt_start(cb) + time.sleep(0.5) + _ = rtt_read_text(jlink, 0.5) + + cmd = f"flash haitian {size}\n".encode("ascii") + send_bytes(jlink, cmd) + print("sent flash command, waiting GO...") + log = wait_for(jlink, "FLASH_HAITIAN_GO", 20.0) + print(log.strip().splitlines()[-1]) + time.sleep(0.2) + + chunk = 256 + sent = 0 + t0 = time.time() + receiving = False + while sent < size: + end = min(sent + chunk, size) + send_bytes(jlink, data[sent:end]) + sent = end + log = wait_for(jlink, "FLASH_ACK", 60.0) + if (not receiving) and ("FLASH_RX" in log or "FLASH_ACK" in log): + receiving = True + print("device receiving...") + if "FLASH_HAITIAN_OK" in log: + print(log.strip().splitlines()[-1]) + print("Done. Local song bank updated.") + return + if sent % (4 * 1024) == 0 or sent == size: + elapsed = time.time() - t0 + print(f" {sent}/{size} ({100.0 * sent / size:.1f}%) {elapsed:.1f}s") + + log = wait_for(jlink, "FLASH_HAITIAN_OK", 60.0) + print(log.strip().splitlines()[-1]) + print("Done. Local song bank updated.") + finally: + try: + jlink.rtt_stop() + except Exception: + pass + jlink.close() + + +if __name__ == "__main__": + main() diff --git a/tools/publish_k1_release.py b/tools/publish_k1_release.py index cc65347..951d071 100644 --- a/tools/publish_k1_release.py +++ b/tools/publish_k1_release.py @@ -25,7 +25,7 @@ MAP_TXT = REPO / "Doc" / "音色文件" / "0903" / "FLASH_MAP.txt" IAP_DIR = REPO / "升级" / "MCU主控升级" OUT_ROOT = REPO / "tools" / "out" -FW_VER = "0.2.2" +FW_VER = "0.2.3" TONE_RES_VER = "0903" UI0902_RES_BASE = 0x00100000 @@ -126,8 +126,8 @@ def main() -> None: "", "外部 Flash 分区:", " 0x00000000 音色/充电图 (toneRes)", - " logo pad + Charg@0xCB70 + 1.bin@0x1B8F0 + 2.bin + 3.bin", - " 0x00100000 UI0902 图片 (模式选择大图、全屏开机 Logo、设置/调音台素材等)", + " logo pad + Charg@0xCB70 + 1.bin@0x1B8F0 + 2.bin(HKTK/2s) + 3.bin", + " 0x00100000 UI0902 图片 (模式选择、开机 Logo、充电、烧录模式、设置/调音台等)", "", f" {comb_name} size={comb_dst.stat().st_size} @ 0x00000000", f" sha256={sha256(comb_dst)}", diff --git a/tools/reset_run.jlink b/tools/reset_run.jlink index 07516df..5b2177f 100644 --- a/tools/reset_run.jlink +++ b/tools/reset_run.jlink @@ -1,3 +1,4 @@ +HideDeviceSelection 1 si SWD speed 4000 device Cortex-M4