#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; 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_POWER_OFF : break; //case MSG_ID_ADCIN1KEY : ADC_IN1_KEY_Handle(xEvent.ID);break; case MSG_ID_BP_KEY: if (!System_LowBat_IsActive()) Pick_Handle(); break; case MSG_ID_STOP_BAND: if (!System_LowBat_IsActive()) { if (xEvent.ID) Stop_AutoBand_Soft(); else Stop_AutoBand(); } break; case MSG_ID_START_FOLLOWUP: /* 停后补发:强制再 Start,勿因 NotifyPlayActivity 误判「在播」只换和弦 */ if (!System_LowBat_IsActive() && Band_TakeStartFollowup()) { Band_BeginStartFollowup(); Pick_Handle(); Band_EndStartFollowup(); } 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: /* 立即停声,再交给 UI 画提示;主循环 10s 后关机 */ Stop_AutoBand(); Send_volume(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 : ADC_IN1_KEY_Handle((uint8_t)xEvent.ID, true); break; case MSG_ID_KEY_1617 : 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); } } } } void TaskAutobandThread_entry(void* parameter) { for(;;) { while(!mymidififo_IsQueueEmpty(&m_MidiSendFifo)) { MidiFifoItem_t* pitem = mymidififo_DeQueue(&m_MidiSendFifo); SendMidiDataToDreamDSP(pitem->msg, pitem->msglen); //ResetAutoPowerCount(); } 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); } }