ESPHome  2024.12.2
ethernet_component.cpp
Go to the documentation of this file.
1 #include "ethernet_component.h"
3 #include "esphome/core/log.h"
4 #include "esphome/core/util.h"
5 
6 #ifdef USE_ESP32
7 
8 #include <lwip/dns.h>
9 #include <cinttypes>
10 #include "esp_event.h"
11 
12 #ifdef USE_ETHERNET_SPI
13 #include <driver/gpio.h>
14 #include <driver/spi_master.h>
15 #endif
16 
17 namespace esphome {
18 namespace ethernet {
19 
20 static const char *const TAG = "ethernet";
21 
22 EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
23 
24 #define ESPHL_ERROR_CHECK(err, message) \
25  if ((err) != ESP_OK) { \
26  ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \
27  this->mark_failed(); \
28  return; \
29  }
30 
31 #define ESPHL_ERROR_CHECK_RET(err, message, ret) \
32  if ((err) != ESP_OK) { \
33  ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \
34  this->mark_failed(); \
35  return ret; \
36  }
37 
38 EthernetComponent::EthernetComponent() { global_eth_component = this; }
39 
41  ESP_LOGCONFIG(TAG, "Setting up Ethernet...");
42  if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
43  // Delay here to allow power to stabilise before Ethernet is initialized.
44  delay(300); // NOLINT
45  }
46 
47  esp_err_t err;
48 
49 #ifdef USE_ETHERNET_SPI
50  // Install GPIO ISR handler to be able to service SPI Eth modules interrupts
51  gpio_install_isr_service(0);
52 
53  spi_bus_config_t buscfg = {
54  .mosi_io_num = this->mosi_pin_,
55  .miso_io_num = this->miso_pin_,
56  .sclk_io_num = this->clk_pin_,
57  .quadwp_io_num = -1,
58  .quadhd_io_num = -1,
59  .data4_io_num = -1,
60  .data5_io_num = -1,
61  .data6_io_num = -1,
62  .data7_io_num = -1,
63  .max_transfer_sz = 0,
64  .flags = 0,
65  .intr_flags = 0,
66  };
67 
68 #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
69  defined(USE_ESP32_VARIANT_ESP32C6)
70  auto host = SPI2_HOST;
71 #else
72  auto host = SPI3_HOST;
73 #endif
74 
75  err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
76  ESPHL_ERROR_CHECK(err, "SPI bus initialize error");
77 #endif
78 
79  err = esp_netif_init();
80  ESPHL_ERROR_CHECK(err, "ETH netif init error");
81  err = esp_event_loop_create_default();
82  ESPHL_ERROR_CHECK(err, "ETH event loop error");
83 
84  esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
85  this->eth_netif_ = esp_netif_new(&cfg);
86 
87  // Init MAC and PHY configs to default
88  eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
89  eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
90 
91 #ifdef USE_ETHERNET_SPI // Configure SPI interface and Ethernet driver for specific SPI module
92  spi_device_interface_config_t devcfg = {
93  .command_bits = 16, // Actually it's the address phase in W5500 SPI frame
94  .address_bits = 8, // Actually it's the control phase in W5500 SPI frame
95  .dummy_bits = 0,
96  .mode = 0,
97  .duty_cycle_pos = 0,
98  .cs_ena_pretrans = 0,
99  .cs_ena_posttrans = 0,
100  .clock_speed_hz = this->clock_speed_,
101  .input_delay_ns = 0,
102  .spics_io_num = this->cs_pin_,
103  .flags = 0,
104  .queue_size = 20,
105  .pre_cb = nullptr,
106  .post_cb = nullptr,
107  };
108 
109 #if USE_ESP_IDF && (ESP_IDF_VERSION_MAJOR >= 5)
110  eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg);
111 #else
112  spi_device_handle_t spi_handle = nullptr;
113  err = spi_bus_add_device(host, &devcfg, &spi_handle);
114  ESPHL_ERROR_CHECK(err, "SPI bus add device error");
115 
116  eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
117 #endif
118  w5500_config.int_gpio_num = this->interrupt_pin_;
119 #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
120  w5500_config.poll_period_ms = this->polling_interval_;
121 #endif
122  phy_config.phy_addr = this->phy_addr_spi_;
123  phy_config.reset_gpio_num = this->reset_pin_;
124 
125  esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
126 #elif defined(USE_ETHERNET_OPENETH)
127  esp_eth_mac_t *mac = esp_eth_mac_new_openeth(&mac_config);
128 #else
129  phy_config.phy_addr = this->phy_addr_;
130  phy_config.reset_gpio_num = this->power_pin_;
131 
132 #if ESP_IDF_VERSION_MAJOR >= 5
133  eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
134  esp32_emac_config.smi_mdc_gpio_num = this->mdc_pin_;
135  esp32_emac_config.smi_mdio_gpio_num = this->mdio_pin_;
136  esp32_emac_config.clock_config.rmii.clock_mode = this->clk_mode_;
137  esp32_emac_config.clock_config.rmii.clock_gpio = this->clk_gpio_;
138 
139  esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
140 #else
141  mac_config.smi_mdc_gpio_num = this->mdc_pin_;
142  mac_config.smi_mdio_gpio_num = this->mdio_pin_;
143  mac_config.clock_config.rmii.clock_mode = this->clk_mode_;
144  mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_;
145 
146  esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
147 #endif
148 #endif
149 
150  switch (this->type_) {
151 #ifdef USE_ETHERNET_OPENETH
152  case ETHERNET_TYPE_OPENETH: {
153  phy_config.autonego_timeout_ms = 1000;
154  this->phy_ = esp_eth_phy_new_dp83848(&phy_config);
155  break;
156  }
157 #endif
158 #if CONFIG_ETH_USE_ESP32_EMAC
159  case ETHERNET_TYPE_LAN8720: {
160  this->phy_ = esp_eth_phy_new_lan87xx(&phy_config);
161  break;
162  }
163  case ETHERNET_TYPE_RTL8201: {
164  this->phy_ = esp_eth_phy_new_rtl8201(&phy_config);
165  break;
166  }
167  case ETHERNET_TYPE_DP83848: {
168  this->phy_ = esp_eth_phy_new_dp83848(&phy_config);
169  break;
170  }
171  case ETHERNET_TYPE_IP101: {
172  this->phy_ = esp_eth_phy_new_ip101(&phy_config);
173  break;
174  }
175  case ETHERNET_TYPE_JL1101: {
176  this->phy_ = esp_eth_phy_new_jl1101(&phy_config);
177  break;
178  }
181 #if ESP_IDF_VERSION_MAJOR >= 5
182  this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config);
183 #else
184  this->phy_ = esp_eth_phy_new_ksz8081(&phy_config);
185 #endif
186  break;
187  }
188 #endif
189 #ifdef USE_ETHERNET_SPI
190  case ETHERNET_TYPE_W5500: {
191  this->phy_ = esp_eth_phy_new_w5500(&phy_config);
192  break;
193  }
194 #endif
195  default: {
196  this->mark_failed();
197  return;
198  }
199  }
200 
201  esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, this->phy_);
202  this->eth_handle_ = nullptr;
203  err = esp_eth_driver_install(&eth_config, &this->eth_handle_);
204  ESPHL_ERROR_CHECK(err, "ETH driver install error");
205 
206 #ifndef USE_ETHERNET_SPI
207  if (this->type_ == ETHERNET_TYPE_KSZ8081RNA && this->clk_mode_ == EMAC_CLK_OUT) {
208  // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide.
209  this->ksz8081_set_clock_reference_(mac);
210  }
211 
212  for (const auto &phy_register : this->phy_registers_) {
213  this->write_phy_register_(mac, phy_register);
214  }
215 #endif
216 
217  // use ESP internal eth mac
218  uint8_t mac_addr[6];
219  esp_read_mac(mac_addr, ESP_MAC_ETH);
220  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_S_MAC_ADDR, mac_addr);
221  ESPHL_ERROR_CHECK(err, "set mac address error");
222 
223  /* attach Ethernet driver to TCP/IP stack */
224  err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_));
225  ESPHL_ERROR_CHECK(err, "ETH netif attach error");
226 
227  // Register user defined event handers
228  err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &EthernetComponent::eth_event_handler, nullptr);
229  ESPHL_ERROR_CHECK(err, "ETH event handler register error");
230  err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &EthernetComponent::got_ip_event_handler, nullptr);
231  ESPHL_ERROR_CHECK(err, "GOT IP event handler register error");
232 #if USE_NETWORK_IPV6
233  err = esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &EthernetComponent::got_ip6_event_handler, nullptr);
234  ESPHL_ERROR_CHECK(err, "GOT IPv6 event handler register error");
235 #endif /* USE_NETWORK_IPV6 */
236 
237  /* start Ethernet driver state machine */
238  err = esp_eth_start(this->eth_handle_);
239  ESPHL_ERROR_CHECK(err, "ETH start error");
240 }
241 
243  const uint32_t now = millis();
244 
245  switch (this->state_) {
247  if (this->started_) {
248  ESP_LOGI(TAG, "Starting ethernet connection");
250  this->start_connect_();
251  }
252  break;
254  if (!this->started_) {
255  ESP_LOGI(TAG, "Stopped ethernet connection");
257  } else if (this->connected_) {
258  // connection established
259  ESP_LOGI(TAG, "Connected via Ethernet!");
261 
262  this->dump_connect_params_();
263  this->status_clear_warning();
264  } else if (now - this->connect_begin_ > 15000) {
265  ESP_LOGW(TAG, "Connecting via ethernet failed! Re-connecting...");
266  this->start_connect_();
267  }
268  break;
270  if (!this->started_) {
271  ESP_LOGI(TAG, "Stopped ethernet connection");
273  } else if (!this->connected_) {
274  ESP_LOGW(TAG, "Connection via Ethernet lost! Re-connecting...");
276  this->start_connect_();
277  }
278  break;
279  }
280 }
281 
283  const char *eth_type;
284  switch (this->type_) {
286  eth_type = "LAN8720";
287  break;
288 
290  eth_type = "RTL8201";
291  break;
292 
294  eth_type = "DP83848";
295  break;
296 
297  case ETHERNET_TYPE_IP101:
298  eth_type = "IP101";
299  break;
300 
302  eth_type = "JL1101";
303  break;
304 
306  eth_type = "KSZ8081";
307  break;
308 
310  eth_type = "KSZ8081RNA";
311  break;
312 
313  case ETHERNET_TYPE_W5500:
314  eth_type = "W5500";
315  break;
316 
318  eth_type = "OPENETH";
319  break;
320 
321  default:
322  eth_type = "Unknown";
323  break;
324  }
325 
326  ESP_LOGCONFIG(TAG, "Ethernet:");
327  this->dump_connect_params_();
328 #ifdef USE_ETHERNET_SPI
329  ESP_LOGCONFIG(TAG, " CLK Pin: %u", this->clk_pin_);
330  ESP_LOGCONFIG(TAG, " MISO Pin: %u", this->miso_pin_);
331  ESP_LOGCONFIG(TAG, " MOSI Pin: %u", this->mosi_pin_);
332  ESP_LOGCONFIG(TAG, " CS Pin: %u", this->cs_pin_);
333 #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
334  if (this->polling_interval_ != 0) {
335  ESP_LOGCONFIG(TAG, " Polling Interval: %lu ms", this->polling_interval_);
336  } else
337 #endif
338  {
339  ESP_LOGCONFIG(TAG, " IRQ Pin: %d", this->interrupt_pin_);
340  }
341  ESP_LOGCONFIG(TAG, " Reset Pin: %d", this->reset_pin_);
342  ESP_LOGCONFIG(TAG, " Clock Speed: %d MHz", this->clock_speed_ / 1000000);
343 #else
344  if (this->power_pin_ != -1) {
345  ESP_LOGCONFIG(TAG, " Power Pin: %u", this->power_pin_);
346  }
347  ESP_LOGCONFIG(TAG, " MDC Pin: %u", this->mdc_pin_);
348  ESP_LOGCONFIG(TAG, " MDIO Pin: %u", this->mdio_pin_);
349  ESP_LOGCONFIG(TAG, " PHY addr: %u", this->phy_addr_);
350 #endif
351  ESP_LOGCONFIG(TAG, " Type: %s", eth_type);
352 }
353 
355 
357 
359  network::IPAddresses addresses;
360  esp_netif_ip_info_t ip;
361  esp_err_t err = esp_netif_get_ip_info(this->eth_netif_, &ip);
362  if (err != ESP_OK) {
363  ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err));
364  // TODO: do something smarter
365  // return false;
366  } else {
367  addresses[0] = network::IPAddress(&ip.ip);
368  }
369 #if USE_NETWORK_IPV6
370  struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
371  uint8_t count = 0;
372  count = esp_netif_get_all_ip6(this->eth_netif_, if_ip6s);
373  assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES);
374  for (int i = 0; i < count; i++) {
375  addresses[i + 1] = network::IPAddress(&if_ip6s[i]);
376  }
377 #endif /* USE_NETWORK_IPV6 */
378 
379  return addresses;
380 }
381 
383  const ip_addr_t *dns_ip = dns_getserver(num);
384  return dns_ip;
385 }
386 
387 void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) {
388  const char *event_name;
389 
390  switch (event) {
391  case ETHERNET_EVENT_START:
392  event_name = "ETH started";
393  global_eth_component->started_ = true;
394  break;
395  case ETHERNET_EVENT_STOP:
396  event_name = "ETH stopped";
397  global_eth_component->started_ = false;
398  global_eth_component->connected_ = false;
399  break;
400  case ETHERNET_EVENT_CONNECTED:
401  event_name = "ETH connected";
402  break;
403  case ETHERNET_EVENT_DISCONNECTED:
404  event_name = "ETH disconnected";
405  global_eth_component->connected_ = false;
406  break;
407  default:
408  return;
409  }
410 
411  ESP_LOGV(TAG, "[Ethernet event] %s (num=%" PRId32 ")", event_name, event);
412 }
413 
414 void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id,
415  void *event_data) {
416  ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
417  const esp_netif_ip_info_t *ip_info = &event->ip_info;
418  ESP_LOGV(TAG, "[Ethernet event] ETH Got IP " IPSTR, IP2STR(&ip_info->ip));
419  global_eth_component->got_ipv4_address_ = true;
420 #if USE_NETWORK_IPV6 && (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0)
421  global_eth_component->connected_ = global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT;
422 #else
423  global_eth_component->connected_ = true;
424 #endif /* USE_NETWORK_IPV6 */
425 }
426 
427 #if USE_NETWORK_IPV6
428 void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id,
429  void *event_data) {
430  ip_event_got_ip6_t *event = (ip_event_got_ip6_t *) event_data;
431  ESP_LOGV(TAG, "[Ethernet event] ETH Got IPv6: " IPV6STR, IPV62STR(event->ip6_info.ip));
432  global_eth_component->ipv6_count_ += 1;
433 #if (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0)
434  global_eth_component->connected_ =
435  global_eth_component->got_ipv4_address_ && (global_eth_component->ipv6_count_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT);
436 #else
437  global_eth_component->connected_ = global_eth_component->got_ipv4_address_;
438 #endif
439 }
440 #endif /* USE_NETWORK_IPV6 */
441 
443  global_eth_component->got_ipv4_address_ = false;
444 #if USE_NETWORK_IPV6
445  global_eth_component->ipv6_count_ = 0;
446 #endif /* USE_NETWORK_IPV6 */
447  this->connect_begin_ = millis();
448  this->status_set_warning("waiting for IP configuration");
449 
450  esp_err_t err;
451  err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str());
452  if (err != ERR_OK) {
453  ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
454  }
455 
456  esp_netif_ip_info_t info;
457  if (this->manual_ip_.has_value()) {
458  info.ip = this->manual_ip_->static_ip;
459  info.gw = this->manual_ip_->gateway;
460  info.netmask = this->manual_ip_->subnet;
461  } else {
462  info.ip.addr = 0;
463  info.gw.addr = 0;
464  info.netmask.addr = 0;
465  }
466 
467  esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
468 
469  err = esp_netif_dhcpc_get_status(this->eth_netif_, &status);
470  ESPHL_ERROR_CHECK(err, "DHCPC Get Status Failed!");
471 
472  ESP_LOGV(TAG, "DHCP Client Status: %d", status);
473 
474  err = esp_netif_dhcpc_stop(this->eth_netif_);
475  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
476  ESPHL_ERROR_CHECK(err, "DHCPC stop error");
477  }
478 
479  err = esp_netif_set_ip_info(this->eth_netif_, &info);
480  ESPHL_ERROR_CHECK(err, "DHCPC set IP info error");
481 
482  if (this->manual_ip_.has_value()) {
483  if (this->manual_ip_->dns1.is_set()) {
484  ip_addr_t d;
485  d = this->manual_ip_->dns1;
486  dns_setserver(0, &d);
487  }
488  if (this->manual_ip_->dns2.is_set()) {
489  ip_addr_t d;
490  d = this->manual_ip_->dns2;
491  dns_setserver(1, &d);
492  }
493  } else {
494  err = esp_netif_dhcpc_start(this->eth_netif_);
495  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) {
496  ESPHL_ERROR_CHECK(err, "DHCPC start error");
497  }
498  }
499 #if USE_NETWORK_IPV6
500  err = esp_netif_create_ip6_linklocal(this->eth_netif_);
501  if (err != ESP_OK) {
502  ESPHL_ERROR_CHECK(err, "Enable IPv6 link local failed");
503  }
504 #endif /* USE_NETWORK_IPV6 */
505 
506  this->connect_begin_ = millis();
507  this->status_set_warning();
508 }
509 
511 
513  esp_netif_ip_info_t ip;
514  esp_netif_get_ip_info(this->eth_netif_, &ip);
515  ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(&ip.ip).str().c_str());
516  ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());
517  ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(&ip.netmask).str().c_str());
518  ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(&ip.gw).str().c_str());
519 
520  const ip_addr_t *dns_ip1 = dns_getserver(0);
521  const ip_addr_t *dns_ip2 = dns_getserver(1);
522 
523  ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1).str().c_str());
524  ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2).str().c_str());
525 
526 #if USE_NETWORK_IPV6
527  struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
528  uint8_t count = 0;
529  count = esp_netif_get_all_ip6(this->eth_netif_, if_ip6s);
530  assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES);
531  for (int i = 0; i < count; i++) {
532  ESP_LOGCONFIG(TAG, " IPv6: " IPV6STR, IPV62STR(if_ip6s[i]));
533  }
534 #endif /* USE_NETWORK_IPV6 */
535 
536  ESP_LOGCONFIG(TAG, " MAC Address: %s", this->get_eth_mac_address_pretty().c_str());
537  ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL));
538  ESP_LOGCONFIG(TAG, " Link Speed: %u", this->get_link_speed() == ETH_SPEED_100M ? 100 : 10);
539 }
540 
541 #ifdef USE_ETHERNET_SPI
542 void EthernetComponent::set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
543 void EthernetComponent::set_miso_pin(uint8_t miso_pin) { this->miso_pin_ = miso_pin; }
544 void EthernetComponent::set_mosi_pin(uint8_t mosi_pin) { this->mosi_pin_ = mosi_pin; }
545 void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
546 void EthernetComponent::set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
547 void EthernetComponent::set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; }
548 void EthernetComponent::set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; }
549 #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
550 void EthernetComponent::set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; }
551 #endif
552 #else
553 void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; }
554 void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; }
555 void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
556 void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
557 void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) {
558  this->clk_mode_ = clk_mode;
559  this->clk_gpio_ = clk_gpio;
560 }
561 void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); }
562 #endif
564 void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
565 
567  if (this->use_address_.empty()) {
568  return App.get_name() + ".local";
569  }
570  return this->use_address_;
571 }
572 
573 void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
574 
576  esp_err_t err;
577  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, mac);
578  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error");
579 }
580 
582  uint8_t mac[6];
583  get_mac_address_raw(mac);
584  return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
585 }
586 
588  esp_err_t err;
589  eth_duplex_t duplex_mode;
590  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode);
591  ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_DUPLEX_MODE error", ETH_DUPLEX_HALF);
592  return duplex_mode;
593 }
594 
596  esp_err_t err;
597  eth_speed_t speed;
598  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed);
599  ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_SPEED error", ETH_SPEED_10M);
600  return speed;
601 }
602 
604  ESP_LOGI(TAG, "Powering down ethernet PHY");
605  if (this->phy_ == nullptr) {
606  ESP_LOGE(TAG, "Ethernet PHY not assigned");
607  return false;
608  }
609  this->connected_ = false;
610  this->started_ = false;
611  if (this->phy_->pwrctl(this->phy_, false) != ESP_OK) {
612  ESP_LOGE(TAG, "Error powering down ethernet PHY");
613  return false;
614  }
615  return true;
616 }
617 
618 #ifndef USE_ETHERNET_SPI
619 
620 constexpr uint8_t KSZ80XX_PC2R_REG_ADDR = 0x1F;
621 
623  esp_err_t err;
624 
625  uint32_t phy_control_2;
626  err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2));
627  ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed");
628  ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str());
629 
630  /*
631  * Bit 7 is `RMII Reference Clock Select`. Default is `0`.
632  * KSZ8081RNA:
633  * 0 - clock input to XI (Pin 8) is 25 MHz for RMII - 25 MHz clock mode.
634  * 1 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode.
635  * KSZ8081RND:
636  * 0 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode.
637  * 1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII - 25 MHz clock mode.
638  */
639  if ((phy_control_2 & (1 << 7)) != (1 << 7)) {
640  phy_control_2 |= 1 << 7;
641  err = mac->write_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, phy_control_2);
642  ESPHL_ERROR_CHECK(err, "Write PHY Control 2 failed");
643  err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2));
644  ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed");
645  ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str());
646  }
647 }
648 
649 void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data) {
650  esp_err_t err;
651  constexpr uint8_t eth_phy_psr_reg_addr = 0x1F;
652 
653  if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
654  ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page);
655  err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, register_data.page);
656  ESPHL_ERROR_CHECK(err, "Select PHY Register page failed");
657  }
658 
659  ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address);
660  ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value);
661  err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value);
662  ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");
663 
664  if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
665  ESP_LOGD(TAG, "Select PHY Register Page 0x00");
666  err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0);
667  ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed");
668  }
669 }
670 
671 #endif
672 
673 } // namespace ethernet
674 } // namespace esphome
675 
676 #endif // USE_ESP32
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
Definition: helpers.cpp:369
void set_manual_ip(const ManualIP &manual_ip)
esp_eth_phy_t * esp_eth_phy_new_jl1101(const eth_phy_config_t *config)
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
void ksz8081_set_clock_reference_(esp_eth_mac_t *mac)
Set RMII Reference Clock Select bit for KSZ8081.
std::string str() const
Definition: ip_address.h:122
void set_interrupt_pin(uint8_t interrupt_pin)
int speed
Definition: fan.h:35
network::IPAddress get_dns_address(uint8_t num)
static void got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
constexpr uint8_t KSZ80XX_PC2R_REG_ADDR
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
EthernetComponent * global_eth_component
void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio)
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
void status_clear_warning()
Definition: component.cpp:166
uint8_t type
Application App
Global storage of Application pointer - only one Application can exist.
const std::string & get_name() const
Get the name of this Application set by pre_setup().
Definition: application.h:202
std::array< IPAddress, 5 > IPAddresses
Definition: ip_address.h:141
void set_use_address(const std::string &use_address)
uint8_t status
Definition: bl0942.h:74
void add_phy_register(PHYRegister register_value)
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
in_addr ip_addr_t
Definition: ip_address.h:22
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
uint8_t event_id
Definition: tt21100.cpp:15
void set_polling_interval(uint32_t polling_interval)
void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data)
Set arbitratry PHY registers from config.
std::vector< PHYRegister > phy_registers_
std::string str_snprintf(const char *fmt, size_t len,...)
Definition: helpers.cpp:306
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
Definition: helpers.cpp:685