#include <SSD1306Ascii.h>
#include <SSD1306AsciiAvrI2c.h>
#include <SPI.h>
#include <SD.h>

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C
SSD1306AsciiAvrI2c oled;

float profon;
float temper;
float vbatt;
char strDati[38];
unsigned int lettura = 0;
bool mode = 0;
bool vb = 0;
char nomeFile[15];
File Dati;
File root;
char gbuff[9]; // generic buffer 

uint32_t timer;

void screen0() {
    oled.clear();
    oled.setFont(fixed_bold10x15);
    oled.setCursor(0, 0);
    oled.print(F("Lett"));
    //oled.print(lettura);
    oled.setCursor(0, 2);
    oled.print(F("Temp"));
    //oled.print(temper, 1);
    //oled.setCursor(0, 2);
    //oled.print(F("C"));
    oled.setCursor(0, 4);
    oled.print(F("Prof"));
    //oled.print(profon, 1);
    //oled.print(F("m"));
    oled.setCursor(0, 6);
    oled.print(F("BATT"));

}

bool ifSdAbsent() {
    bool absent = false;
    if (!SD.begin(10)) {
        absent = true; //se non sente la SD cambia modo di funzionamento
        oled.setFont(fixed_bold10x15);
        oled.clear();
        oled.setCursor(0, 0);
        oled.print(F(" NESSUNA SD"));
        oled.setCursor(0, 2);
        oled.print(F(" SOLO LETT"));
        oled.setCursor(0, 4);
        oled.print(F("  DIRETTA"));
        delay(2000);
    }
    return absent;

}

void showTemperature() {
    // usa  gbuff[9] globale
    sprintf(gbuff, "%3d.%uC", (int)temper, (uint8_t)(temper * 10) % 10);
    oled.setCursor(55, 2);
    oled.print(gbuff);
}

void showLettura() {
    // usa  gbuff[9] globale
    sprintf(gbuff, "%5u", lettura);
    oled.setCursor(65, 0);
    oled.print(gbuff);
}

void showProfondita() {
    // usa  gbuff[9] globale
    sprintf(gbuff, "%3d.%um", (int)profon, (uint8_t)(profon * 10) % 10);
    oled.setCursor(55, 4);
    oled.print(gbuff);

}

void showVbatt() {
    // usa  gbuff[9] globale
    if (vbatt >=3.3) {
        sprintf(gbuff, "%  1d.%1uV", (int)vbatt, (uint8_t)(vbatt * 10) % 10);
        
    } else {
        sprintf(gbuff, "%s", "BASSA");
    }
    oled.setCursor(68, 6);
    oled.print(gbuff);

}

void errore(byte e) {
    Serial.print("errore: ");
    Serial.println(e);
    while(1);
} 

void openFile() {
    
    /*for (byte idx = 1; idx < 100; idx++) { //controllo i files esistenti
      sprintf(nomeFile, "Dati%04i.txt", idx);
      if ( !SD.exists(nomeFile) ) break;
    }
    Serial.println(nomeFile);
    Dati = SD.open(nomeFile, FILE_WRITE); //apro il nuovo file con l'ultimo nome creato
    if (!Dati) { //controllo se il file e' stato creato correttamente, se no
      errore(1); // chiamo gestione errori passandogli il numero dell'errore
    }
    Dati.close();*/
    
    Dati = SD.open("wokwi.txt", FILE_WRITE); //apro il nuovo file con l'ultimo nome creato
    if (!Dati) { //controllo se il file e' stato creato correttamente, se no
      errore(1); // chiamo gestione errori passandogli il numero dell'errore
    }
    
}

void scrivisd() {
  if (Dati) {
    Serial.println(strDati);
    Dati.println(strDati);
    Dati.flush();
    /*digitalWrite(ledp, HIGH); // breve lampeggio ogni scrittura eseguita
    delay(30);
    digitalWrite(ledp, LOW);*/
  }
  else {
    errore(2);
  }
}

