]> granicus.if.org Git - esp-idf/commitdiff
ethernet: add iperf example to test real bandwidth
authormorris <maoshengrong@espressif.com>
Thu, 20 Sep 2018 11:26:14 +0000 (19:26 +0800)
committermorris <maoshengrong@espressif.com>
Mon, 8 Oct 2018 01:51:17 +0000 (09:51 +0800)
1. Add command for Ethernet based on console component.
2. Make cmd_system and iperf a component that can be referenced by other examples
3. Add "version" command to cmd_system.c
4. Clean up the README.md in all ethernet examples[TW#26525]

36 files changed:
.gitignore
components/ethernet/test/test_emac_deinit.c
examples/ethernet/ethernet/README.md
examples/ethernet/ethernet/main/Kconfig.projbuild
examples/ethernet/iperf/CMakeLists.txt [new file with mode: 0644]
examples/ethernet/iperf/Makefile [new file with mode: 0644]
examples/ethernet/iperf/README.md [new file with mode: 0644]
examples/ethernet/iperf/main/CMakeLists.txt [new file with mode: 0644]
examples/ethernet/iperf/main/Kconfig.projbuild [new file with mode: 0644]
examples/ethernet/iperf/main/cmd_decl.h [new file with mode: 0644]
examples/ethernet/iperf/main/cmd_ethernet.c [new file with mode: 0644]
examples/ethernet/iperf/main/cmd_ethernet.h [new file with mode: 0644]
examples/ethernet/iperf/main/component.mk [new file with mode: 0644]
examples/ethernet/iperf/main/iperf_example_main.c [new file with mode: 0644]
examples/ethernet/iperf/partitions_example.csv [new file with mode: 0644]
examples/ethernet/iperf/sdkconfig.defaults [new file with mode: 0644]
examples/system/console/components/cmd_system/CMakeLists.txt [new file with mode: 0644]
examples/system/console/components/cmd_system/cmd_system.c [moved from examples/system/console/main/cmd_system.c with 67% similarity]
examples/system/console/components/cmd_system/cmd_system.h [new file with mode: 0644]
examples/system/console/components/cmd_system/component.mk [new file with mode: 0644]
examples/system/console/main/CMakeLists.txt
examples/system/console/main/cmd_decl.h
examples/system/console/main/cmd_wifi.c
examples/system/console/main/cmd_wifi.h [new file with mode: 0644]
examples/wifi/iperf/CMakeLists.txt
examples/wifi/iperf/Makefile
examples/wifi/iperf/components/iperf.h [deleted file]
examples/wifi/iperf/components/iperf/CMakeLists.txt [moved from examples/wifi/iperf/components/CMakeLists.txt with 71% similarity]
examples/wifi/iperf/components/iperf/component.mk [moved from examples/wifi/iperf/components/component.mk with 88% similarity]
examples/wifi/iperf/components/iperf/iperf.c [moved from examples/wifi/iperf/components/iperf.c with 83% similarity]
examples/wifi/iperf/components/iperf/iperf.h [new file with mode: 0644]
examples/wifi/iperf/main/CMakeLists.txt
examples/wifi/iperf/main/cmd_decl.h
examples/wifi/iperf/main/cmd_wifi.c
examples/wifi/iperf/main/cmd_wifi.h [new file with mode: 0644]
examples/wifi/iperf/main/iperf_example_main.c [moved from examples/wifi/iperf/main/main.c with 91% similarity]

index 81317c33c39d4dd37db32b6463186b8e2c4172c2..3124eb003ae7db9669f9445b81a49d06d776a35a 100644 (file)
@@ -65,3 +65,5 @@ tools/windows/tool_setup/Output
 
 test_multi_heap_host
 
+# VS Code Settings
+.vscode/
index c9f7ee8cdede55320ff8aa16ffb42142381b3dae..370f7975b06b45b9b1aafb8ddf2dce2071ab9778 100644 (file)
@@ -24,7 +24,6 @@
 #include "tcpip_adapter.h"
 #include "driver/gpio.h"
 #include "driver/periph_ctrl.h"
-#include "esp_wifi.h"
 
 #include "eth_phy/phy_tlk110.h"
 
@@ -84,4 +83,4 @@ TEST_CASE("test emac deinit", "[ethernet][ignore]")
 
     ESP_ERROR_CHECK(esp_eth_disable());
     ESP_ERROR_CHECK(esp_eth_deinit());
-}
\ No newline at end of file
+}
index c79a1d0a10629d48e84b65741d0cb4ab589ee6c8..35b8d78e4db75cd884670dc3a43412a0737cc741 100644 (file)
 # Ethernet Example
-Initialises the Ethernet interface and enables it, then sends DHCP requests and tries to obtain a DHCP lease. If successful then you will be able to ping the device.
+(See the README.md file in the upper level 'examples' directory for more information about examples.)
 
-# PHY Configuration
-Use `make menuconfig` to set the PHY model and the PHY address, and configure the SMI I/O pins (see below). These configuration items will vary depending on the hardware configuration you are using.
+## Overview
 
-The default example configuration is correct for Espressif's Ethernet board with TLK110 PHY. Other hardware will require different configuration and/or changes to the example.
+This example demonstrates basic usage of `Ethernet driver` together with `tcpip_adapter`. The work flow of the example could be as follow:
 
-## PHY Address
-The PHY address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
+1. Initialises the Ethernet interface and enables it
+2. Send DHCP requests and tries to obtain a DHCP lease
+3. If successful then you will be able to ping the device
 
-* Address 31 (default) for Espressif's Ethernet board with TLK110 PHY
-* Address 1 for the common Waveshare LAN8720 PHY breakout
-* Address 0 for other LAN8720 breakouts
+If you have a new Ethernet applicaion to go (for example, connect to IoT cloud via Ethernet), try this as a basic template, then add your own code.
 
-If the PHY address is incorrect then the EMAC will initialise, but all attempts to read/write configuration registers on the PHY will fail.
+## How to use example
 
-## PHY Clock Wiring
-The ESP32 and the Ethernet PHY need a common 50MHz reference clock. This clock can either be be provided externally by a crystal oscillator (e.g. crystal connected to the PHY or a seperate crystal oscillator) or internally by using the EPS32's APLL.
+### Hardware Required
 
-Because of its freqency the signal integrity has to be observed (ringing, capacitive load, resisitive load, skew, length of PCB trace). It is recommended to add a 33Ω resistor in series to reduce ringing.
+To run this example, you should have one ESP32 dev board integrated with an Ethernet interface, or just connect your ESP32 core board to a breakout board which featured in RMII Etherent PHY. Currently esp-idf officially support only two Ethernet PHY: `TLK110` from Texas Instruments and `LAN8720` from microchip.
 
-Possible configurations of the 50MHz clock signal:
+### Configure the project
 
-| Mode     | GPIO Pin | Signal name    | Notes                                                                                              |
-| -------- | -------- | -------------- | -------------------------------------------------------------------------------------------------- |
-| external | `GPIO0`  | `EMAC_TX_CLK`  | Input of 50MHz PHY clock                                                                           |
-| internal | `GPIO16` | `EMAC_CLK_OUT` | Output of 50MHz APLL clock.                                                                        |
-| internal | `GPIO17` | `EMAC_CLK_180` | Inverted output of 50MHz APLL clock. Found to be best suitable for LAN8720 with long signal lines. |
+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. Then go into `Example Configuration` menu.
 
+* Choose PHY device under `Ethernet PHY option` option
 
-#### External PHY Clock
-The external reference clock of 50MHz must be supplied on `GPIO0`. See note about `GPIO0` below.
+* Set PHY address under `PHY address` option, this address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
+  * Address 31 (default) for Espressif's Ethernet board with TLK110 PHY by default
+  * Address 1 for the common Waveshare LAN8720 PHY breakout
+  * Address 0 for other LAN8720 breakouts
 
-#### Internal PHY Clock
-The ESP32 can generate a 50MHz clock using its APLL. When the APLL is already used as clock source for other purposes (most likely I²S) external PHY has to be used.
+* Check whether or not to control PHY's power (if true, you need also to set PHY Power GPIO number later)
 
-The inverted clock signal `EMAC_CLK_180` was found working best with a LAN8720 PHY.
+* Set SMI MDC/MDIO GPIO number according to board schemetic, default these two GPIOs are set as below:
 
-## RMII PHY Wiring
-The following PHY connections are required for RMII PHY data connections. These `GPIO` pin assignments cannot be changed.
+  | Default Example GPIO | RMII Signal | Notes         |
+  | -------------------- | ----------- | ------------- |
+  | GPIO23               | MDC         | Output to PHY |
+  | GPIO18               | MDIO        | Bidirectional |
 
-| GPIO     | RMII Signal | ESP32 EMAC Function | Notes |
-| -------- | ----------- | ------------------- | ----- |
-| `GPIO21` | `TX_EN`     | `EMAC_TX_EN`        |       |
-| `GPIO19` | `TX0`       | `EMAC_TXD0`         |       |
-| `GPIO22` | `TX1`       | `EMAC_TXD1`         |       |
-| `GPIO25` | `RX0`       | `EMAC_RXD0`         |       |
-| `GPIO26` | `RX1`       | `EMAC_RXD1`         |       |
-| `GPIO27` | `CRS_DV`    | `EMAC_RX_DRV`       |       |
+* Select one kind of EMAC clock mode under `EMAC clock mode` option. Possible configurations of the clock are listed as below:
 
-## RMII PHY SMI Wiring
+  | Mode     | GPIO Pin | Signal name  | Notes                                                        |
+  | -------- | -------- | ------------ | ------------------------------------------------------------ |
+  | external | GPIO0    | EMAC_TX_CLK  | Input of 50MHz PHY clock                                     |
+  | internal | GPIO16   | EMAC_CLK_OUT | Output of 50MHz APLL clock                                   |
+  | internal | GPIO17   | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) |
 
-The following PHY connections are required for RMII PHY SMI (aka MDIO) management interface. These GPIO pin assignments can be changed to any unused GPIO pin.
+  * The external reference clock of 50MHz must be supplied on `GPIO0`.
+  * The ESP32 can generate a 50MHz clock using its APLL. When the APLL is already used as clock source for other purposes (most likely I²S), you have no choice but choose external clock.
 
