[牛人杂谈] uip

[复制链接]
3433|12
 楼主| dongnanxibei 发表于 2019-4-28 23:17 | 显示全部楼层 |阅读模式
137615cc5c3cc13f9b.png
NUC472开发板例程中关于网络的开发示例有两种:uip和lwip,目前来看lwip是开发网络的最佳选择,资料很多,而uip几乎是小众选择了,但这两种协议栈的作者是同一个人--Adam Dunkels,感觉他是一个很牛叉的人,写过很多开源软件,uip目前好像停止单独更新了,uip项目合并到contiki项目中了,目前uip单独的最新版本是uip1.0,lwip目前更新记录是lwip2.0 RC2,之所以先选择uip来研究是因为它比较小源代码文件较少,方便入手,但后面肯定还是要学习lwip的,而且lwip2.0的稳定版还没放出来,等放出来后再研究吧。
uip-1.0源码目录很少,如下:

108355cc5c4010c58e.png
uip-1.0比uip-0.9多了一些文件,相比而言uip-0.9更简洁一些。apps目录包含了一些uip应用的示例,方便用于编辑代码时可以参考,其中包含了一些常用的示例如:webserver、webclient、telnetd、smtp等,doc目录包含了参考手册方便用户学习该源码,lib目录是比uip-0.9多出的一个目录,其为uip-1.0的内存管理模块,uip目录则是协议栈的核心文件,最后的unix则是一个示例程序,方便用户移植uip-1.0协议栈到所需要的平台。我们在NUC472平台上使用该协议栈,所需要做的工作就是重写unix目录下的文件
824645cc5c41a4a02c.png

 楼主| dongnanxibei 发表于 2019-4-28 23:18 | 显示全部楼层
在uip-conf.h文件中我们选择引用apps目录下的哪个示例,默认使用的是webserver示例。tapdev文件则是跟硬件相关的以太网发送和接收数据的函数,uip协议栈只是处理以太网数据包,但具体的数据包来源以及处理完之后的数据包发送还是要交由具体硬件来实现的,也就是我们的以太网驱动的编写,clock-arch文件则是由具体的硬件提供一个时钟以便于uip检测时间,这些文件说明都可以在参考手册中找到,在初始学习uip协议栈时建议由简入难,因此,这里我实现的示例是helloworld示例,先看下tapdev模块的编写,tapdev模块只需要完成三个函数即可:tapdev_init()、tapdev_send()、tapdev_read(),在NUC472中实现这三个文件还是比较简单的,如下:
 楼主| dongnanxibei 发表于 2019-4-28 23:19 | 显示全部楼层
  1. /*
  2. * Copyright (c) 2001, Swedish Institute of Computer Science.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. *    notice, this list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. *    notice, this list of conditions and the following disclaimer in the
  14. *    documentation and/or other materials provided with the distribution.
  15. *
  16. * 3. Neither the name of the Institute nor the names of its contributors
  17. *    may be used to endorse or promote products derived from this software
  18. *    without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * Author: Adam Dunkels <adam@sics.se>
  33. *
  34. * $Id: tapdev.c,v 1.8 2006/06/07 08:39:58 adam Exp $
  35. */

  36. #include "NUC472_442.h"
  37. #include "uip.h"
  38. #include "string.h"

  39. extern struct uip_eth_addr ethaddr;
  40. uint32_t volatile u32PktLen = 0;//接收到的数据包长度

  41. /*---------------------------------------------------------------------------*/

  42. /**
  43.   * [url=home.php?mod=space&uid=247401]@brief[/url]  EMAC Tx interrupt handler.
  44.   * @param  None
  45.   * [url=home.php?mod=space&uid=266161]@return[/url] None
  46.   */
  47. void EMAC_TX_IRQHandler(void)
  48. {
  49.     // Clean up Tx resource occupied by previous sent packet(s)
  50.     EMAC_SendPktDone();
  51. }


  52. /**
  53.   * @brief  EMAC Rx interrupt handler.
  54.   * @param  None
  55.   * @return None
  56.   */
  57. void EMAC_RX_IRQHandler(void)
  58. {
  59.     while(1)
  60.         {
  61.         // Get all recv data
  62.         if(EMAC_RecvPkt(uip_buf, (uint32_t *)&u32PktLen) == 0)
  63.             break;
  64.         // Clean up Rx resource occupied by previous received packet
  65.         EMAC_RecvPktDone();
  66.     }
  67. }

  68. void
  69. tapdev_init(void)
  70. {
  71.         // Select RMII interface by default
  72.     EMAC_Open(ethaddr.addr);
  73.     NVIC_EnableIRQ(EMAC_TX_IRQn);
  74.     NVIC_EnableIRQ(EMAC_RX_IRQn);
  75.     EMAC_ENABLE_RX();
  76.     EMAC_ENABLE_TX();
  77. }
  78. /*---------------------------------------------------------------------------*/
  79. unsigned int
  80. tapdev_read(void)
  81. {
  82.         int len = 0;
  83.         len = u32PktLen;
  84.         u32PktLen = 0;
  85.           return len;
  86. }
  87. /*---------------------------------------------------------------------------*/
  88. void
  89. tapdev_send(void)
  90. {
  91.         EMAC_SendPkt(uip_buf, uip_len);
  92. }
  93. /*---------------------------------------------------------------------------*/
 楼主| dongnanxibei 发表于 2019-4-28 23:20 | 显示全部楼层
