#include <stdio.h>
#include <stdlib.h>
#include <string.h> //Requires by memset
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "spi_flash_mmap.h" //esp_spi_flash.h"
#include <esp_http_server.h>

#include "esp_wifi.h"
#include "esp_event.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "driver/gpio.h"
#include <lwip/sockets.h>
#include <lwip/sys.h>
#include <lwip/api.h>
#include <lwip/netdb.h>

//--------added
#include <sys/param.h>
#include "esp_eth.h"
#include <string.h>
#include <esp_vfs_fat.h>
#include "esp_log.h"

#define CTRL_PIN 4

#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MOUNT_POINT "/sdcard"

char upload[] = "<!DOCTYPE html>"
"<html>"
"<head><title>Upload File</title></head>"
"<body>"
"<h1>Upload any file</h1>"
"<input type='file' id='uploaded_file' required><br><br>"
"<button onclick='upload()'>Upload</button><br><br>"
"<progress id='progressBar' value='0' max='100' style='width:300px;'></progress><br>"
"<h3 id='status'></h3>"
"<p id='loaded_n_total'></p>"

"<script>"
"function _(el) { return document.getElementById(el); }"
"function upload() {"
    "var file = _('uploaded_file').files[0];"
    "var formData = file;"  // raw file data
    "var xhr = new XMLHttpRequest();"
    "xhr.upload.addEventListener('progress', progressHandler, false);"
    "xhr.addEventListener('load', completeHandler, false);"
    "xhr.addEventListener('error', errorHandler, false);"
    "xhr.addEventListener('abort', abortHandler, false);"
    "xhr.open('POST', '/upload');"
    "xhr.setRequestHeader('Filename', file.name);"
    "xhr.setRequestHeader('Filetype', file.type);"
    "xhr.send(formData);"
"}"

"function progressHandler(event) {"
    "var percent = Math.round((event.loaded / event.total) * 100);"
    "_('progressBar').value = percent;"
    "_('status').innerHTML = percent + '% uploaded...';"
    "_('loaded_n_total').innerHTML = 'Uploaded ' + event.loaded + ' of ' + event.total + ' bytes';"
"}"

"function completeHandler(event) {"
    "_('status').innerHTML = 'Upload complete!';"
    "_('progressBar').value = 100;"
"}"

"function errorHandler(event) {"
    "_('status').innerHTML = 'Upload failed';"
"}"

"function abortHandler(event) {"
    "_('status').innerHTML = 'Upload aborted';"
"}"
"</script>"
"</body>"
"</html>";



static const char *TAG = "espressif"; // TAG for debug

#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT)
    {
        switch (event_id)
        {
            case WIFI_EVENT_STA_START:
                esp_wifi_connect();
                break;

            case WIFI_EVENT_STA_DISCONNECTED:
                ESP_LOGW(TAG, "Wi-Fi disconnected, retrying...");
                esp_wifi_connect();  //  Reconnect immediately
                break;

            default:
                break;
        }
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}


void connect_wifi(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            //.channel = 6,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    esp_wifi_set_ps(WIFI_PS_NONE);  // Disable power-saving to avoid bcn_timeout

    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
                                           WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                           pdFALSE,
                                           pdFALSE,
                                           portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT)
    {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    }
    else if (bits & WIFI_FAIL_BIT)
    {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    }
    else
    {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
    vEventGroupDelete(s_wifi_event_group);
}

esp_err_t send_web_page(httpd_req_t *req)
{
    int response;
    response = httpd_resp_send(req, upload, HTTPD_RESP_USE_STRLEN);
    return response;
}
esp_err_t get_req_handler(httpd_req_t *req)
{
    return send_web_page(req);
}

