摘要:
本文讲述了Rime协议栈单跳单播的头部,包括ruc(runicast)、uc(unicast)、broadcast、abc,并用图直观表示。
一、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:第二、三、四部分系分析过程,无非就是一些宏展开,没多大阅读价值,建立直接看第五部分结论。
二、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
见本文第三部分。
三、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
四、PACKETBUF_ATTR_LAST
宏PACKETBUF_ATTR_LAST 展开如下:
- #define PACKETBUF_ATTR_LAST { PACKETBUF_ATTR_NONE, 0 }
PACKETBUF_ATTR_NONE是上述枚举类型的元素,其值为0。
五、总结
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
的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单跳单播头部.rar
参考资料:
[1] Adam Dunkels,Fredrik Osterlind,Zhitao He. An Adaptive Communication Architecture for Wireless Sensor Networks[J]