在NUC472中数据的发送和接收是由中断完成的,因此tapdev_read()函数只是返回u32PktLen即可,在接收中断中数据已经保存在uip_buf中了。数据发送只需要调用EMAC_SendPkt接口即可。clock-arch模块的编写也很简单只需要实现两个函数即可:clock_init()、clock_time(),这两个函数的声明是在uip的clock.h文件中,这样便于移植的接口一致性,保证接口不变,文件如下:
  1. /*
  2. * Copyright (c) 2006, Swedish Institute of Computer Science.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. *    notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. *    notice, this list of conditions and the following disclaimer in the
  12. *    documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the Institute nor the names of its contributors
  14. *    may be used to endorse or promote products derived from this software
  15. *    without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * This file is part of the uIP TCP/IP stack
  30. *
  31. * $Id: clock-arch.c,v 1.2 2006/06/12 08:00:31 adam Exp $
  32. */

  33. /**
  34. * \file
  35. *         Implementation of architecture-specific clock functionality
  36. * \author
  37. *         Adam Dunkels <adam@sics.se>
  38. */

  39. #include "clock-arch.h"
  40. #include "uip-timer.h"
  41. #include "NUC472_442.h"

  42. volatile clock_time_t curTime = 0;
  43. /*---------------------------------------------------------------------------*/
  44. void TMR0_IRQHandler(void)
  45. {
  46.     curTime++;
  47.     TIMER_ClearIntFlag(TIMER0);
  48. }

  49. void
  50. clock_init(void)
  51. {
  52.         /* Set the Timer by 2Hz & Start it */
  53.     TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 2);/* 2Hz */
  54.     TIMER_EnableInt(TIMER0);
  55.     NVIC_EnableIRQ(TMR0_IRQn);
  56.     TIMER_Start(TIMER0);
  57. }

  58. clock_time_t
  59. clock_time(void)
  60. {
  61.   return curTime;
  62. }
 楼主| dongnanxibei 发表于 2019-4-28 23:21 | 显示全部楼层
在该文件中我们需要实现的是提供一个时钟,这里使用定时器0来实现的,定时频率为2Hz,每次定时器溢出时curTime计数器增加,在clock_time()函数中返回该计数器,clock-arch.h文件实现如下:
  1. #ifndef __CLOCK_ARCH_H__
  2. #define __CLOCK_ARCH_H__

  3. typedef int clock_time_t;
  4. #define CLOCK_CONF_SECOND 2

  5. #endif /* __CLOCK_ARCH_H__ */

