Contiki的NETWORK层间数据传输流程

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事件:
int
rf230_interrupt(void)
{
  /* Poll the receive process, unless the stack thinks the radio is off */
#if RADIOALWAYSON
if (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内存占用很小的原因之一。

你可能感兴趣的:(NetWork,contiki)