原创 用 C 封装串口数据协议,可用于流式传输

2008-8-12 16:07 3413 10 10 分类: 软件与OS
#define OUT
#define INOUT
#define IN

#define INIT_LIST_HEAD(x)    

#define btsc_TRUE     0
#define btsc_FALSE    1
#define btsc_NULL     0

struct list_head{
    struct list_head* prev,*next;
};


struct btsc_Property{
    char *         name;
    char *         value;        
};


struct btsc_Packet{
    /*struct list_head    list;*/
    struct btsc_Property**     properties;
    int                size;
    int                capacity;
    struct btsc_Context    *    ctx;
};

struct btsc_Packet*     btsc_Packet_Alloc(struct btsc_Context* );
void                    btsc_Packet_Free(struct btsc_Packet*);

struct btsc_Property*    btsc_Property_Alloc(struct btsc_Context* ,char * name,char * value);
void                    btsc_Property_Free(struct btsc_Property*);


struct btsc_Property*     btsc_Property_Get(struct btsc_Packet* packet,char * name);     
void                    btsc_Property_Append(struct btsc_Packet* packet,struct btsc_Property * );


struct btsc_Context{
    void (*tx)(struct btsc_Context*,unsigned char * data,int len);        
    int (*notifier)(struct btsc_Packet* packet);/*外部释放packet,返回NULL*/        
    int        packet_cached_size;
    int        recv_cached_capacity;                        
    char*    recv_buff;                                    
    int        recv_size;        
    void*    user;    // 外部数据传递                            
};


int     btsc_init(struct btsc_Context* IN ctx);    
void     btsc_cleanup(struct btsc_Context* IN ctx);
int        btsc_Pack(struct btsc_Context* IN ctx,struct btsc_Packet* packet,unsigned char * INOUT buff,int* INOUT size);    
void    btsc_Parse(struct btsc_Context* , char * data,int len);


#define BTSC_PACKET_BEGIN(ctx) {\
                                struct btsc_Context* _ctx_internel;\
                                struct btsc_Packet * _pkt ;\
                                _ctx_internel= (ctx);\
                                _pkt = btsc_Packet_Alloc(_ctx_internel);
                                
/* key is not suitable for vairable*/                                
#define BTSC_NEW_PROPERTY(key,value)    {\
                                            struct btsc_Property * _ppt =btsc_Property_Alloc(_ctx_internel,key,value);\
                                            btsc_Property_Append(_pkt,_ppt);\
                                        }
#define BTSC_PACKET_END()        btsc_Pack(_ctx_internel,_pkt,btsc_NULL,0);\
                                btsc_Packet_Free(_pkt);\
                                }

#define BTSC_FOREACH(packet,ppt)    {\
                                    int n;\
                                    for(n=0;n<packet->size;n++){\
                                        ppt = packet->properties[n];
#define BTSC_END_FOREACH()            }\
                                }








