導(dǎo)語 本文基于contiki3.0系統(tǒng),翻譯自iot in five days,使用的節(jié)點(diǎn)是avr-atmega128rfa1
Copper是一個(gè)基于CoAP的IOT通用瀏覽器,它可以和當(dāng)前存在的CoAP設(shè)備直觀的交互和調(diào)試。More Information
- 2.在本次試驗(yàn)中使用兩個(gè)節(jié)點(diǎn):一個(gè)Border Router和一個(gè)CoAP server
注:要確保節(jié)點(diǎn)在之前的sessions已經(jīng)寫入了Node ID,以便產(chǎn)生MAC/IPv6地址
注:在atmega128rfa1平臺上EUI即IEEE地址位于platform/avr-atmega128rfa1/params.h,在本次試驗(yàn)中,我將border-router的IEEE地址設(shè)置為{0x02, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x02},CoAP server節(jié)點(diǎn)設(shè)為{0x02, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x01}
另,發(fā)現(xiàn)以下錯(cuò)誤,修改examples/er-rest-example/project-conf.h中的UIP_CONF_BUFFER_SIZE為240,同時(shí)為了使LED可用,在該文件中添加以下代碼:
#define PLATFORM_HAS_LEDS 1
3.在Makefile(examples/er-rest-example/)中有兩件事要注意:
-
1.resource文件夾被包含作為項(xiàng)目文件夾,所有的resource文件都被加入編譯
-
2.包含了er-coap和rest-engine應(yīng)用
注:如果我們想盡可能避免沖突,移除下面代碼:
#undef NETSTACK_CONF_MAC #define NETSTACK_CONF_MAC nullmac_driver
* 4.接下來檢查**project-conf.h**中的相關(guān)配置,首先確保TCP被禁用,因?yàn)镃oAP是基于UDP的

* 5.**REST_MAX_CHUNK_SIZE**是提供給資源響應(yīng)的最大緩沖區(qū)大小,更大的數(shù)據(jù)要通過resource處理并被發(fā)送給CoAP blocks.**COAP_MAX_OPEN_TRANSACTION**是節(jié)點(diǎn)能夠處理的最大開放傳輸數(shù)量

#CoAP Server
通過測試er-example-server.c(examples/er-rest-example)這個(gè)例子理解它的實(shí)現(xiàn)。首先要注意一個(gè)叫resources的文件夾:各種resources被不同的文件實(shí)現(xiàn),易于調(diào)試。
在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宏定義是獨(dú)立于目標(biāo)平臺的,如果平臺被選定,資源也就確定了。
REST engine通過調(diào)用*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
現(xiàn)在看看res-hello.c,它實(shí)現(xiàn)了一個(gè)“hello world” resource 用于測試
如前所示資源已經(jīng)在**RESOURCE**宏中定義了,對于這個(gè)特定的實(shí)現(xiàn),我們規(guī)定資源名為res-hello,也規(guī)定了link-formatted屬性和**GET**回調(diào)handler。**POST,PUT,DELETE**方法在本resource中不被支持,就傳入**NULL**作為參數(shù)。

**res_get_handler**是**GET** request的回調(diào)函數(shù),其實(shí)現(xiàn):
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; /* |<-------->| */ //默認(rèn)
長度的回復(fù),在本例中整個(gè)字符串只有Hello World!會被發(fā)送
/* 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被設(shè)定了就發(fā)送len長度字節(jié)的信息
length = atoi(len);
if(length < 0) {//如果為負(fù),發(fā)送空字符串
length = 0;
}
if(length > REST_MAX_CHUNK_SIZE) {//如果len比最大允許值還大就值發(fā)送最大允許值的字符串
length = REST_MAX_CHUNK_SIZE;
}
memcpy(buffer, message, length); //copy the default
} else {
memcpy(buffer, message, length);
}
//設(shè)置response內(nèi)容類型為 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,設(shè)置負(fù)荷長度字段
REST.set_response_payload(response, buffer, length);//把負(fù)荷加入response
}

在**project-conf.h**中加入以下代碼用于測試
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
然后編譯并上載(這里為了方便就直接借書上的圖了,具體操作可以看我的這篇博客[Contiki邊界路由](http://www.itdecent.cn/p/8d54bc801271):

在串口打印中也可以看到IPv6服務(wù)器地址,斷開節(jié)點(diǎn)連上另一個(gè)作為客戶端
#Border-Router:
######此部分和我的[Contiki邊界路由](http://www.itdecent.cn/p/8d54bc801271)博客差不多。。。不好意思這篇博客是先寫的

不要關(guān)閉窗口,讓節(jié)點(diǎn)連接,就可以看見類似于如下的信息:

](http://upload-images.jianshu.io/upload_images/1245901-84d37dc1158c1c59.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以ping border-router:

連接上服務(wù)器節(jié)點(diǎn),也可以ping:

這樣就可以發(fā)現(xiàn)服務(wù)器資源了。打開firfox,輸入服務(wù)器地址:
coap://[aaaa::c30c:0000:0000:0001]:5683/

點(diǎn)擊**DISCOVER**,在左側(cè)網(wǎng)頁你就可以:
如果你選擇**toggle**資源,使用**POST**你可以看見服務(wù)器節(jié)點(diǎn)的紅燈會翻轉(zhuǎn);
如果選擇**Hello**資源,服務(wù)器會回應(yīng)你一個(gè)Hello World!
如果你通過選擇并點(diǎn)擊**OBSERVE**,觀察**Sensors->BUTTON**事件,每當(dāng)你按一次用戶按鈕,一個(gè)事件就會被觸發(fā)并被回報(bào)。
最后,如果你去**er-example-server.c**文件,并打開下面的宏定義,可以看到更多可用的宏定義。

獲得當(dāng)前收發(fā)器的RSSI值:

獲取電池電量:

當(dāng)節(jié)點(diǎn)連接到USB,獲取ADC單元的值,實(shí)際值將為:
v[mV]=(units*5000)/4096
如果想讓綠燈亮:

然后在payload(the ongoing tab)上寫:
mode="on"
并按下**POST**或**PUT**