本文讲述了Rime协议栈单跳单播的头部,包括ruc(runicast)、uc(unicast)、broadcastabc,并用图直观表示。

1. Rime协议栈头部格式

1.1 概述

Rime协议栈为了能适用不同的网络协议(network protocols),这就需要解决头部格式兼容问题。很容易想到的方法是定义一个统一的头部格式,但缺点几乎是致命的,头部太大且扩展性差。

img

图1 不同网络协议的头部格式

巧妙的是,Rime干脆不定义任何头部格式,而是将所有头部字段抽象为类型和长度(结构体packetbuf_attrlist)。将头部各字段组织成数组attributes[],部份源代码如下:

struct packetbuf_attrlist
{
  uint8_t type;
  uint8_t len;
};

static const struct packetbuf_attrlist attributes[] = {...};

这样的思想很常见,如:HTTP报文整个报文段内容是普通ASCII文本,头部各个字段靠空格或者回车换行符隔开,而Rime头部是用长度来隔开。

1.2 数据包缓冲属性类型

Contiki将数据包缓冲属性类型(packet buffer attribute type)组织成枚举类型变量,如下:

enum
{
  PACKETBUF_ATTR_NONE,
  /* Scope 0 attributes: used only on the local node. */
  PACKETBUF_ATTR_CHANNEL,
  PACKETBUF_ATTR_NETWORK_ID,
  PACKETBUF_ATTR_LINK_QUALITY,
  PACKETBUF_ATTR_RSSI,
  PACKETBUF_ATTR_TIMESTAMP,
  PACKETBUF_ATTR_RADIO_TXPOWER,
  PACKETBUF_ATTR_LISTEN_TIME,
  PACKETBUF_ATTR_TRANSMIT_TIME,
  PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS,
  PACKETBUF_ATTR_MAC_SEQNO,
  PACKETBUF_ATTR_MAC_ACK,
  /* Scope 1 attributes: used between two neighbors only. */
  PACKETBUF_ATTR_RELIABLE,
  PACKETBUF_ATTR_PACKET_ID,
  PACKETBUF_ATTR_PACKET_TYPE,
  PACKETBUF_ATTR_REXMIT,
  PACKETBUF_ATTR_MAX_REXMIT,
  PACKETBUF_ATTR_NUM_REXMIT,
  PACKETBUF_ATTR_PENDING,
  /* Scope 2 attributes: used between end-to-end nodes. */
  PACKETBUF_ATTR_HOPS,
  PACKETBUF_ATTR_TTL,
  PACKETBUF_ATTR_EPACKET_ID,
  PACKETBUF_ATTR_EPACKET_TYPE,
  PACKETBUF_ATTR_ERELIABLE,
  /* These must be last */
  PACKETBUF_ADDR_SENDER,
  PACKETBUF_ADDR_RECEIVER,
  PACKETBUF_ADDR_ESENDER,
  PACKETBUF_ADDR_ERECEIVER,

  PACKETBUF_ATTR_MAX
};

