/* Ethernet Basic 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 #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_netif.h" #include "esp_eth.h" #include "esp_event.h" #include "esp_log.h" #include "esp_sleep.h" #include "driver/gpio.h" #include #include "sdkconfig.h" #include "lwip/inet.h" #include "lwip/netdb.h" #include "lwip/sockets.h" #include "ssd1306.h" #include "font8x8_basic.h" static const char *TAG = "eth_tester"; #define IP_FSTRING "%3d.%3d.%3d.%3d" #define SIGNAL_SHUTDOWN 1 #define SIGNAL_BUTTON 2 #define SIGNAL_PAR_OFFSET 24 #define SIGNAL_MASK 0x00FFFFFF #define LINE_STATUS_MAIN 0 #define LINE_ID_ADDR 2 #define LINE_IP_SNM 3 #define LINE_IP_GW 4 #define LINE_STATUS_FLAGS1 5 #define LINE_STATUS_FLAGS2 6 #define LINE_STATUS_FLAGS3 7 SSD1306_t display; uint8_t mac_addr[6] = {0}; eth_event_t eth_state = ETHERNET_EVENT_STOP; esp_ip4_addr_t ip_addr; esp_ip4_addr_t ip_snm; esp_ip4_addr_t ip_gw; esp_netif_t *eth_netif; int dns_resolv = -1; bool blink_mod = false; #define ex_button_count 4 uint32_t ex_buttons[ex_button_count] = {15, 14, 2, 5}; static uint8_t get_byte(uint32_t addr, int n) { return (addr >> (8 * n)) & 0xFF; } #define IP4ZCHK(ipaddr) (esp_ip4_addr1_16(ipaddr) | esp_ip4_addr2_16(ipaddr) | esp_ip4_addr3_16(ipaddr) | esp_ip4_addr4_16(ipaddr)) static int check_dns() { esp_netif_dns_info_t dns_info; ESP_ERROR_CHECK(esp_netif_get_dns_info(eth_netif, ESP_NETIF_DNS_MAIN, &dns_info)); // ESP_LOGI(TAG, IP_FSTRING, IP2STR(&dns_info.ip.u_addr.ip4)); // ESP_LOGI(TAG, "%d", IP4ZCHK(&dns_info.ip.u_addr.ip4)); if (IP4ZCHK(&dns_info.ip.u_addr.ip4) != 0) return 1; return 0; } static void check_resolution(void *arg) { struct addrinfo hint; struct addrinfo *res = NULL; memset(&hint, 0, sizeof(hint)); while (1) { dns_resolv = getaddrinfo("www.google.de", NULL, &hint, &res); vTaskDelay(250 / portTICK_RATE_MS); } } static void refresh_display() { char buf[64]; int buflen; switch (eth_state) { case ETHERNET_EVENT_CONNECTED: buflen = sprintf(buf, "%-16s", "LINK UP"); // ssd1306_clear_line(&display, LINE_STATUS_MAIN, false); ssd1306_display_text(&display, LINE_STATUS_MAIN, buf, buflen, false, 0); // buflen = sprintf(buf, "MAC:%02X%02X%02X%02X%02X%02X", // mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); // ssd1306_clear_line(&display, 1, false); // ssd1306_display_text(&display, 1, buf, buflen, false, 0); break; case ETHERNET_EVENT_DISCONNECTED: buflen = sprintf(buf, "%-16s", "LINK DOWN"); // ssd1306_clear_screen(&display, false); ssd1306_display_text(&display, LINE_STATUS_MAIN, buf, buflen, false, 0); ssd1306_clear_line(&display, LINE_ID_ADDR, false); ssd1306_clear_line(&display, LINE_IP_SNM, false); ssd1306_clear_line(&display, LINE_IP_GW, false); break; case ETHERNET_EVENT_START: buflen = sprintf(buf, "%-16s", "ETH RDY"); // ssd1306_clear_screen(&display, false); ssd1306_display_text(&display, LINE_STATUS_MAIN, buf, buflen, false, 0); break; case ETHERNET_EVENT_STOP: buflen = sprintf(buf, "%-16s", "ETH DOWN"); // ssd1306_clear_screen(&display, false); ssd1306_display_text(&display, LINE_STATUS_MAIN, buf, buflen, false, 0); ssd1306_clear_line(&display, LINE_ID_ADDR, false); ssd1306_clear_line(&display, LINE_IP_SNM, false); ssd1306_clear_line(&display, LINE_IP_GW, false); break; default: break; } if ((eth_state == ETHERNET_EVENT_CONNECTED) & (ip_addr.addr != 0)){ // ssd1306_clear_line(&display, 2, false); // ssd1306_display_text(&display, 2, "IP", 2, false, 0); buflen = sprintf(buf, IP_FSTRING, IP2STR(&ip_addr)); //ssd1306_clear_line(&display, 3, false); ssd1306_display_text(&display, LINE_ID_ADDR, "I", 3, true, 0); ssd1306_display_text(&display, LINE_ID_ADDR, buf, buflen, false, 1); buflen = sprintf(buf, IP_FSTRING, IP2STR(&ip_snm)); //ssd1306_clear_line(&display, 4, false); ssd1306_display_text(&display, LINE_IP_SNM, "S", 1, true, 0); ssd1306_display_text(&display, LINE_IP_SNM, buf, buflen, false, 1); buflen = sprintf(buf, IP_FSTRING, IP2STR(&ip_gw)); //ssd1306_clear_line(&display, 5, false); ssd1306_display_text(&display, LINE_IP_GW, "G", 1, true, 0); ssd1306_display_text(&display, LINE_IP_GW, buf, buflen, false, 1); } bool poe = (adc1_get_raw(ADC1_CHANNEL_3) > 2048); //arbitrary value, battery power is ~800 bool eth = (eth_state == ETHERNET_EVENT_CONNECTED); bool addr = (ip_addr.addr != 0) & eth; bool dns = ((check_dns()) && addr && blink_mod) || (dns_resolv == 0); ssd1306_clear_line(&display, LINE_STATUS_FLAGS3, false); ssd1306_display_text(&display, LINE_STATUS_FLAGS3, "POE", 3, poe, 13); ssd1306_display_text(&display, LINE_STATUS_FLAGS3, "LNK", 3, eth, 9); ssd1306_display_text(&display, LINE_STATUS_FLAGS3, "DHCP", 4, addr, 4); ssd1306_display_text(&display, LINE_STATUS_FLAGS3, "DNS", 3, dns, 0); } /** Event handler for Ethernet events */ static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { /* we can get the ethernet driver handle from event data */ esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; eth_state = event_id; switch (event_id) { case ETHERNET_EVENT_CONNECTED: esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); ESP_LOGI(TAG, "Ethernet Link Up"); ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: ESP_LOGI(TAG, "Link Down"); dns_resolv = -1; break; case ETHERNET_EVENT_START: ESP_LOGI(TAG, "Ethernet Started"); break; case ETHERNET_EVENT_STOP: ESP_LOGI(TAG, "Ethernet Stopped"); dns_resolv = -1; break; default: break; } refresh_display(); } /** Event handler for IP_EVENT_ETH_GOT_IP */ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; const esp_netif_ip_info_t *ip_info = &event->ip_info; ESP_LOGI(TAG, "Ethernet Got IP Address"); ESP_LOGI(TAG, "~~~~~~~~~~~"); ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip)); ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); ESP_LOGI(TAG, "~~~~~~~~~~~"); ip_addr = ip_info->ip; ip_snm = ip_info->netmask; ip_gw = ip_info->gw; refresh_display(); } static xQueueHandle signal_queue = NULL; static void IRAM_ATTR isr_shutdown(void* arg) { uint32_t sig = SIGNAL_SHUTDOWN; xQueueSendFromISR(signal_queue, &sig, NULL); } static void IRAM_ATTR isr_button(void* arg) { uint32_t sig = SIGNAL_BUTTON; uint32_t mod = (uint32_t)arg; sig = sig | (mod << SIGNAL_PAR_OFFSET); xQueueSendFromISR(signal_queue, &sig, NULL); } static void task_signals(void* arg) { uint32_t dat; uint32_t sig; uint32_t par; for(;;) { if(xQueueReceive(signal_queue, &dat, portMAX_DELAY)) { //ESP_LOGI(TAG, "Signal: %x", dat); sig = dat & SIGNAL_MASK; par = sig >> SIGNAL_PAR_OFFSET; if (sig == SIGNAL_SHUTDOWN) { ESP_LOGI(TAG, "Got shutdown trigger, going to sleep..."); ssd1306_clear_screen(&display, false); esp_sleep_enable_ext0_wakeup(34, 0); esp_deep_sleep_start(); } if (sig == SIGNAL_BUTTON) { //ESP_LOGI(TAG, "Button pressed: %d", par); } } } } // void icmp_ping(in_addr_t ip) // { // /* convert URL to IP address */ // ip_addr_t target_addr; // struct addrinfo hint; // struct addrinfo *res = NULL; // memset(&hint, 0, sizeof(hint)); // memset(&target_addr, 0, sizeof(target_addr)); // getaddrinfo("www.espressif.com", NULL, &hint, &res); // struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr; // inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4); // freeaddrinfo(res); // esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); // ping_config.target_addr = target_addr; // target IP address // ping_config.count = ESP_PING_COUNT_INFINITE; // ping in infinite mode, esp_ping_stop can stop it // /* set callback functions */ // esp_ping_callbacks_t cbs; // cbs.on_ping_success = test_on_ping_success; // cbs.on_ping_timeout = test_on_ping_timeout; // cbs.on_ping_end = test_on_ping_end; // cbs.cb_args = "foo"; // arguments that will feed to all callback functions, can be NULL // cbs.cb_args = eth_event_group; // esp_ping_handle_t ping; // esp_ping_new_session(&ping_config, &cbs, &ping); // } #define PIN_PHY_POWER 12 void app_main(void) { // ############################################################### // # Display Configuration # // ############################################################### SSD1306_t dev; #if CONFIG_I2C_INTERFACE ESP_LOGI(TAG, "INTERFACE is i2c"); ESP_LOGI(TAG, "CONFIG_SDA_GPIO=%d",CONFIG_SDA_GPIO); ESP_LOGI(TAG, "CONFIG_SCL_GPIO=%d",CONFIG_SCL_GPIO); ESP_LOGI(TAG, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO); i2c_master_init(&dev, CONFIG_SDA_GPIO, CONFIG_SCL_GPIO, CONFIG_RESET_GPIO); #endif // CONFIG_I2C_INTERFACE #if CONFIG_SPI_INTERFACE ESP_LOGI(TAG, "INTERFACE is SPI"); ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d",CONFIG_MOSI_GPIO); ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d",CONFIG_SCLK_GPIO); ESP_LOGI(TAG, "CONFIG_CS_GPIO=%d",CONFIG_CS_GPIO); ESP_LOGI(TAG, "CONFIG_DC_GPIO=%d",CONFIG_DC_GPIO); ESP_LOGI(TAG, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO); spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_CS_GPIO, CONFIG_DC_GPIO, CONFIG_RESET_GPIO); #endif // CONFIG_SPI_INTERFACE #if CONFIG_FLIP dev._flip = true; ESP_LOGW(TAG, "Flip upside down"); #endif #if CONFIG_SSD1306_128x64 ESP_LOGI(TAG, "Panel is 128x64"); ssd1306_init(&dev, 128, 64); #endif // CONFIG_SSD1306_128x64 #if CONFIG_SSD1306_128x32 ESP_LOGI(TAG, "Panel is 128x32"); ssd1306_init(&dev, 128, 32); #endif // CONFIG_SSD1306_128x32 ssd1306_clear_screen(&dev, false); ssd1306_contrast(&dev, 0xff); ssd1306_display_text(&display, 0, "Waiting for eth", 15, false, 0); display = dev; // ############################################################### // # Ethernet Configuration # // ############################################################### // Initialize TCP/IP network interface (should be called only once in application) ESP_ERROR_CHECK(esp_netif_init()); // Create default event loop that running in background ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); eth_netif = esp_netif_new(&cfg); // Set default handlers to process TCP/IP stuffs ESP_ERROR_CHECK(esp_eth_set_default_handlers(eth_netif)); // Register user defined event handers ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr = CONFIG_ETH_ETH_PHY_ADDR; phy_config.reset_gpio_num = CONFIG_ETH_ETH_PHY_RST_GPIO; gpio_pad_select_gpio(PIN_PHY_POWER); gpio_set_direction(PIN_PHY_POWER,GPIO_MODE_OUTPUT); gpio_set_level(PIN_PHY_POWER, 1); vTaskDelay(pdMS_TO_TICKS(10)); #if CONFIG_ETH_USE_INTERNAL_ETHERNET mac_config.smi_mdc_gpio_num = CONFIG_ETH_ETH_MDC_GPIO; mac_config.smi_mdio_gpio_num = CONFIG_ETH_ETH_MDIO_GPIO; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_ETH_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); #elif CONFIG_ETH_ETH_PHY_RTL8201 esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config); #elif CONFIG_ETH_ETH_PHY_LAN8720 esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config); #elif CONFIG_ETH_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); #endif #elif CONFIG_ETH_USE_DM9051 gpio_install_isr_service(0); spi_device_handle_t spi_handle = NULL; spi_bus_config_t buscfg = { .miso_io_num = CONFIG_ETH_DM9051_MISO_GPIO, .mosi_io_num = CONFIG_ETH_DM9051_MOSI_GPIO, .sclk_io_num = CONFIG_ETH_DM9051_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETH_DM9051_SPI_HOST, &buscfg, 1)); spi_device_interface_config_t devcfg = { .command_bits = 1, .address_bits = 7, .mode = 0, .clock_speed_hz = CONFIG_ETH_DM9051_SPI_CLOCK_MHZ * 1000 * 1000, .spics_io_num = CONFIG_ETH_DM9051_CS_GPIO, .queue_size = 20 }; ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_ETH_DM9051_SPI_HOST, &devcfg, &spi_handle)); /* dm9051 ethernet driver is based on spi driver */ eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); dm9051_config.int_gpio_num = CONFIG_ETH_DM9051_INT_GPIO; esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle)); /* attach Ethernet driver to TCP/IP stack */ ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle))); /* start Ethernet driver state machine */ ESP_ERROR_CHECK(esp_eth_start(eth_handle)); // ############################################################### // # Misc Configuration # // ############################################################### // setup power in measurement (for PoE detection) adc1_config_width(ADC_WIDTH_12Bit); adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11); // gpio setup // front buttons //zero-initialize the config structure. gpio_config_t io_conf = {}; //interrupt of rising edge io_conf.intr_type = GPIO_INTR_NEGEDGE; //bit mask of the pins, here 34 + front buttons io_conf.pin_bit_mask = 1ULL<<34; for (int i = 0; i < ex_button_count; i++) { io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL<