Fix mode-select layout/battery margins and enable reliable post-flash boot.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-08-31 08:20:24 +08:00
parent 27cf30cbe4
commit 68e3a37883
9 changed files with 111 additions and 42 deletions

View File

@ -130,13 +130,17 @@ int main(void)
TM1617_GPIO_Init(); TM1617_GPIO_Init();
wk_delay_ms(1000); /* 短暂等待总线稳定;默认跳转 App。
* KEY_MAIN_A USB
* KEY_NULL App Boot */
wk_delay_ms(50);
TM1617KeyValue = TM1617_ScanFkey(); TM1617KeyValue = TM1617_ScanFkey();
if(TM1617KeyValue == 4) if (TM1617KeyValue != KEY_MAIN_A)
{ {
JumpToApplication(); JumpToApplication();
/* 若 App 向量无效则继续走升级模式 */
} }
/* init spi1 function. */ /* init spi1 function. */
BSP_MainPowerEnable(1); BSP_MainPowerEnable(1);
wk_spi1_init(); wk_spi1_init();

View File

@ -155,7 +155,7 @@ static uint32_t pwr_press_tick = 0;
bool powon = false; bool powon = false;
/* ==================== 开机/关机动作 ==================== */ /* ==================== 开机/关机动作 ==================== */
static void PowerOn(void) void System_PowerOn(void)
{ {
/* 控制电源硬件 */ /* 控制电源硬件 */
BSP_MainPowerEnable(1); BSP_MainPowerEnable(1);
@ -173,6 +173,11 @@ static void PowerOn(void)
MainTask_Sendmsg(MSG_ID_POWER_ON,0,0,0); MainTask_Sendmsg(MSG_ID_POWER_ON,0,0,0);
} }
static void PowerOn(void)
{
System_PowerOn();
}
static void PowerOff(void) static void PowerOff(void)
{ {
powon = false; /* 更新关机标志 */ powon = false; /* 更新关机标志 */
@ -202,6 +207,19 @@ void Power_Key_Scan()
uint32_t now = rt_tick_get(); uint32_t now = rt_tick_get();
uint32_t holdtick = 0; uint32_t holdtick = 0;
/* 复位/烧录后自动开机一次,避免黑屏干等长按;正常关机后下电再上电仍走此路径 */
if (powon == false && pwr_key_state == KEY_STATE_IDLE && pwr_press_tick == 0)
{
static uint8_t s_auto_poweron_pending = 1;
if (s_auto_poweron_pending)
{
s_auto_poweron_pending = 0;
PowerOn();
pwr_key_state = KEY_STATE_NONE; /* 忽略开机瞬间可能残留的按键电平 */
return;
}
}
switch(pwr_key_state) switch(pwr_key_state)
{ {
case KEY_STATE_IDLE: case KEY_STATE_IDLE:

View File

@ -164,6 +164,8 @@ extern rt_timer_t OutTime_Stop_timer;
extern uint8_t KEY_ID_1629; extern uint8_t KEY_ID_1629;
extern bool powon; extern bool powon;
void Power_Key_Scan(void);
void System_PowerOn(void);
extern uint8_t Led; extern uint8_t Led;
extern bool PressFlag; extern bool PressFlag;
@ -194,8 +196,6 @@ extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
void Stop_AutoBand(); void Stop_AutoBand();
void Power_Key_Scan();
static void ShowPowerOn(); static void ShowPowerOn();
void GET_ParamNum_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign); void GET_ParamNum_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign);

View File

@ -22,7 +22,13 @@ void RGB_Y_TO_G()
#define UI_MODE_BG_COLOR 0x1925 #define UI_MODE_BG_COLOR 0x1925
#define UI_MODE_LINE_COLOR DARKBLUE #define UI_MODE_LINE_COLOR DARKBLUE
#define UI_MODE_TEXT_COLOR 0xFFFF #define UI_MODE_TEXT_COLOR 0xFFFF
#define UI_MODE_FONT_SIZE 16 /* PDF 标注 MiSans-Medium 21字库无 21用 28 与 40x30 图标比例接近标注稿 */
#define UI_MODE_FONT_SIZE 28
#define UI_MODE_ICON_W 40
#define UI_MODE_ICON_H 30
#define UI_MODE_ICON_TEXT_GAP 8
/* 汉字墨心略偏上;下移与图标光心平齐(过大易显得文字偏下) */
#define UI_MODE_TEXT_OPTICAL_DY 2
/* 模式选择页焦点0=万能 1=普通 2=专业,默认选中万能(与规范一致) */ /* 模式选择页焦点0=万能 1=普通 2=专业,默认选中万能(与规范一致) */
static uint8_t s_mode_select_focus = 0; static uint8_t s_mode_select_focus = 0;
@ -34,8 +40,13 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text,
const uint16_t btn_h = 87; const uint16_t btn_h = 87;
const uint16_t btn_r = 10; const uint16_t btn_r = 10;
const uint16_t btn_x = (240 - btn_w) / 2; const uint16_t btn_x = (240 - btn_w) / 2;
uint16_t text_y = y + (btn_h - UI_MODE_FONT_SIZE) / 2; const uint16_t text_w = (uint16_t)(4 * UI_MODE_FONT_SIZE);
uint16_t text_x; const uint16_t group_w = (uint16_t)(UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP + text_w);
const uint16_t group_x = (uint16_t)(btn_x + (btn_w - group_w) / 2);
const uint16_t mid_y = (uint16_t)(y + btn_h / 2);
const uint16_t icon_y = (uint16_t)(mid_y - UI_MODE_ICON_H / 2);
const uint16_t text_y = (uint16_t)(mid_y - UI_MODE_FONT_SIZE / 2 + UI_MODE_TEXT_OPTICAL_DY);
const uint16_t text_x = (uint16_t)(group_x + UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP);
if (focused) if (focused)
{ {
@ -47,24 +58,24 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text,
LCD_FillRoundRect(btn_x, y, btn_w, btn_h, btn_r, COLOR_NORMAL_BG); LCD_FillRoundRect(btn_x, y, btn_w, btn_h, btn_r, COLOR_NORMAL_BG);
} }
/* 叠加绘制文字,避免在渐变底上打出实心色块 */ LCD_WR_PIC_Trans(group_x, icon_y, UI_MODE_ICON_W, UI_MODE_ICON_H, icon, BLACK);
text_x = LCD_ShowChinese_AutoAlign( LCD_ShowChinese_AutoAlign(
btn_x, btn_x + btn_w, text_x, (uint16_t)(text_x + text_w - 1),
text_y, text_y,
text, text,
LCD_ALIGN_CENTER, LCD_ALIGN_LEFT,
UI_MODE_TEXT_COLOR, UI_MODE_TEXT_COLOR,
BLACK, BLACK,
1, 1,
UI_MODE_FONT_SIZE UI_MODE_FONT_SIZE
); );
LCD_WR_PIC_Trans(text_x - 45, text_y - 5, 40, 30, icon, BLACK);
} }
void UI_DrawModeSelectScreen(void) void UI_DrawModeSelectScreen(void)
{ {
UI_ClearFocus(); UI_ClearFocus();
s_mode_select_focus = 0; s_mode_select_focus = 0;
pCurrentTouch_Area = Touch_ModeSelect_Areas;
LCD_FillByColor(0, 0, 240, 320, BLACK); LCD_FillByColor(0, 0, 240, 320, BLACK);
label_top(); label_top();
@ -212,10 +223,10 @@ void IdleProcess(DisplayTaskMessage_Type msg)
case MSG_ID_TOUCH: case MSG_ID_TOUCH:
for(uint8_t k=0; k<TOUCH_AREA_MODE_SELECT_NUM; k++) for(uint8_t k=0; k<TOUCH_AREA_MODE_SELECT_NUM; k++)
{ {
if( msg.HiByte >= pCurrentTouch_Area[k].x_min && msg.HiByte <= pCurrentTouch_Area[k].x_max && if( msg.HiByte >= Touch_ModeSelect_Areas[k].x_min && msg.HiByte <= Touch_ModeSelect_Areas[k].x_max &&
msg.LoByte >= pCurrentTouch_Area[k].y_min && msg.LoByte <= pCurrentTouch_Area[k].y_max ) msg.LoByte >= Touch_ModeSelect_Areas[k].y_min && msg.LoByte <= Touch_ModeSelect_Areas[k].y_max )
{ {
Touch_Mode_Select_Action(pCurrentTouch_Area[k].Flag,pCurrentTouch_Area[k].ID,k); Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag,Touch_ModeSelect_Areas[k].ID,k);
break; break;
} }
} }

View File

@ -156,7 +156,7 @@ void label_top()
const uint16_t btn_color = /*DARKLGRAY*/0x2988; // 深灰<E6B7B1>????? const uint16_t btn_color = /*DARKLGRAY*/0x2988; // 深灰<E6B7B1>?????
//LCD_FillByColor(0,0,240,25,BLACK); //LCD_FillByColor(0,0,240,25,BLACK);
//LCD_WR_PIC(5,0,12,20,gImage_bar); //LCD_WR_PIC(5,0,12,20,gImage_bar);
Draw_Volume_Bar(5, 5, level, 1, WHITE, GRAY); Draw_Volume_Bar(8, 5, level, 1, WHITE, GRAY);
LCD_DrawLine(0, 26, 240, 26, btn_color); LCD_DrawLine(0, 26, 240, 26, btn_color);
Show_BL_Icon(mGuiData[GUI_BL_SW].Current); Show_BL_Icon(mGuiData[GUI_BL_SW].Current);
Show_Battery_Icon(usb_charging_state); Show_Battery_Icon(usb_charging_state);

View File

@ -28,9 +28,11 @@ void CallUI_RestoreSelect(void);
#define UI_STATUS_BAR_H 26 #define UI_STATUS_BAR_H 26
#define UI_STATUS_BATTERY_X 180 /* 电量组在 Draw_Battery_Icon 内按右对齐重算;此值为允许的最左起点 */
#define UI_STATUS_BATTERY_X 150
#define UI_STATUS_BATTERY_H 11 #define UI_STATUS_BATTERY_H 11
#define UI_STATUS_BATTERY_Y ((UI_STATUS_BAR_H - UI_STATUS_BATTERY_H) / 2) #define UI_STATUS_BATTERY_Y ((UI_STATUS_BAR_H - UI_STATUS_BATTERY_H) / 2)
#define UI_STATUS_BATTERY_RIGHT_MARGIN 8
#define UI_FOCUS_NONE 0xFF #define UI_FOCUS_NONE 0xFF
void UI_ClearFocus(void); void UI_ClearFocus(void);

View File

@ -150,14 +150,13 @@ void LCD_WR_PIC(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const u
} }
} }
/* 跳过 key_color 像素,用于图标透明底(常见 key=BLACK */ /* 跳过近黑色像素(图标导出底色常为 0x0000/0x0001/0x0022非纯 BLACK */
void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width, void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width,
const uint8_t data[], uint16_t key_color) const uint8_t data[], uint16_t key_color)
{ {
uint32_t total_pixels = (uint32_t)length * width; uint32_t total_pixels = (uint32_t)length * width;
uint8_t key_h = (uint8_t)(key_color >> 8);
uint8_t key_l = (uint8_t)(key_color & 0xFF);
uint32_t i; uint32_t i;
(void)key_color;
if (total_pixels == 0) if (total_pixels == 0)
return; return;
@ -166,11 +165,18 @@ void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width,
{ {
uint8_t hi = data[i * 2]; uint8_t hi = data[i * 2];
uint8_t lo = data[i * 2 + 1]; uint8_t lo = data[i * 2 + 1];
if (hi == key_h && lo == key_l) uint16_t c = (uint16_t)((hi << 8) | lo);
uint8_t r5 = (uint8_t)((c >> 11) & 0x1F);
uint8_t g6 = (uint8_t)((c >> 5) & 0x3F);
uint8_t b5 = (uint8_t)(c & 0x1F);
/* 近黑视为透明,避免图标黑底方块 */
if (r5 <= 1 && g6 <= 2 && b5 <= 2)
continue; continue;
LCD_DrawPoint((uint16_t)(x + (i % length)), LCD_DrawPoint((uint16_t)(x + (i % length)),
(uint16_t)(y + (i / length)), (uint16_t)(y + (i / length)),
(uint16_t)((hi << 8) | lo)); c);
} }
} }
@ -1794,11 +1800,14 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s
uint8_t round_r = 2 * scale; uint8_t round_r = 2 * scale;
uint8_t stroke = 1 * scale; uint8_t stroke = 1 * scale;
uint16_t fill_gap = 2 * scale; uint16_t fill_gap = 2 * scale;
uint8_t text_size = 16 * scale; /* 16px ASCII 字体渲染可靠13px 位图与驱动不匹配会乱码 */ /* PDF 标注 7.5,但 8px ASCII 位图乱码;用 16px 并整组右对齐,避免左右被裁 */
uint8_t text_size = 16 * scale;
uint8_t status_bar_h = 26 * scale; uint8_t status_bar_h = 26 * scale;
uint8_t Info[40]; uint8_t Info[40];
uint16_t pole_w = 2 * scale; uint16_t pole_w = 2 * scale;
uint16_t pole_h = 5 * scale; uint16_t pole_h = 5 * scale;
uint16_t gap = 6 * scale;
uint16_t right_margin = 14 * scale;
uint16_t pole_x; uint16_t pole_x;
uint16_t pole_y; uint16_t pole_y;
uint16_t inner_w; uint16_t inner_w;
@ -1806,6 +1815,9 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s
uint16_t fill_w; uint16_t fill_w;
uint16_t text_x; uint16_t text_x;
uint16_t text_y; uint16_t text_y;
uint16_t text_w;
uint16_t group_w;
uint16_t bat_x = x;
uint16_t clear_h; uint16_t clear_h;
if(battery_percent > 100) if(battery_percent > 100)
@ -1813,18 +1825,26 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s
battery_percent = 100; battery_percent = 100;
} }
sprintf((char*)Info, "%d%%", battery_percent);
text_w = (uint16_t)(strlen((char*)Info) * (text_size / 2));
group_w = (uint16_t)(bat_w + pole_w + gap + text_w);
if (group_w + right_margin < 240)
bat_x = (uint16_t)(240 - right_margin - group_w);
if (bat_x < x)
bat_x = x;
clear_h = (bat_h > text_size) ? bat_h : text_size; clear_h = (bat_h > text_size) ? bat_h : text_size;
if(status_bar_h > clear_h) if(status_bar_h > clear_h)
{ {
clear_h = status_bar_h; clear_h = status_bar_h;
} }
LCD_FillByColor(x, 0, 240, clear_h, BLACK); LCD_FillByColor(bat_x > 4 ? (uint16_t)(bat_x - 4) : 0, 0, 240, clear_h, BLACK);
/* 圆角外壳:外框 + 内挖空 */ /* 圆角外壳:外框 + 内挖空 */
LCD_FillRoundRect(x, y, bat_w, bat_h, round_r, border_color); LCD_FillRoundRect(bat_x, y, bat_w, bat_h, round_r, border_color);
if(bat_w > 2 * stroke && bat_h > 2 * stroke) if(bat_w > 2 * stroke && bat_h > 2 * stroke)
{ {
LCD_FillRoundRect(x + stroke, y + stroke, LCD_FillRoundRect(bat_x + stroke, y + stroke,
bat_w - 2 * stroke, bat_h - 2 * stroke, bat_w - 2 * stroke, bat_h - 2 * stroke,
(round_r > stroke) ? (round_r - stroke) : 0, (round_r > stroke) ? (round_r - stroke) : 0,
bg_color); bg_color);
@ -1834,26 +1854,25 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s
inner_h = bat_h - 2 * fill_gap; inner_h = bat_h - 2 * fill_gap;
fill_w = inner_w * battery_percent / 100; fill_w = inner_w * battery_percent / 100;
/* 从左向右实心填充,宽度与百分比一致 */
if(battery_percent > 0 && fill_w > 0) if(battery_percent > 0 && fill_w > 0)
{ {
if(fill_w > inner_w) if(fill_w > inner_w)
{ {
fill_w = inner_w; fill_w = inner_w;
} }
LCD_FillRoundRect(x + fill_gap, y + fill_gap, LCD_FillRoundRect(bat_x + fill_gap, y + fill_gap,
fill_w, inner_h, fill_w, inner_h,
1 * scale, fill_color); 1 * scale, fill_color);
} }
/* 右侧正极小凸起 */ pole_x = bat_x + bat_w;
pole_x = x + bat_w;
pole_y = y + (bat_h - pole_h) / 2; pole_y = y + (bat_h - pole_h) / 2;
LCD_FillRoundRect(pole_x, pole_y, pole_w, pole_h, 1 * scale, border_color); LCD_FillRoundRect(pole_x, pole_y, pole_w, pole_h, 1 * scale, border_color);
sprintf((char*)Info, "%d%%", battery_percent); text_x = (uint16_t)(pole_x + pole_w + gap);
text_x = pole_x + pole_w + 2 * scale;
text_y = (status_bar_h - text_size) / 2; text_y = (status_bar_h - text_size) / 2;
if ((int16_t)text_y < 0)
text_y = 0;
LCD_ShowString(text_x, text_y, Info, WHITE, BLACK, text_size, 0); LCD_ShowString(text_x, text_y, Info, WHITE, BLACK, text_size, 0);
} }

