试验原因
产品板子上用的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\incl
ude\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 which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte 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 application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#define MEMP_NUM_PBUF 16
/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One
per active RAW "connection". */
#define MEMP_NUM_RAW_PCB 3
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 4
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 5
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 8
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#define MEMP_NUM_TCP_SEG 16
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#define MEMP_NUM_SYS_TIMEOUT 17
/* The following four are used only with the sequential API and can be
set 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 used
for sequential API communication and incoming packets. Used in
src/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 of
order. 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 equal
to TCP_SND_BUF. It is the amount of space which must be
available 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 forward
IP packets across network interfaces. If you are going to run lwIP
on 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 of
interfaces. */
#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 ls
return 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 ls
return 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, ...)
{
// 打印格式化字符串的方法 - 1
char 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 use
vsnprintf 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, ...)
{
// 打印格式化字符串的方法 - 2
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); // 这个是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 = -16
case 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_IPV4
netif->output = etharp_output;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->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 other
NVIC_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 warning
if (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_HD
printf("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\
");
#else
printf("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; //外部中断2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0
NVIC_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--ETXI2
EXTI_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 code
GPIO_InitTypeDef GPIO_InitStructure;
// UART/LED的GPIO速度设为50MHZ
// SPI的GPIO速度设置成10MHZ
// 3个LED - PB5, PD3, PD6
GPIO_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; // 口线翻转速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_3; // LED2, LED3 V7 V8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
// 设置外中断1管脚 - PA1
GPIO_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>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_IT_H
#define __STM32F10x_IT_H
#ifdef __cplusplus
extern "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>© 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 where
the 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_len
LWIP_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信息,确实有上述报错。这样虽然能用,却不是规范的解决方法。
我用的时候是带操作系统的,这问题先放这。