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();
wk_delay_ms(1000);
/* 短暂等待总线稳定;默认跳转 App。
* KEY_MAIN_A USB
* KEY_NULL App Boot */
wk_delay_ms(50);
TM1617KeyValue = TM1617_ScanFkey();
if(TM1617KeyValue == 4)
if (TM1617KeyValue != KEY_MAIN_A)
{
JumpToApplication();
/* 若 App 向量无效则继续走升级模式 */
}
/* init spi1 function. */
BSP_MainPowerEnable(1);
wk_spi1_init();

View File

@ -155,7 +155,7 @@ static uint32_t pwr_press_tick = 0;
bool powon = false;
/* ==================== 开机/关机动作 ==================== */
static void PowerOn(void)
void System_PowerOn(void)
{
/* 控制电源硬件 */
BSP_MainPowerEnable(1);
@ -173,6 +173,11 @@ static void PowerOn(void)
MainTask_Sendmsg(MSG_ID_POWER_ON,0,0,0);
}
static void PowerOn(void)
{
System_PowerOn();
}
static void PowerOff(void)
{
powon = false; /* 更新关机标志 */
@ -202,6 +207,19 @@ void Power_Key_Scan()
uint32_t now = rt_tick_get();
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)
{
case KEY_STATE_IDLE:

View File

@ -164,6 +164,8 @@ extern rt_timer_t OutTime_Stop_timer;
extern uint8_t KEY_ID_1629;
extern bool powon;
void Power_Key_Scan(void);
void System_PowerOn(void);
extern uint8_t Led;
extern bool PressFlag;
@ -194,8 +196,6 @@ extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
void Stop_AutoBand();
void Power_Key_Scan();
static void ShowPowerOn();
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_LINE_COLOR DARKBLUE
#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=专业,默认选中万能(与规范一致) */
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_r = 10;
const uint16_t btn_x = (240 - btn_w) / 2;
uint16_t text_y = y + (btn_h - UI_MODE_FONT_SIZE) / 2;
uint16_t text_x;
const uint16_t text_w = (uint16_t)(4 * UI_MODE_FONT_SIZE);
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)
{
@ -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);
}
/* 叠加绘制文字,避免在渐变底上打出实心色块 */
text_x = LCD_ShowChinese_AutoAlign(
btn_x, btn_x + btn_w,
LCD_WR_PIC_Trans(group_x, icon_y, UI_MODE_ICON_W, UI_MODE_ICON_H, icon, BLACK);
LCD_ShowChinese_AutoAlign(
text_x, (uint16_t)(text_x + text_w - 1),
text_y,
text,
LCD_ALIGN_CENTER,
LCD_ALIGN_LEFT,
UI_MODE_TEXT_COLOR,
BLACK,
1,
UI_MODE_FONT_SIZE
);
LCD_WR_PIC_Trans(text_x - 45, text_y - 5, 40, 30, icon, BLACK);
}
void UI_DrawModeSelectScreen(void)
{
UI_ClearFocus();
s_mode_select_focus = 0;
pCurrentTouch_Area = Touch_ModeSelect_Areas;
LCD_FillByColor(0, 0, 240, 320, BLACK);
label_top();
@ -212,10 +223,10 @@ void IdleProcess(DisplayTaskMessage_Type msg)
case MSG_ID_TOUCH:
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 &&
msg.LoByte >= pCurrentTouch_Area[k].y_min && msg.LoByte <= pCurrentTouch_Area[k].y_max )
if( msg.HiByte >= Touch_ModeSelect_Areas[k].x_min && msg.HiByte <= Touch_ModeSelect_Areas[k].x_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;
}
}

View File

@ -156,7 +156,7 @@ void label_top()
const uint16_t btn_color = /*DARKLGRAY*/0x2988; // 深灰<E6B7B1>?????
//LCD_FillByColor(0,0,240,25,BLACK);
//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);
Show_BL_Icon(mGuiData[GUI_BL_SW].Current);
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_BATTERY_X 180
/* 电量组在 Draw_Battery_Icon 内按右对齐重算;此值为允许的最左起点 */
#define UI_STATUS_BATTERY_X 150
#define UI_STATUS_BATTERY_H 11
#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
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,
const uint8_t data[], uint16_t key_color)
{
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;
(void)key_color;
if (total_pixels == 0)
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 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;
LCD_DrawPoint((uint16_t)(x + (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 stroke = 1 * 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 Info[40];
uint16_t pole_w = 2 * 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_y;
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 text_x;
uint16_t text_y;
uint16_t text_w;
uint16_t group_w;
uint16_t bat_x = x;
uint16_t clear_h;
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;
}
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;
if(status_bar_h > clear_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)
{
LCD_FillRoundRect(x + stroke, y + stroke,
LCD_FillRoundRect(bat_x + stroke, y + stroke,
bat_w - 2 * stroke, bat_h - 2 * stroke,
(round_r > stroke) ? (round_r - stroke) : 0,
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;
fill_w = inner_w * battery_percent / 100;
/* 从左向右实心填充,宽度与百分比一致 */
if(battery_percent > 0 && fill_w > 0)
{
if(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,
1 * scale, fill_color);
}
/* 右侧正极小凸起 */
pole_x = x + bat_w;
pole_x = bat_x + bat_w;
pole_y = y + (bat_h - pole_h) / 2;
LCD_FillRoundRect(pole_x, pole_y, pole_w, pole_h, 1 * scale, border_color);
sprintf((char*)Info, "%d%%", battery_percent);
text_x = pole_x + pole_w + 2 * scale;
text_x = (uint16_t)(pole_x + pole_w + gap);
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);
}

View File

@ -1,7 +1,5 @@
@echo off
REM Flash YNGJ-GT1-M app via IAR cspybat (AT32 flash loader).
REM Do NOT pass Commander-style .jlink files to --jlink_script_file.
REM Flash YNGJ-GT1-M app via IAR cspybat, then reset+run and wait for UI boot.
setlocal
set ROOT=%~dp0..
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 CSPY="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.3\common\bin\cspybat"
set STAGE=C:\Temp\k1flash
set JLINK="C:\Program Files\SEGGER\JLink_V818\JLink.exe"
if not exist "%OUT%" (
echo ERROR: missing %OUT% - build first
@ -18,8 +17,15 @@ if not exist "%OUT%" (
mkdir "%STAGE%" 2>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%"
if errorlevel 1 exit /b 1
"C:\Program Files\SEGGER\JLink_V818\JLink.exe" -CommandFile "%~dp0reset_run.jlink"
exit /b %ERRORLEVEL%
echo [2/3] Reset and run...
%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""
deadline = time.time() + timeout_s
header_off = -1
while time.time() < deadline:
term = jlink.rtt_read(0, 1024)
if term:
print("RTT0:", bytes(term).decode("utf-8", errors="replace").strip())
chunk = jlink.rtt_read(1, 8192)
chunk = jlink.rtt_read(1, 16384)
if 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
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:
raise SystemExit("Timeout waiting for SCRN header on RTT channel 1")