/* eth2ap (Ethernet to Wi-Fi AP packet forwarding) 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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_private/wifi.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "tcpip_adapter.h"
#include "esp_netif.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip.h"
#include "lwip/netdb.h"
#include "ping/ping_sock.h"
#include "esp_ping.h"
#include "esp_err.h"


//custom
#define PING_TARGET_HOSTNAME "google.com"
#define PING_TARGET_IPV4 "8.8.8.8"

#define NR_OF_IP_ADDRESSES_TO_WAIT_FOR 1
//end custom

static const char *TAG = "eth_example";
static esp_eth_handle_t s_eth_handle = NULL;
static xQueueHandle flow_control_queue = NULL;
static bool s_sta_is_connected = false;
static bool s_ethernet_is_connected = false;
static uint8_t s_eth_mac[6];


#define FLOW_CONTROL_QUEUE_TIMEOUT_MS (100)
#define FLOW_CONTROL_QUEUE_LENGTH (40)
#define FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS (100)


typedef struct {
    void *packet;
    uint16_t length;
} flow_control_msg_t;


//custom
static bool is_our_netif(const char *prefix, esp_netif_t *netif)
{
    return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix)-1) == 0;
}

static esp_ip4_addr_t s_ip_addr;
static xSemaphoreHandle s_semph_get_ip_addrs;
static void *s_eth_glue = NULL;

static void on_got_ip(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;
    if (!is_our_netif(TAG, event->esp_netif)) {
        ESP_LOGW(TAG, "Got IPv4 from another interface \"%s\": ignored", esp_netif_get_desc(event->esp_netif));
        return;
    }
    ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
    memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
    xSemaphoreGive(s_semph_get_ip_addrs);
}

//end custom






// Forward packets from Wi-Fi to Ethernet
static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb)
{
    if (s_ethernet_is_connected) {
        if (esp_eth_transmit(s_eth_handle, buffer, len) != ESP_OK) {
            ESP_LOGE(TAG, "Ethernet send packet failed");
        }
    }
    esp_wifi_internal_free_rx_buffer(eb);
    return ESP_OK;
}

// Forward packets from Ethernet to Wi-Fi
// Note that, Ethernet works faster than Wi-Fi on ESP32,
// so we need to add an extra queue to balance their speed difference.
static esp_err_t pkt_eth2wifi(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t len, void* priv)
{
    esp_err_t ret = ESP_OK;
    flow_control_msg_t msg = {
        .packet = buffer,
        .length = len
    };
    if (xQueueSend(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) != pdTRUE) {
        ESP_LOGE(TAG, "send flow control message failed or timeout");
        free(buffer);
        ret = ESP_FAIL;
    }
    return ret;
}

// This task will fetch the packet from the queue, and then send out through Wi-Fi.
// Wi-Fi handles packets slower than Ethernet, we might add some delay between each transmitting.
static void eth2wifi_flow_control_task(void *args)
{
    flow_control_msg_t msg;
    int res = 0;
    uint32_t timeout = 0;
    while (1) {
        if (xQueueReceive(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) == pdTRUE) {
            timeout = 0;
            if (s_sta_is_connected && msg.length) {
                do {
                    vTaskDelay(pdMS_TO_TICKS(timeout));
                    timeout += 2;
                    res = esp_wifi_internal_tx(ESP_IF_WIFI_AP, msg.packet, msg.length);
                } while (res && timeout < FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS);
                if (res != ESP_OK) {
                    ESP_LOGE(TAG, "WiFi send packet failed: %d", res);
                }
            }
            free(msg.packet);
        }
    }
    vTaskDelete(NULL);
}

// Event handler for Ethernet
static void eth_event_handler(void *arg, esp_event_base_t event_base,
                              int32_t event_id, void *event_data)
{
    switch (event_id) {
    case ETHERNET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "Ethernet Link Up");
        s_ethernet_is_connected = true;
        esp_eth_ioctl(s_eth_handle, ETH_CMD_G_MAC_ADDR, s_eth_mac);
        esp_wifi_set_mac(WIFI_IF_AP, s_eth_mac);
        ESP_ERROR_CHECK(esp_wifi_start());
        break;
    case ETHERNET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "Ethernet Link Down");
        s_ethernet_is_connected = false;
        ESP_ERROR_CHECK(esp_wifi_stop());
        break;
    case ETHERNET_EVENT_START:
        ESP_LOGI(TAG, "Ethernet Started");
        break;
    case ETHERNET_EVENT_STOP:
        ESP_LOGI(TAG, "Ethernet Stopped");
        break;
    default:
        break;
    }
}

// Event handler for Wi-Fi
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
{
    static uint8_t s_con_cnt = 0;
    switch (event_id) {
    case WIFI_EVENT_AP_STACONNECTED:
        ESP_LOGI(TAG, "Wi-Fi AP got a station connected");
        if (!s_con_cnt) {
            s_sta_is_connected = true;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, pkt_wifi2eth);
        }
        s_con_cnt++;
        break;
    case WIFI_EVENT_AP_STADISCONNECTED:
        ESP_LOGI(TAG, "Wi-Fi AP got a station disconnected");
        s_con_cnt--;
        if (!s_con_cnt) {
            s_sta_is_connected = false;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, NULL);
        }
        break;
    default:
        break;
    }
}

static void configure_static_ip(void)
{
    // Create a TCP/IP adapter instance
    tcpip_adapter_init();

    esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_ETH();

    // Set the static IP configuration
    esp_netif_ip_info_t ip_info;
    IP4_ADDR(&ip_info.ip, 192, 168, 1, 39);    // Set the desired IP address
    IP4_ADDR(&ip_info.gw, 192, 168, 1, 1);      // Set the gateway IP address
    IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);   // Set the subnet mask

    // Set the IP configuration for the AP interface
    tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_AP);  // Disable DHCP for the AP interface
    esp_netif_t *netif = esp_netif_new(&netif_config);
	esp_netif_set_ip_info(netif, &ip_info);

	//esp_netif_create_default_wifi_ap();
	esp_wifi_set_default_wifi_ap_handlers();
	//esp_wifi_start();

    // Enable the TCP/IP adapter for the AP interface
    //tcpip_adapter_if_t if_type = TCPIP_ADAPTER_IF_AP;
    //esp_netif_set_default_wifi_ap(netif);
}

int pingGoogle() {
    struct sockaddr_in target_addr;
    int sock;
    int err;
    struct addrinfo hints, *res;
    int result = 0;

    // Resolve the IP address of the target
    err = getaddrinfo(PING_TARGET_HOSTNAME, NULL, &hints, &res);
    if (err != 0 || res == NULL) {
        ESP_LOGE("pingGoogle", "Failed to resolve target address");
        return 0;
    }

    target_addr.sin_family = AF_INET;
    target_addr.sin_port = 0;
    target_addr.sin_addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;

    // Create a socket
    sock = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
    if (sock < 0) {
        ESP_LOGE("pingGoogle", "Failed to create socket");
        freeaddrinfo(res);
        return 0;
    }

    // Set socket receive timeout
    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    // Send the ping request
    err = sendto(sock, NULL, 0, 0, (struct sockaddr *)&target_addr, sizeof(target_addr));
    if (err < 0) {
        ESP_LOGE("pingGoogle", "Failed to send ping request");
        close(sock);
        freeaddrinfo(res);
        return 0;
    }

    // Receive the ping response
    uint8_t buffer[64];
    struct sockaddr_in from_addr;
    socklen_t from_addr_len = sizeof(from_addr);
    err = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&from_addr, &from_addr_len);
    if (err < 0) {
        ESP_LOGE("pingGoogle", "Failed to receive ping response");
        close(sock);
        freeaddrinfo(res);
        return 0;
    }

    // Check if the response is valid
    if (from_addr.sin_addr.s_addr == target_addr.sin_addr.s_addr) {
        result = 1;
    }

    // Close the socket and free the address info
    close(sock);
    freeaddrinfo(res);

    return result;
}


void setIPAddress(esp_netif_t* eth1_netif) {
	tcpip_adapter_init();
	tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH); // Don't run a DHCP client

	tcpip_adapter_ip_info_t ip_info;
	ip_info.ip.addr = ipaddr_addr("192.168.1.39");
	ip_info.gw.addr = ipaddr_addr("192.168.1.1");
	ip_info.netmask.addr = ipaddr_addr("255.255.255.0");

	tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &ip_info);

	tcpip_adapter_dns_info_t dns_info;
	const char* dns_server = "8.8.8.8";
	IP_ADDR4(&dns_info.ip, 8, 8, 8, 8);
	tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_ETH, ESP_NETIF_DNS_MAIN, &dns_info);
	/*esp_netif_dhcps_stop(eth1_netif);
	char* ip= "192.168.1.39";
	char* gateway = "192.168.1.1";
	char* netmask = "255.255.255.0";
	esp_netif_ip_info_t info_t;
	memset(&info_t, 0, sizeof(esp_netif_ip_info_t));
	ip4addr_aton((const char *)ip, &info_t.ip.addr);
	ip4addr_aton((const char *)gateway, &info_t.gw.addr);
	ip4addr_aton((const char *)netmask, &info_t.netmask.addr);
	esp_netif_set_ip_info(eth1_netif, &info_t);*/

	/*esp_netif_ip_info_t ip_info;
	ESP_LOGE(TAG, "Not Fail @ 8");
    IP4_ADDR(&ip_info.ip, 192, 168, 1, 39);
    ESP_LOGE(TAG, "Not Fail @ 9");
    IP4_ADDR(&ip_info.gw, 192, 168, 1, 1);
    ESP_LOGE(TAG, "Not Fail @ 10");
    IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
    ESP_LOGE(TAG, "Not Fail @ 11");
    //tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
    //esp_netif_dhcpc_stop(eth1_netif);
    //ESP_LOGE(TAG, "Not Fail @ 12");
    esp_netif_set_ip_info(eth1_netif, &ip_info);
    //esp_netif_set_ip_info(esp_netif_get_handle_from_ifkey("ETH_DEF"), &ip_info);
    ESP_LOGE(TAG, "Not Fail @ 13");
    */
}

