试验原因

产品板子上用的LWIP版本较旧,这次准备换成现在官方最新的lwip-2.1.2.
想重新作lwip移植的原因 : 产品板子有bug与lwip相关,应该是以前程序移植的lwip有问题(配置和使用lwip).
正好这次放长假, 仔细研究一下lwip的移植, 配置,使用,调试。

lwip中带调试日志,可以通过ITM打印到MDK的调试窗口或用串口打印到PC端的串口助手上, 这样再遇到lwip使用问题, 就可以根据具体的lwip报错信息来调整程序逻辑。

想在ucosii上作lwip移植, 先作裸机移植.
stm32f1裸机移植lwip-2.1.2的试验已经作完,记录一下。

移植好的工程(stm32f1 + spl lib + lwip-2.1.2 + enc28j60)

my_STM32F10x_StdPeriph_Template_FD_LWIP.zip

试验

lwip下载地址 : http://download.savannah.nongnu.org/releases/lwip/

lwip工程包含2个部分(lwip-2.1.2.zip + contrib-2.1.0.zip)
lwip-2.1.2.zip 是官方代码, 是lwip库实现。
contrib-2.1.0.zip 是大家贡献的代码, 可以看到移植,配置, 使用lwip的demo工程。
在这里插入图片描述

另外要准备一份最后版本的sys_arch.txt, 这个文件是官方对移植lwip的指南,但是在最新lwip版本中已经折腾没了(分散合并到了lwip工程中去了, 对新手特别不友好), 我从lwip git历史中找出了最后版本的sys_arch.txt, 整理了一份 (lwip-2.1.2 sys_arch.txt was deleted)

如果没有sys_arch.txt的指南, 新手根本不知道咋移植lwip到自己的工程, 开源工程最重要的是文档, 要不新手咋用啊。

lwip在stm32f1(SPL固件库)的移植,可以从自己准备的一个干净的SPL库模板上开始。
我整理了一份(STM32F10x_StdPeriph_Template)

移植完的工程目录概览

在这里插入图片描述
蓝色框部分是固件库模板工程原有的目录。
红色框部分是lwip移植的代码。

lwip的移植分为4部分:

  • lwip原始实现直接拷贝过来,不用改的部分
  • 从lwip-2.1.2和contrib-2.1.0实现拷贝过来,需要改的部分
  • 网卡控制器实现
  • 用户层代码

lwip移植相关的目录概览

lwip原始实现直接拷贝过来,不用改的部分

.h是不用移植的,拷贝到工程只是为了看的方便。

lwip/core <= \lwip-2.1.2\src\core (.c)
在这里插入图片描述
lwip/core/ipv4 <= lwip-2.1.2\src\core\ipv4 (
.c)
在这里插入图片描述
lwip/netif <= lwip-2.1.2\src\netif (.c), 子目录ppp不用拷贝(因为我移植完,是要实现一个http片上服务器, 如果你要实现点对点通讯,根据情况拷贝过来)
在这里插入图片描述
lwip/hdr <= D:\ls\STM32\LWIP_zhu_sheng_lin\doc\lwip-2.1.2\src\include\lwip(
.h)

在这里插入图片描述
在这里插入图片描述
lwip/hdr/port <= lwip-2.1.2\src\include\lwip\prot(.h)
在这里插入图片描述
lwip/hdr/netif <= lwip-2.1.2\src\include\netif(
.h)
在这里插入图片描述

从lwip-2.1.2和contrib-2.1.0实现拷贝过来,需要改的部分

在这里插入图片描述
cc.h <= contrib-2.1.0\ports\win32\include\arch
lwipopts.h <= contrib-2.1.0\examples\example_app
sys_arch.c <= contrib-2.1.0\ports\win32
bpstruct.h <= contrib-2.1.0\ports\win32\include\arch
epstruct.h <= contrib-2.1.0\ports\win32\include\arch
ppp_settings.h <= contrib-2.1.0\examples\example_app
sys_arch.h <= contrib-2.1.0\ports\win32\include\arch
ethernetif.c <= contrib-2.1.0\examples\ethernetif

网卡控制器实现

在这里插入图片描述
spi.c/spi.h/enc28j60.c/enc28j60.h 都是找的现成的enc28j60网卡控制器驱动, 因为我手头的开发板用的是enc28j60, 就直接从开发板厂商提供的例子中,将驱动拷贝出来。

我们产品板子上用的LAN8720, 那我后续试验,就将LAN8720驱动拷贝过来就行。

my_nic.c/my_nic.h 是对网卡控制器驱动接口的封装, 因为只要不是从0开始,驱动都是现成的,拷贝过来就行。

为了不用改驱动(维护方便,换网卡驱动时,不用动驱动本身), 应该将对驱动的操作封装成接口,实现网卡初始化,网卡发送,网卡接收,和其他一些网卡逻辑操作。

用户层代码

在这里插入图片描述
用户层代码,用来调用my_nic.h 中定义的网卡驱动初始化接口, 然后启动网卡处理流程(查询方式或中断方式)

LWIP移植的细节

LWIP移植相关文件的修改

cc.h

/** Copyright (c) 2001-2003 Swedish Institute of Computer Science.* All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE.** This file is part of the lwIP TCP/IP stack.* * Author: Adam Dunkels <adam@sics.se>**/
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H#ifdef _MSC_VER
#pragma warning (disable: 4127) /* conditional expression is constant */
#pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */
#pragma warning (disable: 4103) /* structure packing changed by including file */
#pragma warning (disable: 4820) /* 'x' bytes padding added after data member 'y' */
#pragma warning (disable: 4711) /* The compiler performed inlining on the given function, although it was not marked for inlining */
#endif// \lwip\include\lwip\arch.h(48) : #include "arch/cc.h"
#ifndef LWIP_PROVIDE_ERRNO
#define LWIP_PROVIDE_ERRNO // 提供LWIP底层错误号, 如果报错,能看到具体错误是啥
#endif // #ifndef LWIP_PROVIDE_ERRNO// \lwip\include\lwip\arch.h 中定义了lwip自己的数据类型 e.g. u8_t, 不用在这里定义
// typedef uint8_t   u8_t; // on \lwip\arch.h// 结构体对齐的内存定义
// PACK_STRUCT_BEGIN 和 PACK_STRUCT_STRUCT 定义一个就行,但是定义了哪个就要使用哪个
// 或者定义结构时如下
/*
PACK_STRUCT_BEGIN
typedef struct _tag_info {PACK_STRUCT_FIELD(u8_t c1);PACK_STRUCT_FIELD(u32_t u1);
} TAG_INFO PACK_STRUCT_STRUCT;
PACK_STRUCT_END
*/// 结构体内存字节对齐相关宏// 结构体定义前的包含
#ifndef PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
#endif /* PACK_STRUCT_BEGIN */// 结构体定义后的包含
#ifndef PACK_STRUCT_END
#define PACK_STRUCT_END
#endif /* PACK_STRUCT_END */// 结构体定义时的字节对齐
#ifndef PACK_STRUCT_STRUCT
#define PACK_STRUCT_STRUCT __attribute__((packed)) // 1字节对齐
#endif /* PACK_STRUCT_STRUCT */// 结构体字段定义的内存对齐
#ifndef PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x) x
#endif /* PACK_STRUCT_FIELD *//* Define an example for LWIP_PLATFORM_DIAG: since this uses varargs and the old* C standard lwIP targets does not support this in macros, we have extra brackets* around the arguments, which are left out in the following macro definition:*/// 自己提供lwip提示信息处理函数
void lwip_stm32_platform_diag(const char *format, ...);
#define LWIP_PLATFORM_DIAG(x) lwip_stm32_platform_diag x// lwip断言信息处理函数
#ifndef LWIP_PLATFORM_ASSERT
void lwip_stm32_platform_assert(const char *format, ...);
#endif// lwip错误处理函数, 可以将打印那句改成自己的错误处理函数
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \fflush(NULL);handler;} } while(0)/* Define platform endianness (might already be defined) */
// 网卡数据接收发送都是小端格式的数据
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif /* BYTE_ORDER */typedef int sys_prot_t;#ifdef _MSC_VER
/* define _INTPTR for Win32 MSVC stdint.h */
#define _INTPTR 2/* Do not use lwIP default definitions for format strings * because these do not work with MSVC 2010 compiler (no inttypes.h)*/
#define LWIP_NO_INTTYPES_H 1/* Define (sn)printf formatters for these lwIP types */
// 告诉lwip数据格式化时的选项 e.g. printf("%" X8_F "\n", uc_dat); => printf("%02x\n", uc_dat);
#define X8_F  "02x"
#define U16_F "hu"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"#define S16_F "hd"
#define X16_F "hx"
#define SZT_F "lu"
#endif /* _MSC_VER *//* Compiler hints for packing structures */
// 是否使用 #pragma pack(push,1)/#pragma pack(pop) 来包裹其他实现来实现1字节对齐
// 看lwip实现, 就是将#pragma pack(push,1) 定义在 bpstruct.h
// #pragma pack(pop) 定义在 epstruct.h
// 然后根据PACK_STRUCT_USE_INCLUDES 包上这2个头文件(bpstruct.h/epstruct.h)
#define PACK_STRUCT_USE_INCLUDES#ifdef _MSC_VER
/* C runtime functions redefined */
#if _MSC_VER < 1910
#define snprintf _snprintf
#endif
#define strdup   _strdup
#endif// 如果定义了LWIP_NORAND, 需要自己提供随机数发生器
#ifndef LWIP_NORAND
extern unsigned int sys_win_rand(void);
#define LWIP_RAND() (sys_win_rand())
#endif#define PPP_INCLUDE_SETTINGS_HEADER#endif /* LWIP_ARCH_CC_H */

lwipopts.h

这个文件是配置文件, 在自己工程中,根据实际情况(片上内存的剩余量),可以调整这个配置文件, 来微调lwip的性能。参数需要调成啥,要根据自己板子的实际情况来。如果微调的不合适,可以通过打印出的lwip底层日志看问题出在哪.

e.g.
是否要打印日志?
日志级别?
是否响应ipv6?
内存预分配多大?
最多要响应多少个网络连接?

如果不是特殊要求,默认的配置就能工作的很好。

