单片机Json框架的实现

2019-04-15 18:10发布

背景

月初写了一个简单的单片机json生成框架,目的是想为蓝牙开发板封装一套协议。加班了小一个月,终于有时间喘口气搞搞自己的东西了….回过头来看,发现很多不足之处,抽空进行了一些重构。主要修改了以下几个方面:
1.修改了基本的数据结构,统一抽象为 JsonPair 与 JsonObject,方便解析;
2.重新定义了内存管理模块,将结构存储与数据存储分开管理,这样方便根据不同的MCU进行相应调整;
3.重新实现了相应的方法

基本结构

上一篇文章中定义的结构比较混乱,虽然可以较为容易地实现json的生成,但是解析时就会使程序变得异常混乱,所以我将json结构重新抽取为
JsonPair和JsonObject,json数组就是若干JsonObject组成。
typedef struct _JsonPair{ char *key; char *value; int keyLength; int valueLength; struct _JsonObject **obj; int jsonObjLength; int valueType; struct _JsonPair *next; //struct _JsonPair *prev; //char* (* setPair)(struct _JsonPair *this, char *key, char *value); //char* (* getValue)(struct _JsonPair *this, char *key); } JsonPair; typedef struct _JsonObject{ struct _JsonPair *jsonPair; struct _JsonPair *lastJsonPair; struct _JsonObject *next; int length; } JsonObject;
其中JsonPair即为json键值对,可以存储的值为字符串或者json数组,定义valueType用来区分jsonPair中存储内容的类型。struct _JsonObject *obj是一个jsonObject 的数组。同时JsonPair又可以串成一个链表。
我们还定义了JsonObject,里面用来存储jsonPair的链表,两个解构是递归定义的。
下图为基本结构
这里写图片描述

内存管理

单片机上对内存的操作比较麻烦,我们可以直接使用数组作为内存。这样做的好处是内存地址是连续的,我们知道结构体中的地址也是连续的,也就是说我们可以直接把结构体的首地址指向一片足够大的内存,这样结构体变可存值了。定义结构体时应当注意内存对齐。此处我们优化了内存管理结构,将“存储结构的内存”和“存储数据的内存”分离开来,根据情况分别为其分配空间。
char memStructure[MEM_SIZE_STRUCTURE]; char memJsonData[MEM_SIZE_JSONDATA]; char memJsonParse[MEM_SIZE_JSONPARSEDATA]; /****************************************** *Structure Memory Manager *******************************************/ char *structureBasePtr = memStructure; char *structureCurrPtr = memStructure; int structureMemCnt = 0; //malloc jsonPair JsonPair *jsonPairMalloc(){ void *ptr = structureCurrPtr; int size = sizeof(JsonPair); structureMemCnt += size; if(structureMemCnt > MEM_SIZE_STRUCTURE) return NULL; structureCurrPtr = structureCurrPtr + structureMemCnt; return (JsonPair *)ptr; } //malloc jsonObj JsonObject *jsonObjectMalloc(){ void *ptr = structureCurrPtr; int size = sizeof(JsonObject); structureMemCnt += size; if(structureMemCnt > MEM_SIZE_STRUCTURE) return NULL; structureCurrPtr = structureCurrPtr + structureMemCnt; return (JsonObject *)ptr; } char *structureMemFree(){ memset(memJsonData, 0, MEM_SIZE_STRUCTURE); structureBasePtr = memJsonData; structureCurrPtr = memJsonData; structureMemCnt = 0; return structureBasePtr; } /****************************************** *Data Memory Manager *******************************************/ char *dataBasePtr = memJsonData; char *dataCurrPtr = memJsonData; int dataMemIndex = 0; //malloc json data memory char *dataMemMalloc(int size){ char *ptr = dataCurrPtr; dataCurrPtr = dataCurrPtr + size; return ptr; } //free json data memory char *dataMemFree(){ memset(dataBasePtr, 0, MEM_SIZE_JSONDATA); dataBasePtr = dataBasePtr; dataCurrPtr = dataBasePtr; dataMemIndex = 0; return dataBasePtr; } /****************************************** *Data Memory Manager *******************************************/ char *memJsonParseFree(){ memset(dataBasePtr, 0, MEM_SIZE_JSONDATA); }
目前还不能支持多任务操作系统进行任务间切换,除非为不同任务定义不同的存储空间,否则只能顺序转换。

json生成与解析

有了上面的示意图我们即可知道,json生成其实相当于创建一棵树,然后将其顺序转换为字符串。json的解析就是将字符串按照一定顺序取出,然后创建一棵树。
生成json /**************************************** * generate json *****************************************/ JsonObject *createJsonObject(){ JsonObject *ptr = jsonObjectMalloc(); //json-pair header ptr->jsonPair = NULL; //json-pair rear ptr->lastJsonPair = NULL; ptr->length = 0; return ptr; } //add a normal key-value pair JsonObject *addJsonPair(JsonObject *rootObject, char *key, char *value){ JsonPair *jsonPair = jsonPairMalloc(); jsonPair->key = key; jsonPair->keyLength = strlen(key); jsonPair->value = value; jsonPair->valueLength = strlen(value); jsonPair->valueType = VALUE_TYPE_NORMALPAIR; if(rootObject->jsonPair == NULL){ rootObject->jsonPair = jsonPair; rootObject->lastJsonPair = jsonPair; //jsonPair->prev = NULL; jsonPair->next = NULL; }else{ //jsonPair->prev = rootObject->lastJsonPair; jsonPair->next = NULL; rootObject->lastJsonPair->next = jsonPair; rootObject->lastJsonPair = jsonPair; } rootObject->length++; return rootObject; } //get json key-value as string char *generateJsonPairString(char *mem, int *index, JsonPair *jsonPair){ char *str = NULL; mem[(*index)++] = '"'; memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength); *index = *index + jsonPair->keyLength; mem[(*index)++] = '"'; mem[(*index)++] = ':'; memcpy(mem+(*index), jsonPair->value, jsonPair->valueLength); *index = *index + jsonPair->valueLength; mem[(*index)] = '