|
@@ -53,10 +53,11 @@ Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
|
struct SensorData {
|
|
struct SensorData {
|
|
|
double latitude = 0.0;
|
|
double latitude = 0.0;
|
|
|
double longitude = 0.0;
|
|
double longitude = 0.0;
|
|
|
|
|
+ float altura = 0.0;
|
|
|
|
|
+ String tiempo = "";
|
|
|
float temperature = 0.0;
|
|
float temperature = 0.0;
|
|
|
float humidity = 0.0;
|
|
float humidity = 0.0;
|
|
|
float pressure = 0.0;
|
|
float pressure = 0.0;
|
|
|
- float altura = 0.0;
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
SensorData latestData;
|
|
SensorData latestData;
|
|
@@ -65,12 +66,10 @@ SensorData datosAntiguos;
|
|
|
SemaphoreHandle_t dataMutex; // Mutex para proteger el acceso a latestData
|
|
SemaphoreHandle_t dataMutex; // Mutex para proteger el acceso a latestData
|
|
|
SemaphoreHandle_t buttonSemaphore; // Semáforo para la tarea del botón
|
|
SemaphoreHandle_t buttonSemaphore; // Semáforo para la tarea del botón
|
|
|
|
|
|
|
|
-//flag para reducir las lecturas de DHT y presion
|
|
|
|
|
-uint8_t readSensorsFlag = 0;
|
|
|
|
|
-
|
|
|
|
|
bool grabando = false; //inicia apagado
|
|
bool grabando = false; //inicia apagado
|
|
|
TaskHandle_t medicionesHandle = NULL; //para suspend/resume
|
|
TaskHandle_t medicionesHandle = NULL; //para suspend/resume
|
|
|
-int pantallaEstado = 0; //maquina de estados
|
|
|
|
|
|
|
+int pantallaEstado_grab = 0; //maquina de estados cuando se graba ruta
|
|
|
|
|
+int pantallaEstado_menu = 0; //maquina de estados cuando no se esta grabando ruta
|
|
|
float distancia_total = 0.0;
|
|
float distancia_total = 0.0;
|
|
|
volatile unsigned long ignore_isr_until = 0; //para debounce
|
|
volatile unsigned long ignore_isr_until = 0; //para debounce
|
|
|
|
|
|
|
@@ -144,30 +143,30 @@ if (!SD.begin()) {
|
|
|
Serial.printf("SD Card Size: %uMB\n", cardSize);
|
|
Serial.printf("SD Card Size: %uMB\n", cardSize);
|
|
|
|
|
|
|
|
int num = 1;
|
|
int num = 1;
|
|
|
- sprintf(filename, "/data%03d.txt", num);
|
|
|
|
|
|
|
+ sprintf(filename, "/data%03d.xml", num);
|
|
|
while (SD.exists(filename)) {
|
|
while (SD.exists(filename)) {
|
|
|
- Serial.printf("File %s already exists. Trying next.\n", filename);
|
|
|
|
|
num++;
|
|
num++;
|
|
|
- sprintf(filename, "/data%03d.txt", num);
|
|
|
|
|
|
|
+ sprintf(filename, "/data%03d.xml", num);
|
|
|
}
|
|
}
|
|
|
- Serial.printf("Using file: %s\n", filename);
|
|
|
|
|
|
|
|
|
|
File file = SD.open(filename, FILE_WRITE);
|
|
File file = SD.open(filename, FILE_WRITE);
|
|
|
if (file) {
|
|
if (file) {
|
|
|
- Serial.println("File created successfully");
|
|
|
|
|
- file.println("Latitud,Longitud,Temperatura,Humedad,Presion");
|
|
|
|
|
|
|
+ file.println('<?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\t
|
|
|
|
|
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n\txmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2"\n\t
|
|
|
|
|
+ xmlns: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<trk>\n\t\t
|
|
|
|
|
+ <name>Rutita</name>\n\t\t<type>hiking</type>\n\t\t<trkseg>');
|
|
|
file.close();
|
|
file.close();
|
|
|
} else {
|
|
} else {
|
|
|
- Serial.println("Error creando archivo");
|
|
|
|
|
|
|
+ OLED_print("Error","creando archivo");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GPS_test_wait() {
|
|
void GPS_test_wait() {
|
|
|
// Iniciar Serial2 para GPS
|
|
// Iniciar Serial2 para GPS
|
|
|
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RX_PIN, TX_PIN);
|
|
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RX_PIN, TX_PIN);
|
|
|
- while ((gpsSerial.available() > 0) && !gps.location.isValid()) {
|
|
|
|
|
|
|
+ while (((gpsSerial.available() > 0) && gps.location.isValid()) && (gps.speed.age() < 2000)) {
|
|
|
gps.encode(gpsSerial.read());
|
|
gps.encode(gpsSerial.read());
|
|
|
- delay(10);
|
|
|
|
|
|
|
+ delay(100);
|
|
|
OLED_print("GPS", "Esperando.");
|
|
OLED_print("GPS", "Esperando.");
|
|
|
delay(100);
|
|
delay(100);
|
|
|
OLED_print("GPS", "Esperando..");
|
|
OLED_print("GPS", "Esperando..");
|
|
@@ -198,8 +197,13 @@ void task_mediciones(void *pvParameters) {
|
|
|
|
|
|
|
|
float new_latitude = gps.location.lat();
|
|
float new_latitude = gps.location.lat();
|
|
|
float new_longitude = gps.location.lng();
|
|
float new_longitude = gps.location.lng();
|
|
|
- float new_temp = (readSensorsFlag % 60 == 0) ? dht.readTemperature() : latestData.temperature;
|
|
|
|
|
- float new_hum = (readSensorsFlag % 120 == 0) ? dht.readHumidity() : latestData.humidity;
|
|
|
|
|
|
|
+ float new_altitude = gps.altitude.meters();
|
|
|
|
|
+ String new_fecha = String(gps.date.year())+"-"+String(gps.date.month())+"-"+
|
|
|
|
|
+ String(gps.date.day())+"T"+String(gps.time.hour())+":"+
|
|
|
|
|
+ String(gps.time.minute())+":"+String(gps.time.second())+"."+
|
|
|
|
|
+ String(gps.time.centisecond())
|
|
|
|
|
+ float new_temp = dht.readTemperature();
|
|
|
|
|
+ float new_hum = dht.readHumidity();
|
|
|
float new_press = 0.0; // Placeholder, no hay sensor de presión
|
|
float new_press = 0.0; // Placeholder, no hay sensor de presión
|
|
|
|
|
|
|
|
if (gps.location.isValid() && datosAntiguos.latitude != 0.0) {
|
|
if (gps.location.isValid() && datosAntiguos.latitude != 0.0) {
|
|
@@ -209,6 +213,8 @@ void task_mediciones(void *pvParameters) {
|
|
|
if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE) {
|
|
if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE) {
|
|
|
latestData.latitude = new_latitude;
|
|
latestData.latitude = new_latitude;
|
|
|
latestData.longitude = new_longitude;
|
|
latestData.longitude = new_longitude;
|
|
|
|
|
+ latestData.altura = new_altitude;
|
|
|
|
|
+ latestData.tiempo = new_fecha;
|
|
|
latestData.temperature = new_temp;
|
|
latestData.temperature = new_temp;
|
|
|
latestData.humidity = new_hum;
|
|
latestData.humidity = new_hum;
|
|
|
latestData.pressure = new_press;
|
|
latestData.pressure = new_press;
|
|
@@ -219,20 +225,19 @@ void task_mediciones(void *pvParameters) {
|
|
|
File file = SD.open(filename, FILE_APPEND);
|
|
File file = SD.open(filename, FILE_APPEND);
|
|
|
if (file) {
|
|
if (file) {
|
|
|
//Crear la string para escribir en el archivo
|
|
//Crear la string para escribir en el archivo
|
|
|
- String frase = String(datosAntiguos.latitude) + "," +
|
|
|
|
|
- String(datosAntiguos.longitude) + "," +
|
|
|
|
|
- String(datosAntiguos.temperature) + "," +
|
|
|
|
|
- String(datosAntiguos.humidity) + "," +
|
|
|
|
|
- String(datosAntiguos.pressure);
|
|
|
|
|
|
|
+ String frase = '\t\t\t<trkpt> lat="' + String(datosAntiguos.latitude,6) +
|
|
|
|
|
+ '" lon="' + String(datosAntiguos.longitude,6) + '">\n\t\t\t\t<ele>'+
|
|
|
|
|
+ String(datosAntiguos.altura) + '</ele>\n\t\t\t\t<time>'+
|
|
|
|
|
+ datosAntiguos.tiempo+'</time>\n\t\t\t\t<extensions>\n\t\t\t\t\t<gpxtpx:TrackPointExtension>\n\t\t\t\t\t\t<gpxtpx:atemp>'+
|
|
|
|
|
+ String(datosAntiguos.temperature)+'</gpxtpx:atemp>\n\t\t\t\t\t</gpxtpx:TrackPointExtension>\n\t\t\t\t\t<custom:humidity>'+
|
|
|
|
|
+ String(datosAntiguos.humidity)+'</custom:humidity>\n\t\t\t\t\t<custom:pressure>'+String(datosAntiguos.pressure)+
|
|
|
|
|
+ '</custom:pressure>\n\t\t\t\t</extensions>\n\t\t\t</trkpt>';
|
|
|
|
|
|
|
|
// Escribir datos en el archivo
|
|
// Escribir datos en el archivo
|
|
|
file.println(frase);
|
|
file.println(frase);
|
|
|
file.close();
|
|
file.close();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!(readSensorsFlag % 120)) readSensorsFlag = 0;
|
|
|
|
|
- readSensorsFlag++;
|
|
|
|
|
-
|
|
|
|
|
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(MEASUREMENT_INTERVAL_S*1000)); // Espera x*1000 milisegundos
|
|
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(MEASUREMENT_INTERVAL_S*1000)); // Espera x*1000 milisegundos
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -250,14 +255,18 @@ void IRAM_ATTR isr_button() {
|
|
|
lastInterrupt = now;
|
|
lastInterrupt = now;
|
|
|
if (xHigherPriorityTaskWoken) {
|
|
if (xHigherPriorityTaskWoken) {
|
|
|
portYIELD_FROM_ISR();
|
|
portYIELD_FROM_ISR();
|
|
|
- Serial.println("Yield from ISR");
|
|
|
|
|
- } else {
|
|
|
|
|
- Serial.println("No yield from ISR");
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void drawProgressBar(int x, int y, int w, int h, unsigned long progress, unsigned long total) {
|
|
|
|
|
+ display.drawRect(x, y, w, h, SSD1306_WHITE); // Dibuja el borde
|
|
|
|
|
+ int filledWidth = (progress * w) / total;
|
|
|
|
|
+ display.fillRect(x + 1, y + 1, filledWidth - 2, h - 2, SSD1306_WHITE); // Dibuja la barra llena
|
|
|
|
|
+ display.display();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void task_ui(void *pvParameters){
|
|
void task_ui(void *pvParameters){
|
|
|
unsigned long pressTime = 0;
|
|
unsigned long pressTime = 0;
|
|
|
unsigned long lastActivity = millis();
|
|
unsigned long lastActivity = millis();
|
|
@@ -268,15 +277,13 @@ void task_ui(void *pvParameters){
|
|
|
if (xSemaphoreTake(buttonSemaphore, pdMS_TO_TICKS(200)) == pdTRUE){ //button pressed
|
|
if (xSemaphoreTake(buttonSemaphore, pdMS_TO_TICKS(200)) == pdTRUE){ //button pressed
|
|
|
if (processingButton) continue; //evita reentradas
|
|
if (processingButton) continue; //evita reentradas
|
|
|
processingButton = true;
|
|
processingButton = true;
|
|
|
- Serial.println("Button semaphore taken");
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
pressTime = millis();
|
|
pressTime = millis();
|
|
|
lastActivity = millis(); //reset watchdog
|
|
lastActivity = millis(); //reset watchdog
|
|
|
|
|
|
|
|
if (!pantallaOn){
|
|
if (!pantallaOn){
|
|
|
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
|
pantallaOn = true;
|
|
pantallaOn = true;
|
|
|
- Serial.println("Pantalla encendida");
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool timed_out = false;
|
|
bool timed_out = false;
|
|
@@ -284,51 +291,44 @@ void task_ui(void *pvParameters){
|
|
|
while (digitalRead(BUTTON_PIN) == LOW){
|
|
while (digitalRead(BUTTON_PIN) == LOW){
|
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
|
checkTime = millis();
|
|
checkTime = millis();
|
|
|
- if ((millis() - pressTime) > DURACION_WATCHDOG_MS){ //10s timeout para evitar bloqueos
|
|
|
|
|
|
|
+ if ((checkTime - pressTime) > DURACION_WATCHDOG_MS){ //10s timeout para evitar bloqueos
|
|
|
timed_out = true;
|
|
timed_out = true;
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
+ drawProgressBar(0, SCREEN_HEIGHT - 10, SCREEN_WIDTH, 8, checkTime - pressTime, PULASCION_LARGA_MS);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ignore_isr_until = millis() + 50; //ignorar nuevas interrupciones durante 500 ms
|
|
ignore_isr_until = millis() + 50; //ignorar nuevas interrupciones durante 500 ms
|
|
|
|
|
|
|
|
unsigned long duration = checkTime - pressTime;
|
|
unsigned long duration = checkTime - pressTime;
|
|
|
- Serial.printf("Button released after %lu ms\n", duration);
|
|
|
|
|
|
|
|
|
|
if (timed_out){
|
|
if (timed_out){
|
|
|
OLED_print("Apagando","pantalla");
|
|
OLED_print("Apagando","pantalla");
|
|
|
- delay(1000);
|
|
|
|
|
display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la
|
|
display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la
|
|
|
pantallaOn = false;
|
|
pantallaOn = false;
|
|
|
- Serial.println("Pantalla apagada por timeout");
|
|
|
|
|
} else {
|
|
} else {
|
|
|
-
|
|
|
|
|
if (duration >= PULASCION_LARGA_MS){
|
|
if (duration >= PULASCION_LARGA_MS){
|
|
|
- Serial.println("Pulsacion larga detectada");
|
|
|
|
|
//pulsacion larga: cabia entre grabacion y no grabacion de datos
|
|
//pulsacion larga: cabia entre grabacion y no grabacion de datos
|
|
|
grabando = grabando ? false : true; //toggle
|
|
grabando = grabando ? false : true; //toggle
|
|
|
if (grabando){
|
|
if (grabando){
|
|
|
vTaskResume(medicionesHandle);
|
|
vTaskResume(medicionesHandle);
|
|
|
//Mostrar que empieza la grabación
|
|
//Mostrar que empieza la grabación
|
|
|
OLED_print("Ruta","iniciada");
|
|
OLED_print("Ruta","iniciada");
|
|
|
- Serial.println("Toggle to grabando iniciada");
|
|
|
|
|
} else {
|
|
} else {
|
|
|
vTaskSuspend(medicionesHandle);
|
|
vTaskSuspend(medicionesHandle);
|
|
|
//Mostrar que se pausa/finaliza la grabación
|
|
//Mostrar que se pausa/finaliza la grabación
|
|
|
OLED_print("Ruta","pausada");
|
|
OLED_print("Ruta","pausada");
|
|
|
- Serial.println("Toggle to grabando pausada");
|
|
|
|
|
}
|
|
}
|
|
|
- delay (1000); //espera un segundo para que el usuario vea el mensaje
|
|
|
|
|
} else {
|
|
} else {
|
|
|
//Pulsacion corta + grabando datos, cicla datos
|
|
//Pulsacion corta + grabando datos, cicla datos
|
|
|
if (grabando) {
|
|
if (grabando) {
|
|
|
- pantallaEstado = (pantallaEstado + 1) % 3; //cicla entre 0-2
|
|
|
|
|
|
|
+ pantallaEstado_grab = (pantallaEstado_grab + 1) % 5; //cicla entre 0-4
|
|
|
SensorData currentData;
|
|
SensorData currentData;
|
|
|
if(xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
|
|
if(xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
|
|
|
currentData = latestData;
|
|
currentData = latestData;
|
|
|
xSemaphoreGive(dataMutex);
|
|
xSemaphoreGive(dataMutex);
|
|
|
}
|
|
}
|
|
|
- switch (pantallaEstado){
|
|
|
|
|
|
|
+ switch (pantallaEstado_grab){
|
|
|
case 0:
|
|
case 0:
|
|
|
OLED_print("Posicion",String(currentData.longitude) + "," + String(currentData.latitude));
|
|
OLED_print("Posicion",String(currentData.longitude) + "," + String(currentData.latitude));
|
|
|
break;
|
|
break;
|
|
@@ -338,15 +338,17 @@ void task_ui(void *pvParameters){
|
|
|
case 2:
|
|
case 2:
|
|
|
OLED_print("Altitud",String(gps.altitude.meters(), 1)+"m");
|
|
OLED_print("Altitud",String(gps.altitude.meters(), 1)+"m");
|
|
|
break;
|
|
break;
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ OLED_print("Temp/Hum",String(currentData.temperature,1)+"C/"+String(currentData.humidity,1)+"%");
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 4:
|
|
|
|
|
+ OLED_print("Velocidad",String(gps.speed.kmph())+"km/h");
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- Serial.println("Ciclo pantalla datos");
|
|
|
|
|
- delay(1000); //espera 2 segundos para que el usuario vea el mensaje
|
|
|
|
|
} else {
|
|
} else {
|
|
|
- OLED_print("Grabacion","pausada");
|
|
|
|
|
- Serial.println("Grabacion pausada, no ciclar datos");
|
|
|
|
|
- delay(1000); //espera un segundo para que el usuario vea el mensaje
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ pantallaEstado_menu = (pantallaEstado_menu + 1) % 3;
|
|
|
|
|
+ OLED_print("Ruta","pausada");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -359,7 +361,6 @@ void task_ui(void *pvParameters){
|
|
|
if (pantallaOn && ((millis() - lastActivity) > DURACION_WATCHDOG_MS)){
|
|
if (pantallaOn && ((millis() - lastActivity) > DURACION_WATCHDOG_MS)){
|
|
|
display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la pantalla
|
|
display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la pantalla
|
|
|
pantallaOn = false;
|
|
pantallaOn = false;
|
|
|
- Serial.println("Pantalla pagada por watchdog");
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|