导语 本文基于contiki3.0系统,翻译自iot in five days,使用的节点是avr-atmega128rfa1
Copper是一个基于CoAP的IOT通用浏览器,它可以和当前存在的CoAP设备直观的交互和调试。More Information
- 2.在本次试验中使用两个节点:一个Border Router和一个CoAP server
注:要确保节点在之前的sessions已经写入了Node ID,以便产生MAC/IPv6地址
注:在atmega128rfa1平台上EUI即IEEE地址位于platform/avr-atmega128rfa1/params.h,在本次试验中,我将border-router的IEEE地址设置为{0x02, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x02},CoAP server节点设为{0x02, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x01}
另,发现以下错误,修改examples/er-rest-example/project-conf.h中的UIP_CONF_BUFFER_SIZE为240,同时为了使LED可用,在该文件中添加以下代码:
#define PLATFORM_HAS_LEDS 1
3.在Makefile(examples/er-rest-example/)中有两件事要注意:
-
1.resource文件夹被包含作为项目文件夹,所有的resource文件都被加入编译
-
2.包含了er-coap和rest-engine应用
注:如果我们想尽可能避免冲突,移除下面代码:
#undef NETSTACK_CONF_MAC #define NETSTACK_CONF_MAC nullmac_driver
* 4.接下来检查**project-conf.h**中的相关配置,首先确保TCP被禁用,因为CoAP是基于UDP的
![](http://upload-images.jianshu.io/upload_images/1245901-aec86e78e6cf255d.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 5.**REST_MAX_CHUNK_SIZE**是提供给资源响应的最大缓冲区大小,更大的数据要通过resource处理并被发送给CoAP blocks.**COAP_MAX_OPEN_TRANSACTION**是节点能够处理的最大开放传输数量
![](http://upload-images.jianshu.io/upload_images/1245901-d57dfc2fa23f6e32.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#CoAP Server
通过测试er-example-server.c(examples/er-rest-example)这个例子理解它的实现。首先要注意一个叫resources的文件夹:各种resources被不同的文件实现,易于调试。
在CoAP中要被包含的resources定义如下:
/*
* Resources to be activated need to be imported through the extern keyword.
* The build system automatically compiles the resources in the corresponding sub-directory.
*/
extern resource_t
res_hello,
res_mirror,
res_chunks,
res_separate,
res_push,
res_event,
res_sub,
res_b1_sep_b2;
#if PLATFORM_HAS_LEDS
extern resource_t res_leds, res_toggle;
#endif
#if PLATFORM_HAS_LIGHT
#include "dev/light-sensor.h"
extern resource_t res_light;
#endif
/*
#if PLATFORM_HAS_BATTERY
#include "dev/battery-sensor.h"
extern resource_t res_battery;
#endif
#if PLATFORM_HAS_RADIO
#include "dev/radio-sensor.h"
extern resource_t res_radio;
#endif
#if PLATFORM_HAS_SHT11
#include "dev/sht11/sht11-sensor.h"
extern resource_t res_sht11;
#endif
*/
包含在**PLATFORM_HAS_X**的resources宏定义是独立于目标平台的,如果平台被选定,资源也就确定了。
REST engine通过调用*rest_init_engine()*初始化,这样开启的resources就被绑定了。
rest_init_engine();
/*
* Bind the resources to their Uri-Path.
* WARNING: Activating twice only means alternate path, not two instances!
* All static variables are the same for each URI path.
*/
rest_activate_resource(&res_hello, "test/hello");
/* rest_activate_resource(&res_mirror, "debug/mirror"); */
/* rest_activate_resource(&res_chunks, "test/chunks"); */
/* rest_activate_resource(&res_separate, "test/separate"); */
rest_activate_resource(&res_push, "test/push");
/* rest_activate_resource(&res_event, "sensors/button"); */
/* rest_activate_resource(&res_sub, "test/sub"); */
/* rest_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); */
#if PLATFORM_HAS_LEDS
/* rest_activate_resource(&res_leds, "actuators/leds"); */
rest_activate_resource(&res_toggle, "actuators/toggle");
#endif
#if PLATFORM_HAS_LIGHT
rest_activate_resource(&res_light, "sensors/light");
SENSORS_ACTIVATE(light_sensor);
#endif
现在看看res-hello.c,它实现了一个“hello world” resource 用于测试
如前所示资源已经在**RESOURCE**宏中定义了,对于这个特定的实现,我们规定资源名为res-hello,也规定了link-formatted属性和**GET**回调handler。**POST,PUT,DELETE**方法在本resource中不被支持,就传入**NULL**作为参数。
![](http://upload-images.jianshu.io/upload_images/1245901-8975a78e8b536c35.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**res_get_handler**是**GET** request的回调函数,其实现:
static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
const char *len = NULL;
/* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */
char const *const message = "Hello World! ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy";
int length = 12; /* |<-------->| */ //默认
长度的回复,在本例中整个字符串只有Hello World!会被发送
/* The query string can be retrieved by rest_get_query() or parsed for its key-value pairs. */
if(REST.get_query_variable(request, "len", &len)) {//如果len被设定了就发送len长度字节的信息
length = atoi(len);
if(length < 0) {//如果为负,发送空字符串
length = 0;
}
if(length > REST_MAX_CHUNK_SIZE) {//如果len比最大允许值还大就值发送最大允许值的字符串
length = REST_MAX_CHUNK_SIZE;
}
memcpy(buffer, message, length); //copy the default
} else {
memcpy(buffer, message, length);
}
//设置response内容类型为 Content-Type:text/plain
REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */
REST.set_header_etag(response, (uint8_t *)&length, 1);//在response前加入header,设置负荷长度字段
REST.set_response_payload(response, buffer, length);//把负荷加入response
}
![](http://upload-images.jianshu.io/upload_images/1245901-4e4b9ba76ef75c36.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在**project-conf.h**中加入以下代码用于测试
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
然后编译并上载(这里为了方便就直接借书上的图了,具体操作可以看我的这篇博客[Contiki边界路由](http://www.jianshu.com/p/8d54bc801271):
![](http://upload-images.jianshu.io/upload_images/1245901-a732a8a8676815a8.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在串口打印中也可以看到IPv6服务器地址,断开节点连上另一个作为客户端
#Border-Router:
######此部分和我的[Contiki边界路由](http://www.jianshu.com/p/8d54bc801271)博客差不多。。。不好意思这篇博客是先写的
![](http://upload-images.jianshu.io/upload_images/1245901-164137d73e763599.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
不要关闭窗口,让节点连接,就可以看见类似于如下的信息:
![
![](http://upload-images.jianshu.io/upload_images/1245901-6cb368f954af8b69.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](http://upload-images.jianshu.io/upload_images/1245901-84d37dc1158c1c59.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以ping border-router:
![](http://upload-images.jianshu.io/upload_images/1245901-9b5a1edb4fc94d6a.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
连接上服务器节点,也可以ping:
![](http://upload-images.jianshu.io/upload_images/1245901-52925ff581c938b7.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这样就可以发现服务器资源了。打开firfox,输入服务器地址:
coap://[aaaa::c30c:0000:0000:0001]:5683/
![](http://upload-images.jianshu.io/upload_images/1245901-9c63b98fdf3bbf89.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
点击**DISCOVER**,在左侧网页你就可以:
如果你选择**toggle**资源,使用**POST**你可以看见服务器节点的红灯会翻转;
如果选择**Hello**资源,服务器会回应你一个Hello World!
如果你通过选择并点击**OBSERVE**,观察**Sensors->BUTTON**事件,每当你按一次用户按钮,一个事件就会被触发并被回报。
最后,如果你去**er-example-server.c**文件,并打开下面的宏定义,可以看到更多可用的宏定义。
![](http://upload-images.jianshu.io/upload_images/1245901-265dfef0468f3684.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
获得当前收发器的RSSI值:
![](http://upload-images.jianshu.io/upload_images/1245901-8e9eaa3e873609ce.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
获取电池电量:
![](http://upload-images.jianshu.io/upload_images/1245901-9e6fb0c09ca9e19e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
当节点连接到USB,获取ADC单元的值,实际值将为:
v[mV]=(units*5000)/4096
如果想让绿灯亮:
![](http://upload-images.jianshu.io/upload_images/1245901-21bec7552c85bee7.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
然后在payload(the ongoing tab)上写:
mode="on"
并按下**POST**或**PUT**