Fix teacher accomp issues and add ExtFlash chip-erase helper.
Pick fires on downstroke; #IV drops an octave; local songs use 2.bin; transpose updates notes without restart; intro starts on key I; boot string volume/PC corrected. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c724ddd2c9
commit
f179a46c5d
|
|
@ -125,6 +125,8 @@ static void app_adc_pick_process(void)
|
|||
{
|
||||
pick_hold_tick = now;
|
||||
pick_fsm = PICK_FSM_STATE_DOWN;
|
||||
/* 音师:拨片下拨即响(进入 DOWN 触发),不要等复位 */
|
||||
MainTask_Sendmsg(MSG_ID_BP_KEY,PICK_STATE_DOWN,0,0);
|
||||
}
|
||||
if(curstate == PICK_STATE_UP)
|
||||
{
|
||||
|
|
@ -136,8 +138,6 @@ static void app_adc_pick_process(void)
|
|||
if(curstate != PICK_STATE_DOWN)
|
||||
{
|
||||
pick_fsm = PICK_FSM_STATE_IDLE;
|
||||
//发送下拨消息
|
||||
MainTask_Sendmsg(MSG_ID_BP_KEY,PICK_STATE_DOWN,0,0);
|
||||
}
|
||||
break;
|
||||
case PICK_FSM_STATE_UP:
|
||||
|
|
|
|||
|
|
@ -264,6 +264,14 @@ uint8_t app_log_try_command(const char *cmd)
|
|||
app_log_flash_start(size);
|
||||
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");
|
||||
W25Q128_Erase_Chip();
|
||||
LOG_I("FLASH", "W25Q128 chip erase done");
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_OK\n");
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "ui boot", 7) == 0) {
|
||||
LCD_BLK_Set();
|
||||
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
|
||||
|
|
|
|||
118
Global/Global.c
118
Global/Global.c
|
|
@ -25,8 +25,8 @@ GUI_SWITCH mGuiData[] = {
|
|||
};
|
||||
GUI_SWITCH ParamGuiData[] =
|
||||
{
|
||||
{ 0, 0, 30, SONG_MODE_PARAM}, // 0
|
||||
{ 0, 0, 30, EXPRESS_MODE_PARAM}, // 1
|
||||
{ 0, 0, 30, SONG_MODE_PARAM}, // 0 节奏类型(1.bin,约 31 首)
|
||||
{ 0, 0, 0, EXPRESS_MODE_PARAM}, // 1 本地曲目(2.bin,先 1 首可扩)
|
||||
{ 0, 0, 2, ALL_MODE_PARAM}, // 2
|
||||
};
|
||||
|
||||
|
|
@ -360,28 +360,49 @@ void Send_volume(uint8_t vol)
|
|||
SendMidiDataToDreamDSP(mMasterSysExVolume,12);
|
||||
}
|
||||
|
||||
void Accomp_UpdatePlayingChord(void)
|
||||
{
|
||||
uint8_t midi_note_buff[4] = {0,};
|
||||
uint8_t note_cnt = 0;
|
||||
uint8_t i;
|
||||
|
||||
if (!StartFlag)
|
||||
return;
|
||||
if (KEY_ID_1629 == 0 || KEY_ID_1629 == 22 || KEY_ID_1629 == 23)
|
||||
return;
|
||||
|
||||
note_cnt = GetChordNotesByType(KEY_ID_1629,
|
||||
chord_type_index_map[KEY_ID_1629].type,
|
||||
midi_note_buff);
|
||||
for (i = 0; i < note_cnt; i++)
|
||||
AutoBandTop1_Note_On(midi_note_buff[i], 0x50);
|
||||
}
|
||||
|
||||
void ADC_IN1_KEY_Handle(uint8_t key,bool on)
|
||||
{
|
||||
uint8_t midi_note_buff[4] = {0,};
|
||||
uint8_t note_cnt = 0;
|
||||
uint8_t is_preamble = 0;
|
||||
key_toggle[key] = !key_toggle[key];
|
||||
if(key_toggle[key] == 1)
|
||||
{
|
||||
//ResetAutoPowerCount();
|
||||
switch(key)
|
||||
{
|
||||
case 3: AutoBandTop1_Preamble(0); break;
|
||||
case 0: AutoBandTop1_Preamble(1); break;
|
||||
case 1: AutoBandTop1_Postamble(0); break;
|
||||
case 2: AutoBandTop1_Postamble(1); break;
|
||||
case 3: AutoBandTop1_Preamble(0); is_preamble = 1; break;
|
||||
case 0: AutoBandTop1_Preamble(1); is_preamble = 1; break;
|
||||
case 1: AutoBandTop1_Postamble(0); break;
|
||||
case 2: AutoBandTop1_Postamble(1); break;
|
||||
}
|
||||
//AutoBandTop1_Start();
|
||||
AutoBandTop1_SyncStart();
|
||||
wk_delay_ms(50);
|
||||
//AutoBandTop1_Note_On(USE_MIDI.Midi_5, 0x50);
|
||||
//AutoBandTop1_SetPiecePlayMode(1,0,1920);
|
||||
//AutoBandTop1_StartWithNotes(midi_note_buff,GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff));
|
||||
//AutoBandTop1_SetLoopMode(0,1);
|
||||
/* 音师:前奏起始 = 当前调一级和弦第一把位(index 1 + maj,再经移调) */
|
||||
if (is_preamble)
|
||||
{
|
||||
KEY_ID_1629 = 1;
|
||||
chord_type_index_map[1].type = 0;
|
||||
}
|
||||
note_cnt = GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff);
|
||||
for(uint8_t i = 0;i < note_cnt;i++)
|
||||
{
|
||||
|
|
@ -880,6 +901,11 @@ void BT_Chord_offset_map(uint8_t pos_offset,uint8_t chord_offset)
|
|||
|
||||
uint8_t GetChordNotesByType(uint8_t MIDI_Index,uint8_t type,uint8_t *buff)
|
||||
{
|
||||
uint8_t n = 0;
|
||||
uint8_t i;
|
||||
uint8_t root;
|
||||
|
||||
buff[0] = buff[1] = buff[2] = buff[3] = 0;
|
||||
switch(MIDI_Index)
|
||||
{
|
||||
case 1:case 2:case 3:
|
||||
|
|
@ -1109,49 +1135,41 @@ uint8_t GetChordNotesByType(uint8_t MIDI_Index,uint8_t type,uint8_t *buff)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if(buff[3]!= 0)
|
||||
|
||||
n = (buff[3] != 0) ? 4 : 3;
|
||||
switch (chord_type_index_map[MIDI_Index].PitchOffset)
|
||||
{
|
||||
switch(chord_type_index_map[MIDI_Index].PitchOffset)
|
||||
{
|
||||
case 1:
|
||||
buff[0] += 0;
|
||||
buff[1] += 0;
|
||||
buff[2] += 0;
|
||||
buff[3] += 0;
|
||||
break;
|
||||
case 2:
|
||||
buff[0] += 1;
|
||||
buff[1] += 1;
|
||||
buff[2] += 1;
|
||||
buff[3] += 1;
|
||||
break;
|
||||
}
|
||||
buff[0] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
buff[1] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
buff[2] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
buff[3] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
return 4;
|
||||
}else
|
||||
{
|
||||
switch(chord_type_index_map[MIDI_Index].PitchOffset)
|
||||
{
|
||||
case 1:
|
||||
buff[0] += 0;
|
||||
buff[1] += 0;
|
||||
buff[2] += 0;
|
||||
break;
|
||||
case 2:
|
||||
buff[0] += 1;
|
||||
buff[1] += 1;
|
||||
buff[2] += 1;
|
||||
break;
|
||||
}
|
||||
buff[0] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
buff[1] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
buff[2] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
return 3;
|
||||
case 2: /* # 升:整体 +1 半音 */
|
||||
for (i = 0; i < n; i++)
|
||||
buff[i] += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
buff[i] += mGuiData[GUI_TRANSPOSE].Current;
|
||||
|
||||
/* 音师:所有调的 #四级 — 整组和弦低八度,音域压在一个八度内 */
|
||||
if (chord_type_index_map[MIDI_Index].PitchOffset == 2)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (buff[i] >= 12)
|
||||
buff[i] -= 12;
|
||||
}
|
||||
root = buff[0];
|
||||
for (i = 1; i < n; i++)
|
||||
{
|
||||
while (buff[i] >= (uint8_t)(root + 12))
|
||||
buff[i] -= 12;
|
||||
while (buff[i] < root)
|
||||
buff[i] += 12;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void Read_Cur_Measure()
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ void Loop_Light_Handle(uint8_t measure);
|
|||
void BL_Set_led(uint8_t Led, uint8_t chord_type);
|
||||
|
||||
uint8_t GetChordNotesByType(uint8_t MIDI_Index,uint8_t type,uint8_t *buff);
|
||||
/* 伴奏已在播时仅更新和弦音,不 Restart(快转调) */
|
||||
void Accomp_UpdatePlayingChord(void);
|
||||
void BT_Chord_offset_map(uint8_t pos_offset,uint8_t chord_offset);
|
||||
void BT_Pitch_offset_map(uint8_t pos_offset,uint8_t pitch_offset);
|
||||
void Read_Cur_Measure();
|
||||
|
|
|
|||
22
UI/UI_Idle.c
22
UI/UI_Idle.c
|
|
@ -113,7 +113,7 @@ void LoadConfig()
|
|||
{
|
||||
SendProgramChangeMidiEvent(0,Timbre_index[mGuiData[GUI_TIMBRE_SELECT].Current]);
|
||||
|
||||
uint8_t val_127 = (faders[0].val * 127) / 20;
|
||||
uint8_t val_127 = (faders[0].val * 127) / 10;
|
||||
SendVolumeChangeMidiEvent(1,val_127);
|
||||
SendVolumeChangeMidiEvent(2,val_127);
|
||||
SendVolumeChangeMidiEvent(3,val_127);
|
||||
|
|
@ -130,7 +130,7 @@ void LoadConfig()
|
|||
SendVolumeChangeMidiEvent(14,val_127);
|
||||
SendVolumeChangeMidiEvent(15,val_127);
|
||||
|
||||
SendVolumeChangeMidiEvent(0,faders[1].val);
|
||||
SendVolumeChangeMidiEvent(0,(faders[1].val * 127) / 10);
|
||||
|
||||
AW816_Set_Volume(MIC_VOL_MAP[faders[2].val]);
|
||||
|
||||
|
|
@ -147,25 +147,21 @@ void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex)
|
|||
InModeFlag = true;
|
||||
/* 进入子页后抑制残留按下,否则易误触底栏 GUI_TAB_INDEX(id=5)→设置 */
|
||||
app_touch_suppress(500);
|
||||
/* 开机后再次确认弦音色(DSP 已就绪) */
|
||||
SendProgramChangeMidiEvent(0,Timbre_index[mGuiData[GUI_TIMBRE_SELECT].Current]);
|
||||
|
||||
switch (ID)
|
||||
{
|
||||
case 0: /* 万能 → 3.bin */
|
||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
ADDRESS = FLASH_ADDR_AUTOBAND_LEGACY;
|
||||
else
|
||||
ADDRESS = FLASH_ADDR_MODE_UNIVERSAL;
|
||||
case 0: /* 万能 → 3.bin / 本地→2.bin */
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_SongMode_Proc();
|
||||
break;
|
||||
case 1: /* 专业 → 1.bin */
|
||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
ADDRESS = FLASH_ADDR_AUTOBAND_LEGACY;
|
||||
else
|
||||
ADDRESS = FLASH_ADDR_MODE_EXPERT;
|
||||
case 1: /* 专业 → 1.bin / 本地→2.bin */
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_ExpertMode_Proc();
|
||||
break;
|
||||
case 2: /* 普通 → 1.bin */
|
||||
ADDRESS = FLASH_ADDR_MODE_NORMAL;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_FreeMode_Proc();
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ int8_t delta = 0;
|
|||
void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
||||
{
|
||||
uint8_t last_value;
|
||||
uint8_t midi_note_buff[4] = {0,};
|
||||
NvmParam_Type * nvm = drv_nvm_param_ptr();
|
||||
if(FLAG == 1 || FLAG == -1)
|
||||
{
|
||||
|
|
@ -116,17 +115,9 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
|||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
AutoBandTop1_SetPiecePlayMode(1,0,480); // AutoBand 模块未加入工程
|
||||
AutoBandTop1_StartWithNotes(midi_note_buff,GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff));
|
||||
AutoBandTop1_SetLoopMode(0,1);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
AutoBandTop1_SetPiecePlayMode(1,0,480); // AutoBand 模块未加入工程
|
||||
AutoBandTop1_StartWithNotes(midi_note_buff,GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff));
|
||||
}
|
||||
/* 音师:快转调只换和弦音,伴奏不重头 */
|
||||
Accomp_UpdatePlayingChord();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -181,10 +172,12 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
|||
case 0: case 1:
|
||||
if(mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
{
|
||||
AutoBandTop1_LoadPresetItemFromFlash(0);
|
||||
UI_ApplyToneAddress();
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_ApplyToneAddress();
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
|
||||
|
||||
}
|
||||
|
|
@ -222,20 +215,7 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
|||
if(ID == GUI_AUTOBAND_SW)
|
||||
{
|
||||
mGuiData[ID].Current = value;
|
||||
|
||||
if(mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
{
|
||||
ADDRESS = FLASH_ADDR_AUTOBAND_LEGACY;
|
||||
}else
|
||||
{
|
||||
/* 关闭 AutoBand:回到当前 TAB 对应音色库 */
|
||||
switch (mGuiData[GUI_TAB_INDEX].Current)
|
||||
{
|
||||
case 1: ADDRESS = FLASH_ADDR_MODE_EXPERT; break;
|
||||
case 2: ADDRESS = FLASH_ADDR_MODE_NORMAL; break;
|
||||
default: ADDRESS = FLASH_ADDR_MODE_UNIVERSAL; break;
|
||||
}
|
||||
}
|
||||
UI_ReloadTonePreset();
|
||||
if (!UI_SetFocus(GUI_MODE_PARAM))
|
||||
label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM],&mGuiData[GUI_MODE_PARAM]);
|
||||
return;
|
||||
|
|
@ -269,26 +249,20 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
|||
app_tm1629_all_on(LED_COLOR_G);
|
||||
switch(mGuiData[ID].Current)
|
||||
{
|
||||
case 0: /* 万能 → 3.bin */
|
||||
case 0: /* 万能 → 3.bin / 本地→2.bin */
|
||||
if(mGuiData[GUI_TAB_LAST_INDEX].Current == mGuiData[ID].Current)
|
||||
break;
|
||||
StartFlag = 0;
|
||||
AutoBandTop1_Stop();
|
||||
if(mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
ADDRESS = FLASH_ADDR_AUTOBAND_LEGACY;
|
||||
else
|
||||
ADDRESS = FLASH_ADDR_MODE_UNIVERSAL;
|
||||
UI_ApplyToneAddress();
|
||||
break;
|
||||
|
||||
case 1: /* 专业 → 1.bin */
|
||||
case 1: /* 专业 → 1.bin / 本地→2.bin */
|
||||
if(mGuiData[GUI_TAB_LAST_INDEX].Current == mGuiData[ID].Current)
|
||||
break;
|
||||
StartFlag = 0;
|
||||
AutoBandTop1_Stop();
|
||||
if(mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
ADDRESS = FLASH_ADDR_AUTOBAND_LEGACY;
|
||||
else
|
||||
ADDRESS = FLASH_ADDR_MODE_EXPERT;
|
||||
UI_ApplyToneAddress();
|
||||
break;
|
||||
|
||||
case 2: /* 普通 → 1.bin */
|
||||
|
|
@ -296,7 +270,7 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
|
|||
break;
|
||||
StartFlag = 0;
|
||||
AutoBandTop1_Stop();
|
||||
ADDRESS = FLASH_ADDR_MODE_NORMAL;
|
||||
UI_ApplyToneAddress();
|
||||
break;
|
||||
}
|
||||
Refresh_TabSelect_ui(&UI_Label[ID], &mGuiData[ID]);
|
||||
|
|
@ -325,7 +299,6 @@ void UI_SongMode_Init(void)
|
|||
|
||||
void UI_SongMode_Process(DisplayTaskMessage_Type msg)
|
||||
{
|
||||
uint8_t midi_note_buff[4] = {0,};
|
||||
NvmParam_Type * nvm = drv_nvm_param_ptr();
|
||||
|
||||
switch(msg.MessageType)
|
||||
|
|
@ -475,10 +448,8 @@ void UI_SongMode_Process(DisplayTaskMessage_Type msg)
|
|||
USE_MIDI.Midi_6 += delta;
|
||||
if(/*KEY_ID_1629 != 0 && */StartFlag && KEY_ID_1629 != 22 && KEY_ID_1629 != 23)
|
||||
{
|
||||
AutoBandTop1_SetPiecePlayMode(1,0,480);
|
||||
AutoBandTop1_StartWithNotes(midi_note_buff,GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff));
|
||||
AutoBandTop1_SetLoopMode(0,1);
|
||||
AutoBandTop1_StartWithNotes(midi_note_buff,GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff));
|
||||
/* 音师:快转调只换和弦音,伴奏不重头 */
|
||||
Accomp_UpdatePlayingChord();
|
||||
}
|
||||
ResetAutoPowerCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,41 @@ void CallUI_RestoreSelect(void) {
|
|||
LOG_I("UI", "page Restore");
|
||||
}
|
||||
|
||||
/* 音师:节奏类型→1.bin,本地曲目→2.bin,万能节奏→3.bin(不再用 AutoBand legacy) */
|
||||
void UI_ApplyToneAddress(void)
|
||||
{
|
||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
{
|
||||
ADDRESS = FLASH_ADDR_SONG_HAITIAN; /* 本地曲目 → 2.bin */
|
||||
return;
|
||||
}
|
||||
switch (mGuiData[GUI_TAB_INDEX].Current)
|
||||
{
|
||||
case 1: ADDRESS = FLASH_ADDR_MODE_EXPERT; break; /* 专业 → 1.bin */
|
||||
case 2: ADDRESS = FLASH_ADDR_MODE_NORMAL; break; /* 普通 → 1.bin */
|
||||
default: ADDRESS = FLASH_ADDR_MODE_UNIVERSAL; break; /* 万能 → 3.bin */
|
||||
}
|
||||
}
|
||||
|
||||
void UI_ReloadTonePreset(void)
|
||||
{
|
||||
UI_ApplyToneAddress();
|
||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
{
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
|
||||
return;
|
||||
}
|
||||
switch (mGuiData[GUI_TAB_INDEX].Current)
|
||||
{
|
||||
case 2:
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
|
||||
break;
|
||||
default:
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t s_ui_focus_id = UI_FOCUS_NONE;
|
||||
|
||||
static uint8_t UI_NormalizeFocusId(uint8_t widget_id)
|
||||
|
|
@ -236,19 +271,15 @@ void UI_GotoCurrentModePage(void)
|
|||
switch (mGuiData[GUI_TAB_INDEX].Current)
|
||||
{
|
||||
case 0:
|
||||
ADDRESS = mGuiData[GUI_AUTOBAND_SW].Current
|
||||
? FLASH_ADDR_AUTOBAND_LEGACY
|
||||
: FLASH_ADDR_MODE_UNIVERSAL;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_SongMode_Proc();
|
||||
break;
|
||||
case 1:
|
||||
ADDRESS = mGuiData[GUI_AUTOBAND_SW].Current
|
||||
? FLASH_ADDR_AUTOBAND_LEGACY
|
||||
: FLASH_ADDR_MODE_EXPERT;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_ExpertMode_Proc();
|
||||
break;
|
||||
case 2:
|
||||
ADDRESS = FLASH_ADDR_MODE_NORMAL;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_FreeMode_Proc();
|
||||
break;
|
||||
default:
|
||||
|
|
@ -818,19 +849,15 @@ void UI_NavBar_Action(uint8_t value)
|
|||
switch (value)
|
||||
{
|
||||
case UI0902_NAV_UNIVERSAL:
|
||||
ADDRESS = mGuiData[GUI_AUTOBAND_SW].Current
|
||||
? FLASH_ADDR_AUTOBAND_LEGACY
|
||||
: FLASH_ADDR_MODE_UNIVERSAL;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_SongMode_Proc();
|
||||
break;
|
||||
case UI0902_NAV_NORMAL:
|
||||
ADDRESS = FLASH_ADDR_MODE_NORMAL;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_FreeMode_Proc();
|
||||
break;
|
||||
case UI0902_NAV_EXPERT:
|
||||
ADDRESS = mGuiData[GUI_AUTOBAND_SW].Current
|
||||
? FLASH_ADDR_AUTOBAND_LEGACY
|
||||
: FLASH_ADDR_MODE_EXPERT;
|
||||
UI_ApplyToneAddress();
|
||||
MenuPage_ExpertMode_Proc();
|
||||
break;
|
||||
case UI0902_NAV_SETTING:
|
||||
|
|
|
|||
|
|
@ -218,4 +218,7 @@ extern void RestoreSetting();
|
|||
extern void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group);
|
||||
/* 子页顶栏:左返回 + 居中标题(调音台/系统设置) */
|
||||
extern void UI_DrawSubPageHeader(const uint8_t *title_gbk);
|
||||
/* 节奏类型→1.bin / 本地曲目→2.bin / 万能→3.bin */
|
||||
extern void UI_ApplyToneAddress(void);
|
||||
extern void UI_ReloadTonePreset(void);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Erase entire W25Q128 external Flash via RTT command: flash erase chip
|
||||
|
||||
Requires firmware that implements the RTT command (APP/app_log.c).
|
||||
Chip erase typically takes 30–120s; do not power-cycle mid-erase.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import time
|
||||
|
||||
DEFAULT_DEVICES = ("Cortex-M4", "AT32F403AC", "AT32F403A")
|
||||
|
||||
|
||||
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) -> str:
|
||||
deadline = time.time() + timeout_s
|
||||
buf = ""
|
||||
last_print = 0.0
|
||||
while time.time() < deadline:
|
||||
chunk = rtt_read_text(jlink, 0.2)
|
||||
if chunk:
|
||||
buf += chunk
|
||||
if marker in buf:
|
||||
return buf
|
||||
now = time.time()
|
||||
if now - last_print >= 5.0:
|
||||
elapsed = now - (deadline - timeout_s)
|
||||
print(f" ... waiting erase ({elapsed:.0f}s)")
|
||||
last_print = now
|
||||
time.sleep(0.05)
|
||||
raise SystemExit(f"Timeout waiting for {marker!r}\n--- RTT ---\n{buf[-1200:]}")
|
||||
|
||||
|
||||
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("--device", default="Cortex-M4")
|
||||
parser.add_argument("--no-reset", action="store_true")
|
||||
parser.add_argument("--timeout", type=float, default=180.0,
|
||||
help="seconds to wait for FLASH_ERASE_OK (default 180)")
|
||||
args = parser.parse_args()
|
||||
|
||||
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)
|
||||
|
||||
print("Sending: flash erase chip")
|
||||
send_bytes(jlink, b"flash erase chip\n")
|
||||
log = wait_for(jlink, "FLASH_ERASE_BEGIN", 20.0)
|
||||
print(log.strip().splitlines()[-1])
|
||||
print(f"Chip erase running (timeout {args.timeout:.0f}s)...")
|
||||
log = wait_for(jlink, "FLASH_ERASE_OK", args.timeout)
|
||||
print(log.strip().splitlines()[-1])
|
||||
print("ExtFlash chip erase done. Flash MCU + extflash_ALL*.res manually.")
|
||||
finally:
|
||||
try:
|
||||
jlink.rtt_stop()
|
||||
except Exception:
|
||||
pass
|
||||
jlink.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue