首页 > 其他分享 >lwIP——带操作系统(FreeRTOS)移植

lwIP——带操作系统(FreeRTOS)移植

时间:2024-08-12 15:17:59浏览次数:11  
标签:LWIP 操作系统 FreeRTOS CHIP sys netif lwIP ETH define

1. lwIP前期准备

在程序工程中,我们在工程文件夹下创建了一个名为 “lwip”的子文件夹。在“lwip”文件夹下,我们又创建了一个子文件夹:arch 。arch 文件夹用于存放 lwIP 系统的配置文件;

2. 添加lwIP源文件

3. 添加网卡驱动程序

/* Includes ------------------------------------------------------------------*/
#include "bsp_hal_ethernet.h"
/* Private macros ------------------------------------------------------------*/
#define YT8522_RESET_HIGH()             HAL_GPIO_WritePin(YT8522_RESET_GPIO_Port, YT8522_RESET_Pin, GPIO_PIN_SET)
#define YT8522_RESET_LOW()              HAL_GPIO_WritePin(YT8522_RESET_GPIO_Port, YT8522_RESET_Pin, GPIO_PIN_RESET)
#if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE )
    #define YT8522_PHYREGISTER2      0x4F51
    #define YT8522_PHYREGISTER3      0x001C
    
    #define YT8512C_PHYREGISTER2     0x0000
    #define YT8512C_PHYREGISTER3     0x0128
#endif

#define ETH_CHIP_SW_RESET_TO    ((uint32_t)500U)    /* 软件复位等待时间 */
#define ETH_CHIP_MAX_DEV_ADDR   ((uint32_t)31U)     /* PHY地址的最大值 */
#define ETH_CHIP_INIT_TO        ((uint32_t)2000U)   /* 初始化等待时间 */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE )
/* 选择PHY芯片 ---- 自动选择 */
int      PHY_TYPE;
uint16_t ETH_CHIP_PHYSCSR;
uint16_t ETH_CHIP_SPEED_STATUS;
uint16_t ETH_CHIP_DUPLEX_STATUS;
#endif
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
                       PHI IO Functions
*******************************************************************************/
/**
  * @brief  Initializes the MDIO interface GPIO and clocks.
  * @param  None
  * @retval 0 if OK, -1 if ERROR
  */
static int32_t ETH_PHY_IO_Init(void)
{
    /* We assume that MDIO GPIO configuration is already done
     in the ETH_MspInit() else it should be done here
    */

    /* Configure the MDIO Clock */
    HAL_ETH_SetMDIOClockRange(&g_eth_handler);

    return 0;
}
/**
  * @brief  De-Initializes the MDIO interface .
  * @param  None
  * @retval 0 if OK, -1 if ERROR
  */
static int32_t ETH_PHY_IO_DeInit (void)
{
    return 0;
}
/**
  * @brief  Read a PHY register through the MDIO interface.
  * @param  DevAddr: PHY port address
  * @param  RegAddr: PHY register address
  * @param  pRegVal: pointer to hold the register value
  * @retval 0 if OK -1 if Error
  */
static int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
{
    if (HAL_ETH_ReadPHYRegister(&g_eth_handler, DevAddr, RegAddr, pRegVal) != HAL_OK)
    {
        return -1;
    }

    return 0;
}

/**
  * @brief  Write a value to a PHY register through the MDIO interface.
  * @param  DevAddr: PHY port address
  * @param  RegAddr: PHY register address
  * @param  RegVal: Value to be written
  * @retval 0 if OK -1 if Error
  */
static int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
{
    if (HAL_ETH_WritePHYRegister(&g_eth_handler, DevAddr, RegAddr, RegVal) != HAL_OK)
    {
        return -1;
    }

    return 0;
}

/**
  * @brief  Get the time in millisecons used for internal PHY driver process.
  * @retval Time value
  */
static int32_t ETH_PHY_IO_GetTick(void)
{
    return HAL_GetTick();
}
/* Exported macros -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
eth_chip_ioc_tx_t  ETH_CHIP_IOCtx = { ETH_PHY_IO_Init,
                                      ETH_PHY_IO_DeInit,
                                      ETH_PHY_IO_WriteReg,
                                      ETH_PHY_IO_ReadReg,
                                      ETH_PHY_IO_GetTick };
/* Exported functions --------------------------------------------------------*/
void ethernet_reset(void)
{
    YT8522_RESET_LOW();                  /* 硬件复位 */
    HAL_Delay(100);
    YT8522_RESET_HIGH();                 /* 复位结束 */
    HAL_Delay(100);
}
/**
 * @breif       读取以太网芯片寄存器值
 * @param       reg:读取的寄存器地址
 * @retval      无
 */
uint32_t ethernet_read_phy(uint16_t reg)
{
    uint32_t regval;

    HAL_ETH_ReadPHYRegister(&g_eth_handler, ETHERNET_PHY_ADDRESS, reg, &regval);
    return regval;
}
/**
 * @breif       向以太网芯片指定地址写入寄存器值
 * @param       reg   : 要写入的寄存器
 * @param       value : 要写入的寄存器
 * @retval      无
 */
void ethernet_write_phy(uint16_t reg, uint16_t value)
{
    uint32_t temp = value;
    
    HAL_ETH_WritePHYRegister(&g_eth_handler, ETHERNET_PHY_ADDRESS, reg, temp);
}
/**
 * @breif       获得网络芯片的速度模式
 * @param       无
 * @retval      1:100M
                0:10M
 */
uint8_t ethernet_chip_get_speed(void)
{
    uint8_t speed;
    
    if(PHY_TYPE == YT8522) {
        /* 从YT8522的17号寄存器中读取网络速度 */
        speed = ( ( ethernet_read_phy( ETH_CHIP_PHYSCSR ) & ETH_CHIP_SPEED_STATUS ) >> 14 );
    }
    else if(PHY_TYPE == YT8512C) {
        speed = ((ethernet_read_phy(ETH_CHIP_PHYSCSR) & ETH_CHIP_SPEED_STATUS) >> 14);    /* 从YT8512C的17号寄存器中读取网络速度和双工模式 */
    }
    return speed;
}
/*******************************************************************************
                       ETHERNET CHIP
*******************************************************************************/
/**
  * @brief       将IO函数注册到组件对象
  * @param       pobj:设备对象
  * @param       ioctx:保存设备IO功能 
  * @retval      ETH_CHIP_STATUS_OK:OK
  *              ETH_CHIP_STATUS_ERROR:缺少功能
  */
static int32_t eth_chip_regster_bus_io( eth_chip_object_t *pobj, eth_chip_ioc_tx_t *ioctx )
{
    if (!pobj || !ioctx->readreg || !ioctx->writereg || !ioctx->gettick)
    {
        return ETH_CHIP_STATUS_ERROR;
    }

    pobj->io.init = ioctx->init;
    pobj->io.deinit = ioctx->deinit;
    pobj->io.readreg = ioctx->readreg;
    pobj->io.writereg = ioctx->writereg;
    pobj->io.gettick = ioctx->gettick;

    return ETH_CHIP_STATUS_OK;
}
/**
  * @brief       初始化ETH_CHIP并配置所需的硬件资源
  * @param       pobj: 设备对象
  * @retval      ETH_CHIP_STATUS_OK:初始化ETH_CHIP并配置所需的硬件资源成功
                 ETH_CHIP_STATUS_ADDRESS_ERROR:找不到设备地址
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR:不能写入寄存器
                 ETH_CHIP_STATUS_RESET_TIMEOUT:无法执行软件复位
  */
int32_t eth_chip_init( eth_chip_object_t *pobj, eth_chip_ioc_tx_t *ioctx )
{
    uint32_t tickstart = 0;
    uint32_t regvalue = 0;
    uint32_t addr = 0;
    int32_t status = ETH_CHIP_STATUS_OK;
    
    eth_chip_regster_bus_io( pobj, ioctx );
#if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE )
    pobj->io.readreg(addr, PHY_REGISTER2, &regvalue);
    switch (regvalue)
    {
        case YT8522_PHYREGISTER2:{
            pobj->io.readreg(addr, PHY_REGISTER3, &regvalue);//0x0000E928
            regvalue = regvalue >> 10;//0x0000003A
            if( regvalue == 0x3A ) {
                ETH_CHIP_PHYSCSR       = ((uint16_t)0x11);
                ETH_CHIP_SPEED_STATUS  = ((uint16_t)0x4010);
                ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x2000);
                PHY_TYPE               = YT8522;
            }
        }break;
        case YT8512C_PHYREGISTER2:{
            pobj->io.readreg(addr, PHY_REGISTER3, &regvalue);
            if( regvalue == YT8512C_PHYREGISTER3 ) {
                ETH_CHIP_PHYSCSR       = ((uint16_t)0x11);
                ETH_CHIP_SPEED_STATUS  = ((uint16_t)0x4010);
                ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x2000);
                PHY_TYPE               = YT8512C;
            }
        }break;
    }
#else
//
#endif
    if ( pobj->is_initialized == 0 ) {
        if (pobj->io.init != 0) {
            /* MDC时钟 */
            pobj->io.init();
        }
        /* 设置PHY地址为32 */
        pobj->devaddr = ETH_CHIP_MAX_DEV_ADDR + 1;
        /* 主要为了查找PHY地址 */  
        for (addr = 0; addr <= ETH_CHIP_MAX_DEV_ADDR; addr ++) {
            if (pobj->io.readreg(addr, ETH_CHIP_PHYSCSR, &regvalue) < 0) {
                status = ETH_CHIP_STATUS_READ_ERROR;
                /* 无法读取这个设备地址继续下一个地址 */
                continue;
            }
            /* 已经找到PHY地址了 */
            if ( ( regvalue & ETH_CHIP_PHY_COUNT ) == addr ) {
                pobj->devaddr = addr;
                status = ETH_CHIP_STATUS_OK;
                break;
            }
        }
        /* 判断这个PHY地址是否大于32(2^5)*/
        if (pobj->devaddr > ETH_CHIP_MAX_DEV_ADDR) {
            status = ETH_CHIP_STATUS_ADDRESS_ERROR;
        }
        
        /* 如果PHY地址有效 */
        if (status == ETH_CHIP_STATUS_OK) {
            /* 设置软件复位  */
            if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, ETH_CHIP_BCR_SOFT_RESET) >= 0) {
                /* 获取软件重置状态 */
                if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &regvalue) >= 0) {
                    tickstart = ETH_CHIP_SW_RESET_TO;
                    /* 等待软件复位完成或超时  */
                    while ( regvalue & ETH_CHIP_BCR_SOFT_RESET )
                    {
                        if( tickstart != 0 ) {
                            if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &regvalue) < 0)
                            { 
                                status = ETH_CHIP_STATUS_READ_ERROR;
                                break;
                            }
                            HAL_Delay(0);
                            tickstart--;
                        } else {
                            status = ETH_CHIP_STATUS_RESET_TIMEOUT;
                            break;
                        }
                    }
                } else {
                    status = ETH_CHIP_STATUS_READ_ERROR;
                }
            } else {
                status = ETH_CHIP_STATUS_WRITE_ERROR;
            }
        }
    }
    /* 到了这里,初始化完成!!! */
    if (status == ETH_CHIP_STATUS_OK) {
        tickstart =  ETH_CHIP_INIT_TO;
        /* 等待2s进行初始化 */
        while ( tickstart ) {
            tickstart--;
            HAL_Delay(0);
        }
        pobj->is_initialized = 1;
    }
    
    return status;
}
/**
  * @brief       反初始化ETH_CHIP及其硬件资源
  * @param       pobj: 设备对象
  * @retval      ETH_CHIP_STATUS_OK:反初始化失败成功
                 ETH_CHIP_STATUS_ERROR:反初始化失败
  */
