cmd_ethernet.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* Console example — Ethernet commands
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/event_groups.h"
  11. #include "tcpip_adapter.h"
  12. #include "esp_log.h"
  13. #include "esp_console.h"
  14. #include "esp_event_loop.h"
  15. #include "esp_eth.h"
  16. #include "argtable3/argtable3.h"
  17. #include "iperf.h"
  18. #include "sdkconfig.h"
  19. #if CONFIG_PHY_LAN8720
  20. #include "eth_phy/phy_lan8720.h"
  21. #define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
  22. #elif CONFIG_PHY_TLK110
  23. #include "eth_phy/phy_tlk110.h"
  24. #define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
  25. #elif CONFIG_PHY_IP101
  26. #include "eth_phy/phy_ip101.h"
  27. #define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config
  28. #endif
  29. static tcpip_adapter_ip_info_t ip;
  30. static bool started = false;
  31. static EventGroupHandle_t eth_event_group;
  32. static const int GOTIP_BIT = BIT0;
  33. #define PIN_PHY_POWER CONFIG_PHY_POWER_PIN
  34. #define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
  35. #define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
  36. #ifdef CONFIG_PHY_USE_POWER_PIN
  37. static void phy_device_power_enable_via_gpio(bool enable)
  38. {
  39. assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
  40. if (!enable) {
  41. DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
  42. }
  43. gpio_pad_select_gpio(PIN_PHY_POWER);
  44. gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
  45. if (enable == true) {
  46. gpio_set_level(PIN_PHY_POWER, 1);
  47. ESP_LOGI(__func__, "Power On Ethernet PHY");
  48. } else {
  49. gpio_set_level(PIN_PHY_POWER, 0);
  50. ESP_LOGI(__func__, "Power Off Ethernet PHY");
  51. }
  52. vTaskDelay(1); // Allow the power up/down to take effect, min 300us
  53. if (enable) {
  54. /* call the default PHY-specific power on function */
  55. DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
  56. }
  57. }
  58. #endif
  59. static void eth_gpio_config_rmii(void)
  60. {
  61. phy_rmii_configure_data_interface_pins();
  62. phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
  63. }
  64. /* "ethernet" command */
  65. static struct {
  66. struct arg_str *control;
  67. struct arg_end *end;
  68. } eth_control_args;
  69. static int eth_cmd_control(int argc, char **argv)
  70. {
  71. int nerrors = arg_parse(argc, argv, (void **)&eth_control_args);
  72. if (nerrors != 0) {
  73. arg_print_errors(stderr, eth_control_args.end, argv[0]);
  74. return 1;
  75. }
  76. if (!strncmp(eth_control_args.control->sval[0], "start", 5) && !started) {
  77. ESP_ERROR_CHECK(esp_eth_enable());
  78. started = true;
  79. }
  80. if (!strncmp(eth_control_args.control->sval[0], "stop", 4) && started) {
  81. ESP_ERROR_CHECK(esp_eth_disable());
  82. started = false;
  83. }
  84. if (!strncmp(eth_control_args.control->sval[0], "info", 4)) {
  85. uint8_t mac_addr[6];
  86. esp_eth_get_mac(mac_addr);
  87. printf("HW ADDR: " MACSTR "\r\n", MAC2STR(mac_addr));
  88. tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip);
  89. printf("ETHIP: " IPSTR "\r\n", IP2STR(&ip.ip));
  90. printf("ETHMASK: " IPSTR "\r\n", IP2STR(&ip.netmask));
  91. printf("ETHGW: " IPSTR "\r\n", IP2STR(&ip.gw));
  92. }
  93. return 0;
  94. }
  95. /* "iperf" command */
  96. static struct {
  97. struct arg_str *ip;
  98. struct arg_lit *server;
  99. struct arg_lit *udp;
  100. struct arg_int *port;
  101. struct arg_int *interval;
  102. struct arg_int *time;
  103. struct arg_lit *abort;
  104. struct arg_end *end;
  105. } iperf_args;
  106. static int eth_cmd_iperf(int argc, char **argv)
  107. {
  108. int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
  109. iperf_cfg_t cfg;
  110. if (nerrors != 0) {
  111. arg_print_errors(stderr, iperf_args.end, argv[0]);
  112. return 0;
  113. }
  114. memset(&cfg, 0, sizeof(cfg));
  115. /* iperf -a */
  116. if (iperf_args.abort->count != 0) {
  117. iperf_stop();
  118. return 0;
  119. }
  120. if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
  121. ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0))) {
  122. ESP_LOGE(__func__, "Wrong mode! ESP32 should run in client or server mode");
  123. return 0;
  124. }
  125. /* iperf -s */
  126. if (iperf_args.ip->count == 0) {
  127. cfg.flag |= IPERF_FLAG_SERVER;
  128. }
  129. /* iperf -c SERVER_ADDRESS */
  130. else {
  131. cfg.dip = ipaddr_addr(iperf_args.ip->sval[0]);
  132. cfg.flag |= IPERF_FLAG_CLIENT;
  133. }
  134. /* acquiring for ip, could blocked here */
  135. xEventGroupWaitBits(eth_event_group, GOTIP_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
  136. cfg.sip = ip.ip.addr;
  137. if (cfg.sip == 0) {
  138. return 0;
  139. }
  140. /* iperf -u */
  141. if (iperf_args.udp->count == 0) {
  142. cfg.flag |= IPERF_FLAG_TCP;
  143. } else {
  144. cfg.flag |= IPERF_FLAG_UDP;
  145. }
  146. /* iperf -p */
  147. if (iperf_args.port->count == 0) {
  148. cfg.sport = IPERF_DEFAULT_PORT;
  149. cfg.dport = IPERF_DEFAULT_PORT;
  150. } else {
  151. if (cfg.flag & IPERF_FLAG_SERVER) {
  152. cfg.sport = iperf_args.port->ival[0];
  153. cfg.dport = IPERF_DEFAULT_PORT;
  154. } else {
  155. cfg.sport = IPERF_DEFAULT_PORT;
  156. cfg.dport = iperf_args.port->ival[0];
  157. }
  158. }
  159. /* iperf -i */
  160. if (iperf_args.interval->count == 0) {
  161. cfg.interval = IPERF_DEFAULT_INTERVAL;
  162. } else {
  163. cfg.interval = iperf_args.interval->ival[0];
  164. if (cfg.interval <= 0) {
  165. cfg.interval = IPERF_DEFAULT_INTERVAL;
  166. }
  167. }
  168. /* iperf -t */
  169. if (iperf_args.time->count == 0) {
  170. cfg.time = IPERF_DEFAULT_TIME;
  171. } else {
  172. cfg.time = iperf_args.time->ival[0];
  173. if (cfg.time <= cfg.interval) {
  174. cfg.time = cfg.interval;
  175. }
  176. }
  177. printf("mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d\r\n",
  178. cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
  179. cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
  180. cfg.sip & 0xFF, (cfg.sip >> 8) & 0xFF, (cfg.sip >> 16) & 0xFF, (cfg.sip >> 24) & 0xFF, cfg.sport,
  181. cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport,
  182. cfg.interval, cfg.time);
  183. iperf_start(&cfg);
  184. return 0;
  185. }
  186. static esp_err_t eth_event_handler(void *ctx, system_event_t *event)
  187. {
  188. switch (event->event_id) {
  189. case SYSTEM_EVENT_ETH_START:
  190. started = true;
  191. break;
  192. case SYSTEM_EVENT_ETH_GOT_IP:
  193. memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
  194. ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip));
  195. xEventGroupSetBits(eth_event_group, GOTIP_BIT);
  196. break;
  197. case SYSTEM_EVENT_ETH_STOP:
  198. xEventGroupClearBits(eth_event_group, GOTIP_BIT);
  199. started = false;
  200. default:
  201. break;
  202. }
  203. return ESP_OK;
  204. }
  205. void register_ethernet()
  206. {
  207. eth_event_group = xEventGroupCreate();
  208. tcpip_adapter_init();
  209. ESP_ERROR_CHECK(esp_event_loop_init(eth_event_handler, NULL));
  210. eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
  211. config.phy_addr = CONFIG_PHY_ADDRESS;
  212. config.gpio_config = eth_gpio_config_rmii;
  213. config.tcpip_input = tcpip_adapter_eth_input;
  214. config.clock_mode = CONFIG_PHY_CLOCK_MODE;
  215. #ifdef CONFIG_PHY_USE_POWER_PIN
  216. /* Replace the default 'power enable' function with an example-specific one
  217. that toggles a power GPIO. */
  218. config.phy_power_enable = phy_device_power_enable_via_gpio;
  219. #endif
  220. ESP_ERROR_CHECK(esp_eth_init(&config));
  221. eth_control_args.control = arg_str1(NULL, NULL, "<start|stop|info>", "Start/Stop Ethernet or Get info of Ethernet");
  222. eth_control_args.end = arg_end(1);
  223. const esp_console_cmd_t cmd = {
  224. .command = "ethernet",
  225. .help = "Control Ethernet interface",
  226. .hint = NULL,
  227. .func = eth_cmd_control,
  228. .argtable = &eth_control_args
  229. };
  230. ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
  231. iperf_args.ip = arg_str0("c", "client", "<ip>",
  232. "run in client mode, connecting to <host>");
  233. iperf_args.server = arg_lit0("s", "server", "run in server mode");
  234. iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
  235. iperf_args.port = arg_int0("p", "port", "<port>",
  236. "server port to listen on/connect to");
  237. iperf_args.interval = arg_int0("i", "interval", "<interval>",
  238. "seconds between periodic bandwidth reports");
  239. iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
  240. iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
  241. iperf_args.end = arg_end(1);
  242. const esp_console_cmd_t iperf_cmd = {
  243. .command = "iperf",
  244. .help = "iperf command",
  245. .hint = NULL,
  246. .func = &eth_cmd_iperf,
  247. .argtable = &iperf_args
  248. };
  249. ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
  250. }