]> granicus.if.org Git - esp-idf/commitdiff
Merge branch 'bugfix/confgen_avoid_write_to_conf' into 'master'
authorIvan Grokhotkov <ivan@espressif.com>
Thu, 4 Jul 2019 14:36:23 +0000 (22:36 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Thu, 4 Jul 2019 14:36:23 +0000 (22:36 +0800)
tools: avoid using directly _write_to_conf from Kconfiglib

Closes IDFGH-1246

See merge request espressif/esp-idf!5423

41 files changed:
components/bt/controller/lib
components/esp32/CMakeLists.txt
components/esp32/esp_adapter.c
components/esp_eth/CMakeLists.txt
components/esp_eth/Kconfig
components/esp_eth/component.mk
components/esp_eth/include/esp_eth_mac.h
components/esp_eth/include/esp_eth_phy.h
components/esp_eth/linker.lf
components/esp_eth/src/esp_eth_mac_dm9051.c [new file with mode: 0644]
components/esp_eth/src/esp_eth_mac_esp32.c
components/esp_eth/src/esp_eth_phy_dm9051.c [new file with mode: 0644]
components/esp_eth/test/test_emac.c
components/esp_wifi/CMakeLists.txt
components/esp_wifi/include/esp_private/wifi.h
components/esp_wifi/include/esp_private/wifi_os_adapter.h
components/esp_wifi/include/esp_smartconfig.h
components/esp_wifi/lib_esp32
components/esp_wifi/src/smartconfig.c [new file with mode: 0644]
components/smartconfig_ack/include/smartconfig_ack.h
components/smartconfig_ack/smartconfig_ack.c
components/soc/esp32/emac_hal.c
examples/common_components/protocol_examples_common/Kconfig.projbuild
examples/common_components/protocol_examples_common/connect.c
examples/ethernet/basic/README.md
examples/ethernet/basic/main/Kconfig.projbuild
examples/ethernet/basic/main/ethernet_example_main.c
examples/ethernet/eth2ap/README.md
examples/ethernet/eth2ap/main/Kconfig.projbuild
examples/ethernet/eth2ap/main/ethernet_example_main.c
examples/ethernet/iperf/README.md
examples/ethernet/iperf/main/Kconfig.projbuild
examples/ethernet/iperf/main/cmd_ethernet.c
examples/ethernet/iperf/main/ethernet_example_main.c
examples/wifi/smart_config/main/smartconfig_main.c
tools/ci/checkout_project_ref.py
tools/idf_tools.py
tools/kconfig_new/confgen.py
tools/kconfig_new/test/Kconfig
tools/kconfig_new/test/testcases_v1.txt
tools/kconfig_new/test/testcases_v2.txt

index 471f03c2ca55225a600d3783dd277a910bfe80ed..d915fc93499fd925ae301306a7539b5f13bf6e65 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 471f03c2ca55225a600d3783dd277a910bfe80ed
+Subproject commit d915fc93499fd925ae301306a7539b5f13bf6e65
index 916113b5333ba43df66a3cfc1535ee67e79cc9e9..0a314e2ec1853385e7d85421648eef44616bf6e3 100644 (file)
@@ -36,7 +36,7 @@ else()
     # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t
     # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
     set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread
-        smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
+        spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
     set(fragments linker.lf ld/esp32_fragments.lf)
 
     idf_component_register(SRCS "${srcs}"
index 40888f5a53c7a9148779e62ed016657828593de2..0699bf70ca0925c65d9efa419936706c21df67e0 100644 (file)
@@ -33,6 +33,7 @@
 #include "esp_intr_alloc.h"
 #include "esp_attr.h"
 #include "esp_log.h"
+#include "esp_event.h"
 #include "esp_heap_caps.h"
 #include "esp_private/wifi_os_adapter.h"
 #include "esp_private/wifi.h"
@@ -46,7 +47,6 @@
 #include "nvs.h"
 #include "os.h"
 #include "esp_smartconfig.h"
-#include "smartconfig_ack.h"
 #include "esp_coexist_internal.h"
 #include "esp_coexist_adapter.h"
 
@@ -373,6 +373,15 @@ static int32_t task_get_max_priority_wrapper(void)
     return (int32_t)(configMAX_PRIORITIES);
 }
 
+static int32_t esp_event_post_wrapper(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait)
+{
+    if (ticks_to_wait == OSI_FUNCS_TIME_BLOCKING) {
+        return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, portMAX_DELAY);
+    } else {
+        return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, ticks_to_wait);
+    }
+}
+
 static void IRAM_ATTR timer_arm_wrapper(void *timer, uint32_t tmout, bool repeat)
 {
     ets_timer_arm(timer, tmout, repeat);
@@ -427,11 +436,6 @@ static void * IRAM_ATTR zalloc_internal_wrapper(size_t size)
     return ptr;
 }
 
-static void sc_ack_send_wrapper(void *param)
-{
-    return sc_ack_send((sc_ack_t *)param);
-}
-
 static uint32_t coex_status_get_wrapper(void)
 {
 #if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE
@@ -544,6 +548,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._task_get_max_priority = task_get_max_priority_wrapper,
     ._malloc = malloc,
     ._free = free,
+    ._event_post = esp_event_post_wrapper,
     ._get_free_heap_size = esp_get_free_heap_size,
     ._rand = esp_random,
     ._dport_access_stall_other_cpu_start_wrap = esp_dport_access_stall_other_cpu_start_wrap,
@@ -590,8 +595,6 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._modem_sleep_exit = esp_modem_sleep_exit,
     ._modem_sleep_register = esp_modem_sleep_register,
     ._modem_sleep_deregister = esp_modem_sleep_deregister,
-    ._sc_ack_send = sc_ack_send_wrapper,
-    ._sc_ack_send_stop = sc_ack_send_stop,
     ._coex_status_get = coex_status_get_wrapper,
     ._coex_wifi_request = coex_wifi_request_wrapper,
     ._coex_wifi_release = coex_wifi_release_wrapper,
index 5c17f8679421c93d3efbdf06791ceb579418d527..7f41a8409ef245d9dcfcf6dc5991a7c8a9a688df 100644 (file)
@@ -8,6 +8,11 @@ if(CONFIG_IDF_TARGET_ESP32)
     list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c")
 endif()
 
+if(CONFIG_ETH_SPI_ETHERNET_DM9051)
+    list(APPEND esp_eth_srcs "src/esp_eth_mac_dm9051.c"
+                             "src/esp_eth_phy_dm9051.c")
+endif()
+
 idf_component_register(SRCS "${esp_eth_srcs}"
                        INCLUDE_DIRS "include"
                        LDFRAGMENTS "linker.lf"
index 275e0d75ea226287c44d07fa80bf6e26be80952a..40e7ee36dc218cd2dd4e1dcc9da07ac76bce366a 100644 (file)
@@ -2,7 +2,7 @@ menu "Ethernet"
 
     menuconfig ETH_USE_ESP32_EMAC
         depends on IDF_TARGET_ESP32
-        bool "Use ESP32 internal EMAC controller"
+        bool "Support ESP32 internal EMAC controller"
         default y
         help
             ESP32 integrates a 10/100M Ethernet MAC controller.
@@ -128,4 +128,29 @@ menu "Ethernet"
                 Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE.
                 Larger number of buffers could increase throughput somehow.
     endif
+
+    menuconfig ETH_USE_SPI_ETHERNET
+        bool "Support SPI to Ethernet Module"
+        default y
+        help
+            ESP-IDF can also support some SPI-Ethernet module.
+
+    if ETH_USE_SPI_ETHERNET
+        menuconfig ETH_SPI_ETHERNET_DM9051
+            bool "Use DM9051"
+            default y
+            help
+                DM9051 is a fast Ethernet controller with an SPI interface.
+                It's also integrated with a 10/100M PHY and MAC.
+                Set true to enable DM9051 driver.
+
+        if ETH_SPI_ETHERNET_DM9051
+            config ETH_DM9051_INT_GPIO
+                int "DM9051 Interrupt GPIO number"
+                default 4
+                range 0 33
+                help
+                    Set the GPIO number used by DM9051's Interrupt pin.
+        endif
+    endif
 endmenu
index 3f029019228d84c81839344ef3b163f802e35c49..2a5ba23b388329b8fc23c22ed108730d817c0fac 100644 (file)
@@ -8,3 +8,7 @@ COMPONENT_ADD_LDFRAGMENTS += linker.lf
 ifndef CONFIG_IDF_TARGET_ESP32
     COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o
 endif
+
+ifndef CONFIG_ETH_SPI_ETHERNET_DM9051
+    COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o
+endif
index 3c3bd7032a43a9d174cf25cac3ae502a086ad93d..07507cefed357ac2387cd82b414dff335160a96b 100644 (file)
@@ -20,6 +20,11 @@ extern "C" {
 #include <stdbool.h>
 #include "esp_eth_com.h"
 #include "sdkconfig.h"
+#if CONFIG_ETH_USE_SPI_ETHERNET
+#include "driver/gpio.h"
+#include "driver/spi_master.h"
+#endif
+
 
 /**
 * @brief Ethernet MAC
@@ -115,6 +120,7 @@ struct esp_eth_mac_s {
     *      - ESP_OK: read PHY register successfully
     *      - ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument
     *      - ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC
+    *      - ESP_ERR_TIMEOUT: read PHY register failed because of timeout
     *      - ESP_FAIL: read PHY register failed because some other error occurred
     *
     */
@@ -131,6 +137,7 @@ struct esp_eth_mac_s {
     * @return
     *      - ESP_OK: write PHY register successfully
     *      - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC
+    *      - ESP_ERR_TIMEOUT: write PHY register failed because of timeout
     *      - ESP_FAIL: write PHY register failed because some other error occurred
     *
     */
@@ -241,6 +248,10 @@ typedef struct {
     uint32_t rx_task_stack_size;  /*!< Stack size of the receive task */
     uint32_t rx_task_prio;        /*!< Priority of the receive task */
     uint32_t queue_len;           /*!< Length of the transaction queue */
+#if CONFIG_ETH_USE_SPI_ETHERNET
+    spi_device_handle_t spi_hdl;  /*!< Handle of spi device */
+#endif
+
 } eth_mac_config_t;
 
 /**
@@ -255,6 +266,7 @@ typedef struct {
         .queue_len = 100,           \
     }
 
+#if CONFIG_ETH_USE_ESP32_EMAC
 /**
 * @brief Create ESP32 Ethernet MAC instance
 *
@@ -265,7 +277,20 @@ typedef struct {
 *      - NULL: create MAC instance failed because some error occurred
 */
 esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
+#endif
 
+#if CONFIG_ETH_SPI_ETHERNET_DM9051
+/**
+* @brief Create DM9051 Ethernet MAC instance
+*
+* @param config: Ethernet MAC configuration
+*
+* @return
+*      - instance: create MAC instance successfully
+*      - NULL: create MAC instance failed because some error occurred
+*/
+esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config);
+#endif
 #ifdef __cplusplus
 }
 #endif
index 9d29b314945cd8f041f8d50d01e7582460014fdf..b30fdad5ddb8cb027fd5904d86ad8975da33c89f 100644 (file)
@@ -222,6 +222,18 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config);
 */
 esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
 
+#if CONFIG_ETH_SPI_ETHERNET_DM9051
+/**
+* @brief Create a PHY instance of DM9051
+*
+* @param[in] config: configuration of PHY
+*
+* @return
+*      - instance: create PHY instance successfully
+*      - NULL: create PHY instance failed because some error occurred
+*/
+esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config);
+#endif
 #ifdef __cplusplus
 }
 #endif
index e8ec8886ccbfa8873f748e5fcdfe1da459925ec7..69f864d8d6850911b8fe3639b78d5d99cf8c848c 100644 (file)
@@ -1,8 +1,11 @@
 [mapping:esp_eth]
 archive: libesp_eth.a
 entries:
+  if ETH_USE_ESP32_EMAC = y:
     esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text)
     esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text)
     esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text)
     esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text)
     esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text)
