|
本帖最后由 dukelec 于 2021-10-19 03:56 编辑
很早之前就一直在用 MessagePack(简称 msgpack),不过是在电脑和服务器,我一直觉得 msgpack 很适合 MCU,但之前一直没有机会在 MCU 里面用它
msgpack 和 json 差不多,不过 msgpack 可以包含二进制数据,MCU 处理起来比 json 方便超多,所以用来代替 json
最近需要在 MCU 里面使用 msgpack,找了一圈,没有相中的库,我的需求是足够简约且不使用 malloc
所以开始自己写,msgpack 对于 MCU 有一个让我很不爽的地方是,它是大端的,需要转换来转换去
思考了很久,打算创建一个小端版本的 MessagePack 分支:MessagePackEL,除了大小端,其它完全一致
我建的分支已经包含了 C、Python 和 Javascript 的实现: https://github.com/dukelec/msgpackel
其中 C 实现是我新写的,使用方法我贴过来:
(如果你想用于 大端 的 msgpack,库改起来也很简单)
譬如一个数据结构:
- {
- "dev": "abc123",
- "data": {
- "voltage": 3.6,
- "angle": [45, 90]
- }
- }
复制代码
转换成字节流的示范:
- uint8_t msg_buf[256];
- size_t prepare_data(void)
- {
- uint8_t *pos = msg_buf;
- pos = mpk_w_map_hdr(pos, 2); // create top map
- pos = mpk_w_str(pos, "dev"); // create first item
- pos = mpk_w_str(pos, "abc123");
- pos = mpk_w_str(pos, "data"); // create second item
- pos = mpk_w_map_hdr(pos, 2); // create sub map
- pos = mpk_w_str(pos, "voltage");
- pos = mpk_w_float(pos, 3.6f);
- pos = mpk_w_str(pos, "angle");
- pos = mpk_w_array_hdr(pos, 2);
- pos = mpk_w_int(pos, 45);
- pos = mpk_w_int(pos, 90);
- return pos - msg_buf; // return length
- }
复制代码
解析字节流的示范:
- void check_data(void)
- {
- mpk_t st;
- uint8_t *payload, *end;
- size_t num;
- float voltage;
- st = mpk_map_search(msg_buf, NULL, NULL, (uint8_t *)&voltage, NULL,
- "data", "voltage", NULL); // must end with NULL
- if (st == MPK_FLOAT)
- printf("found data.voltage: %f\n", voltage);
- else
- printf("parse data.voltage error: %d\n", st);
- st = mpk_map_search(msg_buf, &payload, &end, NULL, NULL,
- "dev", NULL);
- if (st == MPK_STR) {
- int str_len = end - payload;
- printf("found dev: %.*s\n", str_len, payload); // print non-null terminated string
- } else {
- printf("parse dev error: %d\n", st);
- }
- st = mpk_map_search(msg_buf, &payload, NULL, NULL, &num,
- "data", "angle", NULL);
- if (st == MPK_ARRAY) {
- uint8_t *pos = payload;
- printf("data.angle[] length: %d\n", num);
- for (int i = 0; i < num; i++) {
- int32_t val; // val must be at least 4 bytes
- st = mpk_parse(pos, NULL, &end, (uint8_t *)&val, NULL);
- if (st != MPK_INT && st != MPK_UINT) {
- printf(" parse data.angle error\n");
- break;
- }
- printf(" data.angle[%d]: %ld\n", i, val);
- pos = end;
- }
- } else {
- printf("parse data.angle error: %d\n", st);
- }
- }
复制代码
服务器也可以同时支持 json 和 msgpack,收到 json 就回覆 json,收到 msgpack 就回 msgpack,中间处理完全相同,譬如:
- #!/usr/bin/env python3
- import cgi, sys, os, json
- import umsgpackel
- mime = os.environ.get('CONTENT_TYPE', '')
- is_mpk = True if mime.find('msgpackel') != -1 else False
- if is_mpk:
- print('Content-Type: application/msgpackel; charset=binary\n')
- else:
- print('Content-Type: application/json; charset=utf-8\n')
- sys.stdout.flush()
- if is_mpk:
- data = sys.stdin.buffer.read(int(os.environ.get('CONTENT_LENGTH', 0)))
- else:
- data = sys.stdin.read(int(os.environ.get('CONTENT_LENGTH', 0))) # default=0
- if data: # for POST
- class Form(dict):
- pass
- if is_mpk:
- unpk = umsgpackel.unpackb(data)
- else:
- unpk = json.loads(data)
- form = Form(unpk)
- form.getvalue = form.get
- else: # for GET
- form = cgi.FieldStorage()
- #dev = form.getvalue('dev')
- # do some work ...
- print(f"receive: {unpk} |", file=sys.stderr)
- if is_mpk:
- sys.stdout.buffer.write(umsgpackel.packb({"status": "ok"}))
- else:
- print(json.dumps({"status": "ok"}))
复制代码
这是 http(s) 的示范,msgpack 也可以用于 mqtt 传输,同样是取代 json |
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|