由于我们定时器频率为2Hz,因此测量1S时间需要的时钟计数器变化量为2,即需要两次定时器溢出的时间才为1S,这里需要注意的是uip源码中提供了定时器的模块timer.c/h,跟NUC472库中的定时器模块文件名有冲突,因此这里把uip源码中的timer.c.h文件更改为了uip-timer.c/h,这也充分说明了新唐的库代码的名字起的太简单的,很容易跟第三方库代码的文件名冲突。uip-conf.h文件如下:
  1. /**
  2. * \addtogroup uipopt
  3. * @{
  4. */

  5. /**
  6. * \name Project-specific configuration options
  7. * @{
  8. *
  9. * uIP has a number of configuration options that can be overridden
  10. * for each project. These are kept in a project-specific uip-conf.h
  11. * file and all configuration names have the prefix UIP_CONF.
  12. */

  13. /*
  14. * Copyright (c) 2006, Swedish Institute of Computer Science.
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions
  19. * are met:
  20. * 1. Redistributions of source code must retain the above copyright
  21. *    notice, this list of conditions and the following disclaimer.
  22. * 2. Redistributions in binary form must reproduce the above copyright
  23. *    notice, this list of conditions and the following disclaimer in the
  24. *    documentation and/or other materials provided with the distribution.
  25. * 3. Neither the name of the Institute nor the names of its contributors
  26. *    may be used to endorse or promote products derived from this software
  27. *    without specific prior written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  30. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  33. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  34. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  35. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  36. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  37. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  38. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  39. * SUCH DAMAGE.
  40. *
  41. * This file is part of the uIP TCP/IP stack
  42. *
  43. * $Id: uip-conf.h,v 1.6 2006/06/12 08:00:31 adam Exp $
  44. */

  45. /**
  46. * \file
  47. *         An example uIP configuration file
  48. * \author
  49. *         Adam Dunkels <adam@sics.se>
  50. */

  51. #ifndef __UIP_CONF_H__
  52. #define __UIP_CONF_H__

  53. #include <inttypes.h>

  54. /**
  55. * 8 bit datatype
  56. *
  57. * This typedef defines the 8-bit type used throughout uIP.
  58. *
  59. * \hideinitializer
  60. */
  61. typedef uint8_t u8_t;

  62. /**
  63. * 16 bit datatype
  64. *
  65. * This typedef defines the 16-bit type used throughout uIP.
  66. *
  67. * \hideinitializer
  68. */
  69. typedef uint16_t u16_t;

  70. /**
  71. * Statistics datatype
  72. *
  73. * This typedef defines the dataype used for keeping statistics in
  74. * uIP.
  75. *
  76. * \hideinitializer
  77. */
  78. typedef unsigned short uip_stats_t;

  79. /**
  80. * Maximum number of TCP connections.
  81. *
  82. * \hideinitializer
  83. */
  84. #define UIP_CONF_MAX_CONNECTIONS 40

  85. /**
  86. * Maximum number of listening TCP ports.
  87. *
  88. * \hideinitializer
  89. */
  90. #define UIP_CONF_MAX_LISTENPORTS 40

  91. /**
  92. * uIP buffer size.
  93. *
  94. * \hideinitializer
  95. */
  96. #define UIP_CONF_BUFFER_SIZE     420

  97. /**
  98. * CPU byte order.
  99. *
  100. * \hideinitializer
  101. */
  102. #define UIP_CONF_BYTE_ORDER      LITTLE_ENDIAN

  103. /**
  104. * Logging on or off
  105. *
  106. * \hideinitializer
  107. */
  108. #define UIP_CONF_LOGGING         1

  109. /**
  110. * UDP support on or off
  111. *
  112. * \hideinitializer
  113. */
  114. #define UIP_CONF_UDP             0

  115. /**
  116. * UDP checksums on or off
  117. *
  118. * \hideinitializer
  119. */
  120. #define UIP_CONF_UDP_CHECKSUMS   1

  121. /**
  122. * uIP statistics on or off
  123. *
  124. * \hideinitializer
  125. */
  126. #define UIP_CONF_STATISTICS      1

  127. /* Here we include the header file for the application(s) we use in
  128.    our project. */
  129. /*#include "smtp.h"*/
  130. #include "hello-world.h"
  131. /*#include "telnetd.h"*/
  132. /*#include "webserver.h"*/
  133. /*#include "dhcpc.h"*/
  134. /*#include "resolv.h"*/
  135. /*#include "webclient.h"*/

  136. #endif /* __UIP_CONF_H__ */

  137. /** @} */
  138. /** @} */
 楼主| dongnanxibei 发表于 2019-4-28 23:22 | 显示全部楼层