+  if ETH_SPI_ETHERNET_DM9051 = y:
+    esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text)
diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c
new file mode 100644 (file)
index 0000000..b76c5a4
--- /dev/null
@@ -0,0 +1,852 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include "driver/gpio.h"
+#include "driver/spi_master.h"
+#include "esp_log.h"
+#include "esp_eth.h"
+#include "esp_system.h"
+#include "esp_intr_alloc.h"
+#include "esp_heap_caps.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "sdkconfig.h"
+
+static const char *TAG = "emac_dm9051";
+#define MAC_CHECK(a, str, goto_tag, ret_value, ...)                               \
+    do                                                                            \
+    {                                                                             \
+        if (!(a))                                                                 \
+        {                                                                         \
+            ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+            ret = ret_value;                                                      \
+            goto goto_tag;                                                        \
+        }                                                                         \
+    } while (0)
+
+#define RX_QUEUE_WAIT_MS (100)
+#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
+#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
+
+/**
+ * @brief Registers in DM9051
+ *
+ */
+#define DM9051_NCR (0x00)     // Network Control Register
+#define DM9051_NSR (0x01)     // Network Status Register
+#define DM9051_TCR (0x02)     // Tx Control Register
+#define DM9051_TSR1 (0x03)    // Tx Status Register I
+#define DM9051_TSR2 (0x04)    // Tx Status Register II
+#define DM9051_RCR (0x05)     // Rx Control Register
+#define DM9051_RSR (0x06)     // Rx Status Register
+#define DM9051_ROCR (0x07)    // Receive Overflow Counter Register
+#define DM9051_BPTR (0x08)    // Back Pressure Threshold Register
+#define DM9051_FCTR (0x09)    // Flow Control Threshold Register
+#define DM9051_FCR (0x0A)     // Rx/Tx Flow Control Register
+#define DM9051_EPCR (0x0B)    // EEPROM & PHY Control Register
+#define DM9051_EPAR (0x0C)    // EEPROM & PHY Address Register
+#define DM9051_EPDRL (0x0D)   // EEPROM & PHY Data Register Low
+#define DM9051_EPDRH (0x0E)   // EEPROM & PHY Data Register High
+#define DM9051_WCR (0x0F)     // Wake Up Control Register
+#define DM9051_PAR (0x10)     // Physical Address Register
+#define DM9051_MAR (0x16)     // Multicast Address Hash Table Register
+#define DM9051_GPCR (0x1E)    // General Purpose Control Register
+#define DM9051_GPR (0x1F)     // General Purpose Register
+#define DM9051_TRPAL (0x22)   // Tx Memory Read Pointer Address Low Byte
+#define DM9051_TRPAH (0x23)   // Tx Memory Read Pointer Address High Byte
+#define DM9051_RWPAL (0x24)   // Rx Memory Read Pointer Address Low Byte
+#define DM9051_RWPAH (0x25)   // Rx Memory Read Pointer Address High Byte
+#define DM9051_VIDL (0x28)    // Vendor ID Low Byte
+#define DM9051_VIDH (0x29)    // Vendor ID High Byte
+#define DM9051_PIDL (0x2A)    // Product ID Low Byte
+#define DM9051_PIDH (0x2B)    // Product ID High Byte
+#define DM9051_CHIPR (0x2C)   // CHIP Revision
+#define DM9051_TCR2 (0x2D)    // Transmit Control Register 2
+#define DM9051_ATCR (0x30)    // Auto-Transmit Control Register
+#define DM9051_TCSCR (0x31)   // Transmit Check Sum Control Register
+#define DM9051_RCSCSR (0x32)  // Receive Check Sum Control Status Register
+#define DM9051_SBCR (0x38)    // SPI Bus Control Register
+#define DM9051_INTCR (0x39)   // INT Pin Control Register
+#define DM9051_PPCSR (0x3D)   // Pause Packet Control Status Register
+#define DM9051_EEE_IN (0x3E)  // IEEE 802.3az Enter Counter Register
+#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register
+#define DM9051_ALNCR (0x4A)   // SPI Byte Align Error Counter Register
+#define DM9051_RLENCR (0x52)  // Rx Packet Length Control Register
+#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register
+#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register
+#define DM9051_MPTRCR (0x55)  // Memory Pointer Control Register
+#define DM9051_MLEDCR (0x57)  // More LED Control Register
+#define DM9051_MEMSCR (0x59)  // Memory Control Register
+#define DM9051_TMEMR (0x5A)   // Transmit Memory Size Register
+#define DM9051_MBSR (0x5D)    // Memory BIST Status Register
+#define DM9051_MRCMDX (0x70)  // Memory Data Pre-Fetch Read Command Without Address Increment Register
+#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register
+#define DM9051_MRCMD (0x72)   // Memory Data Read Command With Address Increment Register
+#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register
+#define DM9051_MRRL (0x74)    // Memory Data Read Address Register Low Byte
+#define DM9051_MRRH (0x75)    // Memory Data Read Address Register High Byte
+#define DM9051_MWCMDX (0x76)  // Memory Data Write Command Without Address Increment Register
+#define DM9051_MWCMD (0x78)   // Memory Data Write Command With Address Increment Register
+#define DM9051_MWRL (0x7A)    // Memory Data Write Address Register Low Byte
+#define DM9051_MWRH (0x7B)    // Memory Data Write Address Register High Byte
+#define DM9051_TXPLL (0x7C)   // TX Packet Length Low Byte Register
+#define DM9051_TXPLH (0x7D)   // TX Packet Length High Byte Register
+#define DM9051_ISR (0x7E)     // Interrupt Status Register
+#define DM9051_IMR (0x7F)     // Interrupt Mask Register
+
+/**
+ * @brief status and flag of DM9051 specific registers
+ *
+ */
+#define DM9051_SPI_RD (0) // Burst Read Command
+#define DM9051_SPI_WR (1) // Burst Write Command
+
+#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function
+#define NCR_FDX (1 << 3)    // Duplex Mode of the Internal PHY
+#define NCR_RST (1 << 0)    // Software Reset and Auto-Clear after 10us
+
+#define NSR_SPEED (1 << 7)  // Speed of Internal PHY
+#define NSR_LINKST (1 << 6) // Link Status of Internal PHY
+#define NSR_WAKEST (1 << 5) // Wakeup Event Status
+#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status
+#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status
+#define NSR_RXOV (1 << 1)   // RX Memory Overflow Status
+#define NSR_RXRDY (1 << 0)  // RX Packet Ready
+
+#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely
+
+#define RCR_WTDIS (1 << 6)    // Watchdog Timer Disable
+#define RCR_DIS_LONG (1 << 5) // Discard Long Packet
+#define RCR_DIS_CRC (1 << 4)  // Discard CRC Error Packet
+#define RCR_ALL (1 << 3)      // Receive All Multicast
+#define RCR_RUNT (1 << 2)     // Receive Runt Packet
+#define RCR_PRMSC (1 << 1)    // Promiscuous Mode
+#define RCR_RXEN (1 << 0)     // RX Enable
+
+#define RSR_RF (1 << 7)   // Runt Frame
+#define RSR_MF (1 << 6)   // Multicast Frame
+#define RSR_LCS (1 << 5)  // Late Collision Seen
+#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out
+#define RSR_PLE (1 << 3)  // Physical Layer Error
+#define RSR_AE (1 << 2)   //  Alignment Error
+#define RSR_CE (1 << 1)   // CRC Error
+#define RSR_FOE (1 << 0)  // RX Memory Overflow Error
+
+#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control
+
+#define EPCR_REEP (1 << 5)  // Reload EEPROM
+#define EPCR_WEP (1 << 4)   // Write EEPROM Enable
+#define EPCR_EPOS (1 << 3)  // EEPROM or PHY Operation Select
+#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command
+#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command
+#define EPCR_ERRE (1 << 0)  // EEPROM Access Status or PHY Access Status
+
+#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet
+
+#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control
+
+#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation
+#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation
+#define TCSCR_IPCSE (1 << 0)  // IPv4 CheckSum Generation
+
+#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer
+#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer
+
+#define ISR_LNKCHGS (1 << 5) // Link Status Change
+#define ISR_ROO (1 << 3)     // Receive Overflow Counter Overflow
+#define ISR_ROS (1 << 2)     // Receive Overflow
+#define ISR_PT (1 << 1)      // Packet Transmitted
+#define ISR_PR (1 << 0)      // Packet Received
+#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR)
+
+#define IMR_PAR (1 << 7)     // Pointer Auto-Return Mode
+#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt
+#define IMR_ROOI (1 << 3)    // Enable Receive Overflow Counter Overflow Interrupt
+#define IMR_ROI (1 << 2)     // Enable Receive Overflow Interrupt
+#define IMR_PTI (1 << 1)     // Enable Packet Transmitted Interrupt
+#define IMR_PRI (1 << 0)     // Enable Packet Received Interrupt
+#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI)
+
+typedef struct {
+    uint8_t flag;
+    uint8_t status;
+    uint8_t length_low;
+    uint8_t length_high;
+} dm9051_rx_header_t;
+
+typedef struct {
+    esp_eth_mac_t parent;
+    esp_eth_mediator_t *eth;
+    spi_device_handle_t spi_hdl;
+    SemaphoreHandle_t spi_lock;
+    TaskHandle_t rx_task_hdl;
+    uint32_t sw_reset_timeout_ms;
+    uint8_t addr[6];
+    bool packets_remain;
+} emac_dm9051_t;
+
+static inline bool dm9051_lock(emac_dm9051_t *emac)
+{
+    return xSemaphoreTake(emac->spi_lock, DM9051_SPI_LOCK_TIMEOUT_MS) == pdTRUE;
+}
+
+static inline bool dm9051_unlock(emac_dm9051_t *emac)
+{
+    return xSemaphoreGive(emac->spi_lock) == pdTRUE;
+}
+
+/**
+ * @brief write value to dm9051 internal register
+ */
+static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value)
+{
+    esp_err_t ret = ESP_OK;
+    spi_transaction_t trans = {
+        .cmd = DM9051_SPI_WR,
+        .addr = reg_addr,
+        .length = 8,
+        .flags = SPI_TRANS_USE_TXDATA
+    };
+    trans.tx_data[0] = value;
+    if (dm9051_lock(emac)) {
+        if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
+            ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
+            ret = ESP_FAIL;
+        }
+        dm9051_unlock(emac);
+    } else {
+        ret = ESP_ERR_TIMEOUT;
+    }
+    return ret;
+}
+
+/**
+ * @brief read value from dm9051 internal register
+ */
+static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value)
+{
+    esp_err_t ret = ESP_OK;
+    spi_transaction_t trans = {
+        .cmd = DM9051_SPI_RD,
+        .addr = reg_addr,
+        .length = 8,
+        .flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA
+    };
+    if (dm9051_lock(emac)) {
+        if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
+            ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
+            ret = ESP_FAIL;
+        } else {
+            *value = trans.rx_data[0];
+        }
+        dm9051_unlock(emac);
+    } else {
+        ret = ESP_ERR_TIMEOUT;
+    }
+    return ret;
+}
+
+/**
+ * @brief write buffer to dm9051 internal memory
+ */
+static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
+{
+    esp_err_t ret = ESP_OK;
+    spi_transaction_t trans = {
+        .cmd = DM9051_SPI_WR,
+        .addr = DM9051_MWCMD,
+        .length = len * 8,
+        .tx_buffer = buffer
+    };
+    if (dm9051_lock(emac)) {
+        if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
+            ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
+            ret = ESP_FAIL;
+        }
+        dm9051_unlock(emac);
+    } else {
+        ret = ESP_ERR_TIMEOUT;
+    }
+    return ret;
+}
+
+/**
+ * @brief read buffer from dm9051 internal memory
+ */
+static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
+{
+    esp_err_t ret = ESP_OK;
+    spi_transaction_t trans = {
+        .cmd = DM9051_SPI_RD,
+        .addr = DM9051_MRCMD,
+        .length = len * 8,
+        .rx_buffer = buffer
+    };
+    if (dm9051_lock(emac)) {
+        if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
+            ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
+            ret = ESP_FAIL;
+        }
+        dm9051_unlock(emac);
+    } else {
+        ret = ESP_ERR_TIMEOUT;
+    }
+    return ret;
+}
+
+/**
+ * @brief read mac address from internal registers
+ */
+static esp_err_t dm9051_get_mac_addr(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    for (int i = 0; i < 6; i++) {
+        MAC_CHECK(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]) == ESP_OK, "read PAR failed", err, ESP_FAIL);
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief set new mac address to internal registers
+ */
+static esp_err_t dm9051_set_mac_addr(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    for (int i = 0; i < 6; i++) {
+        MAC_CHECK(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]) == ESP_OK, "write PAR failed", err, ESP_FAIL);
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief clear multicast hash table
+ */
+static esp_err_t dm9051_clear_multicast_table(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    /* rx broadcast packet control by bit7 of MAC register 1DH */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_BCASTCR, 0x00) == ESP_OK, "write BCASTCR failed", err, ESP_FAIL);
+    for (int i = 0; i < 7; i++) {
+        MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + i, 0x00) == ESP_OK, "write MAR failed", err, ESP_FAIL);
+    }
+    /* enable receive broadcast paclets */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + 7, 0x80) == ESP_OK, "write MAR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief software reset dm9051 internal register
+ */
+static esp_err_t dm9051_reset(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    /* power on phy */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_GPR, 0x00) == ESP_OK, "write GPR failed", err, ESP_FAIL);
+    /* mac and phy register won't be accesable within at least 1ms */
+    vTaskDelay(pdMS_TO_TICKS(10));
+    /* software reset */
+    uint8_t ncr = NCR_RST;
+    MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, ncr) == ESP_OK, "write NCR failed", err, ESP_FAIL);
+    uint32_t to = 0;
+    for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
+        MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
+        if (!(ncr & NCR_RST)) {
+            break;
+        }
+        vTaskDelay(pdMS_TO_TICKS(10));
+    }
+    MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief verify dm9051 chip ID
+ */
+static esp_err_t dm9051_verify_id(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    uint8_t id[2];
+    MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL);
+    MAC_CHECK(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION);
+    MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL);
+    MAC_CHECK(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief default setup for dm9051 internal registers
+ */
+static esp_err_t dm9051_setup_default(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    /* disable wakeup */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, 0x00) == ESP_OK, "write NCR failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_WCR, 0x00) == ESP_OK, "write WCR failed", err, ESP_FAIL);
+    /* stop transmitting, enable appending pad, crc for packets */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, 0x00) == ESP_OK, "write TCR failed", err, ESP_FAIL);
+    /* stop receiving, no promiscuous mode, no runt packet(size < 64bytes), not all multicast packets*/
+    /* discard long packet(size > 1522bytes) and crc error packet, enable watchdog */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC) == ESP_OK, "write RCR failed", err, ESP_FAIL);
+    /* send jam pattern (duration time = 1.15ms) when rx free space < 3k bytes */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_BPTR, 0x3F) == ESP_OK, "write BPTR failed", err, ESP_FAIL);
+    /* flow control: high water threshold = 3k bytes, low water threshold = 8k bytes */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_FCTR, 0x38) == ESP_OK, "write FCTR failed", err, ESP_FAIL);
+    /* enable flow control */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE) == ESP_OK, "write FCR failed", err, ESP_FAIL);
+    /* retry late collision packet, at most two transmit command can be issued before transmit complete */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP) == ESP_OK, "write TCR2 failed", err, ESP_FAIL);
+    /* enable auto transmit */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX) == ESP_OK, "write ATCR failed", err, ESP_FAIL);
+    /* generate checksum for UDP, TCP and IPv4 packets */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE) == ESP_OK,
+              "write TCSCR failed", err, ESP_FAIL);
+    /* disable check sum for receive packets */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RCSCSR, 0x00) == ESP_OK, "write RCSCSR failed", err, ESP_FAIL);
+    /* interrupt pin config: push-pull output, active high */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_INTCR, 0x00) == ESP_OK, "write INTCR failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_INTCKCR, 0x00) == ESP_OK, "write INTCKCR failed", err, ESP_FAIL);
+    /* no length limitation for rx packets */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RLENCR, 0x00) == ESP_OK, "write RLENCR failed", err, ESP_FAIL);
+    /* 3K-byte for TX and 13K-byte for RX */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_MEMSCR, 0x00) == ESP_OK, "write MEMSCR failed", err, ESP_FAIL);
+    /* reset tx and rx memory pointer */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX) == ESP_OK,
+              "write MPTRCR failed", err, ESP_FAIL);
+    /* clear network status: wakeup event, tx complete */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END) == ESP_OK, "write NSR failed", err, ESP_FAIL);
+    /* clear interrupt status */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS) == ESP_OK, "write ISR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief start dm9051: enable interrupt and start receive
+ */
+static esp_err_t dm9051_start(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    /* enable interrupt */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, IMR_ALL) == ESP_OK, "write IMR failed", err, ESP_FAIL);
+    /* enable rx */
+    uint8_t rcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
+    rcr |= RCR_RXEN;
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+/**
+ * @brief stop dm9051: disable interrupt and stop receive
+ */
+static esp_err_t dm9051_stop(emac_dm9051_t *emac)
+{
+    esp_err_t ret = ESP_OK;
+    /* disable interrupt */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, 0x00) == ESP_OK, "write IMR failed", err, ESP_FAIL);
+    /* disable rx */
+    uint8_t rcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
+    rcr &= ~RCR_RXEN;
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static void dm9051_isr_handler(void *arg)
+{
+    emac_dm9051_t *emac = (emac_dm9051_t *)arg;
+    BaseType_t high_task_wakeup = pdFALSE;
+    /* notify dm9051 task */
+    vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
+    if (high_task_wakeup != pdFALSE) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+static void emac_dm9051_task(void *arg)
+{
+    emac_dm9051_t *emac = (emac_dm9051_t *)arg;
+    uint8_t status = 0;
+    uint8_t *buffer = NULL;
+    uint32_t length = 0;
+    while (1) {
+        if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
+            /* clear interrupt status */
+            dm9051_register_read(emac, DM9051_ISR, &status);
+            dm9051_register_write(emac, DM9051_ISR, status);
+            /* packet received */
+            if (status & ISR_PR) {
+                do {
+                    buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA);
+                    if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
+                        /* pass the buffer to stack (e.g. TCP/IP layer) */
+                        emac->eth->stack_input(emac->eth, buffer, length);
+                    } else {
+                        free(buffer);
+                    }
+                } while (emac->packets_remain);
+            }
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+static esp_err_t emac_dm9051_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
+{
+    esp_err_t ret = ESP_OK;
+    MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    emac->eth = eth;
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    /* check if phy access is in progress */
+    uint8_t epcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
+    MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_INVALID_STATE);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
+              "write EPAR failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)) == ESP_OK,
+              "write EPDRL failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)) == ESP_OK,
+              "write EPDRH failed", err, ESP_FAIL);
+    /* select PHY and select write operation */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
+    /* polling the busy flag */
+    uint32_t to = 0;
+    do {
+        ets_delay_us(100);
+        MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
+        to += 100;
+    } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
+    MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
+{
+    esp_err_t ret = ESP_OK;
+    MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    /* check if phy access is in progress */
+    uint8_t epcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
+    MAC_CHECK(!(epcr & 0x01), "phy is busy", err, ESP_ERR_INVALID_STATE);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
+              "write EPAR failed", err, ESP_FAIL);
+    /* Select PHY and select read operation */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, 0x0C) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
+    /* polling the busy flag */
+    uint32_t to = 0;
+    do {
+        ets_delay_us(100);
+        MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
+        to += 100;
+    } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
+    MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
+    uint8_t value_h = 0;
+    uint8_t value_l = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRH, &value_h) == ESP_OK, "read EPDRH failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &value_l) == ESP_OK, "read EPDRL failed", err, ESP_FAIL);
+    *reg_value = (value_h << 8) | value_l;
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
+{
+    esp_err_t ret = ESP_OK;
+    MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    memcpy(emac->addr, addr, 6);
+    MAC_CHECK(dm9051_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
+{
+    esp_err_t ret = ESP_OK;
+    MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    memcpy(addr, emac->addr, 6);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_set_link(esp_eth_mac_t *mac, eth_link_t link)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    uint8_t nsr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
+    switch (link) {
+    case ETH_LINK_UP:
+        MAC_CHECK(nsr & NSR_LINKST, "phy is not link up", err, ESP_ERR_INVALID_STATE);
+        MAC_CHECK(dm9051_start(emac) == ESP_OK, "dm9051 start failed", err, ESP_FAIL);
+        break;
+    case ETH_LINK_DOWN:
+        MAC_CHECK(!(nsr & NSR_LINKST), "phy is not link down", err, ESP_ERR_INVALID_STATE);
+        MAC_CHECK(dm9051_stop(emac) == ESP_OK, "dm9051 stop failed", err, ESP_FAIL);
+        break;
+    default:
+        MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
+        break;
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    uint8_t nsr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
+    switch (speed) {
+    case ETH_SPEED_10M:
+        MAC_CHECK(nsr & NSR_SPEED, "phy speed is not at 10Mbps", err, ESP_ERR_INVALID_STATE);
+        break;
+    case ETH_SPEED_100M:
+        MAC_CHECK(!(nsr & NSR_SPEED), "phy speed is not at 100Mbps", err, ESP_ERR_INVALID_STATE);
+        break;
+    default:
+        MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
+        break;
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    uint8_t ncr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
+    switch (duplex) {
+    case ETH_DUPLEX_HALF:
+        MAC_CHECK(!(ncr & NCR_FDX), "phy is not at half duplex", err, ESP_ERR_INVALID_STATE);
+        break;
+    case ETH_DUPLEX_FULL:
+        MAC_CHECK(ncr & NCR_FDX, "phy is not at full duplex", err, ESP_ERR_INVALID_STATE);
+        break;
+    default:
+        MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
+        break;
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_set_promiscuous(esp_eth_mac_t *mac, bool enable)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    uint8_t rcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
+    if (enable) {
+        rcr |= RCR_PRMSC;
+    } else {
+        rcr &= ~RCR_PRMSC;
+    }
+    MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG);
+    MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG);
+    /* Check if last transmit complete */
+    uint8_t tcr = 0;
+    MAC_CHECK(dm9051_register_read(emac, DM9051_TCR, &tcr) == ESP_OK, "read TCR failed", err, ESP_FAIL);
+    MAC_CHECK(!(tcr & TCR_TXREQ), "last transmit still in progress", err, ESP_ERR_INVALID_STATE);
+    /* set tx length */
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF) == ESP_OK, "write TXPLL failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF) == ESP_OK, "write TXPLH failed", err, ESP_FAIL);
+    /* copy data to tx memory */
+    MAC_CHECK(dm9051_memory_write(emac, buf, length) == ESP_OK, "write memory failed", err, ESP_FAIL);
+    /* issue tx polling command */
+    tcr |= TCR_TXREQ;
+    MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, tcr) == ESP_OK, "write TCR failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
+    uint8_t rxbyte = 0;
+    uint16_t rx_len = 0;
+    __attribute__((aligned(4))) dm9051_rx_header_t header; // SPI driver needs the rx buffer 4 byte align
+    emac->packets_remain = false;
+    /* dummy read, get the most updated data */
+    MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
+    MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
+    /* rxbyte must be 0xFF, 0 or 1 */
+    if (rxbyte > 1) {
+        MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL);
+        /* reset rx fifo pointer */
+        MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL);
+        ets_delay_us(10);
+        MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL);
+        MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL);
+    } else if (rxbyte) {
+        MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL);
+        rx_len = header.length_low + (header.length_high << 8);
+        MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL);
+        MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status);
+        *length = rx_len - 4; // substract the CRC length (4Bytes)
+        /* dummy read, get the most updated data */
+        MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
+        MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
+        emac->packets_remain = rxbyte > 0;
+    }
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac)
+{
+    esp_err_t ret = ESP_OK;
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    esp_eth_mediator_t *eth = emac->eth;
+    /* init gpio used by spi-ethernet interrupt */
+    gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO);
+    gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT);
+    gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY);
+    gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE);
+    gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO);
+    gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac);
+    MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
+    /* reset dm9051 */
+    MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL);
+    /* verify chip id */
+    MAC_CHECK(dm9051_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL);
+    /* default setup of internal registers */
+    MAC_CHECK(dm9051_setup_default(emac) == ESP_OK, "dm9051 default setup failed", err, ESP_FAIL);
+    /* clear multicast hash table */
+    MAC_CHECK(dm9051_clear_multicast_table(emac) == ESP_OK, "clear multicast table failed", err, ESP_FAIL);
+    /* get emac address from eeprom */
+    MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
+    return ESP_OK;
+err:
+    gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
+    gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
+    eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
+    return ret;
+}
+
+static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac)
+{
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    esp_eth_mediator_t *eth = emac->eth;
+    dm9051_stop(emac);
+    gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
+    gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
+    eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
+    return ESP_OK;
+}
+
+static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
+{
+    emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
+    vTaskDelete(emac->rx_task_hdl);
+    vSemaphoreDelete(emac->spi_lock);
+    free(emac);
+    return ESP_OK;
+}
+
+esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config)
+{
+    esp_eth_mac_t *ret = NULL;
+    MAC_CHECK(config, "can't set mac config to null", err, NULL);
+    MAC_CHECK(config->spi_hdl, "can't set spi handle to null", err, NULL);
+    emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t));
+    MAC_CHECK(emac, "calloc emac failed", err, NULL);
+    /* bind methods and attributes */
+    emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
+    emac->spi_hdl = config->spi_hdl;
+    emac->parent.set_mediator = emac_dm9051_set_mediator;
+    emac->parent.init = emac_dm9051_init;
+    emac->parent.deinit = emac_dm9051_deinit;
+    emac->parent.del = emac_dm9051_del;
+    emac->parent.write_phy_reg = emac_dm9051_write_phy_reg;
+    emac->parent.read_phy_reg = emac_dm9051_read_phy_reg;
+    emac->parent.set_addr = emac_dm9051_set_addr;
+    emac->parent.get_addr = emac_dm9051_get_addr;
+    emac->parent.set_speed = emac_dm9051_set_speed;
+    emac->parent.set_duplex = emac_dm9051_set_duplex;
+    emac->parent.set_link = emac_dm9051_set_link;
+    emac->parent.set_promiscuous = emac_dm9051_set_promiscuous;
+    emac->parent.transmit = emac_dm9051_transmit;
+    emac->parent.receive = emac_dm9051_receive;
+    /* create mutex */
+    emac->spi_lock = xSemaphoreCreateMutex();
+    MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL);
+    /* create dm9051 task */
+    BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", config->rx_task_stack_size, emac,
+                                       config->rx_task_prio, &emac->rx_task_hdl);
+    MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL);
+    return &(emac->parent);
+err_tsk:
+    vSemaphoreDelete(emac->spi_lock);
+err_lock:
+    free(emac);
+err:
+    return ret;
+}
index f68a16ac9eeb148abb6135974f0901f9375a5f4e..1c1fbcc90cb9203402575dd442e752fe8863bc15 100644 (file)
@@ -41,6 +41,7 @@ static const char *TAG = "emac_esp32";
     } while (0)
 
 #define RX_QUEUE_WAIT_MS (20)