int32_t eth_chip_deinit(eth_chip_object_t *pobj)
{
    if (pobj->is_initialized)
    {
        if (pobj->io.deinit != 0)
        {
            if (pobj->io.deinit() < 0)
            {
                return ETH_CHIP_STATUS_ERROR;
            }
        }

        pobj->is_initialized = 0;  
    }

    return ETH_CHIP_STATUS_OK;
}
/**
  * @brief       关闭ETH_CHIP的下电模式
  * @param       pobj: 设备对象
  * @retval      ETH_CHIP_STATUS_OK:关闭成功
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR:不能写寄存器
  */
int32_t eth_chip_disable_power_down_mode(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &readval) >= 0)
    {
        readval &= ~ETH_CHIP_BCR_POWER_DOWN;

        /* 清除下电模式 */
        if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, readval) < 0)
        {
            status =  ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    return status;
}
/**
  * @brief       使能ETH_CHIP的下电模式
  * @param       pobj: 设备对象
  * @retval      ETH_CHIP_STATUS_OK:关闭成功
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR:不能写寄存器
  */
int32_t eth_chip_enable_power_down_mode(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &readval) >= 0)
    {
        readval |= ETH_CHIP_BCR_POWER_DOWN;

        /* 使能下电模式 */
        if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, readval) < 0)
        {
            status =  ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    return status;
}
/**
  * @brief       启动自动协商过程
  * @param       pobj: 设备对象
  * @retval      ETH_CHIP_STATUS_OK:关闭成功
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR:不能写寄存器
  */
int32_t eth_chip_start_auto_nego(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &readval) >= 0)
    {
        readval |= ETH_CHIP_BCR_AUTONEGO_EN;

        /* 启动自动协商 */
        if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, readval) < 0)
        {
            status =  ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    return status;
}
/**
  * @brief       获取ETH_CHIP设备的链路状态
  * @param       pobj: 设备对象
  * @param       pLinkState: 指向链路状态的指针
  * @retval      ETH_CHIP_STATUS_100MBITS_FULLDUPLEX:100M,全双工
                 ETH_CHIP_STATUS_100MBITS_HALFDUPLEX :100M,半双工
                 ETH_CHIP_STATUS_10MBITS_FULLDUPLEX:10M,全双工
                 ETH_CHIP_STATUS_10MBITS_HALFDUPLEX :10M,半双工
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
  */
int32_t eth_chip_get_link_state(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;//0x7F00

    /* 检测特殊功能寄存器链接值 */
    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_PHYSCSR, &readval) < 0)
    {
        return ETH_CHIP_STATUS_READ_ERROR;
    }

    if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS) && ((readval & ETH_CHIP_DUPLEX_STATUS) != 0))
    {
        return ETH_CHIP_STATUS_100MBITS_FULLDUPLEX;
    }
    else if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS))
    {
        return ETH_CHIP_STATUS_100MBITS_HALFDUPLEX;
    }
    else if (((readval & ETH_CHIP_BCR_DUPLEX_MODE) != ETH_CHIP_BCR_DUPLEX_MODE))
    {
        return ETH_CHIP_STATUS_10MBITS_FULLDUPLEX;
    }
    else
    {
        return ETH_CHIP_STATUS_10MBITS_HALFDUPLEX;
    }
}
/**
  * @brief       设置ETH_CHIP设备的链路状态
  * @param       pobj: 设备对象
  * @param       pLinkState: 指向链路状态的指针
  * @retval      ETH_CHIP_STATUS_OK:设置成功
                 ETH_CHIP_STATUS_ERROR :设置失败
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR :不能写入寄存器
  */
int32_t eth_chip_set_link_state(eth_chip_object_t *pobj, uint32_t linkstate)
{
    uint32_t bcrvalue = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &bcrvalue) >= 0)
    {
        /* 禁用链路配置(自动协商,速度和双工) */
        bcrvalue &= ~(ETH_CHIP_BCR_AUTONEGO_EN | ETH_CHIP_BCR_SPEED_SELECT | ETH_CHIP_BCR_DUPLEX_MODE);

        if (linkstate == ETH_CHIP_STATUS_100MBITS_FULLDUPLEX)
        {
            bcrvalue |= (ETH_CHIP_BCR_SPEED_SELECT | ETH_CHIP_BCR_DUPLEX_MODE);
        }
        else if (linkstate == ETH_CHIP_STATUS_100MBITS_HALFDUPLEX)
        {
            bcrvalue |= ETH_CHIP_BCR_SPEED_SELECT;
        }
        else if (linkstate == ETH_CHIP_STATUS_10MBITS_FULLDUPLEX)
        {
            bcrvalue |= ETH_CHIP_BCR_DUPLEX_MODE;
        }
        else
        {
            /* 错误的链路状态参数 */
            status = ETH_CHIP_STATUS_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    if(status == ETH_CHIP_STATUS_OK)
    {
        /* 写入链路状态 */
        if(pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, bcrvalue) < 0)
        {
            status = ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }

    return status;
}
/**
  * @brief       启用环回模式
  * @param       pobj: 设备对象
  * @param       pLinkState: 指向链路状态的指针
  * @retval      ETH_CHIP_STATUS_OK:设置成功
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR :不能写入寄存器
  */
int32_t eth_chip_enable_loop_back_mode(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &readval) >= 0)
    {
        readval |= ETH_CHIP_BCR_LOOPBACK;

        /* 启用环回模式 */
        if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, readval) < 0)
        {
            status = ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    return status;
}

/**
  * @brief       禁用环回模式
  * @param       pobj: 设备对象
  * @param       pLinkState: 指向链路状态的指针
  * @retval      ETH_CHIP_STATUS_OK:设置成功
                 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器
                 ETH_CHIP_STATUS_WRITE_ERROR :不能写入寄存器
  */
int32_t eth_chip_disable_loop_back_mode(eth_chip_object_t *pobj)
{
    uint32_t readval = 0;
    int32_t status = ETH_CHIP_STATUS_OK;

    if (pobj->io.readreg(pobj->devaddr, ETH_CHIP_BCR, &readval) >= 0)
    {
        readval &= ~ETH_CHIP_BCR_LOOPBACK;

        /* 禁用环回模式 */
        if (pobj->io.writereg(pobj->devaddr, ETH_CHIP_BCR, readval) < 0)
        {
            status =  ETH_CHIP_STATUS_WRITE_ERROR;
        }
    }
    else
    {
        status = ETH_CHIP_STATUS_READ_ERROR;
    }

    return status;
}
#ifndef __BSP_HAL_ETHERNET_H__
#define __BSP_HAL_ETHERNET_H__

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "mytype.h"
#include "eth.h"
/* Private macros ------------------------------------------------------------*/
/* PHY芯片寄存器映射表 */ 
#define ETH_CHIP_BCR                     ((uint16_t)0x0000U)
#define ETH_CHIP_BSR                     ((uint16_t)0x0001U)
#define PHY_REGISTER2                    ((uint16_t)0x0002U)
#define PHY_REGISTER3                    ((uint16_t)0x0003U)
/* 操作SCR寄存器的值(一般不需要修改) */
#define ETH_CHIP_BCR_SOFT_RESET                 ((uint16_t)0x8000U)
#define ETH_CHIP_BCR_LOOPBACK                   ((uint16_t)0x4000U)
#define ETH_CHIP_BCR_SPEED_SELECT               ((uint16_t)0x2000U)
#define ETH_CHIP_BCR_AUTONEGO_EN                ((uint16_t)0x1000U)
#define ETH_CHIP_BCR_POWER_DOWN                 ((uint16_t)0x0800U)
#define ETH_CHIP_BCR_ISOLATE                    ((uint16_t)0x0400U)
#define ETH_CHIP_BCR_RESTART_AUTONEGO           ((uint16_t)0x0200U)
#define ETH_CHIP_BCR_DUPLEX_MODE                ((uint16_t)0x0100U)
/* 操作BSR寄存器的值(一般不需要修改) */   
#define ETH_CHIP_BSR_100BASE_T4                 ((uint16_t)0x8000U)
#define ETH_CHIP_BSR_100BASE_TX_FD              ((uint16_t)0x4000U)
#define ETH_CHIP_BSR_100BASE_TX_HD              ((uint16_t)0x2000U)
#define ETH_CHIP_BSR_10BASE_T_FD                ((uint16_t)0x1000U)
#define ETH_CHIP_BSR_10BASE_T_HD                ((uint16_t)0x0800U)
#define ETH_CHIP_BSR_100BASE_T2_FD              ((uint16_t)0x0400U)
#define ETH_CHIP_BSR_100BASE_T2_HD              ((uint16_t)0x0200U)
#define ETH_CHIP_BSR_EXTENDED_STATUS            ((uint16_t)0x0100U)
#define ETH_CHIP_BSR_AUTONEGO_CPLT              ((uint16_t)0x0020U)
#define ETH_CHIP_BSR_REMOTE_FAULT               ((uint16_t)0x0010U)
#define ETH_CHIP_BSR_AUTONEGO_ABILITY           ((uint16_t)0x0008U)
#define ETH_CHIP_BSR_LINK_STATUS                ((uint16_t)0x0004U)
#define ETH_CHIP_BSR_JABBER_DETECT              ((uint16_t)0x0002U)
#define ETH_CHIP_BSR_EXTENDED_CAP               ((uint16_t)0x0001U)
/* PHY地址 ---- 由用户设置 */
#define ETHERNET_PHY_ADDRESS             0x00
#define ETH_CHIP_ADDR                    ETHERNET_PHY_ADDRESS
/* PHY寄存器的数量 */
#define ETH_CHIP_PHY_COUNT               ((uint16_t)0x001FU)
/* 使能/禁用PHY自动选择功能 */
#define PHY_AUTO_SELECT                  PHY_AUTO_SELECT_NABLE
#define LAN8720                          0
#define SR8201F                          1
#define YT8512C                          2
#define RTL8201                          3
#define YT8522                           4
#if PHY_AUTO_SELECT
/* 选择PHY芯片 ---- 由用户设置 */

#endif
/* PHY芯片进程状态 */
#define  ETH_CHIP_STATUS_READ_ERROR             ((int32_t)-5)
#define  ETH_CHIP_STATUS_WRITE_ERROR            ((int32_t)-4)
#define  ETH_CHIP_STATUS_ADDRESS_ERROR          ((int32_t)-3)
#define  ETH_CHIP_STATUS_RESET_TIMEOUT          ((int32_t)-2)
#define  ETH_CHIP_STATUS_ERROR                  ((int32_t)-1)
#define  ETH_CHIP_STATUS_OK                     ((int32_t) 0)
#define  ETH_CHIP_STATUS_LINK_DOWN              ((int32_t) 1)
#define  ETH_CHIP_STATUS_100MBITS_FULLDUPLEX    ((int32_t) 2)
#define  ETH_CHIP_STATUS_100MBITS_HALFDUPLEX    ((int32_t) 3)
#define  ETH_CHIP_STATUS_10MBITS_FULLDUPLEX     ((int32_t) 4)
#define  ETH_CHIP_STATUS_10MBITS_HALFDUPLEX     ((int32_t) 5)
#define  ETH_CHIP_STATUS_AUTONEGO_NOTDONE       ((int32_t) 6)
/* Private types -------------------------------------------------------------*/
/* PHY自动识别状态 */
enum PHY_AUTO
{
    PHY_AUTO_SELECT_NABLE = 0,
    PHY_AUTO_SELECT_DISABLE
};
/* 定义函数指针 */ 
typedef int32_t  (*eth_chip_init_func)          (void); 
typedef int32_t  (*eth_chip_deinit_func)        (void);
typedef int32_t  (*eth_chip_readreg_func)       (uint32_t, uint32_t, uint32_t *);
typedef int32_t  (*eth_chip_writereg_func)      (uint32_t, uint32_t, uint32_t);
typedef int32_t  (*eth_chip_gettick_func)       (void);
/* PHY共用函数结构体 */ 
typedef struct 
{
    eth_chip_init_func          init;                   /* 指向PHY初始化函数 */ 
    eth_chip_deinit_func        deinit;                 /* 指向PHY反初始化函数 */ 
    eth_chip_writereg_func      writereg;               /* 指向PHY写寄存器函数 */ 
    eth_chip_readreg_func       readreg;                /* 指向PHY读寄存器函数 */ 
    eth_chip_gettick_func       gettick;                /* 指向节拍函数 */ 
} eth_chip_ioc_tx_t;  
/* 注册到组件对象结构体 */
typedef struct 
{
    uint32_t            devaddr;                        /* PHY地址 */
    uint32_t            is_initialized;                 /* 描述该设备是否初始化 */
    eth_chip_ioc_tx_t   io;                             /* 设备调用的函数入口 */
    void                *pdata;                         /* 传入的形参 */
}eth_chip_object_t;
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
#define g_eth_handler                   heth            /* 以太网句柄 */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
extern eth_chip_ioc_tx_t  ETH_CHIP_IOCtx;
#if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE )
/* 选择PHY芯片 ---- 自动选择 */
extern int      PHY_TYPE;
extern uint16_t ETH_CHIP_PHYSCSR;
extern uint16_t ETH_CHIP_SPEED_STATUS;
extern uint16_t ETH_CHIP_DUPLEX_STATUS;
#endif
/* Exported functions --------------------------------------------------------*/
void ethernet_reset(void);
uint32_t ethernet_read_phy(uint16_t reg);
void ethernet_write_phy(uint16_t reg, uint16_t value);
uint8_t ethernet_chip_get_speed(void);
/*******************************************************************************
                       ETHERNET CHIP
*******************************************************************************/
int32_t eth_chip_init( eth_chip_object_t *pobj, eth_chip_ioc_tx_t *ioctx );
int32_t eth_chip_deinit(eth_chip_object_t *pobj);
int32_t eth_chip_disable_power_down_mode(eth_chip_object_t *pobj);
int32_t eth_chip_enable_power_down_mode(eth_chip_object_t *pobj);
int32_t eth_chip_start_auto_nego(eth_chip_object_t *pobj);
int32_t eth_chip_get_link_state(eth_chip_object_t *pobj);
int32_t eth_chip_set_link_state(eth_chip_object_t *pobj, uint32_t linkstate);
int32_t eth_chip_enable_loop_back_mode(eth_chip_object_t *pobj);
int32_t eth_chip_disable_loop_back_mode(eth_chip_object_t *pobj);


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif  // __BSP_HAL_ETHERNET_H__

4. 工程中添加lwIP文件

工程,并添加 lwip/src/api、lwip/src/core、lwip/src/netif 和lwip/arch这四个分组。

(一)、lwip/src/api分组添加下图中的src/api路径下的全部.c 文件。

 (二)、lwip/src/core分组添加下图中的src/core路径下除 ipv6 文件夹的全部.c 文件。

(三)、lwip/src/netif分组添加下图中的src/netif路径下的 ethernet.c 文件。

 (四)、lwip/arch分组添加下图中的arch路径下的全部.c 文件。

4.1 ethernetif.c/h

/* Includes ------------------------------------------------------------------*/
#include "ethernetif.h"
//
#include <string.h>
//
#include "lwip/opt.h"
#include "lwip/pbuf.h"
//
#include "lwip_comm.h"
//
#include "string.h"
//
#include "mytype.h"
#ifdef SYS_SUPPORT_OS
#include "semphr.h"
#endif
/* Private macros ------------------------------------------------------------*/
/* Define those to better describe your network interface. */
#define IFNAME0 'a'
#define IFNAME1 'p'
/*  */
#define ETH_DMA_TRANSMIT_TIMEOUT                (20U)
/* Packets of this app's primary service protocol are smaller
 * than this. Typical size is 1536. */
#define ETH_RX_BUFFER_SIZE                      1524
/* This app buffers receive packets of its primary service
 * protocol for processing later. */
#define ETH_RX_BUFFER_CNT                       10
/* HAL_ETH_Transmit(_IT) may attach two buffers per descriptor. */
#define ETH_TX_BUFFER_MAX                       ((ETH_TX_DESC_CNT) * 2)
#ifdef SYS_SUPPORT_OS
/* The time to block waiting for input. */
#define TIME_WAITING_FOR_INPUT                  ( portMAX_DELAY )
/* Stack size of the interface thread */
#define INTERFACE_THREAD_STACK_SIZE             ( 512 )
#define NETIF_IN_TASK_PRIORITY                  ( 2 )
#endif
/* Private types -------------------------------------------------------------*/
/*
@Note: This interface is implemented to operate in zero-copy mode only:
        - Rx Buffers will be allocated from LwIP stack memory heap,
          then passed to ETH HAL driver.
        - Tx Buffers will be allocated from LwIP stack memory heap,
          then passed to ETH HAL driver.

@Notes:
  1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,
       to customize it please redefine ETH_RX_DESC_CNT in ETH GUI (Rx Descriptor Length)
       so that updated value will be generated in stm32xxxx_hal_conf.h
  1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,
       to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length)
       so that updated value will be generated in stm32xxxx_hal_conf.h

  2.a. Rx Buffers number: ETH_RX_BUFFER_CNT must be greater than ETH_RX_DESC_CNT.
  2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must
       passed to ETH DMA in the init field (heth.Init.RxBuffLen)
*/
typedef enum
{
    RX_ALLOC_OK       = 0x00,
    RX_ALLOC_ERROR    = 0x01
} RxAllocStatusTypeDef;
typedef struct
{
    struct pbuf_custom pbuf_custom;
    uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32);
} RxBuff_t;
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Memory Pool Declaration */
LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");
/*  */
static uint8_t RxAllocStatus;
/* Global Ethernet handle*/
extern ETH_TxPacketConfig TxConfig;
/*  */
eth_chip_object_t ETHCHIP;
/*  */
#ifdef SYS_SUPPORT_OS
xSemaphoreHandle g_tx_semaphore = NULL;  /* 定义一个RX信号量 */
xSemaphoreHandle g_rx_semaphore = NULL;  /* 定义一个TX信号量 */
#endif
/* Private function prototypes -----------------------------------------------*/
void ethernetif_input( void * argument );
void RMII_Thread( void * argument );
/* Private functions ---------------------------------------------------------*/
/**
  * @brief  底层硬件初始化
  * @param  netif:以太网句柄
  * @retval NULL 
**/
static void low_level_init(struct netif *netif)
{
    ETH_MACConfigTypeDef g_eth_macconfig_handler = {0};
    int32_t phy_link_state = 0;
    uint32_t duplex = 0;
    uint32_t speed = 0;
    
    MX_ETH_Init();
    ethernet_reset();
    /* 设置MAC地址长度,为6个字节 */
    netif->hwaddr_len = ETHARP_HWADDR_LEN;  
    /* 初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复 */
    netif->hwaddr[0] = default_mac[0]; 
    netif->hwaddr[1] = default_mac[1]; 
    netif->hwaddr[2] = default_mac[2];
    netif->hwaddr[3] = default_mac[3];   
    netif->hwaddr[4] = default_mac[4];
    netif->hwaddr[5] = default_mac[5];
    /* 最大允许传输单元,允许该网卡广播和ARP功能 */
    netif->mtu = ETH_MAX_PAYLOAD;
    /* 网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播 */
    /* 使能、 ARP 使能等等重要控制位 */
    netif->flags |= NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP;
    
    /* Initialize the RX POOL */
    LWIP_MEMPOOL_INIT(RX_POOL);

    /* 配置发送报文配置常用参数 */
#if 0 //在MX_ETH_Init()中已经配置
    memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
    TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
    TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
#endif
#ifdef SYS_SUPPORT_OS
    /* create a binary semaphore used for informing ethernetif of frame reception */
    g_rx_semaphore = xSemaphoreCreateBinary();
    /* create a binary semaphore used for informing ethernetif of frame transmission */
    g_tx_semaphore = xSemaphoreCreateBinary();
    /* create the task that handles the ETH_MAC */
    sys_thread_new("eth_thread",
                   ethernetif_input,            /* 任务入口函数 */
                   netif,                       /* 任务入口函数参数 */
                   INTERFACE_THREAD_STACK_SIZE, /* 任务栈大小 */
                   NETIF_IN_TASK_PRIORITY);     /* 任务的优先级 */
#endif
#if 0 //在eth_chip_init()中已经配置
    /* 设置PHY IO功能 */
    eth_chip_regster_bus_io(&ETHCHIP, &ETH_CHIP_IOCtx);
#endif
    /* 初始化ETH PHY */
    eth_chip_init( &ETHCHIP, &ETH_CHIP_IOCtx );
    /* 必须开启自动协商功能 */
    eth_chip_start_auto_nego(&ETHCHIP);
    /* 必须等待初始化 */
    HAL_Delay( 2000 );
    phy_link_state = eth_chip_get_link_state(&ETHCHIP);
    
    if (phy_link_state == ETH_CHIP_STATUS_READ_ERROR)
    {
        netif_set_link_down(netif);
        netif_set_down(netif);
    }
    else
    {
        switch (phy_link_state)
        {
            case ETH_CHIP_STATUS_100MBITS_FULLDUPLEX:
                duplex = ETH_FULLDUPLEX_MODE;
                speed = ETH_SPEED_100M;
                break;
            case ETH_CHIP_STATUS_100MBITS_HALFDUPLEX:
                duplex = ETH_HALFDUPLEX_MODE;
                speed = ETH_SPEED_100M;
                break;
            case ETH_CHIP_STATUS_10MBITS_FULLDUPLEX:
                duplex = ETH_FULLDUPLEX_MODE;
                speed = ETH_SPEED_10M;
                break;
            case ETH_CHIP_STATUS_10MBITS_HALFDUPLEX:
                duplex = ETH_HALFDUPLEX_MODE;
                speed = ETH_SPEED_10M;
                break;
            default:
                duplex = ETH_FULLDUPLEX_MODE;
                speed = ETH_SPEED_100M;
                break;
        }
    }
#ifdef SYS_SUPPORT_OS
    /* 配置MAC */
    HAL_ETH_GetMACConfig(&g_eth_handler, &g_eth_macconfig_handler);
    g_eth_macconfig_handler.DuplexMode = duplex;
    g_eth_macconfig_handler.Speed = speed;
    HAL_ETH_SetMACConfig(&g_eth_handler,&g_eth_macconfig_handler);    
    HAL_ETH_Start_IT(&g_eth_handler);
#else    
    /* 配置MAC */
    HAL_ETH_GetMACConfig(&g_eth_handler, &g_eth_macconfig_handler);
    g_eth_macconfig_handler.DuplexMode = duplex;
    g_eth_macconfig_handler.Speed = speed;
    HAL_ETH_SetMACConfig(&g_eth_handler,&g_eth_macconfig_handler);    
    HAL_ETH_Start(&g_eth_handler);
    /* 开启虚拟网卡 */
    netif_set_up(netif);
    netif_set_link_up(netif);
#endif   
    while (!ethernet_read_phy(ETH_CHIP_PHYSCSR))  
    {/* 检查MCU与PHY芯片是否通信成功 */
        PRINTF("MCU与PHY芯片通信失败,请检查电路或者源码!!!!\r\n");
        HAL_Delay( 500 );
    }
#ifdef SYS_SUPPORT_OS
    if (HAL_GetREVID() == 0x1000)
    { 
        /* 
        This thread will keep resetting the RMII interface until good frames are received
        */
        sys_thread_new( "rmii_thread",
                       RMII_Thread,                     /* 任务入口函数 */
                       NULL,                            /* 任务入口函数参数 */
                       configMINIMAL_STACK_SIZE,        /* 任务栈大小 */
                       NETIF_IN_TASK_PRIORITY + 1);     /* 任务的优先级 */
    }
#endif
}
/**
  * @brief  数据包输出函数
  * @param  netif:以太网句柄
  * @param  p:
  * @retval  
**/
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
    uint32_t i = 0U;
    struct pbuf *q = NULL;
    err_t errval = ERR_OK;
    ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0};

    memset(Txbuffer, 0 , ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    for (q = p; q != NULL; q = q->next)
    {
        if (i >= ETH_TX_DESC_CNT)
          return ERR_IF;

        Txbuffer[i].buffer = q->payload;
        Txbuffer[i].len = q->len;

        if (i > 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if (q->next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
    }

    TxConfig.Length = p->tot_len;
    TxConfig.TxBuffer = Txbuffer;
    TxConfig.pData = p;
#ifdef SYS_SUPPORT_OS
    pbuf_ref(p);

    HAL_ETH_Transmit_IT(&g_eth_handler, &TxConfig);

    while (xSemaphoreTake(g_tx_semaphore, TIME_WAITING_FOR_INPUT) != pdTRUE){}

    HAL_ETH_ReleaseTxPacket(&g_eth_handler);
#else
    HAL_ETH_Transmit(&g_eth_handler, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
#endif
    return errval;
}
/**
  * @brief  数据包输入函数
  * @param  netif:以太网句柄
  * @retval  
**/
static struct pbuf * low_level_input(struct netif *netif)
{
    struct pbuf *p = NULL;

    if( RxAllocStatus == RX_ALLOC_OK )
    {
        HAL_ETH_ReadData(&g_eth_handler, (void **)&p);
    }
    
    return p;
}
/**
  * @brief  Custom Rx pbuf free callback
  * @param  pbuf: pbuf to be freed
  * @retval None
  */
static void pbuf_free_custom(struct pbuf *p)
{
    struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;
    LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);
    /* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to
    * call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */
    if (RxAllocStatus == RX_ALLOC_ERROR)
    {
        RxAllocStatus = RX_ALLOC_OK;
    #ifdef SYS_SUPPORT_OS
        portBASE_TYPE taskWoken = pdFALSE;

        if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE)
        {
            portEND_SWITCHING_ISR(taskWoken);
        }
    #endif
    }
}
/* Exported macros -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
#ifdef SYS_SUPPORT_OS
/**
 * This task should be signaled when a receive packet is ready to be read
 * from the interface.
 *
 * @param argument the lwip network interface structure for this ethernetif
 */
void ethernetif_input( void * argument )
{
    struct pbuf *p = NULL;
    struct netif *netif = (struct netif *) argument;

    for( ;; )
    {
        if (xSemaphoreTake( g_rx_semaphore, TIME_WAITING_FOR_INPUT) == pdTRUE)
        {
            do
            {
                p = low_level_input( netif );
                if (p != NULL)
                {
                    if (netif->input( p, netif) != ERR_OK )
                    {
                        pbuf_free(p);
                    }
                }

            }while(p!=NULL);
        }
    }
}
/**
  * @brief  RMII interface watchdog thread
  * @param  argument
  * @retval None
  */
void RMII_Thread( void * argument )
{
    (void) argument; 

    while (1)
    {
        /* some unicast good packets are received */
        if (g_eth_handler.Instance->MMCRGUFCR > 0U)
        {
            /* RMII Init is OK: Delete the Thread */ 
            vTaskDelete(NULL);
        }    
        else if (g_eth_handler.Instance->MMCRFCECR > 10U) 
        {
            /* ETH received too many packets with CRC errors, resetting RMII */
            SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
            SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;

            g_eth_handler.Instance->MMCCR |= ETH_MMCCR_CR;
        }
        else
        {
            /* Delay 200 ms */
            vTaskDelay(200);
        }
    }
}
#else
/**
  * @brief  网卡输入(实际调用low_level_input)
  * @param  netif:以太网句柄
  * @retval NULL 
**/
void ethernetif_input(struct netif *netif)
{
    struct pbuf *p = NULL;

    do
    {
        p = low_level_input( netif );
        
        if (p != NULL)
        {
            if (netif->input( p, netif) != ERR_OK )
            {
                pbuf_free(p);
            }
        }

    } while(p != NULL);
}
#endif
/**
  * @brief  网卡驱动初始化
  * @param  netif:以太网句柄
  * @retval  
**/
err_t ethernetif_init(struct netif *netif)
{
    LWIP_ASSERT("netif != NULL", (netif != NULL));

#if LWIP_NETIF_HOSTNAME
    /* Initialize interface hostname */
    netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
#ifdef SYS_SUPPORT_OS
    /*
    * 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);
#endif
    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...) */
    netif->output = etharp_output;
    netif->linkoutput = low_level_output;

    /* initialize the hardware */
    low_level_init(netif);

    return ERR_OK;
}
#ifndef SYS_SUPPORT_OS
/**
  * @brief  提供lwIP时基
  * @param  无
  * @retval 当前时间值 
**/
u32_t sys_now(void)
{
    return HAL_GetTick();
}
#endif
/*******************************************************************************
                       回调函数
*******************************************************************************/
#ifdef SYS_SUPPORT_OS
/**
  * @brief  Ethernet Rx Transfer completed callback
  * @param  heth: ETH handle
  * @retval None
  */
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
    portBASE_TYPE taskWoken = pdFALSE;
    
    if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE)
    {
        portEND_SWITCHING_ISR(taskWoken);
    }
}
/**
  * @brief  Ethernet Tx Transfer completed callback
  * @param  heth: ETH handle
  * @retval None
  */
