本文介绍了contiki netstack的MAC层以下数据收发层次结构,并讨论如何移植新的无线器件做为contiki的无线收发器。
contiki可以在contiki-conf.h中进行配置
#define NETSTACK_CONF_NETWORK rime_driver //使用rime协议栈 #define NETSTACK_CONF_MAC nullmac_driver //不使用mac层协议 #define NETSTACK_CONF_RDC contikimac_driver //使用contikimac rdc #define NETSTACK_CONF_FRAMER framer_nrf24 //使用nrf24的frame结构 #define NETSTACK_CONF_RADIO nrf24_radio_driver //使用nrf24做为无线器件
NETSTACK_CONF_RADIO
定义contiki netstack使用的无线通信器件,这一层的驱动一般只完成物理层上的收发控制。其定义的原型在radio.h中:
struct radio_driver { int (* init)(void); /** Prepare the radio with a packet to be sent. */ int (* prepare)(const void *payload, unsigned short payload_len); /** Send the packet that has previously been prepared. */ int (* transmit)(unsigned short transmit_len); /** Prepare & transmit a packet. */ int (* send)(const void *payload, unsigned short payload_len); /** Read a received packet into a buffer. */ int (* read)(void *buf, unsigned short buf_len); /** Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not. */ int (* channel_clear)(void); /** Check if the radio driver is currently receiving a packet */ int (* receiving_packet)(void); /** Check if the radio driver has just received a packet */ int (* pending_packet)(void); /** Turn the radio on. */ int (* on)(void); /** Turn the radio off. */ int (* off)(void); };
NETSTACK_CONF_FRAMER
定义使用radio driver的frame格式,这一层完成对数据帧的解析和打包,原型定义在framer.h中
struct framer { int (* create)(void); int (* parse)(void); };
NETSTACK_CONF_RDC
radio duty cycling, RDC层,从radio层获取数据,并通过framer解析。RDC将要发送的数据通过parser打包并通过radio层发送。RDC提供无线传感的省电duty cycling。contiki提供了以下的rdc mac协议:
其中nullrdc_driver不做任何duty cycling动作。
NETSTACK_CONF_MAC
MAC层主要是完成,防碰撞的协议,contiki提供以下的MAC协议:
其中nullmac_driver不做任何防碰撞,直接转发数据
RDC层/MAC层/NETSTACK层的代码contiki提供,如果没有特殊的需求不用做修改和添加,主要的移植工作集中在Framer和radio层.
framer层,完成数据发送前的封包和接收后的解析,在nrf24l01同步等的framer结构都在nrf24l01的硬件中处理,因此定义的framer结构只与地址和payload有关
数据frame结构:
create frame时,RDC将MAC层要发送的数据加上dst addr和src addr后送到radio。
parser frame时,从中解析出dst addr和src addr,然后将actual payload送到MAC层。
按照上述做法实现
const struct framer framer_nrf24 = { create, parse };
driver层
不用考虑任何数据链路层和网络层的内容,只做很单纯的收发动作,因此按照struct radio_driver的要求实现各个API即可:
const struct radio_driver nrf24_radio_driver = { nrf24_radio_init, nrf24_radio_prepare, nrf24_radio_transmit, nrf24_radio_send, nrf24_radio_read, nrf24_radio_channel_clear, nrf24_radio_receiving_packet, nrf24_radio_pending_packet, nrf24_radio_on, nrf24_radio_off, };
由于nrf24l01没有广播地址的概念,因此将nrf24l01的pipe0做为点对点数据, pipe1做为广播数据。也就是将所有节点的pipe0地址设置为自己独有的,所以节点的pipe1的地址设置为相同的,这样针对pipe1地址发送数据,所有节点都能收到,则实现了广播
nrf24l01按照自己的pipe地址设置选择和接收数据,因此nrf24l01只知道自己的地址是什么,不知道发送者是谁,所以实际nrf24l01要通过RF发送的数据需要包含src address。因此将frame数据去掉dst进行发送:
nrf24l01将dst address设置入硬件寄存器,nrf24l01会自动将数据发送到指定的地址。
从发送的数据格式可以看出nrf24l01通过RF收到的数据也是没有dst addr的,但nrf24l01只收自己地址的数据,所以dst addr也就知道是什么,因此nrf24l01收到数据后,根据收到数据的pipe,为数据加上dst addr然后送到RDC层,再由frame来解包。
RDC层直接使用contikimac
MAC层使用nullmac,因为nrf24l01自已后碰撞和可靠接收的硬件机制因此MAC层不用再做动作,直接转发到NETSTACK层即可
NETSTACK用什么,看具体情况,可以选择uip也可用rime等等。
关于nrf24l01一个packet的长度
nrf24l01能发送的净payload为32byte,为了适应在contiki,要从其中分出3~5个byte放src addr,在我的移植中定义为4,因此nrf24l01发送一个包最长为28byte
本文从contiki收发数据的层级介绍了contiki netstack的数据收发层级。并简单介绍了nrf24l01作为contiki radio的移植方法。nrf24l01要以28byte作为净数据来做为contiki的radio是否可行,还需要进一步探讨。