单片机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;
} 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;
JsonPair *jsonPairMalloc(){
void *ptr = structureCurrPtr;
int size = sizeof(JsonPair);
structureMemCnt += size;
if(structureMemCnt > MEM_SIZE_STRUCTURE)
return NULL;
structureCurrPtr = structureCurrPtr + structureMemCnt;
return (JsonPair *)ptr;
}
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;
char *dataMemMalloc(int size){
char *ptr = dataCurrPtr;
dataCurrPtr = dataCurrPtr + size;
return ptr;
}
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
JsonObject *createJsonObject(){
JsonObject *ptr = jsonObjectMalloc();
ptr->jsonPair = NULL;
ptr->lastJsonPair = NULL;
ptr->length = 0;
return ptr;
}
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->next = NULL;
}else{
jsonPair->next = NULL;
rootObject->lastJsonPair->next = jsonPair;
rootObject->lastJsonPair = jsonPair;
}
rootObject->length++;
return rootObject;
}
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)] = '
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