-For the example, these pins are configured via `make menuconfig` under the Example configuration.
+### Build and Flash
 
-| Default Example GPIO | RMII Signal | Notes         |
-| -------------------- | ----------- | ------------- |
-| `GPIO23`             | `MDC`       | Output to PHY |
-| `GPIO18`             | `MDIO`      | Bidirectional |
+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.
 
-The defaults in the example are correct for Espressif's Ethernet development board.
+(To exit the serial monitor, type ``Ctrl-]``.)
 
-## Note about `GPIO0`
+See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
 
-Because `GPIO0` is a strapping pin for entering UART flashing mode on reset, care must be taken when also using this pin as `EMAC_TX_CLK`. If the clock output from the PHY is oscillating during reset, the ESP32 may randomly enter UART flashing mode.
+## Example Output
 
-One solution is to use an additional GPIO as a "power pin", which either powers the PHY on/off or enables/disables the PHY's own oscillator. This prevents the clock signal from being active during a system reset. For this configuration to work, `GPIO0` also needs a pullup resistor and the "power pin" GPIO will need a pullup/pulldown resistor - as appropriate in order to keep the PHY clock disabled when the ESP32 is in reset.
+```bash
+I (0) cpu_start: App cpu up.
+I (281) heap_init: Initializing. RAM available for dynamic allocation:
+I (288) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
+I (294) heap_init: At 3FFB4358 len 0002BCA8 (175 KiB): DRAM
+I (300) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
+I (307) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
+I (313) heap_init: At 4008966C len 00016994 (90 KiB): IRAM
+I (319) cpu_start: Pro cpu start user code
+I (113) cpu_start: Starting scheduler on PRO CPU.
+I (0) cpu_start: Starting scheduler on APP CPU.
+I (116) eth_example: Power On Ethernet PHY
+I (126) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
+I (126) emac: emac reset done
+I (126) eth_example: Ethernet Started
+I (2126) eth_example: Ethernet Link Up
+I (11616) event: eth ip: 192.168.2.156, mask: 255.255.255.0, gw: 192.168.2.2
+I (11616) eth_example: Ethernet Got IP Addr
+I (11616) eth_example: ~~~~~~~~~~~
+I (11616) eth_example: ETHIP:192.168.2.156
+I (11626) eth_example: ETHMASK:255.255.255.0
+I (11626) eth_example: ETHGW:192.168.2.2
+I (11636) eth_example: ~~~~~~~~~~~
+```
 
-See the example source code to see how the "power pin" GPIO can be managed in software.
+## Troubleshooting
+
+* If the PHY address is incorrect then the EMAC will still be initialised, but all attempts to read/write configuration registers in the PHY's register will fail, for example, waiting for auto-negotiation done.
+
+* Check PHY Clock
+
+  > The ESP32's MAC and the External PHY device need a common 50MHz reference clock. This clock can either be provided externally by a crystal oscillator (e.g. crystal connected to the PHY or a seperate crystal oscillator) or internally by generating from EPS32's APLL. The signal integrity of this clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce ringing.
+
+* Check GPIO connections, the RMII PHY wiring is fixed which can not be changed through either IOMUX or GPIO Matrix. They're described as below:
+
+  | GPIO   | RMII Signal | ESP32 EMAC Function |
+  | ------ | ----------- | ------------------- |
+  | GPIO21 | TX_EN       | EMAC_TX_EN          |
+  | GPIO19 | TX0         | EMAC_TXD0           |
+  | GPIO22 | TX1         | EMAC_TXD1           |
+  | GPIO25 | RX0         | EMAC_RXD0           |
+  | GPIO26 | RX1         | EMAC_RXD1           |
+  | GPIO27 | CRS_DV      | EMAC_RX_DRV         |
+
+* Check GPIO0
+
+  > GPIO0 is a strapping pin for entering UART flashing mode on reset, care must be taken when using this pin as `EMAC_TX_CLK`. If the clock output from the PHY is oscillating during reset, the ESP32 may randomly enter UART flashing mode. One solution is to use an additional GPIO as a "power pin", which either powers the PHY on/off or enables/disables the PHY's own oscillator. This prevents the clock signal from being active during a system reset. For this configuration to work, `GPIO0` also needs a pullup resistor and the "power pin" GPIO will need a pullup/pulldown resistor - as appropriate in order to keep the PHY clock disabled when the ESP32 is in reset. See the example source code to see how the "power pin" GPIO can be managed in software. The example defaults to using `GPIO17` for this function, but it can be overriden. On Espressif's Ethernet development board, `GPIO17` is the power pin used to enable/disable the PHY oscillator.
 
-The example defaults to using `GPIO17` for this function, but it can be overriden. On Espressif's Ethernet development board, `GPIO17` is the power pin used to enable/disable the PHY oscillator.
index 7ef25aeaeecf945e6dab7dd04a76708fd5948a1b..8526d516956a9561f2527842a91d6e9b17f97a3a 100644 (file)
@@ -33,7 +33,7 @@ choice PHY_CLOCK_MODE
     prompt "EMAC clock mode"
     default PHY_CLOCK_GPIO0_IN
     help
-        Select external (input on GPIO0) or internal (output on GPIO0, GPIO16 or GPIO17) clock
+        Select external (input on GPIO0) or internal (output on GPIO16 or GPIO17) clock
 
 
 config PHY_CLOCK_GPIO0_IN