static void initialize_ethernet(void)
{
	char *desc;

    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_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_EXAMPLE_ETH_PHY_ADDR;
    phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
    mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
    mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
    esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
#if CONFIG_EXAMPLE_ETH_PHY_IP101
    esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
    esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN8720
    esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
    esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
#elif CONFIG_EXAMPLE_USE_DM9051
    gpio_install_isr_service(0);
    spi_device_handle_t spi_handle = NULL;
    spi_bus_config_t buscfg = {
        .miso_io_num = CONFIG_EXAMPLE_DM9051_MISO_GPIO,
        .mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO,
        .sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1));
    spi_device_interface_config_t devcfg = {
        .command_bits = 1,
        .address_bits = 7,
        .mode = 0,
        .clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000,
        .spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO,
        .queue_size = 20
    };
    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_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_EXAMPLE_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
    //custom gustav
    esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();

    asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc);
        //esp_netif_config.ip_info->ip = (IPSTR) "192.168.1.125";
        esp_netif_config.if_desc = desc;
        esp_netif_config.route_prio = 64;
        esp_netif_config_t netif_config =
        {
                .base = &esp_netif_config,
                .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
        };


        esp_netif_t *netif = esp_netif_new(&netif_config);
        assert(netif);
        free(desc);

	// Set default handlers to process TCP/IP stuffs
	ESP_ERROR_CHECK(esp_eth_set_default_handlers(netif));
	// Register user defined event handers
	ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL));

    //end custom


    esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
	config.stack_input = pkt_eth2wifi;

	ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));


	//start custom
    tcpip_adapter_init();
    tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH); // Don't run a DHCP client

	tcpip_adapter_ip_info_t ip_info;
	ip_info.ip.addr = ipaddr_addr("192.168.1.39");
	ip_info.gw.addr = ipaddr_addr("192.168.1.1");
	ip_info.netmask.addr = ipaddr_addr("255.255.255.0");

	tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &ip_info);

	tcpip_adapter_dns_info_t dns_info;
	const char* dns_server = "8.8.8.8";
	IP_ADDR4(&dns_info.ip, 8, 8, 8, 8);
	tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_ETH, ESP_NETIF_DNS_MAIN, &dns_info);
	//end custom


	esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, (void *)true);

	//start custome
	s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
	esp_netif_attach(netif, s_eth_glue);
	//end custom

	esp_eth_start(s_eth_handle);

	s_semph_get_ip_addrs = xSemaphoreCreateCounting(NR_OF_IP_ADDRESSES_TO_WAIT_FOR, 0);

	//Custom by Gustav
	/*esp_netif_ip_info_t ip_info;

	ip4_addr_t ipaddr, netmask, gw;

	// Set the IP address
	IP4_ADDR(&ipaddr, 192, 168, 1, 39);
	ip_info.ip = ipaddr;

	// Set the gateway
	IP4_ADDR(&gw, 192, 168, 1, 1);
	ip_info.gw = gw;

	// Set the netmask
	IP4_ADDR(&netmask, 255, 255, 255, 0);
	ip_info.netmask = netmask;

	esp_netif_set_ip_info(eth_netif, &ip_info);*/
	//Custom



    //Custom by Gustav
    /*
    esp_netif_config_t eth_netif_config = ESP_NETIF_DEFAULT_ETH();
    ESP_ERROR_CHECK(esp_netif_init());
	ESP_LOGE(TAG, "Not Fail @ 0");
    esp_netif_t* eth_netif = esp_netif_create_default_wifi_sta();//esp_netif_new(&eth_netif_config);
    assert( eth_netif );
    if (!eth_netif) {
		ESP_LOGE(TAG, "Failed to create Ethernet netif");
		//return;
	}
    //setIPAddress(eth_netif);
    //End of Custom Gustav

    esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
    ESP_LOGE(TAG, "Not Fail @ 3");
    //config.stack_input = pkt_eth2wifi;
    //ESP_LOGE(TAG, "Not Fail @ 4");
    ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
    ESP_LOGE(TAG, "Not Fail @ 5");
    //esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, (void *)true);
    //ESP_LOGE(TAG, "Not Fail @ 6");
    esp_eth_start(s_eth_handle);
    ESP_LOGE(TAG, "Not Fail @ 7");
    vTaskDelay(500 / portTICK_PERIOD_MS);

    //setIPAddress(eth_netif);
	*/
    //Custom added by Gustav
    /*
    char *desc;

    esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();

    asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc);
        esp_netif_config.if_desc = desc;
        esp_netif_config.route_prio = 64;
        esp_netif_config_t netif_config = {
        		.base = &esp_netif_config,
				.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
        };
	//esp_netif_t *netif = esp_netif_new(&netif_config);
	esp_netif_t *netif = esp_netif_create_default_wifi_sta();
    assert(netif);
	free(desc);

	esp_netif_init();
		//esp_netif_t *netif = esp_netif_create_default_ethernet();
	esp_netif_dhcpc_stop(netif);
	tcpip_adapter_ip_info_t ip_info;
		ip4addr_aton("192.168.1.35", &ip_info.ip);
		ip4addr_aton("192.168.1.1", &ip_info.gw);
		ip4addr_aton("255.255.255.0", &ip_info.netmask);
		esp_netif_set_ip_info(netif, &ip_info);

	//esp_eth_driver_t *eth_driver = esp_eth_new_netif_glue();
	//esp_netif_attach(netif, eth_driver);
	//esp_netif_set_default_eth_netif(netif);
	//esp_eth_start(netif);

	//ESP_ERROR_CHECK(esp_eth_set_default_handlers(netif));
    // Register user defined event handers
    //ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL));
	ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
	//tcpip_adapter_init();



	//tcpip_adapter_init();
//	tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH); // Don't run a DHCP client
//	tcpip_adapter_ip_info_t ip_info;
//	ip_info.ip.addr = ipaddr_addr("192.168.1.35");
//	ip_info.gw.addr = ipaddr_addr("192.168.1.1");
//	ip_info.netmask.addr = ipaddr_addr("255.255.255.0");
//	tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &ip_info);

	s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
	esp_netif_attach(netif, s_eth_glue);
	esp_eth_start(s_eth_handle);
	esp_netif_set_ip_info(netif, &ip_info);
	//esp_netif_set_ip4_addr(eth_netif, 192,168,1,100);
	 *
	 */

}