跟unix中的uip-conf.h文件是一样的只是加载的应用头文件改为了hello-world模块,uip-conf.h文件是对uipopt.h文件的补充,之前在uip-0.9中这两个文件是没有分开的,是修改的uipopt.h,main.c文件编写同样比较简单,如下:
  1. /******************************************************************************
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
  4. * $Revision: 2 $
  5. * $Date: 14/11/25 10:00a $
  6. * @brief    A uIP httpd sample for NUC472 MCU.
  7. *
  8. * @note
  9. * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
  10. *****************************************************************************/
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include "NUC472_442.h"
  14. #include "uip.h"
  15. #include "uip_arp.h"
  16. #include "tapdev.h"
  17. #include "uip-timer.h"

  18. #define PLL_CLOCK           84000000

  19. #define BUF ((struct uip_eth_hdr *)&uip_buf[0])

  20. // Our MAC address
  21. struct uip_eth_addr ethaddr = {0x00, 0x00, 0x00, 0x59, 0x16, 0x88};

  22. void SYS_Init(void)
  23. {

  24.     /*---------------------------------------------------------------------------------------------------------*/
  25.     /* Init System Clock                                                                                       */
  26.     /*---------------------------------------------------------------------------------------------------------*/
  27.     /* Unlock protected registers */
  28.     SYS_UnlockReg();

  29.     /* Enable External XTAL (4~24 MHz) */
  30.     CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);

  31.     /* Waiting for 12MHz clock ready */
  32.     CLK_WaitClockReady( CLK_STATUS_HXTSTB_Msk);

  33.     /* Switch HCLK clock source to HXT */
  34.     CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HXT,CLK_CLKDIV0_HCLK(1));

  35.     /* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
  36.     CLK->PLLCTL |= CLK_PLLCTL_PD_Msk;

  37.     /* Set PLL frequency */
  38.     CLK->PLLCTL = CLK_PLLCTL_84MHz_HXT;

  39.     /* Waiting for clock ready */
  40.     CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk);

  41.     /* Switch HCLK clock source to PLL */
  42.     CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL,CLK_CLKDIV0_HCLK(1));

  43.     /* Enable IP clock */
  44.     CLK_EnableModuleClock(UART0_MODULE);
  45.     CLK_EnableModuleClock(EMAC_MODULE);
  46.     CLK_EnableModuleClock(TMR0_MODULE);

  47.     /* Select IP clock source */
  48.     CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UARTSEL_HXT, CLK_CLKDIV0_UART(1));
  49.     CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HXT, 0);

  50.     // Configure MDC clock rate to HCLK / (127 + 1) = 656 kHz if system is running at 84 MHz
  51.     CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));

  52.     /* Update System Core Clock */
  53.     /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
  54.     SystemCoreClockUpdate();


  55.     /*---------------------------------------------------------------------------------------------------------*/
  56.     /* Init I/O Multi-function                                                                                 */
  57.     /*---------------------------------------------------------------------------------------------------------*/
  58.     /* Set GPG multi-function pins for UART0 RXD and TXD */
  59.     SYS->GPG_MFPL = SYS_GPG_MFPL_PG1MFP_UART0_RXD | SYS_GPG_MFPL_PG2MFP_UART0_TXD ;
  60.     // Configure RMII pins
  61.     SYS->GPC_MFPL = SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK |
  62.                     SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXERR |
  63.                     SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXDV |
  64.                     SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXD1 |
  65.                     SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXD0 |
  66.                     SYS_GPC_MFPL_PC6MFP_EMAC_MII_TXD0 |
  67.                     SYS_GPC_MFPL_PC7MFP_EMAC_MII_TXD1;


  68.     SYS->GPC_MFPH = SYS_GPC_MFPH_PC8MFP_EMAC_MII_TXEN;
  69.     // Enable high slew rate on all RMII pins
  70.     PC->SLEWCTL |= 0x1DF;

  71.     // Configure MDC, MDIO at PB14 & PB15
  72.     SYS->GPB_MFPH = SYS_GPB_MFPH_PB14MFP_EMAC_MII_MDC | SYS_GPB_MFPH_PB15MFP_EMAC_MII_MDIO;

  73.     /* Lock protected registers */
  74.     SYS_LockReg();

  75. }

  76. // This sample application can response to ICMP ECHO packets (ping)
  77. // IP address is configure with DHCP, but if a lease cannot be acquired, a static IP will be used.
  78. int main(void)
  79. {
  80.         int i;
  81.         uip_ipaddr_t ipaddr;
  82.         struct timer periodic_timer, arp_timer;

  83.         timer_set(&periodic_timer, CLOCK_SECOND / 2);
  84.         timer_set(&arp_timer, CLOCK_SECOND * 10);

  85.         SYS_Init();
  86.         UART_Open(UART0, 115200);
  87.        
  88.         clock_init();
  89.         tapdev_init();
  90.         uip_init();

  91.         uip_ipaddr(ipaddr, 192,168,2,105);
  92.         uip_sethostaddr(ipaddr);
  93.         uip_ipaddr(ipaddr, 192,168,2,1);
  94.         uip_setdraddr(ipaddr);
  95.         uip_ipaddr(ipaddr, 255,255,255,0);
  96.         uip_setnetmask(ipaddr);
  97.         uip_setethaddr(ethaddr);
  98.         hello_world_init();
  99.     printf("NUC472 uIP sample code start\n");

  100.         while(1)
  101.         {
  102.                 uip_len = tapdev_read();
  103.                 if(uip_len > 0)
  104.                 {
  105.                         if(BUF->type == htons(UIP_ETHTYPE_IP))
  106.                         {
  107.                                 uip_arp_ipin();
  108.                                 uip_input();
  109.                                 /* If the above function invocation resulted in data that
  110.                                 should be sent out on the network, the global variable
  111.                                 uip_len is set to a value > 0. */
  112.                                 if(uip_len > 0)
  113.                                 {
  114.                                         uip_arp_out();
  115.                                         tapdev_send();
  116.                                 }
  117.                         }
  118.                         else if(BUF->type == htons(UIP_ETHTYPE_ARP))
  119.                         {
  120.                                 uip_arp_arpin();
  121.                                 /* If the above function invocation resulted in data that
  122.                                 should be sent out on the network, the global variable
  123.                                 uip_len is set to a value > 0. */
  124.                                 if(uip_len > 0)
  125.                                 {
  126.                                         tapdev_send();
  127.                                 }
  128.                         }
  129.                 }
  130.                 else if(timer_expired(&periodic_timer))
  131.                 {
  132.                         timer_reset(&periodic_timer);
  133.                         for(i = 0; i < UIP_CONNS; i++)
  134.                         {
  135.                                 uip_periodic(i);
  136.                                 /* If the above function invocation resulted in data that
  137.                                 should be sent out on the network, the global variable
  138.                                 uip_len is set to a value > 0. */
  139.                                 if(uip_len > 0)
  140.                                 {
  141.                                         uip_arp_out();
  142.                                         tapdev_send();
  143.                                 }
  144.                         }
  145.                 #if UIP_UDP
  146.                         for(i = 0; i < UIP_UDP_CONNS; i++)
  147.                         {
  148.                                 uip_udp_periodic(i);
  149.                                 /* If the above function invocation resulted in data that
  150.                                 should be sent out on the network, the global variable
  151.                                 uip_len is set to a value > 0. */
  152.                                 if(uip_len > 0)
  153.                                 {
  154.                                         uip_arp_out();
  155.                                         tapdev_send();
  156.                                 }
  157.                         }
  158.                 #endif /* UIP_UDP */

  159.                         /* Call the ARP timer function every 10 seconds. */
  160.                         if(timer_expired(&arp_timer))
  161.                         {
  162.                                 timer_reset(&arp_timer);
  163.                                 uip_arp_timer();
  164.                         }
  165.                 }
  166.         }
  167. }

  168. void
  169. uip_log(char *m)
  170. {
  171.   printf("uIP log message: %s\n", m);
  172. }

 楼主| dongnanxibei 发表于 2019-4-28 23:23 | 显示全部楼层
