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