TT12-MCU/applications/core.c

704 lines
19 KiB
C
Raw Normal View History

/*
* 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 <rtthread.h>
#define LOG_TAG "core"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
#include <board.h>
#include <ttmsg/ttmsg.h>
//#include <cfg.h>
#include <usrcfg.h>
2023-08-31 09:14:48 +00:00
#include <ttTR/ttTR.h>
//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;//关闭TT
rt_sem_t okTosend = RT_NULL;//可以发送后续文件
rt_sem_t okToreport = RT_NULL;//配置信息ACK
static rt_thread_t initThread=RT_NULL;
static rt_thread_t deinitThread=RT_NULL;
static rt_timer_t tmrToPNTT=RT_NULL;
static uint8_t isWindowMode=0;//自动或手动引起TT开机
//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 initCfg(void)
{
//无配置文件则新建
int fd = open(LJW_CFG_FILE_NAME, O_RDONLY);
if (fd < 0)
{
close(fd);
const char *cfgstr =
"[config]\n"
"# V1.83\n"
"#定时(默认每小时)上报时刻,\n"
"sendInterval=15\n"
"# 最大文件大小,超过此大小则进入发送流程\n"
"maxSizePerFile=1024 \n"
"# 最小等待时间S超时后进入待机模式暂未使用\n"
"minSecToSleep=30 \n"
"# TT最长等待激活时间M超时后重启\n"
"maxTTWaitTime=10\n"
"# TT最大重试次数\n"
"maxTTRetryCnt=3\n"
"# TT最低信号值\n"
"minTTsinal=3\n"
"# TT状态检测周期数连续满足归为一次判决减少波动的影响\n"
"minTTPeriCnt=3\n"
"# 压缩方式0-不压缩\n"
"compressType=0\n"
"# 加密方式0-不加密\n"
"encrytType=1\n"
"# 开窗时间UTC+8,持续时间H。以【,】为分隔符\n"
"openWindowTime=02,15,03,30,08,15,09,30\n"
"#超时时间M主动开机上报数据情况下最后一次通信后开始计时超时后关闭TT\n"
"timeout=5\n"
"# 工作模式1-TT2-BD\n"
"commMode=1\n"
"# 自毁功能开关1-开启0-跟关闭\n"
"selfDesSW=0\n"
"# 位置告警功能开关1-开启0-关闭\n"
"locAlert=1;\n"
"# 定时上报位置信息间隔M\n"
"locRepInterval=5\n"
"[stats]\n"
"# 继电器开关次数影响继电器寿命10W次\n"
"swCnt=12\n"
"# 第一次上电就满足硬件条件的次数,\n"
"oneShotCnt=0\n"
"# 重启次数\n"
"bootCnt=13\n"
"# 发送总次数,由软件条件触发\n"
"sendCnt=0\n"
"# TT初始化失败次数由MaxRetryCnt次失败后触发\n"
"errCnt=0\n"
"# 最短激活时间\n"
"minActiveTime=0\n"
"# 最长激活时间\n"
"maxActiveTime=0\n"
"# 平均激活时间,暂不考虑实现\n"
"meanActiveTime=0\n"
"# 总定时器超时次数\n"
"allCnt=0\n"
"# 发送成功次数\n"
"okCnt=0\n";
LOG_W("no cfg file found, creat one.");
fd = open(LJW_CFG_FILE_NAME, O_WRONLY | O_CREAT | O_APPEND);
if (fd > 0) {
write(fd, cfgstr, strlen(cfgstr));
close(fd);
}
else {
LOG_E("failed to creat cfg file.");
}
}
else {
close(fd);
}
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");
scfg.locRepInterval = get_cfg("locRepInterval");
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.");
}
static void updatecfg(void)
{
//等待更新
while(1)
{
rt_thread_mdelay(10*1000);//10s写入一次数据到文件
if(rt_sem_take(cfgUpdate, RT_WAITING_NO) == RT_EOK)
{
updateAllSysCfg(&scfg, 0);
}
}
}
void sysSemInit()
{
okTosend = rt_sem_create("okTosend", 0, RT_IPC_FLAG_FIFO);//同一时间仅一个线程发送文件
cfgUpdate = rt_sem_create("cfgUpdate", 0, RT_IPC_FLAG_FIFO);//更新cfg
shuntDownTT = rt_sem_create("shuntDNTT", 0, RT_IPC_FLAG_FIFO);//关闭TT
okToreport = rt_sem_create("reportINFO", 0, RT_IPC_FLAG_FIFO);//关闭TT
// rt_event_init(&chkSta, "chkSta", RT_IPC_FLAG_FIFO);//检查天通状态
// rt_sem_release(cfgUpdate); //上电更新值
initCfg();
// void reportINFO();
reportINFO();
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("updatecfg", updatecfg, RT_NULL, 1024 * 5, 27+1, 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();
if (isInWindowZone()) {//开机检查是否在开窗区间内是则给TT开机
initTT();
setWindowMode();
}
}
//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);
// resetTM();
}
/**
* TT
*/
void stopTM(void)
{
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 d_remain(void);
void resetTM(void)
{
// LOG_D("try to reset");
if (tmrToPNTT == RT_NULL) {
LOG_E("tmrToPNTT is NULL");
return;
}
if (isWindowMode) {
stopTM();
LOG_W("TIMEOUT stopped.[isWindowMode]");
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);
int i=0;
while(rt_timer_start(tmrToPNTT) != RT_EOK)
{
if (i++ > 10) {
LOG_E("TIMEOUT fault.");
return;
break;
}
rt_thread_mdelay(200);
}
LOG_W("%d minutes from now to power down TT.",scfg.timeout);
// d_remain();
// rt_thread_mdelay(500);
// d_remain();
// rt_thread_mdelay(500);
// d_remain();
// rt_thread_mdelay(500);
// d_remain();
}
void d_remain(void)
{
if (tmrToPNTT == RT_NULL) {
LOG_W("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);
rt_uint32_t arg3=0;
rt_timer_control(tmrToPNTT, RT_TIMER_CTRL_GET_STATE, (void*)&arg3);
LOG_D("%s",arg3?"YES":"NO");
if (arg3) {
int tmp=(arg2-rt_tick_get())/1000;
LOG_D("t=%ld,0x%X -> 0x%X",tmp,rt_tick_get(),arg2);
LOG_D("%dm%ds / %d min",tmp/60,tmp%60,arg1/60000);
}
}
/* 定时器超时函数 */
static void timeoutFunc(void *parameter)
{
stopTM();
if (!deinitThread) {
LOG_W("timeout leads to shunt down TT");
// rt_thread_mdelay(3000);// no delay
deInitTT();//Function[rt_mutex_take] shall not be used in ISR
}
}
2023-06-02 06:37:58 +00:00
//extern void ttinfoInit(void);
//extern void startTTinfo(void);
/**
* TT状态1TT连续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) {//部分demo数据体积>>1k
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("msg",27,d[i],s[i]);
}
// list_thread();
if (len)
{
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 '%s' done.",f->fname);
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;
rt_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
{
2023-07-26 08:26:53 +00:00
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[5][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.");
resetTM();//启动超时
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]);
}
}
rt_thread_mdelay(3000);
if (rt_sem_take(okTosend, RT_WAITING_FOREVER) == RT_EOK) {//等待上一轮最后一个文件发送完毕
cnt = getFilesToSend(f, index);
}
}
//发送完毕
// rt_sem_take(sem, timeout)
LOG_D("mission done.");
resetTM();
}
2023-07-26 08:26:53 +00:00
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满足
{
2023-06-16 08:20:18 +00:00
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准备失败");
}
}
}
LOG_W("--------one mission DONE--------");
}
}
/**
*
*/
2023-07-26 08:26:53 +00:00
void chkAndSendFile()
{
sysEventInit();//必须此处初始化不然EVENT无法加入链表
if (!tmrToPNTT) {
tmrToPNTT = rt_timer_create("TTtimeout", timeoutFunc,
RT_NULL, rt_tick_from_millisecond(scfg.timeout*60*1000),
RT_TIMER_FLAG_PERIODIC);//|RT_TIMER_FLAG_SOFT_TIMER);
}
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("chk&send", chkAndSendFile_thread_entry, RT_NULL, 1024 * 5, 19, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
2023-07-26 08:26:53 +00:00
LOG_E("thread 'chk&send' create failure.");
return;
}
}
INIT_APP_EXPORT(chkAndSendFile);
//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),
2023-08-03 03:04:50 +00:00
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();
if (isEthUP()) {
LOG_D("retry.");
rt_hw_stm32_eth_deinit();
rt_hw_stm32_eth_init();
}
}
// rt_thread_mdelay(1000);
if (isTCPok())
{
LOG_D("TCP is ready.");
tcpRecMQ(); //开启tcp接收线程
recTT();
repGetTT();
2023-08-25 08:36:00 +00:00
reportLoc();
// resetTM();//启动超时,激活后开启
}
}
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();
if (isEthUP()) {
rt_hw_stm32_eth_deinit(); //qu激活网口
}
pwTT_thread_entry("0");
// startAlarm();//alarm 引起崩溃
clearWindowMode();
LOG_W("shunt down TT DONE");
}
// initThread = RT_NULL;
deinitThread = RT_NULL;
// list_thread();
}
/**
* TT上电TT相关的网络TCP等
*/
void initTT()
{
/* 创建 serial 线程 */
if (initThread != RT_NULL) {
LOG_W("initThread 未退出");
return;
}
2023-08-25 08:36:00 +00:00
initThread = rt_thread_create("initTT", initTT_thread_entry, RT_NULL, 1024 * 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;
}
2023-08-25 08:36:00 +00:00
deinitThread = rt_thread_create("deInitTT", deInitTT_thread_entry, RT_NULL, 1024 * 5, 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(TTIsReady,ttisok,TT_IS_OK);
MSH_CMD_EXPORT(fileIsReady,fileIsReady);
//MSH_CMD_EXPORT(chkAndSendFile, chkAndSendFile);
//MSH_CMD_EXPORT(getAndSendFile, getAndSendFile);
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