|
好像挺长时间没来这边了,过来转转,也继续和大家交流RT-Thread的情况
这个月底就要发布RT-Thread 1.2.0 beta了,貌似1.2.0稍微有些偏离原来设定的目标(注:原来设定的目标是文档),反而花了很多力气时间在机器间互联上面。
例如RT-Thread 1.2.0 beta版本将默认使用lwIP 1.4.1的版本,而lwIP 1.4.0在长时间高负荷通信测试时依然会存在些问题,1.4.1则修正掉了。1.4.0的PPP也存在问题的,1.4.1相应的也修正了。应了一句话,主流的情况下,lwIP是没问题的,其他的还是需要自己仔细多多测试。
谈到机器间通信,火热些就是物联网,规矩些就是分布式运算,俗气些就是两个芯片间相互发发消息。
所以简单的就是,两个芯片通过UART、SPI、IIC,甚至是以太网,GPRS,WIFI,BLE连起来,然后相互发一个hello。
不过嵌入式设备还是C语言用得比较多,相互发消息就得写C代码(所以RT-Thread的finsh shell用的就是C代码的语法表达式解析),如果说可以做到下面的,这就挺好了:
Machine #1
void my_thread(void*)
{
send("hello");
rt_kprintf("%s\n", recv());
}
Machine #2
void my_thread(void*)
{
if (strcmp(recv(), "hello") == 0)
{
send("hi");
}
}
不过这样的问题微观些,显然很糟糕,发过去对方不响应怎么办,发过去对方乱发东西怎么办。接收这边,直接接收过来,memory谁来处理?
因为Machine上运行的是代码,所以要正确通信,需要写一个正确,规范的代码给Machine,否则对方如何正确理会呢。
代码还是代码,既然Machine上主要还是使用C代码,那么我们就基于C代码定义些规则。
Rule #1
Machine与Machine直接是进行数据交互,翻译成C代码就是,C的结构体,例如:
struct foo
{
char msg[32];
int code;
};
Machine #1发送一个struct foo给Machine #2。当然Machine #2也可以回复另外一个结构体,例如:
struct result
{
int code;
};
Rule #2
Machine与Machine之间应该发送的数据,而不是指针。
为什么不是指针,因为指针指向的数据肯定是本地的,把指针发过去肯定不靠谱。
Rule #3
Machine与Machine之间可以通过数据交互完成大部分操作,例如远程RPC:
struct rpc_request
{
char proc[32];
int argc;
int argv[8];
};
struct rpc_result
{
int rc;
};
在struct rpc_request::proc中给出远端要执行的函数,然后argc是参数的个数,argv是参数(但这里仅局限于整数)。struct rpc_result给出了执行这个函数后的返回值。
显然当一个函数复杂时(各类参数,参数返回值等),这样是行不通的!
为了简化问题,我们先暂时继续这个rpc_request/rpc_result。
Machine与Machine之间既然是基于C结构体交互的,那么我们直接对C结构体进行处理不就可以么?!但是选择二进制交互吗?如果是跨架构,跨语言,跨越云端呢?现在web好像蛮普遍吧,web里有个东西,json (http://www.json.org)。例如一个struct rpc_request可以用这个json来表示:
{"proc":"list_thread", "argc":0, "argv":[0, 0, 0, 0, 0, 0, 0, 0]}
对应的结果struct rpc_result可以表示成:
{"rc":0}
完全基于文本方式进行,挺简单明了的,读起来容易懂。
我们把上面的rpc结构体变成一个头文件:
#ifndef __RPC_H__
#define __RPC_H__
#include <mjson.h>
struct rpc_request
{
char proc[32];
int argc;
int argv[8];
};
JSON_EXPORT(rpc_request);
struct rpc_result
{
int rc;
};
JSON_EXPORT(rpc_result);
#endif
是否可以有一个程序把头文件中的结构体,生成出转换这些结构体到json的函数?例如说,rpc_request_decode_json/rpc_request_encode_json.这样当要进行交换结构体时,可以由底层自动做掉。例如生成的代码类似这样:
/* This file is generated by mjsonc. Do not edit. */
#include "rpc_mjson.h"
#include <stdio.h>
#ifdef WIN32
#define snprintf _snprintf
#endif
rt_size_t rpc_request_encode_json(struct rpc_request* self, rt_uint8_t* buf, rt_size_t size)
{
uint32_t index;
rt_uint8_t *ptr = buf;
ptr += snprintf((char*)ptr, size - (ptr - buf), "{");
ptr += snprintf((char*)ptr, size - (ptr - buf), "\"proc\":\"%.*s\"", 32, self->proc);
ptr += snprintf((char*)ptr, size - (ptr - buf), ", \"argv\":[");
ptr += snprintf((char*)ptr, size - (ptr - buf), "%d", self->argv[0]);
for (index = 1; index < 8; index ++)
{
ptr += snprintf((char*)ptr, size - (ptr - buf), ", %d", self->argv[index]);
}
ptr += snprintf((char*)ptr, size - (ptr - buf), "]");
ptr += snprintf((char*)ptr, size - (ptr - buf), ",\"argc\": %d", self->argc);
ptr += snprintf((char*)ptr, size - (ptr - buf), "}");
return ptr - buf;
}
rt_size_t rpc_result_encode_json(struct rpc_result* self, rt_uint8_t* buf, rt_size_t size)
{
rt_uint8_t *ptr = buf;
ptr += snprintf((char*)ptr, size - (ptr - buf), "{");
ptr += snprintf((char*)ptr, size - (ptr - buf), "\"rc\": %d", self->rc);
ptr += snprintf((char*)ptr, size - (ptr - buf), "}");
return ptr - buf;
}
void rpc_request_decode_json_with_node(struct rpc_request* self, struct json_node* node)
{
uint32_t index;
struct json_node* child;
snprintf(self->proc, 32, "%.*s", 32, json_node_get_string(node, "proc", RT_NULL));
child = json_get_node(node, "argv", RT_NULL);
for (index = 0; index < 8; index ++)
self->argv[index] = json_node_get_integer(json_node_get_array(child, index, RT_NULL), RT_NULL);
self->argc = json_node_get_integer(node, "argc", RT_NULL);
}
MJSON_DECODE_DEFINE(rpc_request);
void rpc_result_decode_json_with_node(struct rpc_result* self, struct json_node* node)
{
self->rc = json_node_get_integer(node, "rc", RT_NULL);
}
MJSON_DECODE_DEFINE(rpc_result);
假设和远程的服务端进行交互,可以按照类似下面的代码来调用:
void mjson_http(void)
{
struct rpc_request request;
struct rpc_result result;
/* request .... */
memset(&request, 0x0, sizeof(struct rpc_request));
strcpy(request.proc, "list_thread");
/* 假设服务端访问链接是http://192.168.10.10/json.php */
mjson_do_http("http://192.168.10.10/json.php", "rpc_request", &request,
"rpc_result", &result);
rt_kprintf("result: %d\n", result.rc);
}
总结下,当要进行Machine与Machine间交互时,需要定义个C结构,如果是http方式,调用
mjson_do_http(URI, "request", &request, "result", &result);
来进行自动交互数据。
如果是UART,则可以是mjson_do_uart,其它的类推(例如IIC,SPI等)。当然也可以是:mjson_do(URI, ....);具体的传输方式由URI来指定。
Machine可以是执行RT-Thread的终端,也可以是运行web服务器的超强server,或者是手机、平板、电视。反正Machine与Machine之间通过json进行数据沟通,C结构体自动通过mjsonc编译器生成相应的json编码和解码函数。 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|