diff --git a/.gitmodules b/.gitmodules index 1e18ab0..b81e15f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,5 +5,5 @@ path = lib/FreeRTOS url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git [submodule "lib/LwIP"] - path = lib/LwIP + path = lib/LwIP/lwip url = https://git.savannah.nongnu.org/git/lwip.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d2ed687..30aa514 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,11 @@ set(TARGET_SOURCES "board/clock_config.c" "board/peripherals.c" "board/pin_mux.c" + "lib/LwIP/port/lwip_helpers.c" + "lib/LwIP/port/sys_arch.c" + "src/ethernetif.c" "src/freertos_helpers.c" + "src/fsl_phy.c" "src/main.c" "src/system_utilities.c" ) @@ -81,6 +85,7 @@ set(TARGET_C_INCLUDES # Shared libraries linked with application set(TARGET_LIBS "freertos_kernel" + "lwip" ) # Shared library and linker script search paths @@ -114,6 +119,9 @@ set(FREERTOS_CONFIG_FILE_DIRECTORY "${CMAKE_SOURCE_DIR}/include" CACHE STRING "" set(FREERTOS_PORT "GCC_ARM_CM3" CACHE STRING "") add_subdirectory(lib/FreeRTOS) +set(LWIP_CONFIG_FILE_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/LwIP/port/include" CACHE STRING "") +add_subdirectory(lib/LwIP) + # Shared sources, includes and definitions add_compile_definitions(${TARGET_C_DEFINES}) include_directories(${TARGET_C_INCLUDES}) diff --git a/MK60DN512xxx10.mex b/MK60DN512xxx10.mex index a3fc0db..279784f 100644 --- a/MK60DN512xxx10.mex +++ b/MK60DN512xxx10.mex @@ -117,14 +117,14 @@ + - - - - + + + @@ -191,25 +191,32 @@ - + - - + + + - - + - + + + + + + + + true diff --git a/SDK b/SDK index 855e1be..d22b5f5 160000 --- a/SDK +++ b/SDK @@ -1 +1 @@ -Subproject commit 855e1be1225ff859dd5a9a5a3959ecc702a028df +Subproject commit d22b5f5974384786fbc1488f395c3af984a4c466 diff --git a/board/clock_config.c b/board/clock_config.c index 36606c2..2b8a6be 100644 --- a/board/clock_config.c +++ b/board/clock_config.c @@ -49,9 +49,9 @@ processor_version: 11.0.1 ******************************************************************************/ #define MCG_IRCLK_DISABLE 0U /*!< MCGIRCLK disabled */ #define MCG_PLL_DISABLE 0U /*!< MCGPLLCLK disabled */ -#define OSC_ER_CLK_DISABLE 0U /*!< Disable external reference clock */ #define RTC_OSC_CAP_LOAD_12PF 0x1800U /*!< RTC oscillator capacity load: 12pF */ #define RTC_RTC32KCLK_PERIPHERALS_ENABLED 1U /*!< RTC32KCLK to other peripherals: enabled */ +#define SIM_ENET_RMII_CLK_SEL_EXTAL_CLK 0U /*!< SDHC clock select: Core/system clock */ #define SIM_OSC32KSEL_OSC32KCLK_CLK 0U /*!< OSC32KSEL select: OSC32KCLK clock */ #define SIM_PLLFLLSEL_MCGFLLCLK_CLK 0U /*!< PLLFLL select: MCGFLLCLK clock */ @@ -64,21 +64,6 @@ extern uint32_t SystemCoreClock; /******************************************************************************* * Code ******************************************************************************/ -/*FUNCTION********************************************************************** - * - * Function Name : CLOCK_CONFIG_FllStableDelay - * Description : This function is used to delay for FLL stable. - * - *END**************************************************************************/ -static void CLOCK_CONFIG_FllStableDelay(void) -{ - uint32_t i = 30000U; - while (i--) - { - __NOP(); - } -} - /*FUNCTION********************************************************************** * * Function Name : CLOCK_CONFIG_SetRtcClock @@ -115,6 +100,18 @@ static void CLOCK_CONFIG_SetRtcClock(uint32_t capLoad, uint8_t enableOutPeriph) CLOCK_DisableClock(kCLOCK_Rtc0); } +/*FUNCTION********************************************************************** + * + * Function Name : CLOCK_CONFIG_SetFllExtRefDiv + * Description : Configure FLL external reference divider (FRDIV). + * Param frdiv : The value to set FRDIV. + * + *END**************************************************************************/ +static void CLOCK_CONFIG_SetFllExtRefDiv(uint8_t frdiv) +{ + MCG->C1 = ((MCG->C1 & ~MCG_C1_FRDIV_MASK) | MCG_C1_FRDIV(frdiv)); +} + /******************************************************************************* ************************ BOARD_InitBootClocks function ************************ ******************************************************************************/ @@ -133,24 +130,31 @@ name: BOARD_BootClockRUN called_from_default_init: true outputs: - {id: Bus_clock.outFreq, value: 50 MHz} -- {id: Core_clock.outFreq, value: 50 MHz} +- {id: Core_clock.outFreq, value: 100 MHz} - {id: Flash_clock.outFreq, value: 25 MHz} - {id: FlexBus_clock.outFreq, value: 50 MHz} - {id: LPO_clock.outFreq, value: 1 kHz} - {id: MCGFFCLK.outFreq, value: 39.0625 kHz} -- {id: PLLFLLCLK.outFreq, value: 25 MHz} -- {id: System_clock.outFreq, value: 50 MHz} +- {id: OSCERCLK.outFreq, value: 50 MHz} +- {id: RMIICLK.outFreq, value: 50 MHz} +- {id: System_clock.outFreq, value: 100 MHz} settings: -- {id: MCGMode, value: FBE} -- {id: MCG.CLKS.sel, value: MCG.OSCSEL} +- {id: MCGMode, value: PEE} - {id: MCG.FRDIV.scale, value: '1280'} - {id: MCG.IREFS.sel, value: MCG.FRDIV} -- {id: MCG.PRDIV.scale, value: '13'} +- {id: MCG.PLLS.sel, value: MCG.PLL} +- {id: MCG.PRDIV.scale, value: '13', locked: true} +- {id: MCG.VDIV.scale, value: '26', locked: true} - {id: MCG_C2_RANGE0_CFG, value: Very_high} - {id: MCG_C2_RANGE0_FRDIV_CFG, value: Very_high} +- {id: OSC_CR_ERCLKEN_CFG, value: Enabled} - {id: OSC_CR_SYS_OSC_CAP_LOAD_CFG, value: SC18PF} +- {id: RMIISrcConfig, value: 'yes'} - {id: RTC_CR_OSCE_CFG, value: Enabled} - {id: RTC_CR_OSC_CAP_LOAD_CFG, value: SC12PF} +- {id: SIM.OUTDIV2.scale, value: '2'} +- {id: SIM.OUTDIV3.scale, value: '2'} +- {id: SIM.OUTDIV4.scale, value: '4'} sources: - {id: OSC.OSC.outFreq, value: 50 MHz, enabled: true} - {id: RTC.RTC32kHz.outFreq, value: 32.768 kHz, enabled: true} @@ -162,7 +166,7 @@ sources: ******************************************************************************/ const mcg_config_t mcgConfig_BOARD_BootClockRUN = { - .mcgMode = kMCG_ModeFBE, /* FBE - FLL Bypassed External */ + .mcgMode = kMCG_ModePEE, /* PEE - PLL Engaged External */ .irclkEnableMode = MCG_IRCLK_DISABLE, /* MCGIRCLK disabled */ .ircs = kMCG_IrcSlow, /* Slow internal reference clock selected */ .fcrdiv = 0x1U, /* Fast IRC divider: divided by 2 */ @@ -174,14 +178,14 @@ const mcg_config_t mcgConfig_BOARD_BootClockRUN = { .enableMode = MCG_PLL_DISABLE, /* MCGPLLCLK disabled */ .prdiv = 0xcU, /* PLL Reference divider: divided by 13 */ - .vdiv = 0x0U, /* VCO divider: multiplied by 24 */ + .vdiv = 0x2U, /* VCO divider: multiplied by 26 */ }, }; const sim_clock_config_t simConfig_BOARD_BootClockRUN = { .pllFllSel = SIM_PLLFLLSEL_MCGFLLCLK_CLK, /* PLLFLL select: MCGFLLCLK clock */ .er32kSrc = SIM_OSC32KSEL_OSC32KCLK_CLK, /* OSC32KSEL select: OSC32KCLK clock */ - .clkdiv1 = 0x10000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /1, OUTDIV3: /1, OUTDIV4: /2 */ + .clkdiv1 = 0x1130000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /2, OUTDIV3: /2, OUTDIV4: /4 */ }; const osc_config_t oscConfig_BOARD_BootClockRUN = { @@ -190,7 +194,7 @@ const osc_config_t oscConfig_BOARD_BootClockRUN = .workMode = kOSC_ModeExt, /* Use external clock */ .oscerConfig = { - .enableMode = OSC_ER_CLK_DISABLE, /* Disable external reference clock */ + .enableMode = kOSC_ErClkEnable, /* Enable external reference clock, disable external reference clock in STOP mode */ } }; @@ -206,15 +210,17 @@ void BOARD_BootClockRUN(void) /* Initializes OSC0 according to board configuration. */ CLOCK_InitOsc0(&oscConfig_BOARD_BootClockRUN); CLOCK_SetXtal0Freq(oscConfig_BOARD_BootClockRUN.freq); - /* Set MCG to FBE mode. */ - CLOCK_SetExternalRefClkConfig(mcgConfig_BOARD_BootClockRUN.oscsel); - CLOCK_SetFbeMode(mcgConfig_BOARD_BootClockRUN.frdiv, - mcgConfig_BOARD_BootClockRUN.dmx32, - mcgConfig_BOARD_BootClockRUN.drs, - CLOCK_CONFIG_FllStableDelay); + /* Configure FLL external reference divider (FRDIV). */ + CLOCK_CONFIG_SetFllExtRefDiv(mcgConfig_BOARD_BootClockRUN.frdiv); + /* Set MCG to PEE mode. */ + CLOCK_BootToPeeMode(mcgConfig_BOARD_BootClockRUN.oscsel, + kMCG_PllClkSelPll0, + &mcgConfig_BOARD_BootClockRUN.pll0Config); /* Set the clock configuration in SIM module. */ CLOCK_SetSimConfig(&simConfig_BOARD_BootClockRUN); /* Set SystemCoreClock variable. */ SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK; + /* Set RMII clock source. */ + CLOCK_SetRmii0Clock(SIM_ENET_RMII_CLK_SEL_EXTAL_CLK); } diff --git a/board/clock_config.h b/board/clock_config.h index 46ef2f1..245fb30 100644 --- a/board/clock_config.h +++ b/board/clock_config.h @@ -38,7 +38,7 @@ void BOARD_InitBootClocks(void); /******************************************************************************* * Definitions for BOARD_BootClockRUN configuration ******************************************************************************/ -#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 50000000U /*!< Core clock frequency: 50000000Hz */ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 100000000U /*!< Core clock frequency: 100000000Hz */ /*! @brief MCG set for BOARD_BootClockRUN configuration. */ diff --git a/board/pin_mux.c b/board/pin_mux.c index a114204..811e34e 100644 --- a/board/pin_mux.c +++ b/board/pin_mux.c @@ -84,14 +84,14 @@ BOARD_InitPins: - {pin_num: '77', peripheral: FB, signal: 'A, 27', pin_signal: PTA26/MII0_TXD3/FB_A27} - {pin_num: '123', peripheral: FB, signal: CS5_TSIZ1_BE23_16_BLS15_8, pin_signal: PTC16/CAN1_RX/UART3_RX/ENET0_1588_TMR0/FB_CS5_b/FB_TSIZ1/FB_BE23_16_b} - {pin_num: '124', peripheral: FB, signal: CS4_TSIZ0_BE31_24_BLS7_0, pin_signal: PTC17/CAN1_TX/UART3_TX/ENET0_1588_TMR1/FB_CS4_b/FB_TSIZ0/FB_BE31_24_b} + - {pin_num: '66', peripheral: ENET, signal: RMII_CRS_DV, pin_signal: PTA14/SPI0_PCS0/UART0_TX/RMII0_CRS_DV/MII0_RXDV/I2S0_RX_BCLK/I2S0_TXD1} - {pin_num: '82', peripheral: ENET, signal: RMII_MDC, pin_signal: ADC0_SE9/ADC1_SE9/TSI0_CH6/PTB1/I2C0_SDA/FTM1_CH1/RMII0_MDC/MII0_MDC/FTM1_QD_PHB} - {pin_num: '81', peripheral: ENET, signal: RMII_MDIO, pin_signal: ADC0_SE8/ADC1_SE8/TSI0_CH0/PTB0/LLWU_P5/I2C0_SCL/FTM1_CH0/RMII0_MDIO/MII0_MDIO/FTM1_QD_PHA} - - {pin_num: '68', peripheral: ENET, signal: RMII_TXD0, pin_signal: PTA16/SPI0_SOUT/UART0_CTS_b/UART0_COL_b/RMII0_TXD0/MII0_TXD0/I2S0_RX_FS/I2S0_RXD1} - - {pin_num: '69', peripheral: ENET, signal: RMII_TXD1, pin_signal: ADC1_SE17/PTA17/SPI0_SIN/UART0_RTS_b/RMII0_TXD1/MII0_TXD1/I2S0_MCLK} - - {pin_num: '55', peripheral: ENET, signal: RMII_RXER, pin_signal: PTA5/USB_CLKIN/FTM0_CH2/RMII0_RXER/MII0_RXER/CMP2_OUT/I2S0_TX_BCLK/JTAG_TRST_b} - {pin_num: '65', peripheral: ENET, signal: RMII_RXD0, pin_signal: CMP2_IN1/PTA13/LLWU_P4/CAN0_RX/FTM1_CH1/RMII0_RXD0/MII0_RXD0/I2S0_TX_FS/FTM1_QD_PHB} - {pin_num: '64', peripheral: ENET, signal: RMII_RXD1, pin_signal: CMP2_IN0/PTA12/CAN0_TX/FTM1_CH0/RMII0_RXD1/MII0_RXD1/I2S0_TXD0/FTM1_QD_PHA} - - {pin_num: '66', peripheral: ENET, signal: RMII_CRS_DV, pin_signal: PTA14/SPI0_PCS0/UART0_TX/RMII0_CRS_DV/MII0_RXDV/I2S0_RX_BCLK/I2S0_TXD1} + - {pin_num: '55', peripheral: ENET, signal: RMII_RXER, pin_signal: PTA5/USB_CLKIN/FTM0_CH2/RMII0_RXER/MII0_RXER/CMP2_OUT/I2S0_TX_BCLK/JTAG_TRST_b} + - {pin_num: '68', peripheral: ENET, signal: RMII_TXD0, pin_signal: PTA16/SPI0_SOUT/UART0_CTS_b/UART0_COL_b/RMII0_TXD0/MII0_TXD0/I2S0_RX_FS/I2S0_RXD1} + - {pin_num: '69', peripheral: ENET, signal: RMII_TXD1, pin_signal: ADC1_SE17/PTA17/SPI0_SIN/UART0_RTS_b/RMII0_TXD1/MII0_TXD1/I2S0_MCLK} - {pin_num: '67', peripheral: ENET, signal: rmii_txen, pin_signal: PTA15/SPI0_SCK/UART0_RX/RMII0_TXEN/MII0_TXEN/I2S0_RXD0} - {pin_num: '72', peripheral: ENET, signal: RMII_CLKIN, pin_signal: EXTAL0/PTA18/FTM0_FLT2/FTM_CLKIN0} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** diff --git a/include/FreeRTOSConfig.h b/include/FreeRTOSConfig.h index 0cd4d0c..102101b 100644 --- a/include/FreeRTOSConfig.h +++ b/include/FreeRTOSConfig.h @@ -19,8 +19,8 @@ #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 #define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 -#define configUSE_MUTEXES 0 -#define configUSE_RECURSIVE_MUTEXES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ #define configQUEUE_REGISTRY_SIZE 10 @@ -122,7 +122,7 @@ standard names. */ #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xEventGroupSetBitFromISR 1 -#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 diff --git a/include/ethernetif.h b/include/ethernetif.h new file mode 100644 index 0000000..a90369b --- /dev/null +++ b/include/ethernetif.h @@ -0,0 +1,146 @@ +/* + * 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 + * + */ + +/* + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 SDRVL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef ETHERNETIF_H +#define ETHERNETIF_H + +#include "lwip/err.h" +#include "fsl_enet.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef ENET_RXBD_NUM + #define ENET_RXBD_NUM (5) +#endif +#ifndef ENET_TXBD_NUM +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + #define ENET_TXBD_NUM (5) +#else + #define ENET_TXBD_NUM (3) +#endif +#endif +#ifndef ENET_RXBUFF_SIZE + #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) +#endif +#ifndef ENET_TXBUFF_SIZE + #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) +#endif + +/* MAC address configuration. */ +#ifndef configMAC_ADDR0 +#define configMAC_ADDR0 0x00 +#endif +#ifndef configMAC_ADDR1 +#define configMAC_ADDR1 0x12 +#endif +#ifndef configMAC_ADDR2 +#define configMAC_ADDR2 0x13 +#endif +#ifndef configMAC_ADDR3 +#define configMAC_ADDR3 0x10 +#endif +#ifndef configMAC_ADDR4 +#define configMAC_ADDR4 0x15 +#endif +#ifndef configMAC_ADDR5 +#define configMAC_ADDR5 0x11 +#endif + +#define ENET_OK (0U) +#define ENET_ERROR (0xFFU) +#define ENET_TIMEOUT (0xFFFU) + +/* ENET IRQ priority. Used in FreeRTOS. */ +#ifndef ENET_PRIORITY + #define ENET_PRIORITY (6U) +#endif +#ifndef ENET_1588_PRIORITY + #define ENET_1588_PRIORITY (5U) +#endif +/* The PHY address.*/ +#ifndef ENET_PHY_ADDRESS + #define ENET_PHY_ADDRESS (1) +#endif + +/* Defines Ethernet Autonegotiation Timeout during initialization. + * Set it to 0 to disable the waiting. */ +#ifndef ENET_ATONEGOTIATION_TIMEOUT + #define ENET_ATONEGOTIATION_TIMEOUT (0xFFFU) +#endif + +/** + * This function should be passed as a parameter to netif_add() + */ +err_t ethernetif_init(struct netif *netif); + +/** + * This function should be called when a packet is ready to be read + * from the interface. + * It is used by bare-metal applications. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input(struct netif *netif); + +#endif diff --git a/include/fsl_phy.h b/include/fsl_phy.h new file mode 100644 index 0000000..4ef4e36 --- /dev/null +++ b/include/fsl_phy.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#ifndef _FSL_PHY_H_ +#define _FSL_PHY_H_ + +#include "fsl_enet.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */ + +/*! @brief Defines the PHY registers. */ +#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */ +#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */ +#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */ +#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */ +#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */ +#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */ +#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */ + +#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1*/ + +/*! @brief Defines the mask flag in basic control register. */ +#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */ +#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */ +#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */ +#define PHY_BCTL_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */ +#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ +#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ + +/*!@brief Defines the mask flag of operation mode in control two register*/ +#define PHY_CTL1_REMOTELOOP_MASK 0x0008U /*!< The PHY remote loopback mask. */ +#define PHY_CTL2_10HALFDUPLEX_MASK 0x0004U /*!< The PHY 10M half duplex mask. */ +#define PHY_CTL2_100HALFDUPLEX_MASK 0x0008U /*!< The PHY 100M half duplex mask. */ +#define PHY_CTL2_10FULLDUPLEX_MASK 0x0014U /*!< The PHY 10M full duplex mask. */ +#define PHY_CTL2_100FULLDUPLEX_MASK 0x0018U /*!< The PHY 100M full duplex mask. */ + +/*! @brief Defines the mask flag in basic status register. */ +#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */ +#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */ +#define PHY_BSTATUS_SPEEDUPLX_MASK 0x001cU /*!< The PHY speed and duplex mask. */ +#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */ + +/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */ +#define PHY_100BaseT4_ABILITY_MASK 0x200U /*!< The PHY have the T4 ability. */ +#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_10BASETX_FULLDUPLEX_MASK 0x040U /*!< The PHY has the 10M full duplex ability.*/ +#define PHY_10BASETX_HALFDUPLEX_MASK 0x020U /*!< The PHY has the 10M full duplex ability.*/ + +/*! @brief Defines the PHY status. */ +enum _phy_status +{ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */ + kStatus_PHY_AutoNegotiateFail = MAKE_STATUS(kStatusGroup_PHY, 1) /*!< ENET PHY AutoNegotiate Fail. */ +}; + +/*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */ +typedef enum _phy_speed +{ + kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */ + kPHY_Speed100M /*!< ENET PHY 100M speed. */ +} phy_speed_t; + +/*! @brief Defines the PHY link duplex. */ +typedef enum _phy_duplex +{ + kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */ + kPHY_FullDuplex /*!< ENET PHY full duplex. */ +} phy_duplex_t; + +/*! @brief Defines the PHY loopback mode. */ +typedef enum _phy_loop +{ + kPHY_LocalLoop = 0U, /*!< ENET PHY local loopback. */ + kPHY_RemoteLoop /*!< ENET PHY remote loopback. */ +} phy_loop_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize the SMI interface and initialize PHY. + * The SMI is the MII management interface between PHY and MAC, which should be + * firstly initialized before any other operation for PHY. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. + * @retval kStatus_Success PHY initialize success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + * @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail + */ +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz); + +/*! + * @brief PHY Write function. This function write data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * the two loopback mode should not be both set. when one loopback mode is set + * the other one should be disabled. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, bool enable); + +/*! + * @brief Gets the PHY link status. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY get link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHY_H_ */ diff --git a/lib/LwIP/CMakeLists.txt b/lib/LwIP/CMakeLists.txt new file mode 100644 index 0000000..8b0d5ff --- /dev/null +++ b/lib/LwIP/CMakeLists.txt @@ -0,0 +1,141 @@ +cmake_minimum_required(VERSION 3.10) + +project(lwip) + +if(NOT LWIP_CONFIG_FILE_DIRECTORY) + message(FATAL_ERROR "Please specify LWIP_CONFIG_FILE_DIRECTORY for lwipopts.h") +endif() + +set(lwip_SRCS + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/if_api.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c" + "lwip/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c" + "lwip/src/apps/http/altcp_proxyconnect.c" + "lwip/src/apps/http/fs.c" + "lwip/src/apps/http/fsdata.c" + "lwip/src/apps/http/http_client.c" + "lwip/src/apps/http/httpd.c" + "lwip/src/apps/lwiperf/lwiperf.c" + "lwip/src/apps/mdns/mdns.c" + "lwip/src/apps/mdns/mdns_domain.c" + "lwip/src/apps/mdns/mdns_out.c" + "lwip/src/apps/mqtt/mqtt.c" + "lwip/src/apps/netbiosns/netbiosns.c" + "lwip/src/apps/smtp/smtp.c" + "lwip/src/apps/snmp/snmp_asn1.c" + "lwip/src/apps/snmp/snmp_core.c" + "lwip/src/apps/snmp/snmp_mib2.c" + "lwip/src/apps/snmp/snmp_mib2_icmp.c" + "lwip/src/apps/snmp/snmp_mib2_interfaces.c" + "lwip/src/apps/snmp/snmp_mib2_ip.c" + "lwip/src/apps/snmp/snmp_mib2_snmp.c" + "lwip/src/apps/snmp/snmp_mib2_system.c" + "lwip/src/apps/snmp/snmp_mib2_tcp.c" + "lwip/src/apps/snmp/snmp_mib2_udp.c" + "lwip/src/apps/snmp/snmp_msg.c" + "lwip/src/apps/snmp/snmp_netconn.c" + "lwip/src/apps/snmp/snmp_pbuf_stream.c" + "lwip/src/apps/snmp/snmp_raw.c" + "lwip/src/apps/snmp/snmp_scalar.c" + "lwip/src/apps/snmp/snmp_snmpv2_framework.c" + "lwip/src/apps/snmp/snmp_snmpv2_usm.c" + "lwip/src/apps/snmp/snmp_table.c" + "lwip/src/apps/snmp/snmp_threadsync.c" + "lwip/src/apps/snmp/snmp_traps.c" + "lwip/src/apps/snmp/snmpv3.c" + "lwip/src/apps/snmp/snmpv3_mbedtls.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/apps/tftp/tftp.c" + "lwip/src/core/altcp.c" + "lwip/src/core/altcp_alloc.c" + "lwip/src/core/altcp_tcp.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/ipv4/acd.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/netif/bridgeif.c" + "lwip/src/netif/bridgeif_fdb.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/lowpan6.c" + "lwip/src/netif/lowpan6_ble.c" + "lwip/src/netif/lowpan6_common.c" + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/polarssl/arc4.c" + "lwip/src/netif/ppp/polarssl/des.c" + "lwip/src/netif/ppp/polarssl/md4.c" + "lwip/src/netif/ppp/polarssl/md5.c" + "lwip/src/netif/ppp/polarssl/sha1.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/zepif.c" + +) + +set(lwip_INCS + "lwip/src/include" +) + +add_library(${PROJECT_NAME} ${lwip_SRCS}) +target_include_directories(${PROJECT_NAME} PUBLIC ${lwip_INCS} ${LWIP_CONFIG_FILE_DIRECTORY}) \ No newline at end of file diff --git a/lib/LwIP b/lib/LwIP/lwip similarity index 100% rename from lib/LwIP rename to lib/LwIP/lwip diff --git a/lib/LwIP/port/include/arch/cc.h b/lib/LwIP/port/include/arch/cc.h new file mode 100644 index 0000000..853aa9a --- /dev/null +++ b/lib/LwIP/port/include/arch/cc.h @@ -0,0 +1,43 @@ +/* + * 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 + * + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +#define LWIP_ERRNO_INCLUDE +#define LWIP_ERRNO_STDINCLUDE 1 + +extern unsigned int lwip_platform_rand(void); +#define LWIP_RAND() (lwip_platform_rand()) + +#define LWIP_TIMEVAL_PRIVATE 0 + +#endif /* LWIP_ARCH_CC_H */ diff --git a/lib/LwIP/port/include/arch/sys_arch.h b/lib/LwIP/port/include/arch/sys_arch.h new file mode 100644 index 0000000..0cfc889 --- /dev/null +++ b/lib/LwIP/port/include/arch/sys_arch.h @@ -0,0 +1,95 @@ +/* + * 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 + * + */ +#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 */ diff --git a/lib/LwIP/port/include/lwipopts.h b/lib/LwIP/port/include/lwipopts.h new file mode 100644 index 0000000..b631323 --- /dev/null +++ b/lib/LwIP/port/include/lwipopts.h @@ -0,0 +1,334 @@ +/* + * 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 + * + */ +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +#ifdef LWIP_OPTTEST_FILE +#include "lwipopts_test.h" +#else /* LWIP_OPTTEST_FILE */ + +#define LWIP_IPV4 1 +#define LWIP_IPV6 1 + +#define NO_SYS 0 +#define LWIP_SOCKET (NO_SYS==0) +#define LWIP_NETCONN (NO_SYS==0) +#define LWIP_NETIF_API (NO_SYS==0) + +#define LWIP_IGMP LWIP_IPV4 +#define LWIP_ICMP LWIP_IPV4 + +#define LWIP_SNMP LWIP_UDP +#define MIB2_STATS LWIP_SNMP +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_SNMP_V3 (LWIP_SNMP) +#endif + +#define LWIP_DNS LWIP_UDP +#define LWIP_MDNS_RESPONDER LWIP_UDP + +#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER) + +#define LWIP_HAVE_LOOPIF 1 +#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_LOOPBACK_MAX_PBUFS 10 + +#define TCP_LISTEN_BACKLOG 1 + +#define LWIP_COMPAT_SOCKETS 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_RCVBUF 1 + +#define LWIP_TCPIP_CORE_LOCKING 1 + +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 + +#define LWIP_DEBUG 1 + + +#ifdef LWIP_DEBUG + +#define LWIP_DBG_MIN_LEVEL 0 +#define PPP_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_ON +#define NETIF_DEBUG LWIP_DBG_ON +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_ON +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) + + +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ +/* MSVC port: intel processors don't need 4-byte alignment, + but are faster that way! */ +#define MEM_ALIGNMENT 4U + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#define MEM_SIZE 10240 + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#define MEMP_NUM_PBUF 16 +/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One + per active RAW "connection". */ +#define MEMP_NUM_RAW_PCB 3 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 8 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 5 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 16 +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 17 + +/* The following four are used only with the sequential API and can be + set to 0 if the application only will use the raw API. */ +/* MEMP_NUM_NETBUF: the number of struct netbufs. */ +#define MEMP_NUM_NETBUF 2 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 12 +/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used + for sequential API communication and incoming packets. Used in + src/api/tcpip.c. */ +#define MEMP_NUM_TCPIP_MSG_API 16 +#define MEMP_NUM_TCPIP_MSG_INPKT 16 + + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 72 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 256 + +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT (NO_SYS==0) + + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +#define LWIP_ALTCP (LWIP_TCP) +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_ALTCP_TLS (LWIP_TCP) +#define LWIP_ALTCP_TLS_MBEDTLS (LWIP_TCP) +#endif + + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 1 + +/* TCP Maximum segment size. */ +#define TCP_MSS 1024 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF 2048 + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) + +/* TCP writable space (bytes). This must be less than or equal + to TCP_SND_BUF. It is the amount of space which must be + available in the tcp snd_buf for select to return writable */ +#define TCP_SNDLOWAT (TCP_SND_BUF/2) + +/* TCP receive window. */ +#define TCP_WND (10 * 1024) + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + + +/* ---------- ARP options ---------- */ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_QUEUEING 1 + + +/* ---------- IP options ---------- */ +/* Define IP_FORWARD to 1 if you wish to have the ability to forward + IP packets across network interfaces. If you are going to run lwIP + on a device with only one network interface, define this to 0. */ +#define IP_FORWARD 1 + +/* IP reassembly and segmentation.These are orthogonal even + * if they both deal with IP fragments */ +#define IP_REASSEMBLY 1 +#define IP_REASS_MAX_PBUFS (10 * ((1500 + PBUF_POOL_BUFSIZE - 1) / PBUF_POOL_BUFSIZE)) +#define MEMP_NUM_REASSDATA IP_REASS_MAX_PBUFS +#define IP_FRAG 1 +#define IPV6_FRAG_COPYHEADER 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. */ +#define LWIP_DHCP LWIP_UDP + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK (LWIP_DHCP) + + +/* ---------- AUTOIP options ------- */ +#define LWIP_AUTOIP (LWIP_DHCP) +#define LWIP_DHCP_AUTOIP_COOP (LWIP_DHCP && LWIP_AUTOIP) + + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define LWIP_UDPLITE LWIP_UDP +#define UDP_TTL 255 + + +/* ---------- RAW options ---------- */ +#define LWIP_RAW 1 + + +/* ---------- Statistics options ---------- */ + +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 + +#if LWIP_STATS +#define LINK_STATS 1 +#define IP_STATS 1 +#define ICMP_STATS 1 +#define IGMP_STATS 1 +#define IPFRAG_STATS 1 +#define UDP_STATS 1 +#define TCP_STATS 1 +#define MEM_STATS 1 +#define MEMP_STATS 1 +#define PBUF_STATS 1 +#define SYS_STATS 1 +#endif /* LWIP_STATS */ + +/* ---------- NETBIOS options ---------- */ +#define LWIP_NETBIOS_RESPOND_NAME_QUERY 1 + +/* ---------- PPP options ---------- */ + +#define PPP_SUPPORT 1 /* Set > 0 for PPP */ + +#if PPP_SUPPORT + +#define NUM_PPP 1 /* Max PPP sessions. */ + + +/* Select modules to enable. Ideally these would be set in the makefile but + * we're limited by the command line length so you need to modify the settings + * in this file. + */ +#define PPPOE_SUPPORT 1 +#define PPPOS_SUPPORT 1 + +#define PAP_SUPPORT 1 /* Set > 0 for PAP. */ +#define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */ +#define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP */ +#define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */ +#define CCP_SUPPORT 0 /* Set > 0 for CCP */ +#define VJ_SUPPORT 0 /* Set > 0 for VJ header compression. */ +#define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */ + +#endif /* PPP_SUPPORT */ + +#endif /* LWIP_OPTTEST_FILE */ + +/* The following defines must be done even in OPTTEST mode: */ + +#if !defined(NO_SYS) || !NO_SYS /* default is 0 */ +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() +#endif + +#ifndef LWIP_PLATFORM_ASSERT +/* Define LWIP_PLATFORM_ASSERT to something to catch missing stdio.h includes */ +void lwip_platform_assert(const char *msg, int line, const char *file); +#define LWIP_PLATFORM_ASSERT(x) lwip_platform_assert(x, __LINE__, __FILE__) +#endif + +/* FreeRTOS related settings */ +#define TCPIP_MBOX_SIZE 32 +#define TCPIP_THREAD_STACKSIZE 1024 + + +#endif /* LWIP_LWIPOPTS_H */ diff --git a/lib/LwIP/port/lwip_helpers.c b/lib/LwIP/port/lwip_helpers.c new file mode 100644 index 0000000..e1159b4 --- /dev/null +++ b/lib/LwIP/port/lwip_helpers.c @@ -0,0 +1,15 @@ +#include + +#include "fsl_debug_console.h" + +void lwip_platform_assert(const char *msg, int line, const char *file) { + PRINTF("Assertion \"%s\" failed at line %d in %s\r\n", msg, line, file); + for(;;) { + /**/ + } +} + +int lwip_platform_rand(void) { + /* TODO: Use RNG. */ + return rand(); +} \ No newline at end of file diff --git a/lib/LwIP/port/sys_arch.c b/lib/LwIP/port/sys_arch.c new file mode 100644 index 0000000..a8f26f6 --- /dev/null +++ b/lib/LwIP/port/sys_arch.c @@ -0,0 +1,607 @@ +/* + * 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 + * + */ + +/* lwIP includes. */ +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/stats.h" +#include "lwip/tcpip.h" +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" + +/** 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 0 +#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 1 +#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 1 +#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 = pdMS_TO_TICKS(delay_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 = pdMS_TO_TICKS(timeout_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 = pdMS_TO_TICKS(timeout_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); + + return 0; +} + +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*/ diff --git a/src/ethernetif.c b/src/ethernetif.c new file mode 100644 index 0000000..a3dc367 --- /dev/null +++ b/src/ethernetif.c @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2001-2004 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 + * + */ + +/* + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 SDRVL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "netif/etharp.h" +#include "netif/ppp/pppoe.h" +#include "lwip/igmp.h" +#include "lwip/mld6.h" + +#define USE_RTOS 1 +#define FSL_RTOS_FREE_RTOS 1 + +#define LINK_SPEED_OF_YOUR_NETIF_IN_BPS 100000000 + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" +#endif + +#include "ethernetif.h" + +#include "fsl_enet.h" +#include "fsl_phy.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +#define ENET_ALIGN(x) \ + ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1))) + +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +#define kENET_RxEvent kENET_RxIntEvent +#define kENET_TxEvent kENET_TxIntEvent +#endif + +/** + * Helper struct to hold private data used to operate your ethernet interface. + */ +struct ethernetif +{ + ENET_Type *base; +#if (defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)) || \ + (USE_RTOS && defined(FSL_RTOS_FREE_RTOS)) + enet_handle_t handle; +#endif + uint32_t phyAddr; +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + EventGroupHandle_t enetTransmitAccessEvent; + TaskHandle_t rxTaskHandle; + EventBits_t txFlag; +#endif + uint8_t RxBuffDescrip[ENET_RXBD_NUM * sizeof(enet_rx_bd_struct_t) + ENET_BUFF_ALIGNMENT]; + uint8_t TxBuffDescrip[ENET_TXBD_NUM * sizeof(enet_tx_bd_struct_t) + ENET_BUFF_ALIGNMENT]; + uint8_t RxDataBuff[ENET_RXBD_NUM * ENET_ALIGN(ENET_RXBUFF_SIZE) + ENET_BUFF_ALIGNMENT]; + uint8_t TxDataBuff[ENET_TXBD_NUM * ENET_ALIGN(ENET_TXBUFF_SIZE) + ENET_BUFF_ALIGNMENT]; +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + uint8_t txIdx; +#if !(USE_RTOS && defined(FSL_RTOS_FREE_RTOS)) + uint8_t rxIdx; +#endif +#endif +}; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static struct ethernetif ethernetif_0; + +/******************************************************************************* + * Code + ******************************************************************************/ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param) +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param) +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ +{ + struct netif *netif = (struct netif *)param; + struct ethernetif *ethernetif = netif->state; + + BaseType_t xHigherPriorityTaskWoken = 0U; + + switch (event) + { + case kENET_RxEvent: + { + if(__get_IPSR()) + { + xTaskNotifyFromISR(ethernetif->rxTaskHandle, 0x1UL, eSetBits, &xHigherPriorityTaskWoken); + } + else + { + xTaskNotify(ethernetif->rxTaskHandle, 0x1UL, eSetBits); + } + break; + } + case kENET_TxEvent: + { + if (__get_IPSR()) + { + xEventGroupSetBitsFromISR(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, &xHigherPriorityTaskWoken); + } + else + { + xEventGroupSetBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag); + } + } + break; + default: + break; + } + if(__get_IPSR()) + { + if (pdTRUE == xHigherPriorityTaskWoken) + { + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + } +} +#endif + +#if LWIP_IPV4 && LWIP_IGMP +static err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, u8_t action) +{ + struct ethernetif *ethernetif = netif->state; + uint8_t multicastMacAddr[6]; + err_t result; + + multicastMacAddr[0] = 0x01U; + multicastMacAddr[1] = 0x00U; + multicastMacAddr[2] = 0x5EU; + multicastMacAddr[3] = (group->addr >> 8) & 0x7FU; + multicastMacAddr[4] = (group->addr >> 16) & 0xFFU; + multicastMacAddr[5] = (group->addr >> 24) & 0xFFU; + + switch (action) + { + case IGMP_ADD_MAC_FILTER: + /* Adds the ENET device to a multicast group.*/ + ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr); + result = ERR_OK; + break; + case IGMP_DEL_MAC_FILTER: +/* Moves the ENET device from a multicast group.*/ +#if 0 + ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); +#endif + result = ERR_OK; + break; + default: + result = ERR_IF; + break; + } + + return result; +} +#endif + +#if LWIP_IPV6 && LWIP_IPV6_MLD +static err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action) +{ + struct ethernetif *ethernetif = netif->state; + uint8_t multicastMacAddr[6]; + err_t result; + + multicastMacAddr[0] = 0x33U; + multicastMacAddr[1] = 0x33U; + multicastMacAddr[2] = (group->addr[3]) & 0xFFU; + multicastMacAddr[3] = (group->addr[3] >> 8) & 0xFFU; + multicastMacAddr[4] = (group->addr[3] >> 16) & 0xFFU; + multicastMacAddr[5] = (group->addr[3] >> 24) & 0xFFU; + + switch (action) + { + case NETIF_ADD_MAC_FILTER: + /* Adds the ENET device to a multicast group.*/ + ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr); + result = ERR_OK; + break; + case NETIF_DEL_MAC_FILTER: +/* Moves the ENET device from a multicast group.*/ +#if 0 + ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); +#endif + result = ERR_OK; + break; + default: + result = ERR_IF; + break; + } + + return result; +} +#endif + +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +static inline enet_rx_bd_struct_t *get_rx_desc(struct ethernetif *ethernetif, uint32_t index) +{ + return (enet_rx_bd_struct_t *)ENET_ALIGN(ðernetif->RxBuffDescrip[index * sizeof(enet_rx_bd_struct_t)]); +} + +static inline enet_tx_bd_struct_t *get_tx_desc(struct ethernetif *ethernetif, uint32_t index) +{ + return (enet_tx_bd_struct_t *)ENET_ALIGN(ðernetif->TxBuffDescrip[index * sizeof(enet_tx_bd_struct_t)]); +} +#endif + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) +static void enet_rx_task(void *params) { + struct netif *netif = params; + uint32_t ulNotifyValue = 0U; + + for(;;) { + xTaskNotifyWait(0UL, 0xFFFFFFFFUL, &ulNotifyValue, portMAX_DELAY); + ethernetif_input(netif); + } +} +#endif + +/** + * Initializes ENET driver. + */ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) +static void enet_init(struct netif *netif, struct ethernetif *ethernetif) +{ + enet_config_t config; + uint32_t sysClock; + bool link = false; + phy_speed_t speed; + phy_duplex_t duplex; + uint32_t count = 0; + enet_buffer_config_t buffCfg; + + /* prepare the buffer configuration. */ + buffCfg.rxBdNumber = ENET_RXBD_NUM; /* Receive buffer descriptor number. */ + buffCfg.txBdNumber = ENET_TXBD_NUM; /* Transmit buffer descriptor number. */ + buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE); /* Aligned receive data buffer size. */ + buffCfg.txBuffSizeAlign = ENET_ALIGN(ENET_TXBUFF_SIZE); /* Aligned transmit data buffer size. */ + buffCfg.rxBdStartAddrAlign = (enet_rx_bd_struct_t *)ENET_ALIGN( + ethernetif->RxBuffDescrip); /* Aligned receive buffer descriptor start address. */ + buffCfg.txBdStartAddrAlign = (enet_tx_bd_struct_t *)ENET_ALIGN( + ethernetif->TxBuffDescrip); /* Aligned transmit buffer descriptor start address. */ + buffCfg.rxBufferAlign = (uint8_t *)ENET_ALIGN(ethernetif->RxDataBuff); /* Receive data buffer start address. */ + buffCfg.txBufferAlign = (uint8_t *)ENET_ALIGN(ethernetif->TxDataBuff); /* Transmit data buffer start address. */ + + sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk); + + ENET_GetDefaultConfig(&config); + + PHY_Init(ethernetif->base, ethernetif->phyAddr, sysClock); + + while ((count < ENET_ATONEGOTIATION_TIMEOUT) && (!link)) + { + PHY_GetLinkStatus(ethernetif->base, ethernetif->phyAddr, &link); + + if (link) + { + /* Get the actual PHY link speed. */ + PHY_GetLinkSpeedDuplex(ethernetif->base, ethernetif->phyAddr, &speed, &duplex); + /* Change the MII speed and duplex for actual link status. */ + config.miiSpeed = (enet_mii_speed_t)speed; + config.miiDuplex = (enet_mii_duplex_t)duplex; + } + + count++; + } + +#if 0 /* Disable assert. If initial auto-negation is timeout, \ \ + the ENET set to default 100Mbs and full-duplex.*/ + if (count == ENET_ATONEGOTIATION_TIMEOUT) + { + LWIP_ASSERT("\r\nPHY Link down, please check the cable connection.\r\n", 0); + } +#endif + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + /* Create the Event for transmit busy release trigger. */ + ethernetif->enetTransmitAccessEvent = xEventGroupCreate(); + ethernetif->txFlag = 0x1; + + config.interrupt |= kENET_RxFrameInterrupt | kENET_TxFrameInterrupt | kENET_TxBufferInterrupt; + + NVIC_SetPriority(ENET_Receive_IRQn, ENET_PRIORITY); + NVIC_SetPriority(ENET_Transmit_IRQn, ENET_PRIORITY); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + NVIC_SetPriority(ENET_1588_Timer_IRQn, ENET_1588_PRIORITY); +#endif +#endif /* USE_RTOS */ + + /* Initialize the ENET module.*/ + ENET_Init(ethernetif->base, ðernetif->handle, &config, &buffCfg, netif->hwaddr, sysClock); + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + xTaskCreate(enet_rx_task, "enet_rx_task", 1024, netif, 2, ðernetif->rxTaskHandle); + + ENET_SetCallback(ðernetif->handle, ethernet_callback, netif); +#endif + + ENET_ActiveRead(ethernetif->base); +} +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +static void enet_init(struct netif *netif, struct ethernetif *ethernetif) +{ + enet_config_t config; + uint32_t sysClock; + bool link = false; + phy_speed_t speed; + phy_duplex_t duplex; + uint32_t count = 0; + enet_buffer_config_t buffCfg; + uint32_t rxBufferStartAddr[ENET_RXBD_NUM]; + uint32_t i; + + /* calculate start addresses of all rx buffers */ + for (i = 0; i < ENET_RXBD_NUM; i++) + { + rxBufferStartAddr[i] = ENET_ALIGN(ðernetif->RxDataBuff[i * ENET_ALIGN(ENET_RXBUFF_SIZE)]); + } + + /* prepare the buffer configuration. */ + buffCfg.rxRingLen = ENET_RXBD_NUM; /* The length of receive buffer descriptor ring. */ + buffCfg.txRingLen = ENET_TXBD_NUM; /* The length of transmit buffer descriptor ring. */ + buffCfg.txDescStartAddrAlign = get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor start address. */ + buffCfg.txDescTailAddrAlign = get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor tail address. */ + buffCfg.rxDescStartAddrAlign = get_rx_desc(ethernetif, 0U); /* Aligned receive descriptor start address. */ + buffCfg.rxDescTailAddrAlign = get_rx_desc(ethernetif, ENET_RXBD_NUM); /* Aligned receive descriptor tail address. */ + buffCfg.rxBufferStartAddr = rxBufferStartAddr; /* Start addresses of the rx buffers. */ + buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE); /* Aligned receive data buffer size. */ + + sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk); + + ENET_GetDefaultConfig(&config); + + PHY_Init(ethernetif->base, ethernetif->phyAddr, 0); + + while ((count < ENET_ATONEGOTIATION_TIMEOUT) && (!link)) + { + PHY_GetLinkStatus(ethernetif->base, ethernetif->phyAddr, &link); + if (link) + { + /* Get the actual PHY link speed. */ + PHY_GetLinkSpeedDuplex(ethernetif->base, ethernetif->phyAddr, &speed, &duplex); + /* Change the MII speed and duplex for actual link status. */ + config.miiSpeed = (enet_mii_speed_t)speed; + config.miiDuplex = (enet_mii_duplex_t)duplex; + } + + count++; + } + +#if 0 /* Disable assert. If initial auto-negation is timeout, \ \ + the ENET set to default 100Mbs and full-duplex.*/ + if (count == ENET_ATONEGOTIATION_TIMEOUT) + { + LWIP_ASSERT("\r\nPHY Link down, please check the cable connection.\r\n", 0); + } +#endif + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + /* Create the Event for transmit busy release trigger. */ + ethernetif->enetTransmitAccessEvent = xEventGroupCreate(); + ethernetif->txFlag = 0x1; + + NVIC_SetPriority(ETHERNET_IRQn, ENET_PRIORITY); +#else + ethernetif->rxIdx = 0U; +#endif /* USE_RTOS */ + + ethernetif->txIdx = 0U; + + ENET_Init(ethernetif->base, &config, netif->hwaddr, sysClock); + +/* Create the handler. */ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + ENET_EnableInterrupts(ethernetif->base, kENET_DmaTx | kENET_DmaRx); + ENET_CreateHandler(ethernetif->base, ðernetif->handle, &config, &buffCfg, ethernet_callback, netif); +#endif + + ENET_DescriptorInit(ethernetif->base, &config, &buffCfg); + + /* Active TX/RX. */ + ENET_StartRxTx(ethernetif->base, 1, 1); +} +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void low_level_init(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = configMAC_ADDR0; + netif->hwaddr[1] = configMAC_ADDR1; + netif->hwaddr[2] = configMAC_ADDR2; + netif->hwaddr[3] = configMAC_ADDR3; + netif->hwaddr[4] = configMAC_ADDR4; + netif->hwaddr[5] = configMAC_ADDR5; + + /* maximum transfer unit */ + netif->mtu = 1500; /* TODO: define a config */ + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + /* ENET driver initialization.*/ + enet_init(netif, ethernetif); + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) + { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +} + +/** + * Returns next buffer for TX. + * Can wait if no buffer available. + */ +static unsigned char *enet_get_tx_buffer(struct ethernetif *ethernetif) +{ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + { + static unsigned char ucBuffer[ENET_FRAME_MAX_FRAMELEN]; + return ucBuffer; + } +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + { + enet_tx_bd_struct_t *txBuffDesc = get_tx_desc(ethernetif, ethernetif->txIdx); +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + while (1) + { + if (ENET_IsTxDescriptorDmaOwn(txBuffDesc)) + { + xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false, + portMAX_DELAY); + } + else + { + break; + } + } +#else + { + uint32_t counter; + + for (counter = ENET_TIMEOUT; counter != 0U; counter--) + { + if (!ENET_IsTxDescriptorDmaOwn(txBuffDesc)) + { + break; + } + } + + if (counter == 0U) + { + return (unsigned char *)NULL; + } + } +#endif + return (unsigned char *)ENET_ALIGN(ethernetif->TxDataBuff + (ethernetif->txIdx * ENET_ALIGN(ENET_TXBUFF_SIZE))); + } +#endif +} + +/** + * Sends frame via ENET. + */ +static err_t enet_send_frame(struct ethernetif *ethernetif, unsigned char *data, const uint32_t length) +{ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + { + status_t result; + + do + { + result = ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length); + + if (result == kStatus_ENET_TxFrameBusy) + { + xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false, + portMAX_DELAY); + } + + } while (result == kStatus_ENET_TxFrameBusy); + return ERR_OK; + } +#elif defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + { + uint32_t counter; + + for (counter = ENET_TIMEOUT; counter != 0U; counter--) + { + if (ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length) != kStatus_ENET_TxFrameBusy) + { + return ERR_OK; + } + } + + return ERR_TIMEOUT; + } +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + { + uint32_t tail; + enet_tx_bd_struct_t *txBuffDesc = get_tx_desc(ethernetif, ethernetif->txIdx); + + ENET_SetupTxDescriptor(txBuffDesc, data, length, NULL, 0U, length, false, false, kENET_FirstLastFlag, 0U); + ethernetif->txIdx = (ethernetif->txIdx + 1U) % ENET_TXBD_NUM; + + /* Update the transmit tail address. */ + if (ethernetif->txIdx == 0U) + { + tail = (uint32_t)get_tx_desc(ethernetif, ENET_TXBD_NUM); + } + else + { + tail = (uint32_t)get_tx_desc(ethernetif, ethernetif->txIdx); + } + ENET_UpdateTxDescriptorTail(ethernetif->base, 0U, tail); + + return ERR_OK; + } +#endif +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static err_t low_level_output(struct netif *netif, struct pbuf *p) +{ + err_t result; + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + unsigned char *pucBuffer; + unsigned char *pucChar; + + LWIP_ASSERT("Output packet buffer empty", p); + + pucBuffer = enet_get_tx_buffer(ethernetif); + if (pucBuffer == NULL) + { + return ERR_BUF; + } + +/* Initiate transfer. */ + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + if (p->len == p->tot_len) + { +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + /* No pbuf chain, don't have to copy -> faster. */ + pucBuffer = (unsigned char *)p->payload; +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + /* No pbuf chain, still have to copy as pbuf could be reclaimed early. */ + memcpy(pucBuffer, p->payload, p->len); +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ + } + else + { + /* pbuf chain, copy into contiguous ucBuffer. */ + if (p->tot_len >= ENET_FRAME_MAX_FRAMELEN) + { + return ERR_BUF; + } + else + { + pucChar = pucBuffer; + + for (q = p; q != NULL; q = q->next) + { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + if (q == p) + { + memcpy(pucChar, q->payload, q->len); + pucChar += q->len; + } + else + { + memcpy(pucChar, q->payload, q->len); + pucChar += q->len; + } + } + } + } + + /* Send frame. */ + result = enet_send_frame(ethernetif, pucBuffer, p->tot_len); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) + { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } + else + { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } +/* increase ifoutdiscards or ifouterrors on error */ + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return result; +} + +/** + * Gets the length of received frame (if any). + */ +static status_t enet_get_rx_frame_size(struct ethernetif *ethernetif, uint32_t *length) +{ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + { + return ENET_GetRxFrameSize(ðernetif->handle, length); + } +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + { + return ENET_GetRxFrameSize(ethernetif->base, ðernetif->handle, length, 0U); + } +#else + { + uint8_t index = ethernetif->rxIdx; + enet_rx_bd_struct_t *rxDesc = get_rx_desc(ethernetif, index); + uint32_t rxControl = ENET_GetRxDescriptor(rxDesc); + + /* Reset the length to zero. */ + *length = 0; + + if (rxControl & ENET_RXDESCRIP_WR_OWN_MASK) + { + return kStatus_ENET_RxFrameEmpty; + } + else + { + do + { + /* Application owns the buffer descriptor, get the length. */ + if (rxControl & ENET_RXDESCRIP_WR_LD_MASK) + { + if (rxControl & ENET_RXDESCRIP_WR_ERRSUM_MASK) + { + return kStatus_ENET_RxFrameError; + } + else + { + *length = rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK; + return kStatus_Success; + } + } + + index = (index + 1U) % ENET_RXBD_NUM; + rxDesc = get_rx_desc(ethernetif, index); + rxControl = ENET_GetRxDescriptor(rxDesc); + } while (index != ethernetif->rxIdx); + + return kStatus_ENET_RxFrameError; + } + } +#endif +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ +} + +/** + * Reads frame from ENET. + */ +static void enet_read_frame(struct ethernetif *ethernetif, uint8_t *data, uint32_t length) +{ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + { + ENET_ReadFrame(ethernetif->base, ðernetif->handle, data, length); + } +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + { + ENET_ReadFrame(ethernetif->base, ðernetif->handle, data, length, 0U); + } +#else + { + enet_rx_bd_struct_t *rxDesc; + uint8_t index = ethernetif->rxIdx; + uint32_t rxControl; + bool isLastBuff = false; + uint32_t len = 0; + uint32_t offset = 0; + + if (!data) + { + do + { + rxDesc = get_rx_desc(ethernetif, ethernetif->rxIdx); + ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM; + rxControl = ENET_GetRxDescriptor(rxDesc); + + /* Update the receive buffer descriptor. */ + ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, false, false); + + /* Find the last buffer descriptor for the frame. */ + if (rxControl & ENET_RXDESCRIP_WR_LD_MASK) + { + break; + } + } while (ethernetif->rxIdx != index); + } + else + { + while (!isLastBuff) + { + rxDesc = get_rx_desc(ethernetif, ethernetif->rxIdx); + ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM; + rxControl = ENET_GetRxDescriptor(rxDesc); + + if (rxControl & ENET_RXDESCRIP_WR_LD_MASK) + { + /* This is a valid frame. */ + isLastBuff = true; + if (length == (rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK)) + { + /* Copy the frame to user's buffer. */ + len = (rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK) - offset; + if (len > ENET_ALIGN(ENET_RXBUFF_SIZE)) + { + memcpy(data + offset, (void *)rxDesc->buff1Addr, ENET_ALIGN(ENET_RXBUFF_SIZE)); + offset += ENET_ALIGN(ENET_RXBUFF_SIZE); + memcpy(data + offset, (void *)rxDesc->buff2Addr, len - ENET_ALIGN(ENET_RXBUFF_SIZE)); + } + else + { + memcpy(data + offset, (void *)rxDesc->buff1Addr, len); + } + } + + /* Update the receive buffer descriptor. */ + ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, false, false); + } + else + { + /* Store a frame on several buffer descriptors. */ + isLastBuff = false; + /* Length check. */ + if (offset >= length) + { + /* Updates the receive buffer descriptors. */ + ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, false, false); + break; + } + + memcpy(data + offset, (void *)rxDesc->buff1Addr, ENET_ALIGN(ENET_RXBUFF_SIZE)); + offset += ENET_ALIGN(ENET_RXBUFF_SIZE); + + /* Update the receive buffer descriptor. */ + ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, false, false); + } + } + } + + ENET_UpdateRxDescriptorTail(ethernetif->base, 0U, (uint32_t)get_rx_desc(ethernetif, ENET_RXBD_NUM)); + } +#endif /* USE_RTOS */ +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf *low_level_input(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p = NULL; + struct pbuf *q; + uint32_t len; + status_t status; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + status = enet_get_rx_frame_size(ethernetif, &len); + + if (kStatus_ENET_RxFrameEmpty != status) + { + /* Call enet_read_frame when there is a received frame. */ + if (len != 0) + { +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) + { +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + if (p->next == 0) /* One-chain buffer.*/ + { + enet_read_frame(ethernetif, p->payload, p->len); + } + else /* Multi-chain buffer.*/ + { + uint8_t data_tmp[ENET_FRAME_MAX_FRAMELEN]; + uint32_t data_tmp_len = 0; + + enet_read_frame(ethernetif, data_tmp, p->tot_len); + + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for (q = p; (q != NULL) && ((data_tmp_len + q->len) <= sizeof(data_tmp)); q = q->next) + { + /* Read enough bytes to fill this pbuf in the chain. The + * available data in the pbuf is given by the q->len + * variable. */ + memcpy(q->payload, &data_tmp[data_tmp_len], q->len); + data_tmp_len += q->len; + } + } + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) + { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } + else + { + /* unicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } + else + { + /* drop packet*/ + enet_read_frame(ethernetif, NULL, 0U); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Fail to allocate new memory space\n")); + + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + } + else + { + /* Update the received buffer when error happened. */ + if (status == kStatus_ENET_RxFrameError) + { +#if 0 && defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) /* Error statisctics */ + enet_data_error_stats_t eErrStatic; + /* Get the error information of the received g_frame. */ + ENET_GetRxErrBeforeReadFrame(ðernetif->handle, &eErrStatic); +#endif + + /* Update the receive buffer. */ + enet_read_frame(ethernetif, NULL, 0U); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: RxFrameError\n")); + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + } + } + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input(struct netif *netif) +{ + struct pbuf *p; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + /* move received packet into a new pbuf */ + while ((p = low_level_input(netif)) != NULL) + { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +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 */ + + /* + * 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); + + netif->state = ðernetif_0; + 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...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + +#if LWIP_IPV4 && LWIP_IGMP + netif_set_igmp_mac_filter(netif, ethernetif_igmp_mac_filter); + netif->flags |= NETIF_FLAG_IGMP; +#endif +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif_set_mld_mac_filter(netif, ethernetif_mld_mac_filter); + netif->flags |= NETIF_FLAG_MLD6; +#endif + + /* Init ethernetif parameters.*/ + ethernetif_0.base = ENET; + ethernetif_0.phyAddr = ENET_PHY_ADDRESS; + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} diff --git a/src/fsl_phy.c b/src/fsl_phy.c new file mode 100644 index 0000000..7a767b7 --- /dev/null +++ b/src/fsl_phy.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "fsl_phy.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the timeout macro. */ +#define PHY_TIMEOUT_COUNT 0xFFFFFU + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +extern uint32_t ENET_GetInstance(ENET_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to enet clocks for each instance. */ +extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) +{ + uint32_t bssReg; + uint32_t counter = PHY_TIMEOUT_COUNT; + uint32_t idReg = 0; + status_t result = kStatus_Success; + uint32_t instance = ENET_GetInstance(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + ENET_SetSMI(base, srcClock_Hz, false); + + /* Initialization after PHY stars to work. */ + while ((idReg != PHY_CONTROL_ID1) && (counter != 0)) + { + PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg); + counter --; + } + + if (!counter) + { + return kStatus_Fail; + } + + /* Reset PHY. */ + counter = PHY_TIMEOUT_COUNT; + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) + { + /* Set the negotiation. */ + result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U)); + if (result == kStatus_Success) + { + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + if (result == kStatus_Success) + { + /* Check auto negotiation complete. */ + while (counter --) + { + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); + if ( result == kStatus_Success) + { + if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) + { + break; + } + } + + if (!counter) + { + return kStatus_PHY_AutoNegotiateFail; + } + } + } + } + } + + return result; +} + +status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t counter; + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI write command. */ + ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data); + + /* Wait for SMI complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} + +status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr) +{ + assert(dataPtr); + + uint32_t counter; + + /* Clear the MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI read command operation. */ + ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame); + + /* Wait for MII complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Get data from MII register. */ + *dataPtr = ENET_ReadSMIData(base); + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} + +status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, bool enable) +{ + status_t result; + uint32_t data = 0; + + /* Set the loop mode. */ + if (enable) + { + if (mode == kPHY_LocalLoop) + { + /* First read the current status in control register. */ + result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_LOOP_MASK)); + } + } + else + { + /* First read the current status in control register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_CONTROL1_REG, (data | PHY_CTL1_REMOTELOOP_MASK)); + } + } + } + else + { + /* Disable the loop mode. */ + if (mode == kPHY_LocalLoop) + { + /* First read the current status in the basic control register. */ + result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data & ~PHY_BCTL_LOOP_MASK)); + } + } + else + { + /* First read the current status in control one register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_CONTROL1_REG, (data & ~PHY_CTL1_REMOTELOOP_MASK)); + } + } + } + return result; +} + +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status) +{ + assert(status); + + status_t result = kStatus_Success; + uint32_t data; + + /* Read the basic status register. */ + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data); + if (result == kStatus_Success) + { + if (!(PHY_BSTATUS_LINKSTATUS_MASK & data)) + { + /* link down. */ + *status = false; + } + else + { + /* link up. */ + *status = true; + } + } + return result; +} + +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex) +{ + assert(duplex); + + status_t result = kStatus_Success; + uint32_t data, ctlReg; + + /* Read the control two register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &ctlReg); + if (result == kStatus_Success) + { + data = ctlReg & PHY_BSTATUS_SPEEDUPLX_MASK; + if ((PHY_CTL2_10FULLDUPLEX_MASK == data) || (PHY_CTL2_100FULLDUPLEX_MASK == data)) + { + /* Full duplex. */ + *duplex = kPHY_FullDuplex; + } + else + { + /* Half duplex. */ + *duplex = kPHY_HalfDuplex; + } + + data = ctlReg & PHY_BSTATUS_SPEEDUPLX_MASK; + if ((PHY_CTL2_100HALFDUPLEX_MASK == data) || (PHY_CTL2_100FULLDUPLEX_MASK == data)) + { + /* 100M speed. */ + *speed = kPHY_Speed100M; + } + else + { /* 10M speed. */ + *speed = kPHY_Speed10M; + } + } + + return result; +} diff --git a/src/main.c b/src/main.c index b2cc077..72d3bd2 100644 --- a/src/main.c +++ b/src/main.c @@ -1,12 +1,28 @@ -#include "FreeRTOS.h" #include "board.h" #include "clock_config.h" -#include "fsl_debug_console.h" #include "peripherals.h" #include "pin_mux.h" + +/* Console */ +#include "fsl_debug_console.h" + +/* MISC */ #include "system_utilities.h" + +/*FreeRTOS*/ +#include "FreeRTOS.h" #include "task.h" +/* LwIP */ +#include "lwip/dhcp.h" +#include "lwip/prot/dhcp.h" +#include "lwip/tcpip.h" + +/* ENET */ +#include "ethernetif.h" + +static struct netif fsl_netif0; + static void vTaskHello(void *pvParameters); int main(void) { @@ -28,9 +44,84 @@ int main(void) { } } -static void vTaskHello(void *pvParameters) { - for(;;) { - vTaskDelay(pdMS_TO_TICKS(1000)); - PRINTF("Hello world @%d\r\n", xTaskGetTickCount()); +static void setup_lwip(void) { + ip4_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw; + + SYSMPU->CESR &= ~(SYSMPU_CESR_VLD_MASK); /* Disable MPU */ + + tcpip_init(NULL, NULL); + netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, NULL, ethernetif_init, tcpip_input); + netif_set_default(&fsl_netif0); + netif_set_up(&fsl_netif0); + dhcp_start(&fsl_netif0); +} + +static void print_dhcp_state(struct netif *netif) { + static u8_t dhcp_last_state = DHCP_STATE_OFF; + struct dhcp *dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + + if (dhcp_last_state != dhcp->state) { + dhcp_last_state = dhcp->state; + + PRINTF(" DHCP state : "); + switch (dhcp_last_state) { + case DHCP_STATE_OFF: + PRINTF("OFF"); + break; + case DHCP_STATE_REQUESTING: + PRINTF("REQUESTING"); + break; + case DHCP_STATE_INIT: + PRINTF("INIT"); + break; + case DHCP_STATE_REBOOTING: + PRINTF("REBOOTING"); + break; + case DHCP_STATE_REBINDING: + PRINTF("REBINDING"); + break; + case DHCP_STATE_RENEWING: + PRINTF("RENEWING"); + break; + case DHCP_STATE_SELECTING: + PRINTF("SELECTING"); + break; + case DHCP_STATE_INFORMING: + PRINTF("INFORMING"); + break; + case DHCP_STATE_CHECKING: + PRINTF("CHECKING"); + break; + case DHCP_STATE_BOUND: + PRINTF("BOUND"); + break; + case DHCP_STATE_BACKING_OFF: + PRINTF("BACKING_OFF"); + break; + default: + PRINTF("%u", dhcp_last_state); + assert(0); + break; + } + PRINTF("\r\n"); + + if (dhcp_last_state == DHCP_STATE_BOUND) { + PRINTF("\r\n IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t *)&netif->ip_addr.u_addr)[0], + ((u8_t *)&netif->ip_addr.u_addr)[1], ((u8_t *)&netif->ip_addr.u_addr)[2], + ((u8_t *)&netif->ip_addr.u_addr)[3]); + PRINTF(" IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&netif->netmask.u_addr)[0], + ((u8_t *)&netif->netmask.u_addr)[1], ((u8_t *)&netif->netmask.u_addr)[2], + ((u8_t *)&netif->netmask.u_addr)[3]); + PRINTF(" IPv4 Gateway : %u.%u.%u.%u\r\n\r\n", ((u8_t *)&netif->gw.u_addr)[0], + ((u8_t *)&netif->gw.u_addr)[1], ((u8_t *)&netif->gw.u_addr)[2], ((u8_t *)&netif->gw.u_addr)[3]); + } + } +} + +static void vTaskHello(void *pvParameters) { + setup_lwip(); + for (;;) { + vTaskDelay(pdMS_TO_TICKS(1000)); + print_dhcp_state(&fsl_netif0); } }