TLV通信協議之TLV封包的實現

  • TLV通信協議的簡介

TLV,即Tag(Type)—Length—Value,是一種簡單實用的數據傳輸方案。在TLV的定義中,可以知道它包括三個域,分別爲:標籤域(Tag),長度域(Length),內容域(Value)。這裏的長度域的值實際上就是內容域的長度。

  • 只用TLV可能會出現問題

問題1:數據可能重合!如果你設置0x01爲溫度,那麼後面如果還有個有個0x01可能是表示其他的數據的,而不是溫度,這就會導致數據的重合。

解決方案:爲了避免這個問題我們需要加一個報頭,固定爲0xFD,用來標誌一個報文的開始。

問題2:數據可能會跳變出錯!我們不能保證數據傳輸過程中數據不會發生跳變而導致接受端收到錯誤的信息,如:0x01表示溫度,跳變爲0x02就表示另外的東西了。

解決方案:我們需要在一個字節流末尾加一個CRC校驗,傳輸前算一下字節流的大小,傳輸到另外一個端口後再算一下,對比前後兩個CRC的值,如果相同,表示沒有發生字節跳變,如果不同,那就捨棄!

加工後的TLV:

  • TLV封包的實現 

    1、頭文件 

    #ifndef  _TLV_PACK_H_
    #define  _TLV_PACK_H_
    
    #include <stdint.h>
    #include <time.h>
    
    #define PACK_HEADER        0xFD 
    #define TLV_FIXED_SIZE     5
    #define TAG                0x01 
    #define TLV_BUFSIZE        256
    
    typedef struct tlv_buf_s 
    {
        char                   buf[TLV_BUFSIZE];
        int                    len;  /* data length */
        int                    size; /* buffer size */
    } tlv_buf_t;  
    int packtlv_time(char *buf, int size, struct tm *tm);
    
    int packtlv_msg(tlv_buf_t *tlv,struct tm *tm);
    
    void dump_buf(char *data, int len);
    
    #endif   /* ----- #ifndef _TLV_PACK_H_  ----- */
    
    

    2、源文件 

    /*********************************************************************************
     *      Copyright:  (C) 2020 shx
     *                  All rights reserved.
     *
     *       Filename:  tlv_pack.c
     *    Description:  This file 
     *                 
     *        Version:  1.0.0(04/20/2020)
     *         Author:  tianjincheng <[email protected]>
     *      ChangeLog:  1, Release initial version on "04/20/2020 03:28:26 PM"
     *                 
     ********************************************************************************/
    #include <stdio.h>
    #include <string.h>
    #include "tlv_pack.h"
    #if 1
    int main(int argc, char *argv[])
    {
        tlv_buf_t tlv;
        time_t tmp;  
        struct tm *s_ptime;
        time(&tmp);  
        s_ptime = localtime(&tmp);
    
        packtlv_msg(&tlv, s_ptime); //將tlv的數據進行封包
        dump_buf(tlv.buf, tlv.len); //打印封包後的數據
    
        return 0;
    }
    
    #endif 
    int packtlv_time(char *buf, int size, struct tm *tm)
    {
        int     ofset = 0;   //記錄buf的偏移量
        int     tlv_len = 0; //記錄tlv的length 
        if (!buf|| size < TLV_FIXED_SIZE +6) //參數合法性檢測
        {
            printf("error input argms\n");
            return -1;
        }
    
        buf[ofset] = PACK_HEADER;  //加入head
        ofset += 1; 
        buf[ofset] = TAG;          //加入tag
        ofset += 1;
        tlv_len = TLV_FIXED_SIZE +6;   //加入length
        buf[ofset] = tlv_len;
        ofset += 1;
        /*加入value */
        buf[ofset++] = tm->tm_year +1900; 
        buf[ofset++] = tm->tm_mon  + 1;
        buf[ofset++] = tm->tm_mday;
        buf[ofset++] = tm->tm_hour;
        buf[ofset++] = tm->tm_min;
        buf[ofset++] = tm->tm_sec;
    
        return ofset;
    
    }
    
    #if  1
    int packtlv_msg(tlv_buf_t *tlv,struct  tm *tm)
    {
        int               rv = 0;
        if( !tlv )
        {
            return -1;
        }
    
        memset(tlv->buf, 0, sizeof(tlv->buf));   /*  將buf置空 */
        tlv->size = sizeof(tlv->buf);            /*  設置buf的初始size*/
        tlv->len = 0;                            /*  設置buf的初始數據長度 */
    
        if( tm )
        {
            rv = packtlv_time(&tlv->buf[tlv->len], tlv->size, tm);
            if( rv > 0 )
            {
                tlv->len += rv;
                tlv->size -= rv;
            }
    
        }
        return 0;
    }
    
    void dump_buf(char *data, int len)
    {
        int  i = 0;
        for (i = 0; i< len; i++)
        {
            printf("0x%02x ", (unsigned char)data[i]);
        }
        puts(" ");
    }
    #endif 
    

     

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章