Sfoglia il codice sorgente

Add SDA and SCL pin configuration for OLED display in Kconfig and main.c

Co-authored-by: Copilot <copilot@github.com>
dacowars 1 settimana fa
parent
commit
43639e4e4c
2 ha cambiato i file con 457 aggiunte e 13 eliminazioni
  1. 14 0
      main/Kconfig.projbuild
  2. 443 13
      main/main.c

+ 14 - 0
main/Kconfig.projbuild

@@ -34,4 +34,18 @@ menu "SD SPI Example Configuration"
             GPIO number where the SD card CS pin is connected.
             Make sure the pin supports input/output and has pull-up if needed.
 
+    config PIN_SDA
+        int "SDA pin configuration"
+        default 21
+        range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
+        help 
+            GPIO number where the OLED display SDA pin is connected.        
+
+    config PIN_SCL
+        int "SCL pin configuration"
+        default 22
+        range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
+        help 
+            GPIO number where the OLED display SCL pin is connected.  
+
 endmenu

+ 443 - 13
main/main.c

@@ -14,11 +14,20 @@
 #include "sdmmc_cmd.h"
 #include "ssd1306.h"
 #include <driver/i2c_master.h>
+#include "math.h"
+#include "string.h"
+#include "esp_wifi.h"
+#include "esp_netif.h"
+#include "esp_event.h"
+#include "esp_http_server.h"
+#include "lwip/inet.h"
+#include "sys/stat.h"
 
 const char *DHT_TAG = "DHT22";
 const char *GPS_TAG = "GPS_PARSER";
 const char *SD_TAG = "SD_CARD";
 const char *OLED_TAG = "SSD1306OLED";
+const char *GEN_TAG = "General";
 
 #define MOUNT_POINT "/sdcard"
 
@@ -30,12 +39,17 @@ const char *OLED_TAG = "SSD1306OLED";
 #define PIN_NUM_SDA CONFIG_PIN_SDA
 #define PIN_NUM_SCL CONFIG_PIN_SCL
 
+#define PIN_TX GPIO_NUM_17
+#define PIN_RX GPIO_NUM_16
+
 //definicion de tiempos de pulsacion
 #define PULSACION_LARGA_MS 2000
 #define DURACION_WATCHDOG_MS 10000
 
 #define MEASUREMENT_INTERVAL_S 1
 
+#define DEG2RAD (M_PI/180.0)
+
 const int uart_buffer_size = (1024 * 2);
 int length = 0;
 
@@ -43,18 +57,20 @@ uint8_t data;
 
 static gps_parser_t gps;
 
-void uart_configurator();
-
-static esp_err_t s_example_write_file(const char *path, char *data);
-
-static i2c_master_bus_handle_t i2c_bus0_init(gpio_num_t sda, gpio_num_t scl, uint32_t hz);
+static httpd_handle_t http_server = NULL;
+static esp_netif_t *ap_netif = NULL;
+static bool wifiActivado = false;
+static uint32_t wifiLastActivity = 0;
 
