tinyos学习笔记8--TestLinkLocal例程代码说明

      上一篇说明了TestLinkLocal例程的功能,本篇将对TestLinkLocal例程的代码进行分析。

1 配置文件TestLinkLocalAppC.nc

/** Test the link-local communication in the blip stack
 */
configuration TestLinkLocalAppC {

} implementation {
  components MainC, LedsC;
  components TestLinkLocalC;
  components IPStackC;
  components new TimerMilliC();
  components new UdpSocketC();

  TestLinkLocalC.Boot -> MainC;
  TestLinkLocalC.SplitControl -> IPStackC;
  TestLinkLocalC.Sock -> UdpSocketC;
  TestLinkLocalC.Timer -> TimerMilliC;
  TestLinkLocalC.Leds -> LedsC;

  components StaticIPAddressTosIdC; // Use TOS_NODE_ID in address
  //components StaticIPAddressC; // Use LocalIeee154 in address
}
      MainC、LedsC、TimerMilliC、都是前面见过的组件,IPStackC和UdpSocketC是本例程比较重要的组件。各组件间的接口关系如上所示。

2 模块组件TestLinkLocalC.nc

<pre name="code" class="html">#include "blip_printf.h"
#include <lib6lowpan/ip.h>

module TestLinkLocalC {
  uses {
    interface Boot;
    interface SplitControl;
    interface UDP as Sock;
    interface Timer<TMilli>;
    interface Leds;
  }
}

       首先交代了本模块中使用的接口。 

implementation {
  nx_struct echo_state {
    nx_int8_t cmd;
    nx_uint32_t seqno;
  } m_data;

  enum {
    SVC_PORT = 10210,
    CMD_ECHO = 1,
    CMD_REPLY = 2,
  };
      定义了一个结构体变量m_data,包含cmd命令及seqno数据包序列号两个变量。这个对一些常量采用enum的方法而不是为define。

  event void Boot.booted() {
    //printfUART_init();
    call SplitControl.start();
    m_data.seqno = 0;
  }

  event void SplitControl.startDone(error_t e) {
    call Timer.startPeriodic(2048);
    call Sock.bind(SVC_PORT);
  }

  event void SplitControl.stopDone(error_t e) {}
      在Boot.booted事件中干了两件事:第一,初始化数据包序列号seqno。第二:SplitControl.start()。而在SplitControl.startDone()中启动了一个两秒的定时器和绑定了SVC_PORT端口。 为何不在Boot.booted事件中直接启动定时器和绑定端口??

  event void Timer.fired() {
    struct sockaddr_in6 dest;

    inet_pton6("ff02::1", &dest.sin6_addr);
    dest.sin6_port = htons(SVC_PORT);
    
    m_data.cmd = CMD_ECHO;
    m_data.seqno ++;

    call Sock.sendto(&dest, &m_data, sizeof(m_data));
    call Leds.led0Toggle();
  }
      定时时间到后,进行命令数据的发送。在这段代码中先使用inet_pton6()函数、htons()函数对地址和端口进行转换。这两个函数在ip.h中进行了定义。

#ifndef NO_LIB6LOWPAN_ASCII
/*
 * parse a string representation of an IPv6 address
 */ 
void inet_pton6(char *addr, struct in6_addr *dest);
int  inet_ntop6(struct in6_addr *addr, char *buf, int cnt);
#endif
      接下来为m_data结构体填充数据。然后调用Sock.sendto()函数发送数据,其三个参数分别为目的地址、带发送数据的缓存及数据长度。最后调用函数实现Led0的反转。

event void Sock.recvfrom(struct sockaddr_in6 *src, void *payload,                                                               
                           uint16_t len, struct ip6_metadata *meta) {
    nx_struct echo_state *cmd = payload;
    printf("TestLinkLocalC: recv from: ");
    printf_in6addr(&src->sin6_addr);
    printf("\n");

    if (cmd->cmd == CMD_ECHO) {
      cmd->cmd = CMD_REPLY;
      call Sock.sendto(src, payload, len);
      call Leds.led1Toggle();
    } else {
      printf("TestLinkLocalC: reply seqno: %li\n", cmd->seqno);
      call Leds.led2Toggle();
    }
  }
}
      以上这段代码的作用为Sock收到数据后的事件处理函数。当Sock端口收到数据后,由Sock.recvfrom()事件处理函数来接收、处理数据包。该数据包的有效载荷为playload即为命令,故而赋值给了cmd。
    printf("TestLinkLocalC: recv from: ");
    printf_in6addr(&src->sin6_addr);
    printf("\n");
      这三行代码对数据包的源地址进行打印输出。接下来的if...else...对收到的命令进行判断,如果收到的命令是CMD_ECHO则回复消息给发送方并且反转Led1。如果收到的数据是一个回复消息,则打印

printf("TestLinkLocalC: reply seqno: %li\n", cmd->seqno);

      并反转Led2。


By:霜月孤鸟

2015.12.28

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值