1. 程式人生 > >Contiki OS 資料包接收流程分析

Contiki OS 資料包接收流程分析

Contiki OS 資料包接收流程 

總的來說分為兩步:1、適配層sicslowpan.c(以ipv6為例)呼叫tcpip_input()(位於tcipip.c)向tcpip_process傳遞PACKET_INPUT事件/訊息

    2、tcpip程序處理函式event_handler()依據該事件呼叫uip6.c/uip.c接收資料包

 

以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中會對網路層以及傳輸層的包頭進行分析,並提交給應用程式,並依據連線狀態以及資料包型別進行處理。

至此,資料的接收流程結束。