本文讲述了Rime协议栈单跳单播的头部,包括ruc
(runicast)、uc
(unicast)、broadcast
、abc
,并用图直观表示。
1. Rime协议栈头部格式
1.1 概述
Rime协议栈为了能适用不同的网络协议(network protocols),这就需要解决头部格式兼容问题。很容易想到的方法是定义一个统一的头部格式,但缺点几乎是致命的,头部太大且扩展性差。
图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_BIT
、RUNICAST_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头部
runicast
的attributes
数组定义源代码如下:
static const struct packetbuf_attrlist attributes[] =
{
RUNICAST_ATTRIBUTES
PACKETBUF_ATTR_LAST
};
结合上述分析,runicast
头部示意图如下:
图2 runicast头部示意图
5.2 unicast头部
unicast
的attributes
数组定义源代码如下:
static const struct packetbuf_attrlist attributes[] =
{
UNICAST_ATTRIBUTES
PACKETBUF_ATTR_LAST
};
结合上述分析,runicast
头部示意图如下:
图3 unicast头部示意图
5.3 broadcast
broadcast的attributes
数组定义源代码如下:
static const struct packetbuf_attrlist attributes[] =
{
BROADCAST_ATTRIBUTES
PACKETBUF_ATTR_LAST
};
结合上述分析,broadcast头部示意图如下:
图4 broadcast头部示意图
5.4 abc
abc的attributes
数组定义源代码如下:
static const struct packetbuf_attrlist attributes[] =
{
ABC_ATTRIBUTES
PACKETBUF_ATTR_LAST
};
结合上述分析,abc头部示意图如下:
图5 abc头部示意图
5.5 其他问题
如果你细心的话,你会发现rucb
、stuc
、abc
是没有头部的。我的理解是这样的,rucb
块传输层,直接把应用程序数据交给下层ruc
,无须增加头部。Rime协议栈将可靠传输层分成两层stuc
与ruc
,只须加一次头部。abc层的数据直接发送出去,也无须增加头部(abc
类似于物理层的功能)。
本文所有头部示意图源文件:Rime单跳单播头部
参考资料:
[1] Adam Dunkels,Fredrik Osterlind,Zhitao He. An Adaptive Communication Architecture for Wireless Sensor Networks[J]