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);
}
}