/* * @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 #define LOG_TAG "ttmsg" #define LOG_LVL LOG_LVL_DBG #include #include "ttmsg.h" #include #include 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; 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; } LOG_E("p=%d",flen); //更新算法,改用特定大小依次读取文件,弃用一次性全部读入文件 // static uint8_t row =0; uint8_t row = (file_size / flen) + (file_size % flen > 0 ? 1 : 0); cfg.fallpiece[0] = row; LOG_E("--------row=%d,%d",row,cfg.fallpiece[0]); 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; LOG_E("row=%d,%d",row,cfg.fallpiece[0]); return cfg.fallpiece[0]; } /** * 天通上电 * @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); } void cmdCCID(uint8_t ccid) { uint8_t dout[200]; 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] = 1; uint8_t ack[]={0x37}; size_t rst = packMsg(&cfg, ack, sizeof(ack), dout);//packMsgs // memcpy() sendMsg(dout, rst); } /** * 手动发送心跳 */ void sendACK(void) { uint8_t dout[200]; 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] = 1; uint8_t ack[]={0x37}; size_t rst = packMsg(&cfg, ack, sizeof(ack), dout);//packMsgs if (rst) { uint8_t addr[]={0x39,0x39,0x39,0x39}; updateTargetAddr(dout, addr); if (sendMsg(dout, rst) == RT_EOK) { // LOG_I("send %d bytes to TT Done.",rst); } } }