#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