Contiki学习笔记:Rime协议栈数据发送rucb_send

8404阅读 0评论2012-07-18 Jelline
分类:嵌入式

摘要:

    本文讲述Rime协议栈发送数据rucb_send函数,先是给出如何使用,而后深入源码分析细节,包括read_data、packetbuf_clear、read_chunk、packetbuf_set_datalen。


一、概述

    Rime协议栈建立连接后,就可以进行通信了(发送、接收数据),Rime协议栈提供单跳单播、单跳广播、多跳三种功能,本文仅介绍单跳单播(Single-hop unicast)发送数据,如下图红色箭头所示

图1 Rime协议栈

    注:使用Rime协议栈进行通信,需要先建立连接,建立连接过程已在博文《Contiki学习笔记:Rime协议栈单跳单播建立连接rucb_open 》进行详细阐述了。

Rime是层次型协议栈,整个发送数据是通过上层调用下层服务来完成的,具体如下:

    rucb_send --> runicast_send --> stunicast_send_stubborn --> unicast_send --> broadcast_send --> abc_send --> rime_output --> NETSTACK_MAC.send


PS:因有些函数涉及内容较多,故将各个函数独立成文,本文仅讲解rucb_send。


二、rucb_send

2.1 如何使用

在文件example-rucb.c有一个rucb发送数据的例子,相关源代码如下:

  1. static struct rucb_conn rucb;

  2. /*接收者Rime地址*/
  3. rimeaddr_t recv;
  4. recv.u8[0] = 52;
  5. recv.u8[1] = 0;

  6. rucb_send(&rucb, &recv);

    这里的rucb已经在建立连接阶段进行一系列设置了,博文见博文《Contiki学习笔记:Rime协议栈单跳单播建立连接rucb_open 》。这里recv地址为52.0,更多关于Rime地址见博文《Contiki学习笔记:Rime协议栈之Rime地址rimeaddr_t》。

2.2 rucb_send

rucb是块传输(Bulk transfer)层[1],可以理解成传输层,rucb_send源代码如下:

  1. int rucb_send(struct rucb_conn *c, const rimeaddr_t *receiver)
  2. {
  3.   c->chunk = 0;
  4.   read_data(c);
  5.   rimeaddr_copy(&c->receiver, receiver);
  6.   rimeaddr_copy(&c->sender, &rimeaddr_node_addr);
  7.   runicast_send(&c->c, receiver, MAX_TRANSMISSIONS);
  8.   return 0;
  9. }

    c->chunk将数据块数目初始化为0,read_data进行一些Rime缓冲区初始化相关工作,见本文第三部分。rimeaddr_copy函数设置接收者receiver和发送者sender的Rime地址,rimeaddr_node_addr在contiki/core/net/rime/rimeaddr.c文件定义,用于标识本节点的Rime地址,关于Rime地址rimeaddr_t及函数rimeaddr_copy相关介绍见博文《Contiki学习笔记:Rime协议栈之Rime地址rimeaddr_t》。接下来,调用下一层的发送函数runicast_send,关于runicast_send见博文《Contiki学习笔记:Rime协议栈数据发送runicast_send》。


三、read_data

函数read_data进行一些Rime缓冲区初始化相关工作,源代码如下:

  1. //read_data(c);
  2. static int read_data(struct rucb_conn *c)
  3. {
  4.   int len = 0;
  5.   packetbuf_clear();
  6.   if(c->u->read_chunk)
  7.   {
  8.     len = c->u->read_chunk(c, c->chunk *RUCB_DATASIZE, packetbuf_dataptr(), RUCB_DATASIZE);
  9.   } packetbuf_set_datalen(len);
  10.   return len;
  11. }

    packetbuf_dataptr返回Rime缓冲区数据部分的指针(Rime缓冲区还存放头部),packetbuf_dataptr源代码如下:

  1. void *packetbuf_dataptr(void)
  2. {
  3.   return (void*)(&packetbuf[bufptr + PACKETBUF_HDR_SIZE]);
  4. }

3.1 packetbuf_clear

    packetbuf_clear用于清空和重置Rime缓冲区packetbuf相关变量(头部大小、头部指针、数据指针等),详情见博文《Contiki学习笔记:Rime协议栈之Rime缓冲区管理》,packetbuf_clear函数源代码如下:

  1. void packetbuf_clear(void)
  2. {
  3.   buflen = bufptr = 0;
  4.   hdrptr = PACKETBUF_HDR_SIZE;
  5.   packetbufptr = &packetbuf[PACKETBUF_HDR_SIZE];
  6.   packetbuf_attr_clear();
  7. }

3.2 read_chunk

    连接结构体rucb_conn成员变量u是回调结构体rucb_callbacks指针类型,结构体rucb_callbacks有3个函数指针成员变量,分别是写数据块write_chunk、读数据块read_chunk、超时timedout,这些函数需要自己实现。Contiki提供了一例子example-rucb.c(在contiki/examples/rime/目录下),这里实现了这些函数,本文以此为例,分析读数据块函数read_chunk。read_chunk源代码如下:

  1. #define RUCB_DATASIZE 64 //在rucb.h定义
  2. #define FILESIZE 40000

  3. static unsigned long bytecount;

  4. //len = c->u->read_chunk(c, c->chunk * RUCB_DATASIZE, packetbuf_dataptr(), RUCB_DATASIZE);
  5. static int read_chunk(struct rucb_conn *c, int offset, char *to, int maxsize)
  6. {
  7.   int size;
  8.   size = maxsize;

  9.   /*调整size大小,不得超出文件大小*/
  10.   if(bytecount + maxsize >= FILESIZE)
  11.   {
  12.     size = FILESIZE - bytecount;
  13.   }
  14.   bytecount += size;

  15.   if(bytecount == FILESIZE)
  16.   {
  17.     printf("Completion time %lu / %u\n", (unsigned long)clock_time() - start_time, CLOCK_SECOND);
  18.     print_stats();
  19.   }
  20.   
  21.   return size;
  22. }

    这个函数实在让我费解,原以为是将数据读入Rime缓冲区,分析过后,才发现只是调整size大小。全局静态成员变量bytecount对字节进行计数,要确保bytecount+maxsize <= FILESIZE,否则截断。

3.3 packetbuf_set_datalen

    packetbuf_set_datalen设置Rime缓冲区中数据部分的大小(Rime缓冲区存放头部和数据),packetbuf_set_datalen源代码如下:

  1. void packetbuf_set_datalen(uint16_t len)
  2. {
  3.   PRINTF("packetbuf_set_len: len %d\n", len);
  4.   buflen = len;
  5. }



参考资料:

[1] 博文《Contiki学习笔记:Rime协议栈概述及学习资料

[2] Adam Dunkels,Fredrik Osterlind,Zhitao He. An Adaptive Communication Architecture for Wireless Sensor Networks[J]

上一篇:Contiki学习笔记:Rime协议栈数据发送runicast_send
下一篇:IAR MSP430函数参数传递(寄存器与栈混用)之普通参数