diff --git a/examples/ethernet/iperf/CMakeLists.txt b/examples/ethernet/iperf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..347df08
--- /dev/null
@@ -0,0 +1,9 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/components
+                         $ENV{IDF_PATH}/examples/wifi/iperf/components)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(ethernet-iperf)
diff --git a/examples/ethernet/iperf/Makefile b/examples/ethernet/iperf/Makefile
new file mode 100644 (file)
index 0000000..73e0eac
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := ethernet-iperf
+
+EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/system/console/components
+EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/wifi/iperf/components
+
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/ethernet/iperf/README.md b/examples/ethernet/iperf/README.md
new file mode 100644 (file)
index 0000000..a999095
--- /dev/null
@@ -0,0 +1,176 @@
+# Ethernet iperf example
+
+(See the README.md file in the upper level 'examples' directory for more information about examples.)
+
+## Overview
+
+This example demonstrates basic usage of [iperf](https://iperf.fr/) protocol to measure the throughout/bandwidth of Ethernet.
+
+This example is based on esp-idf's console component. For more information about console you can read the [guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/console.html).
+
+## How to use example
+
+### Prepare work
+
+1. Install iperf tool on PC
+   * Debian/Ubuntu: `sudo apt-get install iperf` 
+   * macOS: `brew install iperf`(if using Homebrew) or `sudo port install iperf`(if using MacPorts)
+   * Windows(MSYS2): Downloads binaries from [here]( https://iperf.fr/iperf-download.php#windows)
+2. Initialise Ethernet on ESP32, run `ethernet start`
+3. Get ip information(optional), run `ethernet info`
+
+### Configure the project
+
+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. Then go into `Example Configuration` menu.
+
+* Check whether or not to store the history command into flash under `Store command history in flash` option
+
+* Set PHY address under `PHY address` option, this address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
+
+  - Address 31 (default) for Espressif's Ethernet board with TLK110 PHY by default
+  - Address 1 for the common Waveshare LAN8720 PHY breakout
+  - Address 0 for other LAN8720 breakouts
+
+* Check whether or not to control PHY's power (if true, you need also to set PHY Power GPIO number later)
+
+* Set SMI MDC/MDIO GPIO number according to board schemetic, default these two GPIOs are set as below:
+
+  | Default Example GPIO | RMII Signal | Notes         |
+  | -------------------- | ----------- | ------------- |
+  | GPIO23               | MDC         | Output to PHY |
+  | GPIO18               | MDIO        | Bidirectional |
+
+* Select one kind of EMAC clock mode under `EMAC clock mode` option. Possible configurations of the clock are listed as below:
+
+  | Mode     | GPIO Pin | Signal name  | Notes                                                        |
+  | -------- | -------- | ------------ | ------------------------------------------------------------ |
+  | external | GPIO0    | EMAC_TX_CLK  | Input of 50MHz PHY clock                                     |
+  | internal | GPIO16   | EMAC_CLK_OUT | Output of 50MHz APLL clock                                   |
+  | internal | GPIO17   | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) |
+
+  - The external reference clock of 50MHz must be supplied on `GPIO0`.
+  - The ESP32 can generate a 50MHz clock using its APLL. When the APLL is already used as clock source for other purposes (most likely I²S), you have no choice but choose external clock.
+
+### 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.
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+### Test uplink bandwidth
+
+* PC: run command: `iperf -u -s -i 3` to start iperf server in UDP mode, and report interval is 3 seconds.
+* ESP32: run command: `iperf -u -c PC_IP -i 3 -t 30` to start iperf client in UDP mode, and the test will last 30 seconds.
+
+#### PC output
+
+```bash
+------------------------------------------------------------
+Server listening on UDP port 5001
+Receiving 1470 byte datagrams
+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%)
+```
+
+#### ESP32 output
+
+```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
+```
+
+### Test downlink bandwidth
+
+* PC: run command: `iperf -u -c ESP_IP -b 80M -t 30 -i 3` to start iperf client in UDP mode with estimated bandwidth 100M, and report interval is 3 seconds.
+* ESP32: run command: `iperf -u -s -t 30 -i 3` to start iperf server in UDP mode, and the test will last 30 seconds.
+
+#### PC output
+```bash
+------------------------------------------------------------
+Client connecting to 192.168.2.156, UDP port 5001
+Sending 1470 byte datagrams
+UDP buffer size:  208 KByte (default)
+------------------------------------------------------------
+[  3] local 192.168.2.160 port 59581 connected with 192.168.2.156 port 5001
+[ ID] Interval       Transfer     Bandwidth
+[  3]  0.0- 3.0 sec  28.6 MBytes  80.0 Mbits/sec
+[  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] 24.0-27.0 sec  28.6 MBytes  80.0 Mbits/sec
+```
+
+#### ESP32 output
+```bash
+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
+```
+
+## Suggestions of getting higher bandwidth
+
+1. Higher MCU working frequency will get higher bandwidth
+2. Put frequency invoked function into IRAM via macro `IRAM_ATTR` in code.
+3. Priority of iperf task may also have effect.
+
+## Troubleshooting
+
+- If the PHY address is incorrect then the EMAC will still be initialised, but all attempts to read/write configuration registers in the PHY's register will fail, for example, waiting for auto-negotiation done.
+
+- Check PHY Clock
+
+  > The ESP32's MAC and the External PHY device need a common 50MHz reference clock. This clock can either be provided externally by a crystal oscillator (e.g. crystal connected to the PHY or a seperate crystal oscillator) or internally by generating from EPS32's APLL. The signal integrity of this clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce ringing.
+
+- Check GPIO connections, the RMII PHY wiring is fixed which can not be changed through either IOMUX or GPIO Matrix. They're described as below:
+
+  | GPIO   | RMII Signal | ESP32 EMAC Function |
+  | ------ | ----------- | ------------------- |
+  | GPIO21 | TX_EN       | EMAC_TX_EN          |
+  | GPIO19 | TX0         | EMAC_TXD0           |
+  | GPIO22 | TX1         | EMAC_TXD1           |
+  | GPIO25 | RX0         | EMAC_RXD0           |
+  | GPIO26 | RX1         | EMAC_RXD1           |
+  | GPIO27 | CRS_DV      | EMAC_RX_DRV         |
+
+- Check GPIO0
+
+  > GPIO0 is a strapping pin for entering UART flashing mode on reset, care must be taken when using this pin as `EMAC_TX_CLK`. If the clock output from the PHY is oscillating during reset, the ESP32 may randomly enter UART flashing mode. One solution is to use an additional GPIO as a "power pin", which either powers the PHY on/off or enables/disables the PHY's own oscillator. This prevents the clock signal from being active during a system reset. For this configuration to work, `GPIO0` also needs a pullup resistor and the "power pin" GPIO will need a pullup/pulldown resistor - as appropriate in order to keep the PHY clock disabled when the ESP32 is in reset. See the example source code to see how the "power pin" GPIO can be managed in software. The example defaults to using `GPIO17` for this function, but it can be overriden. On Espressif's Ethernet development board, `GPIO17` is the power pin used to enable/disable the PHY oscillator.
\ No newline at end of file
diff --git a/examples/ethernet/iperf/main/CMakeLists.txt b/examples/ethernet/iperf/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..16ecc32
--- /dev/null
@@ -0,0 +1,5 @@
+set(COMPONENT_SRCS "cmd_ethernet.c"
+                   "iperf_example_main.c")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
diff --git a/examples/ethernet/iperf/main/Kconfig.projbuild b/examples/ethernet/iperf/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..0a94d49
--- /dev/null
@@ -0,0 +1,91 @@
+menu "Example Configuration"
+
+config STORE_HISTORY
+    bool "Store command history in flash"
+    default y
+    help
+        Linenoise line editing library provides functions to save and load
+        command history. If this option is enabled, initalizes a FAT filesystem
+        and uses it to store command history.
+
+menu "Etherent PHY Device"
+choice PHY_MODEL
+    prompt "Ethernet PHY"
+    default CONFIG_PHY_TLK110
+    help
+        Select the PHY driver to use for the example.
+config PHY_TLK110
+    bool "TI TLK110 PHY"
+    help
+        Select this to use the TI TLK110 PHY
+config PHY_LAN8720
+    bool "Microchip LAN8720 PHY"
+    help
+        Select this to use the Microchip LAN8720 PHY
+endchoice
+
+config PHY_ADDRESS
+    int "PHY Address (0-31)"
+    default 31
+    range 0 31
+    help
+        Set the PHY Address (0-31) for the hardware configuration.
+
+choice PHY_CLOCK_MODE
+    prompt "EMAC clock mode"
+    default PHY_CLOCK_GPIO0_IN
+    help
+        Select external (input on GPIO0) or internal (output on GPIO16 or GPIO17) clock
+config PHY_CLOCK_GPIO0_IN
+    bool "GPIO0 input"
+    help
+        Input of 50MHz refclock on GPIO0
+config PHY_CLOCK_GPIO16_OUT
+    bool "GPIO16 output"
+    help
+        Output the internal 50MHz APLL clock on GPIO16
+config PHY_CLOCK_GPIO17_OUT
+    bool "GPIO17 output (inverted)"
+    help
+        Output the internal 50MHz APLL clock on GPIO17 (inverted signal)
+endchoice
+
+config PHY_CLOCK_MODE
+    int
+    default 0 if PHY_CLOCK_GPIO0_IN
+    default 2 if PHY_CLOCK_GPIO16_OUT
+    default 3 if PHY_CLOCK_GPIO17_OUT
+
+config PHY_USE_POWER_PIN
+    bool "Use PHY Power (enable/disable) pin"
+    default y
+    help
+        Use a GPIO "power pin" to power the PHY on/off during operation.
+
+if PHY_USE_POWER_PIN
+config PHY_POWER_PIN
+    int "PHY Power GPIO"
+    default 17
+    range 0 33
+    help
+        GPIO number to use for powering on/off the PHY.
+endif
+endmenu
+
+menu "Etherent SMI interface"
+config PHY_SMI_MDC_PIN
+    int "SMI MDC Pin"
+    default 23
+    range 0 33
+    help
+        GPIO number to use for SMI clock output MDC to PHY.
+
+config PHY_SMI_MDIO_PIN
+    int "SMI MDIO Pin"
+    default 18
+    range 0 33
+    help
+       GPIO number to use for SMI data pin MDIO to/from PHY.
+endmenu
+
+endmenu
diff --git a/examples/ethernet/iperf/main/cmd_decl.h b/examples/ethernet/iperf/main/cmd_decl.h
new file mode 100644 (file)
index 0000000..ca84f56
--- /dev/null
@@ -0,0 +1,20 @@
+/* Console example — declarations of command registration functions.
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cmd_system.h"
+#include "cmd_ethernet.h"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/examples/ethernet/iperf/main/cmd_ethernet.c b/examples/ethernet/iperf/main/cmd_ethernet.c
new file mode 100644 (file)
index 0000000..f8a80a3
--- /dev/null
@@ -0,0 +1,286 @@
+/* Console example — Ethernet commands
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#include <stdio.h>
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/event_groups.h"
+#include "tcpip_adapter.h"
+#include "esp_log.h"
+#include "esp_console.h"
+#include "esp_event_loop.h"
+#include "esp_eth.h"
+#include "argtable3/argtable3.h"
+#include "iperf.h"
+#include "sdkconfig.h"
+
+#ifdef CONFIG_PHY_LAN8720
+#include "eth_phy/phy_lan8720.h"
+#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
+#endif
+#ifdef CONFIG_PHY_TLK110
+#include "eth_phy/phy_tlk110.h"
+#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
+#endif
+
+static tcpip_adapter_ip_info_t ip;
+static bool started = false;
+static EventGroupHandle_t eth_event_group;
+static const int GOTIP_BIT = BIT0;
+
+#define PIN_PHY_POWER CONFIG_PHY_POWER_PIN
+#define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
+#define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
+
+#ifdef CONFIG_PHY_USE_POWER_PIN
+
+static void phy_device_power_enable_via_gpio(bool enable)
+{
+    assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
+
+    if (!enable) {
+        DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
+    }
+
+    gpio_pad_select_gpio(PIN_PHY_POWER);
+    gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
+    if (enable == true) {
+        gpio_set_level(PIN_PHY_POWER, 1);
+        ESP_LOGI(__func__, "Power On Ethernet PHY");
+    } else {
+        gpio_set_level(PIN_PHY_POWER, 0);
+        ESP_LOGI(__func__, "Power Off Ethernet PHY");
+    }
+
+    vTaskDelay(1); // Allow the power up/down to take effect, min 300us
+
+    if (enable) {
+        /* call the default PHY-specific power on function */
+        DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
+    }
+}
+#endif
+
+static void eth_gpio_config_rmii(void)
+{
+    phy_rmii_configure_data_interface_pins();
+    phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
+}
+
+/* "ethernet" command */
+
+static struct {
+    struct arg_str *control;
+    struct arg_end *end;
+} eth_control_args;
+
+static int eth_cmd_control(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **)&eth_control_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, eth_control_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!strncmp(eth_control_args.control->sval[0], "start", 5) && !started) {
+        ESP_ERROR_CHECK(esp_eth_enable());
+        started = true;
+    }
+    if (!strncmp(eth_control_args.control->sval[0], "stop", 4) && started) {
+        ESP_ERROR_CHECK(esp_eth_disable());
+        started = false;
+    }
+    if (!strncmp(eth_control_args.control->sval[0], "info", 4)) {
+        uint8_t mac_addr[6];
+        esp_eth_get_mac(mac_addr);
+        printf("HW ADDR: " MACSTR "\r\n", MAC2STR(mac_addr));
+        tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip);
+        printf("ETHIP: " IPSTR "\r\n", IP2STR(&ip.ip));
+        printf("ETHMASK: " IPSTR "\r\n", IP2STR(&ip.netmask));
+        printf("ETHGW: " IPSTR "\r\n", IP2STR(&ip.gw));
+    }
+    return 0;
+}
+
+/* "iperf" command */
+
+static struct {
+    struct arg_str *ip;
+    struct arg_lit *server;
+    struct arg_lit *udp;
+    struct arg_int *port;
+    struct arg_int *interval;
+    struct arg_int *time;
+    struct arg_lit *abort;
+    struct arg_end *end;
+} iperf_args;
+
+static int eth_cmd_iperf(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
+    iperf_cfg_t cfg;
+
+    if (nerrors != 0) {
+        arg_print_errors(stderr, iperf_args.end, argv[0]);
+        return 0;
+    }
+
+    memset(&cfg, 0, sizeof(cfg));
+
+    /* iperf -a */
+    if (iperf_args.abort->count != 0) {
+        iperf_stop();
+        return 0;
+    }
+
+    if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
+            ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0))) {
+        ESP_LOGE(__func__, "Wrong mode! ESP32 should run in client or server mode");
+        return 0;
+    }
+
+    /* iperf -s */
+    if (iperf_args.ip->count == 0) {
+        cfg.flag |= IPERF_FLAG_SERVER;
+    }
+    /* iperf -c SERVER_ADDRESS */
+    else {
+        cfg.dip = ipaddr_addr(iperf_args.ip->sval[0]);
+        cfg.flag |= IPERF_FLAG_CLIENT;
+    }
+
+    /* acquiring for ip, could blocked here */
+    xEventGroupWaitBits(eth_event_group, GOTIP_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
+
+    cfg.sip = ip.ip.addr;
+    if (cfg.sip == 0) {
+        return 0;
+    }
+
+    /* iperf -u */
+    if (iperf_args.udp->count == 0) {
+        cfg.flag |= IPERF_FLAG_TCP;
+    } else {
+        cfg.flag |= IPERF_FLAG_UDP;
+    }
+
+    /* iperf -p */
+    if (iperf_args.port->count == 0) {
+        cfg.sport = IPERF_DEFAULT_PORT;
+        cfg.dport = IPERF_DEFAULT_PORT;
+    } else {
+        if (cfg.flag & IPERF_FLAG_SERVER) {
+            cfg.sport = iperf_args.port->ival[0];
+            cfg.dport = IPERF_DEFAULT_PORT;
+        } else {
+            cfg.sport = IPERF_DEFAULT_PORT;
+            cfg.dport = iperf_args.port->ival[0];
+        }
+    }
+
+    /* iperf -i */
+    if (iperf_args.interval->count == 0) {
+        cfg.interval = IPERF_DEFAULT_INTERVAL;
+    } else {
+        cfg.interval = iperf_args.interval->ival[0];
+        if (cfg.interval <= 0) {
+            cfg.interval = IPERF_DEFAULT_INTERVAL;
+        }
+    }
+
+    /* iperf -t */
+    if (iperf_args.time->count == 0) {
+        cfg.time = IPERF_DEFAULT_TIME;
+    } else {
+        cfg.time = iperf_args.time->ival[0];
+        if (cfg.time <= cfg.interval) {
+            cfg.time = cfg.interval;
+        }
+    }
+
+    printf("mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d\r\n",
+           cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
+           cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
+           cfg.sip & 0xFF, (cfg.sip >> 8) & 0xFF, (cfg.sip >> 16) & 0xFF, (cfg.sip >> 24) & 0xFF, cfg.sport,
+           cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport,
+           cfg.interval, cfg.time);
+
+    iperf_start(&cfg);
+    return 0;
+}
+
+static esp_err_t eth_event_handler(void *ctx, system_event_t *event)
+{
+    switch (event->event_id) {
+    case SYSTEM_EVENT_ETH_START:
+        started = true;
+        break;
+    case SYSTEM_EVENT_ETH_GOT_IP:
+        memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
+        ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip));
+        xEventGroupSetBits(eth_event_group, GOTIP_BIT);
+        break;
+    case SYSTEM_EVENT_ETH_STOP:
+        xEventGroupClearBits(eth_event_group, GOTIP_BIT);
+        started = false;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+void register_ethernet()
+{
+    eth_event_group = xEventGroupCreate();
+    tcpip_adapter_init();
+    ESP_ERROR_CHECK(esp_event_loop_init(eth_event_handler, NULL));
+
+    eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
+    config.phy_addr = CONFIG_PHY_ADDRESS;
+    config.gpio_config = eth_gpio_config_rmii;
+    config.tcpip_input = tcpip_adapter_eth_input;
+    config.clock_mode = CONFIG_PHY_CLOCK_MODE;
+#ifdef CONFIG_PHY_USE_POWER_PIN
+    /* Replace the default 'power enable' function with an example-specific one
+     that toggles a power GPIO. */
+    config.phy_power_enable = phy_device_power_enable_via_gpio;
+#endif
+
+    ESP_ERROR_CHECK(esp_eth_init(&config));
+
+    eth_control_args.control = arg_str1(NULL, NULL, "<start|stop|info>", "Start/Stop Ethernet or Get info of Ethernet");
+    eth_control_args.end = arg_end(1);
+    const esp_console_cmd_t cmd = {
+        .command = "ethernet",
+        .help = "Control Ethernet interface",
+        .hint = NULL,
+        .func = eth_cmd_control,
+        .argtable = &eth_control_args
+    };
+    ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
+
+    iperf_args.ip = arg_str0("c", "client", "<ip>",
+                             "run in client mode, connecting to <host>");
+    iperf_args.server = arg_lit0("s", "server", "run in server mode");
+    iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
+    iperf_args.port = arg_int0("p", "port", "<port>",
+                               "server port to listen on/connect to");
+    iperf_args.interval = arg_int0("i", "interval", "<interval>",
+                                   "seconds between periodic bandwidth reports");
+    iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
+    iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
+    iperf_args.end = arg_end(1);
+    const esp_console_cmd_t iperf_cmd = {
+        .command = "iperf",
+        .help = "iperf command",
+        .hint = NULL,
+        .func = &eth_cmd_iperf,
+        .argtable = &iperf_args
+    };
+    ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
+}
diff --git a/examples/ethernet/iperf/main/cmd_ethernet.h b/examples/ethernet/iperf/main/cmd_ethernet.h
new file mode 100644 (file)
index 0000000..bd619c7
--- /dev/null
@@ -0,0 +1,20 @@
+/* Console example — declarations of command registration functions.
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register Ethernet functions
+void register_ethernet();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/examples/ethernet/iperf/main/component.mk b/examples/ethernet/iperf/main/component.mk
new file mode 100644 (file)
index 0000000..0b9d758
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
diff --git a/examples/ethernet/iperf/main/iperf_example_main.c b/examples/ethernet/iperf/main/iperf_example_main.c
new file mode 100644 (file)
index 0000000..b36ea12
--- /dev/null
@@ -0,0 +1,194 @@
+/* Console example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+#include "driver/uart.h"
+#include "linenoise/linenoise.h"
+#include "argtable3/argtable3.h"
+#include "cmd_decl.h"
+#include "esp_vfs_fat.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "sdkconfig.h"
+
+static const char *TAG = "ethernet-console";
+
+#if CONFIG_STORE_HISTORY
+
+#define MOUNT_PATH "/data"
+#define HISTORY_PATH MOUNT_PATH "/history.txt"
+
+static void initialize_filesystem()
+{
+    static wl_handle_t wl_handle;
+    const esp_vfs_fat_mount_config_t mount_config = {
+        .max_files = 4,
+        .format_if_mount_failed = true
+    };
+    esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
+        return;
+    }
+}
+#endif // CONFIG_STORE_HISTORY
+
+static void initialize_nvs()
+{
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(err);
+}
+
+static void initialize_console()
+{
+    /* Disable buffering on stdin and stdout */
+    setvbuf(stdin, NULL, _IONBF, 0);
+    setvbuf(stdout, NULL, _IONBF, 0);
+
+    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
+    esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+    /* Move the caret to the beginning of the next line on '\n' */
+    esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+    /* Configure UART. Note that REF_TICK is used so that the baud rate remains
+     * correct while APB frequency is changing in light sleep mode.
+     */
+    const uart_config_t uart_config = {
+        .baud_rate = CONFIG_CONSOLE_UART_BAUDRATE,
+        .data_bits = UART_DATA_8_BITS,
+        .parity = UART_PARITY_DISABLE,
+        .stop_bits = UART_STOP_BITS_1,
+        .use_ref_tick = true
+    };
+    ESP_ERROR_CHECK(uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config));
+
+    /* Install UART driver for interrupt-driven reads and writes */
+    ESP_ERROR_CHECK(uart_driver_install(CONFIG_CONSOLE_UART_NUM,
+                                        256, 0, 0, NULL, 0));
+
+    /* Tell VFS to use UART driver */
+    esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+
+    /* Initialize the console */
+    esp_console_config_t console_config = {
+        .max_cmdline_args = 8,
+        .max_cmdline_length = 256,
+#if CONFIG_LOG_COLORS
+        .hint_color = atoi(LOG_COLOR_CYAN)
+#endif
+    };
+    ESP_ERROR_CHECK(esp_console_init(&console_config));
+
+    /* Configure linenoise line completion library */
+    linenoiseSetMultiLine(1);
+
+    /* Tell linenoise where to get command completions and hints */
+    linenoiseSetCompletionCallback(&esp_console_get_completion);
+    linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
+
+    /* Set command history size */
+    linenoiseHistorySetMaxLen(100);
+
+#if CONFIG_STORE_HISTORY
+    /* Load command history from filesystem */
+    linenoiseHistoryLoad(HISTORY_PATH);
+#endif
+}
+
+void app_main()
+{
+    initialize_nvs();
+
+#if CONFIG_STORE_HISTORY
+    initialize_filesystem();
+#endif
+
+    initialize_console();
+
+    /* Register commands */
+    esp_console_register_help_command();
+    register_system();
+    register_ethernet();
+
+    /* Prompt to be printed before each line.
+     * This can be customized, made dynamic, etc.
+     */
+    const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
+
+    printf("\n =======================================================\n");
+    printf(" |       Steps to Test Ethernet Bandwidth              |\n");
+    printf(" |                                                     |\n");
+    printf(" |  1. Enter 'help', check all supported commands      |\n");
+    printf(" |  2. Enter 'ethernet start'                          |\n");
+    printf(" |  3. Wait ESP32 to get IP from DHCP                  |\n");
+    printf(" |  4. Enter 'ethernet info', optional                 |\n");
+    printf(" |  4. Server: 'iperf -u -s -i 3'                      |\n");
+    printf(" |  4. Client: 'iperf -u -c SERVER_IP -t 60 -i 3'      |\n");
+    printf(" |                                                     |\n");
+    printf(" =======================================================\n\n");
+
+    /* Figure out if the terminal supports escape sequences */
+    int probe_status = linenoiseProbe();
+    if (probe_status) {
+        /* zero indicates success */
+        printf("\n"
+               "Your terminal application does not support escape sequences.\n"
+               "Line editing and history features are disabled.\n"
+               "On Windows, try using Putty instead.\n");
+        linenoiseSetDumbMode(1);
+#if CONFIG_LOG_COLORS
+        /* Since the terminal doesn't support escape sequences,
+         * don't use color codes in the prompt.
+         */
+        prompt = "esp32> ";
+#endif //CONFIG_LOG_COLORS
+    }
+
+    /* Main loop */
+    while (true) {
+        /* Get a line using linenoise.
+         * The line is returned when ENTER is pressed.
+         */
+        char *line = linenoise(prompt);
+        if (line == NULL) {
+            /* Ignore empty lines */
+            continue;
+        }
+        /* Add the command to the history */
+        linenoiseHistoryAdd(line);
+#if CONFIG_STORE_HISTORY
+        /* Save command history to filesystem */
+        linenoiseHistorySave(HISTORY_PATH);
+#endif
+
+        /* Try to run the command */
+        int ret;
+        esp_err_t err = esp_console_run(line, &ret);
+        if (err == ESP_ERR_NOT_FOUND) {
+            printf("Unrecognized command\n");
+        } else if (err == ESP_ERR_INVALID_ARG) {
+            // command was empty
+        } else if (err == ESP_OK && ret != ESP_OK) {
+            printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(err));
+        } else if (err != ESP_OK) {
+            printf("Internal error: %s\n", esp_err_to_name(err));
+        }
+        /* linenoise allocates line buffer on the heap, so need to free it */
+        linenoiseFree(line);
+    }
+}
diff --git a/examples/ethernet/iperf/partitions_example.csv b/examples/ethernet/iperf/partitions_example.csv
new file mode 100644 (file)
index 0000000..7e28b56
--- /dev/null
@@ -0,0 +1,6 @@
+# Name,   Type, SubType, Offset,  Size, Flags
+# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 1M,
+storage,  data, fat,     ,        1M, 
diff --git a/examples/ethernet/iperf/sdkconfig.defaults b/examples/ethernet/iperf/sdkconfig.defaults
new file mode 100644 (file)
index 0000000..74d1647
--- /dev/null
@@ -0,0 +1,27 @@
+# Reduce bootloader log verbosity
+CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y
+CONFIG_LOG_BOOTLOADER_LEVEL=2
+
+# Increase main task stack size
+CONFIG_MAIN_TASK_STACK_SIZE=7168
+
+# Enable filesystem
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
+CONFIG_APP_OFFSET=0x10000
+
+# Enable FreeRTOS stats formatting functions, needed for 'tasks' command
+CONFIG_FREERTOS_USE_TRACE_FACILITY=y
+CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+
+# ESP32-specific
+CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+
+# Ethernet
+CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE=y
+
diff --git a/examples/system/console/components/cmd_system/CMakeLists.txt b/examples/system/console/components/cmd_system/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b45a40c
--- /dev/null
@@ -0,0 +1,7 @@
+set(COMPONENT_ADD_INCLUDEDIRS .)
+
+set(COMPONENT_SRCS "cmd_system.c")
+
+set(COMPONENT_REQUIRES console spi_flash)
+
+register_component()
similarity index 67%
rename from examples/system/console/main/cmd_system.c
rename to examples/system/console/components/cmd_system/cmd_system.c
index 3bfa7f02893c7d32ac25c74a2a74d1a48499ce80..46d265a0374933d9dc02df88be8eb46657ae452a 100644 (file)
 #include "esp_console.h"
 #include "esp_system.h"
 #include "esp_sleep.h"