//---------------------------------------------------------------------
void init_sd_card(void);
void deinit_sd_card(void);
esp_err_t upload_file_handler(httpd_req_t *req)
{
    char filename[64];
    httpd_req_get_hdr_value_str(req, "Filename", filename, sizeof(filename));

    ESP_LOGI(TAG, "Uploading file: %s", filename);

    //reinit sd card
    gpio_set_level(CTRL_PIN, 0);
    vTaskDelay(pdMS_TO_TICKS(1000));
    init_sd_card();

    const char filepath[128];
    snprintf(filepath, sizeof(filepath), MOUNT_POINT "/%s", filename);

    char *buf = malloc(16*1024);
    int ret, remaining = req->content_len;


    /*//debugging
    struct stat st;
    if (stat("/sdcard", &st) == 0 && S_ISDIR(st.st_mode)) {
        ESP_LOGI(TAG, "/sdcard exists and is a directory");
    } else {
        ESP_LOGE(TAG, "/sdcard not available or not a directory");
    }

    //open file
    uint64_t total, free2;
    esp_err_t info_err = esp_vfs_fat_info(MOUNT_POINT, &total, &free2);
    if (info_err == ESP_OK) {
        ESP_LOGI(TAG, "SD card space - Total: %llu KB, Free: %llu KB", total / 1024, free2 / 1024);
    } else {
        ESP_LOGE(TAG, "esp_vfs_fat_info() failed: %s", esp_err_to_name(info_err));
    }*/

    FILE *f = fopen(filepath, "wb");
    if (f == NULL)
        {
            ESP_LOGE(TAG, "Failed to open %s for writing", filepath);
            //perror("fopen");  // <-- This will print the real reason
            return ESP_FAIL;
            
        }

    //copy file
    while (remaining > 0) {
        //Read the data for the request
        if ((ret = httpd_req_recv(req, buf, //READ INTO BUF, AKA STORED IN BUF
                        MIN(remaining, 16*1024))) <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                //Retry receiving if timeout occurred
                continue;
            }
            return ESP_FAIL;
        }

        fwrite(buf, 1, ret, f);
        //ESP_LOGI(TAG, "Uploaded chunk to SD File");
        remaining -= ret;

        //vTaskDelay(pdMS_TO_TICKS(100));

    }

    fclose(f); 
    free(buf);
    ESP_LOGI(TAG, "Finished copying to SD File");

    //deinit sd card
    deinit_sd_card();
    gpio_set_level(CTRL_PIN, 1);
    vTaskDelay(pdMS_TO_TICKS(1000));

    return send_web_page(req);
}

/* //An HTTP POST handler
static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[100];
    int ret, remaining = req->content_len;

    while (remaining > 0) {
        //Read the data for the request
        if ((ret = httpd_req_recv(req, buf, //READ INTO BUF, AKA STORED IN BUF
                        MIN(remaining, sizeof(buf)))) <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                //Retry receiving if timeout occurred
                continue;
            }
            return ESP_FAIL;
        }

        // Send back the same data  // INSTEAD, WRITE TO SD FILE
        httpd_resp_send_chunk(req, buf, ret);
        remaining -= ret;

        // Log data received //UNECCESARY
        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", ret, buf);
        ESP_LOGI(TAG, "====================================");
    }

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}*/

//-----------------------------------------------------------------

httpd_uri_t uri_get = {
    .uri = "/",
    .method = HTTP_GET,
    .handler = get_req_handler,
    .user_ctx = NULL};

httpd_uri_t upload_file = {
    .uri = "/upload",
    .method = HTTP_POST,
    .handler = upload_file_handler,
    .user_ctx = NULL};


httpd_handle_t setup_server(void)
{
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    httpd_handle_t server = NULL;
    config.stack_size = 2*20480; //8192;
    config.recv_wait_timeout = 120; // seconds
    config.send_wait_timeout = 120;

    //---to match URI
    config.uri_match_fn = httpd_uri_match_wildcard;

    if (httpd_start(&server, &config) == ESP_OK)
    {
        httpd_register_uri_handler(server, &uri_get); // register the functions we're using
        httpd_register_uri_handler(server, &upload_file);
    }

    return server;
}

//---------------------------------------------------------------------------------------------------------------------------
// SD Stuff

/* SD card and FAT filesystem 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.
*/

// This example uses SDMMC peripheral to communicate with SD card.

#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "sd_test_io.h"
#include "esp_mac.h"
#if SOC_SDMMC_IO_POWER_EXTERNAL
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#endif

#define EXAMPLE_MAX_CHAR_SIZE    64

#define MOUNT_POINT "/sdcard"
#define EXAMPLE_IS_UHS1    (CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_SDR50 || CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_DDR50 || CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_SDR104)

