/* AndesTrack S.A.C. - Datalogger GPS Vehicular (version mejorada)
- Velocidad simulada con potenciometro en A0
- Buffer en RAM + reintento de escritura si la microSD no responde
SD: DO->12 DI->11 SCK->13 CS->4 VCC->5V GND->GND
Pot: VCC->5V GND->GND SIG->A0 */
#include <SPI.h>
#include <SD.h>
const int CS_PIN = 4; // pon 7 (pin erroneo) para PROBAR el buffer
const int POT_PIN = A0;
const char* LOG_FILE = "trip.csv";
const unsigned long INTERVALO_MS = 2000; // muestreo cada 2 s
const unsigned long RETRY_MS = 5000; // reintento de SD cada 5 s
const int MAX_BUFFER = 20; // registros que caben en RAM
struct RegistroViaje {
unsigned long timestamp;
float latitud;
float longitud;
float velocidad_kmh;
};
RegistroViaje buffer[MAX_BUFFER];
int enBuffer = 0; // registros pendientes en RAM
bool sdDisponible = false;
unsigned long ultimoRegistro = 0;
unsigned long ultimoIntentoSD = 0;
unsigned long numeroRegistro = 0;
void setup() {
Serial.begin(9600);
Serial.println(F("=== AndesTrack - Datalogger GPS (mejorado) ==="));
pinMode(CS_PIN, OUTPUT);
inicializarSD(); // primer intento
}
void loop() {
unsigned long ahora = millis();
// 1) Generar una lectura cada INTERVALO_MS
if (ahora - ultimoRegistro >= INTERVALO_MS) {
ultimoRegistro = ahora;
RegistroViaje dato = leerSensor();
if (sdDisponible && guardarRegistro(dato)) {
Serial.print(F("Registro #")); Serial.print(numeroRegistro);
Serial.println(F(" guardado en microSD."));
} else {
sdDisponible = false; // la SD fallo -> a RAM, no se pierde el dato
almacenarEnBuffer(dato);
}
}
// 2) Si no hay SD, reintentar cada RETRY_MS
if (!sdDisponible && (ahora - ultimoIntentoSD >= RETRY_MS)) {
ultimoIntentoSD = ahora;
Serial.println(F("Reintentando inicializar microSD..."));
if (inicializarSD()) vaciarBuffer(); // recupero lo guardado en RAM
}
}
// Inicializa la SD y crea la cabecera si hace falta
bool inicializarSD() {
if (!SD.begin(CS_PIN)) {
Serial.println(F("microSD NO detectada. Los datos iran a RAM."));
sdDisponible = false;
return false;
}
sdDisponible = true;
if (!SD.exists(LOG_FILE)) {
File f = SD.open(LOG_FILE, FILE_WRITE);
if (f) { f.println(F("registro,timestamp_ms,latitud,longitud,velocidad_kmh")); f.close(); }
}
Serial.println(F("microSD lista."));
return true;
}
// Lee el sensor: velocidad desde el potenciometro (A0)
RegistroViaje leerSensor() {
RegistroViaje r;
r.timestamp = millis();
r.latitud = -12.0464 + (random(-500, 500) / 100000.0);
r.longitud = -77.0428 + (random(-500, 500) / 100000.0);
int lectura = analogRead(POT_PIN); // 0..1023
r.velocidad_kmh = map(lectura, 0, 1023, 0, 120); // 0..120 km/h
return r;
}
// Escribe un registro en la microSD (cierre inmediato = pregunta 3)
bool guardarRegistro(const RegistroViaje &d) {
File f = SD.open(LOG_FILE, FILE_WRITE);
if (!f) return false;
numeroRegistro++;
f.print(numeroRegistro); f.print(",");
f.print(d.timestamp); f.print(",");
f.print(d.latitud, 6); f.print(",");
f.print(d.longitud, 6); f.print(",");
f.println(d.velocidad_kmh, 1);
f.close();
return true;
}
// Guarda en RAM cuando no hay SD (FIFO: descarta el mas antiguo si se llena)
void almacenarEnBuffer(const RegistroViaje &d) {
if (enBuffer < MAX_BUFFER) {
buffer[enBuffer++] = d;
Serial.print(F("Sin SD -> guardado en RAM ("));
Serial.print(enBuffer); Serial.print(F("/"));
Serial.print(MAX_BUFFER); Serial.println(F(")"));
} else {
for (int i = 1; i < MAX_BUFFER; i++) buffer[i - 1] = buffer[i];
buffer[MAX_BUFFER - 1] = d;
Serial.println(F("RAM llena: se descarto el registro mas antiguo."));
}
}
// Vuelca a la SD todo lo acumulado en RAM
void vaciarBuffer() {
Serial.print(F("Volcando ")); Serial.print(enBuffer);
Serial.println(F(" registros de RAM a microSD..."));
int i = 0;
while (i < enBuffer) {
if (!guardarRegistro(buffer[i])) { sdDisponible = false; break; }
i++;
}
int restantes = enBuffer - i; // compacto lo no escrito
for (int k = 0; k < restantes; k++) buffer[k] = buffer[i + k];
enBuffer = restantes;
if (enBuffer == 0) Serial.println(F("Buffer vaciado. Todo persistido."));
}