+#include "esp_spi_flash.h"
 #include "driver/rtc_io.h"
 #include "driver/uart.h"
 #include "argtable3/argtable3.h"
-#include "cmd_decl.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "soc/rtc_cntl_reg.h"
 #include "rom/uart.h"
+#include "cmd_system.h"
 #include "sdkconfig.h"
 
 #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
 #define WITH_TASKS_INFO 1
 #endif
 
+static const char *TAG = "cmd_system";
+
 static void register_free();
+static void register_heap();
+static void register_version();
 static void register_restart();
 static void register_deep_sleep();
 static void register_light_sleep();
@@ -40,6 +45,8 @@ static void register_tasks();
 void register_system()
 {
     register_free();
+    register_heap();
+    register_version();
     register_restart();
     register_deep_sleep();
     register_light_sleep();
@@ -49,11 +56,41 @@ void register_system()
 #endif
 }
 
+/* 'version' command */
+static int get_version(int argc, char **argv)
+{
+    esp_chip_info_t info;
+    esp_chip_info(&info);
+    printf("IDF Version:%s\r\n", esp_get_idf_version());
+    printf("Chip info:\r\n");
+    printf("\tmodel:%s\r\n", info.model == CHIP_ESP32 ? "ESP32" : "Unknow");
+    printf("\tcores:%d\r\n", info.cores);
+    printf("\tfeature:%s%s%s%s%d%s\r\n",
+           info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
+           info.features & CHIP_FEATURE_BLE ? "/BLE" : "",
+           info.features & CHIP_FEATURE_BT ? "/BT" : "",
+           info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:",
+           spi_flash_get_chip_size() / (1024 * 1024), " MB");
+    printf("\trevision number:%d\r\n", info.revision);
+    return 0;
+}
+
+static void register_version()
+{
+    const esp_console_cmd_t cmd = {
+        .command = "version",
+        .help = "Get version of chip and SDK",
+        .hint = NULL,
+        .func = &get_version,
+    };
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
+}
+
 /** 'restart' command restarts the program */
 
