/* 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 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; esp_ping_handle_t ping; int dns_resolv = -1; bool blink_mod = false; 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); } } //TODO: Implement ping https://github.com/espressif/esp-idf/blob/master/examples/protocols/icmp_echo/main/echo_example_main.c static void start_icmp_ping() { esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG(); config.timeout_ms = 1000; config.interval_ms = 1000; config.count = 16; config.target_addr = target_addr; /* set callback functions */ esp_ping_callbacks_t cbs = { .on_ping_success = cmd_ping_on_ping_success, .on_ping_timeout = cmd_ping_on_ping_timeout, .on_ping_end = cmd_ping_on_ping_end, .cb_args = NULL }; esp_ping_new_session(&config, &cbs, &ping); esp_ping_start(ping); return 0; } 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 task_signals(void* arg) { uint32_t sig; for(;;) { if(xQueueReceive(signal_queue, &sig, portMAX_DELAY)) { 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(); } } } } #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); 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 //zero-initialize the config structure. gpio_config_t io_conf = {}; //interrupt of rising edge io_conf.intr_type = GPIO_INTR_POSEDGE; //bit mask of the pins, here 34 io_conf.pin_bit_mask = 1ULL<<34; //set as input mode io_conf.mode = GPIO_MODE_INPUT; ESP_ERROR_CHECK(gpio_config(&io_conf)); ESP_ERROR_CHECK(gpio_set_intr_type(34, GPIO_INTR_POSEDGE)); // interrut for shutdown/deep sleep ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LOWMED)); ESP_ERROR_CHECK(gpio_isr_handler_add(34, isr_shutdown, NULL)); // signal task, to catch shutdown signal signal_queue = xQueueCreate(10, sizeof(uint32_t)); //start signal task xTaskCreate(task_signals, "signals", 2048, NULL, 10, NULL); // start task to continually check dns resolution xTaskCreate(check_resolution, "dns_res", 2048, NULL, 10, NULL); // continuously refresh display // not all events trigger refreshing the disply while (1) { blink_mod = !blink_mod; refresh_display(); vTaskDelay(350 / portTICK_RATE_MS); } }