+#define PHY_OPERATION_TIMEOUT_US (1000)
 
 typedef struct {
     esp_eth_mac_t parent;
@@ -49,12 +50,8 @@ typedef struct {
     intr_handle_t intr_hdl;
     SemaphoreHandle_t rx_counting_sem;
     TaskHandle_t rx_task_hdl;
-    const char *name;
     uint32_t sw_reset_timeout_ms;
     uint32_t frames_remain;
-    uint32_t rx_task_stack_size;
-    uint32_t rx_task_prio;
-    uint32_t queue_len;
     uint8_t addr[6];
     uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM];
     uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM];
@@ -78,9 +75,15 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
     MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
     emac_hal_set_phy_data(emac->hal, reg_value);
     emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, true);
-    /* Delay some time and Check for the Busy flag */
-    ets_delay_us(1000);
-    MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
+    /* polling the busy flag */
+    uint32_t to = 0;
+    bool busy = true;
+    do {
+        ets_delay_us(100);
+        busy = emac_hal_is_mii_busy(emac->hal);
+        to += 100;
+    } while (busy && to < PHY_OPERATION_TIMEOUT_US);
+    MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
     return ESP_OK;
 err:
     return ret;
@@ -93,9 +96,15 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
     emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
     MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
     emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, false);
-    /* Delay some time and Check for the Busy flag */
-    ets_delay_us(1000);
-    MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
+    /* polling the busy flag */
+    uint32_t to = 0;
+    bool busy = true;
+    do {
+        ets_delay_us(100);
+        busy = emac_hal_is_mii_busy(emac->hal);
+        to += 100;
+    } while (busy && to < PHY_OPERATION_TIMEOUT_US);
+    MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
     /* Store value */
     *reg_value = emac_hal_get_phy_data(emac->hal);
     return ESP_OK;
@@ -224,16 +233,14 @@ err:
 static void emac_esp32_rx_task(void *arg)
 {
     emac_esp32_t *emac = (emac_esp32_t *)arg;
-    esp_eth_mediator_t *eth = emac->eth;
     uint8_t *buffer = NULL;
     uint32_t length = 0;
-
     while (1) {
         if (xSemaphoreTake(emac->rx_counting_sem, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS)) == pdTRUE) {
             buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE);
             if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
                 /* pass the buffer to stack (e.g. TCP/IP layer) */
-                eth->stack_input(eth, buffer, length);
+                emac->eth->stack_input(emac->eth, buffer, length);
             } else {
                 free(buffer);
             }
@@ -298,50 +305,32 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
     MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
     /* set MAC address to emac register */
     emac_hal_set_address(emac->hal, emac->addr);
-    /* Interrupt configuration */
-    MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr,
-                             &emac->hal, &(emac->intr_hdl)) == ESP_OK,
-              "alloc emac interrupt failed", err, ESP_FAIL);
-    /* create counting semaphore */
-    emac->rx_counting_sem = xSemaphoreCreateCounting(emac->queue_len, 0);
-    MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, ESP_FAIL);
-    /* create rx task */
-    BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", emac->rx_task_stack_size, emac,
-                                       emac->rx_task_prio, &emac->rx_task_hdl);
-    MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, ESP_FAIL);
     return ESP_OK;
-err_task:
-    vSemaphoreDelete(emac->rx_counting_sem);
-err_sem:
-    esp_intr_free(emac->intr_hdl);
 err:
-    periph_module_disable(PERIPH_EMAC_MODULE);
     eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
+    periph_module_disable(PERIPH_EMAC_MODULE);
     return ret;
 }
 
 static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
 {
-    esp_err_t ret = ESP_OK;
     emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
     esp_eth_mediator_t *eth = emac->eth;
 #if CONFIG_ETH_PHY_USE_RST
     gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0);
 #endif
     emac_hal_stop(emac->hal);
-    MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL) == ESP_OK, "lowlevel deinit failed", err, ESP_FAIL);
-    MAC_CHECK(esp_intr_free(emac->intr_hdl) == ESP_OK, "free emac interrupt failed", err, ESP_FAIL);
-    vTaskDelete(emac->rx_task_hdl);
-    vSemaphoreDelete(emac->rx_counting_sem);
+    eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
     periph_module_disable(PERIPH_EMAC_MODULE);
     return ESP_OK;
-err:
-    return ret;
 }
 
 static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
 {
     emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
+    esp_intr_free(emac->intr_hdl);
+    vTaskDelete(emac->rx_task_hdl);
+    vSemaphoreDelete(emac->rx_counting_sem);
     int i = 0;
     for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
         free(emac->hal->rx_buf[i]);
@@ -400,10 +389,6 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
     /* initialize hal layer driver */
     emac_hal_init(emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
     emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
-    emac->rx_task_stack_size = config->rx_task_stack_size;
-    emac->rx_task_prio = config->rx_task_prio;
-    emac->queue_len = config->queue_len;
-    emac->name = "emac_esp32";
     emac->parent.set_mediator = emac_esp32_set_mediator;
     emac->parent.init = emac_esp32_init;
     emac->parent.deinit = emac_esp32_deinit;
@@ -418,7 +403,29 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
     emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
     emac->parent.transmit = emac_esp32_transmit;
     emac->parent.receive = emac_esp32_receive;
+    /* Interrupt configuration */
+    MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr,
+                             &emac->hal, &(emac->intr_hdl)) == ESP_OK,
+              "alloc emac interrupt failed", err_intr, NULL);
+    /* create counting semaphore */
+    emac->rx_counting_sem = xSemaphoreCreateCounting(config->queue_len, 0);
+    MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, NULL);
+    /* create rx task */
+    BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
+                                       config->rx_task_prio, &emac->rx_task_hdl);
+    MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL);
     return &(emac->parent);
+err_task:
+    vSemaphoreDelete(emac->rx_counting_sem);
+err_sem:
+    esp_intr_free(emac->intr_hdl);
+err_intr:
+    for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
+        free(emac->tx_buf[i]);
+    }
+    for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
+        free(emac->rx_buf[i]);
+    }
 err_buffer:
     free(emac->hal);
 err_hal:
diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c
new file mode 100644 (file)
index 0000000..cb658c1
--- /dev/null
@@ -0,0 +1,302 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include "esp_log.h"
+#include "esp_eth.h"
+#include "eth_phy_regs_struct.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+static const char *TAG = "dm9051";
+#define PHY_CHECK(a, str, goto_tag, ...)                                          \
+    do                                                                            \
+    {                                                                             \
+        if (!(a))                                                                 \
+        {                                                                         \
+            ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+            goto goto_tag;                                                        \
+        }                                                                         \
+    } while (0)
+
+/***************Vendor Specific Register***************/
+
+/**
+ * @brief DSCR(DAVICOM Specified Configuration Register)
+ *
+ */
+typedef union {
+    struct {
+        uint32_t reserved1 : 1; /* Reserved */
+        uint32_t sleep : 1;     /* Set 1 to enable PHY into sleep mode */
+        uint32_t mfpsc : 1;     /* MII frame preamble suppression control bit */
+        uint32_t smrst : 1;     /* Set 1 to reset all state machines of PHY */
+        uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */
+        uint32_t reserved2 : 2; /* Reserved */
+        uint32_t flink100 : 1;  /* Force Good Link in 100Mbps */
+        uint32_t reserved3 : 2; /* Reserved */
+        uint32_t tx_fx : 1;     /* 100BASE-TX or FX Mode Control */
+        uint32_t reserved4 : 1; /* Reserved */
+        uint32_t bp_adpok : 1;  /* BYPASS ADPOK */
+        uint32_t bp_align : 1;  /* Bypass Symbol Alignment Function */
+        uint32_t bp_scr : 1;    /* Bypass Scrambler/Descrambler Function */
+        uint32_t bp_4b5b : 1;   /* Bypass 4B5B Encoding and 5B4B Decoding */
+    };
+    uint32_t val;
+} dscr_reg_t;
+#define ETH_PHY_DSCR_REG_ADDR (0x10)
+
+/**
+ * @brief DSCSR(DAVICOM Specified Configuration and Status Register)
+ *
+ */
+typedef union {
+    struct {
+        uint32_t anmb : 4;     /* Auto-Negotiation Monitor Bits */
+        uint32_t phy_addr : 5; /* PHY Address */
+        uint32_t reserved : 3; /* Reserved */
+        uint32_t hdx10 : 1;    /* 10M Half-Duplex Operation Mode */
+        uint32_t fdx10 : 1;    /* 10M Full-Duplex Operation Mode */
+        uint32_t hdx100 : 1;   /* 100M Half-Duplex Operation Mode */
+        uint32_t fdx100 : 1;   /* 100M Full-Duplex Operation Mode */
+    };
+    uint32_t val;
+} dscsr_reg_t;
+#define ETH_PHY_DSCSR_REG_ADDR (0x11)
+
+typedef struct {
+    esp_eth_phy_t parent;
+    esp_eth_mediator_t *eth;
+    const char *name;
+    uint32_t addr;
+    uint32_t reset_timeout_ms;
+    uint32_t autonego_timeout_ms;
+    eth_link_t link_status;
+} phy_dm9051_t;
+
+static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
+{
+    PHY_CHECK(eth, "can't set mediator for dm9051 to null", err);
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    dm9051->eth = eth;
+    return ESP_OK;
+err:
+    return ESP_ERR_INVALID_ARG;
+}
+
+static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    esp_eth_mediator_t *eth = dm9051->eth;
+    bmsr_reg_t bmsr;
+
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
+    eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
+    if (dm9051->link_status != link) {
+        if (link == ETH_LINK_UP) {
+            phy->negotiate(phy);
+        } else {
+            PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
+            dm9051->link_status = link;
+        }
+    }
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    esp_eth_mediator_t *eth = dm9051->eth;
+    dscr_reg_t dscr;
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
+    dscr.smrst = 1;
+    PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err);
+    bmcr_reg_t bmcr = {.reset = 1};
+    PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
+    /* Wait for reset complete */
+    uint32_t to = 0;
+    for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) {
+        vTaskDelay(pdMS_TO_TICKS(10));
+        PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
+        PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
+        if (!bmcr.reset && !dscr.smrst) {
+            break;
+        }
+    }
+    PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err);
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    esp_eth_mediator_t *eth = dm9051->eth;
+    /* Start auto negotiation */
+    bmcr_reg_t bmcr = {
+        .speed_select = 1,     /* 100Mbps */
+        .duplex_mode = 1,      /* Full Duplex */
+        .en_auto_nego = 1,     /* Auto Negotiation */
+        .restart_auto_nego = 1 /* Restart Auto Negotiation */
+    };
+    PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
+    /* Wait for auto negotiation complete */
+    bmsr_reg_t bmsr;
+    dscsr_reg_t dscsr;
+    uint32_t to = 0;
+    for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) {
+        vTaskDelay(pdMS_TO_TICKS(10));
+        PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
+        PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err);
+        if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) {
+            break;
+        }
+    }
+    if (to >= dm9051->autonego_timeout_ms / 10) {
+        ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
+    }
+    /* Updata information about link, speed, duplex */
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err);
+    eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
+    eth_speed_t speed = ETH_SPEED_10M;
+    eth_duplex_t duplex = ETH_DUPLEX_HALF;
+    if (dscsr.fdx100 || dscsr.hdx100) {
+        speed = ETH_SPEED_100M;
+    } else {
+        speed = ETH_SPEED_10M;
+    }
+    if (dscsr.fdx100 || dscsr.fdx10) {
+        duplex = ETH_DUPLEX_FULL;
+    } else {
+        duplex = ETH_DUPLEX_HALF;
+    }
+    PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
+    PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
+    if (dm9051->link_status != link) {
+        PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
+        dm9051->link_status = link;
+    }
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    esp_eth_mediator_t *eth = dm9051->eth;
+    bmcr_reg_t bmcr;
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
+    if (!enable) {
+        /* Enable IEEE Power Down Mode */
+        bmcr.power_down = 1;
+    } else {
+        /* Disable IEEE Power Down Mode */
+        bmcr.power_down = 0;
+    }
+    PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
+    if (!enable) {
+        PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
+    } else {
+        PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
+    }
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    dm9051->addr = addr;
+    return ESP_OK;
+}
+
+static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
+{
+    PHY_CHECK(addr, "get phy address failed", err);
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    *addr = dm9051->addr;
+    return ESP_OK;
+err:
+    return ESP_ERR_INVALID_ARG;
+}
+
+static esp_err_t dm9051_del(esp_eth_phy_t *phy)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    free(dm9051);
+    return ESP_OK;
+}
+
+static esp_err_t dm9051_init(esp_eth_phy_t *phy)
+{
+    phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
+    esp_eth_mediator_t *eth = dm9051->eth;
+    /* Power on Ethernet PHY */
+    PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
+    /* Reset Ethernet PHY */
+    PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
+    /* Check PHY ID */
+    phyidr1_reg_t id1;
+    phyidr2_reg_t id2;
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
+    PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
+    PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err);
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+static esp_err_t dm9051_deinit(esp_eth_phy_t *phy)
+{
+    /* Power off Ethernet PHY */
+    PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
+    return ESP_OK;
+err:
+    return ESP_FAIL;
+}
+
+esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
+{
+    PHY_CHECK(config, "can't set phy config to null", err);
+    PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err);
+    phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
+    PHY_CHECK(dm9051, "calloc dm9051 object failed", err);
+    dm9051->name = "dm9051";
+    dm9051->addr = config->phy_addr;
+    dm9051->reset_timeout_ms = config->reset_timeout_ms;
+    dm9051->link_status = ETH_LINK_DOWN;
+    dm9051->autonego_timeout_ms = config->autonego_timeout_ms;
+    dm9051->parent.reset = dm9051_reset;
+    dm9051->parent.init = dm9051_init;
+    dm9051->parent.deinit = dm9051_deinit;
+    dm9051->parent.set_mediator = dm9051_set_mediator;
+    dm9051->parent.negotiate = dm9051_negotiate;
+    dm9051->parent.get_link = dm9051_get_link;
+    dm9051->parent.pwrctl = dm9051_pwrctl;
+    dm9051->parent.get_addr = dm9051_get_addr;
+    dm9051->parent.set_addr = dm9051_set_addr;
+    dm9051->parent.del = dm9051_del;
+
+    return &(dm9051->parent);
+err:
+    return NULL;
+}
index ac2d10a75c6110b33f5048aef0614807c866bf70..141bf3e1dab8bc5c89a2bb7622d29a46d3dbc718 100644 (file)
@@ -8,6 +8,7 @@
 #include "test_utils.h"
 #include "esp_eth.h"
 #include "esp_log.h"
+#include "sdkconfig.h"
 
 static const char *TAG = "esp_eth_test";
 /** Event handler for Ethernet events */
@@ -89,3 +90,48 @@ TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]")
     TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle));
     vTaskDelay(portMAX_DELAY);
 }
+
+#if CONFIG_ETH_USE_SPI_ETHERNET
+TEST_CASE("dm9051 io test", "[ethernet][ignore]")
+{
+    spi_device_handle_t spi_handle = NULL;
+    spi_bus_config_t buscfg = {
+        .miso_io_num = 25,
+        .mosi_io_num = 23,
+        .sclk_io_num = 19,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+    };
+    TEST_ESP_OK(spi_bus_initialize(HSPI_HOST, &buscfg, 1));
+    spi_device_interface_config_t devcfg = {
+        .command_bits = 1,
+        .address_bits = 7,
+        .mode = 0,
+        .clock_speed_hz = 20 * 1000 * 1000,
+        .spics_io_num = 22,
+        .queue_size = 20
+    };
+    TEST_ESP_OK(spi_bus_add_device(HSPI_HOST, &devcfg, &spi_handle));
+    gpio_install_isr_service(0);
+    tcpip_adapter_init();
+    TEST_ESP_OK(esp_event_loop_create_default());
+    TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers());
+    TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
+    TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
+    eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
+    mac_config.spi_hdl = spi_handle;
+    esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
+    eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
+    esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
+    esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
+    esp_eth_handle_t eth_handle = NULL;
+    TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle));
+    vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY));
+    TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
+    TEST_ESP_OK(phy->del(phy));
+    TEST_ESP_OK(mac->del(mac));
+    TEST_ESP_OK(esp_event_loop_delete_default());
+    TEST_ESP_OK(spi_bus_remove_device(spi_handle));
+    TEST_ESP_OK(spi_bus_free(HSPI_HOST));
+}
+#endif
index dd3e3d1d2dff3f6162eb1143aab1d7f278a4254e..469497f6999b442e87fd2f5e47fa6ab71601a9cf 100644 (file)
@@ -10,9 +10,10 @@ idf_component_register(SRCS "src/coexist.c"
                             "src/mesh_event.c"
                             "src/phy_init.c"
                             "src/restore.c"
+                            "src/smartconfig.c"
                             "src/wifi_init.c"
                     INCLUDE_DIRS "include" "${idf_target}/include"
-                    PRIV_REQUIRES wpa_supplicant nvs_flash
+                    PRIV_REQUIRES wpa_supplicant nvs_flash smartconfig_ack
                     LDFRAGMENTS "${ldfragments}")
 
 idf_build_get_property(build_dir BUILD_DIR)
index c8fbe90ed0bceeb47972283fb551dbcddc17d252..ee0654f8bf5d4d36c738a69985aad011fb9faa65 100644 (file)
@@ -36,6 +36,7 @@
 #include "esp_wifi_types.h"
 #include "esp_event.h"
 #include "esp_wifi.h"
+#include "esp_smartconfig.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -181,6 +182,34 @@ esp_err_t esp_wifi_internal_set_sta_ip(void);
   */
 esp_err_t esp_wifi_internal_set_fix_rate(wifi_interface_t ifx, bool en, wifi_phy_rate_t rate);
 
+/**
+  * @brief     Start SmartConfig, config ESP device to connect AP. You need to broadcast information by phone APP.
+  *            Device sniffer special packets from the air that containing SSID and password of target AP.
+  *
+  * @attention 1. This API can be called in station or softAP-station mode.
+  * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call
+  *               esp_smartconfig_stop first.
+  *
+  * @param     config pointer to smartconfig start configure structure
+  *
+  * @return
+  *     - ESP_OK: succeed
+  *     - others: fail
+  */
+esp_err_t esp_smartconfig_internal_start(const smartconfig_start_config_t *config);
+
+/**
+  * @brief     Stop SmartConfig, free the buffer taken by esp_smartconfig_start.
+  *
+  * @attention Whether connect to AP succeed or not, this API should be called to free
+  *            memory taken by smartconfig_start.
+  *
+  * @return
+  *     - ESP_OK: succeed
+  *     - others: fail
+  */
+esp_err_t esp_smartconfig_internal_stop(void);
+
 /**
   * @brief     Check the MD5 values of the OS adapter header files in IDF and WiFi library
   *
index 165caa6edc547a9008239663d0785b6e345fc65b..912ec3a5377b318504bd0104e6e066b2b9b61fbc 100644 (file)
@@ -21,7 +21,7 @@
 extern "C" {
 #endif
 
-#define ESP_WIFI_OS_ADAPTER_VERSION  0x00000002
+#define ESP_WIFI_OS_ADAPTER_VERSION  0x00000003
 #define ESP_WIFI_OS_ADAPTER_MAGIC    0xDEADBEAF
 
 #define OSI_FUNCS_TIME_BLOCKING      0xffffffff
@@ -72,6 +72,7 @@ typedef struct {
     int32_t (* _task_get_max_priority)(void);
     void *(* _malloc)(uint32_t size);
     void (* _free)(void *p);
+    int32_t (* _event_post)(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait);
     uint32_t (* _get_free_heap_size)(void);
     uint32_t (* _rand)(void);
     void (* _dport_access_stall_other_cpu_start_wrap)(void);
@@ -118,8 +119,6 @@ typedef struct {
     int32_t (* _modem_sleep_exit)(uint32_t module);
     int32_t (* _modem_sleep_register)(uint32_t module);
     int32_t (* _modem_sleep_deregister)(uint32_t module);
-    void (* _sc_ack_send)(void *param);
-    void (* _sc_ack_send_stop)(void);
     uint32_t (* _coex_status_get)(void);
     int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration);
     int32_t (* _coex_wifi_release)(uint32_t event);
index 34cf8667ab923e9d49802da528e64abbbcd89b9f..bd5c545e584f3635d2629791eea24aeddbad9422 100644 (file)
 #include <stdint.h>
 #include <stdbool.h>
 #include "esp_err.h"
+#include "esp_event_base.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef enum {
-    SC_STATUS_WAIT = 0,             /**< Waiting to start connect */
-    SC_STATUS_FIND_CHANNEL,         /**< Finding target channel */
-    SC_STATUS_GETTING_SSID_PSWD,    /**< Getting SSID and password of target AP */
-    SC_STATUS_LINK,                 /**< Connecting to target AP */
-    SC_STATUS_LINK_OVER,            /**< Connected to AP successfully */
-} smartconfig_status_t;
-
 typedef enum {
     SC_TYPE_ESPTOUCH = 0,       /**< protocol: ESPTouch */
     SC_TYPE_AIRKISS,            /**< protocol: AirKiss */
     SC_TYPE_ESPTOUCH_AIRKISS,   /**< protocol: ESPTouch and AirKiss */
 } smartconfig_type_t;
 
