Contiki OS 数据包接收流程分析

Contiki OS 数据包接收流程 


总的来说分为两步:1、适配层sicslowpan.c(以ipv6为例)调用tcpip_input()(位于tcipip.c)向tcpip_process传递PACKET_INPUT事件/消息

    2、tcpip进程处理函数event_handler()依据该事件调用uip6.c/uip.c接收数据包

 Contiki OS 数据包接收流程分析_第1张图片

以ESB为例:CPU为msp430, 射频芯片为Tr1001。相关代码在/platform/esb 以及 /cpu/msp430 ,/core/net中在contiki-conf.h中首先对各层的协议栈进行了定义。如下:

#define NETSTACK_CONF_RADIO tr1001_driver

#define NETSTACK_CONF_NETWORK uip_driver

#define NETSTACK_CONF_MAC nullmac_driver

#define NETSTACK_CONF_RDC nullrdc_driver


从主函数Contiki-esb-main.c开始,先说数据的接收流程。

首先,定义一块网卡:

static struct uip_fw_netif tr1001if =

{UIP_FW_NETIF(0,0,0,0, 0,0,0,0, uip_driver_send)};

其中uip_driver_send就是这块网卡的发包函数。

在主函数中会进行协议栈的初始化,另外开启几个关于收发数据的进程。

int main(void)

{

msp430_cpu_init();

process_start(&etimer_process, NULL);

netstack_init();

init_uip_net();

autostart_start(autostart_processes);

watchdog_start();

while(1) {

int r;

do {

/* Reset watchdog. */

watchdog_periodic();

r = process_run();

} while(r > 0);

return 0;

}

其中,init_uip_net() 中启动了两个进程如下:

static void init_uip_net(void)

{

process_start(&tcpip_process, NULL);//该进程在tcpip.c中进行处理

process_start(&uip_fw_process, NULL);

}

这两个进程我们在以后会用到。

 

netstack_init()如下:

void netstack_init(void)

{

NETSTACK_RADIO.init();

NETSTACK_RDC.init();

NETSTACK_MAC.init();

NETSTACK_NETWORK.init();

}

即,netstack_init会对各层驱动均进行初始化。

下面,主要说Radio层的驱动初始化:

Int tr1001_init(void)

{

PT_INIT(&rxhandler_pt);

process_start(&tr1001_process, NULL);

return 1;

}

该初始化过程中启动了 tr1001_process, 如下:

PROCESS_THREAD(tr1001_process, ev, data)

{

PROCESS_BEGIN();

while(1) {

PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);

packetbuf_clear();

len = tr1001_read(packetbuf_dataptr(), PACKETBUF_SIZE); // 读取数据

if(len > 0) {

packetbuf_set_datalen(len);

NETSTACK_RDC.input(); // 向上提交

}

}

PROCESS_END();

}

当该进程收到事件ev == PROCESS_EVENT_POLL时,就会从射频芯片读数据。

我们知道,射频芯片每收到一个frame,都会向cpu发送一个中断,进而CPU将收到的数据读走。下面,看这个PROCESS_EVENT_POLL事件的产生过程。

中断注册函数如下:

interrupt (UART0RX_VECTOR)

tr1001_rxhandler(void)

{

ENERGEST_ON(ENERGEST_TYPE_IRQ);

tr1001_default_rxhandler_pt(RXBUF0);

if(tr1001_rxstate == RXSTATE_FULL) {

LPM4_EXIT;

}

ENERGEST_OFF(ENERGEST_TYPE_IRQ);

}

Char tr1001_default_rxhandler_pt(unsigned char incoming_byte))

{

static unsigned char rxtmp, tmppos;

if(rxcrctmp == rxcrc) {

/* A full packet has been received and the CRC checks out. We'll

request the driver to take care of the incoming data. */

RIMESTATS_ADD(llrx);

process_poll(&tr1001_process);//提升优先级

PT_END(&rxhandler_pt);

}

 

到这里,radio层的收包过程就结束了。通过 NETSTACK_RDC.input() 将数据提交到rdc层。

进入函数:nullrdc_driver.input(), 即core\net\mac 下的 nullrdc.c 中的packet_input。

static void packet_input(void)

{

NETSTACK_MAC.input();

}

提交给mac层继续处理。进入函数nullmac_driver.input(),即core\net\mac 下的 nullmac.c 中的packet_input。

static void packet_input(void)

{

NETSTACK_NETWORK.input();

}

提交给网络层进行处理。进入函数uip_driver.input(), 即platform/esb/net/uip_dirver.c中的 input函数。

 

static void input(void)

{

if(packetbuf_datalen() > 0 && packetbuf_datalen() <=UIP_BUFSIZE - UIP_LLH_LEN) {

memcpy(&uip_buf[UIP_LLH_LEN], packetbuf_dataptr(),packetbuf_datalen());

uip_len = hc_inflate(&uip_buf[UIP_LLH_LEN], packetbuf_datalen());

tcpip_input();    //传递PACKET_INPUT事件

}

}

Void tcpip_input(void)

{

process_post_synch(&tcpip_process, PACKET_INPUT, NULL);

}

Tcpip_input 向进程tcpip_process 传递消息PACKET_INPUT。(下面三个函数均位于/core/net/tcpip.c)

PROCESS_THREAD(tcpip_process, ev, data)

{

PROCESS_BEGIN();

tcpip_event = process_alloc_event();

while(1) {

PROCESS_YIELD();

eventhandler(ev, data); //tcpip进程处理函数

}

PROCESS_END();

}

/*---------------------------------------------------------------*/

static void

eventhandler(process_event_tev, process_data_t data)

{

switch(ev) {

case PROCESS_EVENT_EXITED: …

case PROCESS_EVENT_TIMER: ….

case TCP_POLL: …

case UDP_POLL: ...

case PACKET_INPUT:

packet_input();

break;

};

}

static void

packet_input(void)

{

if(uip_len > 0) {

tcpip_is_forwarding = 1;

if(uip_fw_forward() == UIP_FW_LOCAL) { // 这里执行路由和转发

tcpip_is_forwarding = 0;

check_for_tcp_syn();

uip_input();  //tcp调用uip读取数据包

if(uip_len > 0) {

tcpip_output();

}

}

tcpip_is_forwarding = 0;

}

}

到uip_input(就是函数uip_process()),至此数据成功的转交到UIP协议栈进行处理。

Uip_process中会对网络层以及传输层的包头进行分析,并提交给应用程序,并依据连接状态以及数据包类型进行处理。

至此,数据的接收流程结束。

你可能感兴趣的:(OS,contiki,6lowpan,数据包接收,uip,sicslowpan)