天天看点

uip0.9成功移植Z-STACK中

        之前将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目录,并在这两个目录分别添加一下源文件

uip0.9成功移植Z-STACK中
uip0.9成功移植Z-STACK中

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工程,如下图所示

uip0.9成功移植Z-STACK中

      然后在相关文件中做一些修改。在一个大工程项目中,条件编译用的很多,为了和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网络中的数据接收缓冲区,一旦接收到数据,就将这些数据发送以太网中。然后编译链接,这其中不乏出现各种问题,需要自己去一一解决。

接下来看一下实验运行的结果

                                      :

uip0.9成功移植Z-STACK中

这是一个ZigBee模块打开时出现的结果,因为此时zigbee网络中还没有数据,所以此时buf一直为Battery:(我将buf初始化为Battery:),所以看到了以上结果。然后打开另一个zigbee模块,可以看到这个运行结果:

uip0.9成功移植Z-STACK中

看到了么,结果发生变化了,网络调试助手接收到了从无线网络中发过来的数据,这是cc2530内部温度传感器的数据!同时将串口助手打开看到:

uip0.9成功移植Z-STACK中

看到这个结果说明移植是成功的!哈哈!离完成项目又进了一步!

PS:在之前裸机移植uIP0.9到cc2530上,发现移植web服务器时出了一个很怪异的问题!这个问题困扰了很久了!从理论上分析根本不会出现这个问题,但是实践中可能会漏洞百出。等解决了这个问题再贴出来!相信很多同学都遇到了这个问题!