ethernet.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "sdkconfig.h"
  2. #ifdef CONFIG_ETH_W5500_ENABLED
  3. #include "ethernet.h"
  4. #include "settings.h"
  5. #include "esp_event.h"
  6. #include "esp_log.h"
  7. #include "esp_netif.h"
  8. #include "driver/gpio.h"
  9. #include "driver/spi_master.h"
  10. #include "esp_eth.h"
  11. #include "esp_eth_mac.h"
  12. #include "esp_eth_mac_spi.h"
  13. #include "esp_eth_netif_glue.h"
  14. #include "esp_eth_phy.h"
  15. #include "esp_mac.h"
  16. #include "iot_board.h"
  17. #include <string.h>
  18. static const char *TAG = "ethernet";
  19. #define ETH_SPI_CLOCK_MHZ 20
  20. // lwIP DHCP hostnames are limited to 31 characters plus the trailing NUL.
  21. #define DHCP_HOSTNAME_MAX_LEN 31
  22. static esp_netif_t *s_eth_netif = NULL;
  23. static esp_eth_handle_t s_eth_handle = NULL;
  24. static bool s_eth_connected = false;
  25. static bool s_eth_link_up = false;
  26. static void eth_event_handler(void *arg, esp_event_base_t event_base,
  27. int32_t event_id, void *event_data) {
  28. (void)arg;
  29. switch (event_id) {
  30. case ETHERNET_EVENT_CONNECTED:
  31. s_eth_link_up = true;
  32. ESP_LOGI(TAG, "Ethernet link up");
  33. break;
  34. case ETHERNET_EVENT_DISCONNECTED:
  35. s_eth_link_up = false;
  36. s_eth_connected = false;
  37. ESP_LOGW(TAG, "Ethernet link down");
  38. break;
  39. case ETHERNET_EVENT_START:
  40. ESP_LOGI(TAG, "Ethernet started");
  41. break;
  42. case ETHERNET_EVENT_STOP:
  43. s_eth_connected = false;
  44. ESP_LOGI(TAG, "Ethernet stopped");
  45. break;
  46. default:
  47. break;
  48. }
  49. }
  50. static void eth_got_ip_handler(void *arg, esp_event_base_t event_base,
  51. int32_t event_id, void *event_data) {
  52. (void)arg;
  53. ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
  54. if (event->esp_netif == s_eth_netif) {
  55. ESP_LOGI(TAG, "Ethernet got IP: " IPSTR, IP2STR(&event->ip_info.ip));
  56. s_eth_connected = true;
  57. }
  58. }
  59. esp_err_t ethernet_init(void) {
  60. if (s_eth_handle != NULL) {
  61. ESP_LOGW(TAG, "Ethernet already initialized");
  62. return ESP_OK;
  63. }
  64. // Verify SPI bus is ready (board.c must have initialized it)
  65. if (iot_board_get_handle(BOARD_SPI_ETH_ID) == NULL) {
  66. ESP_LOGE(TAG, "SPI bus not initialized — cannot init W5500");
  67. return ESP_ERR_INVALID_STATE;
  68. }
  69. // Ensure netif and event loop are initialized
  70. esp_err_t ret = esp_netif_init();
  71. if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
  72. return ret;
  73. }
  74. ret = esp_event_loop_create_default();
  75. if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
  76. return ret;
  77. }
  78. // Register event handlers
  79. ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID,
  80. &eth_event_handler, NULL));
  81. ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
  82. &eth_got_ip_handler, NULL));
  83. // Create default ethernet netif
  84. esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
  85. s_eth_netif = esp_netif_new(&netif_cfg);
  86. // Hardware reset the W5500 before SPI communication
  87. #if BOARD_ETH_RST_GPIO >= 0
  88. gpio_config_t rst_cfg = {
  89. .pin_bit_mask = (1ULL << BOARD_ETH_RST_GPIO),
  90. .mode = GPIO_MODE_OUTPUT,
  91. .pull_up_en = GPIO_PULLUP_DISABLE,
  92. .pull_down_en = GPIO_PULLDOWN_DISABLE,
  93. .intr_type = GPIO_INTR_DISABLE,
  94. };
  95. gpio_config(&rst_cfg);
  96. gpio_set_level(BOARD_ETH_RST_GPIO, 0);
  97. vTaskDelay(pdMS_TO_TICKS(10));
  98. gpio_set_level(BOARD_ETH_RST_GPIO, 1);
  99. vTaskDelay(pdMS_TO_TICKS(10));
  100. ESP_LOGI(TAG, "W5500 hardware reset complete (GPIO %d)", BOARD_ETH_RST_GPIO);
  101. #endif
  102. // Configure SPI device for W5500 (bus already initialized by board.c)
  103. spi_device_interface_config_t spi_devcfg = {
  104. .mode = 0,
  105. .clock_speed_hz = ETH_SPI_CLOCK_MHZ * 1000 * 1000,
  106. .queue_size = 16,
  107. .spics_io_num = BOARD_ETH_CS_GPIO,
  108. };
  109. eth_w5500_config_t w5500_config =
  110. ETH_W5500_DEFAULT_CONFIG(BOARD_SPI_HOST, &spi_devcfg);
  111. w5500_config.int_gpio_num = BOARD_ETH_INT_GPIO;
  112. #if BOARD_ETH_INT_GPIO < 0
  113. w5500_config.poll_period_ms = 10;
  114. #endif
  115. // Create MAC instance
  116. eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
  117. mac_config.rx_task_stack_size = 4096;
  118. esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
  119. if (mac == NULL) {
  120. ESP_LOGE(TAG, "Failed to create W5500 MAC");
  121. esp_netif_destroy(s_eth_netif);
  122. s_eth_netif = NULL;
  123. return ESP_FAIL;
  124. }
  125. // Create PHY instance
  126. eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
  127. phy_config.reset_gpio_num = -1; // We already did HW reset above
  128. esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
  129. if (phy == NULL) {
  130. ESP_LOGE(TAG, "Failed to create W5500 PHY");
  131. mac->del(mac);
  132. esp_netif_destroy(s_eth_netif);
  133. s_eth_netif = NULL;
  134. return ESP_FAIL;
  135. }
  136. // Install Ethernet driver
  137. esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
  138. ret = esp_eth_driver_install(&eth_config, &s_eth_handle);
  139. if (ret != ESP_OK) {
  140. ESP_LOGE(TAG, "Ethernet driver install failed: %s", esp_err_to_name(ret));
  141. phy->del(phy);
  142. mac->del(mac);
  143. esp_netif_destroy(s_eth_netif);
  144. s_eth_netif = NULL;
  145. return ret;
  146. }
  147. // W5500 has no factory MAC — derive one from the ESP32's base MAC
  148. uint8_t eth_mac[6];
  149. esp_read_mac(eth_mac, ESP_MAC_ETH);
  150. esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, eth_mac);
  151. ESP_LOGI(TAG, "Ethernet MAC: %02X:%02X:%02X:%02X:%02X:%02X", eth_mac[0],
  152. eth_mac[1], eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]);
  153. // Attach netif glue
  154. esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(s_eth_handle);
  155. ESP_ERROR_CHECK(esp_netif_attach(s_eth_netif, glue));
  156. // Set hostname before DHCP starts
  157. char dev_name[65];
  158. settings_get_device_name(dev_name, sizeof(dev_name));
  159. ethernet_set_hostname(dev_name);
  160. // Start Ethernet
  161. ret = esp_eth_start(s_eth_handle);
  162. if (ret != ESP_OK) {
  163. ESP_LOGE(TAG, "Ethernet start failed: %s", esp_err_to_name(ret));
  164. return ret;
  165. }
  166. ESP_LOGI(TAG, "W5500 Ethernet initialized (CS=%d, INT=%d, RST=%d)",
  167. BOARD_ETH_CS_GPIO, BOARD_ETH_INT_GPIO, BOARD_ETH_RST_GPIO);
  168. return ESP_OK;
  169. }
  170. void ethernet_set_hostname(const char *device_name) {
  171. if (!s_eth_netif || !device_name) {
  172. return;
  173. }
  174. char hostname[DHCP_HOSTNAME_MAX_LEN + 1];
  175. size_t j = 0;
  176. for (size_t i = 0; device_name[i] && j < sizeof(hostname) - 1; i++) {
  177. char c = device_name[i];
  178. if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  179. (c >= '0' && c <= '9')) {
  180. hostname[j++] = c;
  181. } else if (j > 0 && hostname[j - 1] != '-') {
  182. hostname[j++] = '-';
  183. }
  184. }
  185. while (j > 0 && hostname[j - 1] == '-') {
  186. j--;
  187. }
  188. if (j == 0) {
  189. strlcpy(hostname, "esp32-airplay", sizeof(hostname));
  190. } else {
  191. hostname[j] = '\0';
  192. }
  193. esp_err_t err = esp_netif_set_hostname(s_eth_netif, hostname);
  194. if (err != ESP_OK) {
  195. ESP_LOGE(TAG, "Failed to set hostname '%s': %s", hostname,
  196. esp_err_to_name(err));
  197. } else {
  198. ESP_LOGI(TAG, "Hostname set to: %s", hostname);
  199. }
  200. }
  201. bool ethernet_is_connected(void) {
  202. return s_eth_connected;
  203. }
  204. bool ethernet_is_link_up(void) {
  205. return s_eth_link_up;
  206. }
  207. esp_err_t ethernet_get_ip_str(char *ip_str, size_t len) {
  208. if (!s_eth_netif || !ip_str || len == 0) {
  209. return ESP_ERR_INVALID_ARG;
  210. }
  211. esp_netif_ip_info_t ip_info;
  212. esp_err_t err = esp_netif_get_ip_info(s_eth_netif, &ip_info);
  213. if (err == ESP_OK) {
  214. snprintf(ip_str, len, IPSTR, IP2STR(&ip_info.ip));
  215. }
  216. return err;
  217. }
  218. void ethernet_get_mac_str(char *mac_str, size_t len) {
  219. if (!mac_str || len == 0) {
  220. return;
  221. }
  222. if (!s_eth_handle) {
  223. mac_str[0] = '\0';
  224. return;
  225. }
  226. uint8_t mac[6];
  227. if (esp_eth_ioctl(s_eth_handle, ETH_CMD_G_MAC_ADDR, mac) == ESP_OK) {
  228. snprintf(mac_str, len, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1],
  229. mac[2], mac[3], mac[4], mac[5]);
  230. } else {
  231. mac_str[0] = '\0';
  232. }
  233. }
  234. #endif // CONFIG_ETH_W5500_ENABLED