-/**
-  * @brief  The callback of SmartConfig, executed when smart-config status changed.
-  *
-  * @param  status  Status of SmartConfig:
-  *    - SC_STATUS_GETTING_SSID_PSWD : pdata is a pointer of smartconfig_type_t, means config type.
-  *    - SC_STATUS_LINK : pdata is a pointer to wifi_config_t.
-  *    - SC_STATUS_LINK_OVER : pdata is a pointer of phone's IP address(4 bytes) if pdata unequal NULL.
-  *    - otherwise : parameter void *pdata is NULL.
-  * @param  pdata  According to the different status have different values.
-  *
-  */
-typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata);
+/** Smartconfig event declarations */
+typedef enum {
+    SC_EVENT_SCAN_DONE,                /*!< ESP32 station smartconfig has finished to scan for APs */
+    SC_EVENT_FOUND_CHANNEL,            /*!< ESP32 station smartconfig has found the channel of the target AP */
+    SC_EVENT_GOT_SSID_PSWD,            /*!< ESP32 station smartconfig got the SSID and password */
+    SC_EVENT_SEND_ACK_DONE,            /*!< ESP32 station smartconfig has sent ACK to cellphone */
+} smartconfig_event_t;
+
+/** @brief smartconfig event base declaration */
+ESP_EVENT_DECLARE_BASE(SC_EVENT);
+
+/** Argument structure for SC_EVENT_GOT_SSID_PSWD event */
+typedef struct {
+    uint8_t ssid[32];           /**< SSID of the AP. Null terminated string. */
+    uint8_t password[64];       /**< Password of the AP. Null terminated string. */
+    bool bssid_set;             /**< whether set MAC address of target AP or not. */
+    uint8_t bssid[6];           /**< MAC address of target AP. */
+    smartconfig_type_t type;    /**< Type of smartconfig(ESPTouch or AirKiss). */
+    uint8_t token;              /**< Token from cellphone which is used to send ACK to cellphone. */
+    uint8_t cellphone_ip[4];    /**< IP address of cellphone. */
+} smartconfig_event_got_ssid_pswd_t;
+
+/** Configure structure for esp_smartconfig_start */
+typedef struct {
+    bool enable_log;            /**< Enable smartconfig logs. */
+} smartconfig_start_config_t;
+
+#define SMARTCONFIG_START_CONFIG_DEFAULT() { \
+    .enable_log = false \
+};
 
 /**
   * @brief  Get the version of SmartConfig.
@@ -66,14 +77,13 @@ const char *esp_smartconfig_get_version(void);
   * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call
   *               esp_smartconfig_stop first.
   *
-  * @param     cb  SmartConfig callback function.
-  * @param     ... log  1: UART output logs; 0: UART only outputs the result.
+  * @param     config pointer to smartconfig start configure structure
   *
   * @return
   *     - ESP_OK: succeed
   *     - others: fail
   */
-esp_err_t esp_smartconfig_start(sc_callback_t cb, ...);
+esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config);
 
 /**
   * @brief     Stop SmartConfig, free the buffer taken by esp_smartconfig_start.
index 6579ef9a7ebdfa4196398056ee5337c300ca74e3..7657dd453d4349d03458b77c082acbfe6b6736c4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6579ef9a7ebdfa4196398056ee5337c300ca74e3
+Subproject commit 7657dd453d4349d03458b77c082acbfe6b6736c4
diff --git a/components/esp_wifi/src/smartconfig.c b/components/esp_wifi/src/smartconfig.c
new file mode 100644 (file)
index 0000000..a4138c8
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//         http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <string.h>
+#include "esp_log.h"
+#include "esp_event_base.h"
+#include "esp_private/wifi.h"
+#include "esp_smartconfig.h"
+#include "smartconfig_ack.h"
+
+/* Smartconfig events definitions */
+ESP_EVENT_DEFINE_BASE(SC_EVENT);
+
+static const char *TAG = "smartconfig";
+
+static void handler_got_ssid_passwd(void *arg, esp_event_base_t base, int32_t event_id, void *data)
+{
+    smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)data;
+    uint8_t ssid[33] = { 0 };
+    uint8_t password[65] = { 0 };
+    uint8_t cellphone_ip[4];
+    esp_err_t err = ESP_OK;
+
+    memcpy(ssid, evt->ssid, sizeof(evt->ssid));
+    memcpy(password, evt->password, sizeof(evt->password));
+    memcpy(cellphone_ip, evt->cellphone_ip, sizeof(evt->cellphone_ip));
+
+    ESP_LOGD(TAG, "SSID:%s", ssid);
+    ESP_LOGD(TAG, "PASSWORD:%s", password);
+    ESP_LOGD(TAG, "Phone ip: %d.%d.%d.%d\n", cellphone_ip[0], cellphone_ip[1], cellphone_ip[2], cellphone_ip[3]);
+
+    err = sc_send_ack_start(evt->type, evt->token, evt->cellphone_ip);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Send smartconfig ACK error: %d", err);
+    }
+}
+
+esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config)
+{
+    esp_err_t err = ESP_OK;
+
+    err = esp_event_handler_register(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd, NULL);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Register smartconfig default event handler fail!");
+        return err;
+    }
+
+    err = esp_smartconfig_internal_start(config);
+    if (err != ESP_OK) {
+        esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd);
+    }
+    return err;
+}
+
+esp_err_t esp_smartconfig_stop(void)
+{
+    esp_err_t err = ESP_OK;
+
+    err = esp_smartconfig_internal_stop();
+    if (err == ESP_OK) {
+        sc_send_ack_stop();
+        esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd);
+    }
+    return err;
+}
\ No newline at end of file
index be49fd3bd133cb717fdb07183378b55334695672..0eb3e4b6606c8619855daaa45c5922a4c05f46dc 100644 (file)
 extern "C" {
 #endif
 
-#define SC_ACK_TASK_PRIORITY             2          /*!< Priority of sending smartconfig ACK task */
-#define SC_ACK_TASK_STACK_SIZE           2048       /*!< Stack size of sending smartconfig ACK task */
-
-#define SC_ACK_TOUCH_SERVER_PORT         18266      /*!< ESP touch UDP port of server on cellphone */
-#define SC_ACK_AIRKISS_SERVER_PORT       10000      /*!< Airkiss UDP port of server on cellphone */
-
-#define SC_ACK_TOUCH_LEN                 11         /*!< Length of ESP touch ACK context */
-#define SC_ACK_AIRKISS_LEN               7          /*!< Length of Airkiss ACK context */
-
-#define SC_ACK_MAX_COUNT                 30         /*!< Maximum count of sending smartconfig ACK */
-
-/**
- * @brief Smartconfig ACK type.
- */
-typedef enum {
-    SC_ACK_TYPE_ESPTOUCH = 0,                       /*!< ESP touch ACK type */
-    SC_ACK_TYPE_AIRKISS,                            /*!< Airkiss ACK type */
-} sc_ack_type_t;
-
-/**
- * @brief Smartconfig parameters passed to sc_ack_send call.
- */
-typedef struct sc_ack {
-    sc_ack_type_t type;           /*!< Smartconfig ACK type */
-    uint8_t *link_flag;           /*!< Smartconfig link flag */
-    sc_callback_t cb;             /*!< Smartconfig callback function */
-    struct {
-        uint8_t token;            /*!< Smartconfig token to be sent */
-        uint8_t mac[6];           /*!< MAC address of station */
-        uint8_t ip[4];            /*!< IP address of cellphone */
-    } ctx;
-} sc_ack_t;
-
 /**
   * @brief  Send smartconfig ACK to cellphone.
   *
-  * @attention The API is only used in libsmartconfig.a.
+  * @attention The API can only be used when receiving SC_EVENT_GOT_SSID_PSWD event.
   *
-  * @param  param: smartconfig parameters;
+  * @param  type: smartconfig type(ESPTouch or AirKiss);
+  *         token: token from the cellphone;
+  *         cellphone_ip: IP address of the cellphone;
+  *
+  * @retuen ESP_OK: succeed
+  *         others: fail
   */
-void sc_ack_send(sc_ack_t *param);
+esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip);
 
 /**
   * @brief  Stop sending smartconfig ACK to cellphone.
-  *
-  * @attention The API is only used in libsmartconfig.a.
   */
-void sc_ack_send_stop(void);
+void sc_send_ack_stop(void);
 
 #ifdef __cplusplus
 }
index f84aad367261021fbfa201378b1a9a399eeb1032..fae5e58bbc2d515d62347fe95476336f157c94af 100644 (file)
 #include "tcpip_adapter.h"
 #include "esp_log.h"
 #include "esp_wifi.h"
+#include "esp_event.h"
 #include "esp_smartconfig.h"
 #include "smartconfig_ack.h"
 
+#define SC_ACK_TASK_PRIORITY             2          /*!< Priority of sending smartconfig ACK task */
+#define SC_ACK_TASK_STACK_SIZE           2048       /*!< Stack size of sending smartconfig ACK task */
+
+#define SC_ACK_TOUCH_SERVER_PORT         18266      /*!< ESP touch UDP port of server on cellphone */
+#define SC_ACK_AIRKISS_SERVER_PORT       10000      /*!< Airkiss UDP port of server on cellphone */
+
+#define SC_ACK_TOUCH_LEN                 11         /*!< Length of ESP touch ACK context */
+#define SC_ACK_AIRKISS_LEN               7          /*!< Length of Airkiss ACK context */
+
+#define SC_ACK_MAX_COUNT                 30         /*!< Maximum count of sending smartconfig ACK */
+
+/**
+ * @brief Smartconfig parameters passed to sc_ack_send call.
+ */
+typedef struct sc_ack {
+    smartconfig_type_t type;      /*!< Smartconfig type(ESPTouch or AirKiss) */
+    struct {
+        uint8_t token;            /*!< Smartconfig token from the cellphone */
+        uint8_t mac[6];           /*!< MAC address of station */
+        uint8_t ip[4];            /*!< IP address of cellphone */
+    } ctx;
+} sc_ack_t;
+
 static const char *TAG = "smartconfig";
 
 /* Flag to indicate sending smartconfig ACK or not. */
@@ -48,13 +72,13 @@ static void sc_ack_send_task(void *pvParameters)
     tcpip_adapter_ip_info_t local_ip;
     uint8_t remote_ip[4];
     memcpy(remote_ip, ack->ctx.ip, sizeof(remote_ip));
-    int remote_port = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT;
+    int remote_port = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT;
     struct sockaddr_in server_addr;
     socklen_t sin_size = sizeof(server_addr);
     int send_sock = -1;
     int optval = 1;
     int sendlen;
-    int ack_len = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN;
+    int ack_len = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN;
     uint8_t packet_count = 1;
     int err;
     int ret;
@@ -73,7 +97,7 @@ static void sc_ack_send_task(void *pvParameters)
         ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &local_ip);
         if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) {
             /* If ESP touch, smartconfig ACK contains local IP address. */
-            if (ack->type == SC_ACK_TYPE_ESPTOUCH) {
+            if (ack->type == SC_TYPE_ESPTOUCH) {
                 memcpy(ack->ctx.ip, &local_ip.ip.addr, 4);
             }
 
@@ -94,12 +118,7 @@ static void sc_ack_send_task(void *pvParameters)
                 if (sendlen > 0) {
                     /* Totally send 30 smartconfig ACKs. Then smartconfig is successful. */
                     if (packet_count++ >= SC_ACK_MAX_COUNT) {
-                        if (ack->link_flag) {
-                            *ack->link_flag = 1;
-                        }
-                        if (ack->cb) {
-                            ack->cb(SC_STATUS_LINK_OVER, remote_ip);
-                        }
+                        esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY);
                         goto _end;
                     }
                 }
@@ -127,31 +146,36 @@ _end:
     vTaskDelete(NULL);
 }
 