/** Copyright (c) 2001-2003 Swedish Institute of Computer Science.* All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE.** This file is part of the lwIP TCP/IP stack.* * Author: Adam Dunkels <adam@sics.se>**/
#ifndef LWIP_LWIPOPTS_H
#define LWIP_LWIPOPTS_H#ifdef LWIP_OPTTEST_FILE
#include "lwipopts_test.h"
#else /* LWIP_OPTTEST_FILE */// 网络通讯包是IPV4还是IPV6?
#define LWIP_IPV4                  1
// #define LWIP_IPV6                  1// 是否有系统,如果有系统,就要提供一些同步函数
#define NO_SYS                     1 // 无系统 = 1, 有系统 = 0
#define LWIP_SOCKET                (NO_SYS==0)
#define LWIP_NETCONN               (NO_SYS==0)
#define LWIP_NETIF_API             (NO_SYS==0)#define LWIP_IGMP                  LWIP_IPV4
#define LWIP_ICMP                  LWIP_IPV4#define LWIP_SNMP                  LWIP_UDP
#define MIB2_STATS                 LWIP_SNMP
#ifdef LWIP_HAVE_MBEDTLS
#define LWIP_SNMP_V3               (LWIP_SNMP)
#endif#define LWIP_DNS                   LWIP_UDP
#define LWIP_MDNS_RESPONDER        LWIP_UDP#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER)#define LWIP_HAVE_LOOPIF           1
#define LWIP_NETIF_LOOPBACK        1
#define LWIP_LOOPBACK_MAX_PBUFS    10#define TCP_LISTEN_BACKLOG         1#define LWIP_COMPAT_SOCKETS        1
#define LWIP_SO_RCVTIMEO           1
#define LWIP_SO_RCVBUF             1#define LWIP_TCPIP_CORE_LOCKING    1// 在网络通讯时,是否使用回调
#define LWIP_NETIF_LINK_CALLBACK        1
#define LWIP_NETIF_STATUS_CALLBACK      1
#define LWIP_NETIF_EXT_STATUS_CALLBACK  1// 调试模式定义, 可以打印调试信息
// LWIP_DEBUG + LWIP_DBG_MIN_LEVEL + X_DEBUG 就可以决定打印出哪种类别(e.g. ICMP or TCP or IP)的哪种严重程度的日志(所有, 警告, 一般错误, 严重错误)
#if !defined(LWIP_DEBUG)
#define LWIP_DEBUG
#endif#ifdef LWIP_DEBUG// 日志级别
//  /** Debug level: ALL messages*/
//  #define LWIP_DBG_LEVEL_ALL     0x00 // 所有
//  /** Debug level: Warnings. bad checksums, dropped packets, ... */
//  #define LWIP_DBG_LEVEL_WARNING 0x01 // 警告
//  /** Debug level: Serious. memory allocation failures, ... */
//  #define LWIP_DBG_LEVEL_SERIOUS 0x02 // 一般错误
//  /** Debug level: Severe */
//  #define LWIP_DBG_LEVEL_SEVERE  0x03 // 严重错误// LWIP_DBG_MIN_LEVEL 设置的范围如上 : LWIP_DBG_LEVEL_ALL ~ LWIP_DBG_LEVEL_SEVERE// 如果LWIP_DBG_MIN_LEVEL不设置为LWIP_DBG_LEVEL_ALL, 那正常运行时,是看不到LWIP日志的
#define LWIP_DBG_MIN_LEVEL         LWIP_DBG_LEVEL_ALL// 日志种类
// value range : LWIP_DBG_OFF/LWIP_DBG_ON
// 要打印哪种类型的通讯调试信息,就将下面的宏改为LWIP_DBG_ON,不要调试信息为LWIP_DBG_OFF
#define PPP_DEBUG                  LWIP_DBG_ON
#define MEM_DEBUG                  LWIP_DBG_ON
#define MEMP_DEBUG                 LWIP_DBG_ON
#define PBUF_DEBUG                 LWIP_DBG_ON
#define API_LIB_DEBUG              LWIP_DBG_ON
#define API_MSG_DEBUG              LWIP_DBG_ON
#define TCPIP_DEBUG                LWIP_DBG_ON
#define NETIF_DEBUG                LWIP_DBG_ON
#define SOCKETS_DEBUG              LWIP_DBG_ON
#define DNS_DEBUG                  LWIP_DBG_ON
#define AUTOIP_DEBUG               LWIP_DBG_ON
#define DHCP_DEBUG                 LWIP_DBG_ON
#define IP_DEBUG                   LWIP_DBG_ON
#define IP_REASS_DEBUG             LWIP_DBG_ON
#define ICMP_DEBUG                 LWIP_DBG_ON
#define IGMP_DEBUG                 LWIP_DBG_ON
#define UDP_DEBUG                  LWIP_DBG_ON
#define TCP_DEBUG                  LWIP_DBG_ON
#define TCP_INPUT_DEBUG            LWIP_DBG_ON
#define TCP_OUTPUT_DEBUG           LWIP_DBG_ON
#define TCP_RTO_DEBUG              LWIP_DBG_ON
#define TCP_CWND_DEBUG             LWIP_DBG_ON
#define TCP_WND_DEBUG              LWIP_DBG_ON
#define TCP_FR_DEBUG               LWIP_DBG_ON
#define TCP_QLEN_DEBUG             LWIP_DBG_ON
#define TCP_RST_DEBUG              LWIP_DBG_ON
#endif#define LWIP_DBG_TYPES_ON         (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT)/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for whichlwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2byte alignment -> define MEM_ALIGNMENT to 2. */
/* MSVC port: intel processors don't need 4-byte alignment,but are faster that way! */
#define MEM_ALIGNMENT           4U/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE               10240/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the applicationsends a lot of data out of ROM (or other static memory), thisshould be set high. */
#define MEMP_NUM_PBUF           16
/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. Oneper active RAW "connection". */
#define MEMP_NUM_RAW_PCB        3
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. Oneper active UDP "connection". */
#define MEMP_NUM_UDP_PCB        4
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCPconnections. */
#define MEMP_NUM_TCP_PCB        5
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCPconnections. */
#define MEMP_NUM_TCP_PCB_LISTEN 8
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCPsegments. */
#define MEMP_NUM_TCP_SEG        16
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously activetimeouts. */
#define MEMP_NUM_SYS_TIMEOUT    17/* The following four are used only with the sequential API and can beset to 0 if the application only will use the raw API. */
/* MEMP_NUM_NETBUF: the number of struct netbufs. */
#define MEMP_NUM_NETBUF         2
/* MEMP_NUM_NETCONN: the number of struct netconns. */
#define MEMP_NUM_NETCONN        10
/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is usedfor sequential API communication and incoming packets. Used insrc/api/tcpip.c. */
#define MEMP_NUM_TCPIP_MSG_API   16
#define MEMP_NUM_TCPIP_MSG_INPKT 16/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE          120/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE       256/** SYS_LIGHTWEIGHT_PROT* define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection* for certain critical regions during buffer allocation, deallocation and memory* allocation and deallocation.*/
#define SYS_LIGHTWEIGHT_PROT    (NO_SYS==0)/* ---------- TCP options ---------- */
#define LWIP_TCP                1
#define TCP_TTL                 255#define LWIP_ALTCP              (LWIP_TCP)
#ifdef LWIP_HAVE_MBEDTLS
#define LWIP_ALTCP_TLS          (LWIP_TCP)
#define LWIP_ALTCP_TLS_MBEDTLS  (LWIP_TCP)
#endif/* Controls if TCP should queue segments that arrive out oforder. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ         1/* TCP Maximum segment size. */
#define TCP_MSS                 1024/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF             2048/* TCP sender buffer space (pbufs). This must be at least = 2 *TCP_SND_BUF/TCP_MSS for things to work. */
#define TCP_SND_QUEUELEN       (4 * TCP_SND_BUF/TCP_MSS)/* TCP writable space (bytes). This must be less than or equalto TCP_SND_BUF. It is the amount of space which must beavailable in the tcp snd_buf for select to return writable */
#define TCP_SNDLOWAT           (TCP_SND_BUF/2)/* TCP receive window. */
#define TCP_WND                 (20 * 1024)/* Maximum number of retransmissions of data segments. */
#define TCP_MAXRTX              12/* Maximum number of retransmissions of SYN segments. */
#define TCP_SYNMAXRTX           4/* ---------- ARP options ---------- */
#define LWIP_ARP                1
#define ARP_TABLE_SIZE          10
#define ARP_QUEUEING            1/* ---------- IP options ---------- */
/* Define IP_FORWARD to 1 if you wish to have the ability to forwardIP packets across network interfaces. If you are going to run lwIPon a device with only one network interface, define this to 0. */
#define IP_FORWARD              1/* IP reassembly and segmentation.These are orthogonal even* if they both deal with IP fragments */
#define IP_REASSEMBLY           1
#define IP_REASS_MAX_PBUFS      (10 * ((1500 + PBUF_POOL_BUFSIZE - 1) / PBUF_POOL_BUFSIZE))
#define MEMP_NUM_REASSDATA      IP_REASS_MAX_PBUFS
#define IP_FRAG                 1
#define IPV6_FRAG_COPYHEADER    1/* ---------- ICMP options ---------- */
#define ICMP_TTL                255/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration ofinterfaces. */
#define LWIP_DHCP               LWIP_UDP/* 1 if you want to do an ARP check on the offered address(recommended). */
#define DHCP_DOES_ARP_CHECK    (LWIP_DHCP)/* ---------- AUTOIP options ------- */
#define LWIP_AUTOIP            (LWIP_DHCP)
#define LWIP_DHCP_AUTOIP_COOP  (LWIP_DHCP && LWIP_AUTOIP)/* ---------- UDP options ---------- */
#define LWIP_UDP                1
#define LWIP_UDPLITE            LWIP_UDP
#define UDP_TTL                 255/* ---------- RAW options ---------- */
#define LWIP_RAW                1/* ---------- Statistics options ---------- */#define LWIP_STATS              1
#define LWIP_STATS_DISPLAY      1#if LWIP_STATS
#define LINK_STATS              1
#define IP_STATS                1
#define ICMP_STATS              1
#define IGMP_STATS              1
#define IPFRAG_STATS            1
#define UDP_STATS               1
#define TCP_STATS               1
#define MEM_STATS               1
#define MEMP_STATS              1
#define PBUF_STATS              1
#define SYS_STATS               1
#endif /* LWIP_STATS *//* ---------- NETBIOS options ---------- */
#define LWIP_NETBIOS_RESPOND_NAME_QUERY 1/* ---------- PPP options ---------- */// #define PPP_SUPPORT             1      /* Set > 0 for PPP */#if PPP_SUPPORT#define NUM_PPP                 1      /* Max PPP sessions. *//* Select modules to enable.  Ideally these would be set in the makefile but* we're limited by the command line length so you need to modify the settings* in this file.*/
#define PPPOE_SUPPORT           1
#define PPPOS_SUPPORT           1#define PAP_SUPPORT             1      /* Set > 0 for PAP. */
#define CHAP_SUPPORT            1      /* Set > 0 for CHAP. */
#define MSCHAP_SUPPORT          0      /* Set > 0 for MSCHAP */
#define CBCP_SUPPORT            0      /* Set > 0 for CBCP (NOT FUNCTIONAL!) */
#define CCP_SUPPORT             0      /* Set > 0 for CCP */
#define VJ_SUPPORT              1      /* Set > 0 for VJ header compression. */
#define MD5_SUPPORT             1      /* Set > 0 for MD5 (see also CHAP) */#endif /* PPP_SUPPORT */#endif /* LWIP_OPTTEST_FILE *//* The following defines must be done even in OPTTEST mode: */#if !defined(NO_SYS) || !NO_SYS /* default is 0 */
void sys_check_core_locking(void);
#define LWIP_ASSERT_CORE_LOCKED()  sys_check_core_locking()
void sys_mark_tcpip_thread(void);
#define LWIP_MARK_TCPIP_THREAD()   sys_mark_tcpip_thread()#if !defined(LWIP_TCPIP_CORE_LOCKING) || LWIP_TCPIP_CORE_LOCKING /* default is 1 */
void sys_lock_tcpip_core(void);
#define LOCK_TCPIP_CORE()          sys_lock_tcpip_core()
void sys_unlock_tcpip_core(void);
#define UNLOCK_TCPIP_CORE()        sys_unlock_tcpip_core()
#endif
#endif#endif /* LWIP_LWIPOPTS_H */

sys_arch.c

提供一些lwip要求的函数
被注释掉的函数是贡献者代码中提供的带操作系统相关的函数。
如果带了操作系统, 编译不过时,缺哪个函数就实现哪个函数。