void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
    portBASE_TYPE taskWoken = pdFALSE;
    
    if (xSemaphoreGiveFromISR(g_tx_semaphore, &taskWoken) == pdTRUE)
    {
        portEND_SWITCHING_ISR(taskWoken);
    }
}

/**
  * @brief  Ethernet DMA transfer error callback
  * @param  heth: ETH handle
  * @retval None
  */
void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
{
    if ((HAL_ETH_GetDMAError(heth) & ETH_DMASR_RBUS) == ETH_DMASR_RBUS)
    {
        portBASE_TYPE taskWoken = pdFALSE;
        
        if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE)
        {
            portEND_SWITCHING_ISR(taskWoken);
        }
    }
}
#endif
void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
    struct pbuf_custom *p = LWIP_MEMPOOL_ALLOC(RX_POOL);
    
    if (p)
    {
        /* Get the buff from the struct pbuf address. */
        *buff = (uint8_t *)p + offsetof(RxBuff_t, buff);
        p->custom_free_function = pbuf_free_custom;
        /* Initialize the struct pbuf.
        * This must be performed whenever a buffer's allocated because it may be
        * changed by lwIP or the app, e.g., pbuf_free decrements ref. */
        pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUFFER_SIZE);
    }
    else
    {
        RxAllocStatus = RX_ALLOC_ERROR;
        *buff = NULL;
    }
}

void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
{
    struct pbuf **ppStart = (struct pbuf **)pStart;
    struct pbuf **ppEnd = (struct pbuf **)pEnd;
    struct pbuf *p = NULL;

    /* Get the struct pbuf from the buff address. */
    p = (struct pbuf *)(buff - offsetof(RxBuff_t, buff));
    p->next = NULL;
    p->tot_len = 0;
    p->len = Length;

    /* Chain the buffer. */
    if (!*ppStart)
    {
        /* The first buffer of the packet. */
        *ppStart = p;
    }
    else
    {
        /* Chain the buffer to the end of the packet. */
        (*ppEnd)->next = p;
    }
    *ppEnd  = p;

    /* Update the total length of all the buffers of the chain. Each pbuf in the chain should have its tot_len
    * set to its own length, plus the length of all the following pbufs in the chain. */
    for (p = *ppStart; p != NULL; p = p->next)
    {
        p->tot_len += Length;
    }
}

void HAL_ETH_TxFreeCallback(uint32_t * buff)
{
    pbuf_free((struct pbuf *)buff);
}
#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "lwip/err.h"
#include "lwip/netif.h"
/* Private macros ------------------------------------------------------------*/
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
err_t   ethernetif_init(struct netif *netif);   /* 网卡初始化函数 */
//void    ethernetif_input(struct netif *netif);  /* 数据包输入函数 */
//u32_t   sys_now(void);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif  // __ETHERNETIF_H__

4.2 lwip_comm.c/h

/* Includes ------------------------------------------------------------------*/
#include "lwip_comm.h"
//
#include "ethernetif.h"
//
#include "lwip/dhcp.h"
#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "lwip/tcpip.h"
//
#include "mytype.h"
/* Private macros ------------------------------------------------------------*/
#ifdef SYS_SUPPORT_OS
    /* LINK线程配置 */
    #define LWIP_LINK_TASK_PRIO             3                   /* 任务优先级 */
    #define LWIP_LINK_STK_SIZE              128 * 2             /* 任务堆栈大小 */
    void lwip_link_thread( void * argument );                   /* 链路线程 */

    /* DHCP线程配置 */
    #define LWIP_DHCP_TASK_PRIO             4                   /* 任务优先级 */
    #define LWIP_DHCP_STK_SIZE              128 * 2             /* 任务堆栈大小 */
    void lwip_periodic_handle(void *argument);                  /* DHCP线程 */
    void lwip_link_status_updated(struct netif *netif);         /* DHCP状态回调函数 */
#endif
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* lwip控制结构体 */
__lwip_dev g_lwipdev;  
/* 定义一个全局的网络接口 */
struct netif g_lwip_netif;                          
#if LWIP_DHCP
    /* DHCP精细处理计时器 */
    uint32_t g_dhcp_fine_timer = 0;
    /* DHCP状态初始化 */
    __IO uint8_t g_lwip_dhcp_state = LWIP_DHCP_OFF;
#endif
/* Private functions ---------------------------------------------------------*/
/**
 * @breif       lwip 默认IP设置
 * @param       lwipx  : lwip控制结构体指针
 * @retval      无
 */
static void lwip_comm_default_ip_set(__lwip_dev *lwipx)
{
     /* 默认远端IP为:192.168.1.134 */
    lwipx->remoteip[0] = 192;
    lwipx->remoteip[1] = 168;
    lwipx->remoteip[2] = 1;
    lwipx->remoteip[3] = 88;
    
    /* MAC地址设置 */
    lwipx->mac[0] = default_mac[0];
    lwipx->mac[1] = default_mac[1];
    lwipx->mac[2] = default_mac[2];
    lwipx->mac[3] = default_mac[3];
    lwipx->mac[4] = default_mac[4];
    lwipx->mac[5] = default_mac[5];
    
    /* 默认本地IP为:192.168.1.30 */
    lwipx->ip[0] = 192;
    lwipx->ip[1] = 168;
    lwipx->ip[2] = 100;
    lwipx->ip[3] = 66;
     /* 默认子网掩码: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] = 100;
    lwipx->gateway[3] = 1;
    lwipx->dhcpstatus = 0; /* 没有DHCP */
    lwipx->lwip_display_fn = NULL;
}
/**
 * @brief       通知用户网络接口配置状态
 * @param       netif:网卡控制块
 * @retval      无
 */