每个枚举元素都是一个常量(枚举型是预处理指令#define的替代),若第一个枚举元素没有赋值,则默认为0,随后元素以1递增。所以在本例,PACKETBUF_ATTR_NONE为0,PACKETBUF_ATTR_MAX为28。

1.3 runicast头部

contiki/core/net/rime/runicast.c文件定义了该数组,源代码如下:

static const struct packetbuf_attrlist attributes[] =
{
  RUNICAST_ATTRIBUTES PACKETBUF_ATTR_LAST
};

RUNICAST_ATTRIBUTES分析见本文第二部分,PACKETBUF_ATTR_LAST分析见本文第四部分。所有宏展开,理清变量间关系,最后得到runicast头部示意图见本文第五部分。

PS:第二、三、四部分系分析过程,无非就是一些宏展开,没多大阅读价值,建立直接看第五部分结论。

2. RUNICAST_ATTRIBUTES

RUNICAST_ATTRIBUTES展开如下:

#define RUNICAST_ATTRIBUTES \
{ PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_BIT }, \
{ PACKETBUF_ATTR_PACKET_ID, PACKETBUF_ATTR_BIT * RUNICAST_PACKET_ID_BITS }, \
STUNICAST_ATTRIBUTES

2.1 PACKETBUF_ATTR_PACKET_TYPE

PACKETBUF_ATTR_PACKET_TYPE是上述枚举类型的元素,其值为15,PACKETBUF_ATTR_BIT#define定义,其值为1。

2.2 PACKETBUF_ATTR_PACKET_ID

PACKETBUF_ATTR_PACKET_ID是上述枚举类型的元素,其值为14。PACKETBUF_ATTR_BITRUNICAST_PACKET_ID_BITS皆由#define定义,其值分别为1、2,两者乘积为2。源码如下:

#define PACKETBUF_ATTR_BIT 1
#define RUNICAST_PACKET_ID_BITS 2

2.3 STUNICAST_ATTRIBUTES

STUNICAST_ATTRIBUTES一步步展开如下:

#define STUNICAST_ATTRIBUTES UNICAST_ATTRIBUTES

#define UNICAST_ATTRIBUTES
{ PACKETBUF_ADDR_RECEIVER, PACKETBUF_ADDRSIZE }, \
BROADCAST_ATTRIBUTES

2.3.1 PACKETBUF_ADDR_RECEIVER

PACKETBUF_ADDR_RECEIVER是上述枚举类型的元素,其值为26。宏PACKETBUF_ADDRSIZE 展开如下:

#define PACKETBUF_ADDRSIZE (sizeof(rimeaddr_t) * PACKETBUF_ATTR_BYTE)

typedef union
{
  unsigned char u8[RIMEADDR_SIZE];
} rimeaddr_t;

#define PACKETBUF_ATTR_BYTE 8

Rime地址长度RIMEADDR_SIZE默认为2,sizeof(rimeaddr_t)为2,所以PACKETBUF_ADDRSIZE为16。可见packetbuf_attrlist成员变量长度len是以bit为单位。

2.3.2 BROADCAST_ATTRIBUTES

见本文第三部分。

3. BROADCAST_ATTRIBUTES

BROADCAST_ATTRIBUTES宏展开如下:

#define BROADCAST_ATTRIBUTES
{ PACKETBUF_ADDR_SENDER, PACKETBUF_ADDRSIZE }, \
ABC_ATTRIBUTES

3.1 PACKETBUF_ADDR_SENDER

PACKETBUF_ADDR_SENDER是上述枚举类型的元素,其值为25,宏PACKETBUF_ADDRSIZE展开如下:

#define PACKETBUF_ADDRSIZE (sizeof(rimeaddr_t) * PACKETBUF_ATTR_BYTE)

typedef union
{
  unsigned char u8[RIMEADDR_SIZE];
} rimeaddr_t;

#define PACKETBUF_ATTR_BYTE 8

Rime地址长度RIMEADDR_SIZE默认为2,sizeof(rimeaddr_t)为2,所以PACKETBUF_ADDRSIZE为16。

3.2 ABC_ATTRIBUTES

ABC_ATTRIBUTES展开如下:

#define ABC_ATTRIBUTES

4. PACKETBUF_ATTR_LAST

PACKETBUF_ATTR_LAST展开如下:

#define PACKETBUF_ATTR_LAST { PACKETBUF_ATTR_NONE, 0 }

PACKETBUF_ATTR_NONE是上述枚举类型的元素,其值为0。

5. 总结

5.1 runicast头部

runicastattributes数组定义源代码如下:

static const struct packetbuf_attrlist attributes[] =
{
  RUNICAST_ATTRIBUTES
  PACKETBUF_ATTR_LAST
};

结合上述分析,runicast头部示意图如下:

img

图2 runicast头部示意图

5.2 unicast头部

unicastattributes数组定义源代码如下:

static const struct packetbuf_attrlist attributes[] =
{
  UNICAST_ATTRIBUTES
  PACKETBUF_ATTR_LAST
};

结合上述分析,runicast头部示意图如下:

img

图3 unicast头部示意图

5.3 broadcast

broadcast的attributes数组定义源代码如下:

static const struct packetbuf_attrlist attributes[] =
{
  BROADCAST_ATTRIBUTES
  PACKETBUF_ATTR_LAST
};

结合上述分析,broadcast头部示意图如下:

img

图4 broadcast头部示意图

5.4 abc

abc的attributes数组定义源代码如下:

static const struct packetbuf_attrlist attributes[] =
{
  ABC_ATTRIBUTES
  PACKETBUF_ATTR_LAST
};

结合上述分析,abc头部示意图如下:

img

图5 abc头部示意图

5.5 其他问题

如果你细心的话,你会发现rucbstucabc是没有头部的。我的理解是这样的,rucb块传输层,直接把应用程序数据交给下层ruc,无须增加头部。Rime协议栈将可靠传输层分成两层stucruc,只须加一次头部。abc层的数据直接发送出去,也无须增加头部(abc类似于物理层的功能)。

本文所有头部示意图源文件:Rime单跳单播头部

参考资料:

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

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-22 16:33

results matching ""

    No results matching ""