Contiki协议栈Rime:原始变色龙chameleon-raw

更多的Contiki协议栈知识,请参考索引目录:
Contiki协议栈:索引目录

1 概述

在Contiki中,默认的变色龙模块是chameleon_bitopt,它能让不同层的协议头进行跨层位组合处理,减小总体头部尺寸。
我们也可以在contiki-conf.h中自定义变色龙头处理模块为chameleon_raw:

#define CHAMELEON_CONF_MODULE chameleon_raw

之所以将chamelon_raw叫做原始变色龙,因为它是chameleon_bitopt的简化版,未进行跨层位组合。
相关源码位于:contiki/core/net/rime/chameleon_raw.[ch]

2 相关定义

raw_hdr

struct raw_hdr {
  uint8_t channel[2];
};

raw_hdr里面定义了两个字节的channel,它是用来存放通道号的。

chameleon_raw

CC_CONST_FUNCTION struct chameleon_module chameleon_raw = { 
   input, 
   output,
   hdrsize 
};

定义了变色龙处理模块的结构体。

2 相关函数

hdrsize

static int hdrsize(const struct packetbuf_attrlist *a)
{
  int size, len;

  /* 通过这个通道中的所有属性,计算最终的头部尺寸。 */
  size = 0;
  for(; a->type != PACKETBUF_ATTR_NONE; ++a) {
#if CHAMELEON_WITH_MAC_LINK_ADDRESSES
    if(a->type == PACKETBUF_ADDR_SENDER ||
       a->type == PACKETBUF_ADDR_RECEIVER) {
      /* Let the mac layer handle the sender and receiver */
      continue;
    }
#endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
    len = a->len;
    if(len < 8) {  // 这里有疑问
      len = 8;
    }
    size += len;
  }
  return size / 8; // size的单位是bit,除8将其转为字节
}

函数的实现过程很简单:累加属性链表中记录的属性的长度,然后将单位由bit转换为byte。

这段代码将来可能会产生bug,因为在对size累加时,只是将len < 8的包属性的值记为8,没有考虑到今后的包属性可能大于8。我已经在contiki的github仓库中提出了该BUG,并修改了代码,且已经在申请了pull request(请看代码改动),希望能被采纳吧!

output

static int
output(struct channel *c)
{
  const struct packetbuf_attrlist *a;
  int byteptr, len;
  uint8_t *hdrptr;
  struct raw_hdr *hdr;

  /* 通过计算本通道中对应属性,得出最终头部尺寸. */
  if(packetbuf_hdralloc(c->hdrsize + sizeof(struct raw_hdr)) == 0) {
    return 0;
  }
  hdr = (struct raw_hdr *)packetbuf_hdrptr(); // 先存放通道号
  hdr->channel[0] = c->channelno & 0xff;  //低8位
  hdr->channel[1] = (c->channelno >> 8) & 0xff; // 高8位

  hdrptr = ((uint8_t *)packetbuf_hdrptr()) + sizeof(struct raw_hdr);
  byteptr = 0;
  /* 根据属性链表,以此将属性数组中对应值写入头部 */
  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
#if CHAMELEON_WITH_MAC_LINK_ADDRESSES
    if(a->type == PACKETBUF_ADDR_SENDER ||
       a->type == PACKETBUF_ADDR_RECEIVER) {
      /* Let the link layer handle sender and receiver */
      continue;
    }
#endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */

    // 为啥len是这样的?估计跟上面的问题是关联的。
    len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0); 
    if(PACKETBUF_IS_ADDR(a->type)) {
      // 如果对应的属性是地址属性,将其存入头部
      const linkaddr_t *linkaddr;
      linkaddr = packetbuf_addr(a->type);
      hdrptr[byteptr] = linkaddr->u8[0];
      hdrptr[byteptr + 1] = linkaddr->u8[1];
    } else {
      packetbuf_attr_t val;
      val = packetbuf_attr(a->type);
      memcpy(&hdrptr[byteptr], &val, len / 8);
    }
    byteptr += len / 8;
  }

  return 1; /* Send out packet */
}

该函数负责根据属性链表中的type和len,依次将属性数组中对应属性压入都最终的头部。在压入头部前,先压入通道号,这是因为在解析头部时,会根据通道号查找到对应的通道,然后根据通道的属性链表和头长度做相应的处理。
看到这里,我们难免会有一点小兴奋,因为我们终于知道packetbuf中的那些函数该如何应用了。可以回头再看看之前的博客。

input

static struct channel *input(void)
{
  const struct packetbuf_attrlist *a;
  int byteptr, bitptr, len;
  uint8_t *hdrptr;
  struct raw_hdr *hdr;
  struct channel *c;

  /* 头部的前两个字节是发送端压入的通道号,先把它解析出来 */
  hdr = (struct raw_hdr *)packetbuf_dataptr();
  if(packetbuf_hdrreduce(sizeof(struct raw_hdr)) == 0) {
    return NULL;
  }
  /* 根据通道号查找对应的通道 */
  c = channel_lookup((hdr->channel[1] << 8) + hdr->channel[0]);
  if(c == NULL) {
    return NULL;
  }

  hdrptr = packetbuf_dataptr();
  if(packetbuf_hdrreduce(c->hdrsize) == 0) {
    return NULL;
  }
  byteptr = bitptr = 0;
  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
  /* 根据通道中的属性链表,依次解析头部信息到属性数组中 */
#if CHAMELEON_WITH_MAC_LINK_ADDRESSES
    if(a->type == PACKETBUF_ADDR_SENDER ||
       a->type == PACKETBUF_ADDR_RECEIVER) {
      /* Let the link layer handle sender and receiver */
      continue;
    }
#endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */

    len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);
    if(PACKETBUF_IS_ADDR(a->type)) {
      const linkaddr_t addr;
      memcpy((uint8_t *)&addr, &hdrptr[byteptr], len / 8);
      packetbuf_set_addr(a->type, &addr);
    } else {
      packetbuf_attr_t val = 0;
      memcpy((uint8_t *)&val, &hdrptr[byteptr], len / 8);
      packetbuf_set_attr(a->type, val);
    }
    byteptr += len / 8;
  }
  return c;
}

output函数的逆过程,负责将packetbuf中的信息转换为包属性,存放到属性数组中。

4 小结

关于这次留的坑,今后补上。
到了这里,我们终于可以packetbuf中的接口应该如何使用了,再赶紧回顾一下之前的日志吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值