TLV :即Tag(Type)-Length-Value,它包含三个域,第一个Tag为要封装的数据的类型域,第二个Length为封装的总的数据长度,第三个Value为要装入数据的值。其实就是一个简单的自定义通信协议,将要传送的数据进行编码组织将其发送出去的过程。想要了解的更细致,建议自己可以百度搜索学习,这里就不细述了。下面就以一个例子说一下装包和解包。数据装包
装包的过程其实很简单,只要将你的数据按照包头(PACK_HEADER)、Tag(Type)-Length-Value、校验和的顺序将每个字节按十六进制的形式装进去,形成一个字节流发送出去,如下图:PACK_HEADER自己定义(我定义为0xFD),大小通常为一个字节;Tag也是自己定义,通常为一个字节;Length的大小要看你的数据所占用的字节大小,它的大小为包头大小+Tag大小+Length大小+校验和大小+数据字节大小,自身一般占用一个字节;crc校验和一般占两个字节。crc校验有兴趣可以自己学习,本人也不是很懂,用别人的源码。知道了怎么装包,下面来解释一下**为什么要加包头和校验和进去:**举一个例子,如果我们不加头和尾,要发送的数据为0x01 0x03 0x3c,接收端就会按照Tag(Type)-Length-Value顺序进行解析,知道数据的类型为01,长度为3,值为3c。但是发送的过程中也有可能数据丢失或者混入了其他数据,这时数据有可能会变为0x00 0x01 0x56 0x03 0x23,这时接收端按照之前的顺序解析就会出错,当我们加上头的时候,接收端解析的时候会先找到包头,然后按顺序解析,但是这样还是有出错的可能,但是加上crc校验和之后,crc根据接收到的数据计算出一个校验和,用来和装包装进去的校验和进行比较,如果相同说明这一帧数据正确,接收端才会开始解析数据,如果不正确就不解析。下面是我将获取到的温度进行装包的代码:
intpacktlv_temp(char *buf,int size,float temp){ unsigned short crc16=0; int packlen=0; int ofset=0; int data_len=2; int i,j; float a; if( !buf || !temp || size<TLV_MIN_SIZE ) { printf("Invalid input argumrnts\n"); return 0; } /*pack header*/ buf[ofset]=PACK_HEADER; ofset+=1; /*type*/ buf[ofset]=TAG_TEMP; ofset+=1; /*length*/ /* if( sizeof(temp)<=size-TLV_FIXED_SIZE ) { data_len=sizeof(temp); } else { data_len=size-TLV_FIXED_SIZE; } */ packlen=data_len+TLV_FIXED_SIZE; printf("pack length:%d\n",packlen); buf[ofset]=packlen; ofset+=1; i=(int)temp;/*整数部分*///printf("i=%d\n",i); a=(temp-i)*100;/*小数部分*/ //printf("a=%f\n",a); buf[ofset]=i; ofset+=1; buf[ofset]=a; ofset+=1; crc16 = crc_itu_t(MAGIC_CRC, buf, ofset); ushort_to_bytes(&buf[ofset], crc16); ofset += 2; for(j=0;j<packlen;j++) { printf("0x%02x ",(unsigned char)buf[j]); } printf("\n"); return ofset; }
## 数据解析
解析的过程没有装包那么容易,逻辑性很强而且过程很复杂,建议自己先画一个流程图,搞清解包时所有可能的情况,再来写代码。解包时首先要判断接收到的数据是否为空,在判断整个数据的长度是否比最小长度还要小,满足条件之后开始寻找头,遍历整个接收到数据,一直找到头再开始解析,解析的时候千万别以为就不会出错了,还要判断减去头后的大小是否小于2,小于2说明数据不完整,然后用crc校验,校验正确说明数据没问题可以解析。大概流程就是这样,完整的过程看流程图,如有大佬发现不完整,欢迎指正,共同学习。流程图如下:
下面是代码:
intunpacktlv(char *buf,int bv){ int i; int tlv_len; char *ptr=NULL; float t=0.0; float n,m; unsigned short crc16; unsigned short crc; if( !buf ) { printf("Invailed input!\n"); return 0; } if( buf==NULL ) { printf("buf is NULL!\n"); return 0; } printf("buf is not NULL\n");go_on: if( bv<TLV_MIN_SIZE ) { printf("buf 不完整\n"); return bv; } printf("buf is good!\n"); for(i=0;i<bv;i++) { if( (unsigned char)buf[i]!=PACK_HEADER ) { continue ; } printf("\nFind header!\n"); if( bv-i<2 ) { printf("can not find length...\n"); memmove(buf,&buf[i],bv-i); bv=bv-i; goto go_on; } ptr=&buf[i]; tlv_len=ptr[2]; printf("tlv length:%d\n",tlv_len); if( tlv_len<TLV_MIN_SIZE || tlv_len>TLV_MAX_SIZE ) { printf("tlv_len is error!\n"); memmove(buf,&ptr[2+1],bv-i-2); bv=bv-i-2; goto go_on; } printf("tlv_len is ture!\n"); if( tlv_len>bv-i ) { printf("Error!\n"); memmove(buf,ptr,bv-i); return bv-i; } crc16=crc_itu_t(MAGIC_CRC,(unsigned char*)ptr, tlv_len-2); crc=bytes_to_ushort((unsigned char*)&ptr[tlv_len-2],2) ; if( crc!=crc16 ) { printf("crc is not ture!\n"); memmove(buf,&ptr[tlv_len],bv+tlv_len); bv=bv+tlv_len; goto go_on; } printf("crc is true!\n"); m=ptr[3]; n=((float)ptr[4])/100; //printf("%d\n",ptr[4]); //printf("0x%02x \n",(unsigned char)ptr[4]); t=m+n; printf("Temperature is:%f\n",t); printf("\n"); memmove(buf,&ptr[tlv_len],bv-i-tlv_len); bv=bv-i-tlv_len; goto go_on; } return 0;}