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

news/2024/11/14 12:43:01/文章来源:https://www.cnblogs.com/LiuYong2021/p/18355014

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 donein 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:100M0: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);//0x0000E928regvalue = regvalue >> 10;//0x0000003Aif( 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
//
#endifif ( 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.h1.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.h2.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 mustpassed 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_OSif (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_OSpbuf_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);
#elseHAL_ETH_Transmit(&g_eth_handler, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
#endifreturn 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_OSportBASE_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);
#endifnetif->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_OSuint8_t eth_linkstate;lwip_init();
#elsetcpip_init(NULL, NULL);
#endif lwip_comm_default_ip_set(&g_lwipdev);           /* 设置默认IP等信息 */#if LWIP_DHCPip_addr_set_zero_ip4(&ipaddr);ip_addr_set_zero_ip4(&netmask);ip_addr_set_zero_ip4(&gw);
#elseIP4_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_CALLBACKlwip_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
#elsenetif_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_DHCPg_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_OSdo{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_DHCPg_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;dhcp_stop(netif);
#endifHAL_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 <goldsimon@gmx.de>**//* 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;
}
#endifu32_t
sys_jiffies(void)
{return xTaskGetTickCount();
}#if SYS_LIGHTWEIGHT_PROTsys_prot_t
sys_arch_protect(void)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEXBaseType_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;}
#elsereturn 1;
#endif
}void
sys_arch_unprotect(sys_prot_t pval)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEXBaseType_t ret;
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECKLWIP_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_MUTEXLWIP_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_TIMEOUThere 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_TIMEOUThere 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_TIMEOUThere 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);}}
#endifvQueueDelete(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_STACKWORDSrtos_stacksize = (size_t)stacksize;
#elsertos_stacksize = (size_t)stacksize / sizeof(StackType_t);
#endif/* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass thethread 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 > 0sys_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;
#endifvoid
sys_mark_tcpip_thread(void)
{
#if !NO_SYSlwip_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_SYSif (lwip_tcpip_thread != 0) {TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();#if LWIP_TCPIP_CORE_LOCKINGLWIP_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 <goldsimon@gmx.de>**/
#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 <adam@sics.se>**/
#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_DHCPwhile (g_lwipdev.dhcpstatus != 2 && g_lwipdev.dhcpstatus != 0xff)/* 等待静态和动态分配完成  */{My_mDelay(500);}
#endifreturn 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");elsePRINTF("[D] [RTOS] ethernet_task create failure!\r\n");return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/781784.html

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

相关文章

Less is richness,基于less is more的博客园宽屏主题魔改

写在前面 之前做过很多个人博客,都是做着玩的,资源托管在免费或低价的服务器上,也不经常维护,所以就一直不长久,最终还是选择了博客园。发现博客园可以自定义样式,于是试着给博客换了一个又一个主题。个人比较喜欢宽屏的样式,感觉LessIsMore主题布局比较好、也比较简洁,…

5 大场景上手通义灵码企业知识库 RAG

大家好,我是通义灵码,你的智能编程助手!最近我又升级啦,智能问答功能全面升级至 Qwen2,新版本在各个方面的性能和准确性都得到了显著提升。此外,行间代码补全效果也全面优化,多种编程语言生成性能及准确性大幅提升,如前端、Java、Go、Python、C++ 等。此外,灵码新增代…

2024 年了,IT 运维监控系统都有哪些推荐?

大浪淘沙,2024 年的今天,市面上很多监控系统慢慢淡出了大家的视野,而一些新的监控系统也逐渐崭露头角。今天我们就来看看 2024 年的当下,哪些 IT 运维监控系统最值得关注。 Prometheus毫无疑问,Prometheus 是最值得关注的监控系统,因为 Prometheus 的规范和生态都非常厉害…

不只是前端,后端、产品和测试也需要了解的浏览器知识(二)

继上篇《 不只是前端,后端、产品和测试也需要了解的浏览器知识(一)》介绍了浏览器的基本情况、发展历史以及市场占有率。 本篇文章将介绍浏览器基本原理。在掌握基本原理后,通过技术深入,在研发过程中不断创新,推动产品性能、用户体验的提升,来实现业务的增长,创造可持…

三十分钟入门基础Go(Java小子版)

前言 Go语言定义 Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态、强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC,结构形态及 CSP-style 并发计算。 适用范围 本篇文章适用于学习过其他面向对象语言(Java、…

(二) 树莓派CM4调试

1. 参考资料资料汇总页面https://shumeipai.nxez.com/raspberry-pi-datasheets《bcm2711-peripherals.pdf》,下载地址https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf《cm4io-datasheet.pdf》,下载地址https://datasheets.raspberrypi.com/cm4/cm4-data…

中国式报表有这么多种类型,你都知道吗?

中国式报表是一种在中国企业中使用的会计报告格式,但你真的了解它吗?你知道它有多少种类型吗?今天我们就一起来聊聊,中国式报表都包含哪些类型的报表吧!按样式来划分,中国式报表通常分为以下几类:1. 行式报表 行式报表也就是我们常说的清单式明细表,是最常见也是最简单…

JDBC加载MySQL驱动【底层实现】

JDBC4.0如何加载引入依赖<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.32</version></dependency>上代码import java.sql.Connection;import java.sql.DriverManager;imp…

tensorboard_logger库无法导入的问题解决

一、问题描述最近在学习深度学习时,从大神们那里copy的代码中有用到tensorboard_logger这个库的东西,所以很自然地就用conda install或者pip去安装它,但是结果是:python开源库里面没有这东西。 这就让我很苦恼,所以只能自己动手,丰衣足食了。 二、解决方法首先找到tenso…

sqlserver 2000 数据库文件*。mdf附加到sql2008 报错 提示使用dbcc checkcatalog检查

sqlserver 2000 数据库文件*。mdf附加到sql2008 报错 提示使用dbcc checkcatalog检查检查提示有两个存储过程对象 在 SYSOBJECTS 与 SYSCOMMENTS 之间不匹配。drop procedure TS_G_ArApIniModiy drop procedure TS_T_CRMContactionQry 删除这两个存储过程之后可以直接在sqlser…

广东盈致MES系统——注塑和冲压行业的智能化管理

广东注塑冲压行业MES制造执行系统是一种专门为注塑和冲压行业设计的生产管理系统,可以帮助企业实现生产过程的智能化管理和优化。盈致MES系统是一种常见的MES系统,具有以下特点和功能: 生产计划和调度:MES系统可以帮助企业进行生产计划和任务调度,根据订单需求和资源情况进…

电子取证

内存取证、磁盘取证、服务器取证电子取证tool DiskGenius、FTK、Rstudio,各种都挂一手文件位置 windows ntds.dit: C:\Windows\NTDS\NTDS.dit system: C:\Windows\System32\config\SYSTEM sam: C:\Windows\System32\config\SAMpowershell命令记录:\AppData\Roaming\Mi…