You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

645 lines
20 KiB

#include "ui_controler.hpp"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//
#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<tjc_rx_packet_t> ackQueue;
static ZQueue<tjc_rx_packet_t> 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<void()> 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<void(bool)> 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]);
}
}