/*
    name:            btsc
                    serial communicating  with bluetooth and app-user
    desc:            pair parameter codec
   
        packet=[ key:name,...]
       
    implemented:     zhangbin ,  3 hours occupied
    date:            2007-01-26
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _UNIX
#include <unistd.h>
#endif
#include "btsc.h"

#define PACKET_HEAD        '<'
#define PACKET_TAIL        '>'
#define PROPERTY_DELIMITER    ','
#define PAIR_DELIMITER        '='
#define ESCAPE_CHAR            '\\'


int calcEscapleLength(char * str);
char* escape_copy(char * dest,char * src);
void trim_escape_copy(char * dest,char * src,int size);
int  calcPacketLength(struct btsc_Packet* pkt);
int    is_escape_char(char c);
void parseProperty(struct btsc_Packet * pkt,char * s,char * e);
void parsePacket(struct btsc_Context* ctx,char * s,char* e);
char*     __memchr(char * s,char* e,char c);

char escape_ch_table[]={PACKET_HEAD,PACKET_TAIL,PROPERTY_DELIMITER,PAIR_DELIMITER,ESCAPE_CHAR,'\0'};

struct btsc_Packet*     btsc_Packet_Alloc(struct btsc_Context* ctx){   
    struct btsc_Packet * pt = malloc(sizeof(struct btsc_Packet));       
    pt->size = 0;
    pt->capacity = ctx->packet_cached_size;
    pt->properties=malloc(pt->capacity*sizeof(struct btsc_Property*));   
    pt->ctx = ctx;
    return pt;   
}

void    btsc_Packet_Free(struct btsc_Packet* pt){   
    struct btsc_Property** tmp;
    if( !pt )     return ;
    tmp = pt->properties;
    while(pt->size--){
        btsc_Property_Free(*tmp++);               
    }       
    if( pt->properties){
        free(pt->properties); 
    }
    free(pt);
}


struct btsc_Property*    btsc_Property_Alloc(struct btsc_Context* ctx,char * name,char * value){
    struct btsc_Property * ppt;
    printf("enter btsc_Property_Alloc()\n");
    ppt = malloc( sizeof( struct btsc_Property) );
    if(!ppt)    printf("error: malloc failed (s1)\n");
    ppt->name = malloc( strlen(name)+1);
    if( !ppt->name ) printf("error: malloc failed (s2)\n");
    strcpy(ppt->name,name);   
    ppt->value = malloc( strlen(value)+1);
    if( !ppt->value) printf("error: malloc failed (s3),str:%s, len: %d\n",value,strlen(value)+1);
    strcpy( ppt->value,value);
    return ppt;
}

void        btsc_Property_Free(struct btsc_Property* ppt){
    if( !ppt )    return;
    free( ppt->name);
    free( ppt->value);
    free( ppt);
}

/* scan pointer array */
struct btsc_Property*     btsc_Property_Get(struct btsc_Packet* pkt,char * name){
    int size;
    struct btsc_Property* ppt;
    size = pkt->size;
    while(size--){
        ppt = pkt->properties[size];
        if( !strcmp( name, ppt->name ) ){
            return ppt;/*that's ok */
        }
    }
    return btsc_NULL;
}

/* low effeciency, memory allocation,more costs*/
void    btsc_Property_Append(struct btsc_Packet* pt,struct btsc_Property * ppt){
    struct btsc_Property** tmpppt;
    if( pt->size==pt->capacity){        
        pt->capacity += pt->ctx->packet_cached_size;   
        tmpppt = pt->properties;       
        pt->properties = malloc( pt->capacity * sizeof( struct btsc_Property**) );
        memcpy( pt->properties, tmpppt, pt->size * sizeof( struct btsc_Property**));
        free( tmpppt);
    }
    pt->properties[pt->size++]=ppt;   
}

int     btsc_init(struct btsc_Context* ctx){   
    ctx->packet_cached_size = 10;   
    if( ctx->recv_cached_capacity==0){
        ctx->recv_cached_capacity = 1024*2;   
    }
    ctx->recv_buff = malloc( ctx->recv_cached_capacity );
    ctx->recv_size = 0;
    return btsc_TRUE;
}

void     btsc_cleanup(struct btsc_Context* ctx){
    free(ctx->recv_buff);   
}

/*
**    name:    calcEscapleLength
**    desc:    计算含转义字符串长度
*/
int     calcEscapleLength(char * str){
    int len;
    char * pesc;
    len = 0;   
    while( *str ){
        pesc = escape_ch_table;
        while( *pesc ){
            if( *pesc==*str){
                len++;
                break;
            }
            pesc++;
        }       
        str++;
    }   
    return len;
}


char* escape_copy(char * dest,char * src){
    char * pesc;
    while( *src ){
        pesc = escape_ch_table;
        while( *pesc ){
            if( *pesc==*src){
                *dest++=ESCAPE_CHAR;
                break;
            }
            pesc++;
        }
        *dest++=*src++;               
    }   
    return dest;   
}

void trim_escape_copy(char * dest,char * src,int size){
    int last_escape = btsc_FALSE;
    while( size--){
        if( *src == ESCAPE_CHAR && last_escape != btsc_TRUE){       
            last_escape = btsc_TRUE    ;
            src++;
            continue;
        }
        last_escape = btsc_FALSE;
        *dest++=*src++;       
    }
}

