500 lines
12 KiB
C
500 lines
12 KiB
C
/*
|
||
* @Author: murmur test@test.com
|
||
* @Date: 2023-05-05 10:07:30
|
||
* @LastEditors: murmur test@test.com
|
||
* @LastEditTime: 2023-05-11 16:34:31
|
||
* @FilePath: \TT12-MCU\applications\ttmsg\ttmsg.c
|
||
* @Description:
|
||
*
|
||
* Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
|
||
*/
|
||
|
||
// #include <dfs_file.h>
|
||
|
||
#define LOG_TAG "ttmsg"
|
||
#define LOG_LVL LOG_LVL_DBG
|
||
#include <ulog.h>
|
||
|
||
#include "ttmsg.h"
|
||
#include <board.h>
|
||
#include <usrcfg.h>
|
||
|
||
extern struct rt_event tcp_chk;//tcp条件
|
||
|
||
|
||
/**
|
||
* @brief 按指定分隔符分割字符串
|
||
*
|
||
* @param str 待分割字符串
|
||
* @param deli 分隔符
|
||
* @param out 输出字符串数组
|
||
* @return size_t 分割后字符串个数
|
||
*/
|
||
#ifdef USE_STRTOK
|
||
static size_t split(const char *str, const char *deli, char (*out)[STR_LEN_MAX])
|
||
{
|
||
char buf[50];
|
||
strcpy(buf, str); // strtok会修改字符串
|
||
char *token = strtok(buf, deli);
|
||
char *rst[STR_LEN_MAX];
|
||
|
||
size_t i = 0;
|
||
while (token)
|
||
{
|
||
rst[i++] = token;
|
||
token = strtok(NULL, deli);
|
||
}
|
||
|
||
// 更新out
|
||
for (size_t ii = 0; ii < i; ii++)
|
||
{
|
||
// out[ii] = id[ii];
|
||
strcpy(out[ii], rst[ii]);
|
||
}
|
||
|
||
return i;
|
||
}
|
||
#else
|
||
// strtok_r版本
|
||
static size_t split(const char *str, const char *delim, rt_uint8_t (*out)[STR_LEN_MAX])
|
||
{
|
||
char buf[50];
|
||
strcpy(buf, str); // strtok会修改字符串
|
||
|
||
char *token = NULL;
|
||
char *saveptr = NULL;
|
||
char *rst[STR_LEN_MAX];
|
||
int idx = 0;
|
||
|
||
|
||
token = strtok_r(buf, delim, &saveptr);
|
||
while (token)
|
||
{
|
||
// LOG_D("---%s---",token);
|
||
rst[idx++] = token;
|
||
token = strtok_r(NULL, delim, &saveptr);
|
||
}
|
||
|
||
// 更新out
|
||
for (size_t ii = 0; ii < idx; ii++)
|
||
{
|
||
// out[ii] = id[ii];
|
||
strcpy(out[ii], rst[ii]);
|
||
}
|
||
|
||
return idx;
|
||
}
|
||
#endif
|
||
|
||
|
||
/**
|
||
* @brief 从文件名字符串提取ID
|
||
*
|
||
* @param fin 文件名,支持路径
|
||
* @param out 提取结果
|
||
* @return size_t ID长度
|
||
*/
|
||
static size_t getID(const char *str, rt_uint8_t *out)
|
||
{
|
||
char id[10][STR_LEN_MAX] = {};
|
||
// 分割路径
|
||
size_t len = split(str, "/", id);
|
||
|
||
// 分割后缀
|
||
// LOG_D("file is %s",id[len-1]);
|
||
len = split(id[len - 1], ".", id);
|
||
|
||
// 分割时间
|
||
// LOG_D("file name is %s",id[0]);
|
||
len = split(id[0], "_", id);
|
||
|
||
unsigned char tmp[len];
|
||
for (size_t i = 0; i < len; i++)
|
||
{
|
||
unsigned int v = atoi(id[i]);
|
||
|
||
// 去除代表20的2000
|
||
if (v > 0xff)
|
||
{
|
||
v = v - 2000;
|
||
}
|
||
|
||
tmp[i] = v;
|
||
}
|
||
// LOG_HEX("file ID",16,tmp,len);
|
||
char idstr[30];
|
||
LOG_I("msg id:%s",bytes2str(tmp, len, 10, "_", idstr));
|
||
memcpy(out, tmp, len);
|
||
return len;
|
||
}
|
||
|
||
/**
|
||
* @brief 根据配置初始化MSG
|
||
* @param *tpl MSG结构体
|
||
* @param fin 文件名,由时间戳和随机码组成,作为数据包唯一ID
|
||
* @param flag 参数配置,如信息类型、压缩方式、加密方式等
|
||
* @return 成功返回0
|
||
*/
|
||
rt_uint8_t packInit(MSG *tpl, const rt_uint8_t *fin, rt_uint8_t flag)
|
||
{
|
||
// memset(tpl, 0, sizeof(MSG)); // 分配空间
|
||
// 模板
|
||
MSG msgs_tpl = {
|
||
.fstart = {0x88, 0xAA, 0xBB, 0x88},
|
||
.fnum = {0x00, 0x01},
|
||
.fbak = {0x00, 0x02},
|
||
.ftype = {
|
||
0x70, 0x21},
|
||
.fdlen = {0x00, 0x00},
|
||
|
||
.ftccid = {0x37, 0x32, 0x32, 0x32},
|
||
|
||
.fcfg = flag,
|
||
};
|
||
rt_memcpy(tpl, &msgs_tpl, sizeof(MSG));
|
||
|
||
size_t len = getID(fin, tpl->findex);
|
||
if (len != 7)
|
||
{
|
||
LOG_E("file name %s format error", fin);
|
||
return RT_ERROR;
|
||
}
|
||
|
||
return RT_EOK;
|
||
}
|
||
|
||
/**
|
||
* @description: 按MSG帧格式拼接din数据后输出到dout
|
||
* @param *p_msg MSG格式配置文件
|
||
* @param {rt_uint8_t} *din 待打包数据
|
||
* @param {rt_uint8_t} len 待打包数据长度
|
||
* @param {rt_uint8_t} *dout 打包后数据
|
||
* @return {*} 打包后数据总长度
|
||
*/
|
||
rt_uint8_t packMsg(MSG *p_msg, rt_uint8_t *din, rt_uint8_t len, rt_uint8_t *dout)
|
||
{
|
||
|
||
rt_uint8_t fralen = sizeof(MSG) + len; // len of current frame
|
||
// 计算各字段
|
||
p_msg->fdlen[0] = 0; // 单包长度必不会超过0xFF,故高字节始终为0
|
||
p_msg->fdlen[1] = fralen - 13; // 总长度-帧头长度
|
||
// memcpy(p_msg->findex,id,6);
|
||
|
||
// 将待发数据传入帧数据
|
||
rt_memcpy(p_msg->fdata, din, len);
|
||
|
||
// 将打包后帧数据传入buff
|
||
rt_memcpy(dout, p_msg, fralen);
|
||
|
||
|
||
return fralen;
|
||
}
|
||
|
||
/**
|
||
* @description: 将din按指定长度w分割,再按MSG帧格式拼接
|
||
* @param *cfg MSG格式配置文件
|
||
* @param {rt_uint8_t} *din 待打包数据
|
||
* @param {rt_uint8_t} len 待打包数据长度
|
||
* @param {rt_uint8_t} w 分割长度
|
||
* @param {rt_uint8_t} *dout 打包后数据
|
||
* @return {*} 打包后数据总长度
|
||
*/
|
||
rt_uint8_t packMsgs(MSG *cfg, rt_uint8_t *din, size_t len, rt_uint8_t w, rt_uint8_t (*dout)[200], rt_uint8_t *arrlen)
|
||
{
|
||
if (!(w > 0)) // 无效长度
|
||
{
|
||
w = len;
|
||
}
|
||
rt_uint8_t row = (len / w) + (len % w > 0 ? 1 : 0);
|
||
LOG_I("ROW = %d",row);
|
||
// rt_uint8_t packdata[row][200]; // 打包后数据
|
||
rt_uint8_t tlen[row]; // 打包后数据各维长度
|
||
|
||
cfg->fallpiece[0]=row;
|
||
rt_uint8_t tmplen = 0;
|
||
size_t var=0;
|
||
for (rt_uint8_t index = 0; index< row;index++)
|
||
{
|
||
// rt_uint8_t tmplen = w; // 当前待打包数据的长度
|
||
tmplen = (len - var) > w ? w : (len - var); // 判断最后一包数据的长度
|
||
cfg->fcurpiece[0] = index+1;
|
||
rt_uint8_t col = packMsg(cfg, din+var, tmplen, dout[index]);
|
||
arrlen[index] = col;
|
||
// index++;
|
||
var += w;
|
||
LOG_D("index/row-var-tmplen");
|
||
LOG_D("%5d/%3d-%3d-%6d",index,row,var,tmplen);
|
||
LOG_HEX("per msg",27,dout[index],col);
|
||
}
|
||
|
||
return row;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 将指定文件按帧协议进行切片打包,返回二维数组
|
||
* @param *cfg MSG格式配置文件
|
||
* @param fin 待打包文件名
|
||
* @param flag 配置信息
|
||
* @param dout 打包后二维数组
|
||
* @param arrlen 打包后二维数组各维数组的长度
|
||
* @return
|
||
*/
|
||
rt_uint8_t pack_File(const char *fin, rt_uint8_t flag, const rt_uint8_t (*dout)[200], rt_uint8_t *arrLen)
|
||
{
|
||
static MSG cfg;
|
||
rt_memset(&cfg, 0, sizeof(MSG)); // 分配空间
|
||
rt_uint8_t rst = packInit(&cfg, fin, flag);
|
||
if (rst != RT_EOK)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int fd_in = -1; //, fd_out = -1;
|
||
|
||
size_t file_size = 0;
|
||
rt_uint8_t len = 0;
|
||
// rt_uint8_t *buffer = RT_NULL;
|
||
static size_t flen = 150; // 每包数据初始长度,最大不超过 FRAME_DATA_LEN_MAX
|
||
// rt_uint8_t len = 0;
|
||
|
||
fd_in = open(fin, O_RDONLY, 0);
|
||
if (fd_in < 0)
|
||
{
|
||
LOG_E("open the input file : %s error!\n", fin);
|
||
close(fd_in);
|
||
return len;
|
||
}
|
||
|
||
file_size = lseek(fd_in, 0, SEEK_END);
|
||
LOG_I("file size is %d bytes.", file_size);
|
||
lseek(fd_in, 0, SEEK_SET);
|
||
close(fd_in);
|
||
|
||
// 粗略调整每包大小
|
||
if (file_size > (size_t) FRAME_DATA_LEN_MAX)
|
||
{
|
||
while (file_size % flen < flen / 1.2 && flen < FRAME_DATA_LEN_MAX) // 阈值约83%
|
||
{
|
||
flen += 1;
|
||
}
|
||
if (file_size % flen < flen / 1.2)
|
||
{ // 到达限制仍不符合要求
|
||
flen = 150;
|
||
while (file_size % flen < flen / 2.5 && flen < FRAME_DATA_LEN_MAX) // 调整阈值为40%
|
||
{
|
||
flen += 1;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
flen = file_size;
|
||
}
|
||
|
||
//更新算法,改用特定大小依次读取文件,弃用一次性全部读入文件
|
||
uint8_t row = (file_size / flen) + (file_size % flen > 0 ? 1 : 0);
|
||
cfg.fallpiece[0] = row;
|
||
|
||
uint8_t block_size = 0;
|
||
rt_uint8_t *buffer = RT_NULL;
|
||
buffer = (rt_uint8_t *) rt_malloc(flen);
|
||
if (buffer == RT_NULL)
|
||
{
|
||
LOG_E("No memory for read %s.", fin);
|
||
return 0;
|
||
}
|
||
fd_in = open(fin, O_RDONLY, 0);
|
||
for (size_t i = 0; i < file_size; i += flen)
|
||
{
|
||
if ((file_size - i) < flen)
|
||
{
|
||
block_size = file_size - i;
|
||
}
|
||
else
|
||
{
|
||
block_size = flen;
|
||
}
|
||
// LOG_D("block_size=%d-%d-%d",block_size,i,file_size);
|
||
rt_memset(buffer, 0x00, flen);
|
||
read(fd_in, buffer, block_size);
|
||
// LOG_HEX("hex_file",27,buffer,block_size);
|
||
uint8_t index = (i / flen);
|
||
cfg.fcurpiece[0] = index + 1;
|
||
|
||
//crypt before pack
|
||
uint8_t tmp[200];
|
||
uint8_t len = cryptSingleMsg(buffer, block_size, tmp);
|
||
// LOG_HEX("crypt msg",16,tmp,len);
|
||
uint8_t col = packMsg(&cfg, tmp, len, dout[index]);
|
||
|
||
// uint8_t col = packMsg(&cfg, buffer, block_size, dout[index]);
|
||
arrLen[index] = col;
|
||
// LOG_D("index/row bef-aft");
|
||
// LOG_D("%5d/%3d %3d-%3d",index+1,row,len,col);
|
||
// LOG_HEX("per msg",27,dout[index],col);
|
||
}
|
||
|
||
if (buffer != RT_NULL)
|
||
{
|
||
rt_free(buffer);
|
||
}
|
||
|
||
if (fd_in >= 0)
|
||
{
|
||
close(fd_in);
|
||
}
|
||
|
||
return row;
|
||
}
|
||
|
||
|
||
/**
|
||
* 天通上电
|
||
* @param parameter "0"断电,其它上电
|
||
*/
|
||
void pwTT_thread_entry(void *parameter)
|
||
{
|
||
// LOG_I("--%s--",parameter);
|
||
int f = rt_pin_read(TT_EN);
|
||
int flag = f;
|
||
if (strcmp(parameter,"NULL")==0)//无参数,状态翻转
|
||
{
|
||
flag = !f;
|
||
}
|
||
else
|
||
{
|
||
#ifndef RELAY
|
||
flag = !(rt_bool_t) atoi(parameter);
|
||
#else
|
||
flag = (rt_bool_t) atoi(parameter);
|
||
#endif
|
||
}
|
||
|
||
rt_pin_write(TT_EN, flag);//
|
||
rt_thread_mdelay(300);
|
||
|
||
// if (!flag) {
|
||
// initTT();
|
||
// }
|
||
// else {
|
||
// deInitTT();
|
||
// }
|
||
|
||
|
||
#ifndef RELAY
|
||
if (rt_pin_read(TT_EN))//检查设置后状态
|
||
{
|
||
LOG_I("set TT %s", "OFF");//高电平关断
|
||
// add_val("swCnt");//更新统计值
|
||
}
|
||
else
|
||
{
|
||
// add_val("swCnt");//更新统计值
|
||
LOG_I("set TT %s", "ON");//低电平开启
|
||
}
|
||
#else
|
||
LOG_I("set TT %s", rt_pin_read(TT_EN)?"ON":"OFF");
|
||
#endif
|
||
}
|
||
|
||
static int swTT(int argc, char **argv)
|
||
{
|
||
static char s[5]="NULL";
|
||
if (argc >= 2)
|
||
{
|
||
rt_strcpy(s,argv[1]);
|
||
}
|
||
else {
|
||
rt_strcpy(s,"NULL");
|
||
}
|
||
|
||
/* 创建线程 */
|
||
rt_thread_t thread = rt_thread_create("sw_TT", pwTT_thread_entry, (void *) s, 1024 * 2, 25, 10);
|
||
/* 创建成功则启动线程 */
|
||
if (thread != RT_NULL)
|
||
{
|
||
rt_thread_startup(thread);
|
||
}
|
||
else
|
||
{
|
||
LOG_E("thread 'sw_TT' create failure.");
|
||
return RT_ERROR;
|
||
}
|
||
}
|
||
|
||
MSH_CMD_EXPORT(swTT, 切换TT电源。不带参切换电源状态,支持参数);
|
||
|
||
extern struct rt_messagequeue TTrx_mq;
|
||
void recTT_thread_entry()
|
||
{
|
||
// while(tcpInit() != RT_EOK)
|
||
// {
|
||
// LOG_W("TT server is not ready.");
|
||
// rt_thread_mdelay(100);
|
||
// }
|
||
// LOG_D("TT server is ready.");
|
||
static TTRx_MSG msg;
|
||
static uint8_t bf[1024];
|
||
static size_t dlen=0;
|
||
rt_memset(bf,0,1024);
|
||
while (1)
|
||
{
|
||
if (!isTCPok()) {
|
||
break;
|
||
}
|
||
|
||
rt_memset(&msg, 0, sizeof(msg));
|
||
if (rt_mq_recv(&TTrx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER) == RT_EOK)
|
||
{
|
||
//
|
||
if (!msg.size)
|
||
{ //收到数据长度为0表示tcp断开
|
||
break;
|
||
}
|
||
LOG_I("%d Bytes received from TT",msg.size);
|
||
LOG_HEX("TTrec", 27, msg.data, msg.size);
|
||
|
||
//复制数据
|
||
memcpy(bf,msg.data,msg.size);
|
||
dlen=msg.size;
|
||
//存入log
|
||
char tmp[1024]="";//接收的数据不会很长,200足矣
|
||
trDataTolog(bytes2str(bf, dlen, 16, " ", tmp), strlen(tmp), 0);
|
||
//此处调用处理函数
|
||
parseTTData(bf,dlen);
|
||
}
|
||
}
|
||
// LOG_D("close recTT_thread_entry.");
|
||
}
|
||
//INIT_COMPONENT_EXPORT(recTT_thread_entry);
|
||
|
||
/**
|
||
* 接收TT数据
|
||
*/
|
||
void recTT(void)
|
||
{
|
||
/* 创建线程 */
|
||
rt_thread_t thread = rt_thread_create("recTT", recTT_thread_entry, RT_NULL, 1024 * 10, 24, 10);
|
||
/* 创建成功则启动线程 */
|
||
if (thread != RT_NULL)
|
||
{
|
||
rt_thread_startup(thread);
|
||
}
|
||
else
|
||
{
|
||
LOG_E("thread 'recTT' create failure.");
|
||
return;
|
||
}
|
||
}
|
||
MSH_CMD_EXPORT(recTT,TTrx demo.)
|
||
|
||
/**
|
||
* 更新目标地址
|
||
*/
|
||
void updateTargetAddr(uint8_t *din, uint8_t *addr)
|
||
{
|
||
memcpy(din+13,addr,4);
|
||
}
|