1. 程式人生 > >nbr_table原始碼之標頭檔案

nbr_table原始碼之標頭檔案

學完contiki的核心之後,想重點學一學路由協議RPL。奈何資料實在太少,網上大部分都講只是講個大概而已,很多具體細節都沒有,我也是很苦惱。基本上都是靠《基於IP的物聯網架構、技術與應用》還有這位博主http://cgbluesky.blog.163.com/裡翻譯的關於RPL的標準手冊RFC6550。艱難學了個基本,接下來更多細節想從RPL的原始碼裡一探究竟,沒想到一開啟完全懵逼,太複雜了,咱還是一步一步來吧,先從裡面經常用到的結構裡開始研究。第一個就是鄰居列表nbr_table。 如果你有contiki的原始碼可以在這個目錄下 \core\net 找到nbr_table.h。至於為啥叫鄰居列表,那就得去看IPV6了,裡面就有這個鄰居的概念,我想這個鄰居列表可能不僅用在RPL,IPV6的原始碼裡肯定也會用到吧。廢話不多說,開始看原始碼。 /*********************************************************************nbr_table.h***************************************************/ 首先定義了一個鄰居列表裡成員的數量,最多8個成員 /* Neighbor table size */
#ifdef NBR_TABLE_CONF_MAX_NEIGHBORS #define NBR_TABLE_MAX_NEIGHBORS NBR_TABLE_CONF_MAX_NEIGHBORS #else /* NBR_TABLE_CONF_MAX_NEIGHBORS */ #define NBR_TABLE_MAX_NEIGHBORS 8 #endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */ 鄰居列表的成員是什麼資料型別的,這裡定為void,是為了方便後續鄰居成員可以是各種結構體型別 /* An item in a neighbor table */
typedef void nbr_table_item_t; 鄰居列表的操作函式,用來從列表裡刪除成員 /* Callback function, called when removing an item from a table */ typedef void(nbr_table_callback)(nbr_table_item_t *item); 鄰居列表結構體,就是說一個列表就是一個結構體咯,結構體裡有一個索引index,列表成員的大小item_size,還有用來從列表裡刪除成員的函式,最後是一個成員指標。你可能覺得很奇怪,不是說是一個列表麼,沒看出來有多個成員的感覺啊,別急往下看就懂了。 /* A neighbor table */
typedef struct nbr_table { int index; int item_size; nbr_table_callback *callback; nbr_table_item_t *data; } nbr_table_t; 重頭戲來了,這裡定義了一個巨集,叫NBR_TABLE(type,name),它就是用來建立一個鄰居列表的。這種風格跟contiki系統的原始碼風格是一樣的,一個巨集就代表了三條語句。我們注意看這裡的兩個巨集NBR_TABLE和NBR_TABLE_GLOBAL有啥區別,就最後一條語句一個是靜態變數一個不是,其實GLOBAL就代表著這個變數是全域性的,但是巨集裡定義的前兩個可不是。在rpl原始碼裡我們找一個例子展開來看看。比如NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);展開 static rpl_parent_t rpl_parents_mem[8] static nbr_table_t rpl_parents_struct = {0,sizeof(type),NULL,(nbr_table_item_t *) rpl_parents_mem} nbr_table_t* rpl_parents = &rpl_parents_struct 是不是就看出來點意思了,首先定義了一個你指定了type的型別的陣列,然後定義了一個鄰居列表結構體,然後把那個陣列的指標交給nbr_table_item_t指標型別的成員,也就是列表結構體裡的data成員實際就是列表陣列的頭指標了,突然明白了為啥要有item_size這個成員了,並且我們也看到了這個成員的值是sizeof(type),也就是以後要一個一個成員取出來的時候就知道一次取多少資料了,這個列表結構體可以適用各種不同型別的成員,真是靈活。 static type #define NBR_TABLE(type, name) \ static type _##name##_mem[NBR_TABLE_MAX_NEIGHBORS]; \ static nbr_table_t name##_struct = { 0, sizeof(type), NULL, (nbr_table_item_t *)_##name##_mem }; \ static nbr_table_t *name = &name##_struct \
/** \brief A non-static neighbor table. To be initialized through nbr_table_register(name) */ #define NBR_TABLE_GLOBAL(type, name) \ static type _##name##_mem[NBR_TABLE_MAX_NEIGHBORS]; \ static nbr_table_t name##_struct = { 0, sizeof(type), NULL, (nbr_table_item_t *)_##name##_mem }; \ nbr_table_t *name = &name##_struct \ #define NBR_TABLE_DECLARE(name) extern nbr_table_t *name 最後這個列表結構體指標是為了給定義鄰居列表結構體之外的模組訪問列表結構體的時候使用的,所以就有下面這個巨集,對這個列表結構體指標的一個外部宣告。像剛剛那個NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);是在rpl_dag.c裡,而在rpl.h裡有NBR_TABLE_DECLARE(rpl_parents);這麼一句,所以在rpl.c裡很多地方都用到這個rpl_parents指標。 typedef enum { NBR_TABLE_REASON_UNDEFINED, NBR_TABLE_REASON_RPL_DIO, NBR_TABLE_REASON_RPL_DAO, NBR_TABLE_REASON_RPL_DIS, NBR_TABLE_REASON_ROUTE, NBR_TABLE_REASON_IPV6_ND, NBR_TABLE_REASON_MAC, NBR_TABLE_REASON_LLSEC } nbr_table_reason_t; 這個列舉型暫時還不清楚用在哪 接下來就聲明瞭一大堆針對這個鄰居列表結構體的操作函式。 int nbr_table_register(nbr_table_t *table, nbr_table_callback *callback); nbr_table_item_t *nbr_table_head(nbr_table_t *table); nbr_table_item_t *nbr_table_next(nbr_table_t *table, nbr_table_item_t *item); nbr_table_item_t *nbr_table_add_lladdr(nbr_table_t *table, const linkaddr_t *lladdr, nbr_table_reason_t reason, void *data); nbr_table_item_t *nbr_table_get_from_lladdr(nbr_table_t *table, const linkaddr_t *lladdr); int nbr_table_remove(nbr_table_t *table, nbr_table_item_t *item); int nbr_table_lock(nbr_table_t *table, nbr_table_item_t *item); int nbr_table_unlock(nbr_table_t *table, nbr_table_item_t *item); linkaddr_t *nbr_table_get_lladdr(nbr_table_t *table, const nbr_table_item_t *item); #endif /* NBR_TABLE_H_ */