/** Copyright (c) 2001-2003 Swedish Institute of Computer Science.* All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE.** This file is part of the lwIP TCP/IP stack.* * Author: Adam Dunkels <adam@sics.se>*         Simon Goldschmidt**/#include "main.h"#include <stdlib.h>
#include <stdio.h> /* sprintf() for task names */#ifdef _MSC_VER
#pragma warning (push, 3)
#endif
// #include <windows.h>
#ifdef _MSC_VER
#pragma warning (pop)
#endif
#include <time.h>#include <lwip/opt.h>
#include <lwip/arch.h>
#include <lwip/stats.h>
#include <lwip/debug.h>
#include <lwip/sys.h>
#include <lwip/tcpip.h>
#include <lwip/err.h>//  /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is only
//   * called once in a call stack (calling it nested might cause trouble in some
//   * implementations, so let's avoid this in core code as long as we can).
//   */
//  #ifndef LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
//  #define LWIP_SYS_ARCH_CHECK_NESTED_PROTECT 1
//  #endif//  /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is *not*
//   * called before functions potentiolly involving the OS scheduler.
//   *
//   * This scheme is currently broken only for non-core-locking when waking up
//   * threads waiting on a socket via select/poll.
//   */
//  #ifndef LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED
//  #define LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED LWIP_TCPIP_CORE_LOCKING
//  #endif//  #define LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER (LWIP_SYS_ARCH_CHECK_NESTED_PROTECT || LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED)//  /* These functions are used from NO_SYS also, for precise timer triggering */
//  static LARGE_INTEGER freq, sys_start_time;
//  #define SYS_INITIALIZED() (freq.QuadPart != 0)//  static DWORD netconn_sem_tls_index;//  static HCRYPTPROV hcrypt;//  u32_t
//  sys_win_rand(void)
//  {
//    u32_t ret;
//    if (CryptGenRandom(hcrypt, sizeof(ret), (BYTE*)&ret)) {
//      return ret;
//    }
//    LWIP_ASSERT("CryptGenRandom failed", 0);
//    return 0;
//  }extern int g_i_tick_cnt;// lwip需要的随机数发生器,根据需要实现。
unsigned int sys_win_rand(void)
{// 产生随机数的函数// @todo by lsreturn 0;
}//  static void
//  sys_win_rand_init(void)
//  {
//    if (!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, 0)) {
//      DWORD err = GetLastError();
//      LWIP_PLATFORM_DIAG(("CryptAcquireContext failed with error %d, trying to create NEWKEYSET", (int)err));
//      if(!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
//        char errbuf[128];
//        err = GetLastError();
//        snprintf(errbuf, sizeof(errbuf), "CryptAcquireContext failed with error %d", (int)err);
//        LWIP_UNUSED_ARG(err);
//        LWIP_ASSERT(errbuf, 0);
//      }
//    }
//  }//  static void
//  sys_init_timing(void)
//  {
//    QueryPerformanceFrequency(&freq);
//    QueryPerformanceCounter(&sys_start_time);
//  }//  static LONGLONG
//  sys_get_ms_longlong(void)
//  {
//    LONGLONG ret;
//    LARGE_INTEGER now;
//  #if NO_SYS
//    if (!SYS_INITIALIZED()) {
//      sys_init();
//      LWIP_ASSERT("initialization failed", SYS_INITIALIZED());
//    }
//  #endif /* NO_SYS */
//    QueryPerformanceCounter(&now);
//    ret = now.QuadPart-sys_start_time.QuadPart;
//    return (u32_t)(((ret)*1000)/freq.QuadPart);
//  }//  u32_t
//  sys_jiffies(void)
//  {
//    return (u32_t)sys_get_ms_longlong();
//  }//  u32_t
//  sys_now(void)
//  {
//    return (u32_t)sys_get_ms_longlong();
//  }// 提供系统时间
// 现在用的是时钟tick, 每ms发生一次的tick
u32_t sys_now(void)
{// 提供当前的tick// @note by lsreturn g_i_tick_cnt;
}//  CRITICAL_SECTION critSec;
//  #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
//  static int protection_depth;
//  #endif//  static void
//  InitSysArchProtect(void)
//  {
//    InitializeCriticalSection(&critSec);
//  }//  sys_prot_t
//  sys_arch_protect(void)
//  {
//  #if NO_SYS
//    if (!SYS_INITIALIZED()) {
//      sys_init();
//      LWIP_ASSERT("initialization failed", SYS_INITIALIZED());
//    }
//  #endif
//    EnterCriticalSection(&critSec);
//  #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
//    LWIP_ASSERT("nested SYS_ARCH_PROTECT", protection_depth == 0);
//  #endif
//  #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
//    protection_depth++;
//  #endif
//    return 0;
//  }//  void
//  sys_arch_unprotect(sys_prot_t pval)
//  {
//    LWIP_UNUSED_ARG(pval);
//  #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
//    LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth == 1);
//  #else
//    LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth > 0);
//  #endif
//  #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
//    protection_depth--;
//  #endif
//    LeaveCriticalSection(&critSec);
//  }//  #if LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED
//  /** This checks that SYS_ARCH_PROTECT() hasn't been called by protecting
//   * and then checking the level
//   */
//  static void
//  sys_arch_check_not_protected(void)
//  {
//    sys_arch_protect();
//    LWIP_ASSERT("SYS_ARCH_PROTECT before scheduling", protection_depth == 1);
//    sys_arch_unprotect(0);
//  }
//  #else
//  #define sys_arch_check_not_protected()
//  #endif//  static void
//  msvc_sys_init(void)
//  {
//    sys_win_rand_init();
//    sys_init_timing();
//    InitSysArchProtect();
//    netconn_sem_tls_index = TlsAlloc();
//    LWIP_ASSERT("TlsAlloc failed", netconn_sem_tls_index != TLS_OUT_OF_INDEXES);
//  }//  void
//  sys_init(void)
//  {
//    msvc_sys_init();
//  }//  #if !NO_SYS//  struct threadlist {
//    lwip_thread_fn function;
//    void *arg;
//    DWORD id;
//    struct threadlist *next;
//  };//  static struct threadlist *lwip_win32_threads = NULL;//  err_t
//  sys_sem_new(sys_sem_t *sem, u8_t count)
//  {
//    HANDLE new_sem = NULL;//    LWIP_ASSERT("sem != NULL", sem != NULL);//    new_sem = CreateSemaphore(0, count, 100000, 0);
//    LWIP_ASSERT("Error creating semaphore", new_sem != NULL);
//    if(new_sem != NULL) {
//      if (SYS_INITIALIZED()) {
//        SYS_ARCH_LOCKED(SYS_STATS_INC_USED(sem));
//      } else {
//        SYS_STATS_INC_USED(sem);
//      }
//  #if LWIP_STATS && SYS_STATS
//      LWIP_ASSERT("sys_sem_new() counter overflow", lwip_stats.sys.sem.used != 0);
//  #endif /* LWIP_STATS && SYS_STATS*/
//      sem->sem = new_sem;
//      return ERR_OK;
//    }
//     
//    /* failed to allocate memory... */
//    if (SYS_INITIALIZED()) {
//      SYS_ARCH_LOCKED(SYS_STATS_INC(sem.err));
//    } else {
//      SYS_STATS_INC(sem.err);
//    }
//    sem->sem = NULL;
//    return ERR_MEM;
//  }//  void
//  sys_sem_free(sys_sem_t *sem)
//  {
//    /* parameter check */
//    LWIP_ASSERT("sem != NULL", sem != NULL);
//    LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
//    LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
//    CloseHandle(sem->sem);//    SYS_ARCH_LOCKED(SYS_STATS_DEC(sem.used));
//  #if LWIP_STATS && SYS_STATS
//    LWIP_ASSERT("sys_sem_free() closed more than created", lwip_stats.sys.sem.used != (u16_t)-1);
//  #endif /* LWIP_STATS && SYS_STATS */
//    sem->sem = NULL;
//  }//  u32_t
//  sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
//  {
//    DWORD ret;
//    LONGLONG starttime, endtime;
//    LWIP_ASSERT("sem != NULL", sem != NULL);
//    LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
//    LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
//    if (!timeout) {
//      /* wait infinite */
//      starttime = sys_get_ms_longlong();
//      ret = WaitForSingleObject(sem->sem, INFINITE);
//      LWIP_ASSERT("Error waiting for semaphore", ret == WAIT_OBJECT_0);
//      endtime = sys_get_ms_longlong();
//      /* return the time we waited for the sem */
//      return (u32_t)(endtime - starttime);
//    } else {
//      starttime = sys_get_ms_longlong();
//      ret = WaitForSingleObject(sem->sem, timeout);
//      LWIP_ASSERT("Error waiting for semaphore", (ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT));
//      if (ret == WAIT_OBJECT_0) {
//        endtime = sys_get_ms_longlong();
//        /* return the time we waited for the sem */
//        return (u32_t)(endtime - starttime);
//      } else {
//        /* timeout */
//        return SYS_ARCH_TIMEOUT;
//      }
//    }
//  }//  void
//  sys_sem_signal(sys_sem_t *sem)
//  {
//    BOOL ret;
//    sys_arch_check_not_protected();
//    LWIP_ASSERT("sem != NULL", sem != NULL);
//    LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
//    LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
//    ret = ReleaseSemaphore(sem->sem, 1, NULL);
//    LWIP_ASSERT("Error releasing semaphore", ret != 0);
//    LWIP_UNUSED_ARG(ret);
//  }//  err_t
//  sys_mutex_new(sys_mutex_t *mutex)
//  {
//    HANDLE new_mut = NULL;//    LWIP_ASSERT("mutex != NULL", mutex != NULL);//    new_mut = CreateMutex(NULL, FALSE, NULL);
//    LWIP_ASSERT("Error creating mutex", new_mut != NULL);
//    if (new_mut != NULL) {
//      SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mutex));
//  #if LWIP_STATS && SYS_STATS
//      LWIP_ASSERT("sys_mutex_new() counter overflow", lwip_stats.sys.mutex.used != 0);
//  #endif /* LWIP_STATS && SYS_STATS*/
//      mutex->mut = new_mut;
//      return ERR_OK;
//    }
//     
//    /* failed to allocate memory... */
//    SYS_ARCH_LOCKED(SYS_STATS_INC(mutex.err));
//    mutex->mut = NULL;
//    return ERR_MEM;
//  }//  void
//  sys_mutex_free(sys_mutex_t *mutex)
//  {
//    /* parameter check */
//    LWIP_ASSERT("mutex != NULL", mutex != NULL);
//    LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
//    LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
//    CloseHandle(mutex->mut);//    SYS_ARCH_LOCKED(SYS_STATS_DEC(mutex.used));
//  #if LWIP_STATS && SYS_STATS
//    LWIP_ASSERT("sys_mutex_free() closed more than created", lwip_stats.sys.mutex.used != (u16_t)-1);
//  #endif /* LWIP_STATS && SYS_STATS */
//    mutex->mut = NULL;
//  }//  void sys_mutex_lock(sys_mutex_t *mutex)
//  {
//    DWORD ret;
//    LWIP_ASSERT("mutex != NULL", mutex != NULL);
//    LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
//    LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
//    /* wait infinite */
//    ret = WaitForSingleObject(mutex->mut, INFINITE);
//    LWIP_ASSERT("Error waiting for mutex", ret == WAIT_OBJECT_0);
//    LWIP_UNUSED_ARG(ret);
//  }//  void
//  sys_mutex_unlock(sys_mutex_t *mutex)
//  {
//    sys_arch_check_not_protected();
//    LWIP_ASSERT("mutex != NULL", mutex != NULL);
//    LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
//    LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
//    /* wait infinite */
//    if (!ReleaseMutex(mutex->mut)) {
//      LWIP_ASSERT("Error releasing mutex", 0);
//    }
//  }//  #ifdef _MSC_VER
//  const DWORD MS_VC_EXCEPTION=0x406D1388;
//  #pragma pack(push,8)
//  typedef struct tagTHREADNAME_INFO
//  {
//    DWORD dwType; /* Must be 0x1000. */
//    LPCSTR szName; /* Pointer to name (in user addr space). */
//    DWORD dwThreadID; /* Thread ID (-1=caller thread). */
//    DWORD dwFlags; /* Reserved for future use, must be zero. */
//  } THREADNAME_INFO;
//  #pragma pack(pop)//  static void
//  SetThreadName(DWORD dwThreadID, const char* threadName)
//  {
//    THREADNAME_INFO info;
//    info.dwType = 0x1000;
//    info.szName = threadName;
//    info.dwThreadID = dwThreadID;
//    info.dwFlags = 0;//    __try {
//      RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
//    }
//    __except(EXCEPTION_EXECUTE_HANDLER) {
//    }
//  }
//  #else /* _MSC_VER */
//  static void
//  SetThreadName(DWORD dwThreadID, const char* threadName)
//  {
//    LWIP_UNUSED_ARG(dwThreadID);
//    LWIP_UNUSED_ARG(threadName);
//  }
//  #endif /* _MSC_VER *///  static void
//  sys_thread_function(void* arg)
//  {
//    struct threadlist* t = (struct threadlist*)arg;
//  #if LWIP_NETCONN_SEM_PER_THREAD
//    sys_arch_netconn_sem_alloc();
//  #endif
//    t->function(t->arg);
//  #if LWIP_NETCONN_SEM_PER_THREAD
//    sys_arch_netconn_sem_free();
//  #endif
//  }//  sys_thread_t
//  sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
//  {
//    struct threadlist *new_thread;
//    HANDLE h;
//    SYS_ARCH_DECL_PROTECT(lev);//    LWIP_UNUSED_ARG(name);
//    LWIP_UNUSED_ARG(stacksize);
//    LWIP_UNUSED_ARG(prio);//    new_thread = (struct threadlist*)malloc(sizeof(struct threadlist));
//    LWIP_ASSERT("new_thread != NULL", new_thread != NULL);
//    if (new_thread != NULL) {
//      new_thread->function = function;
//      new_thread->arg = arg;
//      SYS_ARCH_PROTECT(lev);
//      new_thread->next = lwip_win32_threads;
//      lwip_win32_threads = new_thread;//      h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sys_thread_function, new_thread, 0, &(new_thread->id));
//      LWIP_ASSERT("h != 0", h != 0);
//      LWIP_ASSERT("h != -1", h != INVALID_HANDLE_VALUE);
//      LWIP_UNUSED_ARG(h);
//      SetThreadName(new_thread->id, name);//      SYS_ARCH_UNPROTECT(lev);
//      return new_thread->id;
//    }
//    return 0;
//  }//  #if !NO_SYS
//  #if LWIP_TCPIP_CORE_LOCKING//  static DWORD lwip_core_lock_holder_thread_id;//  void
//  sys_lock_tcpip_core(void)
//  {
//    sys_mutex_lock(&lock_tcpip_core);
//    lwip_core_lock_holder_thread_id = GetCurrentThreadId();
//  }//  void
//  sys_unlock_tcpip_core(void)
//  {
//    lwip_core_lock_holder_thread_id = 0;
//    sys_mutex_unlock(&lock_tcpip_core);
//  }
//  #endif /* LWIP_TCPIP_CORE_LOCKING *///  static DWORD lwip_tcpip_thread_id;//  void
//  sys_mark_tcpip_thread(void)
//  {
//    lwip_tcpip_thread_id = GetCurrentThreadId();
//  }//  void
//  sys_check_core_locking(void)
//  {
//    /* Embedded systems should check we are NOT in an interrupt context here *///    if (lwip_tcpip_thread_id != 0) {
//      DWORD current_thread_id = GetCurrentThreadId();//  #if LWIP_TCPIP_CORE_LOCKING
//      LWIP_ASSERT("Function called without core lock", current_thread_id == lwip_core_lock_holder_thread_id);
//  #else /* LWIP_TCPIP_CORE_LOCKING */
//      LWIP_ASSERT("Function called from wrong thread", current_thread_id == lwip_tcpip_thread_id);
//  #endif /* LWIP_TCPIP_CORE_LOCKING */
//      LWIP_UNUSED_ARG(current_thread_id); /* for LWIP_NOASSERT */
//    }
//  }
//  #endif /* !NO_SYS *///  err_t
//  sys_mbox_new(sys_mbox_t *mbox, int size)
//  {
//    LWIP_ASSERT("mbox != NULL", mbox != NULL);
//    LWIP_UNUSED_ARG(size);//    mbox->sem = CreateSemaphore(0, 0, MAX_QUEUE_ENTRIES, 0);
//    LWIP_ASSERT("Error creating semaphore", mbox->sem != NULL);
//    if (mbox->sem == NULL) {
//      SYS_ARCH_LOCKED(SYS_STATS_INC(mbox.err));
//      return ERR_MEM;
//    }
//    memset(&mbox->q_mem, 0, sizeof(u32_t)*MAX_QUEUE_ENTRIES);
//    mbox->head = 0;
//    mbox->tail = 0;
//    SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mbox));
//  #if LWIP_STATS && SYS_STATS
//    LWIP_ASSERT("sys_mbox_new() counter overflow", lwip_stats.sys.mbox.used != 0);
//  #endif /* LWIP_STATS && SYS_STATS */
//    return ERR_OK;
//  }//  void
//  sys_mbox_free(sys_mbox_t *mbox)
//  {
//    /* parameter check */
//    LWIP_ASSERT("mbox != NULL", mbox != NULL);
//    LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL);
//    LWIP_ASSERT("mbox->sem != INVALID_HANDLE_VALUE", mbox->sem != INVALID_HANDLE_VALUE);//    CloseHandle(mbox->sem);//    SYS_STATS_DEC(mbox.used);
//  #if LWIP_STATS && SYS_STATS
//    LWIP_ASSERT( "sys_mbox_free() ", lwip_stats.sys.mbox.used != (u16_t)-1);
//  #endif /* LWIP_STATS && SYS_STATS */
//    mbox->sem = NULL;
//  }//  void
//  sys_mbox_post(sys_mbox_t *q, void *msg)
//  {
//    BOOL ret;
//    SYS_ARCH_DECL_PROTECT(lev);
//    sys_arch_check_not_protected();//    /* parameter check */
//    LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
//    LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
//    LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);//    SYS_ARCH_PROTECT(lev);
//    q->q_mem[q->head] = msg;
//    q->head++;
//    if (q->head >= MAX_QUEUE_ENTRIES) {
//      q->head = 0;
//    }
//    LWIP_ASSERT("mbox is full!", q->head != q->tail);
//    ret = ReleaseSemaphore(q->sem, 1, 0);
//    LWIP_ASSERT("Error releasing sem", ret != 0);
//    LWIP_UNUSED_ARG(ret);//    SYS_ARCH_UNPROTECT(lev);
//  }//  err_t
//  sys_mbox_trypost(sys_mbox_t *q, void *msg)
//  {
//    u32_t new_head;
//    BOOL ret;
//    SYS_ARCH_DECL_PROTECT(lev);
//    sys_arch_check_not_protected();//    /* parameter check */
//    LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
//    LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
//    LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);//    SYS_ARCH_PROTECT(lev);//    new_head = q->head + 1;
//    if (new_head >= MAX_QUEUE_ENTRIES) {
//      new_head = 0;
//    }
//    if (new_head == q->tail) {
//      SYS_ARCH_UNPROTECT(lev);
//      return ERR_MEM;
//    }//    q->q_mem[q->head] = msg;
//    q->head = new_head;
//    LWIP_ASSERT("mbox is full!", q->head != q->tail);
//    ret = ReleaseSemaphore(q->sem, 1, 0);
//    LWIP_ASSERT("Error releasing sem", ret != 0);
//    LWIP_UNUSED_ARG(ret);//    SYS_ARCH_UNPROTECT(lev);
//    return ERR_OK;
//  }//  err_t
//  sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
//  {
//    return sys_mbox_trypost(q, msg);
//  }//  u32_t
//  sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout)
//  {
//    DWORD ret;
//    LONGLONG starttime, endtime;
//    SYS_ARCH_DECL_PROTECT(lev);//    /* parameter check */
//    LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
//    LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
//    LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);//    if (timeout == 0) {
//      timeout = INFINITE;
//    }
//    starttime = sys_get_ms_longlong();
//    ret = WaitForSingleObject(q->sem, timeout);
//    if (ret == WAIT_OBJECT_0) {
//      SYS_ARCH_PROTECT(lev);
//      if (msg != NULL) {
//        *msg  = q->q_mem[q->tail];
//      }//      q->tail++;
//      if (q->tail >= MAX_QUEUE_ENTRIES) {
//        q->tail = 0;
//      }
//      SYS_ARCH_UNPROTECT(lev);
//      endtime = sys_get_ms_longlong();
//      return (u32_t)(endtime - starttime);
//    } else {
//      LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT);
//      if (msg != NULL) {
//        *msg  = NULL;
//      }//      return SYS_ARCH_TIMEOUT;
//    }
//  }//  u32_t
//  sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg)
//  {
//    DWORD ret;
//    SYS_ARCH_DECL_PROTECT(lev);//    /* parameter check */
//    LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
//    LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
//    LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);//    ret = WaitForSingleObject(q->sem, 0);
//    if (ret == WAIT_OBJECT_0) {
//      SYS_ARCH_PROTECT(lev);
//      if (msg != NULL) {
//        *msg  = q->q_mem[q->tail];
//      }//      q->tail++;
//      if (q->tail >= MAX_QUEUE_ENTRIES) {
//        q->tail = 0;
//      }
//      SYS_ARCH_UNPROTECT(lev);
//      return 0;
//    } else {
//      LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT);
//      if (msg != NULL) {
//        *msg  = NULL;
//      }//      return SYS_ARCH_TIMEOUT;
//    }
//  }//  #if LWIP_NETCONN_SEM_PER_THREAD
//  sys_sem_t*
//  sys_arch_netconn_sem_get(void)
//  {
//    LPVOID tls_data = TlsGetValue(netconn_sem_tls_index);
//    return (sys_sem_t*)tls_data;
//  }//  void
//  sys_arch_netconn_sem_alloc(void)
//  {
//    sys_sem_t *sem;
//    err_t err;
//    BOOL done;//    sem = (sys_sem_t*)malloc(sizeof(sys_sem_t));
//    LWIP_ASSERT("failed to allocate memory for TLS semaphore", sem != NULL);
//    err = sys_sem_new(sem, 0);
//    LWIP_ASSERT("failed to initialise TLS semaphore", err == ERR_OK);
//    done = TlsSetValue(netconn_sem_tls_index, sem);
//    LWIP_UNUSED_ARG(done);
//    LWIP_ASSERT("failed to initialise TLS semaphore storage", done == TRUE);
//  }//  void
//  sys_arch_netconn_sem_free(void)
//  {
//    LPVOID tls_data = TlsGetValue(netconn_sem_tls_index);
//    if (tls_data != NULL) {
//      BOOL done;
//      free(tls_data);
//      done = TlsSetValue(netconn_sem_tls_index, NULL);
//      LWIP_UNUSED_ARG(done);
//      LWIP_ASSERT("failed to de-init TLS semaphore storage", done == TRUE);
//    }
//  }
//  #endif /* LWIP_NETCONN_SEM_PER_THREAD *///  #endif /* !NO_SYS *///  /* get keyboard state to terminate the debug app on any kbhit event using win32 API */
//  int
//  lwip_win32_keypressed(void)
//  {
//    INPUT_RECORD rec;
//    DWORD num = 0;
//    HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
//    BOOL ret = PeekConsoleInput(h, &rec, 1, &num);
//    if (ret && num) {
//      ReadConsoleInput(h, &rec, 1, &num);
//      if (rec.EventType == KEY_EVENT) {
//        if (rec.Event.KeyEvent.bKeyDown) {
//          /* not a special key? */
//          if (rec.Event.KeyEvent.uChar.AsciiChar != 0) {
//            return 1;
//          }
//        }
//      }
//    }
//    return 0;
//  }//  #include <stdarg.h>//  /* This is an example implementation for LWIP_PLATFORM_DIAG:
//   * format a string and pass it to your output function.
//   */
//  void
//  lwip_win32_platform_diag(const char *format, ...)
//  {
//    va_list ap;
//    /* get the varargs */
//    va_start(ap, format);
//    /* print via varargs; to use another output function, you could use
//       vsnprintf here */
//    vprintf(format, ap);
//    va_end(ap);
//  }// 给lwip提供信息处理函数
void lwip_stm32_platform_diag(const char *format, ...)
{// 打印格式化字符串的方法 - 1char sz_buf[0x100] = {'\0'};const char* psz_msg_prefix = "info:";va_list arglist;/* get the varargs */va_start(arglist, format);/* print via varargs; to use another output function, you could usevsnprintf here */// vprintf(format, ap);memset(sz_buf, 0, sizeof(sz_buf));// strncpy 并不会拷贝\0过去, 指定多长, 就拷贝多长(缓冲区后面都填0了)strncpy(sz_buf, psz_msg_prefix, sizeof(sz_buf) - 1); // 拷贝时, 留一个\0的位置// vsnprintf 会拷贝'\0', 不用特意留末尾'\0'位置vsnprintf(&sz_buf[strlen(psz_msg_prefix)], sizeof(sz_buf) - strlen(psz_msg_prefix), format, arglist);printf("%s", sz_buf);va_end(arglist);
}// 给lwip提供断言处理函数
void lwip_stm32_platform_assert(const char *format, ...)
{// 打印格式化字符串的方法 - 2va_list ap;/* get the varargs */va_start(ap, format);/* print via varargs; to use another output function, you could usevsnprintf here */vprintf(format, ap); // 这个是C库提供的打印函数, 如果是自己va_end(ap);
}// 给lwip提供错误号处理函数
const char *lwip_strerr(err_t err)
{const char* psz_err_string = NULL;char sz_err_sn[17] = {'\0'};switch (err) {
//  /** No error, everything OK. */
//    ERR_OK         = 0,case ERR_OK:psz_err_string = "No error, everything OK.";break;//  /** Out of memory error.     */
//    ERR_MEM        = -1,case ERR_MEM:psz_err_string = "Out of memory error.";break;//  /** Buffer error.            */
//    ERR_BUF        = -2,case ERR_BUF:psz_err_string = "Buffer error.";break;//  /** Timeout.                 */
//    ERR_TIMEOUT    = -3,case ERR_TIMEOUT:psz_err_string = "Timeout.";break;//  /** Routing problem.         */
//    ERR_RTE        = -4,case ERR_RTE:psz_err_string = "Routing problem.";break;//  /** Operation in progress    */
//    ERR_INPROGRESS = -5,case ERR_INPROGRESS:psz_err_string = "Operation in progress";break;//  /** Illegal value.           */
//    ERR_VAL        = -6,case ERR_VAL:psz_err_string = "Illegal value.";break;//  /** Operation would block.   */
//    ERR_WOULDBLOCK = -7,case ERR_WOULDBLOCK:psz_err_string = "Operation would block.";break;//  /** Address in use.          */
//    ERR_USE        = -8,case ERR_USE:psz_err_string = "Address in use.";break;//  /** Already connecting.      */
//    ERR_ALREADY    = -9,case ERR_ALREADY:psz_err_string = "Already connecting.";break;//  /** Conn already established.*/
//    ERR_ISCONN     = -10,case ERR_ISCONN:psz_err_string = "Conn already established.";break;//  /** Not connected.           */
//    ERR_CONN       = -11,case ERR_CONN:psz_err_string = "Not connected.";break;//  /** Low-level netif error    */
//    ERR_IF         = -12,case ERR_IF:psz_err_string = "Low-level netif error";break;//  /** Connection aborted.      */
//    ERR_ABRT       = -13,case ERR_ABRT:psz_err_string = "Connection aborted.";break;//  /** Connection reset.        */
//    ERR_RST        = -14,case ERR_RST:psz_err_string = "Connection reset.";break;//  /** Connection closed.       */
//    ERR_CLSD       = -15,case ERR_CLSD:psz_err_string = "Connection closed.";break;//  /** Illegal argument.        */
//    ERR_ARG        = -16case ERR_ARG:psz_err_string = "Illegal argument.";break;default:memset(sz_err_sn, 0, sizeof(sz_err_sn));snprintf(sz_err_sn, sizeof(sz_err_sn), "%d", err);psz_err_string = sz_err_sn;break;}return psz_err_string;
}

bpstruct.h

这个文件用来包含结构体字节对齐的开始语句.

#pragma pack(push,1)

epstruct.h

这个文件用来包含结构体字节对齐的结束语句

#pragma pack(pop)

ppp_settings.h

这个文件没用到,内容为空

#ifdef _MSC_VER
#pragma warning (disable: 4242) /* PPP only: conversion from 'x' to 'y', possible loss of data */
#pragma warning (disable: 4244) /* PPP only: conversion from 'x' to 'y', possible loss of data (again?) */
#pragma warning (disable: 4310) /* PPP only: cast truncates constant value */
#pragma warning (disable: 4706) /* PPP only: assignment within conditional expression */
#endif /* MSC_VER  */

sys_arch.h

这个文件提供带系统时的同步函数定义

/** Copyright (c) 2001-2003 Swedish Institute of Computer Science.* All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE.** This file is part of the lwIP TCP/IP stack.* * Author: Adam Dunkels <adam@sics.se>**/
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H/* HANDLE is used for sys_sem_t but we won't include windows.h */
struct _sys_sem {void *sem;
};
typedef struct _sys_sem sys_sem_t;
#define sys_sem_valid_val(sema) (((sema).sem != NULL)  && ((sema).sem != (void*)-1))
#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema)))
#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)/* HANDLE is used for sys_mutex_t but we won't include windows.h */
struct _sys_mut {void *mut;
};
typedef struct _sys_mut sys_mutex_t;
#define sys_mutex_valid_val(mutex) (((mutex).mut != NULL)  && ((mutex).mut != (void*)-1))
#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))
#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)#ifndef MAX_QUEUE_ENTRIES
#define MAX_QUEUE_ENTRIES 100
#endif
struct lwip_mbox {void* sem;void* q_mem[MAX_QUEUE_ENTRIES];u32_t head, tail;
};
typedef struct lwip_mbox sys_mbox_t;
#define SYS_MBOX_NULL NULL
#define sys_mbox_valid_val(mbox) (((mbox).sem != NULL)  && ((mbox).sem != (void*)-1))
#define sys_mbox_valid(mbox) ((mbox != NULL) && sys_mbox_valid_val(*(mbox)))
#define sys_mbox_set_invalid(mbox) ((mbox)->sem = NULL)/* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */
typedef u32_t sys_thread_t;sys_sem_t* sys_arch_netconn_sem_get(void);
void sys_arch_netconn_sem_alloc(void);
void sys_arch_netconn_sem_free(void);
#define LWIP_NETCONN_THREAD_SEM_GET()   sys_arch_netconn_sem_get()
#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc()
#define LWIP_NETCONN_THREAD_SEM_FREE()  sys_arch_netconn_sem_free()#define LWIP_EXAMPLE_APP_ABORT() lwip_win32_keypressed()
int lwip_win32_keypressed(void);#endif /* LWIP_ARCH_SYS_ARCH_H */

ethernetif.c

这个文件实现网卡接口(封装调用实际的网卡驱动函数,相当于中间层)

/*** @file* Ethernet Interface Skeleton**//** Copyright (c) 2001-2004 Swedish Institute of Computer Science.* All rights reserved.** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY* OF SUCH DAMAGE.** This file is part of the lwIP TCP/IP stack.** Author: Adam Dunkels <adam@sics.se>**//** This file is a skeleton for developing Ethernet network interface* drivers for lwIP. Add code to the low_level functions and do a* search-and-replace for the word "ethernetif" to replace it with* something that better describes your network interface.*/#include "lwip/opt.h"#if 1 /* don't build, this is only a skeleton, see previous comment */#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ethip6.h"
#include "lwip/etharp.h"
#include "netif/ppp/pppoe.h"// 添加自己的网卡驱动头文件和自己的网卡操作中间层接口头文件
#include "ENC28J60.h"
#include "my_nic.h"/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'/*** Helper struct to hold private data used to operate your ethernet interface.* Keeping the ethernet address of the MAC in this struct is not necessary* as it is already kept in the struct netif.* But this is only an example, anyway...*/
struct ethernetif {struct eth_addr *ethaddr;/* Add whatever per-interface state that is needed here. */
};/* Forward declarations. */
void  ethernetif_input(struct netif *netif);// 提供网卡初始化时的网卡地址, 如果网卡地址是根据自己的配置文件来的,这里要将使用MyMacID的地方改成接口来去网卡地址
// 4C-ED-FB-01-23-45
static const unsigned char MyMacID[6] = {0x4C,0xED,0xFB,0x01,0x23,0x45};/*** In this function, the hardware should be initialized.* Called from ethernetif_init().** @param netif the already initialized lwip network interface structure*        for this ethernetif*/// 为lwip提供网卡初始化函数
static void
low_level_init(struct netif *netif)
{// struct ethernetif *ethernetif = netif->state;/* set MAC hardware address length */netif->hwaddr_len = ETHARP_HWADDR_LEN;/* set MAC hardware address */// 设置网卡地址netif->hwaddr[0] = MyMacID[0];netif->hwaddr[1] = MyMacID[1];netif->hwaddr[2] = MyMacID[2];netif->hwaddr[3] = MyMacID[3];netif->hwaddr[4] = MyMacID[4];                netif->hwaddr[5] = MyMacID[5];/* maximum transfer unit */netif->mtu = 1500;/* device capabilities *//* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;#if LWIP_IPV6 && LWIP_IPV6_MLD/** For hardware/netifs that implement MAC filtering.* All-nodes link-local is handled by default, so we must let the hardware know* to allow multicast packets in.* Should set mld_mac_filter previously. */if (netif->mld_mac_filter != NULL) {ip6_addr_t ip6_allnodes_ll;ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);}
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD *//* Do whatever else is needed to initialize interface. */mymacinit(MyMacID); // 调用自己实际的网卡初始化函数
}/*** This function should do the actual transmission of the packet. The packet is* contained in the pbuf that is passed to the function. This pbuf* might be chained.** @param netif the lwip network interface structure for this ethernetif* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)* @return ERR_OK if the packet could be sent*         an err_t value if the packet couldn't be sent** @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to*       strange results. You might consider waiting for space in the DMA queue*       to become available since the stack doesn't retry to send a packet*       dropped because of memory failure (except for the TCP timers).*/// 为lwip提供网卡数据send实现
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{return PacketSend(p); // 调用自己的网卡数据发送函数//  // struct ethernetif *ethernetif = netif->state;
//  struct pbuf *q;//  // initiate transfer();//#if ETH_PAD_SIZE
//  pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
//#endif//  for (q = p; q != NULL; q = q->next) {
//    /* Send the data from the pbuf to the interface, one pbuf at a
//       time. The size of the data in each pbuf is kept in the ->len
//       variable. */
//    // send data from(q->payload, q->len);
//  }//  // signal that packet should be sent();//  MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
//  if (((u8_t *)p->payload)[0] & 1) {
//    /* broadcast or multicast packet*/
//    MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
//  } else {
//    /* unicast packet */
//    MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
//  }
//  /* increase ifoutdiscards or ifouterrors on error *///#if ETH_PAD_SIZE
//  pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
//#endif//  LINK_STATS_INC(link.xmit);//  return ERR_OK;
}/*** Should allocate a pbuf and transfer the bytes of the incoming* packet from the interface into the pbuf.** @param netif the lwip network interface structure for this ethernetif* @return a pbuf filled with the received packet (including MAC header)*         NULL on memory error*/
// 为lwip提供网卡数据接收函数
static struct pbuf *
low_level_input(struct netif *netif)
{return PacketReceive(netif); // 调用自己的网卡数据接收处理函数
//  // struct ethernetif *ethernetif = netif->state;
//  struct pbuf *p, *q;
//  u16_t len;//  /* Obtain the size of the packet and put it into the "len"
//     variable. */
//  // len = ;//#if ETH_PAD_SIZE
//  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
//#endif//  /* We allocate a pbuf chain of pbufs from the pool. */
//  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);//  if (p != NULL) {//#if ETH_PAD_SIZE
//    pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
//#endif//    /* We iterate over the pbuf chain until we have read the entire
//     * packet into the pbuf. */
//    for (q = p; q != NULL; q = q->next) {
//      /* Read enough bytes to fill this pbuf in the chain. The
//       * available data in the pbuf is given by the q->len
//       * variable.
//       * This does not necessarily have to be a memcpy, you can also preallocate
//       * pbufs for a DMA-enabled MAC and after receiving truncate it to the
//       * actually received size. In this case, ensure the tot_len member of the
//       * pbuf is the sum of the chained pbuf len members.
//       */
//      // read data into(q->payload, q->len);
//    }
//    // acknowledge that packet has been read();//    MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
//    if (((u8_t *)p->payload)[0] & 1) {
//      /* broadcast or multicast packet*/
//      MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
//    } else {
//      /* unicast packet*/
//      MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
//    }
//#if ETH_PAD_SIZE
//    pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
//#endif//    LINK_STATS_INC(link.recv);
//  } else {
//    // drop packet();
//    LINK_STATS_INC(link.memerr);
//    LINK_STATS_INC(link.drop);
//    MIB2_STATS_NETIF_INC(netif, ifindiscards);
//  }//  return p;
}/*** This function should be called when a packet is ready to be read* from the interface. It uses the function low_level_input() that* should handle the actual reception of bytes from the network* interface. Then the type of the received packet is determined and* the appropriate input function is called.** @param netif the lwip network interface structure for this ethernetif*/
// lwip框架自己的网卡接收处理函数,不用改
void
ethernetif_input(struct netif *netif)
{// struct ethernetif *ethernetif;// struct eth_hdr *ethhdr;struct pbuf *p;// ethernetif = netif->state;/* move received packet into a new pbuf */p = low_level_input(netif);/* if no packet could be read, silently ignore this */if (p != NULL) {/* pass all packets to ethernet_input, which decides what packets it supports */if (netif->input(p, netif) != ERR_OK) {LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));pbuf_free(p);p = NULL;}}
}/*** Should be called at the beginning of the program to set up the* network interface. It calls the function low_level_init() to do the* actual setup of the hardware.** This function should be passed as a parameter to netif_add().** @param netif the lwip network interface structure for this ethernetif* @return ERR_OK if the loopif is initialized*         ERR_MEM if private data couldn't be allocated*         any other err_t on error*/// lwip自己的网卡初始化封装函数,不用改。
err_t
ethernetif_init(struct netif *netif)
{struct ethernetif *ethernetif;LWIP_ASSERT("netif != NULL", (netif != NULL));ethernetif = mem_malloc(sizeof(struct ethernetif));if (ethernetif == NULL) {LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));return ERR_MEM;}#if LWIP_NETIF_HOSTNAME/* Initialize interface hostname */netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME *//** Initialize the snmp variables and counters inside the struct netif.* The last argument should be replaced with your link speed, in units* of bits per second.*/// MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);netif->state = ethernetif;netif->name[0] = IFNAME0;netif->name[1] = IFNAME1;/* We directly use etharp_output() here to save a function call.* You can instead declare your own function an call etharp_output()* from it if you have to do some checks before sending (e.g. if link* is available...) */
#if LWIP_IPV4netif->output = etharp_output;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */netif->linkoutput = low_level_output;ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]);/* initialize the hardware */low_level_init(netif);return ERR_OK;
}#endif /* 0 */