-void sc_ack_send(sc_ack_t *param)
+esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip)
 {
     sc_ack_t *ack = NULL;
 
-    if (param == NULL) {
-        ESP_LOGE(TAG, "Smart config ack parameter error");
-        return;
+    if (cellphone_ip == NULL) {
+        ESP_LOGE(TAG, "Cellphone IP address is NULL");
+        return ESP_ERR_INVALID_ARG;
     }
 
     ack = malloc(sizeof(sc_ack_t));
     if (ack == NULL) {
-        ESP_LOGE(TAG, "Smart config ack parameter malloc fail");
-        return;
+        ESP_LOGE(TAG, "ACK parameter malloc fail");
+        return ESP_ERR_NO_MEM;
     }
-    memcpy(ack, param, sizeof(sc_ack_t));
+    ack->type = type;
+    ack->ctx.token = token;
+    memcpy(ack->ctx.ip, cellphone_ip, 4);
 
     s_sc_ack_send = true;
 
     if (xTaskCreate(sc_ack_send_task, "sc_ack_send_task", SC_ACK_TASK_STACK_SIZE, ack, SC_ACK_TASK_PRIORITY, NULL) != pdPASS) {
         ESP_LOGE(TAG, "Create sending smartconfig ACK task fail");
         free(ack);
+        return ESP_ERR_NO_MEM;
     }
+
+    return ESP_OK;
 }
 
-void sc_ack_send_stop(void)
+void sc_send_ack_stop(void)
 {
     s_sc_ack_send = false;
 }
index f7c6fb38ca6bee46ff1f3fb43aa1986967810ae2..4722ee4ecf58177fe9b4f5f57ee82df1f331ae65 100644 (file)
@@ -163,8 +163,6 @@ void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
         hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
         /* Enable Ethernet DMA Tx Descriptor interrupt */
         hal->tx_desc[1].TDES0.InterruptOnComplete = 1;
-        /* Set the DMA Tx descriptors checksum insertion */
-        hal->tx_desc[i].TDES0.ChecksumInsertControl = EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL;
         /* Enable Transmit Timestamp */
         hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
         /* point to the buffer */
index 7de1c435910632f1796fd963c74fc5a9cfccc246..f5d288e9aec025c04a349351cdb858229d90a970 100644 (file)
@@ -1,5 +1,4 @@
 menu "Example Connection Configuration"
-
     choice EXAMPLE_CONNECT_INTERFACE
         prompt "Connect using"
         default EXAMPLE_CONNECT_WIFI
@@ -15,53 +14,120 @@ menu "Example Connection Configuration"
 
     endchoice
 
-    config EXAMPLE_WIFI_SSID
-        depends on EXAMPLE_CONNECT_WIFI
-        string "WiFi SSID"
-        default "myssid"
-        help
-            SSID (network name) for the example to connect to.
-
-    config EXAMPLE_WIFI_PASSWORD
-        depends on EXAMPLE_CONNECT_WIFI
-        string "WiFi Password"
-        default "mypassword"
-        help
-            WiFi password (WPA or WPA2) for the example to use.
-            Can be left blank if the network has no security set.
-
-    choice EXAMPLE_ETH_PHY_MODEL
-        depends on EXAMPLE_CONNECT_ETHERNET
-        prompt "Ethernet PHY Device"
-        default EXAMPLE_ETH_PHY_IP101
-        help
-            Select the PHY driver to use for the example.
-
-        config EXAMPLE_ETH_PHY_IP101
-            bool "IP101"
+    if EXAMPLE_CONNECT_WIFI
+        config EXAMPLE_WIFI_SSID
+            string "WiFi SSID"
+            default "myssid"
             help
-                IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
-                Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+                SSID (network name) for the example to connect to.
 
-        config EXAMPLE_ETH_PHY_RTL8201
-            bool "RTL8201/SR8201"
+        config EXAMPLE_WIFI_PASSWORD
+            string "WiFi Password"
+            default "mypassword"
             help
-                    RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
-                    Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+                WiFi password (WPA or WPA2) for the example to use.
+                Can be left blank if the network has no security set.
+    endif
 
-        config EXAMPLE_ETH_PHY_LAN8720
-            bool "LAN8720"
+    if EXAMPLE_CONNECT_ETHERNET
+        choice EXAMPLE_USE_ETHERNET
+            prompt "Ethernet Type"
+            default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
+            default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
             help
-                    LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
-                    Goto https://www.microchip.com/LAN8720A for more information about it.
+                Select which kind of Ethernet will be used in the example.
 
-        config EXAMPLE_ETH_PHY_DP83848
-            bool "DP83848"
-            help
-                    DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
-                    Goto http://www.ti.com/product/DP83848J for more information about it.
+            config EXAMPLE_USE_INTERNAL_ETHERNET
+                depends on IDF_TARGET_ESP32
+                select ETH_USE_ESP32_EMAC
+                bool "Internal EMAC"
+                help
+                    Select internal Ethernet MAC controller.
 
-    endchoice
+            config EXAMPLE_USE_SPI_ETHERNET
+                bool "SPI Ethernet Module"
+                select ETH_USE_SPI_ETHERNET
+                help
+                    Select external SPI-Ethernet module.
+        endchoice
+
+        if EXAMPLE_USE_INTERNAL_ETHERNET
+            choice EXAMPLE_ETH_PHY_MODEL
+                prompt "Ethernet PHY Device"
+                default EXAMPLE_ETH_PHY_IP101
+                help
+                    Select the Ethernet PHY device to use in the example.
+
+                config EXAMPLE_ETH_PHY_IP101
+                    bool "IP101"
+                    help
+                        IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
+                        Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+
+                config EXAMPLE_ETH_PHY_RTL8201
+                    bool "RTL8201/SR8201"
+                    help
+                        RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
+                        Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+
+                config EXAMPLE_ETH_PHY_LAN8720
+                    bool "LAN8720"
+                    help
+                        LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
+                        Goto https://www.microchip.com/LAN8720A for more information about it.
+
+                config EXAMPLE_ETH_PHY_DP83848
+                    bool "DP83848"
+                    help
+                        DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
+                        Goto http://www.ti.com/product/DP83848J for more information about it.
+            endchoice
+        endif
+
+        if EXAMPLE_USE_SPI_ETHERNET
+            config EXAMPLE_ETH_SPI_HOST
+                int "SPI Host Number"
+                range 0 2
+                default 1
+                help
+                    Set the SPI host used to communicate with DM9051.
+
+            config EXAMPLE_ETH_SCLK_GPIO
+                int "SPI SCLK GPIO number"
+                range 0 33
+                default 19
+                help
+                    Set the GPIO number used by SPI SCLK.
+
+            config EXAMPLE_ETH_MOSI_GPIO
+                int "SPI MOSI GPIO number"
+                range 0 33
+                default 23
+                help
+                    Set the GPIO number used by SPI MOSI.
+
+            config EXAMPLE_ETH_MISO_GPIO
+                int "SPI MISO GPIO number"
+                range 0 33
+                default 25
+                help
+                    Set the GPIO number used by SPI MISO.
+
+            config EXAMPLE_ETH_CS_GPIO
+                int "SPI CS GPIO number"
+                range 0 33
+                default 22
+                help
+                    Set the GPIO number used by SPI CS.
+
+            config EXAMPLE_ETH_SPI_CLOCK_MHZ
+                int "SPI clock speed (MHz)"
+                range 20 80
+                default 20
+                help
+                    Set the clock speed (MHz) of SPI interface.
+        endif
+    endif
 
     config EXAMPLE_CONNECT_IPV6
         bool "Obtain IPv6 link-local address"
@@ -69,5 +135,4 @@ menu "Example Connection Configuration"
         help
             By default, examples will wait until IPv4 and IPv6 addresses are obtained.
             Disable this option if the network does not support IPv6.
-
 endmenu
index f12d40dda54ff35d09dc4cf3fe26bdede28dc359..68895905a48bf5a75afa7f589b42feb3952a9b2c 100644 (file)
@@ -187,8 +187,9 @@ static void start()
     ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL));
 #endif
     eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
-    s_mac = esp_eth_mac_new_esp32(&mac_config);
     eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
+#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
+    s_mac = esp_eth_mac_new_esp32(&mac_config);
 #if CONFIG_EXAMPLE_ETH_PHY_IP101
     s_phy = esp_eth_phy_new_ip101(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
@@ -197,9 +198,33 @@ static void start()
     s_phy = esp_eth_phy_new_lan8720(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_DP83848
     s_phy = esp_eth_phy_new_dp83848(&phy_config);
+#endif
+#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
+    gpio_install_isr_service(0);
+    spi_device_handle_t spi_handle = NULL;
+    spi_bus_config_t buscfg = {
+        .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
+        .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
+        .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+    };
+    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
+    spi_device_interface_config_t devcfg = {
+        .command_bits = 1,
+        .address_bits = 7,
+        .mode = 0,
+        .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
+        .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
+        .queue_size = 20
+    };
+    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
+    /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
+    mac_config.spi_hdl = spi_handle;
+    s_mac = esp_eth_mac_new_dm9051(&mac_config);
+    s_phy = esp_eth_phy_new_dm9051(&phy_config);
 #endif
     esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
-
     ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
     s_connection_name = "Ethernet";
 }
index fead5dd44a03b4573cb43e9eee7cb4b4a7db8268..57f4b472cdf8c6fd48ed9e471c446dcca6f3d603 100644 (file)
@@ -15,35 +15,47 @@ If you have a new Ethernet application to go (for example, connect to IoT cloud
 
 ### Hardware Required
 
-To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+
+`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
 
 ### Project configuration in menuconfig
 
 Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
 
 1. In the `Example Configuration` menu:
+    * Choose the kind of Ethernet this example will run on under `Ethernet Type`.
+    * If `Internal EMAC` is selected:
+        * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
 
-* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
+    * If `SPI Ethernet Module` is selected:
+        * Set SPI specific configuration, including GPIO and clock speed.
 
 2. In the `Component config > Ethernet` menu:
+    * If `Internal EMAC` is selected:
+        * Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
+        * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
+        * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
+        * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
+        * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
+        * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
+
+            | Default Example GPIO | RMII Signal | Notes         |
+            | -------------------- | ----------- | ------------- |
+            | GPIO23               | MDC         | Output to PHY |
+            | GPIO18               | MDIO        | Bidirectional |
 
-* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
-* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
-* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
-* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
-* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
-* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
+        * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
 
-  | Default Example GPIO | RMII Signal | Notes         |
-  | -------------------- | ----------- | ------------- |
-  | GPIO23               | MDC         | Output to PHY |
-  | GPIO18               | MDIO        | Bidirectional |
+    * If `SPI Ethernet Module` is selected:
+        * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`.
 
-* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
 
 ### Extra configuration in the code (Optional)
 
 * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.
+
+**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
   
 ### Build and Flash
 
@@ -56,20 +68,20 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
 ## Example Output
 
 ```bash
-I (336) cpu_start: Starting scheduler on PRO CPU.
-I (0) cpu_start: Starting scheduler on APP CPU.
-I (382) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
-I (392) eth_example: Ethernet Started
-I (3922) eth_example: Ethernet Link Up
-I (5862) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2
-I (5862) eth_example: Ethernet Got IP Address
-I (5862) eth_example: ~~~~~~~~~~~
-I (5862) eth_example: ETHIP:192.168.2.151
-I (5872) eth_example: ETHMASK:255.255.255.0
-I (5872) eth_example: ETHGW:192.168.2.2
-I (5882) eth_example: ~~~~~~~~~~~
+I (394) eth_example: Ethernet Started
+I (3934) eth_example: Ethernet Link Up
+I (3934) eth_example: Ethernet HW Addr 30:ae:a4:c6:87:5b
+I (5864) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2
+I (5864) eth_example: Ethernet Got IP Address
+I (5864) eth_example: ~~~~~~~~~~~
+I (5864) eth_example: ETHIP:192.168.2.151
+I (5874) eth_example: ETHMASK:255.255.255.0
+I (5874) eth_example: ETHGW:192.168.2.2
+I (5884) eth_example: ~~~~~~~~~~~
 ```
 
+Now you can ping your ESP32 in the terminal by entering `ping 192.168.2.151` (it depends on the actual IP address you get).
+
 ## Troubleshooting
 
 * RMII Clock
index 1040116540a2f55c3fe1d9af52542dbbce7d17c7..9c6cae1f73321b6a7dcf1ac044834115491fd7a4 100644 (file)
@@ -1,34 +1,99 @@
 menu "Example Configuration"
-
-    choice EXAMPLE_ETH_PHY_MODEL
-        prompt "Ethernet PHY Device"
-        default EXAMPLE_ETH_PHY_IP101
+    choice EXAMPLE_USE_ETHERNET
+        prompt "Ethernet Type"
+        default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
+        default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
         help
-            Select the Ethernet PHY device to use in the example.
+            Select which kind of Ethernet will be used in the example.
 
-        config EXAMPLE_ETH_PHY_IP101
-            bool "IP101"
+        config EXAMPLE_USE_INTERNAL_ETHERNET
+            depends on IDF_TARGET_ESP32
+            select ETH_USE_ESP32_EMAC
+            bool "Internal EMAC"
             help
-                IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
-                Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+                Select internal Ethernet MAC controller.
 
-        config EXAMPLE_ETH_PHY_RTL8201
-            bool "RTL8201/SR8201"
+        config EXAMPLE_USE_SPI_ETHERNET
+            bool "SPI Ethernet Module"
+            select ETH_USE_SPI_ETHERNET
             help
-                RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
-                Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+                Select external SPI-Ethernet module.
+    endchoice
 
-        config EXAMPLE_ETH_PHY_LAN8720
-            bool "LAN8720"
+    if EXAMPLE_USE_INTERNAL_ETHERNET
+        choice EXAMPLE_ETH_PHY_MODEL
+            prompt "Ethernet PHY Device"
+            default EXAMPLE_ETH_PHY_IP101
             help
-                LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
-                Goto https://www.microchip.com/LAN8720A for more information about it.
+                Select the Ethernet PHY device to use in the example.
+
+            config EXAMPLE_ETH_PHY_IP101
+                bool "IP101"
+                help
+                    IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
+                    Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+
+            config EXAMPLE_ETH_PHY_RTL8201
+                bool "RTL8201/SR8201"
+                help
+                    RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
+                    Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
 
-        config EXAMPLE_ETH_PHY_DP83848
-            bool "DP83848"
+            config EXAMPLE_ETH_PHY_LAN8720
+                bool "LAN8720"
+                help
+                    LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
+                    Goto https://www.microchip.com/LAN8720A for more information about it.
+
+            config EXAMPLE_ETH_PHY_DP83848
+                bool "DP83848"
+                help
+                    DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
+                    Goto http://www.ti.com/product/DP83848J for more information about it.
+        endchoice
+    endif
+
+    if EXAMPLE_USE_SPI_ETHERNET
+        config EXAMPLE_ETH_SPI_HOST
+            int "SPI Host Number"
+            range 0 2
+            default 1
             help
-                DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
-                Goto http://www.ti.com/product/DP83848J for more information about it.
-    endchoice
+                Set the SPI host used to communicate with DM9051.
+
+        config EXAMPLE_ETH_SCLK_GPIO
+            int "SPI SCLK GPIO number"
+            range 0 33
+            default 19
+            help
+                Set the GPIO number used by SPI SCLK.
+
+        config EXAMPLE_ETH_MOSI_GPIO
+            int "SPI MOSI GPIO number"
+            range 0 33
+            default 23
+            help
+                Set the GPIO number used by SPI MOSI.
+
+        config EXAMPLE_ETH_MISO_GPIO
+            int "SPI MISO GPIO number"
+            range 0 33
+            default 25
+            help
+                Set the GPIO number used by SPI MISO.
+
+        config EXAMPLE_ETH_CS_GPIO
+            int "SPI CS GPIO number"
+            range 0 33
+            default 22
+            help
+                Set the GPIO number used by SPI CS.
 
+        config EXAMPLE_ETH_SPI_CLOCK_MHZ
+            int "SPI clock speed (MHz)"
+            range 20 80
+            default 20
+            help
+                Set the clock speed (MHz) of SPI interface.
+    endif
 endmenu
index 4c52b338172f8b06bcfd9cff2850e9be91c026c9..ed794a32b3298908194801f7f92ef0f88a07951a 100644 (file)
 #include "sdkconfig.h"
 
 static const char *TAG = "eth_example";
-static esp_eth_handle_t s_eth_handle = NULL;
 
 /** Event handler for Ethernet events */
 static void eth_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
 {
+    uint8_t mac_addr[6] = {0};
+    /* we can get the ethernet driver handle from event data */
+    esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
+
     switch (event_id) {
     case ETHERNET_EVENT_CONNECTED:
+        esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
         ESP_LOGI(TAG, "Ethernet Link Up");
+        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
+                 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
         break;
     case ETHERNET_EVENT_DISCONNECTED:
         ESP_LOGI(TAG, "Ethernet Link Down");
@@ -66,8 +72,9 @@ void app_main()
     ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
 
     eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
-    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
     eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
+#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
+    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
 #if CONFIG_EXAMPLE_ETH_PHY_IP101
     esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
@@ -76,7 +83,33 @@ void app_main()
     esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_DP83848
     esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
+#endif
+#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
+    gpio_install_isr_service(0);
+    spi_device_handle_t spi_handle = NULL;
+    spi_bus_config_t buscfg = {
+        .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
+        .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
+        .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+    };
+    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
+    spi_device_interface_config_t devcfg = {
+        .command_bits = 1,
+        .address_bits = 7,
+        .mode = 0,
+        .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
+        .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
+        .queue_size = 20
+    };
+    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
+    /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
+    mac_config.spi_hdl = spi_handle;
+    esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
+    esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
 #endif
     esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
-    ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
+    esp_eth_handle_t eth_handle = NULL;
+    ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_handle));
 }
index 4d1c8e0f2d501a7dc0fa0f7c3d84d977ed35de72..26d81db12124491fbddab8c919459263155bd31f 100644 (file)
@@ -12,38 +12,48 @@ The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward
 
 ### Hardware Required
 
-To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+
+`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
 
 ### Project configuration in menuconfig
 
 Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
 
 1. In the `Example Configuration` menu:
+    * Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`.
+    * Set the maximum connection number under `Maximum STA connections`.
+    * Choose the kind of Ethernet this example will run on under `Ethernet Type`.
+    * If `Internal EMAC` is selected:
+        * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
 
-* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
-* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`.
-* Set the maximum connection number under `Maximum STA connections`.
+    * If `SPI Ethernet Module` is selected:
+        * Set SPI specific configuration, including GPIO and clock speed.
 
 2. In the `Component config > Ethernet` menu:
+    * If `Internal EMAC` is selected:
+        * Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
+        * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
+        * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
+        * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
+        * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
+        * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
 
-* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
-* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
-* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
-* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
-* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
-* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
+            | Default Example GPIO | RMII Signal | Notes         |
+            | -------------------- | ----------- | ------------- |
+            | GPIO23               | MDC         | Output to PHY |
+            | GPIO18               | MDIO        | Bidirectional |
 
-  | Default Example GPIO | RMII Signal | Notes         |
-  | -------------------- | ----------- | ------------- |
-  | GPIO23               | MDC         | Output to PHY |
-  | GPIO18               | MDIO        | Bidirectional |
+        * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
 
-* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
+    * If `SPI Ethernet Module` is selected:
+        * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`.
 
 ### Extra configuration in the code (Optional)
 
 * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.peripheral (e.g. I²S), you'd better choose the external clock.
 
+**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
 
 ### Build and Flash
 
index 7c6b87810adb62a8d3172559d1b045f998a8b617..40b54b9ad38c887309c4a4b2002254cd60053166 100644 (file)
 menu "Example Configuration"
-
-    choice EXAMPLE_ETH_PHY_MODEL
-        prompt "Ethernet PHY Device"
-        default EXAMPLE_ETH_PHY_IP101
+    choice EXAMPLE_USE_ETHERNET
+        prompt "Ethernet Type"
+        default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
+        default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
         help
-            Select the Ethernet PHY device to use in the example.
+            Select which kind of Ethernet will be used in the example.
 
-        config EXAMPLE_ETH_PHY_IP101
-            bool "IP101"
+        config EXAMPLE_USE_INTERNAL_ETHERNET
+            depends on IDF_TARGET_ESP32
+            select ETH_USE_ESP32_EMAC
+            bool "Internal EMAC"
             help
-                IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
-                Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+                Select internal Ethernet MAC controller.
 
-        config EXAMPLE_ETH_PHY_RTL8201
-            bool "RTL8201/SR8201"
+        config EXAMPLE_USE_SPI_ETHERNET
+            bool "SPI Ethernet Module"
+            select ETH_USE_SPI_ETHERNET
             help
-                RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
-                Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+                Select external SPI-Ethernet module.
+    endchoice
 
-        config EXAMPLE_ETH_PHY_LAN8720
-            bool "LAN8720"
+    if EXAMPLE_USE_INTERNAL_ETHERNET
+        choice EXAMPLE_ETH_PHY_MODEL
+            prompt "Ethernet PHY Device"
+            default EXAMPLE_ETH_PHY_IP101
             help
-                LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
-                Goto https://www.microchip.com/LAN8720A for more information about it.
+                Select the Ethernet PHY device to use in the example.
+
+            config EXAMPLE_ETH_PHY_IP101
+                bool "IP101"
+                help
+                    IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
+                    Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+
+            config EXAMPLE_ETH_PHY_RTL8201
+                bool "RTL8201/SR8201"
+                help
+                    RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
+                    Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+
+            config EXAMPLE_ETH_PHY_LAN8720
+                bool "LAN8720"
+                help
+                    LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
+                    Goto https://www.microchip.com/LAN8720A for more information about it.
 
-        config EXAMPLE_ETH_PHY_DP83848
-            bool "DP83848"
+            config EXAMPLE_ETH_PHY_DP83848
+                bool "DP83848"
+                help
+                    DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
+                    Goto http://www.ti.com/product/DP83848J for more information about it.
+        endchoice
+    endif
+
+    if EXAMPLE_USE_SPI_ETHERNET
+        config EXAMPLE_ETH_SPI_HOST
+            int "SPI Host Number"
+            range 0 2
+            default 1
             help
-                DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
-                Goto http://www.ti.com/product/DP83848J for more information about it.
-    endchoice
+                Set the SPI host used to communicate with DM9051.
+
+        config EXAMPLE_ETH_SCLK_GPIO
+            int "SPI SCLK GPIO number"
+            range 0 33
+            default 19
+            help
+                Set the GPIO number used by SPI SCLK.
+
+        config EXAMPLE_ETH_MOSI_GPIO
+            int "SPI MOSI GPIO number"
+            range 0 33
+            default 23
+            help
+                Set the GPIO number used by SPI MOSI.
+
+        config EXAMPLE_ETH_MISO_GPIO
+            int "SPI MISO GPIO number"
+            range 0 33
+            default 25
+            help
+                Set the GPIO number used by SPI MISO.
+
+        config EXAMPLE_ETH_CS_GPIO
+            int "SPI CS GPIO number"
+            range 0 33
+            default 22
+            help
+                Set the GPIO number used by SPI CS.
+
+        config EXAMPLE_ETH_SPI_CLOCK_MHZ
+            int "SPI clock speed (MHz)"
+            range 20 80
+            default 20
+            help
+                Set the clock speed (MHz) of SPI interface.
+    endif
 
     config EXAMPLE_WIFI_SSID
         string "Wi-Fi SSID"
index a28bd7740d171f6a556555b91c179c4b3ada6738..6ea43dd3b042ca3a72e01e2ffc12a9a6d982b9f7 100644 (file)
@@ -145,8 +145,9 @@ static void initialize_ethernet(void)
 {
     ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL));
     eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
