Files
ESP32-POE-NW-TEST/main/main.c
2021-09-29 13:31:28 +02:00

430 lines
15 KiB
C

/* 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 <stdio.h>
#include <string.h>
#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 <driver/adc.h>
#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, &eth_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, &eth_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);
}
}