static void lwip_link_status_updated(struct netif *netif)
{
    if (netif_is_up(netif))
    {
#if LWIP_DHCP
        /* Update DHCP state machine */
        g_lwip_dhcp_state = LWIP_DHCP_START;
#endif /* LWIP_DHCP */
        PRINTF ("The network cable is connected \r\n");
    }
    else
    {
#if LWIP_DHCP
        /* Update DHCP state machine */
        g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
#endif /* LWIP_DHCP */
        PRINTF ("The network cable is not connected \r\n");
    }
}
#ifndef SYS_SUPPORT_OS
#if LWIP_DHCP /* 如果使用DHCP */
/**
 * @brief       lwIP的DHCP分配进程
 * @param       netif:网卡控制块
 * @retval      无
 */
static void lwip_dhcp_process(struct netif *netif)
{
    uint32_t ip = 0;
    uint32_t netmask = 0;
    uint32_t gw = 0;
    struct dhcp *dhcp;
    uint8_t iptxt[20];              /* 存储已分配的IP地址 */
    g_lwipdev.dhcpstatus = 1;        /* DHCP标记为1 */
    
    /* 根据DHCP状态进入执行相应的动作 */
    switch (g_lwip_dhcp_state)
    {
        case LWIP_DHCP_START:
        {
             /* 对IP地址、网关地址及子网页码清零操作 */
            ip_addr_set_zero_ip4(&netif->ip_addr);
            ip_addr_set_zero_ip4(&netif->netmask);
            ip_addr_set_zero_ip4(&netif->gw);
            /* 设置DHCP的状态为等待分配IP地址 */
            g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS;
            /* 开启DHCP */
            dhcp_start(netif);
        }
        break;

        case LWIP_DHCP_WAIT_ADDRESS:
        {
            ip = g_lwip_netif.ip_addr.addr;       /* 读取新IP地址 */
            netmask = g_lwip_netif.netmask.addr;  /* 读取子网掩码 */
            gw = g_lwip_netif.gw.addr;            /* 读取默认网关 */
            PRINTF ("等待DHCP分配网络参数......\r\n");
            
            if (dhcp_supplied_address(netif)) 
            {
                PRINTF ("DHCP分配成功......\r\n");
                g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED;
                sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr));
                PRINTF ("IP address assigned by a DHCP server: %s\r\n", iptxt);
                
                if (ip != 0)
                {
                    g_lwipdev.dhcpstatus = 2;         /* DHCP??? */
                    PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]);
                    /* 解析出通过DHCP获取到的IP地址 */
                    g_lwipdev.ip[3] = (uint8_t)(ip >> 24);
                    g_lwipdev.ip[2] = (uint8_t)(ip >> 16);
                    g_lwipdev.ip[1] = (uint8_t)(ip >> 8);
                    g_lwipdev.ip[0] = (uint8_t)(ip);
                    PRINTF("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
                    /* 解析通过DHCP获取到的子网掩码地址 */
                    g_lwipdev.netmask[3] = (uint8_t)(netmask >> 24);
                    g_lwipdev.netmask[2] = (uint8_t)(netmask >> 16);
                    g_lwipdev.netmask[1] = (uint8_t)(netmask >> 8);
                    g_lwipdev.netmask[0] = (uint8_t)(netmask);
                    PRINTF("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
                    /* 解析出通过DHCP获取到的默认网关 */
                    g_lwipdev.gateway[3] = (uint8_t)(gw >> 24);
                    g_lwipdev.gateway[2] = (uint8_t)(gw >> 16);
                    g_lwipdev.gateway[1] = (uint8_t)(gw >> 8);
                    g_lwipdev.gateway[0] = (uint8_t)(gw);
                    PRINTF("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
                }
            }
            else
            {
                dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);

                 /* DHCP超时 */
                if (dhcp->tries > LWIP_MAX_DHCP_TRIES)
                {
                    PRINTF ("DHCP分配失败,进入静态分配......\r\n");
                    g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT;

                    /* 停止DHCP */
                    dhcp_stop(netif);
                    g_lwipdev.dhcpstatus = 0XFF;
                    /* 使用静态IP地址 */
                    IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
                    IP4_ADDR(&(g_lwip_netif.netmask), g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
                    IP4_ADDR(&(g_lwip_netif.gw), g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
                    netif_set_addr(netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw);
                    sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr));
                    PRINTF ("Static IP address: %s\r\n", iptxt);
                }
            }
        }
        break;
        case LWIP_DHCP_LINK_DOWN:
        {
            /* 停止 DHCP */
            dhcp_stop(netif);
            g_lwip_dhcp_state = LWIP_DHCP_OFF; 
        }
        break;
        default: break;
    }
}
#endif
#endif
/* Exported macros -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/**
 * @breif       LWIP初始化(LWIP启动的时候使用)
 * @param       无
 * @retval      0,成功
 *              1,内存错误
 *              2,以太网芯片初始化失败
 *              3,网卡添加失败.
 */
uint8_t lwip_comm_init(void)
{
    struct netif *netif_init_flag;                  /* 调用netif_add()函数时的返回值,用于判断网络初始化是否成功 */
    ip_addr_t ipaddr;                               /* ip地址 */
    ip_addr_t netmask;                              /* 子网掩码 */
    ip_addr_t gw;                                   /* 默认网关 */
#ifndef SYS_SUPPORT_OS
    uint8_t eth_linkstate;
    
    lwip_init();
#else
    tcpip_init(NULL, NULL);
#endif 
    
    lwip_comm_default_ip_set(&g_lwipdev);           /* 设置默认IP等信息 */
    
#if LWIP_DHCP
    ip_addr_set_zero_ip4(&ipaddr);
    ip_addr_set_zero_ip4(&netmask);
    ip_addr_set_zero_ip4(&gw);
#else
    IP4_ADDR(&ipaddr, g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
    IP4_ADDR(&netmask, g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
    IP4_ADDR(&gw, g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
    PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]);
    PRINTF("静态IP地址........................%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
    PRINTF("子网掩码..........................%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
    PRINTF("默认网关..........................%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
    g_lwipdev.dhcpstatus = 0XFF;
#endif   /* 向网卡列表中添加一个网口 */
    netif_init_flag = netif_add(&g_lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &ethernetif_init, &ethernet_input);

    if (netif_init_flag == NULL)
    {
        return 1;                                   /* 网卡添加失败 */
    }
    else                                            /* 网口添加成功后,设置netif为默认值,并且打开netif网口 */
    {
#ifdef SYS_SUPPORT_OS
    #if LWIP_NETIF_LINK_CALLBACK
        lwip_link_status_updated(&g_lwip_netif);    /* DHCP链接状态更新函数 */
        netif_set_link_callback(&g_lwip_netif, lwip_link_status_updated);
        /* 查询PHY连接状态任务 */
        sys_thread_new("eth_link",
                       lwip_link_thread,            /* 任务入口函数 */
                       &g_lwip_netif,               /* 任务入口函数参数 */
                       LWIP_LINK_STK_SIZE,          /* 任务栈大小 */
                       LWIP_LINK_TASK_PRIO);        /* 任务的优先级 */
    #endif
#else
        netif_set_default(&g_lwip_netif);           /* 设置netif为默认网口 */
        lwip_link_status_updated(&g_lwip_netif);    /* 打开netif网口 */
        netif_set_link_callback(&g_lwip_netif, lwip_link_status_updated);
#endif
    }
    g_lwipdev.link_status = LWIP_LINK_OFF;          /* 链接标记为0 */
#if LWIP_DHCP
    g_lwipdev.dhcpstatus = 0;
#ifdef SYS_SUPPORT_OS
    /* DHCP轮询任务 */
    sys_thread_new("eth_dhcp",
                   lwip_periodic_handle,            /* 任务入口函数 */
                   &g_lwip_netif,                   /* 任务入口函数参数 */
                   LWIP_DHCP_STK_SIZE,              /* 任务栈大小 */
                   LWIP_DHCP_TASK_PRIO);            /* 任务的优先级 */
#endif
#endif
#ifndef SYS_SUPPORT_OS
    do
    {
        eth_linkstate = ethernet_read_phy(ETH_CHIP_BSR);
        HAL_Delay(1000);
        
        if ((eth_linkstate & ETH_CHIP_BSR_LINK_STATUS) == 4)
        {
            PRINTF("检测到网线已经插入\r\n");
        }
        else
        {
            PRINTF("检测到网线没有插入\r\n");
        }

    }while((eth_linkstate & ETH_CHIP_BSR_LINK_STATUS) == 0);
#endif   
    return 0;                                       /* 操作OK. */
}
#ifndef SYS_SUPPORT_OS
/**
 * @breif       当接收到数据后调用
 * @param       无
 * @retval      无
 */
void lwip_pkt_handle(void)
{
    /* 从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理 */
    ethernetif_input(&g_lwip_netif);
}
#endif
#ifdef SYS_SUPPORT_OS
#if LWIP_DHCP    /* 如果使用DHCP */
/**
 * @breif       DHCP进程
 * @param       argument:传入的形参
 * @retval      无
 */
void lwip_periodic_handle(void *argument)
{
    struct netif *netif = (struct netif *) argument;
    uint32_t ip = 0;
    uint32_t netmask = 0;
    uint32_t gw = 0;
    struct dhcp *dhcp;
    uint8_t iptxt[20];

    while (1)
    {
        switch (g_lwip_dhcp_state)
        {
            case LWIP_DHCP_START:
            {
                /* 对IP地址、网关地址及子网页码清零操作 */
                ip_addr_set_zero_ip4(&netif->ip_addr);
                ip_addr_set_zero_ip4(&netif->netmask);
                ip_addr_set_zero_ip4(&netif->gw);
                ip_addr_set_zero_ip4(&netif->ip_addr);
                ip_addr_set_zero_ip4(&netif->netmask);
                ip_addr_set_zero_ip4(&netif->gw);
                
                g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS;
                
                PRINTF ("State: Looking for DHCP server ...\r\n");
                dhcp_start(netif);
            }
            break;
            case LWIP_DHCP_WAIT_ADDRESS:
            {
                if (dhcp_supplied_address(netif))
                {
                    g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED;
                    
                    ip = g_lwip_netif.ip_addr.addr;       /* 读取新IP地址 */
                    netmask = g_lwip_netif.netmask.addr;  /* 读取子网掩码 */
                    gw = g_lwip_netif.gw.addr;            /* 读取默认网关 */
                    
                    sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif)));
                    PRINTF ("IP address assigned by a DHCP server: %s\r\n", iptxt);
                    
                    if (ip != 0)
                    {
                        g_lwipdev.dhcpstatus = 2;         /* DHCP成功 */
                        PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]);
                        /* 解析出通过DHCP获取到的IP地址 */
                        g_lwipdev.ip[3] = (uint8_t)(ip >> 24);
                        g_lwipdev.ip[2] = (uint8_t)(ip >> 16);
                        g_lwipdev.ip[1] = (uint8_t)(ip >> 8);
                        g_lwipdev.ip[0] = (uint8_t)(ip);
                        PRINTF("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
                        /* 解析通过DHCP获取到的子网掩码地址 */
                        g_lwipdev.netmask[3] = (uint8_t)(netmask >> 24);
                        g_lwipdev.netmask[2] = (uint8_t)(netmask >> 16);
                        g_lwipdev.netmask[1] = (uint8_t)(netmask >> 8);
                        g_lwipdev.netmask[0] = (uint8_t)(netmask);
                        PRINTF("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
                        /* 解析出通过DHCP获取到的默认网关 */
                        g_lwipdev.gateway[3] = (uint8_t)(gw >> 24);
                        g_lwipdev.gateway[2] = (uint8_t)(gw >> 16);
                        g_lwipdev.gateway[1] = (uint8_t)(gw >> 8);
                        g_lwipdev.gateway[0] = (uint8_t)(gw);
                        PRINTF("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
                        if( g_lwipdev.lwip_display_fn != NULL ) {
                            g_lwipdev.lwip_display_fn(2);
                        }
                    }
                }
                else
                {
                    dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);

                    /* DHCP timeout */
                    if (dhcp->tries > LWIP_MAX_DHCP_TRIES)
                    {
                        g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT;
                        g_lwipdev.dhcpstatus = 0XFF;
                        /* 使用静态IP地址 */
                        IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
                        IP4_ADDR(&(g_lwip_netif.netmask), g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
                        IP4_ADDR(&(g_lwip_netif.gw), g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
                        netif_set_addr(netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw);

                        sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif)));
                        PRINTF ("DHCP Timeout !! \r\n");
                        PRINTF ("Static IP address: %s\r\n", iptxt);
                        if( g_lwipdev.lwip_display_fn != NULL ) {
                            g_lwipdev.lwip_display_fn(2);
                        }
                    }
                }
            }
            break;
            case LWIP_DHCP_LINK_DOWN:
            {
                g_lwip_dhcp_state = LWIP_DHCP_OFF;
            }
            break;
            default: break;
        }

        /* wait 1000 ms */
        vTaskDelay(1000);
    }
}
#endif
/**
  * @brief       检查ETH链路状态,更新netif
  * @param       argument: netif
  * @retval      无
  */