-static int restart(int argc, char** argv)
+static int restart(int argc, char **argv)
 {
-    ESP_LOGI(__func__, "Restarting");
+    ESP_LOGI(TAG, "Restarting");
     esp_restart();
 }
 
@@ -61,7 +98,7 @@ static void register_restart()
 {
     const esp_console_cmd_t cmd = {
         .command = "restart",
-        .help = "Restart the program",
+        .help = "Software reset of the chip",
         .hint = NULL,
         .func = &restart,
     };
@@ -70,7 +107,7 @@ static void register_restart()
 
 /** 'free' command prints available heap memory */
 
-static int free_mem(int argc, char** argv)
+static int free_mem(int argc, char **argv)
 {
     printf("%d\n", esp_get_free_heap_size());
     return 0;
@@ -80,22 +117,42 @@ static void register_free()
 {
     const esp_console_cmd_t cmd = {
         .command = "free",
-        .help = "Get the total size of heap memory available",
+        .help = "Get the current size of free heap memory",
         .hint = NULL,
         .func = &free_mem,
     };
     ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
 }
 
+/* 'heap' command prints minumum heap size */
+static int heap_size(int argc, char **argv)
+{
+    uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
+    ESP_LOGI(TAG, "min heap size: %u", heap_size);
+    return 0;
+}
+
+static void register_heap()
+{
+    const esp_console_cmd_t heap_cmd = {
+        .command = "heap",
+        .help = "Get minimum size of free heap memory that was available during program execution",
+        .hint = NULL,
+        .func = &heap_size,
+    };
+    ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
+
+}
+
 /** 'tasks' command prints the list of tasks and related information */
 #if WITH_TASKS_INFO
 
-static int tasks_info(int argc, char** argv)
+static int tasks_info(int argc, char **argv)
 {
     const size_t bytes_per_task = 40; /* see vTaskList description */
-    chartask_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
+    char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
     if (task_list_buffer == NULL) {
-        ESP_LOGE(__func__, "failed to allocate buffer for vTaskList output");
+        ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output");
         return 1;
     }
     fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
@@ -132,34 +189,34 @@ static struct {
 } deep_sleep_args;
 
 
-static int deep_sleep(int argc, char** argv)
+static int deep_sleep(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &deep_sleep_args);
+    int nerrors = arg_parse(argc, argv, (void **) &deep_sleep_args);
     if (nerrors != 0) {
         arg_print_errors(stderr, deep_sleep_args.end, argv[0]);
         return 1;
     }
     if (deep_sleep_args.wakeup_time->count) {
         uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0];
-        ESP_LOGI(__func__, "Enabling timer wakeup, timeout=%lluus", timeout);
+        ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout);
         ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
     }
     if (deep_sleep_args.wakeup_gpio_num->count) {
         int io_num = deep_sleep_args.wakeup_gpio_num->ival[0];
         if (!rtc_gpio_is_valid_gpio(io_num)) {
-            ESP_LOGE(__func__, "GPIO %d is not an RTC IO", io_num);
+            ESP_LOGE(TAG, "GPIO %d is not an RTC IO", io_num);
             return 1;
         }
         int level = 0;
         if (deep_sleep_args.wakeup_gpio_level->count) {
             level = deep_sleep_args.wakeup_gpio_level->ival[0];
             if (level != 0 && level != 1) {
-                ESP_LOGE(__func__, "Invalid wakeup level: %d", level);
+                ESP_LOGE(TAG, "Invalid wakeup level: %d", level);
                 return 1;
             }
         }
-        ESP_LOGI(__func__, "Enabling wakeup on GPIO%d, wakeup on %s level",
-                io_num, level ? "HIGH" : "LOW");
+        ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level",
+                 io_num, level ? "HIGH" : "LOW");
 
         ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) );
     }
@@ -170,19 +227,19 @@ static int deep_sleep(int argc, char** argv)
 static void register_deep_sleep()
 {
     deep_sleep_args.wakeup_time =
-            arg_int0("t", "time", "<t>", "Wake up time, ms");
+        arg_int0("t", "time", "<t>", "Wake up time, ms");
     deep_sleep_args.wakeup_gpio_num =
-            arg_int0(NULL, "io", "<n>",
-                     "If specified, wakeup using GPIO with given number");
+        arg_int0(NULL, "io", "<n>",
+                 "If specified, wakeup using GPIO with given number");
     deep_sleep_args.wakeup_gpio_level =
-            arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
+        arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
     deep_sleep_args.end = arg_end(3);
 
     const esp_console_cmd_t cmd = {
         .command = "deep_sleep",
         .help = "Enter deep sleep mode. "
-                "Two wakeup modes are supported: timer and GPIO. "
-                "If no wakeup option is specified, will sleep indefinitely.",
+        "Two wakeup modes are supported: timer and GPIO. "
+        "If no wakeup option is specified, will sleep indefinitely.",
         .hint = NULL,
         .func = &deep_sleep,
         .argtable = &deep_sleep_args
@@ -199,9 +256,9 @@ static struct {
     struct arg_end *end;
 } light_sleep_args;
 
-static int light_sleep(int argc, char** argv)
+static int light_sleep(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &light_sleep_args);
+    int nerrors = arg_parse(argc, argv, (void **) &light_sleep_args);
     if (nerrors != 0) {
         arg_print_errors(stderr, light_sleep_args.end, argv[0]);
         return 1;
@@ -209,23 +266,23 @@ static int light_sleep(int argc, char** argv)
     esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
     if (light_sleep_args.wakeup_time->count) {
         uint64_t timeout = 1000ULL * light_sleep_args.wakeup_time->ival[0];
-        ESP_LOGI(__func__, "Enabling timer wakeup, timeout=%lluus", timeout);
+        ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout);
         ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
     }
     int io_count = light_sleep_args.wakeup_gpio_num->count;
     if (io_count != light_sleep_args.wakeup_gpio_level->count) {
-        ESP_LOGE(__func__, "Should have same number of 'io' and 'io_level' arguments");
+        ESP_LOGE(TAG, "Should have same number of 'io' and 'io_level' arguments");
         return 1;
     }
     for (int i = 0; i < io_count; ++i) {
         int io_num = light_sleep_args.wakeup_gpio_num->ival[i];
         int level = light_sleep_args.wakeup_gpio_level->ival[i];
         if (level != 0 && level != 1) {
-            ESP_LOGE(__func__, "Invalid wakeup level: %d", level);
+            ESP_LOGE(TAG, "Invalid wakeup level: %d", level);
             return 1;
         }
-        ESP_LOGI(__func__, "Enabling wakeup on GPIO%d, wakeup on %s level",
-                io_num, level ? "HIGH" : "LOW");
+        ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level",
+                 io_num, level ? "HIGH" : "LOW");
 
         ESP_ERROR_CHECK( gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL) );
     }
