Contiki通信之数据接收过程

本文以mx231cc平台,cpu为avr为例,大致理清Contiki通信之数据接收过程。相关的代码在cpu\avr、core\net、platform\mx231cc目录下。
       首先在platform\mx231cc目录下打开contiki-conf.h文件,里面配置了相关的网络协议栈:
  1. #define NETSTACK_CONF_NETWORK    sicslowpan_driver
  2. #define NETSTACK_CONF_MAC         nullmac_driver
  3. #define NETSTACK_CONF_RDC        sicslowmac_driver
  4. #define NETSTACK_CONF_FRAMER      framer_802154
  5. #define NETSTACK_CONF_RADIO       rf230_driver
复制代码
说明:网络层驱动为 sicslowpan_driver ,MAC层的驱动为 nullmac_driver ,RDC层的驱动为 sicslowmac_driver ,802154包的生成和解析驱动为 framer_802154 ,RADIO层驱动为 rf230_driver 。这些驱动在系统源码中均有定义,不赘述。
       接下来就来看看platform\mx231cc目录下的contiki-mx231cc-main.c主文件。我们注意到对各个网络中各个层的初始化:
  1. /* Start radio and radio receive process */
  2. NETSTACK_RADIO.init();
  3. /* Initialize stack protocols */
  4.   NETSTACK_RDC.init();
  5.   NETSTACK_MAC.init();
  6. NETSTACK_NETWORK.init();
复制代码
我们来看看最重要的 NETSTACK_RADIO.init() ,正是这一初始化开始了Radio接收数据的进程,部分主要的代码如下:
  1. int rf230_init(void)
  2. {
  3.   //略去部分代码
  4. /* Start the packet receive process */
  5.   process_start(&rf230_process, NULL);
  6.   /* Leave radio in on state (?)*/
  7.   on();
  8.   return 1;
  9. }
复制代码
通过语句 process_start(&rf230_process, NULL) 启动了 rf230_process ,我们来看看 rf230_process 的部分主要代码:
  1. PROCESS_THREAD(rf230_process, ev, data)
  2. {
  3. //略去部分代码
  4.     PROCESS_BEGIN();
  5.   while(1) {
  6.     PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
  7.     packetbuf_clear();
  8.     len = rf230_read(packetbuf_dataptr(), PACKETBUF_SIZE); //读取数据       
  9.     if(len > 0) {
  10.       packetbuf_set_datalen(len);
  11.       RF230PROCESSFLAG(2);
  12.       NETSTACK_RDC.input(); //向RDC层提交数据
  13.     } else {
  14.        RF230_receivefail++    
  15. }
  16.   }
  17.   PROCESS_END();
  18. }
复制代码
上述代码表明,当该进程收到 PROCESS_EVENT_POLL 事件时,就会从射频芯片读数据。射频芯片每收到一个frame,都会向cpu 发送一个中断,进而CPU将收到的数据读走。
中断函数部分主要代码如下:
  1. int
  2. rf230_interrupt(void)
  3. {
  4. //略去部分代码
  5.   /* Poll the receive process, unless the stack thinks the radio is off */
  6.   process_poll(&rf230_process);
  7.   
  8. }
复制代码
所以 RADIO 层收包部分就结束了,读取数据后将数据交至 RDC 层进行处理。 NETSTACK_RDC.input() ;下面来看看 NETSTACK_RDC.input() core\net\ma c目录 sicslowmac.c 下的 input_packet() 函数的部分主要代码:
  1. static void
  2. input_packet(void)
  3. {
  4. //略去部分代码
  5.   frame802154_t frame;
  6.   int len;
  7.   len = packetbuf_datalen();
  8.   NETSTACK_MAC.input();
  9.   }
复制代码
提交给 mac 层继续处理。进入函数 nullmac_driver.input() ,即 core\net\mac  下的  nullmac.c  中的 packet_input ,代码如下:
  1. static void
  2. packet_input(void)
  3. {
  4.   NETSTACK_NETWORK.input();
  5. }
复制代码
因为 nullMAC 层对数据什么也不做,直接转接数据,故直接交由 6Lowpan 进行处理,进入函数 sicslowpan_driver.input() , 即 core/net/sicslowpan.c  中的  input() 函数,这是6LowPan适配层,主要负责对 mac 层数据进行压缩报头等数据分析和重组,部分主要代码如下:
  1. static void
  2. input(void)
  3. {
  4. //数据处理过程略
  5. tcpip_input();
  6. }
复制代码
接着 sicslowpan 将数据提交给网络层进行处理,进入函数 tcpip_input() 函数,即位于 core\net 下的 tcpip.c 文件。
  1. void
  2. tcpip_input(void)
  3. {
  4.   process_post_synch(&tcpip_process, PACKET_INPUT, NULL);
  5.   uip_len = 0;
  6. #if UIP_CONF_IPV6
  7.   uip_ext_len = 0;
  8. #endif /*UIP_CONF_IPV6*/
  9. }
复制代码
此函数给 tcpip_process 进程发送了一个 packet_input 事件并激活这个线程。
  1. PROCESS_THREAD(tcpip_process, ev, data)
  2. {
  3.   PROCESS_BEGIN();
  4.   //中间略
  5.   while(1) {
  6.     PROCESS_YIELD();
  7.     eventhandler(ev, data);
  8.   }
  9.   
  10.   PROCESS_END();
  11. }
复制代码
  1. static void
  2. eventhandler(process_event_t ev, process_data_t data)
  3. {
  4. switch(ev) {
  5. case PACKET_INPUT:
  6.       packet_input();
  7.       break;
  8.   }
  9. }
复制代码
接着进入 packet_input() 函数,同样在 tcpip.c 文件下,部分主要代码如下:
  1. static void
  2. packet_input(void)
  3. {
  4. //中间略
  5.       uip_input();
  6.       
  7. }
复制代码
最后进入 uip_input() 函数,至此数据成功的转交到 uIP 协议栈进行处理,在 uip_porcess 会对网络层以及传输层的包头进行分析最后通过 UIP_APPCALL() 函数会把数据包分发到不同的应用程序接着由应用程序进行处理。

你可能感兴趣的:(Contiki通信之数据接收过程)