K1Guitar/UI/UI_Idle.c

339 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
uint8_t CurrentMode = 0;
/* 样机「开机彩灯」:侧灯全亮色序 蓝→青→红→青(末态保持青) */
void UI_BootLedShow(void)
{
static const LedColor_TypeDef seq[] = {
LED_COLOR_B,
LED_COLOR_CYA,
LED_COLOR_R,
LED_COLOR_CYA,
};
static const uint16_t hold_ms[] = { 400, 300, 400, 0 };
uint8_t i;
for (i = 0; i < (uint8_t)(sizeof(seq) / sizeof(seq[0])); i++)
{
app_tm1629_all_on(seq[i]);
if (hold_ms[i] != 0U)
rt_thread_mdelay(hold_ms[i]);
}
}
#define UI_MODE_SCREEN_WIDTH 240
#define UI_MODE_SCREEN_HEIGHT 320
extern bool InModeFlag;
/* 0902-01:行高88、行距92;顶边与模式主页移调/速度(CARD_Y=48)对齐,分割线居中 */
#define UI0902_MODE_ROW_X 9
#define UI0902_MODE_ROW_W 222
#define UI0902_MODE_ROW_H 88
#define UI0902_MODE_ROW_Y0 UI0902_CARD_Y /* 48,与移调/速度顶对齐 */
#define UI0902_MODE_ROW_DY 92 /* 48 / 140 / 232 */
/* 模式页不显示焦点:三行均用未选中资源;单击直接进入 */
static const uint32_t s_mode_row_addr[3] = {
UI0902_ROW_UNIVERSAL_NOT_ADDR, /* 0 万能 */
UI0902_ROW_NORMAL_NOT_ADDR, /* 1 普通 */
UI0902_ROW_EXPERT_NOT_ADDR, /* 2 专业 */
};
static void UI_ModeSelect_DrawButtons(void)
{
uint8_t i;
for (i = 0; i < 3; i++) {
uint16_t y = (uint16_t)(UI0902_MODE_ROW_Y0 + i * UI0902_MODE_ROW_DY);
LCD_WR_PIC_FROM_FLASH(UI0902_MODE_ROW_X, y,
UI0902_MODE_ROW_W, UI0902_MODE_ROW_H,
s_mode_row_addr[i]);
}
}
void UI_ReturnToModeSelect(void)
{
InModeFlag = false;
Stop_AutoBand();
/* 长按回模式选择时,清掉万能 LOOP_LIGHT 残留红灯 */
app_tm1629_all_on(LED_COLOR_G);
CallUI_Idle();
UI_DrawModeSelectScreen();
}
void UI_DrawModeSelectScreen(void)
{
UI_ClearFocus();
pCurrentTouch_Area = Touch_ModeSelect_Areas;
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
label_top();
UI_ModeSelect_DrawButtons();
/* 设计稿 0902-01:模式选择页无底部三栏导航,仅三行模式按钮 */
}
const Touch_AreaTypeDef Touch_ModeSelect_Areas[] = {
/* 状态栏蓝牙:点击开关(须在模式行之前,避免被误判) */
{ UI0902_BT_HIT_X0, UI0902_BT_HIT_X1, UI0902_BT_HIT_Y0, UI0902_BT_HIT_Y1,
0, 0, GUI_BL_SW, NULL },
/* Flag=按钮序号(0万能/1普通/2专业);ID=进入 TAB。全宽便于命中;Y 与 MODE_ROW_* 一致 */
{ 0, 239, 48, 135, 0, 0, 0, NULL },
{ 0, 239, 140, 227, 1, 0, 2, NULL },
{ 0, 239, 232, 319, 2, 0, 1, NULL },
};
#define TOUCH_AREA_MODE_SELECT_NUM (sizeof(Touch_ModeSelect_Areas)/sizeof(Touch_AreaTypeDef))
/* Timbre_index <20><><EFBFBD><EFBFBD> midi_tables.h <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
extern uint8_t channel;
extern uint8_t level;
extern bool powon;
extern bool InModeFlag;
extern int16_t MIC_VOL_MAP[11];
extern int8_t delta;
extern STRING_MIDI USE_MIDI;
void LoadConfig(void)
{
uint8_t ch;
/* 双音色库:主弦走 Bank1,先选 bank 再 PC */
SendProgramWithBankMidiEvent(0, MIDI_BANK_STRING, Timbre_index[mGuiData[GUI_TIMBRE_SELECT].Current]);
/* 伴奏通道预置 Bank0,避免上电后首个 PC 前误用残留 bank */
for (ch = 1; ch <= 15; ch++)
SendBankChangeMidiEvent(ch, MIDI_BANK_ACCOMP);
uint8_t val_127 = (faders[0].val * 127) / 10;
SendVolumeChangeMidiEvent(1,val_127);
SendVolumeChangeMidiEvent(2,val_127);
SendVolumeChangeMidiEvent(3,val_127);
SendVolumeChangeMidiEvent(4,val_127);
SendVolumeChangeMidiEvent(5,val_127);
SendVolumeChangeMidiEvent(6,val_127);
SendVolumeChangeMidiEvent(7,val_127);
SendVolumeChangeMidiEvent(8,val_127);
SendVolumeChangeMidiEvent(9,val_127);
SendVolumeChangeMidiEvent(10,val_127);
SendVolumeChangeMidiEvent(11,val_127);
SendVolumeChangeMidiEvent(12,val_127);
SendVolumeChangeMidiEvent(13,val_127);
SendVolumeChangeMidiEvent(14,val_127);
SendVolumeChangeMidiEvent(15,val_127);
SendVolumeChangeMidiEvent(0,(faders[1].val * 127) / 10);
AW816_Set_Volume(MIC_VOL_MAP[faders[2].val]);
AW816_Set_Reverb(faders[3].val * 10);
}
void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex)
{
(void)areaIndex;
(void)FLAG;
if (ID == GUI_BL_SW)
{
UI_StatusBar_ToggleBluetooth();
return;
}
StartTask();
/* ID 为 TAB 索引:0=万能(Song) 1=专业(Expert) 2=普通(Free) */
mGuiData[GUI_TAB_INDEX].Current = ID;
InModeFlag = true;
/* 进模式:默认当前调一级,避免软关机残留把位影响拨片/前奏 */
StartFlag = 0;
Accomp_ApplyDefaultIChord();
/* 进入子页后抑制残留按下,否则易误触底栏 GUI_TAB_INDEX(id=5)→设置 */
app_touch_suppress(500);
/* DSP 已就绪:再下发音色 + 调音台音量(与关机前 NVM/faders 一致) */
LoadConfig();
switch (ID)
{
case 0: /* 万能 → 3.bin / 本地→2.bin */
MenuPage_SongMode_Proc(); /* Init 设 TAB 并 Reload */
break;
case 1: /* 专业 → 1.bin / 本地→2.bin */
MenuPage_ExpertMode_Proc();
break;
case 2: /* 普通 → 1.bin */
MenuPage_FreeMode_Proc();
break;
default:
break;
}
}
extern uint8_t bat_init_done;
/* 关机充电页已绘制标志:POWER_ON 需清除,以便再次软关机充电时重绘 */
static bool s_charge_ui_drawn = false;
void IdleProcess(DisplayTaskMessage_Type msg)
{
switch (msg.MessageType)
{
case MSG_ID_POWER_ON :
/* 充电软关机开机:滞后的拔电消息可能已切主电/关显示,强制恢复 */
BSP_MainPowerEnable(1);
LCD_WR_REG(0x29); /* Display ON */
s_charge_ui_drawn = false;
LCD_BLK_Set();
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
UI0902_BOOT_LOGO_ADDR);
/* 让出 CPU,避免忙等卡住触摸/主循环线程 */
rt_thread_mdelay(1000);
LoadConfig();
/* 主音量不在此现场切通道读 ADC(会与扫描任务串通道):
* 待 StartScanTask 后由 MasterVolume_Reapply 统一补发 */
UI_DrawModeSelectScreen();
UI_BootLedShow();
StartTouchTask();
StartScanTask();
/* Dream 上电稍后可能忽略首包 SysEx:再发主音量 + 调音台(保持关机前设置)。
* 此时扫描任务已启动、模拟开关在轮询,不可现场重读 ADC(会串通道),
* 统一用 MasterVolume_Reapply 取扫描任务维护的最近一次有效音量 */
rt_thread_mdelay(400);
MasterVolume_Reapply();
LoadConfig();
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
break;
case MSG_ID_POWER_OFF:
/* 无 Type-C:整机关机熄屏;有 Type-C 时随后 POWOFF_CHARG 会再亮充电图 */
LCD_BLK_Clr();
LCD_WR_REG(0x28); /* Display OFF */
LCD_FillByColor(0, 0, 240, 320, BLACK);
break;
case MSG_ID_CHARG:
Show_Battery_Icon(msg.ID);
break;
case MSG_ID_TOUCH:
{
if (!powon)
break; /* 软关机已停触摸;兜底勿进模式选择 */
static uint32_t s_last_enter_ms;
uint32_t now = rt_tick_get() * 1000U / RT_TICK_PER_SECOND;
uint8_t hit = 0U;
for(uint8_t k=0; k<TOUCH_AREA_MODE_SELECT_NUM; k++)
{
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 )
{
hit = 1U;
LOG_I("UI", "mode_select hit area=%u row=%u x=%u y=%u",
(unsigned)k,
(unsigned)Touch_ModeSelect_Areas[k].Flag,
(unsigned)msg.HiByte, (unsigned)msg.LoByte);
/* 蓝牙开关不受进模式防抖限制 */
if (Touch_ModeSelect_Areas[k].ID == GUI_BL_SW)
{
Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag,
Touch_ModeSelect_Areas[k].ID, k);
break;
}
/* 单击直接进入对应模式主页 */
if (now - s_last_enter_ms < 300U)
break;
s_last_enter_ms = now;
Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag,
Touch_ModeSelect_Areas[k].ID, k);
break;
}
}
if (!hit) {
LOG_I("UI", "mode_select miss x=%u y=%u",
(unsigned)msg.HiByte, (unsigned)msg.LoByte);
}
}
break;
case MSG_ID_TOUCH_LONG_REPEAT:
/* 模式页暂无长按动作 */
break;
case MSG_ID_BATTERY_VALUE:
Draw_Status_Battery_Icon(msg.ID);
break;
case MSG_ID_POWOFF_CHARG:
{
/* 已开机:忽略滞后的关机充电消息,勿覆盖模式选择页或切断主电 */
if (powon)
break;
if(!s_charge_ui_drawn)
{
uint8_t peek[4];
BSP_MainPowerEnable(1);
LCD_WR_REG(0x29); /* Display on */
/* 先铺设计底色,避免外置 Flash 未烧充电图时整屏 0xFF 灰底 */
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
W25Q128_Read(peek, UI0902_CHARGE_SCREEN_ADDR, 4);
if (peek[0] != 0xFF || peek[1] != 0xFF)
{
/* 0904 全屏充电画面(UI0902 @ CHARGE_SCREEN);% 由固件叠画 */
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_CHARGE_SCREEN_W, UI0902_CHARGE_SCREEN_H,
UI0902_CHARGE_SCREEN_ADDR);
}
else
{
/* 资源未烧录时的兜底:圆环闪电(需稍后 flash ui0902) */
Draw_Charging_Icon(120, 150, 2, 0x3D7F);
LOG_W("UI", "charge flash empty @0x%08lX — flash ui0902",
(unsigned long)UI0902_CHARGE_SCREEN_ADDR);
}
LCD_BLK_Set();
s_charge_ui_drawn = true;
}
if(usb_charging_state)
{
/* MiSans Semibold 位图:数字与 % 同高对齐,对齐 0904 设计 */
char digits[4];
uint8_t n, i;
uint16_t total_w = g_ChargePctPercent.w;
uint16_t x, y = 266;
uint8_t pct = msg.ID;
if (pct > 100)
pct = 100;
n = (uint8_t)sprintf(digits, "%u", (unsigned)pct);
for (i = 0; i < n; i++)
total_w = (uint16_t)(total_w + g_ChargePctDigits[digits[i] - '0'].w);
LCD_FillByColor(40, 262, 200, 290, UI0902_BG_COLOR);
x = (uint16_t)((240 - total_w) / 2);
for (i = 0; i < n; i++)
{
const ChargePctGlyph *g = &g_ChargePctDigits[digits[i] - '0'];
LCD_WR_PIC_Trans(x, y, g->w, g->h, g->data, BLACK);
x = (uint16_t)(x + g->w);
}
LCD_WR_PIC_Trans(x, y, g_ChargePctPercent.w, g_ChargePctPercent.h,
g_ChargePctPercent.data, BLACK);
}
else
{
/* 关机充电中拔掉:熄屏,允许下次再进充电页 */
LCD_BLK_Clr();
LCD_FillByColor(0, 0, 240, 320, BLACK);
BSP_MainPowerEnable(0);
s_charge_ui_drawn = false;
}
}
break;
case MSG_ID_EC_VOL:
{
/* 主音量已在 MainTask 下发;此处只刷新条 */
level = msg.HiByte;
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
ResetAutoPowerCount();
}
break;
}
}