/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-06-01 murmur the first version * 处理TT相关的初始化、状态切换等逻辑 */ #include #define LOG_TAG "core" #define LOG_LVL LOG_LVL_DBG #include #include #include //#include #include #include //static struct rt_event sw_check; //软件条件 static struct rt_event chkSta; //发送条件,含两部分,1-超时或文件准备好,2-TT满足通信条件 #define ALL_READY 1 //static int maxTTWaitTime = 4; //static int maxTTRetryCnt = 3; rt_sem_t TTReady= RT_NULL;//天通具备发送状态后 rt_sem_release(TTReady); rt_sem_t cfgUpdate = RT_NULL; rt_sem_t shuntDownTT = RT_NULL; rt_sem_t okTosend = RT_NULL; static rt_thread_t initThread=RT_NULL; static rt_thread_t deinitThread=RT_NULL; //void TTisReady(void) //{ // rt_sem_release(TTReady); //} SYS_CFG scfg={ .sendInterval =60, .maxTTWaitTime = 4, .maxTTRetryCnt = 3, .minTTPeriCnt=5, .minTTsinal=5, .timeout=5, .maxSizePerFile=1024, // .openWindowTime[]={0x02, 0x0F, 0x03, 0x1E, 0x08, 0x0F, 0x09, 0x1E} }; /** * 更新全局参数 */ static void updatecfg(void) { //因为不知原因,采用事件集独立更新配置出错,无精力深查 //独立响应单个参数更新事件,程序上更复杂也没特别必要 //现采用事件通知、统一全部重新加载 // memcpy(scfg.openWindowTime, while(1) { if(rt_sem_take(cfgUpdate, RT_WAITING_FOREVER) == RT_EOK) { scfg.maxTTWaitTime = get_cfg("maxTTWaitTime"); scfg.maxTTRetryCnt = get_cfg("maxTTRetryCnt"); scfg.minTTPeriCnt = get_cfg("minTTPeriCnt"); scfg.minTTsinal = get_cfg("minTTsinal"); scfg.timeout = get_cfg("timeout"); scfg.maxSizePerFile = get_cfg("maxSizePerFile"); char str[20]; get_cfgs("openWindowTime",str); size_t len = str2Byte(str, 3, 10, scfg.openWindowTime); //LOG_HEX("win",16,scfg.openWindowTime,8); updateAlarm(scfg.openWindowTime, len); } LOG_D("cfg updated."); } } void sysSemInit() { okTosend = rt_sem_create("okTosend", 0, RT_IPC_FLAG_PRIO); cfgUpdate = rt_sem_create("cfgUpdate", 0, RT_IPC_FLAG_PRIO); shuntDownTT = rt_sem_create("shuntDNTT", 0, RT_IPC_FLAG_PRIO); rt_event_init(&chkSta, "chkSta", RT_IPC_FLAG_PRIO); rt_sem_release(cfgUpdate); //上电更新值 updatecfg(); /* 创建 serial 线程 */ // rt_thread_t thread = rt_thread_create("updatecfg", updatecfg, RT_NULL, 1024 * 1, 27, 10); // /* 创建成功则启动线程 */ // if (thread != RT_NULL) // { // rt_thread_startup(thread); // } // else // { // LOG_E("thread 'updatecfg' create failure."); // return; // } // LOG_D("sysSemInit DONE."); } void sysEventInit(void) { rt_err_t result = rt_event_init(&chkSta, "chkSta", RT_IPC_FLAG_PRIO); if (result != RT_EOK) { LOG_E("init event failed.\n"); } } void sysInit(void) { sysSemInit(); // sysEventInit(); } //INIT_COMPONENT_EXPORT(sysInit); void timerIsReady(void) { rt_event_send(&chkSta, TIMER_IS_OUT); stopTM(); } void fileIsReady(void) { rt_event_send(&chkSta, FILE_IS_OK); stopTM(); } void TTIsReady(void) { rt_event_send(&chkSta, TT_IS_OK); stopTM(); } void d_upSta() { TTIsReady(); } //extern void ttinfoInit(void); //extern void startTTinfo(void); /** * 监控TT状态。需求条件1:TT连续5个周期为激活状态且信号强度不低于5。 */ void checkTT() { repGetTT(); //持续更新 } typedef struct { char fname[60]; uint8_t index; }FILE_INFO; static void upSendFile_thread_entry(void *parameter) { FILE_INFO *f = RT_NULL; f = (FILE_INFO *) parameter; static rt_uint8_t d[BUFFER_ROW][200] = { };//need static? static rt_uint8_t s[BUFFER_ROW] = { }; if (getFileSize(f->fname) > scfg.maxSizePerFile+200) { LOG_W("file '%s' is too large to send.",f->fname); clearFileToSend(f->fname); rt_sem_release(okTosend); return; } LOG_D("ready to send '%s---%d'",f->fname,f->index); rt_uint8_t len = pack_File(f->fname, 0, d, s); for (size_t i = 0; i < len; i++) { LOG_HEX("sendFile",27,d[i],s[i]); } // list_thread(); if (len)//部分demo数据体积>>1k { LOG_D("%d pack(s) to send", f->index ? 1 : len); for (rt_uint8_t var = 0; var < len; var++) { if (!f->index || (var+1) == f->index) { //index=0 全发,或者仅发index if (sendMsg(d[var], s[var]) == RT_EOK) { LOG_D("send pack[%d] done.",var+1); }; rt_thread_mdelay(3000);//发送间隔,目前服务器未处理,暂设为3s避免粘包 } } LOG_I("upSendFile done."); clearFileToSend(f->fname); // list_thread(); rt_sem_release(okTosend); } } /** * 发送文件 * @param f 待发文件,指完整路径名 * @param index 指定发送的切片索引,为0时表示全部发送 */ void upSendFile(const char *f, int index) { static FILE_INFO info; memset(&info, 0, sizeof(FILE_INFO)); strcpy(info.fname, f); info.index = index; /* 创建 serial 线程 */ rt_thread_t thread = rt_thread_create("SendFile", upSendFile_thread_entry, (void *) &info, 1024 * 3, 27, 10); /* 创建成功则启动线程 */ if (thread != RT_NULL) { rt_thread_startup(thread); } else { LOG_E("thread 'upSendFile' create failure."); return; } } void d_upSendFile(int argc, char **argv) { int index=0; if (argc == 3) { index = atoi(argv[2]); } upSendFile(argv[1], index); } /** * 获取本地待发文件列表并倒序发送 */ void getAndSendFile() { static int index[MAX_KEY_LEN]; static char f[10][MAX_KEY_LEN]; int cnt = getFilesToSend(f, index); if(cnt) { LOG_I("ready to send %d file(s).",cnt); } else { LOG_W("no files waiting to be sent."); return; } rt_sem_release(okTosend); while(cnt) { int i=0; for (i = cnt-1; i > -1; i--) { if (rt_sem_take(okTosend, RT_WAITING_FOREVER) == RT_EOK) { rt_thread_mdelay(1000);//thread close upSendFile(f[i],index[i]); } } if (i == -1) {//上一队列发送完成 cnt = getFilesToSend(f, index); } } //发送完毕 // rt_sem_take(sem, timeout) resetTM(); } static void chkAndSendFile_thread_entry() { while (1) { // int e; LOG_I("等待发送条件(文件就绪或定时%d分钟超时)",scfg.sendInterval); if (rt_event_recv(&chkSta, FILE_IS_OK | TIMER_IS_OUT, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL) == RT_EOK) //条件1满足 { LOG_I("等待TT就绪"); LOG_I("当前规则为:连续%d个采集周期TT信号质量不低于%d",scfg.minTTPeriCnt,scfg.minTTsinal); initTT(); } for (size_t var = 0; var < scfg.maxTTRetryCnt; var++) //轮询尝试 { LOG_I("第%d/%d次尝试。", var + 1,scfg.maxTTRetryCnt); int rst = rt_event_recv(&chkSta, TT_IS_OK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, rt_tick_from_millisecond(scfg.maxTTWaitTime*60*1000), RT_NULL); // rst = rt_sem_take(TTReady, rt_tick_from_millisecond(maxTTWaitTime * 60 * 1000)); if (rst == RT_EOK) //条件2满足 { LOG_I("TT准备就绪"); getAndSendFile(); break; } else if (rst == -RT_ETIMEOUT)//超时则重试 { if ((var+1) < scfg.maxTTRetryCnt) { LOG_W("第%d次尝试中TT准备失败,重试。", var + 1); deInitTT(); rt_thread_mdelay(15000); initTT(); } else { LOG_E("TT准备失败"); } } } } } /** * 检查状态并发送文件 */ void chkAndSendFile() { /* 创建 serial 线程 */ rt_thread_t thread = rt_thread_create("chk&send", chkAndSendFile_thread_entry, RT_NULL, 1024 * 2, 19, 10); /* 创建成功则启动线程 */ if (thread != RT_NULL) { rt_thread_startup(thread); } else { LOG_E("thread 'chk&send' create failure."); return; } } INIT_APP_EXPORT(chkAndSendFile); static rt_timer_t tmrToPNTT=RT_NULL; static uint8_t isWindowMode=0;//自动或手动引起TT开机 /** * 关闭超时定时器,定时时间到后关闭TT */ void stopTM() { if (!tmrToPNTT) { return; } rt_timer_stop(tmrToPNTT); rt_timer_stop(tmrToPNTT); } /** * 更新开窗flag以关闭超时机制 */ void setWindowMode(void) { isWindowMode = 1; stopTM(); } /** * 恢复超时机制 */ void clearWindowMode(void) { isWindowMode = 0; stopTM(); } /** * 重启超时定时器,定时时间到后关闭TT * 逻辑是非开窗(包括自动、手动)状态下TT无接收数据则启动关机倒计时 */ void resetTM() { // LOG_D("try to reset"); if (tmrToPNTT == RT_NULL) { return; } if (isWindowMode) { stopTM(); return; } rt_tick_t t= rt_tick_from_millisecond(scfg.timeout*60*1000); rt_timer_control(tmrToPNTT, RT_TIMER_CTRL_SET_TIME,(void*) &t); rt_timer_stop(tmrToPNTT); rt_timer_start(tmrToPNTT); LOG_D("%d minutes from now to power down TT.",scfg.timeout); } void d_remain() { if (tmrToPNTT == RT_NULL) { LOG_I("tmrToPNTT is NULL"); return; } rt_tick_t arg1,arg2; rt_timer_control(tmrToPNTT, RT_TIMER_CTRL_GET_TIME, (void*)&arg1); rt_timer_control(tmrToPNTT, RT_TIMER_CTRL_GET_REMAIN_TIME, (void*)&arg2); LOG_D("%d / %d min",arg2/60000,arg1/60000); } /* 定时器超时函数 */ static void timeoutFunc(void *parameter) { LOG_W("time to shunt down TT"); // rt_thread_mdelay(3000);// no delay deInitTT();//Function[rt_mutex_take] shall not be used in ISR // list_thread(); } //RT_TICK_PER_SECOND //tcp连接保活 //实际场景不存在中间断掉的可能 void initTT_thread_entry() { pwTT_thread_entry("1"); // rt_thread_mdelay(15000);//wait TT to boot up while (1) { if (!isTTon()) { break; } if (!tmrToPNTT) { tmrToPNTT = rt_timer_create("TTtimeout", timeoutFunc, RT_NULL, rt_tick_from_millisecond(scfg.timeout*60*1000), RT_TIMER_FLAG_ONE_SHOT);//|RT_TIMER_FLAG_SOFT_TIMER); } if (!isEthUP()) { //只初始化一次 LOG_D("init eth..."); rt_pin_write(ETH_RESET_PIN, PIN_HIGH); if (rt_hw_stm32_eth_init() == RT_EOK) { LOG_D("eth inited DONE."); // lwip_sys_init(); }; //激活网口 } else if (!isTCPok()) //判断TCP连接是否正常,异常自动重连 { // LOG_W("TT server is not ready,--%d",isTCPok()); // tcpInit(); if (tcpInit() != RT_EOK) { cmd_free(); } // rt_thread_mdelay(1000); if (isTCPok()) { LOG_D("TCP is ready."); tcpRecMQ(); //开启tcp接收线程 recTT(); repGetTT(); // upSendLoc(); // chkAndSendFile(); } } rt_thread_mdelay(3000); //chk with 3 second interval } initThread=RT_NULL; // list_thread(); // cmd_free(); } void deInitTT_thread_entry() { if (deinitThread != RT_NULL && rt_sem_take(shuntDownTT, RT_WAITING_FOREVER) == RT_EOK) { deinitThread =RT_NULL; tcpClose(); rt_hw_stm32_eth_deinit(); //qu激活网口 // rt_thread_mdelay(3000); pwTT_thread_entry("0"); // stopTM(); startAlarm(); clearWindowMode(); // if (0&& tmrToPNTT) // { // rt_timer_delete(tmrToPNTT); //关闭倒计时 // tmrToPNTT = RT_NULL; // } LOG_W("shunt down TT DONE"); } initThread = RT_NULL; deinitThread = RT_NULL; // list_thread(); // cmd_free(); } /** * TT上电,初始化TT相关的网络、TCP等,并保活 */ void initTT() { /* 创建 serial 线程 */ if (initThread != RT_NULL) { return; } initThread = rt_thread_create("initTT", initTT_thread_entry, RT_NULL, 1024 * 1.5, 20, 10); /* 创建成功则启动线程 */ if (initThread != RT_NULL) { rt_thread_startup(initThread); } else { LOG_E("thread 'initTT' create failure."); return; } /* 创建 serial 线程 */ if (deinitThread != RT_NULL) { return; } deinitThread = rt_thread_create("deInitTT", deInitTT_thread_entry, RT_NULL, 1024 * 2, 19, 10); /* 创建成功则启动线程 */ if (deinitThread != RT_NULL) { rt_thread_startup(deinitThread); } else { LOG_E("thread 'deInitTT' create failure."); return; } } /** * TT上电,初始化TT相关的网络、TCP等,并保活 */ void deInitTT() { rt_sem_release(shuntDownTT); } #define FUNC_DEMO #ifdef FUNC_DEMO //测试时导出命令到控制台 MSH_CMD_EXPORT_ALIAS(d_upSta,ttisok,TT_IS_OK); MSH_CMD_EXPORT(fileIsReady,fileIsReady); MSH_CMD_EXPORT(chkAndSendFile, chkAndSendFile); //MSH_CMD_EXPORT(upSendFile, upSendFile); MSH_CMD_EXPORT(initTT,初始化TT); MSH_CMD_EXPORT(deInitTT,去初始化TT); MSH_CMD_EXPORT(d_remain,剩余超时时间); MSH_CMD_EXPORT(resetTM,resetTM); MSH_CMD_EXPORT(d_upSendFile,d_upSendFile); #endif