最快最简单的移植LWIP协议栈,可改可不改的东西统一不修改。后期学会了有能力了再回过头来修改,操作复杂理论复杂,同时讲解对新手不是很友好,故此此文档只讲操作无任何理论讲解。
零、所需文件及环境
1、第四章建立好的串口2当调试口程序
2、编译环境MDK5(KEIL5)
3、一个STM32F407VET6硬件
4、一个下载器j-link 或 st-link等
5.代码编辑器 Notepad++ (可以不要 用记事本也能编译 都是习惯的问题)
6.USB转TTL设备 用于连接电脑串口助手
7. LWIP 2.1.2源码 lwIP - A Lightweight TCP/IP stack - Summary [Savannah]
8.ST以太网库https://www.st.com.cn/zh/embedded-software/stsw-stm32070.html#
0.1 LWIP 2.1.2源码下载 高版本需要自己实验 稳定性来说降版本最好
0.2 ST以太网库下载 需要登录ST账号
0.3 解压三个文件
壹、复制第三章串口2当调试口程序
1.1 第0章为工程模版 但是真正应用时 灯、定时器、调试口 不管啥程序这仨都会用到 所以以后会把第三章程序当做我自己的基础工程。
1.2 复制第三章程序并修改名字
贰、添加及修改ST以太网库
2.1 添加以太网库 将STM32F4x7_ETH_LwIP_V1.1.1/Libraries文件夹下STM32F4x7_ETH_Driver文件夹复制到咱自己的Libraries文件夹下
2.2 进入STM32F4x7_ETH_Driver/inc文件夹,将stm32f4x7_eth_conf_template.h 重命名为stm32f4x7_eth_conf.h
2.3 将以太网库添加进工程文件并添加头文件路径
2.4 修改stm32f4x7_eth_conf.h
#ifndef __STM32F4x7_ETH_CONF_H
#define __STM32F4x7_ETH_CONF_H
#include "stm32f4xx.h"#include "BSP_DELAY.h"
#define USE_ENHANCED_DMA_DESCRIPTORS
//如果使用自己定义的延时函数的话就注销掉下面一行代码,否则使用
//默认的低精度延时函数#define USE_Delay //使用默认延时函数,因此注销掉
#ifdef USE_Delay
// #include "main.h"
#define _eth_delay_ BSP_DELAY_ms //Delay为用户自己提供的高精度延时函数
#else
#define _eth_delay_ ETH_Delay //默认的_eth_delay功能函数延时精度差
#endif#ifdef CUSTOM_DRIVER_BUFFERS_CONFIG
//重新定义以太网接收和发送缓冲区的大小和数量
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE //接收缓冲区的大小
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE //发送缓冲区的大小
#define ETH_RXBUFNB 20 //接收缓冲区数量
#define ETH_TXBUFNB 5 //发送缓冲区数量
#endif//*******************PHY配置块*******************
#ifdef USE_Delay
#define PHY_RESET_DELAY ((uint32_t)0x000000FF) //PHY复位延时
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) //PHY配置延时
#define ETH_REG_WRITE_DELAY ((uint32_t)0x00000001) //向以太网寄存器写数据时的延时
#else
#define PHY_RESET_DELAY ((uint32_t)0x000FFFFF) //PHY复位延时
#define PHY_CONFIG_DELAY ((uint32_t)0x00FFFFFF) //PHY配置延时
#define ETH_REG_WRITE_DELAY ((uint32_t)0x0000FFFF) //向以太网寄存器写数据时的延时
#endif//LAN8720 PHY芯片的状态寄存器
#define PHY_SR ((uint16_t)31) //LAN8720的PHY状态寄存器地址
#define PHY_SPEED_STATUS ((uint16_t)0x0004) //LAN8720 PHY速度值掩码
#define PHY_DUPLEX_STATUS ((uint16_t)0x00010) //LAN8720 PHY连接状态值掩码
#endif
2.5 打开stm32f4x7_eth.c 屏蔽66-102行 这几个数组会BSP_LAN8720.c里面定义
2.6 编译一下 没有错误 如果有其他错误根据错误类型修改
叁、编写BSP_LAN8720.c与BSP_LAN8720.h代码
3.1复制BSP_LED文件夹,并重命名BSP_LAN8720
3.2 打开BSP_LAN8720.c修改为
#include "BSP_LAN8720.h"
#include "stm32f4x7_eth.h"
#include "BSP_DELAY.h"//#include "BSP_DEBUG.h"
#include "BSP_LED.h"
__align(4) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB]; //以太网DMA接收描述符数据结构体指针
__align(4) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB]; //以太网DMA发送描述符数据结构体指针
__align(4) uint8_t Rx_Buff[ETH_RX_BUF_SIZE*ETH_RXBUFNB]; //以太网底层驱动接收buffers指针
__align(4) uint8_t Tx_Buff[ETH_TX_BUF_SIZE*ETH_TXBUFNB]; //以太网底层驱动发送buffers指针static void ETHERNET_NVICConfiguration(void);
//LAN8720初始化
//返回值:0,成功;
// 其他,失败
uint8_t LAN8720_Init(void)
{
uint8_t rval=0;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIO时钟 RMII接口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能SYSCFG时钟
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); //MAC和PHY之间使用RMII接口/*网络引脚设置 RMII接口
ETH_MDIO -------------------------> PA2
ETH_MDC --------------------------> PC1
ETH_RMII_REF_CLK------------------> PA1
ETH_RMII_CRS_DV ------------------> PA7
ETH_RMII_RXD0 --------------------> PC4
ETH_RMII_RXD1 --------------------> PC5
ETH_RMII_TX_EN -------------------> PB11
ETH_RMII_TXD0 --------------------> PB12
ETH_RMII_TXD1 --------------------> PB13
ETH_RESET-------------------------> PB14*/
//配置PA1 PA2 PA7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);//配置PC1,PC4 and PC5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
//配置PG11, PG14 and PG13
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH);
//配置PD3为推完输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推完输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
LAN8720_RST=0; //硬件复位LAN8720
BSP_DELAY_ms(50);
LAN8720_RST=1; //复位结束
ETHERNET_NVICConfiguration();
rval=ETH_MACDMA_Config();
return !rval; //ETH的规则为:0,失败;1,成功;所以要取反一下
}//以太网中断分组配置
void ETHERNET_NVICConfiguration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn; //以太网中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0X00; //中断寄存器组2最高优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0X01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//得到8720的速度模式
//返回值:
//001:10M半双工
//101:10M全双工
//010:100M半双工
//110:100M全双工
//其他:错误.
uint8_t LAN8720_Get_Speed(void)
{
uint8_t speed;
speed=((ETH_ReadPHYRegister(0x00,31)&0x1C)>>2); //从LAN8720的31号寄存器中读取网络速度和双工模式
return speed;
}uint16_t LAN8720_Get_State(void)
{
uint16_t State = 0;
State = ETH_ReadPHYRegister(0x00,1); //从LAN8720的31号寄存器中读取网络速度和双工模式
return State;
}uint16_t LAN8720_Get_State_TEXT(uint8_t REG)
{
uint16_t State = 0;
State = ETH_ReadPHYRegister(0x00,REG); //从LAN8720的31号寄存器中读取网络速度和双工模式
return State;
}
/
//以下部分为STM32F407网卡配置/接口函数.//初始化ETH MAC层及DMA配置
//返回值:ETH_ERROR,发送失败(0)
// ETH_SUCCESS,发送成功(1)
uint8_t ETH_MACDMA_Config(void)
{
uint8_t rval;
ETH_InitTypeDef ETH_InitStructure;
//使能以太网时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
ETH_DeInit(); //AHB总线重启以太网
ETH_SoftwareReset(); //软件重启网络
while (ETH_GetSoftwareResetStatus() == SET){;}//等待软件重启网络完成
// printf("ETH_MACDMA_Config ok\r\n");
ETH_StructInit(Ð_InitStructure); //初始化网络为默认值///网络MAC参数设置
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable; //开启网络自适应功能
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable; //关闭反馈
ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable; //关闭重传功能
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; //关闭自动去除PDA/CRC功能
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; //关闭接收所有的帧
ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允许接收所有广播帧
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; //关闭混合模式的地址过滤
ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//对于组播地址使用完美地址过滤
ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; //对单播地址使用完美地址过滤
#ifdef CHECKSUM_BY_HARDWARE
ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; //开启ipv4和TCP/UDP/ICMP的帧校验和卸载
#endif
//当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储转发模式中要保证整个帧存储在FIFO中,
//这样MAC能插入/识别出帧校验值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧
ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; //开启丢弃TCP/IP错误帧
ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable; //开启接收数据的存储转发模式
ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable; //开启发送数据的存储转发模式ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable; //禁止转发错误帧
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable; //不转发过小的好帧
ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable; //打开处理第二帧功能
ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; //开启DMA传输的地址对齐功能
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; //开启固定突发功能
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; //DMA发送的最大突发长度为32个节拍
ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; //DMA接收的最大突发长度为32个节拍
ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
ETH_Init(Ð_InitStructure,LAN8720_PHY_ADDRESS); //配置ETH
ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE); //使能以太网接收中断
rval=ETH_Init(Ð_InitStructure,LAN8720_PHY_ADDRESS); //配置ETH
if(rval==ETH_SUCCESS)//配置成功
{
ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE); //使能以太网接收中断
// printf("ETH_DMAITConfig OK\r\n");
}
return rval;
}extern void lwip_pkt_handle(void); //在lwip_comm.c里面定义
//以太网中断服务函数
void ETH_IRQHandler(void)
{
while(ETH_GetRxPktSize(DMARxDescToGet)!=0) //检测是否收到数据包
{
lwip_pkt_handle();
}
ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}
//接收一个网卡数据包
//返回值:网络数据包帧结构体
FrameTypeDef ETH_Rx_Packet(void)
{
uint32_t framelength=0;
FrameTypeDef frame={0,0};
//检查当前描述符,是否属于ETHERNET DMA(设置的时候)/CPU(复位的时候)
if((DMARxDescToGet->StatusÐ_DMARxDesc_OWN)!=(uint32_t)RESET)
{
frame.length=ETH_ERROR;
if ((ETH->DMASRÐ_DMASR_RBUS)!=(uint32_t)RESET)
{
ETH->DMASR = ETH_DMASR_RBUS;//清除ETH DMA的RBUS位
ETH->DMARPDR=0;//恢复DMA接收
}
return frame;//错误,OWN位被设置了
}
if(((DMARxDescToGet->StatusÐ_DMARxDesc_ES)==(uint32_t)RESET)&&
((DMARxDescToGet->Status & ETH_DMARxDesc_LS)!=(uint32_t)RESET)&&
((DMARxDescToGet->Status & ETH_DMARxDesc_FS)!=(uint32_t)RESET))
{
framelength=((DMARxDescToGet->StatusÐ_DMARxDesc_FL)>>ETH_DMARxDesc_FrameLengthShift)-4;//得到接收包帧长度(不包含4字节CRC)
frame.buffer = DMARxDescToGet->Buffer1Addr;//得到包数据所在的位置
}else framelength=ETH_ERROR;//错误
frame.length=framelength;
frame.descriptor=DMARxDescToGet;
//更新ETH DMA全局Rx描述符为下一个Rx描述符
//为下一次buffer读取设置下一个DMA Rx描述符
DMARxDescToGet=(ETH_DMADESCTypeDef*)(DMARxDescToGet->Buffer2NextDescAddr);
return frame;
}
//发送一个网卡数据包
//FrameLength:数据包长度
//返回值:ETH_ERROR,发送失败(0)
// ETH_SUCCESS,发送成功(1)
uint8_t ETH_Tx_Packet(uint16_t FrameLength)
{
//检查当前描述符,是否属于ETHERNET DMA(设置的时候)/CPU(复位的时候)
if((DMATxDescToSet->StatusÐ_DMATxDesc_OWN)!=(uint32_t)RESET)return ETH_ERROR;//错误,OWN位被设置了
DMATxDescToSet->ControlBufferSize=(FrameLengthÐ_DMATxDesc_TBS1);//设置帧长度,bits[12:0]
DMATxDescToSet->Status|=ETH_DMATxDesc_LS|ETH_DMATxDesc_FS;//设置最后一个和第一个位段置位(1个描述符传输一帧)
DMATxDescToSet->Status|=ETH_DMATxDesc_OWN;//设置Tx描述符的OWN位,buffer重归ETH DMA
if((ETH->DMASRÐ_DMASR_TBUS)!=(uint32_t)RESET)//当Tx Buffer不可用位(TBUS)被设置的时候,重置它.恢复传输
{
ETH->DMASR=ETH_DMASR_TBUS;//重置ETH DMA TBUS位
ETH->DMATPDR=0;//恢复DMA发送
}
//更新ETH DMA全局Tx描述符为下一个Tx描述符
//为下一次buffer发送设置下一个DMA Tx描述符
DMATxDescToSet=(ETH_DMADESCTypeDef*)(DMATxDescToSet->Buffer2NextDescAddr);
return ETH_SUCCESS;
}
//得到当前描述符的Tx buffer地址
//返回值:Tx buffer地址
uint32_t ETH_GetCurrentTxBuffer(void)
{
return DMATxDescToSet->Buffer1Addr;//返回Tx buffer地址
}
3.3 打开BSP_LAN8720.h修改为
#ifndef __BSP_LAN8720_H
#define __BSP_LAN8720_H
//#include "BSP_SYS.h"
#include "stm32f4x7_eth.h"
#define LAN8720_PHY_ADDRESS 0x00 //LAN8720 PHY芯片地址.
#define LAN8720_RST PBout(14) //LAN8720复位引脚
extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB]; //以太网DMA接收描述符数据结构体指针
extern ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB]; //以太网DMA发送描述符数据结构体指针
extern uint8_t Rx_Buff[ETH_RX_BUF_SIZE*ETH_RXBUFNB]; //以太网底层驱动接收buffers指针
extern uint8_t Tx_Buff[ETH_TX_BUF_SIZE*ETH_TXBUFNB]; //以太网底层驱动发送buffers指针extern ETH_DMADESCTypeDef *DMATxDescToSet; //DMA发送描述符追踪指针
extern ETH_DMADESCTypeDef *DMARxDescToGet; //DMA接收描述符追踪指针
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos; //DMA最后接收到的帧信息指针
extern uint8_t LAN8720_Init(void);
extern uint8_t LAN8720_Get_Speed(void);
extern uint16_t LAN8720_Get_State(void);
extern uint8_t ETH_MACDMA_Config(void);
extern FrameTypeDef ETH_Rx_Packet(void);
extern uint8_t ETH_Tx_Packet(uint16_t FrameLength);
extern uint32_t ETH_GetCurrentTxBuffer(void);
extern uint16_t LAN8720_Get_State_TEXT(uint8_t REG);
#endif
3.3 将BSP_LAN8720.c添加进工程文件并添加头文件路径
3.4 编译一下 一个error,以太网DMA接收中断函数ETH_IRQHandler()函数调用lwip_pkt_handle()函数,而此函数暂时未定义。如果有错误注意刚复制的文件 里面有没有乱码 注意修改
肆、添加LWIP源文件
4.1 Libraries文件夹新建Other_Libraries/LWIP文件夹并将之前解压的lwip-2.1.2文件夹复制到此。整体复制有好多没用的刚开始不知道应该删除那些就别乱动,学会了、能用了再说。
4.2 新建工程目录
4.3 将LWIP/lwip-2.1.2/src/api文件夹下九个文件添加至工程LWIP/API
4.4 将LWIP/lwip-2.1.2/src/core文件夹下20个文件添加至工程LWIP/CORE
4.5 将LWIP/lwip-1.4.1/src/core/ipv4文件夹下8个文件添加至工程LWIP/CORE/IPV4
4.6 将LWIP/lwip-2.1.2/src/netif文件夹下7个文件添加至工程LWIP/NETIF
4.7 添加刚才四个分组的头文件·
4.8 编译一下 44个error 不要怕缺少点文件,接下来编写这些文件
伍、添加中间文件
5.0 准备lwip文件时下载过两个文件这是其中另一个contrib-2.1.0文件中七个文件+自己写的ethernetif.h
5.1 在LWIP文件夹中建立arch文件夹,将上述七个复制进来,同时新建ethernetif.h
5.2 修改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 <[email protected]>
*
*/
#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#ifdef _MSC_VER
#if _MSC_VER >= 1910
#include <errno.h> /* use MSVC errno for >= 2017 */
#else
#define LWIP_PROVIDE_ERRNO /* provide errno for MSVC pre-2017 */
#endif
#else /* _MSC_VER */
#define LWIP_PROVIDE_ERRNO /* provide errno for non-MSVC */
#endif /* _MSC_VER *//* 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 */
#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 */
#define PACK_STRUCT_USE_INCLUDES#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)#ifdef _MSC_VER
/* C runtime functions redefined */
#if _MSC_VER < 1910
#define snprintf _snprintf
#endif
#define strdup _strdup
#endif/* 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:
*/
#if !defined(LWIP_TESTMODE) || !LWIP_TESTMODE
void lwip_win32_platform_diag(const char *format, ...);
#define LWIP_PLATFORM_DIAG(x) lwip_win32_platform_diag x
#endif#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 */
5.3 修改ethernetif.c
#include "ethernetif.h"
#include "BSP_LAN8720.h"
#include "lwip_comm.h"
#include "netif/etharp.h"
#include "string.h"//由ethernetif_init()调用用于初始化硬件
//netif:网卡结构体指针
//返回值:ERR_OK,正常
// 其他,失败
static err_t low_level_init(struct netif *netif)
{
#ifdef CHECKSUM_BY_HARDWARE
int i;
#endif
netif->hwaddr_len = ETHARP_HWADDR_LEN; //设置MAC地址长度,为6个字节
//初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复
netif->hwaddr[0]=lwipdev.mac[0];
netif->hwaddr[1]=lwipdev.mac[1];
netif->hwaddr[2]=lwipdev.mac[2];
netif->hwaddr[3]=lwipdev.mac[3];
netif->hwaddr[4]=lwipdev.mac[4];
netif->hwaddr[5]=lwipdev.mac[5];
netif->mtu=1500; //最大允许传输单元,允许该网卡广播和ARP功能netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP;
ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr); //向STM32F4的MAC地址寄存器中写入MAC地址
ETH_DMATxDescChainInit(DMATxDscrTab, Tx_Buff, ETH_TXBUFNB);
ETH_DMARxDescChainInit(DMARxDscrTab, Rx_Buff, ETH_RXBUFNB);
#ifdef CHECKSUM_BY_HARDWARE //使用硬件帧校验
for(i=0;i<ETH_TXBUFNB;i++) //使能TCP,UDP和ICMP的发送帧校验,TCP,UDP和ICMP的接收帧校验在DMA中配置了
{
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
}
#endif
ETH_Start(); //开启MAC和DMA
return ERR_OK;
}
//用于发送数据包的最底层函数(lwip通过netif->linkoutput指向该函数)
//netif:网卡结构体指针
//p:pbuf数据结构体指针
//返回值:ERR_OK,发送正常
// ERR_MEM,发送失败
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
u8 res;
struct pbuf *q;
int l = 0;
u8 *buffer=(u8 *)ETH_GetCurrentTxBuffer();
for(q=p;q!=NULL;q=q->next)
{
memcpy((u8_t*)&buffer[l], q->payload, q->len);
l=l+q->len;
}
res=ETH_Tx_Packet(l);
if(res==ETH_ERROR)return ERR_MEM;//返回错误状态
return ERR_OK;
}
///用于接收数据包的最底层函数
//neitif:网卡结构体指针
//返回值:pbuf数据结构体指针
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p, *q;
u16_t len;
int l =0;
FrameTypeDef frame;
u8 *buffer;
p = NULL;
frame=ETH_Rx_Packet();
len=frame.length;//得到包大小
buffer=(u8 *)frame.buffer;//得到包数据地址
p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL);//pbufs内存池分配pbuf
if(p!=NULL)
{
for(q=p;q!=NULL;q=q->next)
{
memcpy((u8_t*)q->payload,(u8_t*)&buffer[l], q->len);
l=l+q->len;
}
}
frame.descriptor->Status=ETH_DMARxDesc_OWN;//设置Rx描述符OWN位,buffer重归ETH DMA
if((ETH->DMASRÐ_DMASR_RBUS)!=(u32)RESET)//当Rx Buffer不可用位(RBUS)被设置的时候,重置它.恢复传输
{
ETH->DMASR=ETH_DMASR_RBUS;//重置ETH DMA RBUS位
ETH->DMARPDR=0;//恢复DMA接收
}
return p;
}
//网卡接收数据(lwip直接调用)
//netif:网卡结构体指针
//返回值:ERR_OK,发送正常
// ERR_MEM,发送失败
err_t ethernetif_input(struct netif *netif)
{
err_t err;
struct pbuf *p;
p=low_level_input(netif);
if(p==NULL) return ERR_MEM;
err=netif->input(p, netif);
if(err!=ERR_OK)
{
LWIP_DEBUGF(NETIF_DEBUG,("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
return err;
}
//使用low_level_init()函数来初始化网络
//netif:网卡结构体指针
//返回值:ERR_OK,正常
// 其他,失败
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif!=NULL",(netif!=NULL));
#if LWIP_NETIF_HOSTNAME //LWIP_NETIF_HOSTNAME
netif->hostname="lwip"; //初始化名称
#endif
netif->name[0]=IFNAME0; //初始化变量netif的name字段
netif->name[1]=IFNAME1; //在文件外定义这里不用关心具体值
netif->output=etharp_output;//IP层发送数据包函数
netif->linkoutput=low_level_output;//ARP模块发送数据包函数
low_level_init(netif); //底层硬件初始化函数
return ERR_OK;
}
5.4 修改ethernetif.h
#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__
#include "lwip/err.h"
#include "lwip/netif.h"//网卡的名字
#define IFNAME0 'e'
#define IFNAME1 'n'
err_t ethernetif_init(struct netif *netif);
err_t ethernetif_input(struct netif *netif);
#endif
5.5 修改lwipopts.h
#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
#define LWIP_DEBUG 0
// 调试模式定义, 可以打印调试信息
// 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
//#ifdef 0
// 日志级别
// /** 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_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define DNS_DEBUG LWIP_DBG_OFF
#define AUTOIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define IGMP_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#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 10
/* 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 20/* 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 0
#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 */
5.5 修改sys_arch.c
/*
* 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 <[email protected]>
* Simon Goldschmidt
*
*///#include "main.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>#include <stdarg.h>
#include <string.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 uint32_t lwip_localtime;//lwip本地时间计数器,单位:ms
// 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 lwip_localtime;
}// 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;
//}
5.6 将sys_arch.c、ethernetif.c添加进LWIP/ARCH中,同时添加头文件
5.7 将定时器修改为1ms定时器
5.8 修改BSP_TIMER.c文件
5.9 编译一下 还是3个error 如果有其他乱码注意修改
陆、添加LWIP通用文件
LWIP通用文件共两个文件,lwip_comm.c、lwip_comm.c正点原子写的
6.1 编写lwip_comm.c文件
#include "lwip_comm.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/init.h"
#include "ethernetif.h"
#include "BSP_DEBUG.h"
#include <stdio.h>
//#include "BSP_Hardware_Option.h"
__lwip_dev lwipdev; //lwip控制结构体
struct netif lwip_netif; //定义一个全局的网络接口extern u32 memp_get_memorysize(void); //在memp.c里面定义
//extern u8_t *memp_memory; //在memp.c里面定义.
//extern u8_t *ram_heap; //在mem.c里面定义.u32 TCPTimer=0; //TCP查询计时器
u32 ARPTimer=0; //ARP查询计时器
u32 lwip_localtime; //lwip本地时间计数器,单位:ms
//lwip中mem和memp的内存申请
//返回值:0,成功;
// 其他,失败
//u8 lwip_comm_mem_malloc(void)
//{
// u32 mempsize;
// u32 ramheapsize;
// mempsize=memp_get_memorysize(); //得到memp_memory数组大小
// memp_memory=mymalloc(SRAMIN,mempsize); //为memp_memory申请内存
// ramheapsize=LWIP_MEM_ALIGN_SIZE(MEM_SIZE)+2*LWIP_MEM_ALIGN_SIZE(4*3)+MEM_ALIGNMENT;//得到ram heap大小
// ram_heap=mymalloc(SRAMIN,ramheapsize); //为ram_heap申请内存
// if(!memp_memory||!ram_heap)//有申请失败的
// {
// lwip_comm_mem_free();
// return 1;
// }
// return 0;
//}
lwip中mem和memp内存释放
//void lwip_comm_mem_free(void)
//{
// myfree(SRAMIN,memp_memory);
// myfree(SRAMIN,ram_heap);
//}
//lwip 默认IP设置
//lwipx:lwip控制结构体指针
void lwip_comm_default_ip_set(__lwip_dev *lwipx,unsigned char node_id)
{
//MAC地址设置(高三字节固定为:2.0.0,低三字节用STM32唯一ID)
lwipx->mac[0]=0x43;//高三字节(IEEE称之为组织唯一ID,OUI)地址固定为:2.0.0
lwipx->mac[1]=0x52;
lwipx->mac[2]=0x53;
lwipx->mac[3]=0x43;//低三字节用STM32的唯一ID
lwipx->mac[4]=0x01;lwipx->mac[5]=node_id;
//默认本地IP为:192.168.1.30
lwipx->ip[0]=192;
lwipx->ip[1]=168;
lwipx->ip[2]=1;
lwipx->ip[3]=node_id;
//默认子网掩码:255.255.255.0
lwipx->netmask[0]=255;
lwipx->netmask[1]=255;
lwipx->netmask[2]=255;
lwipx->netmask[3]=0;
//默认网关:192.168.1.1
lwipx->gateway[0]=192;
lwipx->gateway[1]=168;
lwipx->gateway[2]=1;
lwipx->gateway[3]=1;
lwipx->dhcpstatus=0;//没有DHCP
//默认远端IP为:192.168.1.100
lwipx->remoteip[0]=192;
lwipx->remoteip[1]=168;
lwipx->remoteip[2]=1;
lwipx->remoteip[3]=14;
}//LWIP初始化(LWIP启动的时候使用)
//返回值:0,成功
// 1,内存错误
// 2,LAN8720初始化失败
// 3,网卡添加失败.
u8 lwip_comm_init(unsigned char node_id)
{
struct netif *Netif_Init_Flag; //调用netif_add()函数时的返回值,用于判断网络初始化是否成功
struct ip4_addr ipaddr; //ip地址
struct ip4_addr netmask; //子网掩码
struct ip4_addr gw; //默认网关
// if(ETH_Mem_Malloc())return 1; //内存申请失败
// if(lwip_comm_mem_malloc())return 1; //内存申请失败
if(LAN8720_Init())return 2; //初始化LAN8720失败
lwip_init(); //初始化LWIP内核
lwip_comm_default_ip_set(&lwipdev,node_id); //设置默认IP等信息
IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]);
IP4_ADDR(&gw,lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
printf("\r\n");
printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);
printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input);//向网卡列表中添加一个网口
if(Netif_Init_Flag==NULL)return 3;//网卡添加失败
else//网口添加成功后,设置netif为默认值,并且打开netif网口
{
netif_set_default(&lwip_netif); //设置netif为默认网口
netif_set_up(&lwip_netif); //打开netif网口
}
return 0;//操作OK.
}//当接收到数据后调用
void lwip_pkt_handle(void)
{
//从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理
ethernetif_input(&lwip_netif);
}//LWIP轮询任务
void lwip_periodic_handle()
{
//ARP每5s周期性调用一次
if ((lwip_localtime - ARPTimer) >= ARP_TMR_INTERVAL)
{
ARPTimer = lwip_localtime;
etharp_tmr();
}}
6.2 编写lwip_comm.h文件
#ifndef _LWIP_COMM_H
#define _LWIP_COMM_H
#include "BSP_LAN8720.h"#define LWIP_MAX_DHCP_TRIES 4 //DHCP服务器最大重试次数
//lwip控制结构体
typedef struct
{
u8 mac[6]; //MAC地址
u8 remoteip[4]; //远端主机IP地址
u8 ip[4]; //本机IP地址
u8 netmask[4]; //子网掩码
u8 gateway[4]; //默认网关的IP地址
vu8 dhcpstatus; //dhcp状态
//0,未获取DHCP地址;
//1,进入DHCP获取状态
//2,成功获取DHCP地址
//0XFF,获取失败.
}__lwip_dev;
extern __lwip_dev lwipdev; //lwip控制结构体void lwip_pkt_handle(void);
void lwip_periodic_handle(void);
void lwip_comm_default_ip_set(__lwip_dev *lwipx,unsigned char node_id);
u8 lwip_comm_mem_malloc(void);
void lwip_comm_mem_free(void);
u8 lwip_comm_init(unsigned char node_id);
void lwip_dhcp_process_handle(void);#endif
6.3 将lwip_comm.c文件添加至工程HARDWARE中,并添加头文件路径
6.4 编译一下1个error
6.4 把这个勾上 再次编译
柒、修改main.c并编译下载
捌、ping一下
8.1 win+r 打开运行窗口 输入cmd打开命令行
8.2 命令行输入 ping 192.168.1.120 -t
8.3 ping通了 暂时成功 网线记得插上