最近有幸接触到了microduino及其生产的microwrt,貌似也叫wrtnode。一个比较吸引人的地方在于:这么一块小小的板子上可以跑小型版的linux系统——openwrt,它又属于业界最近比较火的智能硬件的一种,于是就开始接触一点,期待令人惊喜的应用。
由于我用的是台式机,所以至少要有两块硬件,一个是WRTnode核心板,另一个就是串口转USB板FT232R(windows需要安装它的驱动)。接线也简单,需要注意WRTnode上的TX,RX引脚要分别与FT232R上的TX,RX引脚要对应,用跳线连接即可。示意图如下:
串口工具有很多种,像putty,securecrt都行,我用的是xshell。设置好串口后,就开始连接。如果正常的话输入用户与密码就可进入了。
我的目录是希望WRTnode成为无线中继,即既是AP也是STA。那么就需要配置板子上的wifi模块,如果是笔记本,方便些,无线连接后用浏览器即可;台式机没办法配,所以我就用手机登陆了。详细过程可参考附录,目的很简单,就是让它再连接上一个已经接入公网的路由器。当我点击最终的"保存&应用"时,串口终端打印如下:
此时,再ping下百度就会发现可以连接公网了,这样,一块小板子就真正成了一个可以联网的linux主机了。此时再ifconfig:
apcli0 Link encap:Ethernet HWaddr 02:0C:43:76:20:D0 (这是配好后新增的,显然连接上了192.168.13.1路由器)
inet addr:192.168.13.101 Bcast:192.168.13.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:9 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
br-lan Link encap:Ethernet HWaddr 00:0C:43:76:20:77
inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6945 errors:0 dropped:18 overruns:0 frame:0
TX packets:4657 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:652041 (636.7 KiB) TX bytes:1169944 (1.1 MiB)
eth2 Link encap:Ethernet HWaddr 00:0C:43:76:20:77
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:1004 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:316458 (309.0 KiB)
Interrupt:3
eth2.1 Link encap:Ethernet HWaddr 00:0C:43:76:20:77
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:440 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:94806 (92.5 KiB)
eth2.2 Link encap:Ethernet HWaddr 00:0C:43:76:20:78
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:564 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:221652 (216.4 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:12408 errors:0 dropped:0 overruns:0 frame:0
TX packets:12408 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:847659 (827.7 KiB) TX bytes:847659 (827.7 KiB)
ra0 Link encap:Ethernet HWaddr 00:0C:43:76:20:D0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:992 errors:0 dropped:0 overruns:0 frame:0
TX packets:654 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:173964 (169.8 KiB) TX bytes:359565 (351.1 KiB)
Interrupt:4
不过暂不太清楚为啥会有这么多接口,也许需要补充下openwrt的知识了。接下来,能有什么样的应用就看我们个人的发挥了。
【11.4补充】
找了个无线上网卡,插在台式机上,恰好可以以telnet方式连入开发板,就不在用串口方式了
按照附录教程,我创建了一个helloworld程序,目录结构如下:
在SDK顶层目录上make,即在build_dir\target-mipsel_24kec+dsp_uClibc-0.9.33.2\helloworld下生成了可执行文件,用file命令检测时不能够执行,因为是交叉编译:
当然在bin\ramips\packages\base也有一个关于helloworld的ipk文件,但是安装时出现以下问题:
但是当用winscp把helloworld执行文件放上去时,它是可以执行的:
【11-17更新】
依照helloworld例子,我实现了自己的业务逻辑:即在openwrt系统上将模拟的传感器数据传至yeelink云平台,核心代码如下:
char http_request[512] = {0,};
char yeelink_server[] = "api.yeelink.net";
char temp_path[] = "/v1.0/device/9966/sensor/19877/datapoints";
char switch_path[] = "/v1.0/device/9966/sensor/22595/datapoints";
char apikey[] = "d3d565a59151cd21f3a";
int srvfd;
void makeString(const char* tempstr)
{
memset(http_request,0,sizeof(http_request));//每次重组时都要把http_request给清了
//double value = 30;
char http_attribute[64] = {0,};
// Http内容,表单内容
char http_content[64] = {0,};
// 确定HTTP表单提交内容
sprintf( http_content , "{\"value\":%.4s}" , tempstr);
// 确定 HTTP请求首部
// 例如POST /v1.0/device/1949/sensor/2510/datapoints HTTP/1.1\r\n
char http_header[64] = {0,};
sprintf( http_header , "POST %s HTTP/1.1\r\n",temp_path);
strcpy( http_request , http_header );
// 增加属性 例如 Host: api.yeelink.net\r\n
sprintf( http_attribute , "Host:%s\r\n" , yeelink_server);
strcat( http_request , http_attribute);
// 增加密码 例如 U-ApiKey: ffa3826972d6cc7ba5b17e104ec59fa3
sprintf( http_attribute , "U-ApiKey:%s\r\n" , apikey);
strcat( http_request , http_attribute);
// 增加提交表单内容的长度 例如 Content-Length:12\r\n
sprintf( http_attribute , "Content-Length:%d\r\n" ,strlen(http_content) );
strcat( http_request , http_attribute);
// 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
// 该步骤可省略
strcat( http_request , "Content-Type:application/x-www-form-urlencoded\r\n");
// HTTP首部和HTTP内容 分隔部分
strcat( http_request , "\r\n");
// HTTP负载内容
strcat( http_request , http_content);
}
void make_socket_and_connect()
{
struct sockaddr_in remote_sockaddr;
struct hostent *remote_host;
int result;
#ifdef _WIN32
WSADATA wsaData;
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
printf("WSAStartup failed: %d\n", result);
return;
}
#endif
// DNS解析 获得远程IP地址
remote_host = gethostbyname(yeelink_server);
if( remote_host == NULL )
{
printf("DNS failed\r\n");
return;
}
// 创建套接字
srvfd = socket(AF_INET, SOCK_STREAM, 0);
remote_sockaddr.sin_family = AF_INET;
remote_sockaddr.sin_port = htons(80);
remote_sockaddr.sin_addr.s_addr = *(u_long *) remote_host->h_addr_list[0];
memset(&(remote_sockaddr.sin_zero), 0, sizeof(remote_sockaddr.sin_zero));
// 连接远程主机
result = connect(srvfd, (struct sockaddr *)&remote_sockaddr, sizeof(struct sockaddr));
if( result == 0 )
printf("connect ok\r\n");
}
void send_data(const char* tempstr)
{
make_socket_and_connect();//create socket every time ???
makeString(tempstr);
// send(socket_id , http_request, strlen(http_request), 0);
write(srvfd,http_request,strlen(http_request));
//read response
char http_response[512] = {0};
int bytes_received = 0;
bytes_received = read( srvfd , http_response, 512);
//printf("read bytes:%d\n",bytes_received);
http_response[ bytes_received ] = '\0';
//printf("%s\n",http_response);
// 判断是否收到HTTP OK
char* presult = strstr( http_response , "200 OK\r\n");
if( presult == NULL )
printf("Http response error\r\n");
else
printf("data:%s,200 ok\n\n",tempstr);
close(srvfd);
}
int main(int argc, char** argv)
{
int i;
char str[3];
printf("sending data to Yeelink...\n");
srand(time(NULL));
while (1) {
sprintf(str,"%d",rand()%100);
send_data(str);
sleep(10);//at least 10s required by yeelink
}
return 0;
}
编译之后即可生成二进制文件,但似乎发生点错误,未能生成ipk文件。将执行文件放到板中,运行结果如下图,同时刷新yeelink页面即可发现曲线发生了变化。
不过还是有点问题,接口apcli0貌似时通时断,也会影响程序的执行,大致功能确是实现了。
附录
helloworld教程:
http://blog.chinaunix.net/uid-29418452-id-4071751.html
http://blog.youkuaiyun.com/hui523hui523hui523/article/details/38366427