@@ -233,7 +290,7 @@ static int light_sleep(int argc, char** argv)
         ESP_ERROR_CHECK( esp_sleep_enable_gpio_wakeup() );
     }
     if (CONFIG_CONSOLE_UART_NUM <= UART_NUM_1) {
-        ESP_LOGI(__func__, "Enabling UART wakeup (press ENTER to exit light sleep)");
+        ESP_LOGI(TAG, "Enabling UART wakeup (press ENTER to exit light sleep)");
         ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_CONSOLE_UART_NUM, 3) );
         ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_CONSOLE_UART_NUM) );
     }
@@ -241,43 +298,43 @@ static int light_sleep(int argc, char** argv)
     uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
     esp_light_sleep_start();
     esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
-    const charcause_str;
+    const char *cause_str;
     switch (cause) {
-        case ESP_SLEEP_WAKEUP_GPIO:
-            cause_str = "GPIO";
-            break;
-        case ESP_SLEEP_WAKEUP_UART:
-            cause_str = "UART";
-            break;
-        case ESP_SLEEP_WAKEUP_TIMER:
-            cause_str = "timer";
-            break;
-        default:
-            cause_str = "unknown";
-            printf("%d\n", cause);
+    case ESP_SLEEP_WAKEUP_GPIO:
+        cause_str = "GPIO";
+        break;
+    case ESP_SLEEP_WAKEUP_UART:
+        cause_str = "UART";
+        break;
+    case ESP_SLEEP_WAKEUP_TIMER:
+        cause_str = "timer";
+        break;
+    default:
+        cause_str = "unknown";
+        printf("%d\n", cause);
     }
-    ESP_LOGI(__func__, "Woke up from: %s", cause_str);
+    ESP_LOGI(TAG, "Woke up from: %s", cause_str);
     return 0;
 }
 
 static void register_light_sleep()
 {
     light_sleep_args.wakeup_time =
-            arg_int0("t", "time", "<t>", "Wake up time, ms");
+        arg_int0("t", "time", "<t>", "Wake up time, ms");
     light_sleep_args.wakeup_gpio_num =
-            arg_intn(NULL, "io", "<n>", 0, 8,
-                     "If specified, wakeup using GPIO with given number");
+        arg_intn(NULL, "io", "<n>", 0, 8,
+                 "If specified, wakeup using GPIO with given number");
     light_sleep_args.wakeup_gpio_level =
-            arg_intn(NULL, "io_level", "<0|1>", 0, 8, "GPIO level to trigger wakeup");
+        arg_intn(NULL, "io_level", "<0|1>", 0, 8, "GPIO level to trigger wakeup");
     light_sleep_args.end = arg_end(3);
 
     const esp_console_cmd_t cmd = {
         .command = "light_sleep",
         .help = "Enter light sleep mode. "
-                "Two wakeup modes are supported: timer and GPIO. "
-                "Multiple GPIO pins can be specified using pairs of "
-                "'io' and 'io_level' arguments. "
-                "Will also wake up on UART input.",
+        "Two wakeup modes are supported: timer and GPIO. "
+        "Multiple GPIO pins can be specified using pairs of "
+        "'io' and 'io_level' arguments. "
+        "Will also wake up on UART input.",
         .hint = NULL,
         .func = &light_sleep,
         .argtable = &light_sleep_args
@@ -287,7 +344,7 @@ static void register_light_sleep()
 
 /** This command helps maintain sanity when testing console example from a console */
 
-static int make(int argc, char** argv)
+static int make(int argc, char **argv)
 {
     int count = REG_READ(RTC_CNTL_STORE0_REG);
     if (++count >= 3) {
@@ -296,8 +353,8 @@ static int make(int argc, char** argv)
     }
     REG_WRITE(RTC_CNTL_STORE0_REG, count);
 
-    const charmake_output =
-R"(LD build/console.elf
+    const char *make_output =
+        R"(LD build/console.elf
 esptool.py v2.1-beta1
 )";
 
@@ -390,4 +447,3 @@ static void register_make()
     ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
 }
 
-
diff --git a/examples/system/console/components/cmd_system/cmd_system.h b/examples/system/console/components/cmd_system/cmd_system.h
new file mode 100644 (file)
index 0000000..be746a2
--- /dev/null
@@ -0,0 +1,20 @@
+/* Console example — various system commands
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register system functions
+void register_system();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/examples/system/console/components/cmd_system/component.mk b/examples/system/console/components/cmd_system/component.mk
new file mode 100644 (file)
index 0000000..e0e9f4c
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_ADD_INCLUDEDIRS := .
index 5f8bc46374c24de8dcb3d4247e0bc5112d0be6a2..b28588639086bc17d8233d594066175632f15c07 100644 (file)
@@ -1,5 +1,4 @@
-set(COMPONENT_SRCS "cmd_system.c"
-                   "cmd_wifi.c"
+set(COMPONENT_SRCS "cmd_wifi.c"
                    "console_example_main.c")
 set(COMPONENT_ADD_INCLUDEDIRS ".")
 
index 969d57dd2ba7791a25b66a2f003d019d09e560b5..efdda4e25e08dc5983446c28edc3d36427d8bf60 100644 (file)
@@ -8,8 +8,13 @@
 */
 #pragma once
 
-// Register system functions
-void register_system();
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-// Register WiFi functions
-void register_wifi();
+#include "cmd_system.h"
+#include "cmd_wifi.h"
+
+#ifdef __cplusplus
+}
+#endif
index f0da322477ddd683337556d16269fad689e0dade..52be40efd4affc891e51c26746c3519823f67b62 100644 (file)
@@ -18,6 +18,7 @@
 #include "esp_wifi.h"
 #include "tcpip_adapter.h"
 #include "esp_event_loop.h"
+#include "cmd_wifi.h"
 
 static EventGroupHandle_t wifi_event_group;
 const int CONNECTED_BIT = BIT0;
diff --git a/examples/system/console/main/cmd_wifi.h b/examples/system/console/main/cmd_wifi.h
new file mode 100644 (file)
index 0000000..a1a1655
--- /dev/null
@@ -0,0 +1,21 @@
+/* Console example — declarations of command registration functions.
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register WiFi functions
+void register_wifi();
+
+#ifdef __cplusplus
+}
+#endif
+
index 069eeae866a9dd7f73f30db399443bff7ced5fda..c6c13f2929c861c35ea4066cbf1f339218b9cec0 100644 (file)
@@ -2,5 +2,7 @@
 # in this exact order for cmake to work correctly
 cmake_minimum_required(VERSION 3.5)
 
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/components)
+
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 project(iperf)
index 46d657866e297a2fd436619ed4203b44eba4f5c2..bf2a3d1187acfff3a2bd08341ceb21479721827e 100644 (file)
@@ -5,4 +5,6 @@
 
 PROJECT_NAME := iperf
 
+EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/system/console/components
+
 include $(IDF_PATH)/make/project.mk
diff --git a/examples/wifi/iperf/components/iperf.h b/examples/wifi/iperf/components/iperf.h
deleted file mode 100644 (file)
index 1bbdaf1..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Iperf Example - iperf declaration
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-
-#ifndef __IPERF_H_
-#define __IPERF_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define IPERF_FLAG_CLIENT (1)
-#define IPERF_FLAG_SERVER (1<<1)
-#define IPERF_FLAG_TCP    (1<<2)
-#define IPERF_FLAG_UDP    (1<<3)
-
-#define IPERF_DEFAULT_PORT     5001
-#define IPERF_DEFAULT_INTERVAL 3
-#define IPERF_DEFAULT_TIME     30
-
-#define IPERF_TRAFFIC_TASK_NAME       "iperf_traffic"
-#define IPERF_TRAFFIC_TASK_PRIORITY   10
-#define IPERF_TRAFFIC_TASK_STACK      4096
-#define IPERF_REPORT_TASK_NAME        "iperf_report"
-#define IPERF_REPORT_TASK_PRIORITY    20
-#define IPERF_REPORT_TASK_STACK       4096
-#define IPERF_REPORT_TASK_NAME        "iperf_report"
-
-#define IPERF_UDP_TX_LEN     (1472)
-#define IPERF_UDP_RX_LEN     (16<<10)
-#define IPERF_TCP_TX_LEN     (16<<10)
-#define IPERF_TCP_RX_LEN     (16<<10)
-
-#define IPERF_MAX_DELAY      64
-
-#define IPERF_SOCKET_RX_TIMEOUT      10
-#define IPERF_SOCKET_ACCEPT_TIMEOUT  5
-
-typedef struct {
-    uint32_t flag;
-    uint32_t dip;
-    uint32_t sip;
-    uint16_t dport;
-    uint16_t sport;
-    uint32_t interval;
-    uint32_t time;
-} iperf_cfg_t;
-
-esp_err_t iperf_start(iperf_cfg_t *cfg);
-esp_err_t iperf_stop(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
similarity index 71%
rename from examples/wifi/iperf/components/CMakeLists.txt
rename to examples/wifi/iperf/components/iperf/CMakeLists.txt
index d51a810196474d6822061056a75a02fe78071329..11a8f571e2f3c64dd8229d99e2f96153008f6700 100644 (file)
@@ -2,6 +2,6 @@ set(COMPONENT_ADD_INCLUDEDIRS .)
 
 set(COMPONENT_SRCS "iperf.c")
 
-set(COMPONENT_PRIV_REQUIRES lwip)
+set(COMPONENT_REQUIRES lwip)
 
 register_component()
similarity index 88%
rename from examples/wifi/iperf/components/component.mk
rename to examples/wifi/iperf/components/iperf/component.mk
index da115f7d4b8bb7da70d37b114763859042e5d707..e5a56dfd569b22ad98345ce824a1d25aa6e6690c 100644 (file)
@@ -1,8 +1,8 @@
 #
 # Component Makefile
 #
-# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
-# this will take the sources in the src/ directory, compile them and link them into 
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
 # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
 # please read the SDK documents if you need to do this.
 #
similarity index 83%
rename from examples/wifi/iperf/components/iperf.c
rename to examples/wifi/iperf/components/iperf/iperf.c
index 80cadb400f444fa53fbcac3592ac5b754bf7b9bb..eb310ef74e9613f7afd7de7b213af922f6e5e0ba 100644 (file)
@@ -7,19 +7,20 @@
    CONDITIONS OF ANY KIND, either express or implied.
 */
 