int       calcPacketLength(struct btsc_Packet* pkt){
    int len;
    int size;
    struct btsc_Property* ppt;   
    len = 0;
    size = pkt->size;
    while( size--){
        ppt = pkt->properties[size];   
        len+=strlen(ppt->name)+strlen(ppt->value);   

        len+= calcEscapleLength(ppt->name);
        len+= calcEscapleLength(ppt->value);   
    }
    len+= pkt->size*2+1;
    return  len;
}


int        btsc_Pack(struct btsc_Context*  ctx,struct btsc_Packet* pkt,unsigned char * obuff,int* osize){
    struct btsc_Property* ppt;
    int size;
    int len;
    unsigned char * buff;
    char * pbuff;
    len = calcPacketLength( pkt);
    buff = malloc( len );
    size = pkt->size;
    pbuff = (char*)buff;
    *pbuff++=PACKET_HEAD;   
    while( size--){
        ppt = pkt->properties[size];   
        pbuff = escape_copy(pbuff,ppt->name);
        *pbuff++=PAIR_DELIMITER;
        pbuff = escape_copy(pbuff,ppt->value);
        if( size ){
            *pbuff++=PROPERTY_DELIMITER;           
        }
    }
    *pbuff = PACKET_TAIL;
    if( ctx->tx ){
        ctx->tx(ctx,buff,len);
    }
    if( obuff && *osize >=len){
        memcpy( obuff, buff ,len);
        *osize = len;
    }

    free(buff);
    return btsc_TRUE;   
}

/* e not in range*/
char*     __memchr(char * s,char* e,char c){
    while( s!=e){
        if( *s == c){
            return s;
        }       
        s++;
    }
    return btsc_NULL;
}

int        is_escape_char(char c){
    return btsc_FALSE;   
}

/*
    name: parseProperty
    desc: 指定内存范围中提取属性  key=>value
        搜索包含e
    params:   
        pkt    --    消息数据包
        s    --    起始内存地址
        e    --    结束地址 ,
*/
void parseProperty(struct btsc_Packet * pkt,char * s,char * e){
    char * p1,*p2;
    int n;
    struct btsc_Property*    ppt;
    p1 = s ;
    p2 = e;
__REPEAT:   
    p1 = __memchr(p1,e+1,PAIR_DELIMITER);
    if( p1 ){
        if( *(p1-1) == ESCAPE_CHAR ){
            p1++;
            goto __REPEAT;
        }
        ppt = malloc( sizeof( struct btsc_Property ));
        n = p1-s;        
        ppt->name = malloc( n+1 );
        memset(ppt->name,0,n+1);       
        trim_escape_copy(ppt->name,s,n);
       
        n =e-p1;
        ppt->value = malloc( n+1);
        memset(ppt->value,0,n+1);
        trim_escape_copy(ppt->value,p1+1,n);
       
        btsc_Property_Append(pkt,ppt);
    }
}

/*
    name: parsePacket
    desc:    分解指定内存到包结构
            成功分解出包立刻回送到应用接收者 ( btsc_Context::notifier)
    param:
        s,e     内存地址 (处e)

** 缓冲区还需进一步测试,包括缓冲区大小调节, 不完整协议包格式的容错
*/
void     parsePacket(struct btsc_Context* ctx,char * s,char* e){
    char *p,*p1,*p2;
    struct btsc_Packet * pkt;
    if( e-s <=1 ){
        return ;
    }
    pkt = btsc_Packet_Alloc(ctx);
   
    p1 = s+1;
    p2 = e-1;
    p = p1;
__REPEAT:   
    p = __memchr(p,e,PROPERTY_DELIMITER);
    if( p ){
        if( *(p-1)==ESCAPE_CHAR){
            p = p+1;
            goto __REPEAT;
        }
        parseProperty(pkt,p1,p-1);
        p1 = ++p;
        goto __REPEAT;
    }
    /*allow one property reside in*/
    parseProperty(pkt,p1,e-1);
    if( ctx->notifier ){
        if(ctx->notifier(pkt)){ /* nonzero value, delete internal*/
            btsc_Packet_Free(pkt);           
        }
    }else{
       btsc_Packet_Free(pkt);   
    }
}

