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中我们可以看到:资源文件添加到工程路径,所有资源文件编译加入。

  1. REST_RESOURCES_DIR = ./resources
  2. REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c' ! -
  3. name 'res-plugtest*'))
  4. PROJECTDIRS += $(REST_RESOURCES_DIR)
  5. 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使能以下定义,可以获得更多的可用资源:

  1. #define REST_RES_HELLO 1
  2. #define REST_RES_SEPARATE 1
  3. #define REST_RES_PUSHING 1
  4. #define REST_RES_EVENT 1
  5. #define REST_RES_SUB 1
  6. #define REST_RES_LEDS 1
  7. #define REST_RES_TOGGLE 1
  8. #define REST_RES_BATTERY 1
  9. #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”