#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
const char* names[] = {"CLK", "CMD", "D0", "D1", "D2", "D3"};
const int pins[] = {CONFIG_EXAMPLE_PIN_CLK,
                    CONFIG_EXAMPLE_PIN_CMD,
                    CONFIG_EXAMPLE_PIN_D0
                    #ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
                    ,CONFIG_EXAMPLE_PIN_D1,
                    CONFIG_EXAMPLE_PIN_D2,
                    CONFIG_EXAMPLE_PIN_D3
                    #endif
                    };

const int pin_count = sizeof(pins)/sizeof(pins[0]);

#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
const int adc_channels[] = {CONFIG_EXAMPLE_ADC_PIN_CLK,
                            CONFIG_EXAMPLE_ADC_PIN_CMD,
                            CONFIG_EXAMPLE_ADC_PIN_D0
                            #ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
                            ,CONFIG_EXAMPLE_ADC_PIN_D1,
                            CONFIG_EXAMPLE_ADC_PIN_D2,
                            CONFIG_EXAMPLE_ADC_PIN_D3
                            #endif
                            };
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE

pin_configuration_t config = {
    .names = names,
    .pins = pins,
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
    .adc_channels = adc_channels,
#endif
};
#endif //CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS

sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;

void init_sd_card(void)
{
    esp_err_t ret;

    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
        .format_if_mount_failed = true,
#else
        .format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
        .max_files = 5,
        .allocation_unit_size = 16 * 1024
    };
    /*sdmmc_card_t *card;
    const char mount_point[] = MOUNT_POINT;*/
    ESP_LOGI(TAG, "Initializing SD card");

    // Use settings defined above to initialize SD card and mount FAT filesystem.
    // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
    // Please check its source code and implement error recovery when developing
    // production applications.

    ESP_LOGI(TAG, "Using SDMMC peripheral");

    // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)
    // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 40MHz for SDMMC)
    // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
    sdmmc_host_t host = SDMMC_HOST_DEFAULT();
#if CONFIG_EXAMPLE_SDMMC_SPEED_HS
    host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
#elif CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_SDR50
    host.slot = SDMMC_HOST_SLOT_0;
    host.max_freq_khz = SDMMC_FREQ_SDR50;
    host.flags &= ~SDMMC_HOST_FLAG_DDR;
#elif CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_DDR50
    host.slot = SDMMC_HOST_SLOT_0;
    host.max_freq_khz = SDMMC_FREQ_DDR50;
#elif CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_SDR104
    host.slot = SDMMC_HOST_SLOT_0;
    host.max_freq_khz = SDMMC_FREQ_SDR104;
    host.flags &= ~SDMMC_HOST_FLAG_DDR;
#endif

    // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply.
    // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card
    // and the internal LDO power supply, we need to initialize the power supply first.
#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO
    sd_pwr_ctrl_ldo_config_t ldo_config = {
        .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID,
    };
    sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;

    ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create a new on-chip LDO power control driver");
        return;
    }
    host.pwr_ctrl_handle = pwr_ctrl_handle;
#endif

    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
#if EXAMPLE_IS_UHS1
    slot_config.flags |= SDMMC_SLOT_FLAG_UHS1;
#endif

    // Set bus width to use:
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
    slot_config.width = 4;
#else
    slot_config.width = 1;
#endif

    // On chips where the GPIOs used for SD card can be configured, set them in
    // the slot_config structure:
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
    slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
    slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
    slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
    slot_config.cd = GPIO_NUM_7;
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
    slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
    slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
    slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
#endif  // CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
#endif  // CONFIG_SOC_SDMMC_USE_GPIO_MATRIX

    // Enable internal pullups on enabled pins. The internal pullups
    // are insufficient however, please make sure 10k external pullups are
    // connected on the bus. This is for debug / example purpose only.
    slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;

    ESP_LOGI(TAG, "Mounting filesystem");
    ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
    

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem. "
                     "If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                     "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
            check_sd_card_pins(&config, pin_count);
#endif
        }
        return;
    }
    ESP_LOGI(TAG, "Filesystem mounted");

    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);

    // Use POSIX and C standard library functions to work with files:


    // Format FATFS