提供实际的网卡驱动

为了可维护,找到的现成网卡实现不要动,自己封装一个中间层。

// @file my_nic.h#if !defined(__MY_NIC_H__)
#define __MY_NIC_H__#include "lwip/pbuf.h"
#include "lwip/netif.h"void my_nic_setting(void);
struct pbuf *PacketReceive(struct netif *netif);
err_t PacketSend (struct pbuf *p);extern void process_mac(void);#endif // #if defined(__MY_NIC_H__)
// @file my_nic.c#include "my_nic.h"#include "main.h"#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/ip_addr.h"
#include "lwip/pbuf.h"#include "ENC28J60.h"//extern functions
extern err_t ethernetif_init(struct netif *netif);
extern void  ethernetif_input(struct netif *netif);//global data
struct netif g_my_netif;void my_nic_setting(void)
{struct ip4_addr _ipaddr;struct ip4_addr _netmask;struct ip4_addr _gw;lwip_init();IP4_ADDR(&_ipaddr, 192, 168, 1, 66);IP4_ADDR(&_netmask, 255, 255, 255, 0);IP4_ADDR(&_gw, 192, 168, 1, 1);netif_add(&g_my_netif, &_ipaddr, &_netmask, &_gw, NULL, ethernetif_init,ethernet_input);netif_set_default(&g_my_netif);netif_set_up(&g_my_netif);
}/****************************************************************************
* 名    称:void PacketSend (struct pbuf *p)
* 功    能:发送一包数据	完成pbuf中数据的发送																	 
* 入口参数:
* 出口参数: 
* 说    明:基于uip的驱动程序完成LwIP的数据包发送和接收
* 调用方法:将pbuf中的数据拷贝到全局数组MyDatabuf中,然后调用上面的函数enc28j60PacketSend发送数据
****************************************************************************/ 
//以太网数据帧的最大长度1500,定义这个数组会增大内存开销,但是驱动程序变得简单
static unsigned char  MySendbuf[1500]; 
err_t PacketSend (struct pbuf *p)
{struct pbuf *q = NULL;unsigned int templen = 0;for(q = p;q!=NULL;q = q->next){memcpy(&MySendbuf[templen],q->payload,q->len);	 //将pbuf中的数据拷贝到全局数组MyDatabuf中templen += 	q->len ;if(templen > 1500 || templen > p->tot_len)	 	//有效性校验,防止数据溢出{LWIP_PLATFORM_DIAG(("PacketSend: error,tmplen=%"U32_F",tot_len=%"U32_F"\n\t", templen, p->tot_len));return ERR_BUF;}}//拷贝完毕,下面进行数据的发送工作if(templen == p->tot_len){enc28j60PacketSend(templen, MySendbuf);		   //调用网卡发送函数return ERR_OK; }LWIP_PLATFORM_DIAG(("PacketSend: length mismatch ,tmplen=%"U32_F",tot_len=%"U32_F"\n\t", templen, p->tot_len));return ERR_BUF;
}
/****************************************************************************
* 名    称:struct pbuf *PacketReceive(struct netif *netif)
* 功    能:完成LwIP需要的数据包接收																	 
* 入口参数:
* 出口参数: 
* 说    明:基于uip的驱动程序完成LwIP的数据包发送和接收
* 调用方法:网卡的数据拷贝到全局数组MyRecvbuf中,再组装成pbuf
****************************************************************************/ 
//以太网数据帧的最大长度1500,定义这个数组会增大内存开销,但是驱动程序变得简单
static unsigned char  MyRecvbuf[1500]; 
struct pbuf *PacketReceive(struct netif *netif)
{struct pbuf *p = NULL;	unsigned int recvlen = 0;unsigned int i = 0;struct pbuf *q = NULL;recvlen = enc28j60PacketReceive(1500, MyRecvbuf);if(!recvlen)	       //接收数据长度为0,直接返回空{return NULL;}//申请内核pbuf空间,为RAM类型p = pbuf_alloc(PBUF_RAW, recvlen, PBUF_RAM);if(!p)			       //申请失败,则返回空{LWIP_PLATFORM_DIAG(("PacketReceive: pbuf_alloc fail ,len=%"U32_F"\n\t", recvlen));return NULL;}//申请成功,拷贝数据到pbuf中q = p;while(q != NULL){   memcpy(q->payload,&MyRecvbuf[i],q->len);i += q->len;q = q->next;if(i >= recvlen)  break;}return p;
}void process_mac(void)
{bool b_loop = false;do {ethernetif_input(&g_my_netif);} while(b_loop);
}

用户层代码

用户层代码只是调用网卡初始化函数,然后用中断方式处理网卡响应(收/发).
在手头这块开发板上,enc28j60的中断引脚接到了MCU的外中断1引脚。
这样,只要有网卡数据接收事件,就会先进去外中断1,然后就可以处理网卡数据的收发了。

// @file main.h#if !defined(__MAIN_H__)
#define __MAIN_H__#include "stm32f10x.h"#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>#include <stdarg.h>
#include <string.h>extern int g_i_tick_cnt;#define LED1_ON GPIO_SetBits(GPIOB, GPIO_Pin_5);  
#define LED1_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_5); #define LED2_ON GPIO_SetBits(GPIOD, GPIO_Pin_6);  
#define LED2_OFF GPIO_ResetBits(GPIOD, GPIO_Pin_6); #define LED3_ON GPIO_SetBits(GPIOD, GPIO_Pin_3);  
#define LED3_OFF GPIO_ResetBits(GPIOD, GPIO_Pin_3);  #define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA          0x01000000#endif // #if !defined(__MAIN_H__)
// @file main.c#include "main.h"
#include "spi.h"
#include "my_nic.h"/*
选择芯片后就不需要在option->c/c++中再定义类似STM32F103_HD的东西了
因为选择芯片时已经加进去了。而且当你的定义和你选择的芯片不同时,会报错:
..\..\Libraries\CMSIS\stm32f10x.h(298): error: #67: expected a "}"ADC1_2_IRQn = 18,
*/void RCC_Configuration(void);
void NVIC_Configuration(void);
void GPIO_Configuration(void);void show_mcu_type(void);void delay_ms(int i_ms);int main(void)
{int i_loop_cnt = 0;RCC_Configuration(); // 设置时钟频率和tick节拍printf(">> main\n");// 这里测试过了, tick非常准, 1ms一个tick中断
//  printf(">> 1s done\n");
//  do {} while (g_i_tick_cnt < 1000 * 60);
//  printf("<< 1s done\n");// options => c/c++ => Define 那里只填USE_STDPERIPH_DRIVER时, 到底要填啥 STM32F10X_XX宏show_mcu_type(); // show mcu macro is STM32F10X_HD or otherNVIC_Configuration(); // 设置中断等级, 外部中断(网卡中断接在外中断1)GPIO_Configuration(); // 设置管脚配置(外中断1, 3个LED, 4个SPI设备)SPI1_Init(); // Enc28j60网卡控制器在SPI1上my_nic_setting(); // 设置网卡参数// 并不能放外中断1中处理, 因为网卡设置时, 就进了外中断, 导致网卡并没有设置完就卡在外中断处理中死循环了// process_mac(); // 处理网卡数据包while (1){if (0 == (i_loop_cnt % 10)) {printf("i_loop_cnt = %d\n", i_loop_cnt);}++i_loop_cnt;LED1_ON; LED2_OFF; LED3_OFF;		//LED1亮  LED2,LED3灭(LED2,LED3 仅V5  V3,V2,V2.1板有)delay_ms(1000);LED1_OFF; LED2_ON; LED3_OFF;		//LED2亮  LED1,LED3灭(LED2,LED3 仅V5  V3,V2,V2.1板有)delay_ms(1000);LED1_OFF; LED2_OFF; LED3_ON;		//LED3亮  LED1,LED2灭(LED2,LED3 仅V5  V3,V2,V2.1板有)delay_ms(1000);// for remove warningif (i_loop_cnt < 0) {i_loop_cnt = 0;}if (i_loop_cnt < 0) {break;}}return 0;
}void RCC_Configuration(void)
{   SystemInit();SysTick_Config(1 * 72000);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// STM32F103有5个GPIO(A, B, C, D, E)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);// RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
}void delay_ms(int i_ms)
{int i_tick_now = 0;// 防止tick溢出那一瞬间do {i_tick_now = g_i_tick_cnt;} while (i_tick_now < 0);do {} while ((g_i_tick_cnt - i_tick_now) < i_ms);
}void show_mcu_type(void)
{#if defined(STM32F10X_LD)printf("STM32F10X_LD: STM32 Low density devices\n\- Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers\n\where the Flash memory density ranges between 16 and 32 Kbytes.\n\
");#elif defined(STM32F10X_LD_VL)printf("STM32F10X_LD_VL: STM32 Low density Value Line devices\n\- Low-density value line devices are STM32F100xx microcontrollers where the Flash\n\memory density ranges between 16 and 32 Kbytes.\n\
");#elif defined(STM32F10X_MD)printf("STM32F10X_MD: STM32 Medium density devices\n\- Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers\n\where the Flash memory density ranges between 64 and 128 Kbytes.\n\
");#elif defined(STM32F10X_MD_VL)printf("STM32F10X_MD_VL: STM32 Medium density Value Line devices\n\- Medium-density value line devices are STM32F100xx microcontrollers where the\n\Flash memory density ranges between 64 and 128 Kbytes.\n\
");#elif defined(STM32F10X_HD)// f103ZE 是 STM32F10X_HDprintf("STM32F10X_HD: STM32 High density devices\n\- High-density devices are STM32F101xx and STM32F103xx microcontrollers where\n\the Flash memory density ranges between 256 and 512 Kbytes.\n\
");#elif defined(STM32F10X_HD_VL)printf("STM32F10X_HD_VL: STM32 High density value line devices\n\- High-density value line devices are STM32F100xx microcontrollers where the\n\Flash memory density ranges between 256 and 512 Kbytes.\n\
");#elif defined(STM32F10X_XL)printf("STM32F10X_XL: STM32 XL-density devices\n\- XL-density devices are STM32F101xx and STM32F103xx microcontrollers where\n\the Flash memory density ranges between 512 and 1024 Kbytes.\n\
");#elif defined(STM32F10X_CL)printf("STM32F10X_CL: STM32 Connectivity line devices\n\- Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.\n\
");#elseprintf("unknown STM32F10X_ ...\n"); // 如果只选cpu, 不填STM32F10X_xx, 到了这,所以STM32F10X_xx必须填写#endif
}int fputc(int ch, FILE *f)
{ 	if (DEMCR & TRCENA) {while (ITM_Port32(0) == 0);ITM_Port8(0) = ch;}return(ch);/*while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   USART1->DR = (u8) ch;      return ch;*/
}void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;/* Configure one bit for preemption priority *//* 优先级组 说明了抢占优先级所用的位数,和子优先级所用的位数   在这里是1, 7 */    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* Enable the EXTI2 Interrupt */NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;				 //外部中断2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	     //抢占优先级 0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;			 //子优先级0  //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				 //使能NVIC_Init(&NVIC_InitStructure);//用于配置AFIO外部中断配置寄存器AFIO_EXTICR1,用于选择EXTI2外部中断的输入源是PE2。GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);     //外部中断配置AFIO--ETXI2EXTI_InitStructure.EXTI_Line = EXTI_Line1;					  //PE2 作为键盘的行线。检测状态EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			  //中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		  //下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}void GPIO_Configuration(void)
{// my codeGPIO_InitTypeDef GPIO_InitStructure;// UART/LED的GPIO速度设为50MHZ// SPI的GPIO速度设置成10MHZ// 3个LED - PB5, PD3, PD6GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // LED1  V6, 将V6,V7,V8 配置为通用推挽输出  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 口线翻转速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);					 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_3; // LED2, LED3 V7 V8GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOD, &GPIO_InitStructure);// 设置外中断1管脚 - PA1GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // ENC28J60接收完成中断引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 内部上拉输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);		 // SPI1管脚 - PA5-SCK, PA6-MISO, PA7-MOSI GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 如果一个SPI上接着多个设备, 操作之间是会有影响的.// 只有禁掉了其他设备的片选,只保留一个片选。才能正常操作一个SPI设备//// 板子的SPI1上有4个设备, 片选如下:// PA4 - 网卡(ENC28J60)的片选// PB7 - LCD(TFT液晶显示屏)的片选// PB12 - VS1003的片选(SPI2)// PC4 - 存储(SST25VF016B)的片选// SPI片选引脚// PA4 - 网卡(ENC28J60)的片选GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_4); // 禁止片选// PB7 - LCD(TFT液晶显示屏)的片选// PB12 - VS1003的片选(SPI2)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_7); // 禁止片选 GPIO_SetBits(GPIOB, GPIO_Pin_12); // 禁止片选 // PC4 - 存储(SST25VF016B)的片选GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_SetBits(GPIOC, GPIO_Pin_4); // 禁止片选  
}
/********************************************************************************* @file    Project/STM32F10x_StdPeriph_Template/stm32f10x_it.h * @author  MCD Application Team* @version V3.5.0* @date    08-April-2011* @brief   This file contains the headers of the interrupt handlers.******************************************************************************* @attention** THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.** <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>*******************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_IT_H
#define __STM32F10x_IT_H#ifdef __cplusplusextern "C" {
#endif /* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);#ifdef __cplusplus
}
#endif#endif /* __STM32F10x_IT_H *//******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
/********************************************************************************* @file    Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c * @author  MCD Application Team* @version V3.5.0* @date    08-April-2011* @brief   Main Interrupt Service Routines.*          This file provides template for all exceptions handler and *          peripherals interrupt service routine.******************************************************************************* @attention** THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.** <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>*******************************************************************************//* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
#include "main.h"
#include "my_nic.h"int g_i_tick_cnt = 0;/** @addtogroup STM32F10x_StdPeriph_Template* @{*//* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//******************************************************************************/
/*            Cortex-M3 Processor Exceptions Handlers                         */
/******************************************************************************//*** @brief  This function handles NMI exception.* @param  None* @retval None*/
void NMI_Handler(void)
{
}/*** @brief  This function handles Hard Fault exception.* @param  None* @retval None*/
void HardFault_Handler(void)
{/* Go to infinite loop when Hard Fault exception occurs */while (1){}
}/*** @brief  This function handles Memory Manage exception.* @param  None* @retval None*/
void MemManage_Handler(void)
{/* Go to infinite loop when Memory Manage exception occurs */while (1){}
}/*** @brief  This function handles Bus Fault exception.* @param  None* @retval None*/
void BusFault_Handler(void)
{/* Go to infinite loop when Bus Fault exception occurs */while (1){}
}/*** @brief  This function handles Usage Fault exception.* @param  None* @retval None*/
void UsageFault_Handler(void)
{/* Go to infinite loop when Usage Fault exception occurs */while (1){}
}/*** @brief  This function handles SVCall exception.* @param  None* @retval None*/
void SVC_Handler(void)
{
}/*** @brief  This function handles Debug Monitor exception.* @param  None* @retval None*/
void DebugMon_Handler(void)
{
}/*** @brief  This function handles PendSVC exception.* @param  None* @retval None*/
void PendSV_Handler(void)
{
}/*** @brief  This function handles SysTick Handler.* @param  None* @retval None*/
void SysTick_Handler(void)
{// printf(">> SysTick_Handler\n");g_i_tick_cnt++;
}void EXTI1_IRQHandler(void)
{
//  int ret = 0;if (EXTI_GetITStatus(EXTI_Line1) != RESET) {printf(">> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)\n");EXTI_ClearITPendingBit(EXTI_Line1);		//清除中断请求标志process_mac();}
}/******************************************************************************/
/*                 STM32F10x Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f10x_xx.s).                                            */
/******************************************************************************//*** @brief  This function handles PPP interrupt request.* @param  None* @retval None*/
/*void PPP_IRQHandler(void)
{
}*//*** @}*/ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

移植完成后的测试

打开LWIP日志选项
首先是编译过,将编译警告都去掉. 警告不是东西。
程序跑起来,可以看到MDK调试窗口接收到的ITM打印信息。能看到arp包的处理。
再ping一下,可以看到LWIP的调试信息,源IP和目标IP都打印出来了,在PC端命令行窗口能得ping结果,说明LWIP移植成功。

>> main
STM32F10X_HD: STM32 High density devices- High-density devices are STM32F101xx and STM32F103xx microcontrollers wherethe Flash memory density ranges between 256 and 512 Kbytes.
info:netif: netmask of interface info:netif: GW address of interface info:netif_set_ipaddr: netif address being changed
info:netif: added interface lo IPinfo: addr info:127.0.0.1info: netmask info:255.0.0.0info: gw info:127.0.0.1info:
info:igmp_init: initializing
info:dns_init: initializing
info:netif: netmask of interface info:netif: GW address of interface info:netif_set_ipaddr: netif address being changed
mac addr = 4C-ED-FB-01-23-45
info:netif: added interface en IPinfo: addr info:192.168.1.66info: netmask info:255.255.255.0info: gw info:192.168.1.1info:
info:netif: setting default interface en
info:pbuf_alloc(length=28)
info:pbuf_alloc(length=28) == 200011f0
info:pbuf_add_header: old 20001210 new 20001202 (14)
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
i_loop_cnt = 0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_alloc(length=28)
info:pbuf_alloc(length=28) == 20001244
info:pbuf_add_header: old 20001264 new 20001256 (14)
info:pbuf_free(20001244)
info:pbuf_free: deallocating 20001244
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=74)
info:pbuf_alloc(length=74) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:ip_input: iphdr->dest 0x4201a8c0 netif->ip_addr 0x4201a8c0 (0x1a8c0, 0x1a8c0, 0x42000000)
info:ip4_input: packet accepted on interface en
info:ip4_input: 
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62749      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|   64  |    1  |    0x01ab     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (dest)
info:+-------------------------------+
info:ip4_input: p->len 60 p->tot_len 60
info:pbuf_remove_header: old 2000120e new 20001222 (20)
info:icmp_input: ping
info:pbuf_add_header: old 20001222 new 20001200 (34)
info:pbuf_remove_header: old 20001200 new 20001222 (34)
info:pbuf_add_header: old 20001222 new 2000120e (20)
info:ip4_output_if: en1
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62749      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|  255  |    1  |    0x42aa     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (dest)
info:+-------------------------------+
info:ip4_output_if: call netif->output()
info:pbuf_add_header: old 2000120e new 20001200 (14)
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=74)
info:pbuf_alloc(length=74) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:ip_input: iphdr->dest 0x4201a8c0 netif->ip_addr 0x4201a8c0 (0x1a8c0, 0x1a8c0, 0x42000000)
info:ip4_input: packet accepted on interface en
info:ip4_input: 
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62750      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|   64  |    1  |    0x01aa     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (dest)
info:+-------------------------------+
info:ip4_input: p->len 60 p->tot_len 60
info:pbuf_remove_header: old 2000120e new 20001222 (20)
info:icmp_input: ping
info:pbuf_add_header: old 20001222 new 20001200 (34)
info:pbuf_remove_header: old 20001200 new 20001222 (34)
info:pbuf_add_header: old 20001222 new 2000120e (20)
info:ip4_output_if: en1
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62750      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|  255  |    1  |    0x42a9     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (dest)
info:+-------------------------------+
info:ip4_output_if: call netif->output()
info:pbuf_add_header: old 2000120e new 20001200 (14)
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=74)
info:pbuf_alloc(length=74) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:ip_input: iphdr->dest 0x4201a8c0 netif->ip_addr 0x4201a8c0 (0x1a8c0, 0x1a8c0, 0x42000000)
info:ip4_input: packet accepted on interface en
info:ip4_input: 
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62751      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|   64  |    1  |    0x01a9     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (dest)
info:+-------------------------------+
info:ip4_input: p->len 60 p->tot_len 60
info:pbuf_remove_header: old 2000120e new 20001222 (20)
info:icmp_input: ping
info:pbuf_add_header: old 20001222 new 20001200 (34)
info:pbuf_remove_header: old 20001200 new 20001222 (34)
info:pbuf_add_header: old 20001222 new 2000120e (20)
info:ip4_output_if: en1
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62751      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|  255  |    1  |    0x42a8     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (dest)
info:+-------------------------------+
info:ip4_output_if: call netif->output()
info:pbuf_add_header: old 2000120e new 20001200 (14)
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=74)
info:pbuf_alloc(length=74) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:ip_input: iphdr->dest 0x4201a8c0 netif->ip_addr 0x4201a8c0 (0x1a8c0, 0x1a8c0, 0x42000000)
info:ip4_input: packet accepted on interface en
info:ip4_input: 
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62752      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|   64  |    1  |    0x01a8     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (dest)
info:+-------------------------------+
info:ip4_input: p->len 60 p->tot_len 60
info:pbuf_remove_header: old 2000120e new 20001222 (20)
info:icmp_input: ping
info:pbuf_add_header: old 20001222 new 20001200 (34)
info:pbuf_remove_header: old 20001200 new 20001222 (34)
info:pbuf_add_header: old 20001222 new 2000120e (20)
info:ip4_output_if: en1
info:IP header:
info:+-------------------------------+
info:| 4 | 5 |  0x00 |        60     | (v, hl, tos, len)
info:+-------------------------------+
info:|    62752      |000|       0   | (id, flags, offset)
info:+-------------------------------+
info:|  255  |    1  |    0x42a7     | (ttl, proto, chksum)
info:+-------------------------------+
info:|  192  |  168  |    1  |   66  | (src)
info:+-------------------------------+
info:|  192  |  168  |    1  |  102  | (dest)
info:+-------------------------------+
info:ip4_output_if: call netif->output()
info:pbuf_add_header: old 2000120e new 20001200 (14)
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
>> EXTI1_IRQHandler() : (EXTI_GetITStatus(EXTI_Line1) != RESET)
info:pbuf_alloc(length=60)
info:pbuf_alloc(length=60) == 200011f0
info:pbuf_remove_header: old 20001200 new 2000120e (14)
info:autoip_arp_reply()
info:pbuf_free(200011f0)
info:pbuf_free: deallocating 200011f0
i_loop_cnt = 10

