K1Guitar/UI/UI_Idle.c

369 lines
13 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_G,
};
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;
/* 模式选择三行与演奏页移调卡不再共用 Y:演奏页按 0923-04 上移后仍保持本页 48/140/232 */
#define UI0902_MODE_ROW_X 9
#define UI0902_MODE_ROW_W 222
#define UI0902_MODE_ROW_H 88
#define UI0902_MODE_ROW_Y0 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)
{
InModeFlag = false; /* 模式选择页:未进入演奏模式,禁止伴奏起奏 */
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);
Dream_ApplyEditorParams();
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;
}
/* 音源板初始化要到秒级。没就绪就进模式,LoadConfig/拨片会打出不对的声音 */
if (!Audio_IsReady())
{
LOG_I("UI", "mode enter deferred: audio not ready");
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;
static uint8_t s_boot_led_done = 0;
/* Logo 保持到彩灯结束再进模式选择。电压未知或仍低于 6.8V 时留在 Logo,不点灯。 */
static void UI_BeginPerformancePower(void)
{
if (!powon || !app_adc_charge_ui_allowed() || s_boot_led_done)
{
if (powon && app_adc_charge_ui_allowed())
System_RequestAudioBringUp();
return;
}
s_boot_led_done = 1;
UI_BootLedShow();
System_RequestAudioBringUp();
UI_DrawModeSelectScreen();
StartTouchTask();
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
}
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();
s_boot_led_done = 0;
/* 先留 Logo。彩灯(蓝→青→红→绿,约 1.1s)播完才进模式选择 */
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
UI0902_BOOT_LOGO_ADDR);
/* 扫描先跑,才能采到包电压。电压已高于 6.8V 时这里就播彩灯并切模式页 */
StartScanTask();
UI_BeginPerformancePower();
break;
case MSG_ID_HEAVY_BOOT:
UI_BeginPerformancePower();
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:
if (!s_boot_led_done)
break;
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);
}
s_charge_ui_drawn = true;
Power_LogRails("charge-ui");
}
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);
/* 插入后先显示充电画面。高于 6.8V 一直亮;否则 10s 后关屏,充电继续 */
if (app_adc_charge_ui_allowed())
Power_ChargeBacklightSteady();
else
Power_ChargeBacklightLowHold();
}
else
{
/* 关机充电中拔掉:熄屏,允许下次再进充电页 */
Power_ChargeBacklightSessionReset();
LCD_BLK_Clr();
LCD_FillByColor(0, 0, 240, 320, BLACK);
BSP_MainPowerEnable(0);
s_charge_ui_drawn = false;
Power_LogRails("charge-unplug");
}
}
break;
case MSG_ID_EC_VOL:
{
/* 主音量已在 MainTask 下发;Logo 期间不画音量条 */
level = msg.HiByte;
if (!s_boot_led_done)
break;
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
ResetAutoPowerCount();
}
break;
}
}