背景
最近买了51822的蓝牙开发板,闲暇之余进行了一些调试,目前还没有深究蓝牙协议的原理。借助git上51822的现有安卓例程以及开发板自带程序,基本可以实现Android手机和开发板间的数据传递,那么,问题来了。
数据用什么样的格式传递呢?如果数据量小的话可以自定义一些规则进行解析,记得做毕业设计的时候就是自定义了几个tag,单片机通过串口发送带Tag的字符串,上位机根据Tag解析数据,显然这种方法并不通用。Json大概是安卓开发中传递数据使用的最广泛的传输格式了,那么,能不能自己写个json工具框架呢?当然能了.....只是有点麻烦而已。目前已经完成了单片机JSON的生成。
实现
单片机实现一个Json框架有什么困难呢?我觉得最大的障碍就是内存管理了,要知道,这种没有mmu和linux操作系统的单片机,很多时候并不能直接进行malloc相关的堆操作。而json这种结构化数据的操作则需要大量辅助的数据结构,比如树和链表都需要我们对内存进行频繁操作,如果不进行特殊处理是很难在单片机上完成的。
在单片机上使用内存,我们多用的是数组,在代码编译的时候编译器回自动给我们的数组分配一段连续内存空间供我们操作。显然,我们可以利用这段内存来当作我们存放结构化数据的内存空间,而我们要做的就是提供一套规则,对这段内存进行操作。
在实际操作中,由于单片机的种类繁多,各种函数的实际使用效果也不相同,尤其是sizeof函数,很多时候不能正确测量类型长度,所以对于结构体数据最好是手动指定内存大小。
51822中的核心是使用CM0作为微控制器,我们在mdk下使用c语言进行开发。
基本结构
#define JSONTYPE_KV 1
#define JSONTYPE_ARR 2
/**
*键值对
*/
typedef struct _JSONNode{
struct _JSONNode *next;
struct _JSONNode *prev;
//JSONOBJ
int type; //Node类型,分为普通键值对和JSON数组
char *key; //键
int keyLength; //键字符串的长度
//key_value type==JSONTYPE_KV
char *value; //值
int valueLength; //值字符串长度
//JSONARRAY ARRAY type==JSONTYPE_ARR
int arrayLength; //值为JSON数组时数组元素个数<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
struct _JSONObjectNode **objectNode; //数组
}JSONNode;
/**
* JSONObject 主要用于JSON数组
*/
typedef struct _JSONObjectNode{
//JSONARRAY
JSONNode **jsonNode; //JSON Obj中的jsonNode链表,也就是每个JSON对象中的所有键值对都有链表存储
int length; //链表的长度
struct _JSONObjectNode *next; //指向下一个jsonNode节点
}JSONObjectNode;
/**
* JSON主干列表
*/
typedef struct _JSONList{
JSONNode *start;
JSONNode *end;
int length;
}JSONList;
具体实现方法
内存管理
<span style="font-weight: normal;"><span style="font-size:12px;">char TypeMem[MY_TYPE_MALLOC_SIZE];
char *mPtr = TypeMem;
char *mPtrRecord = TypeMem;
//**********自定义的malloc***********
void *myMemMalloc(int size){
char *ptr = mPtr;
mPtr = mPtr + size;
return ptr;
}
void myMemFree(void *ptr){
//myfree(ptr);
mPtr = mPtrRecord;
memset(mPtrRecord, 0, MY_TYPE_MALLOC_SIZE);
}
void myMemCpy(void *des,void *src,int n){
//mem_memcpy(des, src, n);
memcpy(des, src, n);
}
//**********获取一个JSONNode的内存空间******************
JSONNode *newJSONNode(){
JSONNode *node = myMemMalloc(sizeof(JSONNode));
return node;
}
//***********获取一个JSONObject的内存空间******************
JSONObjectNode *newJSONObjectNode(){
JSONObjectNode *node = myMemMalloc(24);
return node;
}</span></span>
JSON生成
JSONList *initLinkList(){
//int length = sizeof(JSONList); //由于不能保证这个函数在任何单片机上直接可以使用,此处写死
JSONList *ret = myMemMalloc(24);
ret->start = NULL;
ret->end = NULL;
ret->length = 0;
return ret;
}
void initJSONNode(JSONNode *node, char *key, char *value, int type){
node->key = key;
node->value = value;
node->keyLength = strlen(key);
node->valueLength = strlen(value);
node->type = type;
}
/**
* 添加一个普通JSON键值对
*/
void addNode(JSONList *list, char *key, char *value){
JSONNode *node = NULL;
node = newJSONNode();
if(list->length == 0){
node->next = NULL;
node->prev = NULL;
list->start = node;
list->end = node;
}else{
node->next = NULL;
node->prev = list->end;
list->end->next = node;
list->end = node;
}
list->length++;
node->type = JSONTYPE_KV;
node->keyLength = strlen(key);
node->valueLength = strlen(value);
node->key = key;
node->value = value;
}
/**
* 添加一个JSON Array键值对
*/
void addJSONArray(JSONList *list, char *key, JSONObjectNode **value, int length){
JSONNode *node = NULL;
int i;
JSONNode *indexNode = list->start;
int sameKeyFlag = 0;
while(indexNode != NULL){ //遍历查看是否已经有这个键
int cmp = strcmp(indexNode->key, key);
if(cmp == 0){
sameKeyFlag = 1;
node = indexNode; //如果存在,直接获取节点
break;
}
indexNode = indexNode->next;
}
if(sameKeyFlag == 0){ //如果不存在,创建一个节点加入链表
node = newJSONNode();
node->arrayLength = -1;
if(list->length == 0){
node->next = NULL;
node->prev = NULL;
list->start = node;
list->end = node;
}else{
node->next = NULL;
node->prev = list->end;
list->end->next = node;
list->end = node;
}
list->length++;
}
node->type = JSONTYPE_ARR;
node->keyLength = strlen(key);
//node->valueLength = strlen(value);
node->key = key;
//node->array[node->arrayIndex] = value;
//node->arrayIndex++;
node->value = NULL;
node->valueLength = 0;
node->objectNode = value;
node->arrayLength = length;
}
/**
* 将普通jsonNode转换为字符串的形式
*/
char *getJSONObjString(char *mem, int *index, JSONNode *nodePtr){
char *str = NULL;
mem[(*index)++] = '"';
memcpy(mem+(*index), nodePtr->key, nodePtr->keyLength);
*index = *index + nodePtr->keyLength;
mem[(*index)++] = '"';
mem[(*index)++] = ':';
memcpy(mem+(*index), nodePtr->value, nodePtr->valueLength);
*index = *index + nodePtr->valueLength;
mem[(*index)] = '\0';
str = mem;
return str;
}
/**
* 将json数组转换为字符串,如果嵌套了数组则会递归转换
*/
char *getJSONArrayString(char *mem, int *index, JSONNode *nodePtr){
char *str = NULL;
int i,j;
int length = nodePtr->arrayLength;
int type;
mem[(*index)++] = '"';
memcpy(mem+(*index), nodePtr->key, nodePtr->keyLength);
*index = *index + nodePtr->keyLength;
mem[(*index)++] = '"';
mem[(*index)++] = ':';
if(length > 0){
mem[(*index)++] = '[';
for(i=0; i<length; i++){
JSONObjectNode *objectNode;
if(i == 0){
objectNode = nodePtr->objectNode[i];
}else{
objectNode = objectNode->next;
}
mem[(*index)++] = '{';
for(j=0; j<objectNode->length; j++){
type = objectNode->jsonNode[j]->type;
if(type == JSONTYPE_KV){
getJSONObjString((mem), index, objectNode->jsonNode[j]);
}else if(type == JSONTYPE_ARR){
getJSONArrayString((mem), index, objectNode->jsonNode[j]);
}
mem[(*index)++] = ',';
}
mem[(*index)-1] = '}';
if(i < nodePtr->arrayLength-1){
mem[(*index)++] = ',';
}
}
mem[(*index)++] = ']';
}
mem[(*index)] = '\0';
str = mem;
return str;
}
/**
* 转换主干JSON列表为字符串
*/
char *getJsonString(JSONNode **start, int length){
int i,j;
int arrayLength;
JSONNode *nodePtr = *start;
char *jsonStr = myMemMalloc(256);
int index = 0;
jsonStr[0] = '{';
index++;
for(i=0; i<length; i++){
if(nodePtr != NULL){
if(nodePtr->type == JSONTYPE_KV){
getJSONObjString(jsonStr, &index, nodePtr);
}else if(nodePtr->type == JSONTYPE_ARR){
getJSONArrayString(jsonStr, &index, nodePtr);
}
jsonStr[index] = ',';
index++;
}
nodePtr = nodePtr->next;
}
jsonStr[index-1] = '}';
jsonStr[index] = '\0';
return jsonStr;
}
使用例程
char* testJSON(){
JSONList *list = initLinkList(); //初始化主干list
JSONObjectNode *obj1 = newJSONObjectNode(); //初始化jsonArray中的元素
JSONObjectNode *obj2 = newJSONObjectNode();
obj1->jsonNode = myMemMalloc(24);
obj2->jsonNode = myMemMalloc(24);
addNode(list, "name", "chen"); //添加键值对
addNode(list, "abcd", "chenchen");
addNode(list, "gender", "female");
addNode(list, "age", "27");
JSONNode *node1 = newJSONNode(); //给jsonArray中的元素赋值
initJSONNode(node1, "key1", "value1", JSONTYPE_KV);
JSONNode *node2 = newJSONNode();
initJSONNode(node2, "key2", "value2", JSONTYPE_KV);
obj1->jsonNode[0] = node1; //将jsonArray中的元素链接
obj1->jsonNode[1] = node2;
obj1->length = 2;
JSONNode *node3 = newJSONNode();
initJSONNode(node3, "key3", "value3", JSONTYPE_KV);
JSONNode *node4 = newJSONNode();
initJSONNode(node4, "key4", "value4", JSONTYPE_KV);
obj2->jsonNode[0] = node3;
obj2->jsonNode[1] = node4;
obj2->length = 2;
obj1->next = obj2; //将jsonArray中的数据串起来
addJSONArray(list, "array", &obj1, 2); //为jsonArray加一个键
char *str = getJsonString(&(list->start), list->length); //生成json字符串
return str;
}
由于开发板串口驱动不对,我们无法直接看到打印数据,我们直接将数据通过蓝牙返回了手机
这就是我们最后生成的json数据。
最后付一下源码下载的地址,有待继续完善 https://git.oschina.net/vonchenchen/Embed_C_JSON_Utils.git