main()函数的流程比较简单,可以参考uip库中doc目录下的example-mainloop-with-arp.c和example-mainloop-without-arp.c,这里使用的example-mainloop-with-arp.c文件,在uip参考文件中有提到应用程序的流程说明。uip是使用查询法来检测是否需要发送数据以及是否有数据进来,因此在mainloop中不停的执行tapdev_read(),进而检测uip_len变量值,不为0则表明收到了数据,之后便调用uip协议栈对数据进行处理,处理完成之后再次检测uip_len变量查看是否需要发送数据,如果需要发送数据则调用tapdev_send()函数。整个流程还是比较简单的,而uip协议栈对数据的处理则需要一个UIP_APPCALL宏来实现,对于不同的应用需要实现不同的UIP_APPCALL,本例中是加载的hello-wolrd模块,因此UIP_APPCALL定义在了hello-world.h文件中,如下:
  1. /**
  2. * \addtogroup apps
  3. * @{
  4. */

  5. /**
  6. * \defgroup helloworld Hello, world
  7. * @{
  8. *
  9. * A small example showing how to write applications with
  10. * \ref psock "protosockets".
  11. */

  12. /**
  13. * \file
  14. *         Header file for an example of how to write uIP applications
  15. *         with protosockets.
  16. * \author
  17. *         Adam Dunkels <adam@sics.se>
  18. */

  19. #ifndef __HELLO_WORLD_H__
  20. #define __HELLO_WORLD_H__

  21. /* Since this file will be included by uip.h, we cannot include uip.h
  22.    here. But we might need to include uipopt.h if we need the u8_t and
  23.    u16_t datatypes. */
  24. #include "uipopt.h"

  25. #include "psock.h"

  26. /* Next, we define the uip_tcp_appstate_t datatype. This is the state
  27.    of our application, and the memory required for this state is
  28.    allocated together with each TCP connection. One application state
  29.    for each TCP connection. */
  30. typedef struct hello_world_state {
  31.   struct psock p;
  32.   char inputbuffer[10];
  33.   char name[40];
  34. } uip_tcp_appstate_t;

  35. /* Finally we define the application function to be called by uIP. */
  36. void hello_world_appcall(void);
  37. #ifndef UIP_APPCALL
  38. #define UIP_APPCALL hello_world_appcall
  39. #endif /* UIP_APPCALL */

  40. void hello_world_init(void);

  41. #endif /* __HELLO_WORLD_H__ */
  42. /** @} */
  43. /** @} */
 楼主| dongnanxibei 发表于 2019-4-28 23:23 | 显示全部楼层