总结

看第三方的教程和资料,和自己作一遍的体会完全不一样。
有些细节,教程和资料上压根都没说,自己做了试验才有体会。

e.g.
为啥要移植这个文件过来?
这个文件哪来的?
这个要给lwip提供的函数咋实现?
如果只想打印某类lwip通讯处理的报错信息(e.g. tcp通讯错误, 内存分配失败), 怎么整?

备注 - 2020_0223_1807
用中断方式响应网络请求有问题,放了一会,再ping就没响应了。
网上的解决方法:

void
ethernetif_input(struct netif *netif)
{// struct ethernetif *ethernetif;// struct eth_hdr *ethhdr;struct pbuf* p = NULL;int i_pkt_len = 0; // 包长度// ethernetif = netif->state;do {/* move received packet into a new pbuf */p = low_level_input(netif);if (NULL == p) {/* if no packet could be read, silently ignore this */break;}/* pass all packets to ethernet_input, which decides what packets it supports */if (netif->input(p, netif) != ERR_OK) {LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));}pbuf_free(p);p = NULL;// 检查网卡接收缓冲区内是否还有没处理的包, 直到全部处理完, 再出去// 防止网卡缓冲区内还有包,导致数据堆积, 不再响应网卡中断i_pkt_len = enc28j60Read(EPKTCNT);if (0 == i_pkt_len) {// 收到的以太网数据包长度   EPKCNT中记录了接收到的以太网包的数据长度信息;break;} else {// 提示一下,有下一个包要处理, 包长度为i_pkt_lenLWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input() : have next %d recv data need process\n", i_pkt_len));}} while (1);
}

