Contiki的NETWORK层间数据传输流程

来源:互联网 发布:java全套视频教程下载 编辑:程序博客网 时间:2024/05/17 22:18
Contiki的NETWORK层之间的数据流路径:
Send:
Network->Mac->Rdc(->Frame802154)->Radio
Recv:
Radio->Rdc(->Frame802154)->Mac->Network
注:在此结构中,802154应该是属于RDC层的,
如果不将RDC算作一层,应该是介于Mac和Radio之间。是Mac层的出口。这也是Contiki的一项重要模块之一。在Contiki中ContikiMAC.c模块实现了RDC功能。论文《The ContikiMAC Radio Duty Cycling Protocol》详细描述了RDC的实现与理论基础。

在Contiki中接收采用事件驱动方式。接收通过一个PThread任务,等待数据到来事件,如果数据到来事件触发,则将数据则取出来。这个事件触发是在Radio的中断中设置的。
即:NETSTACK_RDC.input()的调用一般都是在Radio的一个PThread中,由于在Network.open的时候已经将每一层的回调函数设置完备,所以当接收到数据的时候,通过每一层的回调,将数据传递到Network_Network处,即协议栈的最顶部应用层处理。

以contiki\cpu\avr\radio\rf230bb\rf230bb.c文件为例
rf230_interrupt()函数中判断接收到数据, 调用process_poll(&rf230_process),发送PROCESS_EVENT_POLL事件:
intrf230_interrupt(void){  /* Poll the receive process, unless the stack thinks the radio is off */#if RADIOALWAYSONif (RF230_receive_on) {  DEBUGFLOW('+');#endif#if RF230_CONF_TIMESTAMPS  interrupt_time = timesynch_time();  interrupt_time_set = 1;#endif /* RF230_CONF_TIMESTAMPS */  process_poll(&rf230_process);    rf230_pending = 1;  #if RADIOSTATS //TODO:This will double count buffered packets  RF230_receivepackets++;#endif  RIMESTATS_ADD(llrx);#if RADIOALWAYSON} else {  DEBUGFLOW('-');  rxframe[rxframe_head].length=0;}#endif  return 1;}

在rf230_process PThread中收到PROCESS_EVENT_POLL,调用NETSTACK_RDC.input()进入数据接收处理流程。最后在Radio文件中,找到了调用process_poll()函数来,poll一个PROCESS_EVENT_POLL。
PROCESS_THREAD(rf230_process, ev, data){  int len;  PROCESS_BEGIN();  RF230PROCESSFLAG(99);  while(1) {    PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);    RF230PROCESSFLAG(42);    packetbuf_clear();    /* Turn off interrupts to avoid ISR writing to the same buffers we are reading. */    HAL_ENTER_CRITICAL_REGION();    len = rf230_read(packetbuf_dataptr(), PACKETBUF_SIZE);    /* Restore interrupts. */    HAL_LEAVE_CRITICAL_REGION();    PRINTF("rf230_read: %u bytes lqi %u\n",len,rf230_last_correlation);#if DEBUG>1     {        uint8_t i;        unsigned const char * rxdata = packetbuf_dataptr();        PRINTF("0000");        for (i=0;i<len+AUX_LEN;i++) PRINTF(" %02x",rxdata[i]);        PRINTF("\n");      }#endif    RF230PROCESSFLAG(1);    if(len > 0) {      packetbuf_set_datalen(len);      RF230PROCESSFLAG(2);      NETSTACK_RDC.input();    } else {#if RADIOSTATS       RF230_receivefail++;#endif    }  }  PROCESS_END();}

附1:
以Contiki中example-mesh.c历程为例:
examples/example-mesh.c/example_mesh_process/mesh_open

send:
(在rime中:
mesh.c/mesh_send()
multihop_send()
unicast_send()
broadcast_send()
abc_send()(abc_send中调用rime_output)
)
rime.c/rime_output()/NETSTACK_MAC.send
nullmac.c/NETSTACK_RDC.send
(NETSTACK_FRAMER.create 生成framer)
nullrdc.c/NET_RADIO.send
nullrdc.c/mac_call_sent_callback 处理发送结束后的状态。

recv:
tf230bb/fr230bb.c/rf230_interrupt  调用process_poll产生PROCESS_EVENT_POLL。
pthread
rf230bb.c/rf230_process任务/NETSTACK_RDC.input
(NETSTACK_FRAMER.parse解析收到的数据帧,是否符合MAC层要求)
nullrdc.c/NETSTACK_MAC.input
nullmac.c/NETSTACK_NETWORK.input 调用rime.c/input()/abc_input()
通过rime协议栈的回调传递给
mesh.c/data_packet_received()此函数回调应用层的接收处理函数
example-mesh.c/example_recv()处理接收数据。

附2:
stunicast.c中
对于重发的处理,由在发送过程中设置timer如果在规定的时间内,如果没有数据返回则通过timer调用回调处理函数,如果有数据返回则在在recv_from_stunicast()调用stunicast_cancel()取消timer,避免调用回调。
在Contiki中,数据的发送与接收分别使用一个任务,这样可以避免之间的冲突问题。
NETWORK协议栈层之间的数据交互,通过buf来实现。这一点与Linux的sk_buff很像,所以导致了很多不必要的内存拷贝,这也是为什么Contiki内存占用很小的原因之一。
0 0
原创粉丝点击