之前将UIP0.9移植到CC2530上,是裸機移植的,由于項目需要,前幾天将UIP0.9移植到Z-STACK中,并且系統能穩定運作,即實作了一個簡單的TCP/IP+ZIGBEE的網關或者無線接入點。下面簡要闡述下移植過程及運作結果。
說明一下,我的Z-STACK版本ZStack-CC2530-2.2.2-1.3.0,用的是SimpleApp例程,在移植之前需要熟悉SimpleApp中的SimpleCollector和SimpleSensor實驗,以及UIP0.9的cc2530裸機移植實驗。最重要的是要熟悉
Z-STACK中事件驅動OSAL的運作機制和流程,這樣才知道在哪些地方添加需要的代碼。
首先,在該項目的source目錄裡面添加uip和uip_app目錄,并在這兩個目錄分别添加一下源檔案
uip目錄中的檔案均為uip0.9源碼包裡面的檔案,uip_app目錄中兩個檔案自己添加,然後分别将這些檔案添加到工程。将enc28j60的驅動程式檔案命名為hal_net.c,為了和Z-STACK中的驅動檔案名字保持一緻,相應添加一個頭檔案
hal_net.h,這兩個檔案在之前移植過程都有,隻不過改了名字,略做修改而已。再分别将這兩個檔案添加進Z-STACK的驅動目錄中,即driver目錄中,相應路徑為
C:\Texas Instruments\ZStack-CC2530-2.2.2-1.3.0\Components\hal\target\CC2530EB
然後打開SimpleCollectorEB工程,如下圖所示
然後在相關檔案中做一些修改。在一個大工程項目中,條件編譯用的很多,為了和Z-STACK中保持一緻,在
hal_board_cfg.h添加如下代碼
#ifndef HAL_NET
#define HAL_NET TRUE
#endif
#ifndef UIP
#define UIP TRUE
#endif
當不需要網絡功能就可以将這寫注釋掉。
然後在sapi.c檔案SAPI_Init函數添加如下代碼
void SAPI_Init( byte task_id )
{
uint8 startOptions;
#if (defined UIP)&&(UIP == TRUE)
uip_init(); //uip初始化
example1_init(); //uip應用程式初始化
#endif
sapi_TaskID = task_id;
sapi_bindInProgress = 0xffff;
sapi_epDesc.endPoint = zb_SimpleDesc.EndPoint;
sapi_epDesc.task_id = &sapi_TaskID;
.....
}
當然别忘了添加頭檔案
#if (defined UIP)&&(UIP == TRUE)
#include "uip.h"
#include "app.h"
#endif
在hal_driver.c檔案HalDriverInit()函數中末尾添加如下代碼(記住是末尾添加,不能在開始添加,否則會有問題,我剛開始是放在開頭的,結果出現調試不出結果,這個問題我也找了半天原因,先不說哈!)
#if (defined HAL_NET) && (HAL_NET == TRUE)
HalNetInit(); //網絡晶片驅動的初始化
#endif
需要在這個HalNetInit()中添加 HalSpiInit()函數,因為我用的是enc28j60網絡晶片,其與cc2530的IO相連接配接,用的IO模拟SPI接口,是以這裡面要初始化這幾個IO。
同樣在該檔案 Hal_ProcessPoll ()函數中添加如下代碼:(這個最好在開頭添加,因為網絡資料包處理要及時)
#if (defined HAL_NET) && (HAL_NET == TRUE)
HalNetDataPoll();
#endif
這個 HalNetDataPoll()函數是什麼呢?我在裡面添加了如下代碼
uint8 i;
uint16 j;
uip_len = dev_poll();
for(j=0;j<500;j++);
if(uip_len==0)
{
for(i = 0; i < UIP_CONNS; i++)
{
uip_periodic(i);
if(uip_len>0)
{
uip_arp_out();
dev_send();
}
}
if(++arptimer == 20)
{
uip_arp_timer();
arptimer = 0;
}
}
else
{
if(BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();
uip_input();
if(uip_len > 0)
{
uip_arp_out();
dev_send();
}
}
else if(BUF->type == htons(UIP_ETHTYPE_ARP))
{
uip_arp_arpin();
if(uip_len>0)
{
dev_send();
}
}
}
其實大家對這部分代碼應該相當熟悉了,對!這就是移植uip到cc2530中main函數裡面的大while(1)循環裡面的代碼。 因為Hal_ProcessPoll ()函數是系統輪詢用的,每次for循環都會調用這個函數,是以HalNetDataPoll()每次都會得到調用以進行網絡資料包的及時處理。這個是移植過程的關鍵部分。我之前試過用事件驅動機制将這個while循環的内容分解掉,将其放在Z-stack中的不同部分,但是發現效果極差,什麼看不到想要的結果!可能是哪兒拆分的不合理!但是這種方式使能看到網絡通信的結果的。
另外就是資料類型的定義,在uip和z-stack中的定義是不同,這個很容易處理!還有就是頭檔案,這個在編譯出錯時進行相應添加!
最後就是uip.c檔案,這個需要自己寫,我的代碼如下
void example1_init()
{
uip_listen(HTONS(1234));
}
#if 1
void example1_appcall()
{
switch(uip_conn->lport) {
case HTONS(1234):
if(uip_timedout()||uip_aborted()||uip_closed()){
//delay_sec(5);
}else if(uip_connected()){
#if 1
uip_send(uip_appdata,sprintf((char*)uip_appdata,"%s",
"Hello,I connected to you! thanks."));
#endif
}else if(uip_rexmit()){
#if 1
uip_send(uip_appdata,sprintf((char*)uip_appdata,"%s",
"this is retransmission packet"));
#endif
}else if(uip_poll()){
#if 1
// uip_send(uip_appdata,sprintf((char*)uip_appdata,"%s",
// "Hi, we are idle"));
//uip_send("idle",4);
uip_send(buf,32);
#endif
}else if(uip_acked()){
#if 0
uip_send(uip_appdata,sprintf((char*)uip_appdata,"%s",
"this is a second packet."));
#endif
if(uip_newdata()){
goto newdata_with_acked;
}
}else if(uip_newdata()){
newdata_with_acked:
#if 1
uip_send(uip_appdata,sprintf((char*)uip_appdata,"%s",
"this is a second packet."));
#endif
}else{
}
break;
default:
break;
}
}
#endif
上面代碼中有一個數組buf,這個是在SimpleCollector.c檔案中定義的,因為buf為zigbee網絡中的資料接收緩沖區,一旦接收到資料,就将這些資料發送以太網中。然後編譯連結,這其中不乏出現各種問題,需要自己去一一解決。
接下來看一下實驗運作的結果
:
這是一個ZigBee子產品打開時出現的結果,因為此時zigbee網絡中還沒有資料,是以此時buf一直為Battery:(我将buf初始化為Battery:),是以看到了以上結果。然後打開另一個zigbee子產品,可以看到這個運作結果:
看到了麼,結果發生變化了,網絡調試助手接收到了從無線網絡中發過來的資料,這是cc2530内部溫度傳感器的資料!同時将序列槽助手打開看到:
看到這個結果說明移植是成功的!哈哈!離完成項目又進了一步!
PS:在之前裸機移植uIP0.9到cc2530上,發現移植web伺服器時出了一個很怪異的問題!這個問題困擾了很久了!從理論上分析根本不會出現這個問題,但是實踐中可能會漏洞百出。等解決了這個問題再貼出來!相信很多同學都遇到了這個問題!