View File

@ -1,7 +1,5 @@
@echo off @echo off
REM Flash YNGJ-GT1-M app via IAR cspybat (AT32 flash loader). REM Flash YNGJ-GT1-M app via IAR cspybat, then reset+run and wait for UI boot.
REM Do NOT pass Commander-style .jlink files to --jlink_script_file.
setlocal setlocal
set ROOT=%~dp0.. set ROOT=%~dp0..
set OUT=%ROOT%\project\IAR_V7.4\YNGJ-GT1-M\Exe\YNGJ-GT1-M.out set OUT=%ROOT%\project\IAR_V7.4\YNGJ-GT1-M\Exe\YNGJ-GT1-M.out
@ -9,6 +7,7 @@ set GEN=%ROOT%\project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.general.xcl
set DRV=%ROOT%\project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.driver.xcl set DRV=%ROOT%\project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.driver.xcl
set CSPY="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.3\common\bin\cspybat" set CSPY="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.3\common\bin\cspybat"
set STAGE=C:\Temp\k1flash set STAGE=C:\Temp\k1flash
set JLINK="C:\Program Files\SEGGER\JLink_V818\JLink.exe"
if not exist "%OUT%" ( if not exist "%OUT%" (
echo ERROR: missing %OUT% - build first echo ERROR: missing %OUT% - build first
@ -18,8 +17,15 @@ if not exist "%OUT%" (
mkdir "%STAGE%" 2>nul mkdir "%STAGE%" 2>nul
copy /Y "%OUT%" "%STAGE%\YNGJ-GT1-M.out" >nul copy /Y "%OUT%" "%STAGE%\YNGJ-GT1-M.out" >nul
echo [1/3] Downloading...
%CSPY% -f "%GEN%" "--debug_file=%STAGE%\YNGJ-GT1-M.out" --download_only --backend -f "%DRV%" %CSPY% -f "%GEN%" "--debug_file=%STAGE%\YNGJ-GT1-M.out" --download_only --backend -f "%DRV%"
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
"C:\Program Files\SEGGER\JLink_V818\JLink.exe" -CommandFile "%~dp0reset_run.jlink" echo [2/3] Reset and run...
exit /b %ERRORLEVEL% %JLINK% -CommandFile "%~dp0reset_run.jlink"
if errorlevel 1 exit /b 1
echo [3/3] Wait for auto PowerOn + logo (about 3s)...
timeout /t 3 /nobreak >nul
echo Done. UI should be on mode-select screen.
exit /b 0

View File

@ -138,17 +138,26 @@ def capture_rtt_png(out_path: str, device: str, timeout_s: float, do_reset: bool
buffer = b"" buffer = b""
deadline = time.time() + timeout_s deadline = time.time() + timeout_s
header_off = -1
while time.time() < deadline: while time.time() < deadline:
term = jlink.rtt_read(0, 1024) term = jlink.rtt_read(0, 1024)
if term: if term:
print("RTT0:", bytes(term).decode("utf-8", errors="replace").strip()) print("RTT0:", bytes(term).decode("utf-8", errors="replace").strip())
chunk = jlink.rtt_read(1, 8192) chunk = jlink.rtt_read(1, 16384)
if chunk: if chunk:
buffer += bytes(chunk) buffer += bytes(chunk)
if len(buffer) >= HEADER_SIZE and buffer[:4] == MAGIC: # Drain stale bytes before SCRN (previous incomplete dumps).
header_off = buffer.find(MAGIC)
if header_off >= 0 and len(buffer) >= header_off + HEADER_SIZE:
if header_off > 0:
print(f"Discarded {header_off} stale RTT1 bytes before SCRN")
buffer = buffer[header_off:]
break break
time.sleep(0.01) # Cap memory if SCRN never appears
if len(buffer) > 256 * 1024:
buffer = buffer[-65536:]
time.sleep(0.001)
if len(buffer) < HEADER_SIZE or buffer[:4] != MAGIC: if len(buffer) < HEADER_SIZE or buffer[:4] != MAGIC:
raise SystemExit("Timeout waiting for SCRN header on RTT channel 1") raise SystemExit("Timeout waiting for SCRN header on RTT channel 1")