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, ®val);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, ®value);switch (regvalue){case YT8522_PHYREGISTER2:{pobj->io.readreg(addr, PHY_REGISTER3, ®value);//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, ®value);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, ®value) < 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, ®value) >= 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, ®value) < 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(ÐCHIP, Ð_CHIP_IOCtx); #endif/* 初始化ETH PHY */eth_chip_init( ÐCHIP, Ð_CHIP_IOCtx );/* 必须开启自动协商功能 */eth_chip_start_auto_nego(ÐCHIP);/* 必须等待初始化 */HAL_Delay( 2000 );phy_link_state = eth_chip_get_link_state(ÐCHIP);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, ðernetif_init, ðernet_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, ®val);/* 判断链接状态 */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; }