用网上的解决方法不好使,会出现以下报错
我猜: 中断一来就处理或者处理完一个包,继续处理网卡接收缓冲区内剩下的接收内容,可能包还没收全(因为通过调试,看到处理的包有的才4个字节,这就不是一个完整的包),导致包分析无效,再后续的包处理就不对了(字节错开了,不是从真正的包头开始处理的)。

assert:Assertion "pbuf_free: p->ref > 0" failed at line 753 in lwip\core\pbuf.c
info:pbuf_free: 20001234 has ref 255, ending here.

刚才试了,ping设备可以ping的通,但是MDK打印出的ITM信息,确实有上述报错。这样虽然能用,却不是规范的解决方法。

我用的时候是带操作系统的,这问题先放这。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 大连哪里做大连哪做大连双眼皮加开眼角

    ...

    2024/4/13 11:36:12
  2. angular中组件changeDetection为ChangeDetectionStrategy.OnPush时的学习

    注&#xff1a;我用的angular 8 一个angular应用是由组件树组成的&#xff0c;changeDetection是其中比较深的部分&#xff0c;我也不懂哈。 angular中changeDetection中的策略有这样的描述&#xff1a; 总而言之&#xff0c;对于一个组件而言&#xff0c;2中changeDetectio…...

    2024/4/13 11:36:27
  3. 「转载」Angular系列之变化检测(Change Detection)

    https://segmentfault.com/a/1190000010928087...

    2024/4/17 12:48:24
  4. 大连哪里整双眼皮好

    ...

    2024/4/13 11:36:12
  5. 大连董萍双眼皮图片

    ...

    2024/4/5 11:41:18
  6. 春天割双眼皮多少钱

    ...

    2024/4/5 11:41:21
  7. Angularjs 的 ngInfiniteScroll 的使用方法

    来源&#xff1a;http://www.cnblogs.com/JamKong/p/5586629.html 一、介绍 ngInfiniteScroll 是一个 AngularJS 的扩展指令&#xff0c;实现了网页的无限滚动的功能&#xff0c;也就是相当于页面滚动到最底部的时候自动加载更多内容。 二、使用方法 引入js库 1 <script typ…...

    2024/4/13 11:36:32
  8. 10分钟快速上手angular cdk

    coercion 常用类型转换工具 angular/cdk/coercion 常用类型转换工具 import { Component, OnInit } from "angular/core"; import {coerceArray,coerceBooleanProperty,coerceNumberProperty,_isNumberValue } from "angular/cdk/coercion"; Component({se…...

    2024/4/13 11:36:42
  9. 深究AngularJS——ng-drag、ng-drop

    1.相关地址&#xff1a; 插件下载&#xff1a;https://github.com/fatlinesofcode/ngDraggable/blob/master/ngDraggable.js data-drag形式没用过&#xff0c;但找到了两个相关链接 http://codef0rmer.github.io/angular-dragdrop/#!/#%2F http://benohead.com/drag-drop-w…...

    2024/4/16 3:09:56
  10. 第1章基本的软件需求

    第1章基本的软件需求“喂,是P h i l吗?我是人力资源部的M a r i a,我们在使用你编写的职员系统时遇到一个问题,一个职员想把她的名字改成Sparkle Starlight,而系统不允许,你能帮帮忙吗?”“她嫁给了一个姓Starlight 的人吗?” P h i l问道。“不,她没有结婚,而仅仅是…...

    2024/4/13 11:36:42
  11. Angular5 自定义scrollbar样式之 ngx-perfect-scollbar

    版本 angular 5.0ngx-perfect-scrollbar ^5.3.5为什么不用 ngx-perfect-scrollbar 最新的版本 v7 呢&#xff1f; 因为它报错啊&#xff01;&#xff01;&#xff01; 每次init的时候&#xff0c;就报一个Object() is not a function。 根据GitHub上热心网友的建议&#xff0c;…...

    2024/4/13 11:36:27
  12. 成都双眼皮成美ok

    ...

    2024/4/13 11:37:02
  13. ng中infinite-scroll插件无限请求问题解决方法

    在使用angular开发移动端页面的童鞋们&#xff0c;有时要做到上拉加载&#xff0c;虽然jquery有很多插件可以满足这个效果&#xff0c;但是我们要知道使用angualr项目就尽量不要再使用jquery&#xff0c;因此ng的infinite-scroll上拉加载就很有作用了&#xff0c;但是使用的小伙…...

    2024/4/13 11:37:27
  14. 【推荐】[网址]PHP各种开源网站系统、cms系统一览[持续更新]

    2019独角兽企业重金招聘Python工程师标准>>> 开源的网站系统很多,今天小编统计整理一下现在流行的各种开源系统、cms推荐,分享给大家参考使用,如果大家有好的资源分享,也请在本文留言评论! 1.cms系统 1)知名cms dedecms: http://www.dedecms.com/ 优点:免…...

    2024/4/13 11:37:27
  15. jQuery EasyUI入门

    EasyUI 简介 Easyui是一种基于jQuery、Angular.、Vue和React的用户界面插件集合&#xff0c; easyui为创建现代化&#xff0c;互动&#xff0c;JavaScript应用程序&#xff0c;提供必要的功能&#xff0c;使用easyui你不需要写很多代码&#xff0c;你只需要通过编写一些简单HTM…...

    2024/4/5 16:18:34
  16. Angularjs和bootstrap、jquery和easyUI的各自主要功能

    开始做app项目以来&#xff0c;一直使用着AngularJS和bootstrap这两个工具&#xff0c;但还真没仔细想过这两个工具与jQuery和easyui有什么区别&#xff0c;各自负责怎样的功能部分&#xff0c;今天有些时间&#xff0c;来总结一下这其间的区别和这些工具各自能实现的功能。 1…...

    2024/4/16 0:55:34
  17. 长沙割双眼皮雅美优选

    ...

    2024/4/5 16:18:34
  18. easyui序号列显示NaN

    错因&#xff1a;JQuery 版本不一致。 应该更改为1.8.3转载于:https://www.cnblogs.com/taony/p/4922961.html...

    2024/4/13 11:37:07
  19. html easyui怎么实现折叠面板,如何通过EasyUI快速构建折叠面板效果

    通过外部引入EasyUI插件后再通过添加 easyui-accordion类到div标记中来实现折叠面板的效果今天将要向大家介绍的是如何通过jQuery easyui插件来快速制作出折叠面板的效果(类似于手风琴效果)。接下来在文章中将和大家详细介绍如何实现这个效果的EasyUIEasyUI是一种基于jQuery、A…...

    2024/4/13 11:37:27
  20. easyui(一)

    什么是easyui easyui是一种基于jQuery、Angular.、Vue和React的用户界面插件集合。 easyui为创建现代化&#xff0c;互动&#xff0c;JavaScript应用程序&#xff0c;提供必要的功能。 第一先导她的架包 在创文件夹 然后把架包导进去 ctrlshiflr 查找本工作区间打开的工程…...

    2024/4/13 11:37:22

最新文章

  1. C++修炼之路之反向迭代器和非模板参数,模板特化,分离编译

    目录 前言 一&#xff1a;反向迭代器 二&#xff1a;非类型模板参数 三&#xff1a;模板的特化 四&#xff1a;模板的分离编译 五&#xff1a;模板的优点与缺点 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 前言 在vector&am…...

    2024/4/19 3:31:32
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. AI小程序的创业方向:深度思考与逻辑引领

    随着人工智能技术的快速发展&#xff0c;AI小程序逐渐成为创业的新热点。在这个充满机遇与挑战的时代&#xff0c;我们有必要深入探讨AI小程序的创业方向&#xff0c;以把握未来的发展趋势。 一、目标市场定位 首先&#xff0c;我们要明确目标市场。针对不同的用户需求&#x…...

    2024/4/17 8:07:05
  4. 【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)

    目录 前言 什么是面向对象&#xff1f; 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类对象的存储方式 this指针 结语 前言 最早的C版本&#xff08;C with classes&#xff09;中&#xff0c;最先加上的就是类的机制&#xff0c;它构成…...

    2024/4/18 0:06:53
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/18 0:33:31
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/18 22:36:36
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/18 9:45:31
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/17 2:33:17
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/17 7:50:46
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/18 3:56:01
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/18 3:56:04
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/18 3:55:30
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/18 3:55:54
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/18 3:55:45
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/17 21:50:30
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/15 13:53:08
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/15 9:16:52
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/18 9:24:29
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/18 3:56:18
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/18 3:55:57
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/18 3:55:50
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/15 23:28:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/18 3:56:20
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/18 3:56:11
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57