上手:CoAP server and Copper

导语 本文基于contiki3.0系统,翻译自iot in five days,使用的节点是avr-atmega128rfa1
    1. 获取Copper(Cu) CoAP

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文件都被加入编译


    上手:CoAP server and Copper_第1张图片
  • 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**


  

你可能感兴趣的:(上手:CoAP server and Copper)