-    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
     eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
+#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
+    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
 #if CONFIG_EXAMPLE_ETH_PHY_IP101
     esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
@@ -155,6 +156,31 @@ static void initialize_ethernet(void)
     esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_DP83848
     esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
+#endif
+#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
+    gpio_install_isr_service(0);
+    spi_device_handle_t spi_handle = NULL;
+    spi_bus_config_t buscfg = {
+        .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
+        .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
+        .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+    };
+    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
+    spi_device_interface_config_t devcfg = {
+        .command_bits = 1,
+        .address_bits = 7,
+        .mode = 0,
+        .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
+        .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
+        .queue_size = 20
+    };
+    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
+    /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
+    mac_config.spi_hdl = spi_handle;
+    esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
+    esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
 #endif
     esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
     config.stack_input = pkt_eth2wifi;
index 47ed723f8f2b509c3ed9fd7a7db6be5677256ce4..c75e90096a9ccf99d896cda0a348f56cb605b705 100644 (file)
@@ -10,9 +10,13 @@ The cli environment in the example is based on the [console component](https://d
 
 ## How to use example
 
-To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+### Hardware Required
 
-### Prepare work
+To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
+
+`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
+
+### Other Preparation
 
 1. Install iperf tool on PC
    * Debian/Ubuntu: `sudo apt-get install iperf` 
@@ -24,30 +28,39 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d
 Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
 
 1. In the `Example Configuration` menu:
+    * Enable storing history commands in flash under `Store command history in flash`.
+    * Choose the kind of Ethernet this example will run on under `Ethernet Type`.
+    * If `Internal EMAC` is selected:
+        * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
 
-* Enable storing history commands in flash under `Store command history in flash`.
-* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
+    * If `SPI Ethernet Module` is selected:
+        * Set SPI specific configuration, including GPIO and clock speed.
 
 2. In the `Component config > Ethernet` menu:
+    * If `Internal EMAC` is selected:
+        * Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
+        * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
+        * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
+        * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
+        * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
+        * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
 
-* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
-* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
-* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
-* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
-* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
-* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
+            | Default Example GPIO | RMII Signal | Notes         |
+            | -------------------- | ----------- | ------------- |
+            | GPIO23               | MDC         | Output to PHY |
+            | GPIO18               | MDIO        | Bidirectional |
 
-  | Default Example GPIO | RMII Signal | Notes         |
-  | -------------------- | ----------- | ------------- |
-  | GPIO23               | MDC         | Output to PHY |
-  | GPIO18               | MDIO        | Bidirectional |
+        * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
 
-* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
+    * If `SPI Ethernet Module` is selected:
+        * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`.
 
 ### Extra configuration in the code (Optional)
 
 * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.
 
+**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
+
 ### Build and Flash
 
 Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system.
@@ -73,15 +86,15 @@ UDP buffer size:  208 KByte (default)
 ------------------------------------------------------------
 [  3] local 192.168.2.160 port 5001 connected with 192.168.2.156 port 49154
 [ ID] Interval       Transfer     Bandwidth        Jitter   Lost/Total Datagrams
-[  3]  0.0- 3.0 sec  24.8 MBytes  69.5 Mbits/sec   0.172 ms    1/17721 (0.0056%)
-[  3]  3.0- 6.0 sec  24.8 MBytes  69.5 Mbits/sec   0.169 ms    0/17719 (0%)
-[  3]  6.0- 9.0 sec  24.8 MBytes  69.5 Mbits/sec   0.170 ms    0/17719 (0%)
-[  3]  9.0-12.0 sec  24.8 MBytes  69.5 Mbits/sec   0.170 ms    0/17718 (0%)
-[  3] 12.0-15.0 sec  24.8 MBytes  69.5 Mbits/sec   0.169 ms    0/17717 (0%)
-[  3] 15.0-18.0 sec  24.8 MBytes  69.5 Mbits/sec   0.170 ms    0/17720 (0%)
-[  3] 18.0-21.0 sec  24.8 MBytes  69.5 Mbits/sec   0.170 ms    0/17721 (0%)
-[  3] 21.0-24.0 sec  24.8 MBytes  69.5 Mbits/sec   0.169 ms    0/17720 (0%)
-[  3] 24.0-27.0 sec  24.8 MBytes  69.5 Mbits/sec   0.169 ms    0/17723 (0%)
+[  3]  0.0- 3.0 sec  26.1 MBytes  72.8 Mbits/sec   0.198 ms    1/18585 (0.0054%)
+[  3]  3.0- 6.0 sec  26.3 MBytes  73.7 Mbits/sec   0.192 ms    0/18792 (0%)
+[  3]  6.0- 9.0 sec  26.3 MBytes  73.5 Mbits/sec   0.189 ms    0/18741 (0%)
+[  3]  9.0-12.0 sec  26.2 MBytes  73.3 Mbits/sec   0.191 ms   43/18739 (0.23%)
+[  3] 12.0-15.0 sec  26.3 MBytes  73.5 Mbits/sec   0.194 ms    0/18739 (0%)
+[  3] 15.0-18.0 sec  26.3 MBytes  73.5 Mbits/sec   0.191 ms    0/18741 (0%)
+[  3] 18.0-21.0 sec  26.3 MBytes  73.5 Mbits/sec   0.187 ms    0/18752 (0%)
+[  3] 21.0-24.0 sec  26.3 MBytes  73.4 Mbits/sec   0.192 ms    0/18737 (0%)
+[  3] 24.0-27.0 sec  26.3 MBytes  73.5 Mbits/sec   0.188 ms    0/18739 (0%)
 ```
 
 #### ESP32 output
@@ -89,16 +102,17 @@ UDP buffer size:  208 KByte (default)
 ```bash
 mode=udp-client sip=192.168.2.156:5001, dip=192.168.2.160:5001, interval=3, time=30
     Interval           Bandwidth
-   0-   3 sec       69.34 Mbits/sec
-   3-   6 sec       69.55 Mbits/sec
-   6-   9 sec       69.55 Mbits/sec
-   9-  12 sec       69.55 Mbits/sec
-  12-  15 sec       69.55 Mbits/sec
-  15-  18 sec       69.56 Mbits/sec
-  18-  21 sec       69.56 Mbits/sec
-  21-  24 sec       69.56 Mbits/sec
-  24-  27 sec       69.56 Mbits/sec
-  27-  30 sec       69.56 Mbits/sec
+   0-   3 sec       72.92 Mbits/sec
+   3-   6 sec       73.76 Mbits/sec
+   6-   9 sec       73.56 Mbits/sec
+   9-  12 sec       73.56 Mbits/sec
+  12-  15 sec       73.56 Mbits/sec
+  15-  18 sec       73.56 Mbits/sec
+  18-  21 sec       73.61 Mbits/sec
+  21-  24 sec       73.55 Mbits/sec
+  24-  27 sec       73.56 Mbits/sec
+  27-  30 sec       73.56 Mbits/sec
+   0-  30 sec       73.52 Mbits/sec
 ```
 
 ### Test downlink bandwidth
@@ -119,11 +133,13 @@ UDP buffer size:  208 KByte (default)
 [  3]  3.0- 6.0 sec  28.6 MBytes  80.0 Mbits/sec
 [  3]  6.0- 9.0 sec  28.6 MBytes  80.0 Mbits/sec
 [  3]  9.0-12.0 sec  28.6 MBytes  80.0 Mbits/sec
-[  3] 12.0-15.0 sec  28.6 MBytes  79.9 Mbits/sec
-[  3] 15.0-18.0 sec  28.6 MBytes  80.0 Mbits/sec
-[  3] 18.0-21.0 sec  28.6 MBytes  80.0 Mbits/sec
-[  3] 21.0-24.0 sec  28.6 MBytes  80.0 Mbits/sec
+[  3] 12.0-15.0 sec  28.4 MBytes  79.5 Mbits/sec
+[  3] 15.0-18.0 sec  28.6 MBytes  79.9 Mbits/sec
+[  3] 18.0-21.0 sec  28.6 MBytes  79.9 Mbits/sec
+[  3] 21.0-24.0 sec  28.6 MBytes  79.9 Mbits/sec
 [  3] 24.0-27.0 sec  28.6 MBytes  80.0 Mbits/sec
+[  3] 27.0-30.0 sec  28.5 MBytes  79.7 Mbits/sec
+[  3]  0.0-30.0 sec   286 MBytes  79.9 Mbits/sec
 ```
 
 #### ESP32 output
@@ -131,16 +147,17 @@ UDP buffer size:  208 KByte (default)
 mode=udp-server sip=192.168.2.156:5001, dip=0.0.0.0:5001, interval=3, time=30
     Interval           Bandwidth
 I (2534456) iperf: want recv=16384
-   0-  30 sec       72.67 Mbits/sec
-   3-   6 sec       74.18 Mbits/sec
-   6-   9 sec       73.14 Mbits/sec
-   9-  12 sec       73.65 Mbits/sec
-  12-  15 sec       72.87 Mbits/sec
-  15-  18 sec       73.29 Mbits/sec
-  18-  21 sec       74.35 Mbits/sec
-  21-  24 sec       72.28 Mbits/sec
-  24-  27 sec       73.39 Mbits/sec
-  27-  30 sec       73.49 Mbits/sec
+   0-   3 sec       79.36 Mbits/sec
+   3-   6 sec       79.56 Mbits/sec
+   6-   9 sec       79.51 Mbits/sec
+   9-  12 sec       79.24 Mbits/sec
+  12-  15 sec       77.33 Mbits/sec
+  15-  18 sec       79.01 Mbits/sec
+  18-  21 sec       78.58 Mbits/sec
+  21-  24 sec       78.24 Mbits/sec
+  24-  27 sec       79.56 Mbits/sec
+  27-  30 sec       77.20 Mbits/sec
+   0-  30 sec       78.76 Mbits/sec
 ```
 
 ## Suggestions of getting higher bandwidth
index 001b648a57e1f4f7bf9f821f99db6de9ee9f5710..b84eefa7e7292c2fdeccbedfe36fe1f34f349bb9 100644 (file)
@@ -1,5 +1,4 @@
 menu "Example Configuration"
-
     config EXAMPLE_STORE_HISTORY
         bool "Store command history in flash"
         default y
@@ -8,35 +7,101 @@ menu "Example Configuration"
             command history. If this option is enabled, initalizes a FAT filesystem
             and uses it to store command history.
 
-    choice EXAMPLE_ETH_PHY_MODEL
-        prompt "Ethernet PHY Device"
-        default EXAMPLE_ETH_PHY_IP101
+    choice EXAMPLE_USE_ETHERNET
+        prompt "Ethernet Type"
+        default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
+        default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
         help
-            Select the Ethernet PHY device to use in the example.
+            Select which kind of Ethernet will be used in the example.
 
-        config EXAMPLE_ETH_PHY_IP101
-            bool "IP101"
+        config EXAMPLE_USE_INTERNAL_ETHERNET
+            depends on IDF_TARGET_ESP32
+            select ETH_USE_ESP32_EMAC
+            bool "Internal EMAC"
             help
-                IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
-                Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+                Select internal Ethernet MAC controller.
 
-        config EXAMPLE_ETH_PHY_RTL8201
-            bool "RTL8201/SR8201"
+        config EXAMPLE_USE_SPI_ETHERNET
+            bool "SPI Ethernet Module"
+            select ETH_USE_SPI_ETHERNET
             help
-                RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
-                Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
+                Select external SPI-Ethernet module.
+    endchoice
 
-        config EXAMPLE_ETH_PHY_LAN8720
-            bool "LAN8720"
+    if EXAMPLE_USE_INTERNAL_ETHERNET
+        choice EXAMPLE_ETH_PHY_MODEL
+            prompt "Ethernet PHY Device"
+            default EXAMPLE_ETH_PHY_IP101
             help
-                LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
-                Goto https://www.microchip.com/LAN8720A for more information about it.
+                Select the Ethernet PHY device to use in the example.
+
+            config EXAMPLE_ETH_PHY_IP101
+                bool "IP101"
+                help
+                    IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
+                    Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
+
+            config EXAMPLE_ETH_PHY_RTL8201
+                bool "RTL8201/SR8201"
+                help
+                    RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
+                    Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
 
-        config EXAMPLE_ETH_PHY_DP83848
-            bool "DP83848"
+            config EXAMPLE_ETH_PHY_LAN8720
+                bool "LAN8720"
+                help
+                    LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
+                    Goto https://www.microchip.com/LAN8720A for more information about it.
+
+            config EXAMPLE_ETH_PHY_DP83848
+                bool "DP83848"
+                help
+                    DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
+                    Goto http://www.ti.com/product/DP83848J for more information about it.
+        endchoice
+    endif
+
+    if EXAMPLE_USE_SPI_ETHERNET
+        config EXAMPLE_ETH_SPI_HOST
+            int "SPI Host Number"
+            range 0 2
+            default 1
             help
-                DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
-                Goto http://www.ti.com/product/DP83848J for more information about it.
-    endchoice
+                Set the SPI host used to communicate with DM9051.
+
+        config EXAMPLE_ETH_SCLK_GPIO
+            int "SPI SCLK GPIO number"
+            range 0 33
+            default 19
+            help
+                Set the GPIO number used by SPI SCLK.
+
+        config EXAMPLE_ETH_MOSI_GPIO
+            int "SPI MOSI GPIO number"
+            range 0 33
+            default 23
+            help
+                Set the GPIO number used by SPI MOSI.
+
+        config EXAMPLE_ETH_MISO_GPIO
+            int "SPI MISO GPIO number"
+            range 0 33
+            default 25
+            help
+                Set the GPIO number used by SPI MISO.
+
+        config EXAMPLE_ETH_CS_GPIO
+            int "SPI CS GPIO number"
+            range 0 33
+            default 22
+            help
+                Set the GPIO number used by SPI CS.
 
+        config EXAMPLE_ETH_SPI_CLOCK_MHZ
+            int "SPI clock speed (MHz)"
+            range 20 80
+            default 20
+            help
+                Set the clock speed (MHz) of SPI interface.
+    endif
 endmenu
index 1692a5dd63711f8d9fbe6b372238d69f9dcae911..832d049b043540ea278b3cc1868aa14d6a86cd18 100644 (file)
@@ -183,8 +183,9 @@ void register_ethernet()
     ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &event_handler, NULL));
 
     eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
-    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
     eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
+#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
+    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
 #if CONFIG_EXAMPLE_ETH_PHY_IP101
     esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
@@ -193,6 +194,31 @@ void register_ethernet()
     esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
 #elif CONFIG_EXAMPLE_ETH_PHY_DP83848
     esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
+#endif
+#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
+    gpio_install_isr_service(0);
+    spi_device_handle_t spi_handle = NULL;
+    spi_bus_config_t buscfg = {
+        .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
+        .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
+        .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+    };
+    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
+    spi_device_interface_config_t devcfg = {
+        .command_bits = 1,
+        .address_bits = 7,
+        .mode = 0,
+        .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
+        .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
+        .queue_size = 20
+    };
+    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
+    /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
+    mac_config.spi_hdl = spi_handle;
+    esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
+    esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
 #endif
     esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
     ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_handle));
index 53e5cfb9843deb0029f328c296d5240375f23d25..1f0718fd03b1a87b8e6f1b72c83772f624f185ca 100644 (file)
@@ -85,7 +85,7 @@ static void initialize_console()
 
     /* Initialize the console */
     esp_console_config_t console_config = {
-        .max_cmdline_args = 8,
+        .max_cmdline_args = 16,
         .max_cmdline_length = 256,
 #if CONFIG_LOG_COLORS
         .hint_color = atoi(LOG_COLOR_CYAN)
index 3a405ff8a380a0775e706dcbcd7a362b45f1f8b9..0819f256da2f84b731fab69dacc5fee87d244fe8 100644 (file)
@@ -29,7 +29,7 @@ static EventGroupHandle_t s_wifi_event_group;
    to the AP with an IP? */
 static const int CONNECTED_BIT = BIT0;
 static const int ESPTOUCH_DONE_BIT = BIT1;
-static const char *TAG = "sc";
+static const char *TAG = "smartconfig_example";
 
 static void smartconfig_example_task(void * parm);
 
@@ -43,6 +43,36 @@ static void event_handler(void* arg, esp_event_base_t event_base,
         xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
     } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
         xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
+    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
+        ESP_LOGI(TAG, "Scan done");
+    } else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
+        ESP_LOGI(TAG, "Found channel");
+    } else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
+        ESP_LOGI(TAG, "Got SSID and password");
+
+        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
+        wifi_config_t wifi_config;
+        uint8_t ssid[33] = { 0 };
+        uint8_t password[65] = { 0 };
+
+        bzero(&wifi_config, sizeof(wifi_config_t));
+        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
+        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
+        wifi_config.sta.bssid_set = evt->bssid_set;
+        if (wifi_config.sta.bssid_set == true) {
+            memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
+        }
+
+        memcpy(ssid, evt->ssid, sizeof(evt->ssid));
+        memcpy(password, evt->password, sizeof(evt->password));
+        ESP_LOGI(TAG, "SSID:%s", ssid);
+        ESP_LOGI(TAG, "PASSWORD:%s", password);
+
+        ESP_ERROR_CHECK( esp_wifi_disconnect() );
+        ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+        ESP_ERROR_CHECK( esp_wifi_connect() );
+    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
+        xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
     }
 }
 
@@ -57,51 +87,18 @@ static void initialise_wifi(void)
 
     ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
     ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
+    ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
 
     ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
     ESP_ERROR_CHECK( esp_wifi_start() );
 }
 
-static void sc_callback(smartconfig_status_t status, void *pdata)
-{
-    switch (status) {
-        case SC_STATUS_WAIT:
-            ESP_LOGI(TAG, "SC_STATUS_WAIT");
-            break;
-        case SC_STATUS_FIND_CHANNEL:
-            ESP_LOGI(TAG, "SC_STATUS_FINDING_CHANNEL");
-            break;
-        case SC_STATUS_GETTING_SSID_PSWD:
-            ESP_LOGI(TAG, "SC_STATUS_GETTING_SSID_PSWD");
-            break;
-        case SC_STATUS_LINK:
-            ESP_LOGI(TAG, "SC_STATUS_LINK");
-            wifi_config_t *wifi_config = pdata;
-            ESP_LOGI(TAG, "SSID:%s", wifi_config->sta.ssid);
-            ESP_LOGI(TAG, "PASSWORD:%s", wifi_config->sta.password);
-            ESP_ERROR_CHECK( esp_wifi_disconnect() );
-            ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_config) );
-            ESP_ERROR_CHECK( esp_wifi_connect() );
-            break;
-        case SC_STATUS_LINK_OVER:
-            ESP_LOGI(TAG, "SC_STATUS_LINK_OVER");
-            if (pdata != NULL) {
-                uint8_t phone_ip[4] = { 0 };
-                memcpy(phone_ip, (uint8_t* )pdata, 4);
-                ESP_LOGI(TAG, "Phone ip: %d.%d.%d.%d\n", phone_ip[0], phone_ip[1], phone_ip[2], phone_ip[3]);
-            }
-            xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
-            break;
-        default:
-            break;
-    }
-}
-
 static void smartconfig_example_task(void * parm)
 {
     EventBits_t uxBits;
     ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
-    ESP_ERROR_CHECK( esp_smartconfig_start(sc_callback) );
+    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
     while (1) {
         uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY); 
         if(uxBits & CONNECTED_BIT) {
index 5b6b332c9c664fa4d9da9af4c56977ed18c54519..e9c060a1b0b3ffda615561cf9e7c9dc96d76bd94 100755 (executable)
@@ -34,16 +34,20 @@ def target_branch_candidates(proj_name):
     except (KeyError, TypeError):
         pass
     # branch name read from IDF
-    git_describe = subprocess.check_output(["git", "describe", "--tags", "HEAD"])
-    match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe)
-    if match:
-        major_revision = match.group(1)
-        minor_revision = match.group(2)
-        # release branch
-        candidates.append("release/v{}.{}".format(major_revision, minor_revision))
-        # branch to match all major branches, like v3.x or v3
-        candidates.append("release/v{}.x".format(major_revision))
-        candidates.append("release/v{}".format(major_revision))
+    try:
+        git_describe = subprocess.check_output(["git", "describe", "--tags", "HEAD"])
+        match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe.decode())
+        if match:
+            major_revision = match.group(1)
+            minor_revision = match.group(2)
+            # release branch
+            candidates.append("release/v{}.{}".format(major_revision, minor_revision))
+            # branch to match all major branches, like v3.x or v3
+            candidates.append("release/v{}.x".format(major_revision))
+            candidates.append("release/v{}".format(major_revision))
+    except subprocess.CalledProcessError:
+        # this should not happen as IDF should have describe message
+        pass
 
     return [c for c in candidates if c]  # filter out null value
 
index 30ed7b6389e6ef28952846cbded8ddbcc7c79121..c005ecd6f4a11e17db70eb92b34bb6ad015c3995 100755 (executable)
@@ -175,7 +175,7 @@ def run_cmd_check_output(cmd, input_text=None, extra_paths=None):
             input_text = input_text.encode()
         result = subprocess.run(cmd, capture_output=True, check=True, input=input_text)
         return result.stdout + result.stderr
-    except AttributeError:
+    except (AttributeError, TypeError):
         p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
         stdout, stderr = p.communicate(input_text)
         if p.returncode != 0:
index 496650cff9cc9594c48ad980b2d542d29525b17a..d3a27b517a0d1e1f88b8068849f9621179b87adb 100755 (executable)
@@ -473,7 +473,9 @@ def write_json_menus(deprecated_options, config, filename):
                 # should have one condition which is true
                 for min_range, max_range, cond_expr in sym.ranges:
                     if kconfiglib.expr_value(cond_expr):
-                        greatest_range = [int(min_range.str_value), int(max_range.str_value)]
+                        base = 16 if sym.type == kconfiglib.HEX else 10
+                        greatest_range = [int(min_range.str_value, base), int(max_range.str_value, base)]
+                    break
 
             new_json = {
                 "type": kconfiglib.TYPE_TO_STR[sym.type],
index 6462fe82de2c833acaa1c8c6e5f7721263ae882b..8529fd5208a0b4e6e541ff5200dc23e2e077aa69 100644 (file)
@@ -41,6 +41,12 @@ menu "Test config"
         range 0 10
         default 1
 
+    config TEST_CONDITIONAL_HEX_RANGES
+        hex "Something with a hex range"
+        range 0x00 0xaf if TEST_BOOL
+        range 0x10 0xaf
+        default 0xa0
+
     config SUBMENU_TRIGGER
         bool "I enable/disable some submenu items"
         default y
index 4563d4928062d0bd5054a38f3dbba2e32d052ede..0f68536cc072c5cc03c1f392534dd007ce46db7f 100644 (file)
@@ -1,6 +1,6 @@
 * Set TEST_BOOL, showing child items
 > { "TEST_BOOL" : true }
-< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100]} }
+< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100], "TEST_CONDITIONAL_HEX_RANGES": [0, 175]} }
 
 * Set TEST_CHILD_STR
 > { "TEST_CHILD_STR" : "Other value" }
@@ -8,7 +8,7 @@
 
 * Clear TEST_BOOL, hiding child items
 > { "TEST_BOOL" : false }
-< { "values" : { "TEST_BOOL" : false, "TEST_CHILD_STR" : null, "TEST_CHILD_BOOL" : null },  "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10]} }
+< { "values" : { "TEST_BOOL" : false, "TEST_CHILD_STR" : null, "TEST_CHILD_BOOL" : null },  "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10], "TEST_CONDITIONAL_HEX_RANGES": [16, 175]} }
 
 * Set TEST_CHILD_BOOL, invalid as parent is disabled
 > { "TEST_CHILD_BOOL" : false }
index 77d23bf66acac3d152f5bfc9d4395fb44c2a6bdf..7a735fd1a65f8b5e02b841a9ea991402825c7da4 100644 (file)
@@ -1,6 +1,6 @@
 * Set TEST_BOOL, showing child items
 > { "TEST_BOOL" : true }
-< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100]}, "visible": {"TEST_CHILD_BOOL" : true, "TEST_CHILD_STR" : true} }
+< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100], "TEST_CONDITIONAL_HEX_RANGES": [0, 175]}, "visible": {"TEST_CHILD_BOOL" : true, "TEST_CHILD_STR" : true} }
 
 * Set TEST_CHILD_STR
 > { "TEST_CHILD_STR" : "Other value" }
@@ -8,7 +8,7 @@
 
 * Clear TEST_BOOL, hiding child items
 > { "TEST_BOOL" : false }
-< { "values" : { "TEST_BOOL" : false },  "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10]}, "visible": { "TEST_CHILD_BOOL" : false, "TEST_CHILD_STR" : false } }
+< { "values" : { "TEST_BOOL" : false },  "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10], "TEST_CONDITIONAL_HEX_RANGES": [16, 175]}, "visible": { "TEST_CHILD_BOOL" : false, "TEST_CHILD_STR" : false } }
 
 * Set TEST_CHILD_BOOL, invalid as parent is disabled
 > { "TEST_CHILD_BOOL" : false }