-#include <sys/socket.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/socket.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
 #include "esp_log.h"
-
 #include "iperf.h"
 
 typedef struct {
     iperf_cfg_t cfg;
-    bool     finish;
+    bool finish;
     uint32_t total_len;
     uint32_t buffer_len;
-    uint8_t  *buffer;
+    uint8_t *buffer;
     uint32_t sockfd;
 } iperf_ctrl_t;
 
@@ -53,12 +54,13 @@ inline static bool iperf_is_tcp_server(void)
     return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
 }
 
-int iperf_get_socket_error_code(int sockfd)
+static int iperf_get_socket_error_code(int sockfd)
 {
     uint32_t optlen = sizeof(int);
     int result;
     int err;
 
+    /* get the error state, and clear it */
     err = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &optlen);
     if (err == -1) {
         ESP_LOGE(TAG, "getsockopt failed: ret=%d", err);
@@ -68,7 +70,7 @@ int iperf_get_socket_error_code(int sockfd)
     return result;
 }
 
-int iperf_show_socket_error_reason(const char *str, int sockfd)
+static int iperf_show_socket_error_reason(const char *str, int sockfd)
 {
     int err = iperf_get_socket_error_code(sockfd);
 
@@ -79,18 +81,19 @@ int iperf_show_socket_error_reason(const char *str, int sockfd)
     return err;
 }
 