在uip协议栈中会调用UIP_APPCALL处理数据,hello-world.c文件比较简单,如下:
  1. /**
  2. * \addtogroup helloworld
  3. * @{
  4. */

  5. /**
  6. * \file
  7. *         An example of how to write uIP applications
  8. *         with protosockets.
  9. * \author
  10. *         Adam Dunkels <adam@sics.se>
  11. */

  12. /*
  13. * This is a short example of how to write uIP applications using
  14. * protosockets.
  15. */

  16. /*
  17. * We define the application state (struct hello_world_state) in the
  18. * hello-world.h file, so we need to include it here. We also include
  19. * uip.h (since this cannot be included in hello-world.h) and
  20. * <string.h>, since we use the memcpy() function in the code.
  21. */
  22. #include "hello-world.h"
  23. #include "uip.h"
  24. #include <string.h>

  25. /*
  26. * Declaration of the protosocket function that handles the connection
  27. * (defined at the end of the code).
  28. */
  29. static int handle_connection(struct hello_world_state *s);
  30. /*---------------------------------------------------------------------------*/
  31. /*
  32. * The initialization function. We must explicitly call this function
  33. * from the system initialization code, some time after uip_init() is
  34. * called.
  35. */
  36. void
  37. hello_world_init(void)
  38. {
  39.   /* We start to listen for connections on TCP port 1000. */
  40.   uip_listen(HTONS(1000));
  41. }
  42. /*---------------------------------------------------------------------------*/
  43. /*
  44. * In hello-world.h we have defined the UIP_APPCALL macro to
  45. * hello_world_appcall so that this funcion is uIP's application
  46. * function. This function is called whenever an uIP event occurs
  47. * (e.g. when a new connection is established, new data arrives, sent
  48. * data is acknowledged, data needs to be retransmitted, etc.).
  49. */
  50. void
  51. hello_world_appcall(void)
  52. {
  53.   /*
  54.    * The uip_conn structure has a field called "appstate" that holds
  55.    * the application state of the connection. We make a pointer to
  56.    * this to access it easier.
  57.    */
  58.   struct hello_world_state *s = &(uip_conn->appstate);

  59.   /*
  60.    * If a new connection was just established, we should initialize
  61.    * the protosocket in our applications' state structure.
  62.    */
  63.   if(uip_connected()) {
  64.     PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer));
  65.   }

  66.   /*
  67.    * Finally, we run the protosocket function that actually handles
  68.    * the communication. We pass it a pointer to the application state
  69.    * of the current connection.
  70.    */
  71.   handle_connection(s);
  72. }
  73. /*---------------------------------------------------------------------------*/
  74. /*
  75. * This is the protosocket function that handles the communication. A
  76. * protosocket function must always return an int, but must never
  77. * explicitly return - all return statements are hidden in the PSOCK
  78. * macros.
  79. */
  80. static int
  81. handle_connection(struct hello_world_state *s)
  82. {
  83.   PSOCK_BEGIN(&s->p);

  84.   PSOCK_SEND_STR(&s->p, "Hello. What is your name?\n");
  85.   PSOCK_READTO(&s->p, '\n');
  86.   strncpy(s->name, s->inputbuffer, sizeof(s->name));
  87.   PSOCK_SEND_STR(&s->p, "Hello ");
  88.   PSOCK_SEND_STR(&s->p, s->name);
  89.   PSOCK_CLOSE(&s->p);
  90.   
  91.   PSOCK_END(&s->p);
  92. }

 楼主| dongnanxibei 发表于 2019-4-28 23:26 | 显示全部楼层
