TT12-MCU/applications/func/func.c
CSSC-WORK\murmur 1a14d5b193 更新为5s一发
添加对232接收断帧数据的处理
更新对不符合帧格式数据的处理方式,改为透传
2024-01-15 18:27:37 +08:00

1944 lines
52 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-07-06 murmur the first version
*/
#include "func.h"
#define LOG_TAG "func"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
extern SYS_CFG scfg;
extern int cryptSingleMsg(uint8_t *din, size_t len, uint8_t *dout);
extern int pointInPolygon(int polyCorners,float polyX[], float polyY[],float x,float y);
extern rt_sem_t okToreport;
extern void resetTM(void);
unsigned long getFileSize(char *file);
void updateSysRTC(uint8_t *din, size_t len);
int isFileExit(char *f);
#define CFG_ACK
/**
* 配置文件后的ack信号
*/
void ack(void)
{
#ifdef CFG_ACK
rt_sem_release(okToreport);
#endif
}
/**
* 将收发数据以ASCII字符形式存入log
* @param din 待存储数据
* @param len 数据长度
* @return 1-发送的数据0-接收的数据,其它为发送失败的数据
*/
int trDataTolog(uint8_t *din, size_t len, uint8_t isTx)
{
// return RT_EOK;
char fn[60];
initDataLogPath(fn);
int fd = open(fn, O_WRONLY | O_CREAT | O_APPEND);
//没有加锁,多试几次再报错
int trycnt=0;
while (fd < 0)
{
rt_thread_mdelay(200);
fd = open(fn, O_WRONLY | O_CREAT | O_APPEND);
trycnt +=1;
if (trycnt>5) {
break;
}
}
if (fd<0) {
LOG_E("open file %s failed!", fn);
return -RT_ERROR;
}
else
{
char log[30]="\n";
getTimestmp(log+1);
strcat(log,isTx?" [T]: ":" [R]: ");
write(fd, log, strlen(log));
uint8_t tmp[1024];
len = cryp_data(din, len, tmp);//加密数据
bytes2str(tmp, len, 16, "", tmp);
len = strlen(tmp);
int rst = write(fd, tmp, len);
if (rst != len)
{
LOG_E("write to file %s failed!", fn);
close(fd);
return -RT_ERROR;
}
close(fd);
return RT_EOK;
}
}
extern rt_sem_t cfgUpdate;
//3.2.1双模通信功能
//1为TT通信0为BD短报文通信
void setCommMode(int isTT)
{
LOG_I("FUNC = setCommMode");
if (isTT) {
//change mode
}
else {
}
//write to cfg file
// set_cfg("commMode", isTT);
scfg.commMode=isTT;
rt_sem_release(cfgUpdate);
LOG_D("set commMode to %s",isTT?"TT":"BD");
ack();
}
int getCommMode()
{
//load from cfg file
// int flag = get_cfg("commMode");
// if (flag < 0) {
// LOG_W("get mode fault.");
// }
// return flag;
return scfg.commMode;
}
//3.2.2状态自检
/**
* 获取磁盘剩余空间大小单位MB
* @param path指定磁盘挂载的路径为空时表示挂载在根目录的磁盘
* @return 返回结果单位MB
*/
static uint16_t getFreeSpace(const char *path)
{
long long cap;
struct statfs buffer;
int result = dfs_statfs(path ? path : "/", &buffer);
if (result != 0)
{
LOG_E("dfs_statfs failed.");
return 0;
}
cap = (uint16_t)((long long)buffer.f_bsize) * ((long long)buffer.f_bfree) / 1024LL / 1024LL ;//转换为MB
return cap;
}
void d_getFreeSpace()
{
LOG_D("free space of flash is %d MB.",getFreeSpace(NULL));
uint16_t rst = getFreeSpace("/sd");
LOG_D("free space of sd is %d MB.%02X,%02X",rst,rst>>8,rst&0xff);
}
/**
* 獲取電池電量。
* @return 返回電量百分比
*/
RT_WEAK int getPowerLevel(void)
{
return 0x63;
}
typedef struct
{
uint16_t len;
rt_uint8_t data[300];
} SMSG;//single messgae
rt_sem_t one_msg_send_done=RT_NULL;
void upSend_thread_entry(void* parameter)
{
SMSG* msg = RT_NULL;
msg = (SMSG*) parameter;
// LOG_D("1--%p",msg);
// LOG_HEX("--",16,msg->data,msg->len);
//check status
#define CHK_STA
#ifdef CHK_STA
uint8_t trycnt = 0;
while (!isTTjh()) //判断TT状态
{
rt_thread_mdelay(4000);
trycnt += 1;
if (trycnt > 3)
{
break;
}
}
if (!isTTjh()) {
//cache to file
LOG_W("TT is not ready, try to cache %d bytes data to file.",msg->len);
cacheDataToFile(msg->data, msg->len);
return ;
}
#endif
//打包数据
uint8_t dout[300];
static MSG cfg;
rt_memset(&cfg, 0, sizeof(MSG)); // 分配空间
char fin[30];
time2Str(fin);
strcat(fin,".bin");
packInit(&cfg, fin, 0); //写入配置
cfg.fcurpiece[0] = 1;
cfg.fallpiece[0] = msg->len/FRAME_DATA_LEN_MAX+1;
#ifdef CRYPT_BEFRE_PACK
//crypt before pack
//更改后3S单帧数据升为200+超出TT最大单包数据容量须分包
for (size_t var = 0; var < msg->len; var=var+FRAME_DATA_LEN_MAX) {
cfg.fcurpiece[0] = var/FRAME_DATA_LEN_MAX+1;
static uint8_t tmp[200];
uint8_t tlen = (msg->len-var)>FRAME_DATA_LEN_MAX?FRAME_DATA_LEN_MAX:(msg->len-var);
uint8_t len = cryptSingleMsg(msg->data+var, tlen, tmp);
// LOG_HEX("2",16,msg->data+var,tlen);
size_t rst = packMsg(&cfg, tmp, len, dout);//引起数据异常
#else
size_t rst = packMsg(&cfg, tmpmsg->data, msg->len, dout);//packMsgs
#endif
// LOG_HEX("upSend", 27, dout, rst);
if (rst)
{
if (sendMsg(dout, rst) == RT_EOK)
{
LOG_I("send %d bytes to TT Done.",rst);
}
else//发送失败,实例不存在此种情况
{
LOG_E("send error, try to cache %d bytes data to file.",msg->len);
cacheDataToFile(msg->data, msg->len);
break;
}
}
}
// rt_sem_release(one_msg_send_done);
// list_thread();
return ;
}
/**
* 上傳单帧天通數據
* @param din 待發送數據
* @param len 待發送數據的長度
* @return
*/
int upSend(uint8_t *din, size_t len)
{
LOG_D("try to upsend to TT.");
//return;
// if (one_msg_send_done == RT_NULL) {
// one_msg_send_done = rt_sem_create("senddone", 1, RT_IPC_FLAG_PRIO);
// }
static SMSG msg;
rt_memset(&msg, 0, sizeof(SMSG));
rt_memcpy(msg.data,din,len);
msg.len=len;
// LOG_D("0--%p",&msg);
//仅创建一个线程用于发送
// if (rt_sem_take(one_msg_send_done, rt_tick_from_millisecond(10000)) != RT_EOK) {
// //10s等待上一发送仍未完成
// LOG_E("wait error, try to cache %d bytes data to file.",msg.len);
// cacheDataToFile(msg.data, msg.len);
// return -RT_ERROR;
// }
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("upSend", upSend_thread_entry, (void *) &msg, 1024 * 5, 26, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
return RT_EOK;
}
else
{
LOG_E("thread 'upSend' create failure.");
return -RT_ERROR;
}
}
/**
* 系统自检,自动发送自检结果
*/
void selfTest(void)
{
// return;
LOG_I("FUNC = selftest");
rt_uint8_t rst[200]={0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _CMD_SELF_TEST>>8, _CMD_SELF_TEST & 0xff};
int p = 6;
rt_uint8_t sysSta=1,commSpeed=0;
//长度
rst[p++]=0x00;
rst[p++]=0x09;
rst[p++] = sysSta; //系统状态
rst[p++] = getXh();//xh,jh //信号值
rst[p++] = isTTjh(); //激活
rst[p++] = commSpeed; //速率
// rst[p++] = scfg.commMode;
rst[p++] = getPowerLevel(); //电量
//flash 剩餘空間 //FLASH剩余空间
uint16_t cap = getFreeSpace("/");
rst[p++] = (uint8_t)(cap >> 8);
rst[p++] = (uint8_t)(cap & 0xff);
//SD卡剩餘空間
cap = getFreeSpace("/sd"); //SD卡剩余空间
rst[p++] = (uint8_t)(cap >> 8);
rst[p++] = (uint8_t)(cap & 0xff);
//添加配置文件信息
uint8_t size = sizeof(scfg); //配置文件信息
memcpy(rst + p,&scfg, size);
p+=size;
rst[7] = p-8;//更新数据长度
rst[p++] = bccCRC(rst+2, p-1); ////校验位为1个字节采用异或运算从指令的第3个字节开始到奇偶校验位的前一个字节结束
rst[p++] = 0xED; //结束位
// LOG_HEX("selfTestRes",16,rst,p);
//发送结果
upSend(rst,p);
}
//3.2.3日志记录
//日志功能由各函数通过LOG_D()实现
//3.2.4自毁功能
/**
* 设置自毁功能开关
* @param setON 1-自毁功能开启0-关闭
*/
void setSelfDestructSWT(int setON)
{
LOG_I("FUNC = set selfdestruct");
//write to cfg file
// set_cfg("selfDesSW", setON);
scfg.selfDesSW=setON;
rt_sem_release(cfgUpdate);
LOG_D("set SelfDesSW to %s",setON?"ON":"OFF");
}
/**
* 获取自毁开关状态
* @return 1-自毁功能开启0-关闭
*/
int getSelfDestructSWT()
{
LOG_I("FUNC = get selfdestruct");
//load from cfg file
// int flag = get_cfg("selfDesSW");
// if (flag < 0) {
// LOG_W("get mode fault.");
// }
// return flag;
return scfg.selfDesSW;
}
/**
* 启动自毁
*/
void selfDestruct()
{
if (getSelfDestructSWT()) {
//硬件自毁
LOG_W("SELF DESTRUCT START.");
}
}
//3.2.5开、关窗功能
extern void updateAlarm(uint8_t *t, size_t len);
/**
* 更新开窗时间,目前支持两组开窗时段。更新会清除之前的开窗设置
*/
void setCommWindow(uint8_t *t, size_t len)
{
LOG_I("FUNC = setCommWindow");
size_t cnt = sizeof(scfg.openWindowTime);
if (len>cnt) {
LOG_W("only support %d windows",cnt/4);
len = cnt;
}
len= len/4*4;//窗口需要成对
updateAlarm(t,len);
if (isManualWindow()) {
stopAlarm();
}
else {
startAlarm();
}
memset(scfg.openWindowTime,0,sizeof(scfg.openWindowTime));
memcpy(scfg.openWindowTime,t,len);
// rt_sem_release(cfgUpdate);
char tmpstr[len*3];
bytes2str(t, len, 10, ",", tmpstr);
set_cfgs("openWindowTime",tmpstr);
// LOG_D("updated new CommWindow zone");
ack();
}
void d_demo(int argc, char **argv)
{
if (argc == 2)
{
int fd = open(argv[1], O_RDONLY, 0);
if (fd < 0)
{
LOG_E("open the input file : %s error!\n", argv[1]);
return;
}
rt_uint16_t file_size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
rt_uint8_t *buffer = RT_NULL;
buffer = (rt_uint8_t *) malloc(file_size);
if (!buffer)
{
LOG_E("No memory for reading file!\n");
close(fd);
return;
}
read(fd, buffer, file_size);
close(fd);
upSend(buffer, file_size);
rt_free(buffer);
}
}
/**
* 存储手动开窗状态,便于意外重启后恢复状态
* @param isManualWindow 负数代表无0代表手动开窗不自动关整数代表自动关窗超时时间
*/
void setManualWindow(int isManualWindow)
{
scfg.isMaWin = isManualWindow;
set_cfg("isMaWin", isManualWindow);
}
void closeWindow(void);
/**
* 是否手动开窗状态
* @return 1-手动开窗模式0-无
*/
int isManualWindow(void)
{
int rst = scfg.isMaWin;
if (rst >= 0) {
rst = 1;
LOG_I("is in manual open mode.");
}
else {
rst = 0;
}
return rst;
}
void checkManualWindow(void)
{
int rst = scfg.isMaWin;
if (rst < 0) {//none
return;
}
stopAlarm();
if (rst == 0) {//manual open without auto close
return;
}
//设置定时器,定时器到则关窗
/* 创建定时器,单次定时器 */
rt_timer_t timer1;
timer1 = rt_timer_create("manualModeWindow", closeWindow,
RT_NULL, rt_tick_from_millisecond(rst*60*1000),
RT_TIMER_FLAG_ONE_SHOT);
/* 启动定时器 */
if (timer1 != RT_NULL)
{
rt_timer_start(timer1);
LOG_D("手动开窗完成,%d分钟后自动关窗。",rst);
}
return;
}
/**
* 手动控制开窗
* @param t 开窗时长单位分钟时间到则自动关窗。t=0时需要手动关窗。
*/
void openWindow(int t)
{
//保存记录
setManualWindow(t);
//开启TT
initTT();
// setWindowMode();
//手动开窗优先级最高,自动开窗其次,高优先级会屏蔽低优先级
stopAlarm();
if (!t) {
LOG_D("手动开窗完成,需手动关窗。");
// return;
}
else {
//设置定时器,定时器到则关窗
/* 创建定时器,单次定时器 */
rt_timer_t timer1;
timer1 = rt_timer_create("manualWin", closeWindow,
RT_NULL, rt_tick_from_millisecond(t*60*1000),
RT_TIMER_FLAG_ONE_SHOT);
/* 启动定时器 */
if (timer1 != RT_NULL)
{
rt_timer_start(timer1);
LOG_D("手动开窗完成,%d分钟后自动关窗。",t);
}
}
ack();
}
/**
* 手动关窗
*/
void closeWindow(void)
{
setManualWindow(-1);
// 恢复RTC
startAlarm();
deInitTT();
LOG_D("手动关窗完成。");
}
//3.2.6工作参数配置、状态查询
//包含浮体自身、标体透传、两者结合
//这里主要实现浮体自身
//浮体自身的参数配置各功能函数有实现,此处需规定参数下发协议和解码实现
//获取当前位置
/**
* 获取当前经纬度信息
* @param dout 存储结果的数组
* @param cnt 获取几组位置数据
* @return 数组长度。0表示位置数据未准备好。
*/
RT_WEAK int getLoc(uint8_t * dout, size_t cnt)
{
LOG_D("待实现获取位置函数此处以0xCD代替");
uint8_t tmp[200];
memset(tmp,0xCD,200);
memcpy(dout,tmp,cnt*10);
return cnt*10;//4+4+2
}
/**
* 确保获取正常的位置数据
* @param dout 位置数据结果
* @param pairCnt 获取几组位置数据
* @return 数组长度
*/
static int getAndCheckLoc(uint8_t *dout, size_t pairCnt)
{
uint8_t loc[200];
size_t cnt = getLoc(loc,pairCnt);
//定位故障,临时填充数据
if (!cnt) {
// LOG_W("NONE Loc data, using 0x37 replaced");
cnt = pairCnt*10;
memset(loc,0x37,cnt);
}
if (!cnt) {
return 0;
// LOG_W("位置信息还未准备好。");
}
// else {
// memcpy(dout,loc,cnt);
// }
// return cnt;
// while (!cnt)
// {
// return 0;
// static uint8_t i=0;
// LOG_W("位置信息还未准备好。");
// rt_thread_mdelay(4000);//状态数据默认3s更新一次
// cnt = getLoc(loc,pairCnt);
// if (i++ > 20) {
// LOG_E("位置信息获取异常");
//// break;
// memset(dout,0x37,pairCnt*10);
// return pairCnt*10;
// }
// }
memcpy(dout,loc,cnt);
return cnt;
}
/**
* c回应深度数据含位置信息
* @param din
* @param len
* @return
*/
int reportDepth(uint8_t *din,size_t len)
{
// 000000000000000000005AA53E320608000A170407101B33FFFFFFFF24ED
LOG_I("FUNC = reportDepth");
//获取并更新位置信息
uint8_t dout[200];
rt_memset(dout,0,200);
size_t nlen = getAndCheckLoc(dout, 1);
rt_memcpy(dout+10, din, len);//5aa5从第11字节开始共len个字节
LOG_HEX("depth",16,dout,len+10);
upSend(dout, len+10);
}
//天通指令类型0x70 0x01
/**
* 从数组更新系统各项工作参数
* @param cfg 参数数组
* @param len 数组长度为零时使用当前系统的scfg
*/
void updateAllSysCfg(uint8_t *cfg, size_t len)
{
LOG_I("FUNC = update SYSCFG");
if (len) {
memcpy(&scfg,cfg,len);
}
//详见SYS_CFG的定义
/**
*
uint8_t sendInterval;
uint8_t maxTTWaitTime;
uint8_t maxTTRetryCnt;
uint8_t minTTPeriCnt;
uint8_t minTTsinal;
uint8_t timeout;
uint8_t openWindowTime[8];
uint16_t maxSizePerFile;
uint8_t commMode;
uint8_t selfDesSW;
uint8_t locAlert;
uint8_t locRepInterval;
*/
static int rst = 1;
rst &= set_cfg("sendInterval",scfg.sendInterval);
rst &= set_cfg("maxTTWaitTime",scfg.maxTTWaitTime);
rst &= set_cfg("maxTTRetryCnt",scfg.maxTTRetryCnt);
rst &= set_cfg("minTTPeriCnt",scfg.minTTPeriCnt);
rst &= set_cfg("minTTsinal",scfg.minTTsinal);
rst &= set_cfg("timeout",scfg.timeout);
// char tmpstr[sizeof(scfg.openWindowTime)*3];
// bytes2str(scfg.openWindowTime, sizeof(scfg.openWindowTime), 10, ",", tmpstr);
// rst &= set_cfgs("openWindowTime",tmpstr);
rst &= set_cfg("maxSizePerFile", scfg.maxSizePerFile);
rst &= set_cfg("commMode",scfg.commMode);
rst &= set_cfg("selfDesSW",scfg.selfDesSW);
rst &= set_cfg("locAlert",scfg.locAlert);
rst &= set_cfg("locRepInterval",scfg.locRepInterval);
rst &= set_cfg("isMaWin",scfg.isMaWin);
if (rst) {
LOG_I("set value success.");
}
// if ((uint16_t)getFileSize("cfg.ini") != (uint16_t)getFileSize("sd/cfg.ini")) {
// LOG_D("backup cfg file to sd");
// copy("cfg.ini", "sd/cfg.ini");
// }
}
/**
* 上报系统各项工作参数
*/
void reportSysCfg()
{
LOG_I("FUNC = report SYSCFG");
// scfg.commMode=1;
// scfg.timeout=5;
// scfg.maxSizePerFile=1024;
// uint8_t w[]={0x01,2,3,4,5,6,7,8};
// memcpy(scfg.openWindowTime,w,8);
uint8_t size = sizeof(scfg);
uint8_t rst[200] = { 0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _CFG_UPDATE_CFG >> 8, _CFG_UPDATE_CFG & 0xff };
int p = 6;
rst[p++] = 0;
rst[p++] = size;
memcpy(rst + p,&scfg, size);
p+=size;
rst[p] = bccCRC(rst + 2, p-2);
rst[++p] = 0xED;
size = p+1;
LOG_HEX("cfg",16,rst,size);
upSend(rst, size);
// LOG_HEX("scfg",16,&scfg,size);
// LOG_HEX("cfg",16,rst,p+1);
// updateAllSysCfg(rst+8, rst[7]);
}
//3.2.8定时自报位置信息
//每小时传数据时同步传位置信息
//与告警信息共用编码方式
//首字节为是否越界默认为00此处为预留。
//单次最多可上报15条位置信息
/**
* 按15条经纬度打包位置信息。由[是否越界]+[时戳]+[15组数据]组成。
* 是否越界为预留,不在此判断。
* 15组数据采集顺序为MOB(most oldest bit),越新的数据离时戳越近
* 由于加密后数据最大会增加16字节后位置数据条数改为10
* @param dout 存储位置信息的数组
* @return 数组大小
*/
#define _LOC_CNT 8
static int packLocMsg(uint8_t *dout)
{
uint8_t alertMsg[200] =
{ 0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _INFO_LOCATION >> 8, _INFO_LOCATION & 0xFF, 0, 0 };
alertMsg[8] = 0; //首字节00为定时发送未检测围栏其它为在围栏外
int len = time2Byte(alertMsg+9) + 1;//添加时间戳,len为数据长度
size_t rst = getAndCheckLoc(alertMsg + 8 + len, _LOC_CNT);
if (!rst) {//无有效位置数据
return 0;
}
len += rst;
//add battery info
// uint8_t temp[60];
// rst = getBattInfo(temp);
// memcpy(alertMsg+8+len,temp,rst);
rst = getBattRAWInfo(alertMsg+8+len);
len += rst;
alertMsg[7] = len; //update len of raw data
alertMsg[8 + len] = bccCRC(alertMsg + 2, 8 + len - 2); //update CRC
alertMsg[8 + len + 1] = 0xED;
len = 8 + len + 2;
// LOG_HEX("packLocMsg", 16, alertMsg, len); //bccCRC+Tail
memcpy(dout, alertMsg, len);
return len;
}
static void d_packLocMsg(void)
{
uint8_t tmp[200];
size_t len = packLocMsg(tmp);
// len = cryptSingleMsg(tmp, len, tmp);
// uint8_t din[]={0x5A,0xA5,0x3E,0x32,0x06,0x08,0x00,0x0A,0x17,0x09,0x05,0x0F,0x24,0x0B,0xFF,0xFF,0xFF,0xFF,0x33,0xED};
// reportDepth(din, sizeof(din));
LOG_HEX("c",16,tmp,len);
// upSend(tmp, len);
}
/**
* 获取信号信息,以时戳开头
* @param dout
*/
RT_WEAK size_t getSignals(uint8_t *dout, uint8_t len);
void packSignal(void)
{
LOG_I("FUNC = get signals");
uint8_t signalMsg[200] =
{ 0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _INFO_SIGNAL >> 8, _INFO_SIGNAL & 0xFF, 0, 0 };
uint8_t len = time2Byte(signalMsg+8);//添加时间戳
len += getSignals(signalMsg + 8 + len, 100);
signalMsg[7] = len; //update len of raw data
signalMsg[8 + len] = bccCRC(signalMsg + 2, 8 + len - 2); //update CRC
signalMsg[8 + len + 1] = 0xED;
len = 8 + len + 2;
LOG_HEX("signal",16,signalMsg,len);
upSend(signalMsg,len);
}
/**
* 获取电池信息,带时戳
*/
void reportBattInfo(void)
{
uint8_t battInfo[200] = { 0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _INFO_BATT >> 8, _INFO_BATT & 0xFF, 0, 0 };
uint8_t len = time2Byte(battInfo + 8); //添加时间戳
uint8_t blen = getBattRAWInfo(battInfo + 8 + len);
len += blen;
battInfo[7] = len; //update len of raw data
battInfo[8 + len] = bccCRC(battInfo + 2, 8 + len - 2); //update CRC
battInfo[8 + len + 1] = 0xED;
len = 8 + len + 2;
// LOG_HEX("battInfo", 16, battInfo, len); //bccCRC+Tail
upSend(battInfo, len);
}
///**
// * 加密位置信息。对位置信息的更改需在加密前操作
// * @param din 存储待加密位置信息的数组
// * @param len 带加密长度
// * @param dout 存储加密结果的数组
// * @return 加密后的长度
// */
//int cryptSingleMsg(uint8_t *din, size_t len, uint8_t *dout)
//{ //加密。因加密后数据长度会变化,故不能只加密位置数据。
// uint8_t cd[200]={0xAB,0xBA};
// size_t nlen = 0;
//
////#define FULL_DATA_CRYPT
//#ifdef FULL_DATA_CRYPT
// nlen = cryp_data(din, len, cd);
//#else
// //单独加密时在加密后数据头部添加0xABBA便于识别、解析
// nlen = cryp_data(din, len, cd + 2) + 2;
//#endif
// memcpy(dout, cd, nlen);
// return nlen;
//}
//static uint8_t locMsg[200];
//static rt_timer_t repLoc;
//static rt_sem_t isReadyToSendLoc;
int isInFence(uint8_t *loc);
/**
* 打包并检测位置数据 默认10s更新一次
* @return
*/
static int itime=0;//间隔时间
void reportLoc_thread_entry(void *parameter)
{
#define CHECK_INTERVAL 6
//static int i=0;
while (isTCPok())
{
rt_thread_mdelay(CHECK_INTERVAL*1000); //默认6s刷新一次
// static uint32_t i = 0;
int isReadyToSendLoc=0;
uint8_t rst[200];
size_t len = packLocMsg(rst);
if (!len) {//无有效位置数据
// return;
rt_thread_mdelay(500);//添加延时避免死循环卡死线程
continue;
}
//检测是否在围栏内
uint8_t isLocOk[]={0x37,0x37,0x37};
if (scfg.locAlert && memcmp(rst+len-11-4,isLocOk,sizeof(isLocOk)) != 0 && !isInFence(rst+len-11-4))//不在围栏内。定位正常才判断围栏
{
rst[8] |= 1<<7;
isReadyToSendLoc = 1;
resetTM();//不关机
}
itime += 1 ;
// LOG_D("%d/%d s",itime*CHECK_INTERVAL,scfg.locRepInterval * 60);
if (itime*CHECK_INTERVAL >= scfg.locRepInterval * 60)//定时发送默认5分钟
{
itime = 0;
isReadyToSendLoc = 1;
}
if (isReadyToSendLoc) {
// LOG_HEX("loc",16,rst,len);
if (isTTjh()) {//loc数据不用缓存故需要激活才发送
upSend(rst, len);
}
else {
itime = 0;
}
}
}
}
void reportLoc()
{
rt_thread_t thread = rt_thread_create("RPLoc", reportLoc_thread_entry, RT_NULL, 1024 * 10, 27, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
LOG_E("thread 'PCLoc' create failure.");
return;
}
}
//3.2.9深度异常告警
/**
* 将位置信息合入深度信息
* @param din
* @param len
* @param dout
* @return
*/
int depthAlert(uint8_t *din, int len)
{
//获取并更新位置信息
// uint8_t loc[10];
// uint8_t dout[200];
// size_t nlen = getAndCheckLoc(dout, 1);
//
// rt_memcpy(dout+10, din, len);//5aa5从第11字节开始共len个字节
// LOG_HEX("depth",16,dout,len+10);
// //加密。因加密后数据长度会变化,故不能只加密位置数据。
// upSend(dout, nlen);
}
//3.2.10位置异常告警
//map.c中实现
/**
* 判断是否在电子围栏内部
* @param x 当前位置经度
* @param y 当前位置纬度
* @return 在内部则返回true反之false
*/
static int isInPolgon(float x, float y)
{
float polyX[10]={},polyY[10]={};
int polyCorners = mapParse("/map.geojson",polyX,polyY);
return pointInPolygon(polyCorners,polyX,polyY,x,y);
}
/**
* 设置位置告警功能开关
* @param setON 1-告警功能开启0-关闭
*/
void setLocationAlertSWT(int setON)
{
LOG_I("FUNC = set Loc Alert");
scfg.locAlert = setON;
set_cfg("locAlert", setON);
}
/**
* 判断给定位置是否在电子围栏内部
* @param loc 经纬度数组8个字节
* @return 1-
*/
int isInFence(uint8_t *loc)
{
// LOG_HEX("x=",16,loc,8);
float x,y =0;
x=*((float *)loc);
y=*((float *)(loc+4));
// LOG_D("%lf-%lf", x, y);
int isIN = isInPolgon(x, y);
if (isIN) {
LOG_D("设备在围栏内,位置正常。");
return 1;
}
else {
LOG_W("警告!设备不在围栏内!");
return 0;
}
}
void d_isInFence(void)
{
uint8_t rst[200];
int len = packLocMsg(rst);
if (!len)
{ //无有效位置数据
LOG_W("无有效位置数据");
return;
}
//检测是否在围栏内
isInFence(rst + len - 11);
//不在围栏内,1+4+4+1+bcc+0x4D
}
//创建定时任务默认时间10秒钟异常则发送
//3.2.12数据存储区清空
//
/**
* 采用格式化命令对存储区进行清空,谨慎使用!
*/
void clearAllData()
{
// mkfs("elm","sd0");//format SD
// mkfs("elm", "W25Q128");//format flash
LOG_I("FUNC = clear files");
//去掉原static
//static int cmd_rm(int argc, char **argv)
//MSH_CMD_EXPORT_ALIAS(cmd_rm, rm, Remove(unlink) the FILE(s).);
DIR *dir = opendir(ROOT_PATH_DATA);
if (dir && isFileExit("/sd/tosend.ini"))
{
closedir(dir);
char *arg[]={"rm","-r",ROOT_PATH_DATA,"/sd/tosend.ini" };
cmd_rm(4,arg);
}
LOG_D("files deleted.");
}
/**
* 重发数据
* @param din
* @param len
*/
void reSend(uint8_t *din, uint8_t len)
{
//file example: sd/cdata/2023_08_23/23_08_23_08_31_44_14.bin
LOG_I("FUNC = resend file");
char f[60]="";
strcat(f,ROOT_PATH_DATA);
char str[30]="";
bytes2str(din, len-1, 10, "_", str);
strcat(f,"20");
strncat(f,str,8);
strcat(f,"/");
strcat(f,str);
strcat(f,".bin");
if (!getFileSize(f)) {
LOG_W("'%f' is empty.");
return;
}
LOG_D("resend '%s'",f);
for (size_t var = 7; var < len; var++) {
postFileInfo(f,din[var]);
}
}
/**
* @brief TT根据下发的指令执行对应的功能
*
* @param din 待执行的指令数据
* @param len 数据长度,单位字节
*/
void ttRunCMD_thread_entry(uint8_t *din, size_t len)
{
/**
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 8+N | 9+N | 10+N |
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
| Header | Header | targetAddr | sourceAddr | mainCMD | subCMD | lenH | lenL | data1 | ... | dataN | BbccCRC | tail |
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
*/
int cmd = (din[4] << 8) + din[5];
// int para[]
switch (cmd)
{
case _CFG_COMM_MODE:
setCommMode(din[8]);
break;
case _CMD_SELF_TEST:
selfTest();
break;
case _CFG_SELF_DESTRUCT:
setSelfDestructSWT(din[8]);
break;
case _CMD_SELF_DESTRUCT:
selfDestruct();
break;
case _CFG_COMM_WINDOW:
setCommWindow(din+8,din[7]);//只支持两组开窗开窗时间为小时、分钟UTC+0
break;
case _CMD_OPEN_WINDOW:
openWindow(din[7]?((din[8] << 8) + din[9]):0);//两字节开窗时间
break;
case _CMD_CLOSE_WINDOW:
closeWindow();
break;
case _CFG_LOCATION_ALERT:
setLocationAlertSWT(din[8]);
break;
case _CMD_CLEAR_DATA:
clearAllData();
break;
case _CFG_UPDATE_CFG:
if (din[7]) {//数据长度不为0则为覆写参数
updateAllSysCfg(din+8, din[7]);
}
else {//数据长度为0则为请求参数
reportSysCfg();
}
break;
case _CMD_RETRY_DATA:
reSend(din+8, din[7]);
break;
case _INFO_BATT:
reportBattInfo();
break;
case _CMD_SET_RTC:
updateSysRTC(din+8, din[7]);
break;
case _INFO_SIGNAL:
packSignal();
break;
default:
LOG_W("0x%04X=未支持的指令。",cmd);
break;
}
}
void ttRunCMD(uint8_t *din, size_t len)
{
static SMSG msg;
rt_memset(&msg, 0, sizeof(SMSG));
rt_memcpy(msg.data,din,len);
msg.len=len;
ttRunCMD_thread_entry(din, len);
}
RT_WEAK int formatAndSendTo3S(uint8_t * din, size_t len)
{
// LOG_D("直接调用小彭的函数进行处理。");
LOG_I("FUNC = forward to 3S");
char str[200] = "RCV:";
int cmd = (din[4] << 8) + din[5];
switch (cmd)
{
case _CMD_RTC_REQUEST: //不加前后缀的指令,仅有少数
bytes2str(din, len, 16, "", str);
break;
default: //默认加前后缀
bytes2str(din, len, 16, "", str + 4);
strcat(str, "\r\n");
break;
}
LOG_D("send '%s' to 3S.", str);
sendTo3S(str, strlen(str));//作为字符串发送
return 0;
}
//#define CHECK_3S_DATA
int chk3SDataValid(uint8_t *din, size_t count)
{
uint8_t head[]={0x5A,0xA5};
//header[4] addr[2]  func[2]  len[2]  data[N]  fcrc[1] tail[1]
if (memcmp(din,head,sizeof(head)))
{
LOG_W("0x5AA5[√] != 0x%02X%02X[×],帧头不匹配",din[0],din[1]);
return -RT_ERROR;
}
if (din[count-2] != bccCRC(din+2,count-2-2))//校验位为1个字节采用异或运算从指令的第3个字节开始到奇偶校验位的前一个字节结束
{
LOG_W("0x%02X[√] != 0x%02X[×],校验值不匹配", bccCRC(din+2,count-2-2),din[count-2] );
return -RT_ERROR;
}
if (din[count-1] != 0xED)
{
LOG_W("0xED[√] != 0x%02X[×],帧尾不匹配",din[count-1]);
return -RT_ERROR;
}
// LOG_D("valid data.");
return RT_EOK;
}
//原计划将指令粗解析放在上位机考虑到上位机到位时间晚现放到MCU端
/**
* @brief 校验、解析3S数据以0x5AA5开头0xED结尾。
*
* @param din 待解析数据
* @param count 待解析数据长度
*/
void parse3SData(uint8_t *din, size_t count)
{
/**
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 8+N | 9+N | 10+N |
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
| Header | Header | targetAddr | sourceAddr | mainCMD | subCMD | lenH | lenL | data1 | ... | dataN | BbccCRC | tail |
+--------+--------+------------+------------+---------+--------+------+------+-------+-----+-------+---------+------+
*/
if (chk3SDataValid(din, count) != RT_EOK) {
#ifdef CHECK_3S_DATA
return;
#endif
}
//有效的数据才能复位超时
if (isTTon()) {
resetTM();
}
// uint8_t dout[200];
// 未采用switch case
if (din[2] == ADDR_TT)//仅给TT的消息
{
ttRunCMD(din,count);
}
else if (din[2] == ADDR_3S)//给3S的指令需要再加工返回数据可能也需要再加工
{
//
formatAndSendTo3S(din,count);
}
else if (din[2] == ADDR_ANJI)
{
//可能需要对回传信息再加工,如查询深度需要加入位置坐标
//或是缓存任务数据
//故需要对数据进行简单判断
int cmd = (din[4] << 8) + din[5];
switch (cmd)
{
// case _CMD_DEPTH_REQUEST:
// reportDepth(din, count);
// break;
case _INFO_DEPTH_ANSWER:
reportDepth(din, count);
break;
default:
LOG_I("pass-through raw data.");
if (isTTjh())
{//如果TT为开机状态具备通信状态待商榷则不缓存直接发
upSend(din, count);
}
else {
cacheDataToFile(din, count);
}
}
// upSend(din, count);
}
else {
LOG_W("无法解析的目标地址");
// cacheDataToFile(din, count);
if (isTTjh())
{//如果TT为开机状态具备通信状态待商榷则不缓存直接发
upSend(din, count);
}
else {
cacheDataToFile(din, count);
}
}
//检查待发文件,相当于失败重发
// if (getCntOfFileToSend() && !isInFileMode()) {//不严格
// fileIsReady();
// }
}
void chkACK(uint8_t *msg, size_t size)
{
rt_uint8_t ackgood[] = { 0x88, 0xAA, 0xBB, 0x88, 0x41, 0x43, 0x4B }; //前四字节=帧头、后三字节=ACK
if (rt_memcmp(msg, ackgood, 4) == 0 && rt_memcmp(msg + size - 3, ackgood + 4, 3) == 0)
{
LOG_I("data is ACK.");
}
else {
LOG_W("INVALID DATA.");
}
}
//#define TR_USE_THREAD
#ifdef TR_USE_THREAD
/**
* @brief 解析TT数据TT收到的指令必是单指令解析容易。
*
* @param din
* @param len
*/
void parseTTData_thread_entry(void *parameter)
{
SMSG* msg = RT_NULL;
msg = (SMSG*) parameter;
uint8_t din[500];
memcpy(din,msg->data,msg->len);
size_t len = (size_t)msg->len;
/**
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
* | fstart[4] | fnum[2] | bak[2] | ftype[2] | fdlen[2] | fcrc[1] | ftccid[4] | rawData[N] |
* | 0x88,0xAA,0xBB,0x88 | 0x00,0x01 | 0x00,0x00 | 0x70,0x21 | 0x00,0xAA | 0x00 | 0x27,0x22,0x22,0x22 | |
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
*/
uint8_t head[]={0x88,0xAA,0xBB,0x88, 0xFF,0xFF, 0x00,0x00, 0x70,0x21, 0x00,0xaa, 0x00, 0x27,0x22,0x22,0x22 };
//fstart[4] fnum[2]  bak[2]  ftype[2]  fdlen[2]  fcrc[1] ftccid[4]
uint8_t index[10];
size_t n=isInByte(din, len, head, 4, index);//仅判断帧头因ACK不一样
uint8_t ndin[200];
if (!n) {
LOG_W("TTData中无匹配帧");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
if (n>1) {
LOG_HEX("frame",16,ndin,cnt);
}
//判断是否为ACK
if ((ndin[10]<<8) | ndin[11] == 0x03) {//数据长度只有3
chkACK(ndin, cnt);
}
//数据
else
{
resetTM();//非ACK信号才能触发延时逻辑
uint8_t rst = memcmp(ndin,head,10);//只比较到ftype
if (rst)
{
LOG_W("帧头不匹配");
return;
}
uint8_t id[30]="";
LOG_I("data info: id=\"%s\", cur/all=[%d/%d]",bytes2str(ndin+17,7,10,"_",id),ndin[25],ndin[26]);
if (ndin[24] >> 7) // fcfg=数据类型。解析TT收到的数据时仅需解析“命令”“数据”传输是单向的。
{
LOG_W("浮标端仅接受指令,暂不支持数据。");
return;
}
uint8_t rawData[200];
uint8_t rawDataLen=cnt-27;
memcpy(rawData, ndin + 27, rawDataLen);
parse3SData(rawData,rawDataLen);
}
}
}
void parseTTData(uint8_t *din, size_t len)
{
static SMSG msg;
memset(&msg, 0, sizeof(SMSG));
memcpy(msg.data,din,len);
msg.len=len;
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("parseTT", parseTTData_thread_entry, (void *) &msg, 1024 * 5, 27-1, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
return RT_EOK;
}
else
{
LOG_E("thread 'parseTT' create failure.");
return -RT_ERROR;
}
}
#else
/**
* @brief 解析TT数据TT收到的指令必是单指令解析容易。
*
* @param din
* @param len
*/
void parseTTData(uint8_t *din, size_t len)
{
/**
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
* | fstart[4] | fnum[2] | bak[2] | ftype[2] | fdlen[2] | fcrc[1] | ftccid[4] | rawData[N] |
* | 0x88,0xAA,0xBB,0x88 | 0x00,0x01 | 0x00,0x00 | 0x70,0x21 | 0x00,0xAA | 0x00 | 0x27,0x22,0x22,0x22 | |
* +---------------------+-----------+-----------+-----------+-----------+---------+---------------------+------------+
*/
uint8_t head[]={0x88,0xAA,0xBB,0x88, 0xFF,0xFF, 0x00,0x00, 0x70,0x21, 0x00,0xaa, 0x00, 0x27,0x22,0x22,0x22 };
//fstart[4] fnum[2]  bak[2]  ftype[2]  fdlen[2]  fcrc[1] ftccid[4]
uint8_t index[10];
size_t n=isInByte(din, len, head, 4, index);//仅判断帧头因ACK不一样
uint8_t ndin[200];
if (!n) {
LOG_W("TTData中无匹配帧");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
if (n>1) {
LOG_HEX("frame",16,ndin,cnt);
}
//判断是否为ACK
if ((ndin[10]<<8) | ndin[11] == 0x03) {//数据长度只有3
chkACK(ndin, cnt);
}
//数据
else
{
resetTM();//非ACK信号才能触发延时逻辑
uint8_t rst = memcmp(ndin,head,10);//只比较到ftype
if (rst)
{
LOG_W("帧头不匹配");
parse3SData(din,len);//由于串口收数据会出现断帧的情况,这里统一改为不处理,异常数据直接透传
return;
}
uint8_t id[30]="";
LOG_I("data info: id=\"%s\", cur/all=[%d/%d]",bytes2str(ndin+17,7,10,"_",id),ndin[25],ndin[26]);
if (ndin[24] >> 7) // fcfg=数据类型。解析TT收到的数据时仅需解析“命令”“数据”传输是单向的。
{
LOG_W("浮标端仅接受指令,暂不支持数据。");
return;
}
uint8_t rawData[200];
uint8_t rawDataLen=cnt-27;
memcpy(rawData, ndin + 27, rawDataLen);
parse3SData(rawData,rawDataLen);
}
}
}
#endif
/**
* get file size in byte
* @param file file name whith fullpath
*/
unsigned long getFileSize(char *file)
{
struct stat stat;
char *fullpath, *path;
unsigned long rst=0;
#ifdef DFS_USING_WORKDIR
/* open current working directory */
path = rt_strdup("/");
#endif
/* build full path for each file */
fullpath = dfs_normalize_path(path, file);
rt_memset(&stat, 0, sizeof(struct stat));
if (dfs_file_stat(fullpath, &stat) == 0)
{
rst = stat.st_size;
}
rt_free(fullpath);
rt_free(path);
return rst;
}
void d_getFileSize(int argc, char ** argv)
{
// char *f;
uint16_t size = (uint16_t)getFileSize(argv[1]);
LOG_D("size = %d Byte.",size);
}
/**
* 判断文件是否存在,参数为文件完整路径
* @param f
* @return
*/
int isFileExit(char *f)
{
int rst = 0;
int fd = open(f, O_RDONLY);
if (fd > 0)
{
rst = 1;
close(fd);
}
return rst;
}
extern SYS_CFG scfg;
static uint8_t iscdlock=0;
/**
* 缓存任务数据
* @param din 单次收到的任务数据
* @param len 任务数据长度
* @return 0--正常,-1--异常
*/
int cacheDataToFile(uint8_t *din, size_t len)
{
LOG_I("FUNC = cache to upsend");
int rst = -RT_ERROR;
//return RT_EOK;
//lock file
while (iscdlock) {
rt_thread_mdelay(1000);
}
static char f[60]="";//必须是static否则log2file报错
getLstCacheFileName(f);
int fd = open(f, O_WRONLY | O_CREAT | O_APPEND);
if (fd < 0)
{
LOG_E("open file %s failed!", f);
goto _exit;
}
else
{
iscdlock=1;
int rst = write(fd, din, len);
if (rst != len)
{
LOG_E("write to file %s failed!", f);
goto _exit;
}
// cnt += len;
close(fd);
unsigned long size = getFileSize(f);
LOG_I("cached %d bytes data to '%s', new size is %ld bytes.",len,f,size);
if (size > scfg.maxSizePerFile) {
updateCacheFileName();//更新文件名,置于线程前避免冲突
cryptCdata(f);//密文覆盖明文
postFileInfo(f,0);//加入待发列表
}
rst=RT_EOK;
}
_exit:
if (fd) {
close(fd);
}
iscdlock=0;
return rst;
}
void d_cacheData()
{
uint8_t demo[200];
size_t len = sizeof(demo);
memset(demo,0xAB,len);
cacheDataToFile(demo, len);
}
//#define TR_USE_THREAD
#ifdef TR_USE_THREAD
void parseRS232_thread_entry(void *parameter)
{
SMSG* msg = RT_NULL;
msg = (SMSG*) parameter;
uint8_t din[500];
memcpy(din,msg->data,msg->len);
size_t len = (size_t)msg->len;
//有HEX有ASCII统一按HEX解析
//部分数据以10字节20字符的0数据开始如深度查询心跳包等
//处理思路是先不管前导0对应指令手动加前导数据
// uint8_t asciiHead[]={0x41, 0x54, 0x2B, 0x53, 0x4E, 0x44,};//"AT+SND"
uint8_t hexHead[]={0x5a, 0xa5};//"5AA5"
//由于帧头有多种且ascii和hex混发无法处理粘包
// LOG_D("data is %s",isDataASCII(din, len)?"ASCII":"BIN");
//check
// if (memcmp(din,asciiHead,sizeof(asciiHead)) == 0) {
if (isDataASCII(din, len)) {
//ascii
LOG_I("type = ASCII");
trDataTolog(din, len, 0);
uint8_t index[10];
uint8_t tmpHead[]={0x35, 0x41, 0x41, 0x35};
size_t n=isInByte(din, len, tmpHead, sizeof(tmpHead), index);
// LOG_D("n=%d",n);
if (!n) {
LOG_W("RS232中无匹配帧");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
uint8_t ndin[400];
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
ndin[cnt]='\0';
uint8_t tmp[200];
size_t ncnt = str2Byte(ndin, 2, 16, tmp);
LOG_HEX("frame",16,tmp,ncnt);
if (chk3SDataValid(tmp, ncnt) != RT_EOK) {
return;
}
parse3SData(tmp,ncnt);
}
}
else//如果不是ASCII则统一按HEX计// if (memcmp(din,hexHead,sizeof(hexHead)) == 0)
{
//bin
LOG_I("type = BIN");
char tmp[200]="";
trDataTolog(bytes2str(din, len, 16, " ", tmp), strlen(tmp), 0);
uint8_t index[10];
size_t n=isInByte(din, len, hexHead, sizeof(hexHead), index);
if (!n) {
LOG_W("RS232中无匹配帧");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
uint8_t ndin[200];
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
LOG_HEX("frame",16,ndin,cnt);
if (chk3SDataValid(ndin, cnt) != RT_EOK) {
return;
}
parse3SData(ndin,cnt);
}
}
}
void parseRS232(uint8_t *din, size_t len)
{
static SMSG msg;
memset(&msg, 0, sizeof(SMSG));
memcpy(msg.data, din, len);
msg.len = len;
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("parse232", parseRS232_thread_entry, (void *) &msg, 1024 * 5, 27 - 1, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
return RT_EOK;
}
else
{
LOG_E("thread 'parse232' create failure.");
return -RT_ERROR;
}
}
#else
void parseRS232(uint8_t *din, size_t len)
{
//有HEX有ASCII统一按HEX解析
//部分数据以10字节20字符的0数据开始如深度查询心跳包等
//处理思路是先不管前导0对应指令手动加前导数据
uint8_t asciiHead[]={0x41, 0x54, 0x2B, 0x53, 0x4E, 0x44,};//"AT+SND"
uint8_t hexHead[]={0x5a, 0xa5};//"5AA5"
//由于帧头有多种且ascii和hex混发无法处理粘包
// LOG_D("data is %s",isDataASCII(din, len)?"ASCII":"BIN");
//check
if (memcmp(din,asciiHead,sizeof(asciiHead)) == 0) {
// if (isDataASCII(din, len) || memcmp(din,asciiHead,sizeof(asciiHead)) == 0) {
//ascii
LOG_I("type = ASCII");
trDataTolog(din, len, 0);
uint16_t index[10];
uint8_t tmpHead[]={0x35, 0x41, 0x41, 0x35};
size_t n=isInByte(din, len, tmpHead, sizeof(tmpHead), index);
// LOG_D("n=%d",n);
if (!n) {
LOG_W("RS232中无匹配帧[ASCII]");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
uint8_t ndin[400];
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
ndin[cnt]='\0';
uint8_t tmp[200];
size_t ncnt = str2Byte(ndin, 2, 16, tmp)-1;//结尾有\r\n
// if (n>1) LOG_HEX("frame",16,tmp,ncnt);
parse3SData(tmp,ncnt);
}
}
else//如果不是ASCII则统一按HEX计// if (memcmp(din,hexHead,sizeof(hexHead)) == 0)
{
//bin
LOG_I("type = BIN");
trDataTolog(din, len, 0);
uint16_t index[20];
size_t n=isInByte(din, len, hexHead, sizeof(hexHead), index);
if (!n) {
LOG_W("RS232中无匹配帧[BIN]");
return;
}
for (size_t i = 0; i < n; i++)
{
//按帧头分割
uint8_t ndin[MAX_LEN_3S];
int cnt=(i+1<n)?index[i+1]-index[i]:len-index[i];
memcpy(ndin,din+index[i],cnt);
// if (n>1) LOG_HEX("frame",16,ndin,cnt);
parse3SData(ndin,cnt);
}
}
}
#endif
#include <netdev_ipaddr.h>
#include <netdev.h>
/**
* check eth
* @return 1-UP,0-DOWN
*/
int isEthUP()
{
//netdev.c
extern struct netdev *netdev_default;
int rst = (netdev_default->flags & 0x01U) ? 1:0; //0x01 = NETDEV_FLAG_UP
// LOG_D("eth is %s.",rst?"up":"down");
// rst &= (netdev_default->flags & 0x04U) ? 1:0;//0x04 NETDEV_FLAG_LINK_UP
return rst;
}
void reportInfo_thread(void)
{
while (1)
{
if (rt_sem_take(okToreport, RT_WAITING_FOREVER) == RT_EOK)
{
if (isTTjh()) {
LOG_D("send cfg ACK");
selfTest();
}
else {
LOG_W("TT is not ready, ACK is invalid.");
}
}
}
}
void reportINFO(void)
{
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("reportINFO", reportInfo_thread, RT_NULL, 1024 * 5, 27, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
LOG_E("thread 'updatecfg' create failure.");
return;
}
}
//INIT_APP_EXPORT(reportINFO);
/**
* 设置3S的RTC时间
*/
void set3SRTC(void)
{
uint8_t cmd[16]={0x5A, 0xA5, ADDR_3S, ADDR_ANJI, _CMD_SET_RTC >> 8, _CMD_SET_RTC & 0xFF, 0x00, 0x06 };
time2Byte(cmd+8);
cmd[14]=bccCRC(cmd+2, 16-4);
cmd[15]=0xED;
LOG_HEX("cmdRTC",16,cmd,sizeof(cmd));
formatAndSendTo3S(cmd, sizeof(cmd));
}
/**
* 更新系统RTC时间
* @param din
* @param len
*/
void updateSysRTC(uint8_t *din, size_t len)
{
LOG_I("FUNC = sest RTC");
struct tm tm_new = { 0 };
time_t old = (time_t)0;
time_t now = (time_t)0;
int err = get_timestamp(&old);
if (err != RT_EOK)
{
LOG_E("Get current timestamp failed. %d", err);
return;
}
din[0] += 2000 - 1900;
din[1] -= 1;
// memcpy(tm_new, din, sizeof(tm_new));
tm_new.tm_year = din[0];
tm_new.tm_mon = din[1];
tm_new.tm_mday = din[2];
tm_new.tm_hour = din[3];
tm_new.tm_min = din[4];
tm_new.tm_sec = din[5];
/* converts the local time into the calendar time. */
now = mktime(&tm_new);
err = set_timestamp(now);
if (err != RT_EOK)
{
LOG_E("set date failed. %d", err);
return;
}
get_timestamp(&now); /* get new timestamp */
rt_kprintf("old: %.*s", 25, ctime(&old));
rt_kprintf("now: %.*s", 25, ctime(&now));
//ACK
uint8_t rst[16]={0x5A, 0xA5, ADDR_ANJI, ADDR_TT, _INFO_RTC_ANSWER >> 8, _INFO_RTC_ANSWER & 0xFF, 0x00, 0x06 };
uint8_t tm[10];
time2Byte(tm);
memcpy(rst+8,tm,6);
rst[14]=bccCRC(rst+2, 14);
rst[15]=0xED;
LOG_HEX("sRTC",16,rst,sizeof(rst));
if (isTTjh()) {
upSend(rst, sizeof(rst));
}
}
/**
* TT工作后设置状态用于系统崩溃后恢复
* @param flag
*/
void setWorkSta(int flag)
{
set_cfg("isWorking", flag);
}
/**
* 是否需要恢复现场
* @return
*/
int isNeedRestore(void)
{
int rst = get_cfg("isWorking");
if (rst > 0) {
LOG_W("restoring TT after crash");
}
else {
rst = 0;
}
return rst;
}
/**
* 将密文解密至内存
* @param fin 密文文件
* @param buffer 解密后数据
* @return 数据长度
*/
size_t decryptCdata(const char *fin, uint8_t *dout)
{
int fd = -1;
fd = open(fin, O_RDONLY, 0);
if (fd < 0)
{
LOG_E("[hex] open the input file : %s error.", fin);
return RT_ERROR;
}
size_t file_size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
rt_uint8_t *buffer = RT_NULL;
buffer = rt_malloc(file_size);
if (!buffer)
{
LOG_E("No memory for read cdata!\n");
return RT_ERROR;
}
read(fd, buffer, file_size);
close(fd);
size_t rst = decryp_data(buffer, file_size, dout);
rt_free(buffer);
return rst;
}
/**
* 加密待发的缓存文件,覆盖源文件
* 当文件内容不再更新时调用此文件
* @param f 缓存文件
*/
void cryptCdata(const char *f)
{
aes_file(f, f);
}
#define FUNC_DEMO
#ifdef FUNC_DEMO //测试时导出命令到控制台
MSH_CMD_EXPORT(d_getFreeSpace,getFreeSpace);
MSH_CMD_EXPORT(selfTest,sysSelfTest);
MSH_CMD_EXPORT(d_packLocMsg,dpackLocMsg);
MSH_CMD_EXPORT(reportLoc,);
MSH_CMD_EXPORT(d_cacheData,d_cacheData);
MSH_CMD_EXPORT(d_getFileSize,d_getFileSize);
MSH_CMD_EXPORT(isEthUP,isEthUP);
MSH_CMD_EXPORT(reportSysCfg,reportSysCfg);
MSH_CMD_EXPORT(d_isInFence,d_isInFence);
MSH_CMD_EXPORT(d_demo,demo for debug function);
MSH_CMD_EXPORT(set3SRTC,RTC);
#endif