/* * 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 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+11) { 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+11) { 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+11) 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+11) LOG_HEX("frame",16,ndin,cnt); parse3SData(ndin,cnt); } } } #endif #include #include /** * 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