void lwip_link_thread( void * argument )
{
    uint32_t regval = 0;
    struct netif *netif = (struct netif *) argument;
    int link_again_num = 0;

    while(1)
    {
        /* 读取PHY状态寄存器,获取链接信息 */
        HAL_ETH_ReadPHYRegister(&g_eth_handler, ETH_CHIP_ADDR,ETH_CHIP_BSR, &regval);

        /* 判断链接状态 */
        if((regval & ETH_CHIP_BSR_LINK_STATUS) == 0)
        {
            g_lwipdev.link_status = LWIP_LINK_OFF;
            
            link_again_num ++ ;
            
            if (link_again_num >= 2)                    /* 网线一段时间没有插入 */
            {
                vTaskDelay(100);
                continue;
            }
            else                                        /* 关闭虚拟网卡及以太网中断 */
            {
#if LWIP_DHCP
                g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
                dhcp_stop(netif);
#endif
                HAL_ETH_Stop_IT(&g_eth_handler);
                netif_set_down(netif);
                netif_set_link_down(netif);
            }
        }
        else                                            /* 网线插入检测 */
        {
            link_again_num = 0;

            if (g_lwipdev.link_status == LWIP_LINK_OFF)/* 开启以太网及虚拟网卡 */
            {
                g_lwipdev.link_status = LWIP_LINK_ON;
                HAL_ETH_Start_IT(&g_eth_handler);
                netif_set_up(netif);
                netif_set_link_up(netif);
            }
        }

        vTaskDelay(100);
    }
}
#else
/**
 * @breif       LWIP轮询处理
 * @param       无
 * @retval      无
 */
void lwip_periodic_handle(void)
{
    sys_check_timeouts();
#if LWIP_DHCP        /* 如果使用DHCP */
    /* Fine DHCP periodic process every 500ms */
    if (HAL_GetTick() - g_dhcp_fine_timer >= DHCP_FINE_TIMER_MSECS)
    {
        g_dhcp_fine_timer =  HAL_GetTick();
        /* process DHCP state machine */
        lwip_dhcp_process(&g_lwip_netif);
    }
#endif
}
#endif
#ifndef __LWIP_COMM_H__
#define __LWIP_COMM_H__

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "netif/etharp.h"
#include "lwip/timeouts.h"
#include "lwip/snmp.h"
/* Private macros ------------------------------------------------------------*/
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* DHCP进程状态 */
#define LWIP_DHCP_OFF                   (uint8_t) 0     /* DHCP服务器关闭状态 */
#define LWIP_DHCP_START                 (uint8_t) 1     /* DHCP服务器启动状态 */
#define LWIP_DHCP_WAIT_ADDRESS          (uint8_t) 2     /* DHCP服务器等待分配IP状态 */
#define LWIP_DHCP_ADDRESS_ASSIGNED      (uint8_t) 3     /* DHCP服务器地址已分配状态 */
#define LWIP_DHCP_TIMEOUT               (uint8_t) 4     /* DHCP服务器超时状态 */
#define LWIP_DHCP_LINK_DOWN             (uint8_t) 5     /* DHCP服务器链接失败状态 */

/* 链接状态 */
#define LWIP_LINK_OFF                   (uint8_t) 0     /* 链接关闭状态 */
#define LWIP_LINK_ON                    (uint8_t) 1     /* 链接开启状态 */
#define LWIP_LINK_AGAIN                 (uint8_t) 2     /* 重复开启 */

/* DHCP服务器最大重试次数 */
#define LWIP_MAX_DHCP_TRIES             (uint8_t) 4
/* Exported types ------------------------------------------------------------*/
typedef void (*display_fn)(uint8_t index);
/*lwip控制结构体*/
typedef struct  
{
    uint8_t mac[6];                                     /* MAC地址 */
    uint8_t remoteip[4];                                /* 远端主机IP地址 */ 
    uint8_t ip[4];                                      /* 本机IP地址 */
    uint8_t netmask[4];                                 /* 子网掩码 */
    uint8_t gateway[4];                                 /* 默认网关的IP地址 */
    uint8_t dhcpstatus;                                 /* dhcp状态
                                                        0, 未获取DHCP地址
                                                        1, 进入DHCP获取状态
                                                        2, 成功获取DHCP地址
                                                        0XFF,获取失败 */
    uint8_t link_status;                                /* 连接状态 */
    display_fn lwip_display_fn;                         /* 显示函数指针 */
}__lwip_dev;
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
extern __lwip_dev g_lwipdev;                            /* lwip控制结构体 */
/* Exported functions --------------------------------------------------------*/
uint8_t lwip_comm_init(void);
//void lwip_pkt_handle(void);
//void lwip_periodic_handle(void);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif  // __LWIP_COMM_H__

4.3 sys_arch.c/h

/*
 * Copyright (c) 2017 Simon Goldschmidt
 * 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: Simon Goldschmidt <[email protected]>
 *
 */

/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"


int errno;

/** Set this to 1 if you want the stack size passed to sys_thread_new() to be
 * interpreted as number of stack words (FreeRTOS-like).
 * Default is that they are interpreted as byte count (lwIP-like).
 */
#ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
#define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS  1
#endif

/** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions.
 * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT().
 */
#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
#define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX     0
#endif

/** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and
 * SYS_ARCH_UNPROTECT() are called matching.
 */
#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
#define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK   0
#endif

/** Set this to 1 to let sys_mbox_free check that queues are empty when freed */
#ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
#define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE       0
#endif

/** Set this to 1 to enable core locking check functions in this port.
 * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED()
 * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */
#ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING
#define LWIP_FREERTOS_CHECK_CORE_LOCKING              0
#endif

/** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer.
 * Default is 1, where FreeRTOS ticks are used to calculate back to ms.
 */
#ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
#define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS           1
#endif

#if !configSUPPORT_DYNAMIC_ALLOCATION
# error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION"
#endif
#if !INCLUDE_vTaskDelay
# error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay"
#endif
#if !INCLUDE_vTaskSuspend
# error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend"
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX
#if !configUSE_MUTEXES
# error "lwIP FreeRTOS port requires configUSE_MUTEXES"
#endif
#endif

#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
static SemaphoreHandle_t sys_arch_protect_mutex;
#endif
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
static sys_prot_t sys_arch_protect_nesting;
#endif

/* Initialize this module (see description in sys.h) */
void
sys_init(void)
{
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
  /* initialize sys_arch_protect global mutex */
  sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex();
  LWIP_ASSERT("failed to create sys_arch_protect mutex",
    sys_arch_protect_mutex != NULL);
#endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
}

#if configUSE_16_BIT_TICKS == 1
#error This port requires 32 bit ticks or timer overflow will fail
#endif

#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
u32_t
sys_now(void)
{
  return xTaskGetTickCount() * portTICK_PERIOD_MS;
}
#endif

u32_t
sys_jiffies(void)
{
  return xTaskGetTickCount();
}

#if SYS_LIGHTWEIGHT_PROT

sys_prot_t
sys_arch_protect(void)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
  BaseType_t ret;
  LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);

  ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY);
  LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE);
#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
  taskENTER_CRITICAL();
#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
  {
    /* every nested call to sys_arch_protect() returns an increased number */
    sys_prot_t ret = sys_arch_protect_nesting;
    sys_arch_protect_nesting++;
    LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret);
    return ret;
  }
#else
  return 1;
#endif
}

void
sys_arch_unprotect(sys_prot_t pval)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
  BaseType_t ret;
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
  LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0);
  sys_arch_protect_nesting--;
  LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval);
#endif

#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
  LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);

  ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex);
  LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);
#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
  taskEXIT_CRITICAL();
#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
  LWIP_UNUSED_ARG(pval);
}

#endif /* SYS_LIGHTWEIGHT_PROT */

void
sys_arch_msleep(u32_t delay_ms)
{
  TickType_t delay_ticks = delay_ms / portTICK_RATE_MS;
  vTaskDelay(delay_ticks);
}

#if !LWIP_COMPAT_MUTEX

/* Create a new mutex*/
err_t
sys_mutex_new(sys_mutex_t *mutex)
{
  LWIP_ASSERT("mutex != NULL", mutex != NULL);

  mutex->mut = xSemaphoreCreateRecursiveMutex();
  if(mutex->mut == NULL) {
    SYS_STATS_INC(mutex.err);
    return ERR_MEM;
  }
  SYS_STATS_INC_USED(mutex);
  return ERR_OK;
}

void
sys_mutex_lock(sys_mutex_t *mutex)
{
  BaseType_t ret;
  LWIP_ASSERT("mutex != NULL", mutex != NULL);
  LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);

  ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);
  LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
}

void
sys_mutex_unlock(sys_mutex_t *mutex)
{
  BaseType_t ret;
  LWIP_ASSERT("mutex != NULL", mutex != NULL);
  LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);

  ret = xSemaphoreGiveRecursive(mutex->mut);
  LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
}

void
sys_mutex_free(sys_mutex_t *mutex)
{
  LWIP_ASSERT("mutex != NULL", mutex != NULL);
  LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);

  SYS_STATS_DEC(mutex.used);
  vSemaphoreDelete(mutex->mut);
  mutex->mut = NULL;
}

#endif /* !LWIP_COMPAT_MUTEX */

err_t
sys_sem_new(sys_sem_t *sem, u8_t initial_count)
{
  LWIP_ASSERT("sem != NULL", sem != NULL);
  LWIP_ASSERT("initial_count invalid (not 0 or 1)",
    (initial_count == 0) || (initial_count == 1));

  sem->sem = xSemaphoreCreateBinary();
  if(sem->sem == NULL) {
    SYS_STATS_INC(sem.err);
    return ERR_MEM;
  }
  SYS_STATS_INC_USED(sem);

  if(initial_count == 1) {
    BaseType_t ret = xSemaphoreGive(sem->sem);
    LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
  }
  return ERR_OK;
}

void
sys_sem_signal(sys_sem_t *sem)
{
  BaseType_t ret;
  LWIP_ASSERT("sem != NULL", sem != NULL);
  LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);

  ret = xSemaphoreGive(sem->sem);
  /* queue full is OK, this is a signal only... */
  LWIP_ASSERT("sys_sem_signal: sane return value",
    (ret == pdTRUE) || (ret == errQUEUE_FULL));
}