#ifdef CONFIG_EXAMPLE_FORMAT_SD_CARD
    ret = esp_vfs_fat_sdcard_format(mount_point, card);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to format FATFS (%s)", esp_err_to_name(ret));
        return;
    }

    if (stat(file_foo, &st) == 0) {
        ESP_LOGI(TAG, "file still exists");
        return;
    } else {
        ESP_LOGI(TAG, "file doesn't exist, formatting done");
    }
#endif // CONFIG_EXAMPLE_FORMAT_SD_CARD

}

void deinit_sd_card(){
    // All done, unmount partition and disable SDMMC peripheral
    esp_vfs_fat_sdcard_unmount(mount_point, card);
    ESP_LOGI(TAG, "Card unmounted");

    card = NULL;

    // Deinitialize the power control driver if it was used
#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO
    ret = sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to delete the on-chip LDO power control driver");
        return;
    }
#endif
}

/*void wifi_signal_tracker_task(void *param)
{
    wifi_ap_record_t ap_info;

    while (1) {
        if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
            ESP_LOGI(TAG, "RSSI: %d dBm", ap_info.rssi);
        } else if(esp_wifi_sta_get_ap_info(&ap_info) == ESP_ERR_WIFI_CONN) {
            ESP_LOGW(TAG, "The station interface don't initialized");
        }
        else if(esp_wifi_sta_get_ap_info(&ap_info) == ESP_ERR_WIFI_NOT_CONNECT){
            ESP_LOGW(TAG, "The station is in disconnect status"); //-->this one is printing
            esp_wifi_connect();
        }

        vTaskDelay(pdMS_TO_TICKS(5000)); // every 5 seconds
    }
}*/

//----------------------------------------------------------------------------------------------------------
//ESPNOW CODE
#include "esp_now.h"
#include "esp_now.h"
#include "esp_netif.h"

typedef struct {
    uint8_t type;  // 0 = ping, 1 = IP response
    char ip[16];
} espnow_msg_t;

bool sent_MAC = false;

static void espnow_recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len)
{
    if (len < sizeof(espnow_msg_t)) return;

    espnow_msg_t incoming;
    memcpy(&incoming, data, sizeof(espnow_msg_t));

    if (incoming.type == 0 && !sent_MAC) {
        ESP_LOGI("ESPNOW", "Received ping from master");

        espnow_msg_t reply = { .type = 1 };

        esp_netif_ip_info_t ip_info;
        esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
        esp_netif_get_ip_info(netif, &ip_info);
        snprintf(reply.ip, sizeof(reply.ip), IPSTR, IP2STR(&ip_info.ip));

        esp_now_peer_info_t peer = {
            .channel = 1,
            .ifidx = ESP_IF_WIFI_STA,
            .encrypt = false
        };
        memcpy(peer.peer_addr, recv_info->src_addr, ESP_NOW_ETH_ALEN);

        if (!esp_now_is_peer_exist(recv_info->src_addr)) {
            esp_now_add_peer(&peer);
        }

        esp_err_t err = esp_now_send(recv_info->src_addr, (uint8_t*)&reply, sizeof(reply));
        if (err == ESP_OK) {
            ESP_LOGI("ESPNOW", "Replied with IP: %s", reply.ip);
        } else {
            ESP_LOGE("ESPNOW", "Reply failed: %s", esp_err_to_name(err));
        }

        sent_MAC = true;
    }
}

void app_main()
{
    //setting up ctrl pin
    esp_rom_gpio_pad_select_gpio(CTRL_PIN);
    gpio_set_direction(CTRL_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(CTRL_PIN, 0);
    vTaskDelay(pdMS_TO_TICKS(500));
    
    // init sd card
    //init_sd_card();

    // Initialize NVS
    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_LOGI(TAG, "ESP_WIFI_MODE_STA");
    connect_wifi();
    
    //xTaskCreate(wifi_signal_tracker_task, "wifi_signal_tracker", 4096, NULL, 5, NULL);

    //start file uploader
    ESP_LOGI(TAG, "Website File Uploader Running...\n");
    setup_server();

    //init esp now
    ESP_LOGI(TAG, "Starting ESP-NOW responder...");
    ESP_ERROR_CHECK(esp_now_init());
    ESP_ERROR_CHECK(esp_now_register_recv_cb(espnow_recv_cb));
}