5.1.2 实践:CoAP 服务器和 Copper
首先获取火狐插件Copper (Cu) CoAP user-agent Copper是一个用于浏览物联网Coap的嵌入式网络设备管理工具。集成到Web浏览器,更直观的调试COAP设备。 更多信息参见 Copper page。
实验用到两个节点:边界路由器(Border Router)和Coap server 节点。
If you are using the Z1 motes, ensure that the motes you will be using to test this (border router, server, client) have been flashed with a node ID to generate the MAC/IPv6 addresses as done in previous sessions, be sure to write down the addresses! Another thing, if you get an error like the following, go to platform/z1/contiki-conf.h and change UIP_CONF_BUFFER_SIZE to 240:
error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE"
make: * [obj_z1/er-coap-07-engine.o] Error 1
在Makefile中我们可以看到:资源文件添加到工程路径,所有资源文件编译加入。
REST_RESOURCES_DIR = ./resources
REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c' ! -
name 'res-plugtest*'))
PROJECTDIRS += $(REST_RESOURCES_DIR)
PROJECT_SOURCEFILES += $(REST_RESOURCES_FILES)
包含er-coap和rest-engine应用程序。
REST Engine shall use Erbium CoAP implementation
APPS += er-coap APPS += rest-engine
删除以下内容,以避免冲突:
undef NETSTACK_CONF_MAC
define NETSTACK_CONF_MAC nullmac_driver
接下来检查project-conf.h相关配置。由于 CoAP是基于UDP,首先确保禁用TCP。 / Disabling TCP on CoAP nodes. /
undef UIP_CONF_TCP
define UIP_CONF_TCP 0
REST_MAX_CHUNK_SIZE定义供资源响应的最大缓冲区大小。更大的数据由资源来处理,并由COAP块发送。COAP_MAX_OPEN_TRANSACTIONS定义节点能够处理的公开事务的最大值。 / Increase rpl-border-router IP-buffer when using more than 64. /
undef REST_MAX_CHUNK_SIZE
define REST_MAX_CHUNK_SIZE 48
/ Multiplies with chunk size, be aware of memory constraints. /
undef COAP_MAX_OPEN_TRANSACTIONS
define COAP_MAX_OPEN_TRANSACTIONS 4
/ Filtering .well-known/core per query can be disabled to save space. /
undef COAP_LINK_FORMAT_FILTERING
define COAP_LINK_FORMAT_FILTERING 0
undef COAP_PROXY_OPTION_PROCESSING
define COAP_PROXY_OPTION_PROCESSING 0
/ Enable client-side support for COAP observe /
define COAP_OBSERVE_CLIENT 1
CoAP Server
下面分析er-example-server.c,看看是如何实现Coap server。首先要注意资源文件夹。 为了方便调试和维护,在不同的文件中实现资源。 COAP服务器包含的资源可声明如下: 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_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
PLATFORM_HAS_X硬件资源依赖于目标平台,如果平台启用,就可以获取到相关资源。 调用rest_init_engine()初始化REST引擎,并激活资源: / Initialize the REST engine. / 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_push, "test/push");
rest_activate_resource(&res_event, "sensors/button"); /
if PLATFORM_HAS_LEDS
rest_activate_resource(&res_toggle, "actuators/toggle");endif
(...) 现在我们分析RES-hello.c如何实现测试的资源“Hello World”。 RESOURCE宏定义资源,这里指定资源名称res_hello, 我们执行指定资源名称为res_hello,链接格式属性和GET回调函数。资源不支持POST,PUT和DELETE方法,所以参数作为空。 RESOURCE(res_hello, "title=\"Hello world: ?len=0..\";rt=\"Text\"", res_get_handler, NULL, NULL, NULL); GET请求事件回调res_get_handler: //
1.应答帧默认长度,这里只发送Hello World!字符串 2.如果指定了len选项,则发送消息字符串长度字节数 3.如果该值为负,送一个空字符串 4.如果len大于允许的最大值,那么我们只能发送最大默认lenght值。 5.复制默认长度。 6.设置响应消息内容类型为Content-Type:text / plain 7.附加帧头到响应消息,设置有效载荷长度域。 8.附加有效载荷到响应消息
在project-conf.h文件中添加以下内容:
undef NETSTACK_CONF_RDC
define NETSTACK_CONF_RDC nullrdc_driver
编译下载
cd examples/er-rest-example/
make TARGET=zoul savetarget
make er-example-server.upload && make login
记下Coap服务器IPv6地址。
下面将另一个节点配置成边界路由器:
Border-Router
cd ../ipv6/rpl-border-router/
make TARGET=z1 savetarget
make border-router.upload && make connect-router
或者
make TARGET=zoul savetarget && make border-router.upload && make connect-router
不要关闭此窗口!等节点连接后,现在你会看到如下输出:
SLIP started on /dev/ttyUSB0''
opened tun device
/dev/tun0''
ifconfig tun0 inet hostname
up
ifconfig tun0 add aaaa::1/64
ifconfig tun0 add fe80::0:0:0:1/64
ifconfig tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:127.0.1.1 P-t-P:127.0.1.1 Mask:255.255.255.255
inet6 addr: fe80::1/64 Scope:Link
inet6 addr: aaaa::1/64 Scope:Global
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Rime started with address 193.12.0.0.0.0.3.229
MAC c1:0c:00:00:00:00:03:e5 Contiki-2.5-release-681-gc5e9d68 started. Node id
is set to 997.
CSMA nullrdc, channel check rate 128 Hz, radio channel 26
Tentative link-local IPv6 address fe80:0000:0000:0000:c30c:0000:0000:03e5
Starting 'Border router process' 'Web server'
Address:aaaa::1 => aaaa:0000:0000:0000
Got configuration message of type P
Setting prefix aaaa::
Server IPv6 addresses:
aaaa::c30c:0:0:3e5
fe80::c30c:0:0:3e5
ping测试边界路由器的连接
ping6 aaaa:0000:0000:0000:c30c:0000:0000:03e5
PING aaaa:0000:0000:0000:c30c:0000:0000:03e5(aaaa::c30c:0:0:3e5) 56 data bytes
64 bytes from aaaa::c30c:0:0:3e5: icmp_seq=1 ttl=64 time=21.0 ms
64 bytes from aaaa::c30c:0:0:3e5: icmp_seq=2 ttl=64 time=19.8 ms
64 bytes from aaaa::c30c:0:0:3e5: icmp_seq=3 ttl=64 time=22.2 ms
64 bytes from aaaa::c30c:0:0:3e5: icmp_seq=4 ttl=64 time=20.7 ms
等Coap server节点连接到边界路由器后,ping Coap server节点
ping6 aaaa:0000:0000:0000:c30c:0000:0000:0001
PING aaaa:0000:0000:0000:c30c:0000:0000:0001(aaaa::c30c:0:0:1) 56 data bytes
64 bytes from aaaa::c30c:0:0:1: icmp_seq=1 ttl=63 time=40.3 ms
64 bytes from aaaa::c30c:0:0:1: icmp_seq=2 ttl=63 time=34.2 ms
64 bytes from aaaa::c30c:0:0:1: icmp_seq=3 ttl=63 time=35.7 ms
下面我们可以开始发现服务器资源,打开Firefox和键入服务器地址
coap://[aaaa::c30c:0000:0000:0001]:5683/
点击DISCOVER按钮,左侧页面将显示有效的资源。
选中toggle资源并点击POST,你可以看到服务器节点的红色LED状态翻转。
如果你选择Sensors → Button事件,然后单击OBSERVE,每次触发用户按钮事件都会产生报告。
最后,如果在er-example-server.c使能以下定义,可以获得更多的可用资源:
#define REST_RES_HELLO 1
#define REST_RES_SEPARATE 1
#define REST_RES_PUSHING 1
#define REST_RES_EVENT 1
#define REST_RES_SUB 1
#define REST_RES_LEDS 1
#define REST_RES_TOGGLE 1
#define REST_RES_BATTERY 1
#define REST_RES_RADIO 1
而现在获得收发器的当前RSSI强度。 coap://[aaaa::c30c:0000:0000:0001]:5683/sensor/radio?p=rssi 读取电池电压值 coap://[aaaa::c30c:0000:0000:0001]:5683/sensors/battery 最后返回节点连接到USB时ADC值,实际值毫伏为 V [mV] = (units * 5000)/4096 如果想打开绿色LED灯,浏览器输入,并点击POST 或PUT: coap://[aaaa::c30c:0000:0000:0001]:5683/actuators/leds?color=g 成功后在运行栏显示负载 mode="on"