void    btsc_Parse(struct btsc_Context* ctx, char * data,int size){
    int len ;
_RESTART:
    while( size ){
        len = ctx->recv_cached_capacity - ctx->recv_size;
        if( len >0){
            if( size <= len){
                len = size;
                size = 0;
            }else{
                size-=len;
            }
            memcpy( ctx->recv_buff+ctx->recv_size,data,len);
            ctx->recv_size+=len;
            data+=len;
        }   
       
        {
            char * p1,*p2;           
_RESCAN:           
            p1 = ctx->recv_buff;
_RESCAN_HEAD:             
            p1 = __memchr(p1,ctx->recv_buff+ctx->recv_size,PACKET_HEAD);           
            if( !p1 ){
                ctx->recv_size =0;
                if( size ){
                    goto _RESTART;
                }
            }
            if( p1>ctx->recv_buff && *(p1-1)==ESCAPE_CHAR){ /* "\<" */
                p1++;
                goto _RESCAN_HEAD;   
            }
           
            /*move backward*/
            ctx->recv_size -=(p1-ctx->recv_buff);
            memmove(ctx->recv_buff,p1, ctx->recv_size);
            p1=ctx->recv_buff;
            p2 = p1+1;
_RESCAN_TAIL:           
            p2 = __memchr(p2,ctx->recv_buff+ctx->recv_size,PACKET_TAIL);
            if( !p2 ){
                if( ctx->recv_size == ctx->recv_cached_capacity ){
                    ctx->recv_size  = 0;
                }
                goto _RESTART;
            }
            if( *(p2-1) == ESCAPE_CHAR ){
                p2++;
                goto _RESCAN_TAIL;   
            }
           
            parsePacket(ctx,p1,p2);
            ctx->recv_size -=p2-p1+1;
            if( ctx->recv_size ){
                memmove(ctx->recv_buff,p2+1,ctx->recv_size);
                goto _RESCAN;
            }             
        }       
    }
}

/*   debug */
#ifdef _DEBUGX
void tx(unsigned char * data,int len);
void notifier(struct btsc_Packet* packet);
/*初始化上下文, tx="发送处理函数",notifier=接收函数*/
struct btsc_Context c={tx:tx,notifier:notifier};

/*测试数据接收并解析*/
void rx(){   
     char * msg="<MSG=HELLO,NAME=SCOTT>"
                 "<MSG2=HELLO2,NAME2=SCOTT2>"
                 "<MSG3=HELLO3,NAME3=SCOTT3>"; /*simulating data*/
    int len = strlen(msg);
    btsc_Parse(&c,msg,len);
}
/*发送处理过程*/
void tx(unsigned char * buff,int len){   
    char *outmsg = malloc(1024*10);
    memset(outmsg,0,1024*10);
    memcpy(outmsg,buff,len);
    printf("encode str: %s\n",outmsg);
    free(outmsg);
    btsc_Parse(&c,buff,len);
}

void notifier(struct btsc_Packet* packet){
    struct btsc_Property * ppt;
    ppt = btsc_Property_Get(packet,"MSG");
    if(ppt)
        printf("property get: MSG=>%s\n",ppt->value);
    /*遍历包内属性参数*/
    BTSC_FOREACH(packet,ppt);
    printf("packet: %s=>%s\n",ppt->name,ppt->value);
    BTSC_END_FOREACH();
}

int main(){
    int r;
    /*optional*/
    c.recv_cached_capacity = 1024; /*初始化接收缓冲区大小 byte*/
    c.packet_cached_size = 5;    /*消息包缓冲属性个数*/
    btsc_init(&c);            /*上下文初始化*/
    puts("test rx()...");
    rx();    /*接*/
    puts("escape testing...");   
    do{
        /*构造消息包,并完成发送*/
        BTSC_PACKET_BEGIN(&c);
        BTSC_NEW_PROPERTY("MSG","calling");

        BTSC_PACKET_END();   
        usleep(1000*50);
        printf(">>seq:%d\n",r);
    }while(0);
       
    btsc_cleanup(&c);   
   
    return 0;
}


#endif
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
10
关闭 站长推荐上一条 /3 下一条