void leggisens() {
    
    temper = (950 / 6.6) - (analogRead(A0) / 6.6);
    profon = analogRead(A1) / 8.5;
    vbatt = analogRead(A7) / 243.0;
    //65535
    showLettura();
    showTemperature();
    showProfondita();
    showVbatt();
 
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void setup()
{
    pinMode(4, INPUT_PULLUP);
    Serial.begin(115200);
   
    oled.begin(&Adafruit128x64, I2C_ADDRESS);
    mode = ifSdAbsent();
    root = SD.open("/");
  printDirectory(root, 0);
  Serial.println("");
    Serial.println(mode);
    screen0();

    openFile();
   
    
}
bool headerFileIsWrite = false;
void loop() {
    if (millis() - timer >= 500) {
        lettura++;
        timer = millis();
        if (!headerFileIsWrite) {
            char fileHeader[] = "Lettura,Temperarura,Profondit\n";
            Serial.print(fileHeader);
            headerFileIsWrite = true;
        }
        sprintf(strDati, "%u,%d.%u,%d.%u", lettura, (int)temper, (uint8_t)(temper * 10) % 10, (int)profon, (uint8_t)(profon * 10) % 10);
        //sprintf(strDati, "L %u, T %d.%d C, P %d.%d m", lettura, (int)temper, (int)(temper * 10) % 10, (int)profon, (int)(profon * 10) % 10);
        //Serial.print(strDati);
        scrivisd();
    }
    // chiamata senza ritardi solo per mostrare l'aggiornamento rapido
    leggisens();
    if (!digitalRead(4)) {
        Dati.close();
        while(1);
    }

    
}

#if(0) 
#include <Wire.h>
#include <SPI.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include <SD.h>
#include <MS5837.h>
#define I2C_ADDRESS 0x3C
#define ledp 3
float profon = 103.45;
float temper = 24.56;
float vbatt;
char strDati[38];
unsigned int lettura = 0;
bool modo = 0;
bool vb = 0;
char nomeFile[15];
MS5837 sensor;
File Dati;
SSD1306AsciiWire oled;

void errore(byte ernm) {
  oled.setFont(fixed_bold10x15);
  oled.clear();
  oled.setCursor(0, 0);

  if (ernm == 1) {
    oled.print(F(" ERRORE"));
    oled.setCursor(0, 2);
    oled.print(F("CREAZIONE"));
    oled.setCursor(0, 4);
    oled.print(F("FILE DATI"));
  }
  else if (ernm == 2) {
    oled.print(F("  ERRORE"));
    oled.setCursor(0, 2);
    oled.print(F("SCRITTURA"));
    oled.setCursor(0, 4);
    oled.print(F(" SULLA SD"));
  }
  else if (ernm == 3) {
    oled.print(F(" ERRORE"));
    oled.setCursor(0, 2);
    oled.print(F(" SENSORE"));
  }
  else if (ernm == 4) {
    oled.print(F("  BATTERIA"));
    oled.setCursor(0, 2);
    oled.print(F("   TROPPO"));
    oled.setCursor(0, 4);
    oled.print(F("  SCARICA!"));
  }
  while (1) {
    digitalWrite(ledp, HIGH);
    delay(250);
    digitalWrite(ledp, LOW);
    delay(250);
  }
}

void leggibatt() {
  vb = 0;
  int valore = analogRead(14); //scarto una lettura
  valore = 0;
  delay(5);
  for (byte y = 0; y < 4; y++) { // 4 letture
    valore += analogRead(14);
    delay(5);
  }
  valore /= 4; //media di 4 letture
  if (valore <= 665) vb = 1; // 665 = 3.0V
  vbatt = (float) ((valore * 1.1) / 1024.0) * 4.2; // per AREF impostato su internal 1.1V
  // x4.2 perche' con il partitore da 150k e 47k, sul pin ci sono 1.00V con 4.2V di batteria
}

void leggisens() {
  for (byte x = 0; x < 4; x++) {
    sensor.read();
    temper += sensor.temperature();
    profon += sensor.depth();
    delay(40);
  }
  temper /= 4;
  profon /= 4;
  sprintf(strDati, "L %u, T %d.%d C, P %d.%d m", lettura, (int)temper, (int)(temper * 10) % 10, (int)profon, (int)(profon * 10) % 10);
}

void dispdati() { // scrive i dati sul display
  oled.setFont(fixed_bold10x15);
  oled.clear();
  oled.setCursor(0, 0);
  oled.print(F("Lett "));
  oled.print(lettura);
  oled.setCursor(0, 2);
  oled.print(F("Temp "));
  oled.print(temper, 1);
  oled.print(F("C"));
  oled.setCursor(0, 4);
  oled.print(F("Prof "));
  oled.print(profon, 1);
  oled.print(F("m"));
  //oled.setFont(font5x7);
  oled.setCursor(0, 6);
  if (vb == 1) {
    oled.print(F("BATT BASSA"));
  }
  else {
    oled.print(F("Batt "));
    oled.print(vbatt, 1);
    oled.print(F("V"));
  }
}

void scrivisd() {
  if (Dati) {
    Dati.println(strDati);
    Dati.flush();
    digitalWrite(ledp, HIGH); // breve lampeggio ogni scrittura eseguita
    delay(30);
    digitalWrite(ledp, LOW);
  }
  else {
    errore(2);
  }
}

void setup() {
  Wire.begin();
  Wire.setClock(400000L);
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  pinMode(ledp, OUTPUT); //non uso la seriale
  digitalWrite(ledp, LOW);
  analogReference(INTERNAL); //settato su 1.1V
  pinMode(14, INPUT); //adc7

  //controllo se la batteria e' troppo bassa, se si blocco in errore
  int valore = analogRead(14); //scarto una lettura
  valore = 0;
  delay(5);
  for (byte y = 0; y < 4; y++) { // 4 letture
    valore += analogRead(14);
    delay(5);
  }
  valore /= 4; //media di 4 letture
  if (valore <= 710) errore (4); //710 = 3.2V, autonomia troppo scarsa

  if (!SD.begin(4)) {
    modo = 1; //se non sente la SD cambia modo di funzionamento
    oled.setFont(fixed_bold10x15);
    oled.clear();
    oled.setCursor(0, 0);
    oled.print(F(" NESSUNA SD"));
    oled.setCursor(0, 2);
    oled.print(F(" SOLO LETT"));
    oled.setCursor(0, 4);
    oled.print(F("  DIRETTA"));
    delay(2000);
  }
  else modo = 0;

  if (modo == 0) {
    for (byte idx = 1; idx < 100; idx++) { //controllo i files esistenti
      sprintf(nomeFile, "Dati%04i.csv", idx);
      if ( !SD.exists(nomeFile) ) break;
    }
    Dati = SD.open(nomeFile, FILE_WRITE); //apro il nuovo file con l'ultimo nome creato
    if (!Dati) { //controllo se il file e' stato creato correttamente, se no
      errore(1); // chiamo gestione errori passandogli il numero dell'errore
    }
  }

  //sensor.init();
  //if (!sensor.init()) { //sensore ko, blocca e lampeggia
  //  errore(3); // blocco commentato in attesa del sensore, da ripristinare per funzionamento regolare
  //  delay(2000);
  //}

  oled.setFont(fixed_bold10x15);
  oled.clear();
  oled.setCursor(0, 2);
  oled.print(F("   INIZIO"));
  oled.setCursor(0, 4);
  oled.print(F(" SCRITTURE"));
  delay(2000);
}

void loop() {
  lettura++;
  leggibatt();
  //leggisens(); // commentato in attesa del sensore, da ripristinare per funzionamento regolare
  dispdati();
  if (modo == 0) { // SD presente, chiama scrittura
    scrivisd();
    delay(400);
  }
  else { // SD non presente, modo lettura diretta
    for (byte z = 0; z < 3; z++) {
      digitalWrite(ledp, HIGH); // 3 lampeggi ogni lettura per ricordare
      delay(30);                // che non c'e' scrittura sulla SD
      digitalWrite(ledp, LOW);
      delay(100);
    }
    delay(1500);
  }
}
#endif