u32_t
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms)
{
  BaseType_t ret;
  LWIP_ASSERT("sem != NULL", sem != NULL);
  LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);

  if(!timeout_ms) {
    /* wait infinite */
    ret = xSemaphoreTake(sem->sem, portMAX_DELAY);
    LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
  } else {
    TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
    ret = xSemaphoreTake(sem->sem, timeout_ticks);
    if (ret == errQUEUE_EMPTY) {
      /* timed out */
      return SYS_ARCH_TIMEOUT;
    }
    LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
  }

  /* Old versions of lwIP required us to return the time waited.
     This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
     here is enough. */
  return 1;
}

void
sys_sem_free(sys_sem_t *sem)
{
  LWIP_ASSERT("sem != NULL", sem != NULL);
  LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);

  SYS_STATS_DEC(sem.used);
  vSemaphoreDelete(sem->sem);
  sem->sem = NULL;
}

err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("size > 0", size > 0);

  mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *));
  if(mbox->mbx == NULL) {
    SYS_STATS_INC(mbox.err);
    return ERR_MEM;
  }
  SYS_STATS_INC_USED(mbox);
  return ERR_OK;
}

void
sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
  BaseType_t ret;
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

  ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY);
  LWIP_ASSERT("mbox post failed", ret == pdTRUE);
}

err_t
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
  BaseType_t ret;
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

  ret = xQueueSendToBack(mbox->mbx, &msg, 0);
  if (ret == pdTRUE) {
    return ERR_OK;
  } else {
    LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
    SYS_STATS_INC(mbox.err);
    return ERR_MEM;
  }
}

err_t
sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
{
  BaseType_t ret;
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

  ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken);
  if (ret == pdTRUE) {
    if (xHigherPriorityTaskWoken == pdTRUE) {
      return ERR_NEED_SCHED;
    }
    return ERR_OK;
  } else {
    LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
    SYS_STATS_INC(mbox.err);
    return ERR_MEM;
  }
}

u32_t
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms)
{
  BaseType_t ret;
  void *msg_dummy;
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

  if (!msg) {
    msg = &msg_dummy;
  }

  if (!timeout_ms) {
    /* wait infinite */
    ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY);
    LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
  } else {
    TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
    ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks);
    if (ret == errQUEUE_EMPTY) {
      /* timed out */
      *msg = NULL;
      return SYS_ARCH_TIMEOUT;
    }
    LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
  }

  /* Old versions of lwIP required us to return the time waited.
     This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
     here is enough. */
  return 1;
}

u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
  BaseType_t ret;
  void *msg_dummy;
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

  if (!msg) {
    msg = &msg_dummy;
  }

  ret = xQueueReceive(mbox->mbx, &(*msg), 0);
  if (ret == errQUEUE_EMPTY) {
    *msg = NULL;
    return SYS_MBOX_EMPTY;
  }
  LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);

  /* Old versions of lwIP required us to return the time waited.
     This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
     here is enough. */
  return 1;
}

void
sys_mbox_free(sys_mbox_t *mbox)
{
  LWIP_ASSERT("mbox != NULL", mbox != NULL);
  LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);

#if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
  {
    UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx);
    LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);

    if (msgs_waiting != 0) {
      SYS_STATS_INC(mbox.err);
    }
  }
#endif

  vQueueDelete(mbox->mbx);

  SYS_STATS_DEC(mbox.used);
}

sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
  TaskHandle_t rtos_task;
  BaseType_t ret;
  sys_thread_t lwip_thread;
  size_t rtos_stacksize;

  LWIP_ASSERT("invalid stacksize", stacksize > 0);
#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
  rtos_stacksize = (size_t)stacksize;
#else
  rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);
#endif

  /* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
     thread function without adaption here. */
  ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task);
  LWIP_ASSERT("task creation failed", ret == pdTRUE);

  lwip_thread.thread_handle = rtos_task;
  return lwip_thread;
}

#if LWIP_NETCONN_SEM_PER_THREAD
#if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0

sys_sem_t *
sys_arch_netconn_sem_get(void)
{
  void* ret;
  TaskHandle_t task = xTaskGetCurrentTaskHandle();
  LWIP_ASSERT("task != NULL", task != NULL);

  ret = pvTaskGetThreadLocalStoragePointer(task, 0);
  return ret;
}

void
sys_arch_netconn_sem_alloc(void)
{
  void *ret;
  TaskHandle_t task = xTaskGetCurrentTaskHandle();
  LWIP_ASSERT("task != NULL", task != NULL);

  ret = pvTaskGetThreadLocalStoragePointer(task, 0);
  if(ret == NULL) {
    sys_sem_t *sem;
    err_t err;
    /* need to allocate the memory for this semaphore */
    sem = mem_malloc(sizeof(sys_sem_t));
    LWIP_ASSERT("sem != NULL", sem != NULL);
    err = sys_sem_new(sem, 0);
    LWIP_ASSERT("err == ERR_OK", err == ERR_OK);
    LWIP_ASSERT("sem invalid", sys_sem_valid(sem));
    vTaskSetThreadLocalStoragePointer(task, 0, sem);
  }
}

void sys_arch_netconn_sem_free(void)
{
  void* ret;
  TaskHandle_t task = xTaskGetCurrentTaskHandle();
  LWIP_ASSERT("task != NULL", task != NULL);

  ret = pvTaskGetThreadLocalStoragePointer(task, 0);
  if(ret != NULL) {
    sys_sem_t *sem = ret;
    sys_sem_free(sem);
    mem_free(sem);
    vTaskSetThreadLocalStoragePointer(task, 0, NULL);
  }
}

#else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
#error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS
#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */

#endif /* LWIP_NETCONN_SEM_PER_THREAD */

#if LWIP_FREERTOS_CHECK_CORE_LOCKING
#if LWIP_TCPIP_CORE_LOCKING

/** Flag the core lock held. A counter for recursive locks. */
static u8_t lwip_core_lock_count;
static TaskHandle_t lwip_core_lock_holder_thread;

void
sys_lock_tcpip_core(void)
{
   sys_mutex_lock(&lock_tcpip_core);
   if (lwip_core_lock_count == 0) {
     lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle();
   }
   lwip_core_lock_count++;
}

void
sys_unlock_tcpip_core(void)
{
   lwip_core_lock_count--;
   if (lwip_core_lock_count == 0) {
       lwip_core_lock_holder_thread = 0;
   }
   sys_mutex_unlock(&lock_tcpip_core);
}

#endif /* LWIP_TCPIP_CORE_LOCKING */

#if !NO_SYS
static TaskHandle_t lwip_tcpip_thread;
#endif

void
sys_mark_tcpip_thread(void)
{
#if !NO_SYS
  lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
#endif
}

void
sys_check_core_locking(void)
{
  /* Embedded systems should check we are NOT in an interrupt context here */
  /* E.g. core Cortex-M3/M4 ports:
         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );

     Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */
  taskENTER_CRITICAL();
  taskEXIT_CRITICAL();

#if !NO_SYS
  if (lwip_tcpip_thread != 0) {
    TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();

#if LWIP_TCPIP_CORE_LOCKING
    LWIP_ASSERT("Function called without core lock",
                current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);
#else /* LWIP_TCPIP_CORE_LOCKING */
    LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);
#endif /* LWIP_TCPIP_CORE_LOCKING */
  }
#endif /* !NO_SYS */
}

#endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/
/*
 * Copyright (c) 2017 Simon Goldschmidt
 * 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: Simon Goldschmdit <[email protected]>
 *
 */
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H

#include "lwip/opt.h"
#include "lwip/arch.h"

/** This is returned by _fromisr() sys functions to tell the outermost function
 * that a higher priority task was woken and the scheduler needs to be invoked.
 */
#define ERR_NEED_SCHED 123

/* This port includes FreeRTOS headers in sys_arch.c only.
 *  FreeRTOS uses pointers as object types. We use wrapper structs instead of
 * void pointers directly to get a tiny bit of type safety.
 */

void sys_arch_msleep(u32_t delay_ms);
#define sys_msleep(ms) sys_arch_msleep(ms)

#if SYS_LIGHTWEIGHT_PROT
typedef u32_t sys_prot_t;
#endif /* SYS_LIGHTWEIGHT_PROT */

#if !LWIP_COMPAT_MUTEX
struct _sys_mut {
  void *mut;
};
typedef struct _sys_mut sys_mutex_t;
#define sys_mutex_valid_val(mutex)   ((mutex).mut != NULL)
#define sys_mutex_valid(mutex)       (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))
#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)
#endif /* !LWIP_COMPAT_MUTEX */

struct _sys_sem {
  void *sem;
};
typedef struct _sys_sem sys_sem_t;
#define sys_sem_valid_val(sema)   ((sema).sem != NULL)
#define sys_sem_valid(sema)       (((sema) != NULL) && sys_sem_valid_val(*(sema)))
#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)

struct _sys_mbox {
  void *mbx;
};
typedef struct _sys_mbox sys_mbox_t;
#define sys_mbox_valid_val(mbox)   ((mbox).mbx != NULL)
#define sys_mbox_valid(mbox)       (((mbox) != NULL) && sys_mbox_valid_val(*(mbox)))
#define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL)

struct _sys_thread {
  void *thread_handle;
};
typedef struct _sys_thread sys_thread_t;

#if LWIP_NETCONN_SEM_PER_THREAD
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()
#endif /* LWIP_NETCONN_SEM_PER_THREAD */

#endif /* LWIP_ARCH_SYS_ARCH_H */

4.4 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 __CC_H__
#define __CC_H__

//#include "cpu.h"
#include <stdlib.h>
#include <stdio.h>

typedef int sys_prot_t;

//#define LWIP_PROVIDE_ERRNO

#if defined (__GNUC__) & !defined (__CC_ARM)

#define LWIP_TIMEVAL_PRIVATE 0
#include <sys/time.h>

#endif

/* define compiler specific symbols */
#if defined (__ICCARM__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES

#elif defined (__GNUC__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__CC_ARM)

#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__TASKING__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#endif
#include "bsp.h"
#define LWIP_PLATFORM_ASSERT(x) do {PRINTF("Assertion \"%s\" failed at line %d in %s\n", \
                                     x, __LINE__, __FILE__); } while(0)

/* Define random number generator function */
#define LWIP_RAND() ((u32_t)rand())

#endif /* __CC_H__ */

4.5 lwipopts.h

/**
  ******************************************************************************
  * @file    LwIP/LwIP_TCP_Echo_Client/Inc/lwipopts.h
  * @author  MCD Application Team
  * @brief   lwIP Options Configuration.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2017 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__

/* NO_SYS 表示无操作系统模拟层,无操作系统为1,有操作系统设置为0 
   注意这个参数设置会编译不同 */
//1:表示无操作系统
#define NO_SYS                  0

/**
 * SYS_LIGHTWEIGHT_PROT==0: disable inter-task protection (and task-vs-interrupt
 * protection) for certain critical regions during buffer allocation, deallocation
 * and memory allocation and deallocation.
 */
#define SYS_LIGHTWEIGHT_PROT    0

/* ---------- 内存选项 ---------- */
/* 内存对齐,按照 4 字节对齐  */
#define MEM_ALIGNMENT           4

/* 堆内存的大小,如果需要更大的堆内存,那么设置高一点 */
#define MEM_SIZE                (20*1024)