功能比较简单就是检测是否有tcp连接到来,如果有连接到来则发送一条消息"Hello, What is your name?\n",之后便等待对方的回应,收到回应后输出"Hello " + "用户名"。编译代码并下载到目标板中运行,我们需要一个tcp调试工具来辅助我们查看运行结果,这里是使用的USR-TCP232-Test-V1.3软件,因为源代码中用户的回应必须要以‘\n’结束,而该工具刚好提供了一个自动发送附加位的选项,
720155cc5c5a6145c7.png
在该软件中设置完协议类型、服务器地址以及端口号之后,点击连接之后,便会收到服务器发来的提示信息,如下:
746675cc5c5bc9801c.png
在发送窗口发送数据之后便会再次收到服务器的响应信息,并断开连接,如下:
733665cc5c5d38c64f.png
此时需要注意的是用户的输入信息不能过长,因为在hello_world_state结构中inputbuffer只有10个字节,最后贴一张工程目录图,不是所有的uip源代码都参与了编译,有一些文件我们没有用到,如下:
618515cc5c5ec0bae0.png

至此,NUC472上uip-1.0协议栈的移植就结束了,剩下的就是对该源码的接口的熟悉了,我们只需要对uip协议栈的接口熟悉就可以编写好代码了,至于其内部的实现有兴趣的话可以深入了解一下,而在uip-1.0源码中提供了一个protosock接口这个是值得一看的,protosock是立足于protothreads,这又是作者编写的另外一个有趣的开源项目,目前最新版本是pt-1.4。protothreads其实是使用了C语言switch语句的特性,

pt官网:http://dunkels.com/adam/pt/index.html

pt中用到的C语言switch语句特性可以在以下网址中查看:http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

这种用法很少有人这么用,我们在编写带操作系统的应用时,一个任务就是一个线程,而我们要求任务调度线程时有这么一个特性:线程切走后在恢复时必须从上次切走的地方继续运行,即记录上次的断点把运行状态入栈,下次进来时重新恢复现场。而pt很巧妙的利用switch语句以及Duff's Device实现了断点续运行,并且不需要压栈入栈,很适合在资源较少的平台上使用。推荐大家去官网上看下这两个项目,足可以大开眼界。当然在现在32位单片机的普及很少会遇到资源不足的情况了,但是了解这么一种编程观点还是很有帮助的。
wanduzi 发表于 2019-4-29 11:31 | 显示全部楼层
网络通信?
zhuomuniao110 发表于 2019-4-29 14:09 | 显示全部楼层
看起来不难的样子。
dontium 发表于 2019-5-11 17:44 | 显示全部楼层
写得不错、我也试试uIP
 楼主| dongnanxibei 发表于 2019-5-12 22:28 | 显示全部楼层
好资料,通俗易懂。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

225

主题

3848

帖子

18

粉丝
快速回复 在线客服 返回列表 返回顶部