static void initialize_wifi(void)
{
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL));

    //Custom Gustav
    //configure_static_ip();
    //End Custom Gustav

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = CONFIG_EXAMPLE_WIFI_SSID,
            .ssid_len = strlen(CONFIG_EXAMPLE_WIFI_SSID),
            .password = CONFIG_EXAMPLE_WIFI_PASSWORD,
            .max_connection = CONFIG_EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK,
            .channel = CONFIG_EXAMPLE_WIFI_CHANNEL // default: channel 1
        },
    };
    if (strlen(CONFIG_EXAMPLE_WIFI_PASSWORD) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
}

static esp_err_t initialize_flow_control(void)
{
    flow_control_queue = xQueueCreate(FLOW_CONTROL_QUEUE_LENGTH, sizeof(flow_control_msg_t));
    if (!flow_control_queue) {
        ESP_LOGE(TAG, "create flow control queue failed");
        return ESP_FAIL;
    }
    BaseType_t ret = xTaskCreate(eth2wifi_flow_control_task, "flow_ctl", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL);
    if (ret != pdTRUE) {
        ESP_LOGE(TAG, "create flow control task failed");
        return ESP_FAIL;
    }
    return ESP_OK;
}

//void app_main(void)
void setup_eth2wifi(void)
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    ESP_ERROR_CHECK(initialize_flow_control());


    initialize_ethernet();
    initialize_wifi();


    while (1)
    {


    	vTaskDelay(3000 / portTICK_PERIOD_MS);
    	//setIPAddress();
		if (pingGoogle() == 1)
		{
			ESP_LOGE(TAG, "FAILED TO PING GOOGLE.COM");
		}
    }
    //Try to set IP manually
    /*vTaskDelay(2000 / portTICK_PERIOD_MS);

    tcpip_adapter_ip_info_t eth_ip_info;
    ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &eth_ip_info));

    IP4_ADDR(&eth_ip_info.ip, 192, 168, 1, 100);
    IP4_ADDR(&eth_ip_info.netmask, 255, 255, 255, 0);
    IP4_ADDR(&eth_ip_info.gw, 192, 168, 1, 1);

    ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &eth_ip_info));*/


}
