1. lwIP前期准备
在程序工程中,我们在工程文件夹下创建了一个名为 “lwip”的子文件夹。在“lwip”文件夹下,我们又创建了一个子文件夹:arch 。arch 文件夹用于存放 lwIP 系统的配置文件;
2. 添加lwIP源文件
3. 添加网卡驱动程序
/* Includes ------------------------------------------------------------------*/ #include "bsp_hal_ethernet.h" /* Private macros ------------------------------------------------------------*/ #define YT8522_RESET_HIGH() HAL_GPIO_WritePin(YT8522_RESET_GPIO_Port, YT8522_RESET_Pin, GPIO_PIN_SET) #define YT8522_RESET_LOW() HAL_GPIO_WritePin(YT8522_RESET_GPIO_Port, YT8522_RESET_Pin, GPIO_PIN_RESET) #if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE ) #define YT8522_PHYREGISTER2 0x4F51 #define YT8522_PHYREGISTER3 0x001C #define YT8512C_PHYREGISTER2 0x0000 #define YT8512C_PHYREGISTER3 0x0128 #endif #define ETH_CHIP_SW_RESET_TO ((uint32_t)500U) /* 软件复位等待时间 */ #define ETH_CHIP_MAX_DEV_ADDR ((uint32_t)31U) /* PHY地址的最大值 */ #define ETH_CHIP_INIT_TO ((uint32_t)2000U) /* 初始化等待时间 */ /* Private types -------------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ #if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE ) /* 选择PHY芯片 ---- 自动选择 */ int PHY_TYPE; uint16_t ETH_CHIP_PHYSCSR; uint16_t ETH_CHIP_SPEED_STATUS; uint16_t ETH_CHIP_DUPLEX_STATUS; #endif /* Private functions ---------------------------------------------------------*/ /******************************************************************************* PHI IO Functions *******************************************************************************/ /** * @brief Initializes the MDIO interface GPIO and clocks. * @param None * @retval 0 if OK, -1 if ERROR */ static int32_t ETH_PHY_IO_Init(void) { /* We assume that MDIO GPIO configuration is already done in the ETH_MspInit() else it should be done here */ /* Configure the MDIO Clock */ HAL_ETH_SetMDIOClockRange(&g_eth_handler); return 0; } /** * @brief De-Initializes the MDIO interface . * @param None * @retval 0 if OK, -1 if ERROR */ static int32_t ETH_PHY_IO_DeInit (void) { return 0; } /** * @brief Read a PHY register through the MDIO interface. * @param DevAddr: PHY port address * @param RegAddr: PHY register address * @param pRegVal: pointer to hold the register value * @retval 0 if OK -1 if Error */ static int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal) { if (HAL_ETH_ReadPHYRegister(&g_eth_handler, DevAddr, RegAddr, pRegVal) != HAL_OK) { return -1; } return 0; } /** * @brief Write a value to a PHY register through the MDIO interface. * @param DevAddr: PHY port address * @param RegAddr: PHY register address * @param RegVal: Value to be written * @retval 0 if OK -1 if Error */ static int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal) { if (HAL_ETH_WritePHYRegister(&g_eth_handler, DevAddr, RegAddr, RegVal) != HAL_OK) { return -1; } return 0; } /** * @brief Get the time in millisecons used for internal PHY driver process. * @retval Time value */ static int32_t ETH_PHY_IO_GetTick(void) { return HAL_GetTick(); } /* Exported macros -----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ eth_chip_ioc_tx_t ETH_CHIP_IOCtx = { ETH_PHY_IO_Init, ETH_PHY_IO_DeInit, ETH_PHY_IO_WriteReg, ETH_PHY_IO_ReadReg, ETH_PHY_IO_GetTick }; /* Exported functions --------------------------------------------------------*/ void ethernet_reset(void) { YT8522_RESET_LOW(); /* 硬件复位 */ HAL_Delay(100); YT8522_RESET_HIGH(); /* 复位结束 */ HAL_Delay(100); } /** * @breif 读取以太网芯片寄存器值 * @param reg:读取的寄存器地址 * @retval 无 */ uint32_t ethernet_read_phy(uint16_t reg) { uint32_t regval; HAL_ETH_ReadPHYRegister(&g_eth_handler, ETHERNET_PHY_ADDRESS, reg, ®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:100M 0:10M */ uint8_t ethernet_chip_get_speed(void) { uint8_t speed; if(PHY_TYPE == YT8522) { /* 从YT8522的17号寄存器中读取网络速度 */ speed = ( ( ethernet_read_phy( ETH_CHIP_PHYSCSR ) & ETH_CHIP_SPEED_STATUS ) >> 14 ); } else if(PHY_TYPE == YT8512C) { speed = ((ethernet_read_phy(ETH_CHIP_PHYSCSR) & ETH_CHIP_SPEED_STATUS) >> 14); /* 从YT8512C的17号寄存器中读取网络速度和双工模式 */ } return speed; } /******************************************************************************* ETHERNET CHIP *******************************************************************************/ /** * @brief 将IO函数注册到组件对象 * @param pobj:设备对象 * @param ioctx:保存设备IO功能 * @retval ETH_CHIP_STATUS_OK:OK * ETH_CHIP_STATUS_ERROR:缺少功能 */ static int32_t eth_chip_regster_bus_io( eth_chip_object_t *pobj, eth_chip_ioc_tx_t *ioctx ) { if (!pobj || !ioctx->readreg || !ioctx->writereg || !ioctx->gettick) { return ETH_CHIP_STATUS_ERROR; } pobj->io.init = ioctx->init; pobj->io.deinit = ioctx->deinit; pobj->io.readreg = ioctx->readreg; pobj->io.writereg = ioctx->writereg; pobj->io.gettick = ioctx->gettick; return ETH_CHIP_STATUS_OK; } /** * @brief 初始化ETH_CHIP并配置所需的硬件资源 * @param pobj: 设备对象 * @retval ETH_CHIP_STATUS_OK:初始化ETH_CHIP并配置所需的硬件资源成功 ETH_CHIP_STATUS_ADDRESS_ERROR:找不到设备地址 ETH_CHIP_STATUS_READ_ERROR:不能读取寄存器 ETH_CHIP_STATUS_WRITE_ERROR:不能写入寄存器 ETH_CHIP_STATUS_RESET_TIMEOUT:无法执行软件复位 */ int32_t eth_chip_init( eth_chip_object_t *pobj, eth_chip_ioc_tx_t *ioctx ) { uint32_t tickstart = 0; uint32_t regvalue = 0; uint32_t addr = 0; int32_t status = ETH_CHIP_STATUS_OK; eth_chip_regster_bus_io( pobj, ioctx ); #if ( PHY_AUTO_SELECT == PHY_AUTO_SELECT_NABLE ) pobj->io.readreg(addr, PHY_REGISTER2, ®value); switch (regvalue) { case YT8522_PHYREGISTER2:{ pobj->io.readreg(addr, PHY_REGISTER3, ®value);//0x0000E928 regvalue = regvalue >> 10;//0x0000003A if( regvalue == 0x3A ) { ETH_CHIP_PHYSCSR = ((uint16_t)0x11); ETH_CHIP_SPEED_STATUS = ((uint16_t)0x4010); ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x2000); PHY_TYPE = YT8522; } }break; case YT8512C_PHYREGISTER2:{ pobj->io.readreg(addr, PHY_REGISTER3, ®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 // #endif if ( pobj->is_initialized == 0 ) { if (pobj->io.init != 0) { /* MDC时钟 */ pobj->io.init(); } /* 设置PHY地址为32 */ pobj->devaddr = ETH_CHIP_MAX_DEV_ADDR + 1; /* 主要为了查找PHY地址 */ for (addr = 0; addr <= ETH_CHIP_MAX_DEV_ADDR; addr ++) { if (pobj->io.readreg(addr, ETH_CHIP_PHYSCSR, ®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.h 1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4, to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length) so that updated value will be generated in stm32xxxx_hal_conf.h 2.a. Rx Buffers number: ETH_RX_BUFFER_CNT must be greater than ETH_RX_DESC_CNT. 2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must passed to ETH DMA in the init field (heth.Init.RxBuffLen) */ typedef enum { RX_ALLOC_OK = 0x00, RX_ALLOC_ERROR = 0x01 } RxAllocStatusTypeDef; typedef struct { struct pbuf_custom pbuf_custom; uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32); } RxBuff_t; /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Memory Pool Declaration */ LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool"); /* */ static uint8_t RxAllocStatus; /* Global Ethernet handle*/ extern ETH_TxPacketConfig TxConfig; /* */ eth_chip_object_t ETHCHIP; /* */ #ifdef SYS_SUPPORT_OS xSemaphoreHandle g_tx_semaphore = NULL; /* 定义一个RX信号量 */ xSemaphoreHandle g_rx_semaphore = NULL; /* 定义一个TX信号量 */ #endif /* Private function prototypes -----------------------------------------------*/ void ethernetif_input( void * argument ); void RMII_Thread( void * argument ); /* Private functions ---------------------------------------------------------*/ /** * @brief 底层硬件初始化 * @param netif:以太网句柄 * @retval NULL **/ static void low_level_init(struct netif *netif) { ETH_MACConfigTypeDef g_eth_macconfig_handler = {0}; int32_t phy_link_state = 0; uint32_t duplex = 0; uint32_t speed = 0; MX_ETH_Init(); ethernet_reset(); /* 设置MAC地址长度,为6个字节 */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* 初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复 */ netif->hwaddr[0] = default_mac[0]; netif->hwaddr[1] = default_mac[1]; netif->hwaddr[2] = default_mac[2]; netif->hwaddr[3] = default_mac[3]; netif->hwaddr[4] = default_mac[4]; netif->hwaddr[5] = default_mac[5]; /* 最大允许传输单元,允许该网卡广播和ARP功能 */ netif->mtu = ETH_MAX_PAYLOAD; /* 网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播 */ /* 使能、 ARP 使能等等重要控制位 */ netif->flags |= NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP; /* Initialize the RX POOL */ LWIP_MEMPOOL_INIT(RX_POOL); /* 配置发送报文配置常用参数 */ #if 0 //在MX_ETH_Init()中已经配置 memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig)); TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD; TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT; #endif #ifdef SYS_SUPPORT_OS /* create a binary semaphore used for informing ethernetif of frame reception */ g_rx_semaphore = xSemaphoreCreateBinary(); /* create a binary semaphore used for informing ethernetif of frame transmission */ g_tx_semaphore = xSemaphoreCreateBinary(); /* create the task that handles the ETH_MAC */ sys_thread_new("eth_thread", ethernetif_input, /* 任务入口函数 */ netif, /* 任务入口函数参数 */ INTERFACE_THREAD_STACK_SIZE, /* 任务栈大小 */ NETIF_IN_TASK_PRIORITY); /* 任务的优先级 */ #endif #if 0 //在eth_chip_init()中已经配置 /* 设置PHY IO功能 */ eth_chip_regster_bus_io(Ð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_OS if (HAL_GetREVID() == 0x1000) { /* This thread will keep resetting the RMII interface until good frames are received */ sys_thread_new( "rmii_thread", RMII_Thread, /* 任务入口函数 */ NULL, /* 任务入口函数参数 */ configMINIMAL_STACK_SIZE, /* 任务栈大小 */ NETIF_IN_TASK_PRIORITY + 1); /* 任务的优先级 */ } #endif } /** * @brief 数据包输出函数 * @param netif:以太网句柄 * @param p: * @retval **/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { uint32_t i = 0U; struct pbuf *q = NULL; err_t errval = ERR_OK; ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0}; memset(Txbuffer, 0 , ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef)); for (q = p; q != NULL; q = q->next) { if (i >= ETH_TX_DESC_CNT) return ERR_IF; Txbuffer[i].buffer = q->payload; Txbuffer[i].len = q->len; if (i > 0) { Txbuffer[i - 1].next = &Txbuffer[i]; } if (q->next == NULL) { Txbuffer[i].next = NULL; } i++; } TxConfig.Length = p->tot_len; TxConfig.TxBuffer = Txbuffer; TxConfig.pData = p; #ifdef SYS_SUPPORT_OS pbuf_ref(p); HAL_ETH_Transmit_IT(&g_eth_handler, &TxConfig); while (xSemaphoreTake(g_tx_semaphore, TIME_WAITING_FOR_INPUT) != pdTRUE){} HAL_ETH_ReleaseTxPacket(&g_eth_handler); #else HAL_ETH_Transmit(&g_eth_handler, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT); #endif return errval; } /** * @brief 数据包输入函数 * @param netif:以太网句柄 * @retval **/ static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p = NULL; if( RxAllocStatus == RX_ALLOC_OK ) { HAL_ETH_ReadData(&g_eth_handler, (void **)&p); } return p; } /** * @brief Custom Rx pbuf free callback * @param pbuf: pbuf to be freed * @retval None */ static void pbuf_free_custom(struct pbuf *p) { struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p; LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf); /* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to * call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */ if (RxAllocStatus == RX_ALLOC_ERROR) { RxAllocStatus = RX_ALLOC_OK; #ifdef SYS_SUPPORT_OS portBASE_TYPE taskWoken = pdFALSE; if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE) { portEND_SWITCHING_ISR(taskWoken); } #endif } } /* Exported macros -----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ #ifdef SYS_SUPPORT_OS /** * This task should be signaled when a receive packet is ready to be read * from the interface. * * @param argument the lwip network interface structure for this ethernetif */ void ethernetif_input( void * argument ) { struct pbuf *p = NULL; struct netif *netif = (struct netif *) argument; for( ;; ) { if (xSemaphoreTake( g_rx_semaphore, TIME_WAITING_FOR_INPUT) == pdTRUE) { do { p = low_level_input( netif ); if (p != NULL) { if (netif->input( p, netif) != ERR_OK ) { pbuf_free(p); } } }while(p!=NULL); } } } /** * @brief RMII interface watchdog thread * @param argument * @retval None */ void RMII_Thread( void * argument ) { (void) argument; while (1) { /* some unicast good packets are received */ if (g_eth_handler.Instance->MMCRGUFCR > 0U) { /* RMII Init is OK: Delete the Thread */ vTaskDelete(NULL); } else if (g_eth_handler.Instance->MMCRFCECR > 10U) { /* ETH received too many packets with CRC errors, resetting RMII */ SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; g_eth_handler.Instance->MMCCR |= ETH_MMCCR_CR; } else { /* Delay 200 ms */ vTaskDelay(200); } } } #else /** * @brief 网卡输入(实际调用low_level_input) * @param netif:以太网句柄 * @retval NULL **/ void ethernetif_input(struct netif *netif) { struct pbuf *p = NULL; do { p = low_level_input( netif ); if (p != NULL) { if (netif->input( p, netif) != ERR_OK ) { pbuf_free(p); } } } while(p != NULL); } #endif /** * @brief 网卡驱动初始化 * @param netif:以太网句柄 * @retval **/ err_t ethernetif_init(struct netif *netif) { LWIP_ASSERT("netif != NULL", (netif != NULL)); #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = "lwip"; #endif /* LWIP_NETIF_HOSTNAME */ #ifdef SYS_SUPPORT_OS /* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); #endif netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; netif->linkoutput = low_level_output; /* initialize the hardware */ low_level_init(netif); return ERR_OK; } #ifndef SYS_SUPPORT_OS /** * @brief 提供lwIP时基 * @param 无 * @retval 当前时间值 **/ u32_t sys_now(void) { return HAL_GetTick(); } #endif /******************************************************************************* 回调函数 *******************************************************************************/ #ifdef SYS_SUPPORT_OS /** * @brief Ethernet Rx Transfer completed callback * @param heth: ETH handle * @retval None */ void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) { portBASE_TYPE taskWoken = pdFALSE; if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE) { portEND_SWITCHING_ISR(taskWoken); } } /** * @brief Ethernet Tx Transfer completed callback * @param heth: ETH handle * @retval None */ void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) { portBASE_TYPE taskWoken = pdFALSE; if (xSemaphoreGiveFromISR(g_tx_semaphore, &taskWoken) == pdTRUE) { portEND_SWITCHING_ISR(taskWoken); } } /** * @brief Ethernet DMA transfer error callback * @param heth: ETH handle * @retval None */ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) { if ((HAL_ETH_GetDMAError(heth) & ETH_DMASR_RBUS) == ETH_DMASR_RBUS) { portBASE_TYPE taskWoken = pdFALSE; if (xSemaphoreGiveFromISR(g_rx_semaphore, &taskWoken) == pdTRUE) { portEND_SWITCHING_ISR(taskWoken); } } } #endif void HAL_ETH_RxAllocateCallback(uint8_t **buff) { struct pbuf_custom *p = LWIP_MEMPOOL_ALLOC(RX_POOL); if (p) { /* Get the buff from the struct pbuf address. */ *buff = (uint8_t *)p + offsetof(RxBuff_t, buff); p->custom_free_function = pbuf_free_custom; /* Initialize the struct pbuf. * This must be performed whenever a buffer's allocated because it may be * changed by lwIP or the app, e.g., pbuf_free decrements ref. */ pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUFFER_SIZE); } else { RxAllocStatus = RX_ALLOC_ERROR; *buff = NULL; } } void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length) { struct pbuf **ppStart = (struct pbuf **)pStart; struct pbuf **ppEnd = (struct pbuf **)pEnd; struct pbuf *p = NULL; /* Get the struct pbuf from the buff address. */ p = (struct pbuf *)(buff - offsetof(RxBuff_t, buff)); p->next = NULL; p->tot_len = 0; p->len = Length; /* Chain the buffer. */ if (!*ppStart) { /* The first buffer of the packet. */ *ppStart = p; } else { /* Chain the buffer to the end of the packet. */ (*ppEnd)->next = p; } *ppEnd = p; /* Update the total length of all the buffers of the chain. Each pbuf in the chain should have its tot_len * set to its own length, plus the length of all the following pbufs in the chain. */ for (p = *ppStart; p != NULL; p = p->next) { p->tot_len += Length; } } void HAL_ETH_TxFreeCallback(uint32_t * buff) { pbuf_free((struct pbuf *)buff); }
#ifndef __ETHERNETIF_H__ #define __ETHERNETIF_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Includes ------------------------------------------------------------------*/ #include "lwip/err.h" #include "lwip/netif.h" /* Private macros ------------------------------------------------------------*/ /* Private types -------------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ err_t ethernetif_init(struct netif *netif); /* 网卡初始化函数 */ //void ethernetif_input(struct netif *netif); /* 数据包输入函数 */ //u32_t sys_now(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif // __ETHERNETIF_H__
4.2 lwip_comm.c/h
/* Includes ------------------------------------------------------------------*/ #include "lwip_comm.h" // #include "ethernetif.h" // #include "lwip/dhcp.h" #include "lwip/init.h" #include "lwip/timeouts.h" #include "lwip/tcpip.h" // #include "mytype.h" /* Private macros ------------------------------------------------------------*/ #ifdef SYS_SUPPORT_OS /* LINK线程配置 */ #define LWIP_LINK_TASK_PRIO 3 /* 任务优先级 */ #define LWIP_LINK_STK_SIZE 128 * 2 /* 任务堆栈大小 */ void lwip_link_thread( void * argument ); /* 链路线程 */ /* DHCP线程配置 */ #define LWIP_DHCP_TASK_PRIO 4 /* 任务优先级 */ #define LWIP_DHCP_STK_SIZE 128 * 2 /* 任务堆栈大小 */ void lwip_periodic_handle(void *argument); /* DHCP线程 */ void lwip_link_status_updated(struct netif *netif); /* DHCP状态回调函数 */ #endif /* Private types -------------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* lwip控制结构体 */ __lwip_dev g_lwipdev; /* 定义一个全局的网络接口 */ struct netif g_lwip_netif; #if LWIP_DHCP /* DHCP精细处理计时器 */ uint32_t g_dhcp_fine_timer = 0; /* DHCP状态初始化 */ __IO uint8_t g_lwip_dhcp_state = LWIP_DHCP_OFF; #endif /* Private functions ---------------------------------------------------------*/ /** * @breif lwip 默认IP设置 * @param lwipx : lwip控制结构体指针 * @retval 无 */ static void lwip_comm_default_ip_set(__lwip_dev *lwipx) { /* 默认远端IP为:192.168.1.134 */ lwipx->remoteip[0] = 192; lwipx->remoteip[1] = 168; lwipx->remoteip[2] = 1; lwipx->remoteip[3] = 88; /* MAC地址设置 */ lwipx->mac[0] = default_mac[0]; lwipx->mac[1] = default_mac[1]; lwipx->mac[2] = default_mac[2]; lwipx->mac[3] = default_mac[3]; lwipx->mac[4] = default_mac[4]; lwipx->mac[5] = default_mac[5]; /* 默认本地IP为:192.168.1.30 */ lwipx->ip[0] = 192; lwipx->ip[1] = 168; lwipx->ip[2] = 100; lwipx->ip[3] = 66; /* 默认子网掩码:255.255.255.0 */ lwipx->netmask[0] = 255; lwipx->netmask[1] = 255; lwipx->netmask[2] = 255; lwipx->netmask[3] = 0; /* 默认网关:192.168.1.1 */ lwipx->gateway[0] = 192; lwipx->gateway[1] = 168; lwipx->gateway[2] = 100; lwipx->gateway[3] = 1; lwipx->dhcpstatus = 0; /* 没有DHCP */ lwipx->lwip_display_fn = NULL; } /** * @brief 通知用户网络接口配置状态 * @param netif:网卡控制块 * @retval 无 */ static void lwip_link_status_updated(struct netif *netif) { if (netif_is_up(netif)) { #if LWIP_DHCP /* Update DHCP state machine */ g_lwip_dhcp_state = LWIP_DHCP_START; #endif /* LWIP_DHCP */ PRINTF ("The network cable is connected \r\n"); } else { #if LWIP_DHCP /* Update DHCP state machine */ g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN; #endif /* LWIP_DHCP */ PRINTF ("The network cable is not connected \r\n"); } } #ifndef SYS_SUPPORT_OS #if LWIP_DHCP /* 如果使用DHCP */ /** * @brief lwIP的DHCP分配进程 * @param netif:网卡控制块 * @retval 无 */ static void lwip_dhcp_process(struct netif *netif) { uint32_t ip = 0; uint32_t netmask = 0; uint32_t gw = 0; struct dhcp *dhcp; uint8_t iptxt[20]; /* 存储已分配的IP地址 */ g_lwipdev.dhcpstatus = 1; /* DHCP标记为1 */ /* 根据DHCP状态进入执行相应的动作 */ switch (g_lwip_dhcp_state) { case LWIP_DHCP_START: { /* 对IP地址、网关地址及子网页码清零操作 */ ip_addr_set_zero_ip4(&netif->ip_addr); ip_addr_set_zero_ip4(&netif->netmask); ip_addr_set_zero_ip4(&netif->gw); /* 设置DHCP的状态为等待分配IP地址 */ g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS; /* 开启DHCP */ dhcp_start(netif); } break; case LWIP_DHCP_WAIT_ADDRESS: { ip = g_lwip_netif.ip_addr.addr; /* 读取新IP地址 */ netmask = g_lwip_netif.netmask.addr; /* 读取子网掩码 */ gw = g_lwip_netif.gw.addr; /* 读取默认网关 */ PRINTF ("等待DHCP分配网络参数......\r\n"); if (dhcp_supplied_address(netif)) { PRINTF ("DHCP分配成功......\r\n"); g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED; sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr)); PRINTF ("IP address assigned by a DHCP server: %s\r\n", iptxt); if (ip != 0) { g_lwipdev.dhcpstatus = 2; /* DHCP??? */ PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]); /* 解析出通过DHCP获取到的IP地址 */ g_lwipdev.ip[3] = (uint8_t)(ip >> 24); g_lwipdev.ip[2] = (uint8_t)(ip >> 16); g_lwipdev.ip[1] = (uint8_t)(ip >> 8); g_lwipdev.ip[0] = (uint8_t)(ip); PRINTF("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 解析通过DHCP获取到的子网掩码地址 */ g_lwipdev.netmask[3] = (uint8_t)(netmask >> 24); g_lwipdev.netmask[2] = (uint8_t)(netmask >> 16); g_lwipdev.netmask[1] = (uint8_t)(netmask >> 8); g_lwipdev.netmask[0] = (uint8_t)(netmask); PRINTF("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); /* 解析出通过DHCP获取到的默认网关 */ g_lwipdev.gateway[3] = (uint8_t)(gw >> 24); g_lwipdev.gateway[2] = (uint8_t)(gw >> 16); g_lwipdev.gateway[1] = (uint8_t)(gw >> 8); g_lwipdev.gateway[0] = (uint8_t)(gw); PRINTF("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); } } else { dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); /* DHCP超时 */ if (dhcp->tries > LWIP_MAX_DHCP_TRIES) { PRINTF ("DHCP分配失败,进入静态分配......\r\n"); g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT; /* 停止DHCP */ dhcp_stop(netif); g_lwipdev.dhcpstatus = 0XFF; /* 使用静态IP地址 */ IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); IP4_ADDR(&(g_lwip_netif.netmask), g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); IP4_ADDR(&(g_lwip_netif.gw), g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); netif_set_addr(netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw); sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr)); PRINTF ("Static IP address: %s\r\n", iptxt); } } } break; case LWIP_DHCP_LINK_DOWN: { /* 停止 DHCP */ dhcp_stop(netif); g_lwip_dhcp_state = LWIP_DHCP_OFF; } break; default: break; } } #endif #endif /* Exported macros -----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ /** * @breif LWIP初始化(LWIP启动的时候使用) * @param 无 * @retval 0,成功 * 1,内存错误 * 2,以太网芯片初始化失败 * 3,网卡添加失败. */ uint8_t lwip_comm_init(void) { struct netif *netif_init_flag; /* 调用netif_add()函数时的返回值,用于判断网络初始化是否成功 */ ip_addr_t ipaddr; /* ip地址 */ ip_addr_t netmask; /* 子网掩码 */ ip_addr_t gw; /* 默认网关 */ #ifndef SYS_SUPPORT_OS uint8_t eth_linkstate; lwip_init(); #else tcpip_init(NULL, NULL); #endif lwip_comm_default_ip_set(&g_lwipdev); /* 设置默认IP等信息 */ #if LWIP_DHCP ip_addr_set_zero_ip4(&ipaddr); ip_addr_set_zero_ip4(&netmask); ip_addr_set_zero_ip4(&gw); #else IP4_ADDR(&ipaddr, g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); IP4_ADDR(&netmask, g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); IP4_ADDR(&gw, g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]); PRINTF("静态IP地址........................%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); PRINTF("子网掩码..........................%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); PRINTF("默认网关..........................%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); g_lwipdev.dhcpstatus = 0XFF; #endif /* 向网卡列表中添加一个网口 */ netif_init_flag = netif_add(&g_lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, ðernetif_init, ðernet_input); if (netif_init_flag == NULL) { return 1; /* 网卡添加失败 */ } else /* 网口添加成功后,设置netif为默认值,并且打开netif网口 */ { #ifdef SYS_SUPPORT_OS #if LWIP_NETIF_LINK_CALLBACK lwip_link_status_updated(&g_lwip_netif); /* DHCP链接状态更新函数 */ netif_set_link_callback(&g_lwip_netif, lwip_link_status_updated); /* 查询PHY连接状态任务 */ sys_thread_new("eth_link", lwip_link_thread, /* 任务入口函数 */ &g_lwip_netif, /* 任务入口函数参数 */ LWIP_LINK_STK_SIZE, /* 任务栈大小 */ LWIP_LINK_TASK_PRIO); /* 任务的优先级 */ #endif #else netif_set_default(&g_lwip_netif); /* 设置netif为默认网口 */ lwip_link_status_updated(&g_lwip_netif); /* 打开netif网口 */ netif_set_link_callback(&g_lwip_netif, lwip_link_status_updated); #endif } g_lwipdev.link_status = LWIP_LINK_OFF; /* 链接标记为0 */ #if LWIP_DHCP g_lwipdev.dhcpstatus = 0; #ifdef SYS_SUPPORT_OS /* DHCP轮询任务 */ sys_thread_new("eth_dhcp", lwip_periodic_handle, /* 任务入口函数 */ &g_lwip_netif, /* 任务入口函数参数 */ LWIP_DHCP_STK_SIZE, /* 任务栈大小 */ LWIP_DHCP_TASK_PRIO); /* 任务的优先级 */ #endif #endif #ifndef SYS_SUPPORT_OS do { eth_linkstate = ethernet_read_phy(ETH_CHIP_BSR); HAL_Delay(1000); if ((eth_linkstate & ETH_CHIP_BSR_LINK_STATUS) == 4) { PRINTF("检测到网线已经插入\r\n"); } else { PRINTF("检测到网线没有插入\r\n"); } }while((eth_linkstate & ETH_CHIP_BSR_LINK_STATUS) == 0); #endif return 0; /* 操作OK. */ } #ifndef SYS_SUPPORT_OS /** * @breif 当接收到数据后调用 * @param 无 * @retval 无 */ void lwip_pkt_handle(void) { /* 从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理 */ ethernetif_input(&g_lwip_netif); } #endif #ifdef SYS_SUPPORT_OS #if LWIP_DHCP /* 如果使用DHCP */ /** * @breif DHCP进程 * @param argument:传入的形参 * @retval 无 */ void lwip_periodic_handle(void *argument) { struct netif *netif = (struct netif *) argument; uint32_t ip = 0; uint32_t netmask = 0; uint32_t gw = 0; struct dhcp *dhcp; uint8_t iptxt[20]; while (1) { switch (g_lwip_dhcp_state) { case LWIP_DHCP_START: { /* 对IP地址、网关地址及子网页码清零操作 */ ip_addr_set_zero_ip4(&netif->ip_addr); ip_addr_set_zero_ip4(&netif->netmask); ip_addr_set_zero_ip4(&netif->gw); ip_addr_set_zero_ip4(&netif->ip_addr); ip_addr_set_zero_ip4(&netif->netmask); ip_addr_set_zero_ip4(&netif->gw); g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS; PRINTF ("State: Looking for DHCP server ...\r\n"); dhcp_start(netif); } break; case LWIP_DHCP_WAIT_ADDRESS: { if (dhcp_supplied_address(netif)) { g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED; ip = g_lwip_netif.ip_addr.addr; /* 读取新IP地址 */ netmask = g_lwip_netif.netmask.addr; /* 读取子网掩码 */ gw = g_lwip_netif.gw.addr; /* 读取默认网关 */ sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif))); PRINTF ("IP address assigned by a DHCP server: %s\r\n", iptxt); if (ip != 0) { g_lwipdev.dhcpstatus = 2; /* DHCP成功 */ PRINTF("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]); /* 解析出通过DHCP获取到的IP地址 */ g_lwipdev.ip[3] = (uint8_t)(ip >> 24); g_lwipdev.ip[2] = (uint8_t)(ip >> 16); g_lwipdev.ip[1] = (uint8_t)(ip >> 8); g_lwipdev.ip[0] = (uint8_t)(ip); PRINTF("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 解析通过DHCP获取到的子网掩码地址 */ g_lwipdev.netmask[3] = (uint8_t)(netmask >> 24); g_lwipdev.netmask[2] = (uint8_t)(netmask >> 16); g_lwipdev.netmask[1] = (uint8_t)(netmask >> 8); g_lwipdev.netmask[0] = (uint8_t)(netmask); PRINTF("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); /* 解析出通过DHCP获取到的默认网关 */ g_lwipdev.gateway[3] = (uint8_t)(gw >> 24); g_lwipdev.gateway[2] = (uint8_t)(gw >> 16); g_lwipdev.gateway[1] = (uint8_t)(gw >> 8); g_lwipdev.gateway[0] = (uint8_t)(gw); PRINTF("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); if( g_lwipdev.lwip_display_fn != NULL ) { g_lwipdev.lwip_display_fn(2); } } } else { dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); /* DHCP timeout */ if (dhcp->tries > LWIP_MAX_DHCP_TRIES) { g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT; g_lwipdev.dhcpstatus = 0XFF; /* 使用静态IP地址 */ IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); IP4_ADDR(&(g_lwip_netif.netmask), g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]); IP4_ADDR(&(g_lwip_netif.gw), g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]); netif_set_addr(netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw); sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif))); PRINTF ("DHCP Timeout !! \r\n"); PRINTF ("Static IP address: %s\r\n", iptxt); if( g_lwipdev.lwip_display_fn != NULL ) { g_lwipdev.lwip_display_fn(2); } } } } break; case LWIP_DHCP_LINK_DOWN: { g_lwip_dhcp_state = LWIP_DHCP_OFF; } break; default: break; } /* wait 1000 ms */ vTaskDelay(1000); } } #endif /** * @brief 检查ETH链路状态,更新netif * @param argument: netif * @retval 无 */ void lwip_link_thread( void * argument ) { uint32_t regval = 0; struct netif *netif = (struct netif *) argument; int link_again_num = 0; while(1) { /* 读取PHY状态寄存器,获取链接信息 */ HAL_ETH_ReadPHYRegister(&g_eth_handler, ETH_CHIP_ADDR,ETH_CHIP_BSR, ®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_DHCP g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN; dhcp_stop(netif); #endif HAL_ETH_Stop_IT(&g_eth_handler); netif_set_down(netif); netif_set_link_down(netif); } } else /* 网线插入检测 */ { link_again_num = 0; if (g_lwipdev.link_status == LWIP_LINK_OFF)/* 开启以太网及虚拟网卡 */ { g_lwipdev.link_status = LWIP_LINK_ON; HAL_ETH_Start_IT(&g_eth_handler); netif_set_up(netif); netif_set_link_up(netif); } } vTaskDelay(100); } } #else /** * @breif LWIP轮询处理 * @param 无 * @retval 无 */ void lwip_periodic_handle(void) { sys_check_timeouts(); #if LWIP_DHCP /* 如果使用DHCP */ /* Fine DHCP periodic process every 500ms */ if (HAL_GetTick() - g_dhcp_fine_timer >= DHCP_FINE_TIMER_MSECS) { g_dhcp_fine_timer = HAL_GetTick(); /* process DHCP state machine */ lwip_dhcp_process(&g_lwip_netif); } #endif } #endif
#ifndef __LWIP_COMM_H__ #define __LWIP_COMM_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Includes ------------------------------------------------------------------*/ #include "bsp.h" #include "netif/etharp.h" #include "lwip/timeouts.h" #include "lwip/snmp.h" /* Private macros ------------------------------------------------------------*/ /* Private types -------------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ /* DHCP进程状态 */ #define LWIP_DHCP_OFF (uint8_t) 0 /* DHCP服务器关闭状态 */ #define LWIP_DHCP_START (uint8_t) 1 /* DHCP服务器启动状态 */ #define LWIP_DHCP_WAIT_ADDRESS (uint8_t) 2 /* DHCP服务器等待分配IP状态 */ #define LWIP_DHCP_ADDRESS_ASSIGNED (uint8_t) 3 /* DHCP服务器地址已分配状态 */ #define LWIP_DHCP_TIMEOUT (uint8_t) 4 /* DHCP服务器超时状态 */ #define LWIP_DHCP_LINK_DOWN (uint8_t) 5 /* DHCP服务器链接失败状态 */ /* 链接状态 */ #define LWIP_LINK_OFF (uint8_t) 0 /* 链接关闭状态 */ #define LWIP_LINK_ON (uint8_t) 1 /* 链接开启状态 */ #define LWIP_LINK_AGAIN (uint8_t) 2 /* 重复开启 */ /* DHCP服务器最大重试次数 */ #define LWIP_MAX_DHCP_TRIES (uint8_t) 4 /* Exported types ------------------------------------------------------------*/ typedef void (*display_fn)(uint8_t index); /*lwip控制结构体*/ typedef struct { uint8_t mac[6]; /* MAC地址 */ uint8_t remoteip[4]; /* 远端主机IP地址 */ uint8_t ip[4]; /* 本机IP地址 */ uint8_t netmask[4]; /* 子网掩码 */ uint8_t gateway[4]; /* 默认网关的IP地址 */ uint8_t dhcpstatus; /* dhcp状态 0, 未获取DHCP地址 1, 进入DHCP获取状态 2, 成功获取DHCP地址 0XFF,获取失败 */ uint8_t link_status; /* 连接状态 */ display_fn lwip_display_fn; /* 显示函数指针 */ }__lwip_dev; /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ extern __lwip_dev g_lwipdev; /* lwip控制结构体 */ /* Exported functions --------------------------------------------------------*/ uint8_t lwip_comm_init(void); //void lwip_pkt_handle(void); //void lwip_periodic_handle(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif // __LWIP_COMM_H__
4.3 sys_arch.c/h
/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt <[email protected]> * */ /* lwIP includes. */ #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "lwip/stats.h" #include "FreeRTOS.h" #include "semphr.h" #include "task.h" int errno; /** Set this to 1 if you want the stack size passed to sys_thread_new() to be * interpreted as number of stack words (FreeRTOS-like). * Default is that they are interpreted as byte count (lwIP-like). */ #ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS #define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 1 #endif /** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions. * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT(). */ #ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX #define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0 #endif /** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and * SYS_ARCH_UNPROTECT() are called matching. */ #ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK #define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0 #endif /** Set this to 1 to let sys_mbox_free check that queues are empty when freed */ #ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE #define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0 #endif /** Set this to 1 to enable core locking check functions in this port. * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED() * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */ #ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING #define LWIP_FREERTOS_CHECK_CORE_LOCKING 0 #endif /** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer. * Default is 1, where FreeRTOS ticks are used to calculate back to ms. */ #ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS #define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1 #endif #if !configSUPPORT_DYNAMIC_ALLOCATION # error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION" #endif #if !INCLUDE_vTaskDelay # error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay" #endif #if !INCLUDE_vTaskSuspend # error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend" #endif #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX #if !configUSE_MUTEXES # error "lwIP FreeRTOS port requires configUSE_MUTEXES" #endif #endif #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX static SemaphoreHandle_t sys_arch_protect_mutex; #endif #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK static sys_prot_t sys_arch_protect_nesting; #endif /* Initialize this module (see description in sys.h) */ void sys_init(void) { #if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX /* initialize sys_arch_protect global mutex */ sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex(); LWIP_ASSERT("failed to create sys_arch_protect mutex", sys_arch_protect_mutex != NULL); #endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ } #if configUSE_16_BIT_TICKS == 1 #error This port requires 32 bit ticks or timer overflow will fail #endif #if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS u32_t sys_now(void) { return xTaskGetTickCount() * portTICK_PERIOD_MS; } #endif u32_t sys_jiffies(void) { return xTaskGetTickCount(); } #if SYS_LIGHTWEIGHT_PROT sys_prot_t sys_arch_protect(void) { #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret; LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL); ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY); LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE); #else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskENTER_CRITICAL(); #endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ #if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK { /* every nested call to sys_arch_protect() returns an increased number */ sys_prot_t ret = sys_arch_protect_nesting; sys_arch_protect_nesting++; LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret); return ret; } #else return 1; #endif } void sys_arch_unprotect(sys_prot_t pval) { #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret; #endif #if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0); sys_arch_protect_nesting--; LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval); #endif #if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL); ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex); LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE); #else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskEXIT_CRITICAL(); #endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ LWIP_UNUSED_ARG(pval); } #endif /* SYS_LIGHTWEIGHT_PROT */ void sys_arch_msleep(u32_t delay_ms) { TickType_t delay_ticks = delay_ms / portTICK_RATE_MS; vTaskDelay(delay_ticks); } #if !LWIP_COMPAT_MUTEX /* Create a new mutex*/ err_t sys_mutex_new(sys_mutex_t *mutex) { LWIP_ASSERT("mutex != NULL", mutex != NULL); mutex->mut = xSemaphoreCreateRecursiveMutex(); if(mutex->mut == NULL) { SYS_STATS_INC(mutex.err); return ERR_MEM; } SYS_STATS_INC_USED(mutex); return ERR_OK; } void sys_mutex_lock(sys_mutex_t *mutex) { BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY); LWIP_ASSERT("failed to take the mutex", ret == pdTRUE); } void sys_mutex_unlock(sys_mutex_t *mutex) { BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); ret = xSemaphoreGiveRecursive(mutex->mut); LWIP_ASSERT("failed to give the mutex", ret == pdTRUE); } void sys_mutex_free(sys_mutex_t *mutex) { LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); SYS_STATS_DEC(mutex.used); vSemaphoreDelete(mutex->mut); mutex->mut = NULL; } #endif /* !LWIP_COMPAT_MUTEX */ err_t sys_sem_new(sys_sem_t *sem, u8_t initial_count) { LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("initial_count invalid (not 0 or 1)", (initial_count == 0) || (initial_count == 1)); sem->sem = xSemaphoreCreateBinary(); if(sem->sem == NULL) { SYS_STATS_INC(sem.err); return ERR_MEM; } SYS_STATS_INC_USED(sem); if(initial_count == 1) { BaseType_t ret = xSemaphoreGive(sem->sem); LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); } return ERR_OK; } void sys_sem_signal(sys_sem_t *sem) { BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); ret = xSemaphoreGive(sem->sem); /* queue full is OK, this is a signal only... */ LWIP_ASSERT("sys_sem_signal: sane return value", (ret == pdTRUE) || (ret == errQUEUE_FULL)); } u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms) { BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); if(!timeout_ms) { /* wait infinite */ ret = xSemaphoreTake(sem->sem, portMAX_DELAY); LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xSemaphoreTake(sem->sem, timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); } /* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1; } void sys_sem_free(sys_sem_t *sem) { LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); SYS_STATS_DEC(sem.used); vSemaphoreDelete(sem->sem); sem->sem = NULL; } err_t sys_mbox_new(sys_mbox_t *mbox, int size) { LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("size > 0", size > 0); mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *)); if(mbox->mbx == NULL) { SYS_STATS_INC(mbox.err); return ERR_MEM; } SYS_STATS_INC_USED(mbox); return ERR_OK; } void sys_mbox_post(sys_mbox_t *mbox, void *msg) { BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY); LWIP_ASSERT("mbox post failed", ret == pdTRUE); } err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); ret = xQueueSendToBack(mbox->mbx, &msg, 0); if (ret == pdTRUE) { return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; } } err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg) { BaseType_t ret; BaseType_t xHigherPriorityTaskWoken = pdFALSE; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken); if (ret == pdTRUE) { if (xHigherPriorityTaskWoken == pdTRUE) { return ERR_NEED_SCHED; } return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; } } u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms) { BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); if (!msg) { msg = &msg_dummy; } if (!timeout_ms) { /* wait infinite */ ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ *msg = NULL; return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } /* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1; } u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) { BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); if (!msg) { msg = &msg_dummy; } ret = xQueueReceive(mbox->mbx, &(*msg), 0); if (ret == errQUEUE_EMPTY) { *msg = NULL; return SYS_MBOX_EMPTY; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); /* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1; } void sys_mbox_free(sys_mbox_t *mbox) { LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); #if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE { UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx); LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0); if (msgs_waiting != 0) { SYS_STATS_INC(mbox.err); } } #endif vQueueDelete(mbox->mbx); SYS_STATS_DEC(mbox.used); } sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) { TaskHandle_t rtos_task; BaseType_t ret; sys_thread_t lwip_thread; size_t rtos_stacksize; LWIP_ASSERT("invalid stacksize", stacksize > 0); #if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS rtos_stacksize = (size_t)stacksize; #else rtos_stacksize = (size_t)stacksize / sizeof(StackType_t); #endif /* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the thread function without adaption here. */ ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task); LWIP_ASSERT("task creation failed", ret == pdTRUE); lwip_thread.thread_handle = rtos_task; return lwip_thread; } #if LWIP_NETCONN_SEM_PER_THREAD #if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 sys_sem_t * sys_arch_netconn_sem_get(void) { void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL); ret = pvTaskGetThreadLocalStoragePointer(task, 0); return ret; } void sys_arch_netconn_sem_alloc(void) { void *ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL); ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret == NULL) { sys_sem_t *sem; err_t err; /* need to allocate the memory for this semaphore */ sem = mem_malloc(sizeof(sys_sem_t)); LWIP_ASSERT("sem != NULL", sem != NULL); err = sys_sem_new(sem, 0); LWIP_ASSERT("err == ERR_OK", err == ERR_OK); LWIP_ASSERT("sem invalid", sys_sem_valid(sem)); vTaskSetThreadLocalStoragePointer(task, 0, sem); } } void sys_arch_netconn_sem_free(void) { void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL); ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret != NULL) { sys_sem_t *sem = ret; sys_sem_free(sem); mem_free(sem); vTaskSetThreadLocalStoragePointer(task, 0, NULL); } } #else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */ #error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */ #endif /* LWIP_NETCONN_SEM_PER_THREAD */ #if LWIP_FREERTOS_CHECK_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING /** Flag the core lock held. A counter for recursive locks. */ static u8_t lwip_core_lock_count; static TaskHandle_t lwip_core_lock_holder_thread; void sys_lock_tcpip_core(void) { sys_mutex_lock(&lock_tcpip_core); if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle(); } lwip_core_lock_count++; } void sys_unlock_tcpip_core(void) { lwip_core_lock_count--; if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = 0; } sys_mutex_unlock(&lock_tcpip_core); } #endif /* LWIP_TCPIP_CORE_LOCKING */ #if !NO_SYS static TaskHandle_t lwip_tcpip_thread; #endif void sys_mark_tcpip_thread(void) { #if !NO_SYS lwip_tcpip_thread = xTaskGetCurrentTaskHandle(); #endif } void sys_check_core_locking(void) { /* Embedded systems should check we are NOT in an interrupt context here */ /* E.g. core Cortex-M3/M4 ports: configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */ taskENTER_CRITICAL(); taskEXIT_CRITICAL(); #if !NO_SYS if (lwip_tcpip_thread != 0) { TaskHandle_t current_thread = xTaskGetCurrentTaskHandle(); #if LWIP_TCPIP_CORE_LOCKING LWIP_ASSERT("Function called without core lock", current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0); #else /* LWIP_TCPIP_CORE_LOCKING */ LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread); #endif /* LWIP_TCPIP_CORE_LOCKING */ } #endif /* !NO_SYS */ } #endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/
/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmdit <[email protected]> * */ #ifndef LWIP_ARCH_SYS_ARCH_H #define LWIP_ARCH_SYS_ARCH_H #include "lwip/opt.h" #include "lwip/arch.h" /** This is returned by _fromisr() sys functions to tell the outermost function * that a higher priority task was woken and the scheduler needs to be invoked. */ #define ERR_NEED_SCHED 123 /* This port includes FreeRTOS headers in sys_arch.c only. * FreeRTOS uses pointers as object types. We use wrapper structs instead of * void pointers directly to get a tiny bit of type safety. */ void sys_arch_msleep(u32_t delay_ms); #define sys_msleep(ms) sys_arch_msleep(ms) #if SYS_LIGHTWEIGHT_PROT typedef u32_t sys_prot_t; #endif /* SYS_LIGHTWEIGHT_PROT */ #if !LWIP_COMPAT_MUTEX struct _sys_mut { void *mut; }; typedef struct _sys_mut sys_mutex_t; #define sys_mutex_valid_val(mutex) ((mutex).mut != NULL) #define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex))) #define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL) #endif /* !LWIP_COMPAT_MUTEX */ struct _sys_sem { void *sem; }; typedef struct _sys_sem sys_sem_t; #define sys_sem_valid_val(sema) ((sema).sem != NULL) #define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema))) #define sys_sem_set_invalid(sema) ((sema)->sem = NULL) struct _sys_mbox { void *mbx; }; typedef struct _sys_mbox sys_mbox_t; #define sys_mbox_valid_val(mbox) ((mbox).mbx != NULL) #define sys_mbox_valid(mbox) (((mbox) != NULL) && sys_mbox_valid_val(*(mbox))) #define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL) struct _sys_thread { void *thread_handle; }; typedef struct _sys_thread sys_thread_t; #if LWIP_NETCONN_SEM_PER_THREAD sys_sem_t* sys_arch_netconn_sem_get(void); void sys_arch_netconn_sem_alloc(void); void sys_arch_netconn_sem_free(void); #define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get() #define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc() #define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free() #endif /* LWIP_NETCONN_SEM_PER_THREAD */ #endif /* LWIP_ARCH_SYS_ARCH_H */
4.4 cc.h
/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels <[email protected]> * */ #ifndef __CC_H__ #define __CC_H__ //#include "cpu.h" #include <stdlib.h> #include <stdio.h> typedef int sys_prot_t; //#define LWIP_PROVIDE_ERRNO #if defined (__GNUC__) & !defined (__CC_ARM) #define LWIP_TIMEVAL_PRIVATE 0 #include <sys/time.h> #endif /* define compiler specific symbols */ #if defined (__ICCARM__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #define PACK_STRUCT_USE_INCLUDES #elif defined (__GNUC__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__CC_ARM) #define PACK_STRUCT_BEGIN __packed #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__TASKING__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #endif #include "bsp.h" #define LWIP_PLATFORM_ASSERT(x) do {PRINTF("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__); } while(0) /* Define random number generator function */ #define LWIP_RAND() ((u32_t)rand()) #endif /* __CC_H__ */
4.5 lwipopts.h
/** ****************************************************************************** * @file LwIP/LwIP_TCP_Echo_Client/Inc/lwipopts.h * @author MCD Application Team * @brief lwIP Options Configuration. ****************************************************************************** * @attention * * Copyright (c) 2017 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ /* NO_SYS 表示无操作系统模拟层,无操作系统为1,有操作系统设置为0 注意这个参数设置会编译不同 */ //1:表示无操作系统 #define NO_SYS 0 /** * SYS_LIGHTWEIGHT_PROT==0: disable inter-task protection (and task-vs-interrupt * protection) for certain critical regions during buffer allocation, deallocation * and memory allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 0 /* ---------- 内存选项 ---------- */ /* 内存对齐,按照 4 字节对齐 */ #define MEM_ALIGNMENT 4 /* 堆内存的大小,如果需要更大的堆内存,那么设置高一点 */ #define MEM_SIZE (20*1024) /* MEMP_NUM_PBUF: 设置内存池的数量 */ #define MEMP_NUM_PBUF 15 /* MEMP_NUM_UDP_PCB: UDP协议控制块的数量. */ #define MEMP_NUM_UDP_PCB 4 /* MEMP_NUM_TCP_PCB: TCP的数量. */ #define MEMP_NUM_TCP_PCB 4 /* MEMP_NUM_TCP_PCB_LISTEN: 监听TCP的数量. */ #define MEMP_NUM_TCP_PCB_LISTEN 2 /* MEMP_NUM_TCP_SEG: 同时排队的TCP的数量段. */ #define MEMP_NUM_TCP_SEG 120 /* MEMP_NUM_SYS_TIMEOUT: 超时模拟活动的数量. */ #define MEMP_NUM_SYS_TIMEOUT 6 /* ---------- Pbuf选项 ---------- */ /* PBUF_POOL 内存池中每个内存块大小 */ #define PBUF_POOL_SIZE 20 /* PBUF_POOL_BUFSIZE: pbuf池中每个pbuf的大小. */ #define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) /* ---------- TCP选项 ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* 控制TCP是否应该对到达的段进行排队 秩序。如果你的设备内存不足,定义为0. */ #define TCP_QUEUE_OOSEQ 0 /* TCP最大段大小 */ #define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */ /* TCP发送者缓冲区空间(字节). */ #define TCP_SND_BUF (11*TCP_MSS) /* TCP_SND_QUEUELEN: TCP发送缓冲区空间。这必须是至少 需要(2 * TCP_SND_BUF/TCP_MSS)才能正常工作 */ #define TCP_SND_QUEUELEN (8* TCP_SND_BUF/TCP_MSS) /* TCP接收窗口 */ #define TCP_WND (2*TCP_MSS) /* ---------- ICMP 选项 ---------- */ #define LWIP_ICMP 1 /* ---------- DHCP 选项 ---------- */ /* 如果您希望DHCP配置为,请将LWIP_DHCP定义为1 */ #define LWIP_DHCP 1 /* ---------- UDP 选项 ---------- */ #define LWIP_UDP 1 #define UDP_TTL 255 /* ---------- Statistics 选项 ---------- */ #define LWIP_STATS 0 #define LWIP_PROVIDE_ERRNO 1 /* ---------- 链接回调选项 ---------- */ /* WIP_NETIF_LINK_CALLBACK==1:支持来自接口的回调函数 每当链接改变(例如,向下链接) */ #define LWIP_NETIF_LINK_CALLBACK 1 /* -------------------------------------- ------------ 帧校验和选项 ------------ -------------------------------------- */ /* The STM32F4xx allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware: - To use this feature let the following define uncommented. - To disable it and process by CPU comment the the checksum. */ #define CHECKSUM_BY_HARDWARE #ifdef CHECKSUM_BY_HARDWARE /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 0 /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 0 /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 0 /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 0 /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 0 /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 0 /* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/ #define CHECKSUM_GEN_ICMP 0 #else /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 1 /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 1 /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 1 /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 1 /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 1 /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 1 /* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/ #define CHECKSUM_GEN_ICMP 1 #endif /* ---------------------------------------------- ---------------- 连续层的选择 ---------------- ---------- Sequential layer options ---------- ---------------------------------------------- */ /** * LWIP_NETCONN==1:启用Netconn API(需要使用api_lib.c) */ #define LWIP_NETCONN 1 /* ------------------------------------ ------------ Socket选项 ------------ ---------- Socket options ---------- ------------------------------------ */ /** * LWIP_SOCKET==1:启用Socket API(要求使用Socket .c) */ #define LWIP_SOCKET 1 /* ------------------------------------ ---------- httpd options ---------- ------------------------------------ */ /** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the * file system (to prevent changing the file included in CVS) */ #define HTTPD_USE_CUSTOM_FSDATA 1 /* --------------------------------- ---------- 操作系统选项 ---------- --------------------------------- */ #define TCPIP_THREAD_NAME "TCP/IP" #define TCPIP_THREAD_STACKSIZE 1000 #define TCPIP_MBOX_SIZE 6 #define DEFAULT_UDP_RECVMBOX_SIZE 6 #define DEFAULT_TCP_RECVMBOX_SIZE 6 #define DEFAULT_ACCEPTMBOX_SIZE 6 #define DEFAULT_THREAD_STACKSIZE 500 #define TCPIP_THREAD_PRIO 5 #define LWIP_SO_RCVTIMEO 1 #endif /* __LWIPOPTS_H__ */
5. 修改ETH中断的优先级,使能被系统管理
6. 添加ethernet task
/* Includes ------------------------------------------------------------------*/ #include "Task_ethernet.h" #include "bsp.h" #include "mydata.h" #include "lwip_comm.h" /* Private macros ------------------------------------------------------------*/ /*******任务优先级******/ #define LWIP_TASK_PRIO 1 /*******任务堆栈大小******/ #define LWIP_STK_SIZE 1024 /* Private types -------------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* 定义线程控制块指针 */ static TaskHandle_t LWIP_Task_Handle = NULL; /* Private functions ---------------------------------------------------------*/ int ethernet_task_init(void) { while ( lwip_comm_init() != 0 ) { LED1_Toggle(); My_mDelay( 500 ); } #if LWIP_DHCP while (g_lwipdev.dhcpstatus != 2 && g_lwipdev.dhcpstatus != 0xff)/* 等待静态和动态分配完成 */ { My_mDelay(500); } #endif return 0; } /* Exported macros -----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ void ethernet_task(void *pvParameters) { static uint16_t _time = 0; ethernet_task_init(); while(1) { if( ++_time == 500 ) { _time = 0; LED1_Toggle(); } My_mDelay( 0 ); } } int Task_Eth_create(void) { /********************任务初始化**************************/ /* 创建任务 */ if( pdPASS == xTaskCreate( (TaskFunction_t )ethernet_task, /* 任务入口函数 */ (const char* )"eth", /* 任务名字 */ (uint16_t )LWIP_STK_SIZE, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )LWIP_TASK_PRIO, /* 任务的优先级 */ (TaskHandle_t* )&LWIP_Task_Handle) ) /* 任务控制块指针 */ PRINTF("[D] [RTOS] ethernet_task create succeed!\r\n"); else PRINTF("[D] [RTOS] ethernet_task create failure!\r\n"); return 0; }
标签:LWIP,操作系统,FreeRTOS,CHIP,sys,netif,lwIP,ETH,define From: https://www.cnblogs.com/LiuYong2021/p/18355014