-void iperf_report_task(void* arg)
+static void iperf_report_task(void *arg)
 {
-    TickType_t delay_interval = (s_iperf_ctrl.cfg.interval * 1000)/portTICK_RATE_MS;
     uint32_t interval = s_iperf_ctrl.cfg.interval;
     uint32_t time = s_iperf_ctrl.cfg.time;
+    TickType_t delay_interval = (interval * 1000) / portTICK_PERIOD_MS;
     uint32_t last_len = 0;
     uint32_t cur = 0;
 
     printf("\n%16s %s\n", "Interval", "Bandwidth");
     while (!s_iperf_ctrl.finish) {
         vTaskDelay(delay_interval);
-        printf("%4d-%4d sec       %.2f Mbits/sec\n", cur, cur+interval, (double)((s_iperf_ctrl.total_len - last_len)*8)/interval/1e6);
+        printf("%4d-%4d sec       %.2f Mbits/sec\n", cur, cur + interval,
+               (double)((s_iperf_ctrl.total_len - last_len) * 8) / interval / 1e6);
         cur += interval;
         last_len = s_iperf_ctrl.total_len;
         if (cur == time) {
@@ -99,28 +102,29 @@ void iperf_report_task(void* arg)
     }
 
     if (cur != 0) {
-        printf("%4d-%4d sec       %.2f Mbits/sec\n", 0, time, (double)(s_iperf_ctrl.total_len*8)/cur/1e6);
+        printf("%4d-%4d sec       %.2f Mbits/sec\n", 0, time,
+               (double)(s_iperf_ctrl.total_len * 8) / cur / 1e6);
     }
 
     s_iperf_ctrl.finish = true;
     vTaskDelete(NULL);
 }
 
-esp_err_t iperf_start_report(void)
+static esp_err_t iperf_start_report(void)
 {
     int ret;
 
-    ret = xTaskCreatePinnedToCore(iperf_report_task, IPERF_REPORT_TASK_NAME, IPERF_REPORT_TASK_STACK, NULL, IPERF_REPORT_TASK_PRIORITY, NULL, portNUM_PROCESSORS-1);
+    ret = xTaskCreatePinnedToCore(iperf_report_task, IPERF_REPORT_TASK_NAME, IPERF_REPORT_TASK_STACK, NULL, IPERF_REPORT_TASK_PRIORITY, NULL, portNUM_PROCESSORS - 1);
 
-    if (ret != pdPASS)  {
+    if (ret != pdPASS) {
         ESP_LOGE(TAG, "create task %s failed", IPERF_REPORT_TASK_NAME);
         return ESP_FAIL;
     }
+
     return ESP_OK;
 }
 
-esp_err_t iperf_run_tcp_server(void)
+static esp_err_t IRAM_ATTR iperf_run_tcp_server(void)
 {
     socklen_t addr_len = sizeof(struct sockaddr);
     struct sockaddr_in remote_addr;
@@ -144,7 +148,7 @@ esp_err_t iperf_run_tcp_server(void)
     addr.sin_family = AF_INET;
     addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
     addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(listen_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
+    if (bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
         iperf_show_socket_error_reason("tcp server bind", listen_socket);
         close(listen_socket);
         return ESP_FAIL;
@@ -162,7 +166,7 @@ esp_err_t iperf_run_tcp_server(void)
     while (!s_iperf_ctrl.finish) {
 
         /*TODO need to change to non-block mode */
-        sockfd = accept(listen_socket, (struct sockaddr*)&remote_addr, &addr_len);
+        sockfd = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
         if (sockfd < 0) {
             iperf_show_socket_error_reason("tcp server listen", listen_socket);
             close(listen_socket);
@@ -192,7 +196,7 @@ esp_err_t iperf_run_tcp_server(void)
     return ESP_OK;
 }
 
-esp_err_t IRAM_ATTR iperf_run_udp_server(void)
+static esp_err_t IRAM_ATTR iperf_run_udp_server(void)
 {
     socklen_t addr_len = sizeof(struct sockaddr_in);
     struct sockaddr_in addr;
@@ -214,12 +218,11 @@ esp_err_t IRAM_ATTR iperf_run_udp_server(void)
     addr.sin_family = AF_INET;
     addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
     addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
+    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
         iperf_show_socket_error_reason("udp server bind", sockfd);
         return ESP_FAIL;
     }
 
-
     addr.sin_family = AF_INET;
     addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
     addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
@@ -246,7 +249,7 @@ esp_err_t IRAM_ATTR iperf_run_udp_server(void)
     return ESP_OK;
 }
 
-esp_err_t iperf_run_udp_client(void)
+static esp_err_t iperf_run_udp_client(void)
 {
     struct sockaddr_in addr;
     iperf_udp_pkt_t *udp;
@@ -262,20 +265,12 @@ esp_err_t iperf_run_udp_client(void)
 
     sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     if (sockfd < 0) {
-        iperf_show_socket_error_reason("udp server create", sockfd);
+        iperf_show_socket_error_reason("udp client create", sockfd);
         return ESP_FAIL;
     }
 
     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
-    addr.sin_family = AF_INET;
-    addr.sin_port = 0;
-    addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
-        iperf_show_socket_error_reason("udp server bind", sockfd);
-        return ESP_FAIL;
-    }
-
     addr.sin_family = AF_INET;
     addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
     addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip;
@@ -288,7 +283,7 @@ esp_err_t iperf_run_udp_client(void)
 
     while (!s_iperf_ctrl.finish) {
         if (false == retry) {
-            id ++;
+            id++;
             udp->id = htonl(id);
             delay = 1;
         }
@@ -319,16 +314,13 @@ esp_err_t iperf_run_udp_client(void)
     return ESP_OK;
 }
 
-
-esp_err_t iperf_run_tcp_client(void)
+static esp_err_t iperf_run_tcp_client(void)
 {
-    struct sockaddr_in local_addr;
     struct sockaddr_in remote_addr;
     int actual_send = 0;
     int want_send = 0;
     uint8_t *buffer;
     int sockfd;
-    int opt;
 
     sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (sockfd < 0) {
@@ -336,18 +328,6 @@ esp_err_t iperf_run_tcp_client(void)
         return ESP_FAIL;
     }
 
-    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-    memset(&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_port = 0;
-    local_addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) != 0) {
-        iperf_show_socket_error_reason("tcp client bind", sockfd);
-        return ESP_FAIL;
-    }
-
-
     memset(&remote_addr, 0, sizeof(remote_addr));
     remote_addr.sin_family = AF_INET;
     remote_addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
@@ -374,7 +354,7 @@ esp_err_t iperf_run_tcp_client(void)
     return ESP_OK;
 }
 
-void iperf_task_traffic(void *arg)
+static void iperf_task_traffic(void *arg)
 {
     if (iperf_is_udp_client()) {
         iperf_run_udp_client();
@@ -388,14 +368,14 @@ void iperf_task_traffic(void *arg)
 
     if (s_iperf_ctrl.buffer) {
         free(s_iperf_ctrl.buffer);
-        s_iperf_ctrl.buffer = 0;
+        s_iperf_ctrl.buffer = NULL;
     }
     ESP_LOGI(TAG, "iperf exit");
     s_iperf_is_running = false;
     vTaskDelete(NULL);
 }
 
-uint32_t iperf_get_buffer_len(void)
+static uint32_t iperf_get_buffer_len(void)
 {
     if (iperf_is_udp_client()) {
         return IPERF_UDP_TX_LEN;
@@ -411,7 +391,7 @@ uint32_t iperf_get_buffer_len(void)
 
 esp_err_t iperf_start(iperf_cfg_t *cfg)
 {
-    int ret;
+    BaseType_t ret;
 
     if (!cfg) {
         return ESP_FAIL;
@@ -429,16 +409,16 @@ esp_err_t iperf_start(iperf_cfg_t *cfg)
     s_iperf_ctrl.buffer_len = iperf_get_buffer_len();
     s_iperf_ctrl.buffer = (uint8_t *)malloc(s_iperf_ctrl.buffer_len);
     if (!s_iperf_ctrl.buffer) {
-        ESP_LOGE(TAG, "create buffer: out of memory");
+        ESP_LOGE(TAG, "create buffer: not enough memory");
         return ESP_FAIL;
     }
     memset(s_iperf_ctrl.buffer, 0, s_iperf_ctrl.buffer_len);
 
-    ret = xTaskCreatePinnedToCore(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, IPERF_TRAFFIC_TASK_PRIORITY, NULL, portNUM_PROCESSORS-1);
-    if (ret != pdPASS)  {
+    ret = xTaskCreatePinnedToCore(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, IPERF_TRAFFIC_TASK_PRIORITY, NULL, portNUM_PROCESSORS - 1);
+    if (ret != pdPASS) {
         ESP_LOGE(TAG, "create task %s failed", IPERF_TRAFFIC_TASK_NAME);
         free(s_iperf_ctrl.buffer);
-        s_iperf_ctrl.buffer = 0;
+        s_iperf_ctrl.buffer = NULL;
         return ESP_FAIL;
     }
 
@@ -453,9 +433,8 @@ esp_err_t iperf_stop(void)
 
     while (s_iperf_is_running) {
         ESP_LOGI(TAG, "wait current iperf to stop ...");
-        vTaskDelay(300/portTICK_RATE_MS);
+        vTaskDelay(300 / portTICK_PERIOD_MS);
     }
 
     return ESP_OK;
 }
-
diff --git a/examples/wifi/iperf/components/iperf/iperf.h b/examples/wifi/iperf/components/iperf/iperf.h
new file mode 100644 (file)
index 0000000..e84e964
--- /dev/null
@@ -0,0 +1,65 @@
+/* Iperf Example - iperf declaration
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __IPERF_H_
+#define __IPERF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp_types.h"
+#include "esp_err.h"
+
+#define IPERF_FLAG_CLIENT (1)
+#define IPERF_FLAG_SERVER (1 << 1)
+#define IPERF_FLAG_TCP (1 << 2)
+#define IPERF_FLAG_UDP (1 << 3)
+
+#define IPERF_DEFAULT_PORT 5001
+#define IPERF_DEFAULT_INTERVAL 3
+#define IPERF_DEFAULT_TIME 30
+
+#define IPERF_TRAFFIC_TASK_NAME "iperf_traffic"
+#define IPERF_TRAFFIC_TASK_PRIORITY 10
+#define IPERF_TRAFFIC_TASK_STACK 4096
+#define IPERF_REPORT_TASK_NAME "iperf_report"
+#define IPERF_REPORT_TASK_PRIORITY 20
+#define IPERF_REPORT_TASK_STACK 4096
+#define IPERF_REPORT_TASK_NAME "iperf_report"
+
+#define IPERF_UDP_TX_LEN (1472)
+#define IPERF_UDP_RX_LEN (16 << 10)
+#define IPERF_TCP_TX_LEN (16 << 10)
+#define IPERF_TCP_RX_LEN (16 << 10)
+
+#define IPERF_MAX_DELAY 64
+
+#define IPERF_SOCKET_RX_TIMEOUT 10
+#define IPERF_SOCKET_ACCEPT_TIMEOUT 5
+
+typedef struct {
+    uint32_t flag;
+    uint32_t dip;
+    uint32_t sip;
+    uint16_t dport;
+    uint16_t sport;
+    uint32_t interval;
+    uint32_t time;
+} iperf_cfg_t;
+
+esp_err_t iperf_start(iperf_cfg_t *cfg);
+
+esp_err_t iperf_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 2487dec22ca4ee983cea9f0b71f7daa38fe8c535..e94ff94b07b5c0aceaaa81b6ad41b61fb9624dea 100644 (file)
@@ -1,5 +1,5 @@
 set(COMPONENT_SRCS "cmd_wifi.c"
-                   "main.c")
+                   "iperf_example_main.c")
 set(COMPONENT_ADD_INCLUDEDIRS ".")
 
 register_component()
index 78707eabd51853528807a2bc0a290331b4585250..4fbc4794910c3519cdfd09edaaf3127d71439cd4 100644 (file)
@@ -8,7 +8,13 @@
 */
 #pragma once
 
-// Register WiFi functions
-void register_wifi(void);
-void initialise_wifi(void);
+#ifdef __cplusplus
+extern "C" {
+#endif
 
+#include "cmd_system.h"
+#include "cmd_wifi.h"
+
+#ifdef __cplusplus
+}
+#endif
index c2af6459492502f37e99468338eb2ee6a90a3315..ea130ecd9c3c1ca34943e653567ce6b91772d213 100644 (file)
@@ -47,7 +47,7 @@ static wifi_args_t sta_args;
 static wifi_scan_arg_t scan_args;
 static wifi_args_t ap_args;
 static bool reconnect = true;
-static const char *TAG="iperf";
+static const char *TAG="cmd_wifi";
 
 static EventGroupHandle_t wifi_event_group;
 const int CONNECTED_BIT = BIT0;
@@ -145,7 +145,7 @@ static bool wifi_cmd_sta_join(const char* ssid, const char* pass)
     ESP_ERROR_CHECK( esp_wifi_connect() );
 
     xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000/portTICK_RATE_MS);
-    
+
     return true;
 }
 
@@ -205,7 +205,7 @@ static bool wifi_cmd_ap_set(const char* ssid, const char* pass)
         },
     };
 
-    reconnect = false; 
+    reconnect = false;
     strncpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
     if (pass) {
         if (strlen(pass) != 0 && strlen(pass) < 8) {
@@ -366,23 +366,10 @@ static int wifi_cmd_iperf(int argc, char** argv)
             cfg.interval, cfg.time);
 
     iperf_start(&cfg);
-    
-    return 0;
-}
 
-static int restart(int argc, char** argv)
-{
-    ESP_LOGI(TAG, "Restarting");
-    esp_restart();
-}
-
-static int heap_size(int argc, char** argv)
-{
-    uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
-    ESP_LOGI(TAG, "min heap size: %u", heap_size);
     return 0;
 }
+
 void register_wifi()
 {
     sta_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
@@ -435,14 +422,6 @@ void register_wifi()
     };
     ESP_ERROR_CHECK( esp_console_cmd_register(&query_cmd) );
 
-    const esp_console_cmd_t restart_cmd = {
-        .command = "restart",
-        .help = "Restart the program",
-        .hint = NULL,
-        .func = &restart,
-    };
-    ESP_ERROR_CHECK( esp_console_cmd_register(&restart_cmd) );
-
     iperf_args.ip = arg_str0("c", "client", "<ip>", "run in client mode, connecting to <host>");
     iperf_args.server = arg_lit0("s", "server", "run in server mode");
     iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
@@ -460,12 +439,4 @@ void register_wifi()
     };
 
     ESP_ERROR_CHECK( esp_console_cmd_register(&iperf_cmd) );
-
-    const esp_console_cmd_t heap_cmd = {
-        .command = "heap",
-        .help = "get min free heap size druing test",
-        .hint = NULL,
-        .func = &heap_size,
-    };
-    ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
 }
diff --git a/examples/wifi/iperf/main/cmd_wifi.h b/examples/wifi/iperf/main/cmd_wifi.h
new file mode 100644 (file)
index 0000000..80e998d
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register WiFi functions
+void register_wifi(void);
+void initialise_wifi(void);
+
+#ifdef __cplusplus
+}
+#endif
similarity index 91%
rename from examples/wifi/iperf/main/main.c
rename to examples/wifi/iperf/main/iperf_example_main.c
index ffeeb680b59a3bbd7ebe34aaa1537256d439af2d..a3a666ed2ab1c8300b919b55ce080d92ac048fc9 100644 (file)
@@ -39,17 +39,17 @@ static void initialize_console()
 
     /* Install UART driver for interrupt-driven reads and writes */
     ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM,
-            256, 0, 0, NULL, 0) );
+                                         256, 0, 0, NULL, 0) );
 
     /* Tell VFS to use UART driver */
     esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
 
     /* Initialize the console */
     esp_console_config_t console_config = {
-            .max_cmdline_args = 32,
-            .max_cmdline_length = 256,
+        .max_cmdline_args = 32,
+        .max_cmdline_length = 256,
 #if CONFIG_LOG_COLORS
-            .hint_color = atoi(LOG_COLOR_CYAN)
+        .hint_color = atoi(LOG_COLOR_CYAN)
 #endif
     };
     ESP_ERROR_CHECK( esp_console_init(&console_config) );
@@ -62,7 +62,7 @@ static void initialize_console()
 
     /* Tell linenoise where to get command completions and hints */
     linenoiseSetCompletionCallback(&esp_console_get_completion);
-    linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
+    linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
 
     /* Set command history size */
     linenoiseHistorySetMaxLen(100);
@@ -76,18 +76,19 @@ void app_main(void)
         ret = nvs_flash_init();
     }
     ESP_ERROR_CHECK( ret );
+
     initialise_wifi();
     initialize_console();
 
     /* Register commands */
     esp_console_register_help_command();
+    register_system();
     register_wifi();
 
     /* Prompt to be printed before each line.
      * This can be customized, made dynamic, etc.
      */
-    const charprompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
+    const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
 
     printf("\n ==================================================\n");
     printf(" |       Steps to test WiFi throughput            |\n");
@@ -116,11 +117,11 @@ void app_main(void)
     }
 
     /* Main loop */
-    while(true) {
+    while (true) {
         /* Get a line using linenoise.
          * The line is returned when ENTER is pressed.
          */
-        charline = linenoise(prompt);
+        char *line = linenoise(prompt);
         if (line == NULL) { /* Ignore empty lines */
             continue;
         }