#include "includes.h" static struct rt_thread TaskScanThread; static struct rt_thread TaskUIThread; static struct rt_thread TaskTouchThread; static struct rt_thread TaskMainThread; static struct rt_thread TaskBTHandleThread; static struct rt_thread TaskBTRecvThread; static struct rt_thread TaskAutobandThread; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskScanThread_Stack[512]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskUIThread_Stack[2048]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskTouchThread_Stack[1536]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskMainThread_Stack[512]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskBTTHandlehread_Stack[512]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskBTRecvThread_Stack[768]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskAutobandThread_Stack[512]; void TaskScanThread_entry(void* parameter) { while(1) { app_tm1629_Scan_Key(); app_tm1617_scan_key(); app_adc_scan_all(); app_tm1617_auto_loop(); rt_thread_mdelay(2); } } void TaskUIThread_entry(void* parameter) { DisplayTaskMessage_Type xEvent = {0,}; while(1) { if(rt_mq_recv(UITask_msg, &xEvent, sizeof(DisplayTaskMessage_Type), RT_WAITING_FOREVER) == RT_EOK) { /* BLE 写节奏风格:停伴奏+换库在任何页面都要执行,且必须在 UI 任务上下文 (TaskBTRecv 栈仅 768B,ReloadTone 深调用链会溢出;本地触控路径同在此任务) */ if (xEvent.MessageType == MSG_ID_BLE_STYLE_SET) { StartFlag = 0; UI_ReloadTonePreset(); /* 内含 Stop_AutoBand */ } /* 低电量提示:任意页面全屏覆盖;倒计时期间吞掉其它 UI 刷新,避免盖住提示 */ if (xEvent.MessageType == MSG_ID_LOW_BAT_TIP) { uint8_t peek[4]; LCD_WR_REG(0x29); LCD_BLK_Set(); LCD_FillByColor(0, 0, 240, 320, BLACK); W25Q128_Read(peek, UI0902_LOWBAT_TIP_ADDR, 4); if (peek[0] != 0xFF || peek[1] != 0xFF) { LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_LOWBAT_TIP_W, UI0902_LOWBAT_TIP_H, UI0902_LOWBAT_TIP_ADDR); } else { LOG_W("UI", "lowbat flash empty @0x%08lX — flash ui0902", (unsigned long)UI0902_LOWBAT_TIP_ADDR); } continue; } if (System_LowBat_IsActive()) continue; if (UI_IsSettingsPage() && (xEvent.MessageType == MSG_ID_TAP_SPEED || xEvent.MessageType == MSG_ID_BP_TRANSPOSE)) { UI_ApplyModeKeysOnSettings(xEvent); continue; } /* 任意页面的用户交互统一复位自动关机;避免各 Process 漏调/early-return 漏调 */ switch (xEvent.MessageType) { case MSG_ID_TOUCH: case MSG_ID_TOUCH_LONG_REPEAT: case MSG_ID_EC_VOL: case MSG_ID_TAP_SPEED: case MSG_ID_BP_TRANSPOSE: ResetAutoPowerCount(); break; default: break; } CurrUIProcress(xEvent); } } } void TaskTouchThread_entry(void* parameter) { static uint8_t s_last_pressed = 0; LOG_TPI("touch task running"); while(1) { TP_Point tp = TP_Read(); /* 已含轴交换/镜像,直接进手势 */ if (tp.pressed) { if (!s_last_pressed) { LOG_TPI("scan down x=%u y=%u", (unsigned)tp.x, (unsigned)tp.y); } } else if (s_last_pressed) { LOG_TPI("scan up"); } s_last_pressed = tp.pressed; app_touch_process(tp.x, tp.y, tp.pressed); TP_LivePoll(); app_log_poll(); Read_Cur_Measure(); rt_thread_mdelay(8); } } void TaskMainThread_entry(void* parameter) { DisplayTaskMessage_Type xEvent = {0,}; while(1) { if(rt_mq_recv(MainTask_msg, &xEvent, sizeof(DisplayTaskMessage_Type), RT_WAITING_FOREVER) == RT_EOK) { switch(xEvent.MessageType) { case MSG_ID_POWER_ON : UITask_Sendmsg(MSG_ID_POWER_ON, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; case MSG_ID_HEAVY_BOOT : UITask_Sendmsg(MSG_ID_HEAVY_BOOT, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; case MSG_ID_POWER_OFF : break; //case MSG_ID_ADCIN1KEY : ADC_IN1_KEY_Handle(xEvent.ID);break; case MSG_ID_BP_KEY: if (!System_LowBat_IsActive() && InModeFlag) Pick_Handle(); break; case MSG_ID_STOP_BAND: /* 停止键/偶拍收束:MainTask 串行硬停(已撤销软停) */ if (!System_LowBat_IsActive()) Stop_AutoBand(); break; case MSG_ID_START_FOLLOWUP: /* 软停补发路径已撤销;保留 case 以免旧固件消息号撞车 */ break; case MSG_ID_LOOP_LIGHT: if (!System_LowBat_IsActive()) Loop_Light_Handle(xEvent.ID); break; case MSG_ID_TM1629_KEY : break; case MSG_ID_TM1617_KEY : break; case MSG_ID_EC_VOL: /* 任意页面都先下发主音量,避免 UI 未处理导致屏显与实际脱节 */ if (!System_LowBat_IsActive()) Send_volume((uint8_t)xEvent.ID); UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; case MSG_ID_LOW_BAT_TIP: /* 立即停声并切掉音源/12V/蓝牙,避免提示的 10s 里继续把电池拉过保护电压 */ Stop_AutoBand(); Send_volume(0); Audio_AbortIfNotReady(); BSP_DreamCorePowerEnable(0); BSP_HT7178PowerEnable(0); BSP_BlueToothPowerEnable(0); System_LowBat_Arm(); UITask_Sendmsg(MSG_ID_LOW_BAT_TIP, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; case MSG_ID_TOUCH: case MSG_ID_CHARG: case MSG_ID_TAP_SPEED: case MSG_ID_BP_TRANSPOSE: case MSG_ID_POWOFF_CHARG: case MSG_ID_BATTERY_VALUE: case MSG_ID_TOUCH_LONG_REPEAT: case MSG_ID_BLE_UI_REFRESH: case MSG_ID_BLE_STYLE_SET: /* 业务消息:先做业务处理,再转发 UI 刷新 */ UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; default: break; } } } } void TaskBTHandleThread_entry(void* parameter) { DisplayTaskMessage_Type xEvent = {0,}; while(1) { if (rt_mq_recv(BLTask_msg, &xEvent, sizeof(DisplayTaskMessage_Type), RT_WAITING_FOREVER) == RT_EOK) { switch(xEvent.MessageType) { case MSG_ID_LIGHT_LED : BL_Set_led(xEvent.ID,xEvent.HiByte); break; case MSG_ID_PITCH_OFFSET : BT_Pitch_offset_map(xEvent.ID,xEvent.HiByte); break; case MSG_ID_CHORD_OFFSET : BT_Chord_offset_map(xEvent.ID,xEvent.HiByte); break; /* BLE section / intro-outro-end commands (06 xx, 04 07) */ case MSG_ID_ADCIN1KEY: if (InModeFlag) ADC_IN1_KEY_Handle((uint8_t)xEvent.ID, true); break; case MSG_ID_KEY_1617: if (InModeFlag) TM1617_Handle((uint8_t)xEvent.ID); break; } } } } void TaskBTRecvThread_entry(void* parameter) { uint8_t c; while(1) { if(rt_sem_take(UART4_sem, RT_WAITING_FOREVER) == RT_EOK) { while(UART4_RxPop(&c)) { UART4_Data_Process(&c); } } } } extern void App_Auto_LogHeldNotes(void); void TaskAutobandThread_entry(void* parameter) { for(;;) { int guard = mymidififo_GetQueueLength(&m_MidiSendFifo); uint16_t now = (uint16_t)wk_timebase_get(); while (guard-- > 0 && !mymidififo_IsQueueEmpty(&m_MidiSendFifo)) { MidiFifoItem_t* peek = mymidififo_TryDeQueue(&m_MidiSendFifo); MidiFifoItem_t item; uint16_t due; uint16_t ahead; if (peek == 0) break; item = *peek; due = item.delayCounter; ahead = (uint16_t)(due - now); /* delayCounter==0 立即发送;未到点的音挪到队尾,避免挡住鼓和低音 */ if (due != 0u && ahead != 0u && ahead < 0x8000u) { mymidififo_DeQueue(&m_MidiSendFifo); mymidififo_InQueue(&m_MidiSendFifo, &item); continue; } mymidififo_DeQueue(&m_MidiSendFifo); SendMidiDataToDreamDSP(item.msg, item.msglen); if (due != 0u) App_Auto_LogHeldNotes(); } rt_thread_mdelay(1); } } rt_err_t TaskInit(void) { rt_err_t ret = RT_EINVAL; TM1629_Mutex = rt_mutex_create("TM1629_Mutex",RT_IPC_FLAG_FIFO); TM1617_Mutex = rt_mutex_create("TM1617_Mutex",RT_IPC_FLAG_FIFO); UART4_sem = rt_sem_create("UART4_sem",0,RT_IPC_FLAG_FIFO); MainTask_msg = rt_mq_create("MainTask msgQ",sizeof(DisplayTaskMessage_Type),128,RT_IPC_FLAG_FIFO); UITask_msg = rt_mq_create("UITask msgQ",sizeof(DisplayTaskMessage_Type),128,RT_IPC_FLAG_FIFO); BLTask_msg = rt_mq_create("BLTask msgQ",sizeof(DisplayTaskMessage_Type),128,RT_IPC_FLAG_FIFO); if(MainTask_msg == RT_NULL || UITask_msg == RT_NULL) { LOG_E("BOOT", "mq create fail main=%p ui=%p", MainTask_msg, UITask_msg); } ret = rt_thread_init(&TaskScanThread, "TaskScanThread", TaskScanThread_entry, RT_NULL, &TaskScanThread_Stack, sizeof(TaskScanThread_Stack), 5, 20); ret = rt_thread_init(&TaskUIThread, "TaskUIThread", TaskUIThread_entry, RT_NULL, &TaskUIThread_Stack, sizeof(TaskUIThread_Stack), 5, 20); ret = rt_thread_init(&TaskTouchThread, "TaskTouchThread", TaskTouchThread_entry, RT_NULL, &TaskTouchThread_Stack, sizeof(TaskTouchThread_Stack), 5, 20); ret = rt_thread_init(&TaskMainThread, "TaskMainThread", TaskMainThread_entry, RT_NULL, &TaskMainThread_Stack, sizeof(TaskMainThread_Stack), 5, 20); ret = rt_thread_init(&TaskBTHandleThread, "TaskBTHandleThread", TaskBTHandleThread_entry, RT_NULL, &TaskBTTHandlehread_Stack, sizeof(TaskBTTHandlehread_Stack), 5, 20); ret = rt_thread_init(&TaskBTRecvThread, "TaskBTRecvThread", TaskBTRecvThread_entry, RT_NULL, &TaskBTRecvThread_Stack, sizeof(TaskBTRecvThread_Stack), 5, 20); ret = rt_thread_init(&TaskAutobandThread, "TaskAutobandThread", TaskAutobandThread_entry, RT_NULL, &TaskAutobandThread_Stack, sizeof(TaskAutobandThread_Stack), 4, 20); rt_thread_startup(&TaskMainThread); rt_thread_startup(&TaskUIThread); /* RTT LCD dump poller must run even before power-on / StartTouchTask. */ LCD_Dump_StartPoller(); return ret; } void StartTask(void) { /* 扫描任务可能已由 StartScanTask 拉起;重复 startup 会被 RT-Thread 忽略 */ StartScanTask(); /* Soft-off(StopFullTask) 会 detach 下列线程;开机须能重建,否则 UI/消息永久失效 */ if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_init(&TaskMainThread, "TaskMainThread", TaskMainThread_entry, RT_NULL, &TaskMainThread_Stack, sizeof(TaskMainThread_Stack), 5, 20); } if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT) rt_thread_startup(&TaskMainThread); if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_init(&TaskUIThread, "TaskUIThread", TaskUIThread_entry, RT_NULL, &TaskUIThread_Stack, sizeof(TaskUIThread_Stack), 5, 20); } if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT) rt_thread_startup(&TaskUIThread); if ((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_init(&TaskBTHandleThread, "TaskBTHandleThread", TaskBTHandleThread_entry, RT_NULL, &TaskBTTHandlehread_Stack, sizeof(TaskBTTHandlehread_Stack), 5, 20); } if ((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT) rt_thread_startup(&TaskBTHandleThread); if ((TaskBTRecvThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_init(&TaskBTRecvThread, "TaskBTRecvThread", TaskBTRecvThread_entry, RT_NULL, &TaskBTRecvThread_Stack, sizeof(TaskBTRecvThread_Stack), 5, 20); } if ((TaskBTRecvThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT) rt_thread_startup(&TaskBTRecvThread); if ((TaskAutobandThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_init(&TaskAutobandThread, "TaskAutobandThread", TaskAutobandThread_entry, RT_NULL, &TaskAutobandThread_Stack, sizeof(TaskAutobandThread_Stack), 4, 20); } if ((TaskAutobandThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT) rt_thread_startup(&TaskAutobandThread); } void StartTouchTask(void) { rt_uint8_t st = (rt_uint8_t)(TaskTouchThread.stat & RT_THREAD_STAT_MASK); XPT2046_Init(); app_touch_reset(); LOG_TPI("gpio reinit before touch task"); if (st == RT_THREAD_CLOSE) { rt_thread_init(&TaskTouchThread, "TaskTouchThread", TaskTouchThread_entry, RT_NULL, &TaskTouchThread_Stack, sizeof(TaskTouchThread_Stack), 5, 20); st = RT_THREAD_INIT; } if (st == RT_THREAD_INIT) { rt_thread_startup(&TaskTouchThread); LOG_TPI("touch task started stat=%u", (unsigned)TaskTouchThread.stat); } } void StartScanTask(void) { rt_uint8_t st = (rt_uint8_t)(TaskScanThread.stat & RT_THREAD_STAT_MASK); if (st == RT_THREAD_CLOSE) { rt_thread_init(&TaskScanThread, "TaskScanThread", TaskScanThread_entry, RT_NULL, &TaskScanThread_Stack, sizeof(TaskScanThread_Stack), 5, 20); st = RT_THREAD_INIT; } if (st == RT_THREAD_INIT) rt_thread_startup(&TaskScanThread); } void StopFullTask(void) { LOG_I("TASK", "StopFullTask begin"); if((TaskScanThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) { LOG_I("TASK", "stop ScanThread"); rt_thread_detach(&TaskScanThread); } /* 软关机 = 系统关闭:停触摸/扫描/BT/伴奏。 Main/UI 保留:Type-C 时要画 Charging Image,长按开机要收 POWER_ON。 */ if((TaskTouchThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) { LOG_I("TASK", "stop TouchThread"); rt_thread_detach(&TaskTouchThread); } if((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) { LOG_I("TASK", "stop BTHandleThread"); rt_thread_detach(&TaskBTHandleThread); } if((TaskBTRecvThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) { LOG_I("TASK", "stop BTRecvThread"); rt_thread_detach(&TaskBTRecvThread); } if((TaskAutobandThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) { LOG_I("TASK", "stop AutobandThread"); rt_thread_detach(&TaskAutobandThread); } LOG_I("TASK", "StopFullTask done"); } static void OutTime_Stop_timer_callback(void *parameter) { uint8_t AllNoteOff_buff[3] = {0xB0,0x7B,0x00}; SendMidiDataToDreamDSP(AllNoteOff_buff,sizeof(AllNoteOff_buff)); AutoBandTop1_Stop(); } void timer_init(void) { OutTime_Stop_timer = rt_timer_create("OutTimeStopTimer", OutTime_Stop_timer_callback, RT_NULL, 1000, RT_TIMER_FLAG_ONE_SHOT); if (OutTime_Stop_timer != RT_NULL) { rt_timer_stop(OutTime_Stop_timer); } }