+extern char filename[13]; // tu archivo gpx
+const char *apSSID = "MiAP";
+const char *apPassword = "password123";
 
 struct SensorData {
   double latitude;
   double longitude;
   float altura;
-  char tiempo;
+  char tiempo[64];
   float velocidad;
   float temperature;
   float humidity;
@@ -79,10 +95,11 @@ char filename[13] = "/panchas.gpx";
 
 ssd1306_handle_t d = NULL;
 
+const char mount_point[] = MOUNT_POINT;
+
 void OLED_test(){
 
-    i2c_master_bus_handle_t i2c_bus =
-        i2c_bus0_init(PIN_NUM_SDA, PIN_NUM_SCL, 400000);
+    i2c_master_bus_handle_t i2c_bus = i2c_bus0_init(PIN_NUM_SDA, PIN_NUM_SCL, 400000);
 
     ssd1306_config_t cfg = {
         .width  = 128,
@@ -109,7 +126,7 @@ void OLED_test(){
 
     ESP_ERROR_CHECK(ssd1306_display(d));
     
-    ESP_ERROR_CHECK(ssd1306_draw_text_scaled(d, 0, 0, "Iniciando...", true, ));
+    ESP_ERROR_CHECK(ssd1306_draw_text_scaled(d, 0, 0, "Iniciando...", true, 1));
 
     ESP_ERROR_CHECK(ssd1306_display(d));
 
@@ -117,7 +134,7 @@ void OLED_test(){
 
 }
 
-void OLED_print(const char& line1, const char& line2){
+void OLED_print(const char *line1, const char *line2){
     
     ESP_ERROR_CHECK(ssd1306_clear(d));
 
@@ -132,7 +149,7 @@ void DHT_test (){
     float t;
     float h;
 
-    static esp_err_t err = dht_attach_pin();
+    esp_err_t err = dht_attach_pin();
 
     if (err != ESP_OK) {
         OLED_print("DHT22", "Error");
@@ -154,9 +171,296 @@ void DHT_test (){
 }
 
 void SD_test(){
+
+    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
+        .format_if_mount_failed = false,
+        .max_files = 5,
+        .allocation_unit_size = 16 * 1024
+    };
+
+    sdmmc_card_t *card;
+
+    sdmmc_host_t host = SDSPI_HOST_DEFAULT();
+    host.max_freq_khz = 9000; //a mas freq no funciona, porque pipas
+
+    spi_bus_config_t bus_cfg = {
+        .mosi_io_num = PIN_NUM_MOSI,
+        .miso_io_num = PIN_NUM_MISO,
+        .sclk_io_num = PIN_NUM_CLK,
+        .quadwp_io_num = -1,
+        .quadhd_io_num = -1,
+        .max_transfer_sz = 4092,
+    };
+
+    esp_err_t ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
+    if (ret != ESP_OK) {
+        ESP_LOGE(SD_TAG, "Failed to initialize bus.");
+        return;
+    }
+
+    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
+    slot_config.gpio_cs = PIN_NUM_CS;
+    slot_config.host_id = host.slot;
+
+    ESP_LOGI(SD_TAG, "Mounting filesystem");
+
+    while((ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card)) != ESP_OK){
+        if (ret == ESP_FAIL) {
+            ESP_LOGE(SD_TAG, "Failed to mount filesystem. "
+                     "If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
+            OLED_print("Error SD", "Prueba a reinsertar");
+        } else {
+            ESP_LOGE(SD_TAG, "Failed to initialize the card (%s). "
+                     "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
+            OLED_print("Error SD", esp_err_to_name(ret));
+        }
+        vTaskDelay(pdMS_TO_TICKS(1000));
+    }
+
+    ESP_LOGI(SD_TAG, "Filesystem mounted");
+
+    OLED_print("SD correcta","");
+
+    // Card has been initialized, print its properties
+    sdmmc_card_print_info(stdout, card);
+
+
     
 }
 
+void GPS_test_wait(){
+
+    // Iniciar Serial2 para GPS
+    bool fixObtained = false;
+
+    uart_configurator();
+
+    gps_parser_init(&gps);
+
+    while (!fixObtained) {
+        while (uart_read_bytes(UART_NUM_2, &data, 1, 0)){
+            gps_parser_encode(&gps, data);
+        }
+        if (gps_location_is_valid(&gps.location) && gps_date_is_valid(&gps.date) && gps_time_is_valid(&gps.time)) {
+            fixObtained = true;
+            break;
+        }
+        vTaskDelay(pdMS_TO_TICKS(300));
+        OLED_print("GPS", "Esperando");
+        vTaskDelay(pdMS_TO_TICKS(300));
+        OLED_print("GPS", "Esperando .");
+        vTaskDelay(pdMS_TO_TICKS(300));
+        OLED_print("GPS", "Esperando ..");
+        vTaskDelay(pdMS_TO_TICKS(300));
+        OLED_print("GPS", "Esperando ...");
+    }
+
+    OLED_print("GPS", "Encontrado");
+
+}
+
+float calcular_delta_dist(float lat1, float  long1, float lat2, float long2){
+  float R = 6371000.0; // Radio de la Tierra en km
+  float delta_lat = (lat2 - lat1) * DEG2RAD;
+  float delta_long = (long2 - long1) * DEG2RAD;
+  lat1 = lat1 * DEG2RAD;
+  lat2 = lat2 * DEG2RAD;
+  float a = sin(delta_lat/2)*sin(delta_lat/2)+cos(lat1)*cos(lat2)*sin(delta_long/2)*sin(delta_long/2);
+  float c = 2 * atan2(sqrt(a),sqrt(1-a));
+  return R * c;  //En m
+}
+
+void task_mediciones(void *pvParameters) {
+    TickType_t xLastWakeTime = xTaskGetTickCount();
+    char buffer[50];
+    while(1) {
+        unsigned long startMillis = pdTICKS_TO_MS(xTaskGetTickCount());
+        // se leen los valores antes de utilizar el semaphore    
+        while (uart_read_bytes(UART_NUM_2, &data, 1, 0)){
+            gps_parser_encode(&gps, data);
+        }
+
+        float new_latitude = gps_location_lat(&gps.location);
+        float new_longitude = gps_location_lng(&gps.location);
+        float new_altitude = 0.0; //gps.altitude.meters(); falta por implementar en la libreria del gps
+        int new_fecha_len = snprintf(buffer, sizeof(buffer), "%d-%02d-%02dT%02d:%02d:%02d.%03d", gps_date_year(&gps.date), gps_date_month(&gps.date),
+                                    gps_date_day(&gps.date), gps_time_hour(&gps.time), gps_time_minute(&gps.time), 
+                                    gps_time_second(&gps.time), gps_time_centisecond(&gps.time));
+        if (new_fecha_len < 0) {
+            buffer[0] = '\0';
+        }
+        float new_temp = 0.0;
+        float new_hum = 0.0;
+        dht_read(&new_temp, &new_hum);
+        float new_press = 0.0; // Placeholder, no hay sensor de presión 
+        
+        float distancia_ciclo = calcular_delta_dist(datosAntiguos.latitude, datosAntiguos.longitude, new_latitude, new_longitude);
+        distancia_total += distancia_ciclo;
+        float new_speed = distancia_ciclo / MEASUREMENT_INTERVAL_S * 3.6;
+        
+
+        if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE) {
+            latestData.latitude = new_latitude;
+            latestData.longitude = new_longitude;
+            latestData.altura = new_altitude;
+            strncpy(latestData.tiempo, buffer, sizeof(latestData.tiempo) - 1);
+            latestData.tiempo[sizeof(latestData.tiempo) - 1] = '\0';
+            latestData.velocidad = new_speed;
+            latestData.temperature = new_temp;
+            latestData.humidity = new_hum;
+            latestData.pressure = new_press;
+            datosAntiguos = latestData;
+            xSemaphoreGive(dataMutex);
+        }
+
+        FILE *f = fopen(filename, "a");
+        if (f) {
+            //Crear la string para escribir en el archivo
+            fprintf(f, "\t\t\t<trkpt lat=\"");
+            fprintf(f, "%2.4f", datosAntiguos.latitude);
+            fprintf(f, "\" lon=\"");
+            fprintf(f, "%2.4f", datosAntiguos.longitude);
+            fprintf(f, "\">\n");
+
+            fprintf(f, "\t\t\t\t<ele>");
+            fprintf(f, "%f", datosAntiguos.altura);
+            fprintf(f, "</ele>\n");
+
+            fprintf(f, "\t\t\t\t<time>");
+            fprintf(f, "%s", datosAntiguos.tiempo);
+            fprintf(f, "</time>\n");
+
+            fprintf(f, "\t\t\t\t<speed>");
+            fprintf(f, "%f", datosAntiguos.velocidad);
+            fprintf(f, "</speed>\n");
+
+            fprintf(f, "\t\t\t\t<extensions>\n");
+            fprintf(f, "\t\t\t\t\t<gpxtpx:TrackPointExtension>\n");
+            fprintf(f, "\t\t\t\t\t\t<gpxtpx:atemp>");
+            fprintf(f, "%f", datosAntiguos.temperature);
+            fprintf(f, "</gpxtpx:atemp>\n");
+            fprintf(f, "\t\t\t\t\t</gpxtpx:TrackPointExtension>\n");
+
+            fprintf(f, "\t\t\t\t\t<custom:humidity>");
+            fprintf(f, "%f", datosAntiguos.humidity);
+            fprintf(f, "</custom:humidity>\n");
+
+            fprintf(f, "\t\t\t\t\t<custom:pressure>");
+            fprintf(f, "%f", datosAntiguos.pressure);
+            fprintf(f, "</custom:pressure>\n");
+
+            fprintf(f, "\t\t\t\t</extensions>\n");
+            fprintf(f, "\t\t\t</trkpt>\n");
+            
+            fclose(f);
+        }
+        unsigned long elapsedMillis = pdTICKS_TO_MS(xTaskGetTickCount()) - startMillis;
+        ESP_LOGI(GEN_TAG, "Elapsed millis: %d.", elapsedMillis);
+
+        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(MEASUREMENT_INTERVAL_S*1000)); // Espera x*1000 milisegundos
+        
+    }
+}
+
+void crear_archivo(){
+    int num = 1;
+
+    sprintf(filename, MOUNT_POINT"/data%03d.gpx", num);
+
+    FILE *f = fopen(filename, "r");
+
+    while (f != NULL) {
+        num++;
+        sprintf(filename, MOUNT_POINT"/data%03d.gpx", num);
+        FILE *f = fopen(filename, "r");
+    }
+
+    FILE *f = fopen(filename, "w");
+
+    char buffer[50];
+
+    if (f) {
+        fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                    "<gpx creator=\"ESP32 GPS LOGGER\" version=\"1.1\"\n"
+                    "\txmlns=\"http://www.topografix.com/GPX/1/1\"\n"
+                    "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+                    "\txmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v2\"\n"
+                    "\txmlns:gpxdata=\"http://www.cluetrust.com/XML/GPXDATA/1/0\"\n"
+                    "\txsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n"
+                    "\t<metadata>\n"
+                    "\t\t<name>Ruta grabada con ESP32 GPS Logger</name>\n"
+                    "\t\t<time>\n");
+        int new_fecha_len = snprintf(buffer, sizeof(buffer), "%d-%02d-%02dT%02d:%02d:%02d.%03d", gps_date_year(&gps.date), gps_date_month(&gps.date),
+                                    gps_date_day(&gps.date), gps_time_hour(&gps.time), gps_time_minute(&gps.time), 
+                                    gps_time_second(&gps.time), gps_time_centisecond(&gps.time));
+        if (new_fecha_len < 0) {
+            buffer[0] = '\0';
+        }
+        fprintf(f, "%s", buffer);
+        fprintf(f, "</time>\n\t</metadata>\n"
+                    "\t<trk>\n"
+                    "\t\t<name>Rutita</name>\n"
+                    "\t\t<type>hiking</type>\n"
+                    "\t\t<trkseg>\n");
+        fclose(f);
+    } else {
+        OLED_print("Error","creando archivo");
+        vTaskDelay(pdMS_TO_TICKS(2000));
+        crear_archivo();
+    }
+}
+
+void cerrar_archivo() {
+    FILE *f = fopen(filename, "w");
+    if (f){
+        fprintf(f, "\t\t</trkseg>\n\t</trk>\n</gpx>");
+        fclose(f);
+    }
+    //int num = 1;
+    //sprintf(filename, "/data%03d.gpx", num);
+    //while (SD.exists(filename)) {
+    //  num++;
+    //  sprintf(filename, "/data%03d.gpx", num);
+    //}
+}
+
+void activarWiFi(void)
+{
+    OLED_print("WiFi", "Activando...");
+
+    ESP_ERROR_CHECK(wifi_ap_init());
+
+    char ip_str[16] = {0};
+    get_ap_ip(ip_str, sizeof(ip_str));
+    OLED_print("WiFi Activo", ip_str);
+
+    vTaskDelay(pdMS_TO_TICKS(2000));
+
+    ESP_ERROR_CHECK(iniciar_servidor_http());
+
+    wifiActivado = true;
+    wifiLastActivity = xTaskGetTickCount();
+}
+
+void desactivarWiFi(void)
+{
+    if (http_server) {
+        httpd_stop(http_server);
+        http_server = NULL;
+    }
+
+    ESP_ERROR_CHECK(esp_wifi_stop());
+    ESP_ERROR_CHECK(esp_wifi_deinit());
+
+    if (ap_netif) {
+        esp_netif_destroy(ap_netif);
+        ap_netif = NULL;
+    }
+
+    wifiActivado = false;
+    OLED_print("WiFi", "Apagado");
+}
+
 void app_main(void)
 {
     // Initialize DHT22 sensor
@@ -237,6 +541,8 @@ void app_main(void)
         return;
     }
 
+    gpio_set_pull_mode(PIN_NUM_MISO, GPIO_PULLUP_ONLY);
+
     sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
     slot_config.gpio_cs = PIN_NUM_CS;
     slot_config.host_id = host.slot;
@@ -278,7 +584,6 @@ void app_main(void)
     spi_bus_free(host.slot);
     */
 
-
     // Initialize display
     /*
     i2c_master_bus_handle_t i2c_bus =
@@ -346,7 +651,7 @@ void uart_configurator() {
     // Install UART driver using an event queue here
     ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
     ESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));
-    ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, GPIO_NUM_17, GPIO_NUM_16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
+    ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, PIN_TX, PIN_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
 }
 
 static esp_err_t s_example_write_file(const char *path, char *data)
@@ -380,3 +685,128 @@ static i2c_master_bus_handle_t i2c_bus0_init(gpio_num_t sda, gpio_num_t scl, uin
     return bus;
 }
 
+static esp_err_t wifi_ap_init(void)
+{
+    esp_err_t err;
+
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    ap_netif = esp_netif_create_default_wifi_ap();
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
+
+    wifi_config_t wifi_config = {
+        .ap = {
+            .ssid = "",
+            .ssid_len = 0,
+            .channel = 1,
+            .password = "",
+            .max_connection = 4,
+            .authmode = WIFI_AUTH_WPA_WPA2_PSK,
+        },
+    };
+
+    strncpy((char *)wifi_config.ap.ssid, apSSID, sizeof(wifi_config.ap.ssid) - 1);
+    strncpy((char *)wifi_config.ap.password, apPassword, sizeof(wifi_config.ap.password) - 1);
+
+    if (strlen(apPassword) == 0) {
+        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
+    }
+
+    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
+    ESP_ERROR_CHECK(esp_wifi_start());
+    return ESP_OK;
+}
+
+static esp_err_t get_ap_ip(char *out_ip, size_t len)
+{
+    esp_netif_ip_info_t ip_info;
+    if (ap_netif == NULL) {
+        return ESP_ERR_INVALID_STATE;
+    }
+    ESP_ERROR_CHECK(esp_netif_get_ip_info(ap_netif, &ip_info));
+    inet_ntoa_r(ip_info.ip, out_ip, len);
+    return ESP_OK;
+}
+
+static esp_err_t root_get_handler(httpd_req_t *req)
+{
+    wifiLastActivity = xTaskGetTickCount();
+
+    char ip_str[16] = {0};
+    get_ap_ip(ip_str, sizeof(ip_str));
+
+    const char *nombreArchivo = (filename[0] == '/') ? filename + 1 : filename;
+
+    char html[1024];
+    snprintf(html, sizeof(html),
+        "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>ESP32 GPS Logger</title>"
+        "<style>body{font-family:Arial;text-align:center;margin:50px;}h1{color:#333;} "
+        "a.button{background:#4CAF50;color:white;padding:20px 40px;text-decoration:none;"
+        "font-size:24px;border-radius:12px;display:inline-block;margin:20px;}</style></head>"
+        "<body><h1>GPS Logger</h1><p>Archivo listo para descargar:</p>"
+        "<a href='/download' class='button' download='%s'>Descargar %s</a>"
+        "<hr><p>IP: %s</p><p>Se apagará en 5 min sin uso.</p></body></html>",
+        nombreArchivo, nombreArchivo, ip_str);
+
+    httpd_resp_set_type(req, "text/html");
+    return httpd_resp_send(req, html, HTTPD_RESP_USE_STRLEN);
+}
+
+static esp_err_t download_get_handler(httpd_req_t *req)
+{
+    wifiLastActivity = xTaskGetTickCount();
+
+    struct stat st;
+    if (stat(filename, &st) != 0) {
+        httpd_resp_send_404(req);
+        return ESP_FAIL;
+    }
+
+    FILE *file = fopen(filename, "r");
+    if (!file) {
+        httpd_resp_send_404(req);
+        return ESP_FAIL;
+    }
+
+    const char *nombreArchivo = (filename[0] == '/') ? filename + 1 : filename;
+    char disposition[128];
+    snprintf(disposition, sizeof(disposition),
+             "attachment; filename=\"%s\"", nombreArchivo);
+
+    httpd_resp_set_type(req, "application/gpx+xml");
+    httpd_resp_set_hdr(req, "Content-Disposition", disposition);
+    httpd_resp_send_file(req, file, st.st_size);
+
+    fclose(file);
+    return ESP_OK;
+}
+
+static const httpd_uri_t root_uri = {
+    .uri       = "/",
+    .method    = HTTP_GET,
+    .handler   = root_get_handler,
+    .user_ctx  = NULL
+};
+
+static const httpd_uri_t download_uri = {
+    .uri       = "/download",
+    .method    = HTTP_GET,
+    .handler   = download_get_handler,
+    .user_ctx  = NULL
+};
+
+static esp_err_t iniciar_servidor_http(void)
+{
+    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
+    if (httpd_start(&http_server, &config) != ESP_OK) {
+        return ESP_FAIL;
+    }
+
+    httpd_register_uri_handler(http_server, &root_uri);
+    httpd_register_uri_handler(http_server, &download_uri);
+    return ESP_OK;
+}
+