/* MEMP_NUM_PBUF: 设置内存池的数量  */
#define MEMP_NUM_PBUF           15
/* MEMP_NUM_UDP_PCB: UDP协议控制块的数量. */
#define MEMP_NUM_UDP_PCB        4
/* MEMP_NUM_TCP_PCB: TCP的数量. */
#define MEMP_NUM_TCP_PCB        4
/* MEMP_NUM_TCP_PCB_LISTEN: 监听TCP的数量. */
#define MEMP_NUM_TCP_PCB_LISTEN 2
/* MEMP_NUM_TCP_SEG: 同时排队的TCP的数量段. */
#define MEMP_NUM_TCP_SEG        120
/* MEMP_NUM_SYS_TIMEOUT: 超时模拟活动的数量. */
#define MEMP_NUM_SYS_TIMEOUT    6


/* ---------- Pbuf选项 ---------- */
/* PBUF_POOL 内存池中每个内存块大小 */
#define PBUF_POOL_SIZE          20

/* PBUF_POOL_BUFSIZE: pbuf池中每个pbuf的大小. */
#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)

/* ---------- TCP选项 ---------- */
#define LWIP_TCP                1
#define TCP_TTL                 255

/* 控制TCP是否应该对到达的段进行排队
   秩序。如果你的设备内存不足,定义为0. */
#define TCP_QUEUE_OOSEQ         0

/* TCP最大段大小 */
#define TCP_MSS                 (1500 - 40)      /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */

/* TCP发送者缓冲区空间(字节). */
#define TCP_SND_BUF             (11*TCP_MSS)

/*  TCP_SND_QUEUELEN: TCP发送缓冲区空间。这必须是至少
    需要(2 * TCP_SND_BUF/TCP_MSS)才能正常工作 */

#define TCP_SND_QUEUELEN        (8* TCP_SND_BUF/TCP_MSS)

/* TCP接收窗口 */
#define TCP_WND                 (2*TCP_MSS)


/* ---------- ICMP 选项 ---------- */
#define LWIP_ICMP               1

/* ---------- DHCP 选项 ---------- */
/* 如果您希望DHCP配置为,请将LWIP_DHCP定义为1 */
#define LWIP_DHCP               1

/* ---------- UDP 选项 ---------- */
#define LWIP_UDP                1
#define UDP_TTL                 255

/* ---------- Statistics 选项 ---------- */
#define LWIP_STATS              0
#define LWIP_PROVIDE_ERRNO      1

/* ---------- 链接回调选项 ---------- */
/* WIP_NETIF_LINK_CALLBACK==1:支持来自接口的回调函数
   每当链接改变(例如,向下链接)
 */
#define LWIP_NETIF_LINK_CALLBACK        1

/*
   --------------------------------------
   ------------ 帧校验和选项 ------------
   --------------------------------------
*/

/* 
The STM32F4xx allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
 - To use this feature let the following define uncommented.
 - To disable it and process by CPU comment the  the checksum.
*/
#define CHECKSUM_BY_HARDWARE 


#ifdef CHECKSUM_BY_HARDWARE
  /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
  #define CHECKSUM_GEN_IP                 0
  /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
  #define CHECKSUM_GEN_UDP                0
  /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
  #define CHECKSUM_GEN_TCP                0 
  /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
  #define CHECKSUM_CHECK_IP               0
  /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
  #define CHECKSUM_CHECK_UDP              0
  /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
  #define CHECKSUM_CHECK_TCP              0
  /* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
  #define CHECKSUM_GEN_ICMP               0
#else
  /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
  #define CHECKSUM_GEN_IP                 1
  /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
  #define CHECKSUM_GEN_UDP                1
  /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
  #define CHECKSUM_GEN_TCP                1
  /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
  #define CHECKSUM_CHECK_IP               1
  /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
  #define CHECKSUM_CHECK_UDP              1
  /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
  #define CHECKSUM_CHECK_TCP              1
  /* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/
  #define CHECKSUM_GEN_ICMP               1
#endif

/*
   ----------------------------------------------
   ---------------- 连续层的选择 ----------------
   ---------- Sequential layer options ----------
   ----------------------------------------------
*/
/**
 * LWIP_NETCONN==1:启用Netconn API(需要使用api_lib.c)
 */
#define LWIP_NETCONN                    1

/*
   ------------------------------------
   ------------ Socket选项 ------------
   ---------- Socket options ----------
   ------------------------------------
*/
/**
 * LWIP_SOCKET==1:启用Socket API(要求使用Socket .c)
 */
#define LWIP_SOCKET                     1

/*
   ------------------------------------
   ---------- httpd options ----------
   ------------------------------------
*/
/** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the
 * file system (to prevent changing the file included in CVS) */
#define HTTPD_USE_CUSTOM_FSDATA         1
/*
   ---------------------------------
   ---------- 操作系统选项 ----------
   ---------------------------------
*/

#define TCPIP_THREAD_NAME               "TCP/IP"
#define TCPIP_THREAD_STACKSIZE          1000
#define TCPIP_MBOX_SIZE                 6
#define DEFAULT_UDP_RECVMBOX_SIZE       6
#define DEFAULT_TCP_RECVMBOX_SIZE       6
#define DEFAULT_ACCEPTMBOX_SIZE         6
#define DEFAULT_THREAD_STACKSIZE        500
#define TCPIP_THREAD_PRIO               5
#define LWIP_SO_RCVTIMEO                1

#endif /* __LWIPOPTS_H__ */

5. 修改ETH中断的优先级,使能被系统管理

6. 添加ethernet task

/* Includes ------------------------------------------------------------------*/
#include "Task_ethernet.h"
#include "bsp.h"
#include "mydata.h"
#include "lwip_comm.h"
/* Private macros ------------------------------------------------------------*/
/*******任务优先级******/
#define LWIP_TASK_PRIO        1
/*******任务堆栈大小******/    
#define LWIP_STK_SIZE         1024 
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* 定义线程控制块指针 */
static TaskHandle_t LWIP_Task_Handle = NULL;
/* Private functions ---------------------------------------------------------*/
int ethernet_task_init(void)
{
    while ( lwip_comm_init() != 0 )
    {
        LED1_Toggle();
        My_mDelay( 500 );
    }
#if LWIP_DHCP
    while (g_lwipdev.dhcpstatus != 2 && g_lwipdev.dhcpstatus != 0xff)/* 等待静态和动态分配完成  */
    {
        My_mDelay(500);
    }
#endif
    
    return 0;
}
/* Exported macros -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
void ethernet_task(void *pvParameters)
{
    static uint16_t _time = 0;
    
    ethernet_task_init();
    while(1)
    {
        if( ++_time == 500 )  {
            _time = 0;
            LED1_Toggle();
        }
        My_mDelay( 0 );
    }
}
int Task_Eth_create(void)
{
    /********************任务初始化**************************/
    /* 创建任务 */
    if( pdPASS == xTaskCreate( (TaskFunction_t )ethernet_task,       /* 任务入口函数 */
                               (const char*    )"eth",               /* 任务名字 */
                               (uint16_t       )LWIP_STK_SIZE,       /* 任务栈大小 */
                               (void*          )NULL,                 /* 任务入口函数参数 */
                               (UBaseType_t    )LWIP_TASK_PRIO,         /* 任务的优先级 */
                               (TaskHandle_t*  )&LWIP_Task_Handle) ) /* 任务控制块指针 */
        PRINTF("[D] [RTOS] ethernet_task create succeed!\r\n");
    else
        PRINTF("[D] [RTOS] ethernet_task create failure!\r\n");

    return 0;
}

 

标签:LWIP,操作系统,FreeRTOS,CHIP,sys,netif,lwIP,ETH,define
From: https://www.cnblogs.com/LiuYong2021/p/18355014

相关文章

  • 操作系统实验学习进度
    最近开始学习操作系统和机组的相关知识,写一个学习进度的笔记作为鞭策,其中的dayn不一定全是一天内完成的,同时,大部分文字来源于学习资料rCore-Tutorial-Book第三版。Day0-入门操作系统初步介绍1.定义一个操作系统(OS)是一个软件,它帮助用户和应用程序使用和管理计算机的......
  • Realtek 网卡驱动程序是用于操作系统与 Realtek 网络适配器之间的通信软件。这些驱动
    Realtek网卡,特别是用于个人电脑和服务器的网卡,曾经发现过一些安全漏洞。以下是一些常见的Realtek网卡漏洞及其相关信息:CVE-2020-28015:这个漏洞存在于RealtekRTL8188EU驱动程序中,影响了在特定情况下的无线网络连接。攻击者可以利用这个漏洞执行任意代码或引发系统崩溃。......
  • 打开Office(word、excel、ppt)显示操作系统当前的配置不能运行此应用程序最全解决方案
    我以前用过分区助手把office从c盘挪到d盘了,从那以后office就用不了了,然后我就删了(貌似没删干净)。最近由于有使用word的需求,所以我从学校官网找到正版软件的安装包,按照步骤重新卸载电脑中office残留并安装好之后,打开word会提示“操作系统当前的配置不能运行此应用程序”,ppt......
  • 【读书笔记-《30天自制操作系统》-1】Day1~Day2
    顾名思义,本书将制作操作系统的整个过程分成了30天来依次讲解。但其实每一天的内容多少与难度各不相同,也并不是每天就可以学习完书中一天的内容。前面的内容要少一些,也比较基础,因此先把第一天和第二天的内容合并起来整理。1.二进制与CPU作者没有从概念开始讲起,而是开篇就......
  • 07.FreeRTOS列表与列表项
    文章目录07.FreeRTOS列表与列表项1.列表和列表项的简介2.列表相关API函数3.代码验证07.FreeRTOS列表与列表项1.列表和列表项的简介列表的定义:typedefstructxLIST{ listFIRST_LIST_INTEGRITY_CHECK_VALUE/*校验值*/ volatileUBaseType_tux......
  • 从事操作系统开发需要具备的知识体系
    操作系统作为计算机硬件与上层应用软件之间的桥梁,其设计与开发是一项复杂而艰巨的任务,要求开发者具备广泛而深入的技术知识。以下是从事操作系统开发所需掌握的八个关键方面:1.计算机体系结构硬件基础:理解CPU的指令集架构(如x86、ARM)、寄存器、内存结构(如RAM、ROM、缓存)、I......
  • 操作系统知识,应付考研复习、期末考试或者工作面试,2h便可看完
    本文是看b站清华大学博主@五道口一只鸭,整理出的学习笔记,主要目的是为了让自己以后方便复习。一、操作系统的概念及特征1、计算机系统的概念:计算机系统由软件和硬件两部分组成。软件:包括系统软件和应用软件。软件(就是程序)定义:完成一定任务的程序及其数据。系统软件:操作系统......
  • [图文直播]Windows操作系统部署Jenkins
    前言首先说明一下我为什么选择在Windows操作系统上部署Jenkins是吧,主要基于虽然从长远上看,我是有进行跨平台开发的需求,但至少在可预见的三到五年时间内,我的潜在客户也都是在windows操作系统上。至于跨平台,规划上要有,但正如天龙八部里天龙寺内面对鸠摩智打算拿拈花指、无相劫指......
  • freertos学习笔记(十一)直接任务通知
    直接任务通知起源队列和信号量是实时操作系统的典型功能,而FreeRTOS提供的直接任务通知比队列和信号量更小且速度更快(快45%)开发人员应优先使用量身定制的功能:直接任务通知、消息缓冲区和流缓冲区。大多数应用程序中,使用队列和信号量等综合功能可能是例外而不是常态实现......
  • KEIL V5编译器换V6编译器后编译lwip报错问题
    2.1.2版本中的lwip有一个叫errno.h的头文件,文件名字叫errno.h,但是文件内部的定义却是“LWIP_HDR_ERRNO_H”这在V5编译器里没有报错,能正常使用,但是在V6编译器里就不行了,“err.c”这个地方全都会报错(useofundeclaredidentifier'LWIP_ENOMEM'),编译器找不到这些宏定义的定义在......