#include "ui_controler.hpp" #include #include #include #include // #include "tjc/tjc_constant.hpp" #include "tjc_event_processer_mgr.hpp" #include "ui_state_mgr.hpp" // using namespace iflytop; #define TAG "UIScheduler" #define MODULE_DEBUG 0 #define UART_RX_OVERTIME 5 #define CMD_OVERTIME 100 static ZThread uart_rx_thread; static ZThread rx_processed_thread; static ZThread ui_block_work_thread; static ZQueue ackQueue; static ZQueue eventQueue; static ZThread usartRxThread; static ZThread eventProcessThread; static bool m_isWaitingForAck; static UART_HandleTypeDef* tjcUart; static UIEvent event_cache; /*********************************************************************************************************************** * UTILS * ***********************************************************************************************************************/ static const char* zhex2str(uint8_t* data, size_t len) { static char buf[256]; memset(buf, 0, sizeof(buf)); for (size_t i = 0; i < len; i++) { sprintf(buf + i * 2, "%02X", data[i]); } return buf; } namespace iflytop { __weak void UIControlerHock_PageInit() {} } // namespace iflytop /*********************************************************************************************************************** * FUNC * ***********************************************************************************************************************/ void UIControler::doBlockWork(const char* blockmask, function fn) { ui_block_work_thread.start([fn, blockmask]() { UIPublicState::setLoadingState(true, blockmask); osDelay(10); fn(); UIPublicState::setLoadingState(false, ""); }); } void UIControler::postInitialize() { ackQueue.initialize(5, sizeof(tjc_rx_packet_t)); eventQueue.initialize(5, sizeof(tjc_rx_packet_t)); usartRxThread.init("UI_RX", 512); eventProcessThread.init("UI_RX_PROCESS", 1024); ui_block_work_thread.init("UI_WORK", 1024); tjcUart = AppHardware::ins()->tjcUart; UIPublicState::initialize(); m_cmdlock.init(); sendcmd("rest"); osDelay(1000); sendcmd("page %d", pg_pStart); } void UIControler::initialize() { // startSchedule(); } void UIControler::pageInitialize() { UIControlerHock_PageInit(); } void UIControler::callUsrEventCb(UIEvent* event) { static AppEvent appEvent; appEvent.type = KAE_UIEvent; appEvent.setUIEvent(event); AppEventBus::ins()->pushEventBlock("UIEvent", &appEvent); } void UIControler::startSchedule() { usartRxThread.start([this]() { static uint8_t rxbuf[256]; tjcUart->USR_UartITRxing = 1; tjcUart->USR_UartITRxBuf = rxbuf; tjcUart->USR_UartITRxBufSize = 256; tjcUart->USR_UartITRxOff = 0; HAL_UART_Receive_IT(tjcUart, &tjcUart->USR_UartITRxBufCache, 1); while (1) { static uint8_t processbuf[256]; int32_t rxsize = 0; if (tjcUart->USR_UartITRxOff != 0 && zos_haspassedms(tjcUart->USR_UartITLastRxTicket) > UART_RX_OVERTIME) { vPortEnterCritical(); if (tjcUart->USR_UartITRxOff != 0 && zos_haspassedms(tjcUart->USR_UartITLastRxTicket) > UART_RX_OVERTIME) { memcpy(processbuf, tjcUart->USR_UartITRxBuf, tjcUart->USR_UartITRxOff); rxsize = tjcUart->USR_UartITRxOff; tjcUart->USR_UartITRxOff = 0; } vPortExitCritical(); } if (rxsize != 0) { processScreenRxPacket(processbuf, rxsize); } osDelay(1); } }); eventProcessThread.start([this]() { while (1) { static tjc_rx_packet_t packet; bool suc = eventQueue.receive(&packet, 10); if (suc) { memset(&event_cache, 0, sizeof(event_cache)); tjc_packet_type_t packetType = (tjc_packet_type_t)packet.data[0]; auto* processer = TJCEventProcesserMgr::findProcesser((tjc_packet_type_t)packetType); // ZLOGI(TAG, "[eventprocess-thread]: rx_event:%s(%d)", tjc::pt2str(packetType), packetType); if (processer != nullptr) { processer->process(packet.data, packet.datalen, &event_cache); } else { event_cache.eventId = packet.data[0]; } // ZLOGI(TAG, "push event %s(%d) ", tjc::pt2str(event_cache.eventId), event_cache.eventId); callUsrEventCb(&event_cache); } osDelay(1); } }); } void UIControler::processScreenRxPacket(uint8_t* data, size_t len) { // 判断包是否合法 #if MODULE_DEBUG ZLOGI(TAG, "[rx-thread] : rx :%s(%d)", zhex2str(data, len), len); #endif if (!(data[len - 1] == 0xff && data[len - 2] == 0xff && data[len - 3] == 0xff)) { ZLOGI(TAG, "rx invalid packet %s", zhex2str(data, len)); return; } if (TJC_MAX_PACKET_SIZE < len) { ZLOGI(TAG, "rx invalid packet(tool long) %s", zhex2str(data, len)); return; } uint8_t packetType = data[0]; static tjc_rx_packet_t packet; packet.datalen = len; memcpy(packet.data, data, len); if (kpt_ack == packetType) { if (m_isWaitingForAck) { bool suc = ackQueue.send(&packet, 10); if (!suc) { ZLOGI(TAG, "ackQueue send failed"); } m_isWaitingForAck = false; } } else { bool suc = eventQueue.send(&packet, 10); if (!suc) { ZLOGI(TAG, "eventQueue send failed"); } } } bool UIControler::readTxt(uint8_t pid, uint8_t cId, char* txt, int32_t txtbuflen) { zlock_guard lg(m_cmdlock); startReceiveAck(); // sendcmd("com_stop"); sendcmd("printh AA"); sendcmd("prints p[%d].b[%d].txt,0", pid, cId); sendcmd("printh 00"); sendcmd("printh FF FF FF"); sendcmd("com_start"); bool suc = ackQueue.receive(&ackcache, CMD_OVERTIME); if (!suc) { ZLOGI(TAG, "readTxt failed"); return false; } int32_t cpysize = ackcache.datalen - 3; if (cpysize > txtbuflen) { cpysize = txtbuflen - 1; } memcpy(txt, &ackcache.data[1], cpysize); return true; } bool UIControler::readFiledAsInt(uint8_t pid, uint8_t bid, const char* filedName, int32_t* val) { for (int i = 0; i < 5; i++) { if (_readFiledAsInt(pid, bid, filedName, val)) { return true; } ZLOGW(TAG, "readFiledAsInt pid:%d bid:%d %s failed retry %d", pid, bid, filedName, i); osDelay(1000); } ZLOGE(TAG, "readFiledAsInt %s failed", filedName); return false; } bool UIControler::_readFiledAsInt(uint8_t pid, uint8_t bid, const char* filedName, int32_t* val) { zlock_guard lg(m_cmdlock); startReceiveAck(); // sendcmd("com_stop"); sendcmd("printh AA"); sendcmd("prints p[%d].b[%d].%s,4", pid, bid, filedName); sendcmd("printh FF FF FF"); // sendcmd("com_start"); bool suc = ackQueue.receive(&ackcache, CMD_OVERTIME); if (!suc) { return false; } uint8_t int32val[4] = {0}; memcpy(int32val, &ackcache.data[1], 4); *val = *(int32_t*)int32val; return true; } bool UIControler::readInt(uint8_t pid, uint8_t bid, int32_t* val) { return readFiledAsInt(pid, bid, "val", val); } bool UIControler::echo(uint8_t tx, uint8_t* rx) { zlock_guard lg(m_cmdlock); startReceiveAck(); // sendcmd("com_stop"); sendcmd("printh AA"); sendcmd("printh %02X", tx); sendcmd("printh FF FF FF"); sendcmd("com_start"); bool suc = ackQueue.receive(&ackcache, CMD_OVERTIME); if (!suc) { ZLOGI(TAG, "readTxt failed"); return false; } uint8_t int32val = 0; memcpy(&int32val, &ackcache.data[1], 1); *rx = int32val; if (tx != int32val) { return false; } return true; } bool UIControler::setTxt(uint8_t pid, uint8_t bid, const char* txt, ...) { zlock_guard lg(m_cmdlock); va_list args; va_start(args, txt); setTxt(pid, bid, txt, args); va_end(args); return true; } bool UIControler::setTxt(uint8_t pid, uint8_t bid, const char* txt, va_list args) { zlock_guard lg(m_cmdlock); static char buf[256]; memset(buf, 0, sizeof(buf)); vsprintf(buf, txt, args); sendcmd("p[%d].b[%d].txt=\"%s\"", pid, bid, buf); return true; } void UIControler::setPicturePicNum(uint8_t pid, uint8_t bid, uint8_t fromBid) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].pic=p[%d].b[%d].pic", pid, bid, pid, fromBid); } void UIControler::setButtonPicNum(uint8_t pid, uint8_t bid, uint8_t fromBid) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].pic=p[%d].b[%d].pic", pid, bid, pid, fromBid); sendcmd("p[%d].b[%d].pic2=p[%d].b[%d].pic2", pid, bid, pid, fromBid); } void UIControler::setPicturePicNumFromGlobal(uint8_t pid, uint8_t bid, uint8_t fromPid, uint8_t fromBid) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].pic=p[%d].b[%d].pic", pid, bid, fromPid, fromBid); } void UIControler::setButtonPicNumFromGlobal(uint8_t pid, uint8_t bid, uint8_t fromPid, uint8_t fromBid) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].pic=p[%d].b[%d].pic", pid, bid, fromPid, fromBid); sendcmd("p[%d].b[%d].pic2=p[%d].b[%d].pic2", pid, bid, fromPid, fromBid); } bool UIControler::setVal(uint8_t pid, uint8_t cid, int32_t val) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].val=%d", pid, cid, val); return true; } bool UIControler::vis(uint16_t buuid, int32_t val) { zlock_guard lg(m_cmdlock); sendcmd("vis %d,%d", buuid & 0xff, val); return true; } void UIControler::setrtc(zdate_t* date) { zlock_guard lg(m_cmdlock); sendcmd("rtc0=%d", date->year); sendcmd("rtc1=%d", date->month); sendcmd("rtc2=%d", date->day); sendcmd("rtc3=%d", date->hours); sendcmd("rtc4=%d", date->minutes); sendcmd("rtc5=%d", date->seconds); } void UIControler::popWin(UIPopWinType_t type, const char* info, function onConfirm) { zlock_guard lg(m_cmdlock); UIPublicState::pushUIPopInfo(type, info, onConfirm); } void UIControler::chpage(uint8_t page, bool triggerEvent) { zlock_guard lg(m_cmdlock); UIStateMgr::ins()->changePage(page); if (triggerEvent) { AppEventBus::ins()->pushPageChangeEvent(page); osDelay(10); } sendcmd("page %d", page); } void UIControler::sendcmd(const char* format, ...) { // static char buf[256]; va_list args; va_start(args, format); // vsprintf(buf, format, args); sendcmd(format, args); va_end(args); } void UIControler::sendcmd(const char* format, va_list args) { static char buf[1024]; memset(buf, 0, sizeof(buf)); vsprintf(buf, format, args); #if MODULE_DEBUG ZLOGI(TAG, "tx:%s", buf); #endif uint8_t len = strlen(buf); if (len > (1024 - 3)) { ZLOGI(TAG, "sendcmd too long"); return; } buf[len] = 0xff; buf[len + 1] = 0xff; buf[len + 2] = 0xff; // vPortEnterCritical(); // HAL_UART_Transmit_DMA(tjcUart, (uint8_t*)buf, len + 3); HAL_UART_Transmit(tjcUart, (uint8_t*)buf, len + 3, 100); // vPortExitCritical(); // while (true) { // osDelay(2); // if (tjcUart->gState == HAL_UART_STATE_BUSY_RX || tjcUart->gState == HAL_UART_STATE_READY) { // return; // } // } } void UIControler::startReceiveAck() { ackQueue.clear(); m_isWaitingForAck = true; } void UIControler::virtualClick(uint8_t pid, uint8_t bid, uint8_t event) { zlock_guard lg(m_cmdlock); sendcmd("click b[%d],%d", bid, event); } void UIControler::setTouchEnableState(uint8_t bid, uint8_t enable) { // tsw obj,state zlock_guard lg(m_cmdlock); sendcmd("tsw b[%d],%d", bid, enable); } void UIControler::setEnumComponentState(uint8_t pid, uint8_t bid, int32_t state) { // 枚举类型使用动画组件 sendcmd("p[%d].b[%d].tim=%d", pid, bid, state * 50); } void UIControler::setPic(uint8_t pid, uint8_t bid, int32_t picNum) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].pic=%d", pid, bid, picNum); } void UIControler::setAph(uint8_t pid, uint8_t bid, int32_t state) { zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].aph=%d", pid, bid, state); } bool UIControler::visEx(uint8_t pid, uint8_t bid, bool val) { zlock_guard lg(m_cmdlock); component_info_t* component = UIStateMgr::ins()->forceFindComponent(pid, bid); if (component == NULL) { ZLOGW(TAG, "visEx failed,component alloc failed"); return false; } bool suc = true; do { if (!component->isPosInited) { suc = readFiledAsInt(pid, bid, "x", &component->oldPosX); if (!suc) { for (size_t i = 0; i < 3; i++) { ZLOGE(TAG, "fatal error, reboot"); osDelay(1000); } NVIC_SystemReset(); } suc = readFiledAsInt(pid, bid, "y", &component->oldPosY); if (!suc) { for (size_t i = 0; i < 3; i++) { ZLOGE(TAG, "fatal error, reboot"); osDelay(1000); } NVIC_SystemReset(); } } if (val) { // 显示 if (!component->isVis) { sendcmd("p[%d].b[%d].x=%d", pid, bid, component->oldPosX); sendcmd("p[%d].b[%d].y=%d", pid, bid, component->oldPosY); component->isVis = true; } } else { if (component->isVis) { component->isPosInited = true; component->isVis = false; sendcmd("p[%d].b[%d].x=%d", pid, bid, -2000); sendcmd("p[%d].b[%d].y=%d", pid, bid, -2000); } } } while (false); return suc; } bool UIControler::movePicToXY(uint8_t pid, uint8_t bid, int32_t x, int32_t y) { sendcmd("p[%d].b[%d].x=%d", pid, bid, x); sendcmd("p[%d].b[%d].y=%d", pid, bid, y); return true; } bool UIControler::movePicTo(uint8_t pid, uint8_t bid, uint8_t toBid) { sendcmd("p[%d].b[%d].x=p[%d].b[%d].x", pid, bid, pid, toBid); sendcmd("p[%d].b[%d].y=p[%d].b[%d].y", pid, bid, pid, toBid); return true; } bool UIControler::movePicOutOfScreen(uint8_t pid, uint8_t bid) { sendcmd("p[%d].b[%d].x=%d", pid, bid, -2000); sendcmd("p[%d].b[%d].y=%d", pid, bid, -2000); return true; } /*********************************************************************************************************************** * 键盘 * ***********************************************************************************************************************/ void UIControler::popFullKeyBoard(uint8_t fromPid, uint8_t fromBid, int limitLength, const char* initval) { zlock_guard lg(m_cmdlock); UIStateMgr::ins()->setKeyboardFrom(fromPid, fromBid); sendcmd("p[%d].b[%d].val=%d", pg_keybdAP, ob_keybdAP_loadpageid, fromPid); sendcmd("p[%d].b[%d].val=%d", pg_keybdAP, ob_keybdAP_loadcmpid, fromBid); sendcmd("p[%d].b[%d].txt=\"%s\"", pg_keybdAP, ob_keybdAP_show, initval); sendcmd("p[%d].b[%d].val=%d", pg_keybdAP, ob_keybdAP_inputlenth, limitLength); sendcmd("p[%d].b[%d].pw=0", pg_keybdAP, ob_keybdAP_show); chpage(pg_keybdAP, false); } void UIControler::popPasswdKeyBoard(uint8_t fromPid, uint8_t fromBid, int limitLength) { zlock_guard lg(m_cmdlock); UIStateMgr::ins()->setKeyboardFrom(fromPid, fromBid); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_loadpageid, fromPid); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_loadcmpid, fromBid); sendcmd("p[%d].b[%d].txt=\"%s\"", pg_keybdB, ob_keybdB_show, ""); sendcmd("p[%d].b[%d].pw=1", pg_keybdB, ob_keybdB_show); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_inputlenth, limitLength); visEx(pg_keybdB, ob_keybdB_b11, false); // '-' visEx(pg_keybdB, ob_keybdB_b10, false); // '.' chpage(pg_keybdB, false); } void UIControler::popNumKeyBoard(uint8_t fromPid, uint8_t fromBid, int limitLength, const char* initval, ...) { zlock_guard lg(m_cmdlock); UIStateMgr::ins()->setKeyboardFrom(fromPid, fromBid); static char buf[60]; va_list args; va_start(args, initval); vsnprintf(buf, sizeof(buf), initval, args); va_end(args); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_loadpageid, fromPid); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_loadcmpid, fromBid); sendcmd("p[%d].b[%d].txt=\"%s\"", pg_keybdB, ob_keybdB_show, buf); sendcmd("p[%d].b[%d].pw=0", pg_keybdB, ob_keybdB_show); sendcmd("p[%d].b[%d].val=%d", pg_keybdB, ob_keybdB_inputlenth, limitLength); visEx(pg_keybdB, ob_keybdB_b11, true); // '-' visEx(pg_keybdB, ob_keybdB_b10, true); // '.' chpage(pg_keybdB, false); } void UIControler::popKeyBMutSel(uint8_t fromPid, uint8_t fromBid, int selectvalindex, const char** selectvals) { zlock_guard lg(m_cmdlock); static char contentbus[512]; memset(contentbus, 0, sizeof(contentbus)); for (int i = 0;; i++) { // \r\n 拼接字符串数组 if (selectvals[i] == nullptr) break; if (i == 0) { sprintf(contentbus, "%s", selectvals[i]); continue; } sprintf(contentbus, "%s\r\n%s", contentbus, selectvals[i]); } popKeyBMutSel(fromPid, fromBid, selectvalindex, contentbus); } void UIControler::popKeyBMutSel(uint8_t fromPid, uint8_t fromBid, int selectvalindex, const char* selectvals) { zlock_guard lg(m_cmdlock); UIStateMgr::ins()->setKeyboardFrom(fromPid, fromBid); sendcmd("p[%d].b[%d].val=%d", pg_keybMutSel, ob_keybMutSel_loadpageid, fromPid); sendcmd("p[%d].b[%d].val=%d", pg_keybMutSel, ob_keybMutSel_loadcmpid, fromBid); sendcmd("p[%d].b[%d].val=%d", pg_keybMutSel, ob_keybMutSel_ctent, selectvalindex); chpage(pg_keybMutSel, false); // 先切换页面,再设置选项 sendcmd("p[%d].b[%d].path=\"%s\"", pg_keybMutSel, ob_keybMutSel_ctent, selectvals); } void UIControler::popKeyBMutSelFix(uint8_t fromPid, uint8_t fromBid, int selectvalindex, const char* keyboardName, const char** selectvals) { int selectValsNum = 0; uint8_t pgNum = pg_keybMutSelFix; UIStateMgr::ins()->setKeyboardFrom(fromPid, fromBid); static uint8_t selbid_table[] = { ob_keybMutSelFix_b0, // ob_keybMutSelFix_b1, // ob_keybMutSelFix_b2, // ob_keybMutSelFix_b3, // ob_keybMutSelFix_b4, // ob_keybMutSelFix_b5, // ob_keybMutSelFix_b6, // ob_keybMutSelFix_b7, // ob_keybMutSelFix_b8, // ob_keybMutSelFix_b9, // ob_keybMutSelFix_b10, // ob_keybMutSelFix_b11, // ob_keybMutSelFix_b12, // ob_keybMutSelFix_b13, // ob_keybMutSelFix_b14, // }; static uint8_t selmaskbid_table[] = { ob_keybMutSelFix_t0, // ob_keybMutSelFix_t1, // ob_keybMutSelFix_t2, // ob_keybMutSelFix_t3, // ob_keybMutSelFix_t4, // ob_keybMutSelFix_t5, // ob_keybMutSelFix_t6, // ob_keybMutSelFix_t7, // ob_keybMutSelFix_t8, // ob_keybMutSelFix_t9, // ob_keybMutSelFix_t10, // ob_keybMutSelFix_t11, // ob_keybMutSelFix_t12, // ob_keybMutSelFix_t13, // ob_keybMutSelFix_t14, // }; for (int i = 0;; i++) { if (selectvals[i] == nullptr) break; selectValsNum++; } if (selectValsNum > sizeof(selbid_table) / sizeof(selbid_table[0])) { ZLOGE(TAG, "selectvals num is too large"); return; } if (selectvalindex >= selectValsNum) { ZLOGE(TAG, "selectvalindex is too large"); return; } zlock_guard lg(m_cmdlock); sendcmd("p[%d].b[%d].val=%d", pgNum, ob_keybMutSelFix_loadpageid, fromPid); sendcmd("p[%d].b[%d].val=%d", pgNum, ob_keybMutSelFix_loadcmpid, fromBid); sendcmd("p[%d].b[%d].val=%d", pgNum, ob_keybMutSelFix_val, selectvalindex); sendcmd("p[%d].b[%d].txt=%d", pgNum, ob_keybMutSelFix_txt, selectvals[selectvalindex]); sendcmd("p[%d].b[%d].txt=\"%s\"", pgNum, ob_keybMutSelFix_keybtil, keyboardName); chpage(pgNum, false); // 先切换页面,再设置选项 // 设置选项 for (int i = 0; i < selectValsNum; i++) { // visEx(pgNum, selbid_table[i], true); sendcmd("p[%d].b[%d].txt=\"%s\"", pgNum, selbid_table[i], selectvals[i]); } // 清空多余的选项 for (int i = selectValsNum; i < sizeof(selbid_table) / sizeof(selbid_table[0]); i++) { sendcmd("p[%d].b[%d].txt=\"\"", pgNum, selbid_table[i], selectvals[i]); } for (int i = 0; i < selectValsNum; i++) { movePicToXY(pgNum, selmaskbid_table[i], -100, -100); } for (int i = selectValsNum; i < sizeof(selbid_table) / sizeof(selbid_table[0]); i++) { movePicTo(pgNum, selmaskbid_table[i], selbid_table[i]); } }