/******************************************************************************** * File Name: ModemTcpComm.c * Function Describe: 通过TCP与服务器通信(TCP通信协议) * Explain: * Writer: * Date: *******************************************************************************/ #define THIS_FILE_ID 8 /*******************************************************************************/ #include "includes.h" //------------------------------------------------------------------------------- SUT_TCP_STATUS sutTcpStatus; SUT_LOGIN_ACK sutLoginAck={0,0,0,0,0,0,0,0,0}; SUT_FOTA_PARA sutFotaPara; //UploadCode和UploadCodeAck 用于确保本地待上传的数据与服务器数据一致性 //本地数据发生变化,需要上传时,将UploadCode加1并确保UploadCode!=UploadCodeAck //服务器收到后原值回传,本地收到服务器回复后覆盖UploadCodeAck //当检查到UploadCode!=UploadCodeAck时,将触发上传 unsigned char g_ucUploadCode=0; //上传标志码,每次上传前先自动加1 unsigned char g_ucUploadCodeAck=128;//上传标志码服务器回传码 static void IapGetUpdateData(uint32_t offset,uint16_t len); static char IapCheckFileMD5_SPI_Flash(unsigned int dataAddr,unsigned int length,uint8_t *MD5); //============================================================================== //@Functions //@brief 将32位大小端数据格式转换 //@param //@retval 转换后的数据 //============================================================================== unsigned int BigLittle32Conv(unsigned int srcData) { SUTDL dl1, dl2;//用于大小端转换 dl1.Data.ulData = srcData; dl2.Data.ucData.b1 = dl1.Data.ucData.b4; dl2.Data.ucData.b2 = dl1.Data.ucData.b3; dl2.Data.ucData.b3 = dl1.Data.ucData.b2; dl2.Data.ucData.b4 = dl1.Data.ucData.b1; return dl2.Data.ulData; } //============================================================================== //@Functions //@brief 将16位大小端数据格式转换 //@param //@retval 转换后的数据 //============================================================================== unsigned short BigLittle16Conv(unsigned short srcData) { SUTDS ds1, ds2;//用于大小端转换 ds1.Data.usData = srcData; ds2.Data.ucData.b1 = ds1.Data.ucData.b2; ds2.Data.ucData.b2 = ds1.Data.ucData.b1; return ds2.Data.usData; } //============================================================================== //@Functions //@brief 从pStr中找到pSearch,返回pSearch后的第一个地址(若无para则返回0)。可配合 StrNumToInt() 使用 //举例:pStr=" "WorkEnable":1,"PowerOnTimeAdj":[123,45,-78,90], " // 如果pSearch="TimeAdj":[" 返回"123,45,-78,90], " // 如果pSearch="Work":" 返回"Enable":1,"PowerOnTimeAdj":[123,45,-78,90], " // 如果pSearch="abcd":" 返回NULL //@param //@retval pSearch后的第一个地址 //============================================================================== char* SearchFromStr(char *pStr,char *pSearch) { char *pResult; unsigned char searchLen; pResult = strstr(pStr, pSearch); if(pResult == NULL) { return NULL; } searchLen = strlen(pSearch); pResult += searchLen; return pResult; } //============================================================================== //@Functions //@brief 指定位置开始,到非数字字符结束的数字字符串转换成整形数值(数值范围-2147483648~2147483647) // "65535,a" --> 65535(十六进制0xFFFF),返回5 // "-123" --> -123(十六进制0x85),返回4 // " -123" --> -123(十六进制0x85),返回5 // "123456789,kk"--> 123456789,返回9 //@param 输入: *pStrNum 字符串数字开始的指针 // 输出 *pNum 转换的值 //@retval 转换的字符串中数字长度(含"-"号和空格),0失败 //============================================================================== static unsigned char StrNumToInt(int *pNum, char *pStrNum) { char i, numLen = 0; char buf[11] = {0}; for(i = 0; i < 10; i++) { if(pStrNum[i]>0x39 || pStrNum[i]<0x30) { if(pStrNum[i] != ' ' && pStrNum[i] != '-') break; } buf[i] = pStrNum[i]; numLen = i + 1; } buf[i] = 0; *pNum = atoi(buf); return numLen; } //============================================================================== //@Functions //@brief 获取 指定位置开始,到"结束的 字符串内容,并返回实际长度,若无",则获取最大长度 // 17010001" --> 17010001(ASCII),返回8 // //@param 输入: *pStr 字符串开始的指针 maxLen // 输出 *pAsc 转换的值 //@retval 转换的字符串长度 //============================================================================== static unsigned char StrToAsc(char *pAsc, char *pStr, unsigned char maxLen) { char i, numLen = 0; for(i = 0; i < maxLen; i++) { if(pStr[i] == '\"') break;//到"结束 pAsc[i] = pStr[i]; numLen = i + 1; } pAsc[i] = 0; return numLen; } /******************************************************************************** Packing 打包函数 按数据包格式将pdata的数据打包到pTcpBuf中 格式: |Head|Cmd|Length(2)| DATA(n)| Check | Length 是从DATA...到Check的数据长度(包含了Check)即Length=n+1 返回包长 包长应等于Length+4 也等于n+5 *********************************************************************************/ unsigned short TcpPacking(unsigned char *pBuf,unsigned char cmd,unsigned short datalen,unsigned char *pdata) { unsigned char i; unsigned char check=0; unsigned short len; if(datalen>(TCP_SEND_BUF_LEN-6))return 0; pBuf[0]=TCP_PACKET_HEAD; check=TCP_PACKET_HEAD; pBuf[1]=cmd; check^=cmd; len=datalen+1; pBuf[2]=(unsigned char)((len>>8)&0xff); check^=pBuf[2]; pBuf[3]=(unsigned char)(len&0xff); check^=pBuf[3]; for(i=0;isizeof(data))return 0; if(sutProductPara.PSN==0 || 0==CheckAKey())return 0;//AKEY无效 不允许登陆 sutLoginInfo.ASN=sutProductPara.PSN; sutLoginInfo.AKEY=sutProductPara.AKEY; memcpy(sutLoginInfo.CCID,sutModemStatus.CCID,20); memcpy(sutLoginInfo.Model,sutProductPara.ProductName,sizeof(sutLoginInfo.Model)); sutLoginInfo.Ver=sutProductPara.SoftwareVer; sutLoginInfo.Rand=sutModemStatus.CSQ; memcpy(data,&sutLoginInfo,sizeof(SUT_LOGIN)); ds.Data.usData=sutLoginInfo.Ver; data[8]=ds.Data.ucData.b2; data[9]=ds.Data.ucData.b1; dl.Data.ulData=sutLoginInfo.ASN; data[12]=dl.Data.ucData.b4; data[13]=dl.Data.ucData.b3; data[14]=dl.Data.ucData.b2; data[15]=dl.Data.ucData.b1; dl.Data.ulData=sutLoginInfo.AKEY; data[16]=dl.Data.ucData.b4; data[17]=dl.Data.ucData.b3; data[18]=dl.Data.ucData.b2; data[19]=dl.Data.ucData.b1; return TcpPacking(pBuf,CMD_LOGIN,sizeof(SUT_LOGIN),data); } /********************************************************************************* PackingSendTest 打包成SendTick信息包,存放在pBuf中 *********************************************************************************/ unsigned short TcpPackingSendTick(unsigned char *pBuf) { // unsigned char *pTemp; // unsigned short i,j,k; // unsigned char check=0; // unsigned short len; // //unsigned short datalen=sutTestData.TcLen+24; // if(datalen>(TCP_SEND_BUF_LEN-6))return 0; // j=0; // pBuf[j++]=TCP_PACKET_HEAD; // check=TCP_PACKET_HEAD; // pBuf[j++]=CMD_SEND_TEST; // len=datalen+1; // pBuf[j++]=(unsigned char)((len>>8)&0xff); // pBuf[j++]=(unsigned char)(len&0xff); // pBuf[j++]=sutTestData.NetMode; // pBuf[j++]=sutTestData.CSQ; // pBuf[j++]=(unsigned char )((sutTestData.GpsNum>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.GpsNum&0xff); // pBuf[j++]=(unsigned char )((sutTestData.BDNum>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.BDNum&0xff); // // pTemp=(unsigned char *)&sutTestData.Longitude; // for(i=8;i>0;i--){ // pBuf[j++]=pTemp[i-1]; // } // pTemp=(unsigned char *)&sutTestData.Latitude; // for(i=8;i>0;i--){ // pBuf[j++]=pTemp[i-1]; // } // pBuf[j++]=(unsigned char )((sutTestData.Speed>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.Speed&0xff); // pBuf[j++]=(unsigned char )((sutTestData.Aspect>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.Aspect&0xff); // // // for(i=0;i(TCP_SEND_BUF_LEN-6))return 0; // j=0; // pBuf[j++]=TCP_PACKET_HEAD; // check=TCP_PACKET_HEAD; // pBuf[j++]=CMD_SEND_TEST; // len=datalen+1; // pBuf[j++]=(unsigned char)((len>>8)&0xff); // pBuf[j++]=(unsigned char)(len&0xff); // pBuf[j++]=g_ucUploadCode; // pBuf[j++]=sutTestData.NetMode; // pBuf[j++]=sutTestData.CSQ; // pBuf[j++]=sutTestData.GpsNum; // pBuf[j++]=sutTestData.BDNum; // // // pTemp=(unsigned char *)&sutTestData.Longitude; // for(i=8;i>0;i--){ // pBuf[j++]=pTemp[i-1]; // } // pTemp=(unsigned char *)&sutTestData.Latitude; // for(i=8;i>0;i--){ // pBuf[j++]=pTemp[i-1]; // } // pBuf[j++]=(unsigned char )((sutTestData.Speed>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.Speed&0xff); // pBuf[j++]=(unsigned char )((sutTestData.Aspect>>8)&0xff); // pBuf[j++]=(unsigned char)(sutTestData.Aspect&0xff); // // // for(i=0;iFileName, info)) {//文件名和版本号不对,结束升级 SlwTrace(DEBUG, "FNameErr\r\n"); sutLoginAck.NewVer=0;//结束升级 sutTcpStatus.ServerStatus=CLOSED; sutFotaPara.fotaStatus=FOTA_END; return; } dl1.Data.ulData=pFileInfo->FileLength; dl2.Data.ucData.b1=dl1.Data.ucData.b4; dl2.Data.ucData.b2=dl1.Data.ucData.b3; dl2.Data.ucData.b3=dl1.Data.ucData.b2; dl2.Data.ucData.b4=dl1.Data.ucData.b1; sutFotaPara.fileLength=dl2.Data.ulData; sutFotaPara.encrypted=pFileInfo->encrypted; sutFotaPara.key=pFileInfo->key; memcpy(sutFotaPara.MD5,pFileInfo->MD5,16); if(sutFotaPara.fileLength==0) {//服务器没有文件,退出升级 SlwTrace(DEBUG, "NoFileInServer"); sutLoginAck.NewVer=0;//结束升级 sutTcpStatus.ServerStatus=CLOSED; sutFotaPara.fotaStatus=FOTA_END; return; } sutFotaPara.lastOffset=-1; sutFotaPara.nextOffset=0; sutFotaPara.tcpCnt=0; sutFotaPara.fotaStatus=FOTA_GET_FILEDATA; sutTcpStatus.FoTa=OPENED; sutTcpStatus.ServerStatus=OPENED; break; case CMD_GET_FILE_DATA_ACK: SlwTrace(DEBUG,"CMD_GET_FILE_DATA_ACK<<\r\n"); unsigned int thisOffset; //offset dl1.Data.ucData.b4=pData[4]; dl1.Data.ucData.b3=pData[5]; dl1.Data.ucData.b2=pData[6]; dl1.Data.ucData.b1=pData[7]; thisOffset=dl1.Data.ulData; //lenght ds.Data.ucData.b2=pData[8]; ds.Data.ucData.b1=pData[9]; thisLen=ds.Data.usData; //save SPI_Flash_Write(pData+10,APP_FILE_DATA_ADDR+thisOffset,thisLen); //done? if((thisOffset+thisLen) >= sutFotaPara.fileLength) { snprintf(info,sizeof(info), "\r\nHBD=%d\r\nLoad done\r\n",sutFotaPara.fileLength); SlwTrace(DEBUG, info); //校验 if(0!=IapCheckFileMD5_SPI_Flash(APP_FILE_DATA_ADDR, sutFotaPara.fileLength, sutFotaPara.MD5)) {//较验成功,准备跳转到IAP前准备 memcpy(sutDeviceConfig.MD5, sutFotaPara.MD5,sizeof(sutDeviceConfig.MD5)); sutDeviceConfig.AppExAddr=APP_FILE_DATA_ADDR; sutDeviceConfig.AppLen=sutFotaPara.fileLength; sutDeviceConfig.FoTaMark[0]='F';sutDeviceConfig.FoTaMark[1]='o';sutDeviceConfig.FoTaMark[2]='T';sutDeviceConfig.FoTaMark[3]='a'; SaveDeviceConfigToFlash(); SlwTrace(DEBUG, "GoingUpdate\r\n"); //系统复位 SystemReset(); }else{ SlwTrace(INF, "Md5Err"); //重新升级 sutFotaPara.fotaStatus=FOTA_GET_FILEINFO; sutTcpStatus.ServerStatus=CLOSED; } }else{ sutFotaPara.tcpCnt=0; sutFotaPara.lastOffset=sutFotaPara.nextOffset; sutFotaPara.nextOffset=thisOffset+thisLen; snprintf(info,sizeof(info), "\r\nHBD=%d\r\n",sutFotaPara.lastOffset); SlwTrace(DEBUG, info); } break; case CMD_LOGIN_REJECT://鉴权失败,拒绝登陆 sutTcpStatus.LoginWaitTime=(unsigned short)pData[4]&0xff; if(sutTcpStatus.LoginWaitTime==0)sutTcpStatus.LoginWaitTime=3600;//1小时 else sutTcpStatus.LoginWaitTime*=60; break; } } /******************************************************************* 封包,获取新版本 |Head|Cmd|length(2) | data... | Check| Head 包头,固定为0xAB Cmd 命令字 length 后续的数据长度,包括到Check的长度 length=1+data.len Check 从Head开始按字节异或运算 data: unsigned long PSN; //终端编号 unsigned char FileName[20]; //文件名 如:RT101_V102.bin unsigned long offset; //请求数据在文件中的开始位置 unsigned short len; //请求数据的长度,服务器返回的数据可能小于等于此长度 *******************************************************************/ unsigned short PacketGetFileData(unsigned char *buf,unsigned int offset,unsigned short len) { unsigned char checksum; unsigned short i,j; char FileName[21]; SUTDL dl; SUTDS ds; j=0; memset(buf,0,35); buf[j++]=TCP_PACKET_HEAD; buf[j++]=CMD_GET_FILE_DATA; buf[j++]=0; buf[j++]=30+1;//数据18字节,1字节checksum //PSN dl.Data.ulData=sutProductPara.PSN; //因为协议要求大端模式传输,所以需要转一下 buf[j++]=dl.Data.ucData.b4; buf[j++]=dl.Data.ucData.b3; buf[j++]=dl.Data.ucData.b2; buf[j++]=dl.Data.ucData.b1; //FileName snprintf(FileName,sizeof(FileName), "%s_V%d.bin", sutProductPara.ProductName,sutLoginAck.NewVer); for(i=0;i<20;i++){ buf[j++]=FileName[i]; } //offset dl.Data.ulData=offset; //因为协议要求大端模式传输,所以需要转一下 buf[j++]=dl.Data.ucData.b4; buf[j++]=dl.Data.ucData.b3; buf[j++]=dl.Data.ucData.b2; buf[j++]=dl.Data.ucData.b1; //len ds.Data.usData=len; buf[j++]=ds.Data.ucData.b2; buf[j++]=ds.Data.ucData.b1; //校验 checksum=0; for(i=0;i1024)l=1024; else l=length-len; SPI_Flash_Read(data,dataAddr+len,l); MD5Update(&mdContext,data,l); len+=l; } MD5Final(&mdContext); //check for(i=0;i<16;i++){ if(MD5[i]!=mdContext.digest[i])break; } if(i<16)return 0; else return 1; } void TcpCommInit(void) { memset(&sutTcpStatus,0,sizeof(SUT_TCP_STATUS)); memset(&sutLoginAck,0,sizeof(SUT_LOGIN_ACK)); memset(&sutFotaPara,0,sizeof(SUT_FOTA_PARA)); } /*******************************************************************************/