With SD Card

Dependencies:   NAVDATA RA8875 SDFileSystem VCODATA mbed

main.cpp

Committer:
gstedile
Date:
2017-07-30
Revision:
2:968b38c3ef49
Parent:
1:30b1ca228fc7

File content as of revision 2:968b38c3ef49:

#include <time.h>
#include "mbed.h"           // v112
#include "RA8875.h"         // v102
#include "MyFont18x32.h"
#include "BPG_Arial08x08.h"
#include "BPG_Arial10x10.h"
#include "BPG_Arial20x20.h"
#include "BPG_Arial31x32.h"
#include "BPG_Arial63x63.h"
#include "GPS.h"            // Comunicacion con el gps.
#include "NAVDATA.h"        // Para la clase NAVDATA que maneja los datos de navegación del último período.
#include "VCODATA.h"        // Para la clase VCODATA que maneja los datos de navegación más recientes parametrizados por velocidad de cada período.
#include "SDFileSystem.h"   // SD Card
#include <sstream>          // Para uso de streams
#include <string> 

int err_Store=0;
int TESTING=0;                                     // -->1:Habilita test de funcionamiento del almacenamiento de datos.
int DEBUG1=0;                                       // -->1:Habilita informacion para debug.
int DEBUG2=0;                                       // -->1:Habilita informacion para debug2.
int DEBUG_GPS=0;                                   // -->1:Habilita datos para debug de comunicacion con gps.
int SIMULATION=1;                                  // -->1: Habilita simulacion cuando no hay datos gps.
enum sentido{DWN=0,UP,NO};
enum figura{ZONA=0,SIN_DT,CIRC,FLECHA,ElIP,GAUGE};
const char *sd_dir="/sd/snocc";                     // Directorio de almacenamiento de datos.
const char *sd_file="/sd/snocc/sdsnocc.csv";        // Archivo csv de almacenamiento de datos. 
const int V_M=40;                                  //Velocidad Maxima
float Counter=0;                                    //Contador de pulsos del sensor de flujo.
float LCounter=0;                                   //Consumo en litros

int sepx= 105;    // Separacion x entre recuadros  
int sepy= 66;     // Separacion x entre recuadros    
int sizex1=100;   // Tamaño cuadro para valores
int sizey1=40;
int xr1=10;       // Posicion de recuadros para exhibir datos
int yr1=10;
int xr2=xr1+sepx;
int yr2=yr1;
int xr3=xr1;
int yr3=yr1+sepy;
int xr4=xr1;
int yr4=yr3+sepy; 
int xr5=xr1;
int yr5=yr4+sepy;
int xr6=xr2;
int yr6=yr5; 

int signal_x=xr2;   // REGION DE SEÑALIZACION
int signal_y=yr3;
int signal_x_sz=99;
int signal_y_sz= 2*sepy-10;

NAVDATA NAVIGATION_OBJECT;                          //Objeto que maneja los datos de navegación del último período. (ANTERIORMENTE LLAMADO NAVIGATION_TABLE, nombre que generaba confusion)
VCODATA NAVIGATION_VMATRIX(NAVIGATION_OBJECT, V_M);          // Objeto que maneja la matriz de datos de navegación            $
VCODATA NAVIGATION_V_SMOOTH_MTRX(NAVIGATION_OBJECT, V_M);    // Objeto que maneja la matriz de datos de navegación promediados $            
NAVDATA TestNAV;                                             // Objeto para crear matriz default;   ///  DEBUG?

LocalFileSystem local("local");                     // Para <PrintScreen>
Serial pc(USBTX, USBRX);                        
RA8875 lcd(p5, p6, p7, p8, NC, "lcd");              // MOSI, MISO, SCK, /ChipSelect, /reset, name   // Comunicacion con Display
SDFileSystem sd(p11, p12, p13, p14, "sd");          // SD CARD: mosi, miso, sclk, cs                // Comunicacion con SD card

 
//>>>>>>>>>>>>>>>>>>  SECCION TOUCH PANEL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
extern "C" void mbed_reset();
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
bool Intersect(rect_t rect, point_t p)
{
    if (p.x >= min(rect.p1.x, rect.p2.x) && p.x <= max(rect.p1.x, rect.p2.x)
    && p.y >= min(rect.p1.y, rect.p2.y) && p.y <= max(rect.p1.y, rect.p2.y))
        return true;
    else
        return false;
}

//>>>>>>>>>>>>>>>>>>  FIN SECCION TOUCH PANEL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

 //Función para la interrupción
  
    void trigger() {                           
         Counter++;
         LCounter=Counter/2500;
         }


//##################### GAUGE - CLOCK ##################################################################

uint16_t ccenterx=100, ccentery=100; //center x,y of the clock
const uint16_t cradius = 110;//radius of the clock
const float scosConst = 0.0174532925;
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0, vx = 0, vy = 0;
float sdeg = 0, mdeg = 0, hdeg = 0, vdeg=0;
uint16_t osx, osy, omx, omy, ohx, ohy,ovx, ovy;
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0;// for next 1 second timeout
uint8_t hh, mm, ss; //containers for current time


void drawClockFace() {
  lcd.fillcircle(ccenterx, ccentery, cradius, Blue);
  lcd.fillcircle(ccenterx, ccentery, cradius - 4, Black);
  uint16_t span_angle=180;  // Grados de span en el reloj. 
  int j=0, RD=255,GN=255, BL=255;                   
  for (int i = 0; i <= span_angle; i += 2) {
    sx = cos((i - 180) * scosConst);
    sy = sin((i - 180) * scosConst);
    x0 = sx * (cradius - 4) + ccenterx;
    yy0 = sy * (cradius - 4) + ccentery;
    x1 = sx * (cradius - 40) + ccenterx;
    yy1 = sy * (cradius - 40) + ccentery;
    if (i < span_angle/2)j=i;
       else j=(span_angle-i) ;   
    
    if (2*j/span_angle>0.9) {
        RD=0;
        GN=255;
        BL=0;
    }
    else  if (2*j/span_angle<0.75){
          RD=255;
          GN=255*4*(2*j/span_angle)/3;     
          BL=0;
          }
          else {
           RD=255*4*(1-(2*j/span_angle));
           GN=255;
           BL=0;
           }

    if (i<10 || i>170) lcd.line(x0, yy0, x1, yy1, RGB(255,0,0));
    else if (i<20 || i>160) lcd.line(x0, yy0, x1, yy1,RGB(255,50,0));
            else if (i<30 || i>150) lcd.line(x0, yy0, x1, yy1, RGB(255,120,0));
                 else if (i<40 || i>140) lcd.line(x0, yy0, x1, yy1, RGB(255,200,0));
                      else if (i<50 || i>130) lcd.line(x0, yy0, x1, yy1, RGB(255,255,0));
                            else if (i<60 || i>120) lcd.line(x0, yy0, x1, yy1, RGB(200,255,0));
                                 else if (i<70 || i>110) lcd.line(x0, yy0, x1, yy1, RGB(120,255,0));
                                       else if (i<80 || i>100) lcd.line(x0, yy0, x1, yy1, RGB(50,255,0));
                                             else lcd.line(x0, yy0, x1, yy1, RGB(0,255,0));
    }
  
    for (int i = 0; i <= span_angle; i +=5 ) {   //  DIBUJO ESCALA 1
        //sx = cos((i - 90) * scosConst);
        sx = cos((i - 180) * scosConst);
        //sy = sin((i - 90) * scosConst);
        sy = sin((i - 180) * scosConst);
        x0 = sx * (cradius - 4) + ccenterx;
        yy0 = sy * (cradius - 4) + ccentery;
        x1 = sx * (cradius - 10) + ccenterx;
        yy1 = sy * (cradius - 10) + ccentery;
        lcd.line(x0, yy0, x1, yy1, White);
    }
    for (int i = 0; i <= span_angle; i +=15 ) {   //  DIBUJO ESCALA 2
        sx = cos((i - 180) * scosConst);
        sy = sin((i - 180) * scosConst);
        x0 = sx * (cradius - 4) + ccenterx;
        yy0 = sy * (cradius - 4) + ccentery;
        x1 = sx * (cradius - 20) + ccenterx;
        yy1 = sy * (cradius - 20) + ccentery;
        lcd.line(x0, yy0, x1, yy1, White);
    }
    lcd.SetTextCursor(ccenterx-35, ccentery-25);
    lcd.SelectUserFont(BPG_Arial20x20);
    lcd.background(Black);
    lcd.foreground(RGB(0,0,255));
    lcd.printf("SNOCC");
    lcd.SetTextCursor(ccenterx-35, ccentery+15);
    lcd.printf("METER");
    lcd.SetTextCursor(ccenterx-18, (ccentery - cradius  +20));
    lcd.background(RGB(0,255,0));
    lcd.foreground(Black);
    lcd.printf("VCO");
    lcd.background(Black); 
}

void setup(void) {
  lcd.foreground(White);
  lcd.background(Black);
  //ccenterx = lcd.width() / 2;
  //ccentery = lcd.height() / 2;
  osx = ccenterx;
  osy = ccentery;
  omx = ccenterx;
  omy = ccentery;
  ohx = ccenterx;
  ohy = ccentery;
}

void drawClockGauge(float value, float fullscl ) {  // Ej. fullscl 2 => -1 a 1

    vdeg=180 * value/fullscl;            
    vx = cos((vdeg - 90) * scosConst);
    vy = sin((vdeg - 90) * scosConst);
    
    lcd.filltriangle(vx * (cradius - 14) + ccenterx + 1, vy * (cradius - 14) + ccentery + 1, (ccenterx + 1)-(vy * (cradius - 14))*0.1, (ccentery + 1)+vx * (cradius - 14)*0.1,(ccenterx + 1)+(vy * (cradius - 14))*0.1, (ccentery + 1)-vx * (cradius - 14)*0.1, RGB(200,255,0), FILL);
    lcd.line(vx * (cradius - 14) + ccenterx + 1, vy * (cradius - 14) + ccentery + 1, ccenterx + 1, ccentery + 1, Red);
    lcd.fillcircle(ccenterx + 1, ccentery + 1, 3, Red);
}

void drawPrintPrfm( int x, int y, float val){// ubicacion x,y, valor

    lcd.roundrect( x,y,x+82,y+36,6,4, RGB(0,0,255));
    lcd.SelectUserFont(BPG_Arial31x32);
    if (val==0) lcd.SetTextCursor(x+15,y+3);  // 100-val=100  ---> print 100
    else lcd.SetTextCursor(x+21,y+3);
    lcd.foreground(RGB(200,255,0));
    lcd.background(Black);
    if ( val<=100) {
    lcd.printf ("%2.0f \r\n",100-val); // Valor porcentual del complemento
    lcd.SelectUserFont(BPG_Arial20x20);
    lcd.SetTextCursor(x+62,y+11);
    lcd.printf("%%");
    }
    else lcd.printf ("---\r\n");
}            


void drawPrintTime(uint16_t x, uint16_t y, uint8_t h, uint8_t m, uint8_t s) {
  lcd.SetTextCursor (x, y);
  lcd.printf(__DATE__);
  lcd.SetTextCursor (x, y - 13);
  if (hh > 12) {
    if (hh < 22) lcd.printf("0");
    lcd.printf ("%d",hh - 12);
  }
  else {
    if (hh < 10) lcd.printf("0");
    lcd.printf ("%d",hh);
  }
  lcd.printf (":");
  if (mm < 10) lcd.printf("0");
  lcd.printf ("%d",mm);
  lcd.printf (":");
  if (ss < 10) lcd.printf("0");
  lcd.printf ("%d",ss);
  if (hh > 12) {
    lcd.printf(" pm");
  }
  else {
    lcd.printf (" am");
  }
}

void reloj(uint16_t cx,uint16_t cy,sentido sent,float gauge, float fullscale){  // coord x, coord y,  valor, fondo de escala;
    ccenterx = cx;
    ccentery = cy;
    osx = ccenterx;
    osy = ccentery;
    omx = ccenterx;
    omy = ccentery;
    ohx = ccenterx;
    ohy = ccentery;
    drawClockFace();
    drawClockGauge(gauge, fullscale );
    drawPrintPrfm(ccenterx - 40, ccentery +40, abs(gauge*100));
    }

           
/* Funcion build_default_Mtrx: Carga los datos (consumo/milla) del vector LAST_NAV_DATA de los objetos NAVDATA de VCODATA para testing.*/
/* Si el parámetro virtual_speed  es  cero, se completa la matríz con valores default. Sino, se carga
   solamente un vector NAVDATA con valores default consistentes con los parámetros y se almacena en la matríz cuando la cantidad
   de períodos a vel constante es alcanzada. Este caso es utilizado para testing.*/

int   build_default_Mtrx(VCODATA &Test_Matrix_VCO,NAVDATA &TestNDO, double virtual_speed, double virtual_timestamp){
     double virtual_time=0;
     double virtual_longitude=-58.5797;                   // Mantiene cte la Longitud.
     double virtual_latitude=-34.4251;
     double virtual_counter=0;
     if (virtual_speed==0){
        //virtual_timestamp=0.00000001;             // en segundos
        for (int i=1; i< Test_Matrix_VCO.vel_max; i++){
            virtual_speed= i*1.0;
                       
            if (i<12) virtual_time=5.0*i;                          // Formato NMEA: hhmmss,ss
            else {
                int mnts=int(5*i/60);
                virtual_time = ((mnts*100) +((5*i)- (mnts*60)));    // Formato NMEA: (hh)mmss,ss
            }
            TestNDO.LAST_NAV_DATA[cons_interpolated]=-1;        // --> -1:Datos iniciales.
            TestNDO.np_concat=0;                                // Cantidad de periodos concatenados:-->0: Solo valores de inicio.
            virtual_latitude+=(virtual_speed*5/3600)/(59.99999981628485);// Tomo delta_t virtual de (virtual_speed*Delta t) y                                                                                                        // calculo latitud recorrida en  virtual_timestamp @virtual_speed y longitud cte.
            if (i<10) virtual_counter+=0.6*i*i;         // Simulacion de consumo; modificar y probar
            else if (i<20) virtual_counter+=55;
                 else if(i<30) virtual_counter+=900/i;
                    else virtual_counter+=0.06*i*i;
            int err_Rot=TestNDO.rotate_data(virtual_longitude, virtual_latitude, virtual_time, virtual_counter, NAVIGATION_VMATRIX.vel_max);
            virtual_timestamp+=5;                               // en segundos, 5 segundos de período
            if(err_Rot==0){                                     // Si la rotacion fue 100% exitosa
                if(Test_Matrix_VCO.store_data(TestNDO,1)!=0) return -1; //Notar que no requiere validar velocidad constante para almacenar; almacena todos los periodos bien rotados.
            }
            else {
                
                if(err_Rot==1) return 1;                        // Tiempo entre muestras demasiado grande. Períódo no válido.
                else return 2;                                  // Timestamp no válido. 
            }
        }            
     }   
     else{                        // Rota valores para la velocidad indicada, seteando valores crecientes de consumo para testing
          
 
            TestNDO.np_concat=0;                                // Cantidad de periodos concatenados:-->0: Solo valores de inicio.
            float virtual_longitude=-58.5797;                   // Mantiene cte la Longitud.
            float virtual_latitude=-34.4251+((virtual_speed*virtual_timestamp)/(59.99999981628485*3600));// Tomo delta_t virtual de (virtual_speed*virtual_timestamp) y calculo     
                                                                                                         // latitud navegada en  virtual_timestamp @virtual_speed y longitud cte.
            virtual_time=virtual_timestamp;                     //en formato NMEA hhmmss,ss
            float virtual_counter=0.01*virtual_timestamp*virtual_timestamp;         // Simulacion de consumo creciente; modificar y probar
            int err_Rot=TestNDO.rotate_data(virtual_longitude, virtual_latitude, virtual_time, virtual_counter, NAVIGATION_VMATRIX.vel_max);
            if(err_Rot==0){                                     // Si la rotacion fue 100% exitosa
                if(Test_Matrix_VCO.store_data(TestNDO,2)==-1) return -1;  // Notar que requiere 2 períodos a igual velocidad para que se almacene definitivamente.
            }
            else {
                if(err_Rot==1) return 1;                        // Tiempo entre muestras demasiado grande. Períódo no válido.
                else return 2;                                  // Timestamp no válido. 
            }
     }            
        return 0;
}

         
 /* Funcion  print_VCO_curve : Imprime la curva de consumo/milla en funcion de la velocidad a partir del vector de objetos NAV_DATA de la clase VCODATA, con lineas (printline=1) o puntos (=0)
    Parametros: Objeto VCODATA; Interpolated: 0 -> no imprime valores interpolados o promediados; 1: interpola con puntos, 2: interpola con lineas*/

    void print_VCO_curve(VCODATA &Matrix_VCO, int interpolated){    
        //lcd.puts("ENTRANDO a print_VCO_curve\r\n");  // DEBUG
        int vcc[2];
        float r,s; // Consumo
        int y,x;
        int VCO= Matrix_VCO.get_VCO(vcc);   
        int y_offset=250;               //Para que imprima de abajo hacia arriba.
        int y_text_offset=15;           //Para cooregir diferencia de impresion entre caracter y linea.
        int x_offset=30;                //Posicionamiento en x
        int y_i=y_offset;               //Punto origen y
        int x_i=x_offset;               //Punto origen x
        int x_scale=10;                  // Escala para graficar eje x.
        int y_scale=90;                 // Escala para graficar eje y.
        lcd.background(RGB(255,255,255));
        lcd.foreground(Blue);
        lcd.SelectUserFont(BPG_Arial20x20);
        lcd.SetTextCursor(0,0);         // Pongo cursor en posicion
        lcd.cls();
        lcd.roundrect( 5,20,470,270,10,8, RGB(255,255,0));          // Rectangulo para encuadre de graficos
        lcd.fillroundrect(10,25,465,264,5,3,Green);
        lcd.foreground(RGB(255,255,0));
        lcd.background(Green);
           
        for (int n=0;n<Matrix_VCO.vel_max;n++){                     // Recorre x de 0 a vel_max.     
            s = Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_mile_p];  // Consumo por milla del período
            y=int(y_offset-y_scale*s);                              // El consumo máximo es alrededor de 2 l/m => Multiplico por y_scale 
                                                                    // para que ocupe mas pantalla.
            x=n*x_scale+x_offset;                                   // para aumentar el span (eje x)       
            switch (interpolated){ 
            case 0:  if (Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_interpolated]==0){  //Valores sin interpolar
                        lcd.SetTextCursor(x,y-y_text_offset);
                        lcd.printf(".");  
                        }
                    break;
            case 1:  if ((Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_interpolated]==1) || (Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_interpolated]==2))lcd.foreground(Orange); // interpola con puntos de otro color
                        lcd.SetTextCursor(x,y-y_text_offset);   // el offset adicional es para corregir la diferencia de ubicacion linea-caracter.
                        lcd.printf(".");
                        lcd.foreground(RGB(255,255,0));
                    break;
            case 2: lcd.line(x_i,y_i,x,y);  // Imprime linea
                    break;
            default: 
                    lcd.SetTextCursor(x,y-y_text_offset);
                    lcd.printf(".");
                    break;
            }      
                         
        x_i=x;
        y_i=y;
        }
        
        x_i=x_offset;
        y_i=y_offset;
        
        lcd.SelectUserFont(BPG_Arial10x10);     // Seleccion de tipo y tamaño de letras
        lcd.background(Green);
        lcd.foreground(Blue);
        lcd.SetTextCursor(30,32);
        lcd.puts("Cons.(l/mn)\r\n");
        lcd.SetTextCursor(420,235);
        lcd.puts("Vel.(kn)\r\n");  
        lcd.line(x_i,y_i,Matrix_VCO.vel_max*x_scale+x_offset,y_i);   // Imprimo eje x.
        for(int j=10;j<=Matrix_VCO.vel_max;j+=10){
            int x=j*x_scale+x_offset;
            lcd.line(x,y_i,x,y_i-5); 
            lcd.SetTextCursor(x,y_i+5);
            lcd.printf("%d",j);
        }              
        lcd.line(x_i,y_i,x_i,40);                           // Imprimo eje y.
            for(int k=1;k<=5;k++){
            y=y_offset-k*0.5*y_scale;
            lcd.line(x_i,y,x_i+10,y); 
            lcd.SetTextCursor(x_i-15,y+5);
            if(y>=0)lcd.printf("%.1f",k*0.5);
            } 
        if (VCO>0){
            r = Matrix_VCO.NAV_DATA[vcc[1]].LAST_NAV_DATA[cons_mile_p];   // Valor de consumo para VMC.
            s = Matrix_VCO.NAV_DATA[vcc[0]].LAST_NAV_DATA[cons_mile_p];   // Valor de consumo para VCO.
            y=int(y_offset-y_scale*s);                                  // el consumo máximo es alrededor de 2 l/m. Multiplico por y_scale para que ocupe mas pantalla.
            x=vcc[0]*x_scale+x_offset;                                     // para aumentar el span (eje x)
            if (interpolated==2){
                lcd.circle(x,y,5); 
            }                                        
            else{
                lcd.SetTextCursor(x,y);         
                lcd.printf("*");
            } 
            lcd.SetTextCursor(vcc[0]*x_scale+x_offset+10,y_offset-s*y_scale+20);
            lcd.printf("%.2lf l/m",s);              
            lcd.SetTextCursor(vcc[0]*x_scale+x_offset+10,y_offset-s*y_scale+10);
            lcd.printf("VCO: %d kn",vcc[0]);  
            
            y=int(y_offset-y_scale*r);                // el consumo máximo es alrededor de 2 l/m. Multiplico por y_scale para que ocupe mas pantalla.
            x=vcc[1]*x_scale+x_offset;                   // para aumentar el span (eje x)
            if (interpolated==2){
                lcd.circle(x,y,5); 
            }                                        
            else{
                lcd.SetTextCursor(x,y);         
                lcd.printf("*");
            } 
            lcd.SetTextCursor(vcc[1]*x_scale+x_offset+10,y_offset-r*y_scale-20);
            lcd.printf("%.2lf l/m",r);              
            lcd.SetTextCursor(vcc[1]*x_scale+x_offset+10,y_offset-r*y_scale-30);
            lcd.printf("VMC: %d kn",vcc[1]);
            

        }
        else{
            lcd.SetTextCursor(120,35); 
            lcd.SelectUserFont(BPG_Arial10x10);     // Seleccion de tipo y tamaño de letras        
            lcd.printf("No hay datos suficientes para obtener la VCO");
            lcd.printf("%d",VCO);//DEBUG
        }
        lcd.foreground(RGB(255,255,0));
        lcd.background(Black);
    }
    
    
 /* Funcion  print_VCO_data : Imprime una tabla con los datos de consumo/milla en funcion de la velocidad a partir del vector de objetos NAV_DATA de la clase VCODATA.
    Parametros: Objeto VCODATA; */

    void print_VCO_data(VCODATA &Matrix_VCO){
            float cons, vel;
            lcd.SelectUserFont(BPG_Arial10x10);     // Seleccion de tipo y tamaño de letras
            lcd.background(RGB(255,255,255));
            lcd.foreground(Blue);
            lcd.SetTextCursor(0,0);                 // Pongo cursor en posicion
            lcd.cls();
            lcd.puts("Velocidad-Consumo\r\n");
            for (int n=0;n<83;n++){                                     // Recorre x de 0 a 83. (Maxima cantidad que entra en una pantalla)    
            cons = Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_mile_p];   // Consumo por milla del período
            vel= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[speed_p];         // Velocidad del período.
            lcd.printf("|  %d - %lf  |  %lf  |",n,vel,cons);
            } 
            wait(3);
            lcd.cls();
            for (int n=83;n<Matrix_VCO.vel_max;n++){                     // Recorre x de 0 a vel_max.     
            cons = Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_mile_p];   // Consumo por milla del período
            vel= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[speed_p];         // Velocidad del período.
            lcd.printf("|  %d - %lf  |  %lf  |",n,vel,cons);
            }                                       
            //lcd.SelectUserFont(BPG_Arial20x20);     // Seleccion de tipo y tamaño de letras
    
    }
    
    
/* Funcion mtrx2sd: Guarda los datos de la matriz en un archivo de texto existente*/
    
    int mtrx2sd(VCODATA &Matrix_VCO, const char *filename){
            double lngtd_f,lngtd_i,lttd_f,lttd_i,tm_f,tm_i,dstnc_p,spd_p,cnsmptn_i,cnsmptn_f,cnsmptn_p,cns_ml_p,cns_hr_p,cns_ntrpltd; // Variables de navegacion;
            FILE *fp1;
            fp1 = fopen(filename, "w");   //Apertura para escritura
            if(fp1 == NULL) {
            return -1;
            }       
            for (int n=0;n<=Matrix_VCO.vel_max;n++){
                lngtd_f= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[longitude_f];        // Longitud y Latitud iniciales y finales.
                lngtd_i= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[longitude_i];
                lttd_f= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[latitude_f];
                lttd_i= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[latitude_i];
                tm_f= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[time_f];                  // El dato (timestamp al final del período en cuestion, en horas) se obtendrá luego proveniente del GPS.
                tm_i= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[time_i];                  // Timestamp al inicio del período en horas.
                dstnc_p= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[distance_p];          // Distancia recorrida durante este período en millas nauticas.
                spd_p= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[speed_p];                // Velocidad media del período en nudos.
                cnsmptn_i= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_i];    // Consumo en litros al comienzo del período.
                cnsmptn_f= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_f];    // Consumo en litros al final del período.
                cnsmptn_p= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_p];    // Consumo en litros del período.
                cns_ml_p= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_mile_p];        // Consumo en litros por milla nautica.
                cns_hr_p= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_hour_p];        // Consumo en litros por hora.
                cns_ntrpltd= Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_interpolated];  // Consumo interpolado?: -1-> initial padding
                               
                fprintf(fp1,"%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f\r\n",lngtd_f,lngtd_i,lttd_f,lttd_i,tm_f,tm_i,dstnc_p,spd_p,cnsmptn_i,cnsmptn_f,cnsmptn_p,cns_ml_p,cns_hr_p,cns_ntrpltd);
                }
           return fclose(fp1);
           }
           
/* Funcion sd2mtrx: Guarda los datos de un archivo de texto existente en la matriz*/           
           
    int sd2mtrx(VCODATA &Matrix_VCO, const char *filename){  
        double lngtd_f,lngtd_i,lttd_f,lttd_i,tm_f,tm_i,dstnc_p,spd_p,cnsmptn_i,cnsmptn_f,cnsmptn_p,cns_ml_p,cns_hr_p,cns_ntrpltd; // Variables de navegacion;  
        FILE *fp1;
        fp1 = fopen(filename, "r");   //Apertura para escritura
        if(fp1 == NULL) {
            return -1;
            }
        for (int n=0;n<Matrix_VCO.vel_max;n++){
            fscanf(fp1,"%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf",&lngtd_f,&lngtd_i,&lttd_f,&lttd_i,&tm_f,&tm_i,&dstnc_p,&spd_p,&cnsmptn_i,&cnsmptn_f,&cnsmptn_p,&cns_ml_p,&cns_hr_p,&cns_ntrpltd);                 // Leemos un double y lo guardamos
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[longitude_f]=lngtd_f;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[longitude_i]=lngtd_i;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[latitude_f]=lttd_f;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[latitude_i]=lttd_i;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[time_f]=tm_f;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[time_i]=tm_i;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[distance_p]=dstnc_p;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[speed_p]=spd_p;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_i]=cnsmptn_i;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_f]=cnsmptn_f; 
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[consumption_p]=cnsmptn_p;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_mile_p]=cns_ml_p;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_hour_p]=cns_hr_p;
            Matrix_VCO.NAV_DATA[n].LAST_NAV_DATA[cons_interpolated]=cns_ntrpltd;  

        }               
        return fclose(fp1);   
        }



/* Function print_signal: imprime un simbolo a partir de las coordenadas de un rectangulo: signal=0-> ZONA VCO,1:Sin datos; 2:Circulo; 3:flecha; 4: elipse */

void print_signal(int x1, int y1, int x2, int y2, int R, int G, int B, figura FIG, sentido S, float prfm){
    int tx1,tx2,tx3,rx1,rx2,ty1,ty2,ty3,ry1,ry2, delta_ty1,delta_ty2,delta_ty3; 
    uint16_t cex,cey,cer1,cer2;
    int delta=6;   // Redimensiono para ajstar la figura dentro del rectangulo
    x1+=delta;  
    y1+=delta;
    x2-=delta;
    y2-=delta;
    
    cex=(x1+x2)/2;
    cey=(y1+y2)/2;
    cer2= (y2-y1)/2;
    cer1= (x2-x1)/2;
    
    switch (S){
          case 1: {        // UP
            tx1=(x2+x1)/2;    //Dimensiones para flecha
            ty1=y1+4;
            tx2=x2-2;
            ty2=(y2+y1)/2;
            tx3=x1+2;
            ty3=(y2+y1)/2;
            delta_ty1=8;
            delta_ty2=-5;
            delta_ty3=-5;
            rx1=(x2+3*x1)/4;
            ry1=(y2+y1)/2;
            rx2=(3*x2+x1)/4;
            ry2=y2-4;
        }
            break;
        case 0: {         // DWN
            tx1=(x2+x1)/2;
            ty1=y2-4;
            tx2=x2-2;
            ty2=(y2+y1)/2;
            tx3=x1+3;
            ty3=(y2+y1)/2;
            delta_ty1=-8;
            delta_ty2=5;
            delta_ty3=5;
            rx1=(x2+3*x1)/4;
            ry1=y1+4;
            rx2=(3*x2+x1)/4;
            ry2=(y2+y1)/2;
        }
        break;
        default:
        break;
    }
    switch (FIG){
            case 0:  // ZONA VCO
               // lcd.roundrect( x1-8,y1-8,x2+8,y2+8, 10,8,    BrightBlue);
                //lcd.roundrect( x1-4,y1-4, x2+4,y2+4, 10,8,    RGB(153,0,153));
                //lcd.foreground(BrightBlue);  
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.fillroundrect( x1+3,y1+3, x2-3,y2-3, 5,4, RGB(R,G,B));
                lcd.SetTextCursor(x1+14,y1-10+(y2-y1)/5);
                lcd.background(RGB(R,G,B));
                lcd.foreground(White);
                lcd.printf ("NAVEGANDO");
                lcd.SetTextCursor(x1+29,y1-18+(y2-y1)/2-10);
                //lcd.SetTextCursor(132,140);
                lcd.SelectUserFont(BPG_Arial20x20);
                lcd.printf ("EN");
                lcd.SetTextCursor(x1+19,y1-18+(y2-y1)*2/3);
                //lcd.SetTextCursor(135,170);  
                lcd.printf ("ZONA");

                lcd.SetTextCursor(x1+24,y1-18+(y2-y1)*9/10);
                //lcd.SetTextCursor(135,170);  
                lcd.printf ("VCO");          
            break;
            case 1:  // SIN DATOS
                //lcd.roundrect( x1-8,y1-8,x2+8,y2+8, 10,8,    BrightBlue);
                //lcd.roundrect( x1-4,y1-4, x2+4,y2+4, 10,8,    RGB(153,0,153));
                lcd.fillroundrect( x1+3,y1+3, x2-3,y2-3, 5,4, RGB(0,0,0));   // Limpia el rectangulo
                lcd.foreground(BrightBlue);     
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.SetTextCursor(x1+18,y1+38);
                lcd.printf ("SIN DATOS");
                lcd.SetTextCursor(x1+14,y1+68);
                lcd.printf ("SUFICIENTES\r\n");                  
            break;
            case 2:   // CIRCULO
                lcd.fillroundrect( x1+3,y1+3, x2-3,y2-3, 5,4, RGB(0,0,0));  //Limpia el rectangulo
                lcd.circle( cex,cey, cer2+10, BrightBlue);
                lcd.fillcircle(cex,cey,cer2+5,RGB(R,G,B));
                
            break;
            case 3:   // FLECHA 
                //lcd.roundrect( x1-8,y1-8,x2+8,y2+8, 10,8,    BrightBlue);
                //lcd.roundrect( x1-4,y1-4, x2+4,y2+4, 10,8,    RGB(153,0,153));
                lcd.fillroundrect( x1+3,y1+3, x2-3,y2-3, 5,4, RGB(0,0,0));  //Limpia el rectangulo
                lcd.fillroundrect(rx1,ry1, rx2,ry2,  5,3,   RGB(R,G,B) );
                lcd.filltriangle( tx1,ty1, tx2,ty2, tx3,ty3, RGB(R,G,B));
                lcd.SetTextCursor(x1+(x2-x1)/2-3,y1+(y2-y1)/5);
                lcd.background(BrightGreen);
                lcd.foreground(Black);
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.printf ("A");
                lcd.SetTextCursor(x1+(x2-x1)/3,y1+(y2-y1)/2-10);
                //lcd.SetTextCursor(132,140);
                lcd.printf ("ZONA");
                lcd.SetTextCursor(x1+(x2-x1)/3+2,y1+(y2-y1)*2/3);
                //lcd.SetTextCursor(135,170);
                lcd.printf ("VCO");  
            break;
            case 4:   // ELIPSE
                lcd.fillroundrect( x1+3,y1+3, x2-3,y2-3, 5,4, RGB(0,0,0));  //Limpia el rectangulo
                lcd.ellipse( cex,cey,cer1,cer2, BrightBlue);
                lcd.fillellipse( cex,cey, cer1-5,cer2-5, RGB(R,G,B));
            break;    
            case 5:   // RELOJ
                if (S==UP)reloj(cex,cey,S,prfm-1,2);
                else reloj(cex,cey,S,1-prfm,2);  // coord x, coord y, sentido, valor, fondo de escala;
            break;    
            default:  
                reloj(cex,cey,S,prfm-1,2);     
            break;    
  
        }                   
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FUNCION print_fondo1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

void print_fondo1(uint8_t r, uint8_t g,uint8_t b,uint8_t r1, uint8_t g1,uint8_t b1){
        int y_offset=250;               //Para que imprima de abajo hacia arriba.
        int x_offset=30;                //Posicionamiento en x
      
        lcd.background(RGB(0,0,0));
        lcd.foreground(RGB(r1,g1,b1));
        lcd.SelectUserFont(BPG_Arial20x20);
        lcd.SetTextCursor(0,0);         // Pongo cursor en posicion
        lcd.cls();
        lcd.roundrect( 2,2,475,270,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de graficos
        lcd.fillroundrect(7,7,470,264,5,3,  RGB(r,g,b));
        lcd.foreground(RGB(r1,g1,b1));   
        lcd.background(RGB(r,g,b));          // Para escribir sobre este fondo
         
}       

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> fin FUNCION print_fondo1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FUNCION print_fondo2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

void print_fondo2(uint8_t r, uint8_t g,uint8_t b,uint8_t r1, uint8_t g1,uint8_t b1){
    /*   Declaradas 
    int sepx= 105;    // Separacion x entre recuadros  
    int sepy= 66;     // Separacion x entre recuadros 
    int sizex1=100;   // Tamaño cuadro para valores
    int sizey1=40;   
    int xr1=10;       // Posicion de recuadros para exhibir datos
    int yr1=10;
    int xr2=xr1+sepx;
    int yr2=yr1;
    int xr3=xr1;
    int yr3=yr1+sepy;
    int xr4=xr1;
    int yr4=yr3+sepy; 
    int xr5=xr1;
    int yr5=yr4+sepy;
    int xr6=xr1;
    int yr6=yr5+sepy; 
    */      
        lcd.background(RGB(0,0,0));
        lcd.foreground(RGB(r1,g1,b1));
        lcd.SelectUserFont(BPG_Arial20x20);
        lcd.SetTextCursor(0,0);         // Pongo cursor en posicion
      
        lcd.roundrect( xr1,yr1,xr1+sizex1,yr1+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr1+3,yr1+4,xr1+95,yr1+sizey1,8,5, Black); //RGB(r,g,b));   // Rectangulo interior lleno
        lcd.roundrect(xr1+3,yr1+4,xr1+95,yr1+sizey1,8,5,  RGB(r,g,b));         // Vacio
        lcd.roundrect( xr2,yr2,xr2+sizex1,yr2+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr2+4,yr2+4,xr2+95,yr2+sizey1,8,5,  Black); //RGB(r,g,b));
        lcd.roundrect(xr2+4,yr2+4,xr2+95,yr2+sizey1,8,5,  RGB(r,g,b));
        lcd.roundrect( xr3,yr3,xr3+sizex1,yr3+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr3+4,yr3+4,xr3+95,yr3+sizey1,8,5, Black);  //RGB(r,g,b));
        lcd.roundrect(xr3+4,yr3+4,xr3+95,yr3+sizey1,8,5,  RGB(r,g,b));        
        lcd.roundrect( xr4,yr4,xr4+sizex1,yr4+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr4+4,yr4+4,xr4+95,yr4+sizey1,8,5, Black);  //RGB(r,g,b));
        lcd.roundrect(xr4+4,yr4+4,xr4+95,yr4+sizey1,8,5,  RGB(r,g,b));
        lcd.roundrect( xr5,yr5,xr5+sizex1,yr5+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr5+4,yr5+4,xr5+95,yr5+sizey1,8,5, Black);  //RGB(r,g,b));
        lcd.roundrect(xr5+4,yr5+4,xr5+95,yr5+sizey1,8,5,  RGB(r,g,b));        
        lcd.roundrect( xr6,yr6,xr6+sizex1,yr6+sepy-8,10,8, RGB(r1,g1,b1));     // Rectangulo para encuadre de valores
        //lcd.fillroundrect(xr6+4,yr6+4,xr6+95,yr6+sizey1,8,5, Black);  //RGB(r,g,b));
        lcd.roundrect(xr6+4,yr6+4,xr6+95,yr6+sizey1,8,5,  RGB(r,g,b));   
                     
        lcd.roundrect( signal_x, signal_y, signal_x + signal_x_sz,signal_y + signal_y_sz+3, 10,8,    BrightBlue);      //Rectangulo para encuadre de grafico de señalizacion (Flecha)
        //lcd.roundrect( signal_x+4, signal_y-4, signal_x+signal_x_sz+4,signal_y + signal_y_sz+4, 10,8,    RGB(153,0,153));
        
        lcd.foreground(RGB(r1,g1,b1));   
        //lcd.background(RGB(r,g,b));          // Si se usa lleno, para escribir sobre este fondo
        lcd.background(Black);            // Para rectangulo vacio
}       

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FIN FUNCION print_fondo2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCION print_values <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


void print_values(int vel, int vco, int vmc, double cons_m, double cons_h, float lcount){
                
                int offset_x=30, offset_y=8; // Para ubicar los valores dentro de los recuadros del fondo2.         
                print_fondo2(255,255,255,0,0,255); // ya deja el background correcto
                //lcd.background(Black);    //  
                int foregndcolor=RGB(0,255,0);
                int despx=7,despy=7;
                lcd.SelectUserFont(BPG_Arial31x32);
                lcd.SetTextCursor(xr1+offset_x,yr1+offset_y); 
                lcd.fillroundrect(xr1+despx,yr1+despy,xr1+sizex1-despx,yr1+sizey1-3,8,5,Black); 
                lcd.foreground(foregndcolor);
                lcd.printf("%2d ",vel);
                lcd.SetTextCursor(xr2+ offset_x,yr2+offset_y);
                lcd.fillroundrect(xr2+despx,yr2+despy,xr2+sizex1-despx,yr2+sizey1-3,8,5,  Black);
                lcd.foreground(foregndcolor);
                lcd.printf("%2d",vco);
                lcd.SetTextCursor(xr3+offset_x,yr3+offset_y);
                lcd.fillroundrect(xr3+despx,yr3+despy,xr3+sizex1-despx,yr3+sizey1-3,8,5, Black);
                lcd.foreground(foregndcolor);
                lcd.printf("%2d", vmc);                
                lcd.SetTextCursor(xr4+offset_x-10,yr4+offset_y);
                lcd.fillroundrect(xr4+despx,yr4+despy,xr4+sizex1-despx,yr4+sizey1-3,8,5, Black);
                lcd.foreground(foregndcolor);
                lcd.printf("%.2lf", cons_m);
                lcd.SetTextCursor(xr5+offset_x-10,yr5+offset_y);
                lcd.fillroundrect(xr5+despx,yr5+despy,xr5+sizex1-despx,yr5+sizey1-3,8,5, Black);
                lcd.foreground(foregndcolor);
                lcd.printf("%.2lf", cons_h); 
                lcd.SetTextCursor(xr6+offset_x-10,yr6+offset_y);
                lcd.fillroundrect(xr6+despx,yr6+despy,xr6+sizex1-despx,yr6+sizey1-3,8,5, Black);
                lcd.foreground(foregndcolor);
                if (lcount<100)lcd.printf("%.2lf", lcount);
                else lcd.printf("%.1lf", lcount);
                
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.background(Black);
                lcd.foreground(RGB(0,255,0));
                lcd.SetTextCursor(xr1+offset_x-12,yr1+sepy-28+offset_y);
                lcd.printf("VEL.GPS(kt)");
                lcd.SetTextCursor(xr2+offset_x-5,yr2+sepy-28+offset_y);
                lcd.printf("VCO (kt)"); 
                lcd.SetTextCursor(xr3+offset_x-5,yr3+sepy-28+offset_y);
                lcd.printf("VMC (kt)");  
                lcd.SetTextCursor(xr4+offset_x-7,yr4+sepy-28+offset_y);
                lcd.printf("Cons.(L/M)");
                lcd.SetTextCursor(xr5+offset_x-5,yr5+sepy-28+offset_y);
                lcd.printf("Cons(L/H)");
                lcd.SetTextCursor(xr6+offset_x-15,yr6+sepy-28+offset_y);
                lcd.printf("Cons.Ac(L/M)");                                
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FIN FUNCION print_values <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCION bienvenida <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
void bienvenida(){
        // Prueba de gauge

   
    print_fondo1(0,0,0,0,0,255);
    lcd.SelectUserFont(BPG_Arial63x63);
    lcd.SetTextCursor(135,34);
    lcd.foreground(RGB(0,255,0));    
    lcd.puts("SNOCC");
    lcd.SelectUserFont(BPG_Arial31x32);
    lcd.SetTextCursor(20,130);
    lcd.foreground(RGB(0,255,0)); 
    lcd.puts("S");
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("istema\t");
    lcd.foreground(RGB(0,255,0));     
    lcd.puts(" N");
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("autico de ");
    lcd.foreground(RGB(0,255,0)); 
    lcd.puts(" O");
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("ptimizacion ");    
    lcd.SetTextCursor(40,200);
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("de ");
    lcd.foreground(RGB(0,255,0));
    lcd.puts("C");
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("onsumo ");
    lcd.puts("de ");
    lcd.foreground(RGB(0,255,0));
    lcd.puts("C");
    lcd.foreground(RGB(255,255,0)); 
    lcd.puts("ombustible");
    wait(5);
    lcd.cls();
    print_fondo1(0,225,0,0,255,0);
    lcd.SelectUserFont(BPG_Arial63x63);
    lcd.background(RGB(0,220,0));
    lcd.foreground(RGB(220,255,0));
    lcd.SetTextCursor(95,20);
    lcd.puts("Bienvenido");
    lcd.SetTextCursor(220,100);
    lcd.puts("a");
    lcd.SetTextCursor(160,190);
    lcd.puts("Bordo");
    
    
    wait(5);
    lcd.cls();
    print_fondo1(0,0,0,0,0,255);        
    print_fondo2(255,255,255,0,0,255);
    reloj(345,135,UP,-1,2);  
    wait(1);
    reloj(345,132,UP,1,2); 
    wait(1); 
    reloj(345,132,UP,0,2); 
    wait(3);
    lcd.cls();
    print_fondo1(0,0,0,0,0,255);
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FIN FUNCION bienvenida <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCION despedida <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
void despedida(){

        
    lcd.cls();
    print_fondo1(0,225,0,0,255,0);
    lcd.SelectUserFont(BPG_Arial63x63);
    lcd.background(RGB(0,225,0));
    lcd.foreground(RGB(220,255,0));
    lcd.SetTextCursor(170,20);
    lcd.puts("Hasta");
    lcd.SetTextCursor(100,100);
    lcd.puts(" el proximo");
    lcd.SetTextCursor(170,180);
    lcd.puts("viaje...");
    wait(2);
    lcd.background(RGB(0,100,0));
    lcd.cls();
    lcd.SetTextCursor(112,100);
    lcd.puts("SNOCC");
    wait(2);
    
    for (int i=0; i<273;i++){
        lcd.foreground(RGB(0,225,0));
        lcd.line(0,i,480,i);
        wait_ms(15);
        lcd.foreground(RGB(200,200,255));
        lcd.line(0,i+2,480,i+2);
        lcd.foreground(RGB(0,0,200));
        lcd.line(0,i,480,i);
        wait_ms(15);
        lcd.foreground(RGB(0,0,200));
        lcd.line(0,i+2,480,i+2);
    }
    lcd.background(RGB(0,0,0));
    lcd.cls();
    while(1);
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FIN FUNCION despedida <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<     
    
    
    
    


//###################################################  MAIN  ###################################################
    
int main()
{   int VCC[2];     // Array de valores crucero críticos. VCC[0]=VCO; VCC[1]=VMC (Velocidad de Máximo Consumo)
    VCC[0]=-1;
    VCC[1]=-1;
    bool menu_flag1=0;  // Flags para touch 
    bool menu_flag2=1;
    bool menu_flag3=0;  // 1--> Apagar
    int R,G,B=0;
    int R1,G1,B1=0;
    int err_Mtrx=0;  
    float PRFM=-1;    // Performance
    sentido SENTIDO;  // Sentido de la flecha
    figura FIG;  
    loc_t butt_x1=450;    // Posicion  boton1 
    loc_t butt_y1=240;    
    loc_t butt_x2=405;    // Posicion  boton2
    loc_t butt_y2=40;
    loc_t butt_x3=450;    // Posicion  boton3
    loc_t butt_y3=12;
    rect_t PrintScreenRectB1 = { butt_x1-20, butt_y1, butt_x1+20, butt_y1+25};        // Rectangulo para encuadrar boton 1.
    rect_t PrintScreenFillRectB1 = { butt_x1-18, butt_y1+2, butt_x1+18, butt_y1+23 }; // Rectangulo relleno para encuadrar boton 1
    rect_t PrintScreenRectB2 = { butt_x2-25, butt_y2, butt_x2+25, butt_y2+25};        // Rectangulo para encuadrar boton 2.
    rect_t PrintScreenFillRectB2 = { butt_x2-23, butt_y2+2, butt_x2+24, butt_y2+23 }; // Rectangulo relleno para encuadrar boton 2
    rect_t PrintScreenRectB3 = { butt_x3-18, butt_y3, butt_x3+18, butt_y3+25};        // Rectangulo para encuadrar boton 3.
    rect_t PrintScreenFillRectB3 = { butt_x3-16, butt_y3+2, butt_x3+16, butt_y3+23 }; // Rectangulo relleno para encuadrar boton 3.
    pc.baud(460800);                                           
    lcd.init();
    lcd.TouchPanelCalibrate();   // Esta funcion fue modificada para fijar calibracion.
    lcd.cls();
    lcd.foreground(RGB(255,255,0));                         // Seteo del color de las letras.
    lcd.SelectUserFont(BPG_Arial20x20);                     // Seleccion de tipo y tamaño de letras
    GPS gps(p9, p10);                                       // Agrego para comunicacion con el GPS
    

//-------------------------------------------------------------------------------------------------------------         
//  Sensor de flujo:       
    InterruptIn pulse_sensor(p15);          // Defino pulse_sensor como una entrada de interrupción en p15 .
    pulse_sensor.mode(PullUp);              // PullUp para esa entrada.
    //pulse_sensor.rise(&trigger);          // Dispara interrupción con flanco ascendente. (Podría tambien ser desecendente--> fall)
    pulse_sensor.fall(&trigger); 
//--------------------------------------------------------------------------------------------------------------           
 
    lcd.SetTextCursor(0,0);                 // Posicionamiento de cursor.
    lcd.puts(">>>>>>>>>>>>>< Proyecto SNOCC ><<<<<<<<<<<<<<\r\n");   
    if (!sd2mtrx(NAVIGATION_VMATRIX, sd_file)) lcd.puts("Datos leidos de SD card\r\n");       // Cargando matriz desde SD.
    else{
        lcd.puts("Error al leer los datos.\r\n Inicio sin datos historicos.\r\n");
        if (TESTING){
            err_Mtrx=build_default_Mtrx(NAVIGATION_VMATRIX,TestNAV,0,0);
            if(err_Mtrx!=0) lcd.printf("Error al crear la Matriz default.%d\r\n",err_Mtrx);   // Creando matriz de inicio default.
            else lcd.printf("Matriz default creada con exito.\r\n");
        }
        if (!mtrx2sd(NAVIGATION_VMATRIX, sd_file)) lcd.printf("Datos default guardados en SD card\r\n");
        else {
            lcd.puts("Error al guardar los datos default.\r\nCreando directorio en SD card...\r\n");
            if(!mkdir(sd_dir, 0777)){                                                         // Creando directorio si no existe.
                lcd.printf("Creado:  %s\r\n", sd_dir);
                lcd.printf("Cargando datos de inicio default en SD card...\r\n");
                if (!mtrx2sd(NAVIGATION_VMATRIX, sd_file)) lcd.printf("Datos default guardados en SD card\r\n");
                else lcd.puts("Error al guardar los datos default.\r\nNo se podran almacenar los datos.\r\n");
            }
            else lcd.puts("Error al guardar los datos default.\r\nNo se podran almacenar los datos.\r\n");
        }
    }  
      
    bienvenida();    // Bienvenida 
    
    float delta=5.0;//DEBUG
    float virtual_tmstmp=0.0;//DEBUG 
    int   prueba=0;  // Variable indice para simulacion.
       
///////////////////////////////////////////////// LOOP INFINITO  ////////////////////////////////////////////////////
    while(1) {
            
        lcd.SetTextCursor(0,0);             // Pongo cursor en posicion
       
        if (DEBUG_GPS)lcd.printf("M0: %s \r\n\r\n", gps.msg);  //Imprimo el mensaje crudo proveniente de la uart
        
        if(!menu_flag1){ //Boton 1 no presionado
            
            if(gps.sample()) {                                      // Si es exitosa la obtencion de datos del gps.                        
                lcd.foreground(RGB(0,255,0));                       // Seteo del color de las letras.
                lcd.SelectUserFont(BPG_Arial20x20);                 // Seleccion de tipo y tamaño de letras
                lcd.SetTextCursor(0,0);                             // Cursor en posicion
              
               if (!NAVIGATION_OBJECT.rotate_data(gps.longitude, gps.latitude, gps.time, Counter,NAVIGATION_VMATRIX.vel_max )){
                    NAVIGATION_OBJECT.LAST_NAV_DATA[cons_interpolated]=0; // Dato tipo recolectado
                    err_Store=NAVIGATION_VMATRIX.store_data(NAVIGATION_OBJECT,3); // Luego de rotar los datos en la tabla de navegacion, 
                                                                        // la guarda en la matriz segun criterios de la clase VCODATA
                                                                        // Deben registrarse 3 periodos de velocidad quasi constante para
                                                                        // que se almacene definitivamente el dato consolidado de los mismos.
                        
                    int i=int(NAVIGATION_OBJECT.LAST_NAV_DATA[speed_p]);   
                    NAVIGATION_V_SMOOTH_MTRX.smooth(4, NAVIGATION_VMATRIX); // Genera matriz de datos filtrados con pasabajos
                    int VCO=NAVIGATION_V_SMOOTH_MTRX.get_VCO(&VCC[0]);      // VCO OBTENIDA DE MATRIZ FILTRADA.
                
                    print_values(NAVIGATION_OBJECT.LAST_NAV_DATA[speed_p], VCC[0],VCC[1], NAVIGATION_OBJECT.LAST_NAV_DATA[cons_mile_p], NAVIGATION_OBJECT.LAST_NAV_DATA[cons_hour_p], LCounter);       
         
                    if (DEBUG1) {    
                    lcd.SetTextCursor(0,60);
                    lcd.puts("Rotacion exitosa!-->");   
                    lcd.printf("Error de rotacion:\t %d\r\n",err_Store);                                            // DEBUG
                    lcd.printf("Speed_f_Mtrx(%d):\t     %lf kn.\r\n",i, NAVIGATION_VMATRIX.NAV_DATA[i].LAST_NAV_DATA[speed_p]);                              // DEBUG
                    lcd.printf("Speed_f_Last(%d):\t\t     %lf km/h.\r\n",i, NAVIGATION_OBJECT.LAST_NAV_DATA[speed_p]*1.852);                    // DEBUG
                    lcd.printf("Time_f_Mtrx(%d):\t      %lf Hours.\r\n",i, NAVIGATION_VMATRIX.NAV_DATA[i].LAST_NAV_DATA[time_f]);                        // DEBUG
                    lcd.printf("Time_f_Last(%d):\t      %lf Hours.\r\n",i, NAVIGATION_OBJECT.LAST_NAV_DATA[time_f]);                        // DEBUG
                    lcd.printf("Dist_p_Mtrx(%d):\t      %lf miles.\r\n",i,NAVIGATION_VMATRIX.NAV_DATA[i].LAST_NAV_DATA[distance_p]);                         // DEBUG
                    }             
                    NAVIGATION_VMATRIX.interpolate();                                                              // Interpolacion.
                    if (!mtrx2sd(NAVIGATION_VMATRIX, sd_file)) lcd.printf("Datos guardados en SD card\r\n");       // Almacenamiento de datos en SD.
                    else lcd.printf("Error al guardar los datos.\r\n");
                    
//______    _______________________________________________________________________________________________________________
                    /*int signal_x=100;   // REGION DE SEÑALIZACION
                    int signal_y=75;
                    int signal_x_sz=110;
                    int signal_y_sz=120;*/
                    
                    //PRFM=NAVIGATION_VMATRIX.performance(i);
                    PRFM=NAVIGATION_V_SMOOTH_MTRX.performance(i); // PERFORMANCE OBTENIDA DE MATRIZ FILTRADA.
                    
                    R1=0;       // COLOR DEFAULT PARA CIRCULO DE REFERENCIA DE PERFORMANCE (,PRFM)
                    G1=255;
                    B1=0;
                    lcd.foreground(RGB(R1,G1,B1));
                    /*lcd.SetTextCursor(0,245);
                    lcd.printf("VCO: %d \t\t",VCC[0]);
                    lcd.printf("VMC: %d \r\n",VCC[1]);
                    */
                    if (PRFM!=-1 && VCC[0]!=-1){
                        if (PRFM>0.98) {
                            R=0;
                            G=255;
                            B=0;
                        }    
                        else {
                            if (PRFM<0.75){
                                R=255;
                                G=255*4*PRFM/3;
                                B=0;
                            }    
                            else {
                                R=255*4*(1-PRFM);
                                G=255;
                                B=0;
                            }    
                        } 
                        float delta_vel= NAVIGATION_VMATRIX.NAV_DATA[i].LAST_NAV_DATA[speed_p]-VCC[0];    // ES IGUAL QUE EN MTRX FILTRADA               
                        if (fabs(delta_vel)<2){
                            FIG=ZONA;  
                        }    
                        else FIG=FLECHA;
                        
                        if (delta_vel<0) SENTIDO=UP;
                        else SENTIDO=DWN;
                    
                        
                    print_signal(signal_x, signal_y, signal_x + signal_x_sz,signal_y + signal_y_sz, 0, 255, 0,FIG,SENTIDO,PRFM);  //  SI ESTA EN ENTORNO DE VCO-->  IMPRIMIR "ZONA VCO". 
                    
                    }
                    else {

                        print_signal(signal_x, signal_y, signal_x + signal_x_sz,signal_y + signal_y_sz,R,G,B,SIN_DT,NO,PRFM);   // SIN DATOS: SOLO RECUADRO PARA TEXTO
        
                    } 

// =================================== ZONA PERFORMANCE  ===================================================================

                if (PRFM >= 0) print_signal(305, 85,385,175, R, G, B,GAUGE,SENTIDO,PRFM);
                else print_signal(305, 85, 385,175, R, G, B,GAUGE,UP, 2.35);
                
                lcd.background(Black);
                lcd.foreground(RGB(0,255,0));

// =================================== FIN ZONA PERFORMANCE  ===================================================================
                
//############################## MODULO DE PERIODO NO VALIDADO #########################################################################                
                }
                else {lcd.puts("Periodo no valido!\r\n");
                wait(1);
                print_fondo1(0,0,0,0,0,255);        
                print_fondo2(255,255,255,0,0,255);
                }
            
            } 
            else {    // No hay datos gps

                lcd.foreground(RGB(0,255,0));             // Seteo del color de las letras.
                lcd.SelectUserFont(BPG_Arial20x20);         // Seleccion de tipo y tamaño de letras
                lcd.SetTextCursor(10,10);    
                if (DEBUG1){
                    if (!mtrx2sd(NAVIGATION_VMATRIX, sd_file)) lcd.printf("Datos default guardados en SD card\r\n");     //DEBUG
                    else lcd.printf("Error al guardar los datos default.\r\n");                                                  //DEBUG
                    lcd.printf("Aun no hay datos gps disponibles. Usando historicos.\r\n");
                }
                
                NAVIGATION_V_SMOOTH_MTRX.smooth(4, NAVIGATION_VMATRIX); // Genera matriz de datos filtrados con pasabajos
                int VCO=NAVIGATION_V_SMOOTH_MTRX.get_VCO(&VCC[0]);      // VCO OBTENIDA DE MATRIZ FILTRADA.
                
                if(!SIMULATION) print_values(-1, VCC[0],VCC[1],-1, NAVIGATION_OBJECT.LAST_NAV_DATA[cons_hour_p], LCounter);       

    
                
//_____________________________________________________________________________________________________________________
               // REGION DE SEÑALIZACION
         
                if (prueba >= NAVIGATION_VMATRIX.vel_max) prueba=prueba-NAVIGATION_VMATRIX.vel_max;
                PRFM=NAVIGATION_V_SMOOTH_MTRX.performance(prueba); // PERFORMANCE OBTENIDA DE MATRIZ FILTRADA.

                float delta_vel= NAVIGATION_VMATRIX.NAV_DATA[prueba].LAST_NAV_DATA[speed_p]-VCC[0];  // Diferencia de velocidad respecto de la vco
                if (PRFM!=-1 && VCC[0]!=-1){
                    if (fabs(delta_vel)<2) FIG=ZONA;    
                    else FIG=FLECHA;
                    if (delta_vel<0) SENTIDO=UP;
                    else SENTIDO=DWN;
                        
                    print_signal(signal_x, signal_y, signal_x + signal_x_sz,signal_y + signal_y_sz, 0, 255, 0,FIG,SENTIDO,PRFM);  //  SI ESTA EN ENTORNO DE VCO-->  IMPRIMIR "ZONA VCO". 
                }
                else {
                    print_signal(signal_x, signal_y, signal_x + signal_x_sz,signal_y + signal_y_sz,R,G,B,SIN_DT,NO,PRFM);     // SIN DATOS SUFICIENTES
    
                } 
// =================================== ZONA PERFORMANCE  ===================================================================
 
                if (PRFM >= 0) print_signal(305, 85,385,175, R, G, B,GAUGE,SENTIDO,PRFM);
                else print_signal(305, 85, 385,175, R, G, B,GAUGE,UP, 2.35);        

                print_values(NAVIGATION_VMATRIX.NAV_DATA[prueba].LAST_NAV_DATA[speed_p], VCC[0],VCC[1], NAVIGATION_VMATRIX.NAV_DATA[prueba].LAST_NAV_DATA[cons_mile_p], NAVIGATION_VMATRIX.NAV_DATA[prueba].LAST_NAV_DATA[cons_hour_p], LCounter);       
                
                lcd.background(Black);
                lcd.foreground(RGB(0,255,0));
                lcd.SetTextCursor(223,12);
                lcd.SelectUserFont(BPG_Arial10x10);
                //lcd.printf("Speedsim[%d]: %.1f \r\n",prueba,NAVIGATION_VMATRIX.NAV_DATA[prueba].LAST_NAV_DATA[speed_p]);
                lcd.printf("SIMULACION");
                wait_ms(600);
                lcd.foreground(RGB(255,0,0));
                lcd.SetTextCursor(223,12);
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.printf("SIMULACION");
                prueba++;
// ====================================== FIN ZONA PERFORMANCE  ===============================================================
    
//%%%%%%%%%%%%%%%%% ESTA PARTE ES PARA VALIDAR EL FUNCIONAMIENTO DE LA ROTACION Y ALMACENAMIENTO DE DATOS %%%%%%%%%%%%%%%%%%%%%
 
        if (TESTING){      //DEBUG                
                float vrtl_speed=12;   // pruebo cargar datos para velocidad 12.
                TestNAV.LAST_NAV_DATA[cons_interpolated]=0;        // --> -1:Datos iniciales. 0--> recolectado (setear para testing)
                err_Mtrx=build_default_Mtrx(NAVIGATION_VMATRIX, TestNAV, vrtl_speed, virtual_tmstmp);
                    if(err_Mtrx!=0){
                        lcd.printf("Error al cargar datos en la Matriz default.%d..\r\n", err_Mtrx); // DEBUG; ya se crea la matriz en el arranque, si no hay archivo.
                    }
                    else lcd.printf("Datos para virtual_speed= %.1f cargado con exito.\r\n",vrtl_speed);            
                lcd.printf("Virtual_Timestamp=%.2f.\t",virtual_tmstmp);//DEBUG
                virtual_tmstmp+=delta; // DEBUG  Esta en formato NMEA(hhmmss.ss): no son validos los valores de segundos mayores a 59, por lo tanto
                                                    // cuando se ingrese 100,00 despues de 95,00 se espera que el sistema no valide la ronda pues en ese
                                                    // formato 100,00 < 95,00  (1m < 95s); seria un valor entrante menor que el anterior.
                
                lcd.printf("V_time(h):%lf\r\n",TestNAV.time_NMEA2hours(virtual_tmstmp));
                }
//%%%%%%%%%%%%% FIN   DE LA PARTE PARA PROBAR EL FUNCIONAMIENTO DE LA ROTACION Y ALMACENAMIENTO DE DATOS......DEBUG.%%%%%%%%%%%%%%%%%%%%%
                
//%%%%%%%%%%%%% DEBUG2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                
            if (DEBUG2){
                int buff_indx=int(NAVIGATION_VMATRIX.NAV_DATA[NAVIGATION_VMATRIX.vel_max].LAST_NAV_DATA[speed_p]+0.5); // DEBUG
                lcd.printf("Cons_m_p[%d]=  %.3f l/ml\t",buff_indx, NAVIGATION_VMATRIX.NAV_DATA[buff_indx].LAST_NAV_DATA[cons_mile_p]); 
                lcd.printf("Dist_p[%d]=  %lf ml\r\n",buff_indx, NAVIGATION_VMATRIX.NAV_DATA[buff_indx].LAST_NAV_DATA[distance_p]);
                lcd.printf("Tiempo_f[%d]=  %lf h\t",buff_indx, NAVIGATION_VMATRIX.NAV_DATA[buff_indx].LAST_NAV_DATA[time_f]);
                lcd.printf("Tiempo_i[%d]=  %lf h\r\n",buff_indx, NAVIGATION_VMATRIX.NAV_DATA[buff_indx].LAST_NAV_DATA[time_i]);
                lcd.printf("Buff_INDX =  %d \t", buff_indx);
                lcd.printf("Speed_p[%d]=  %.2f knots\r\n",buff_indx, NAVIGATION_VMATRIX.NAV_DATA[buff_indx].LAST_NAV_DATA[speed_p]);
                lcd.printf("Per_con[vel_max]=  %d \t", NAVIGATION_VMATRIX.NAV_DATA[NAVIGATION_VMATRIX.vel_max].np_concat);
                lcd.printf("V_buff[%d]=  %.2f\t", NAVIGATION_VMATRIX.vel_max,NAVIGATION_VMATRIX.NAV_DATA[NAVIGATION_VMATRIX.vel_max].LAST_NAV_DATA[speed_p]);
                lcd.printf("TestNAV-time_f =  %lf \t", TestNAV.LAST_NAV_DATA[time_f]);
                lcd.printf("TestNAV-time_i =  %lf \r\n", TestNAV.LAST_NAV_DATA[time_i]);
                lcd.printf("TestNAV-max_per_t =  %lf \t", TestNAV.max_period_time);
                lcd.printf("TestNAV-time_p =  %lf \r\n", TestNAV.LAST_NAV_DATA[time_f]-TestNAV.LAST_NAV_DATA[time_i]);
                lcd.printf("TestNAV-cons_m_p =  %lf \t", TestNAV.LAST_NAV_DATA[cons_mile_p]);
                lcd.printf("TestNAV-cons_h_p =  %lf \r\n", TestNAV.LAST_NAV_DATA[cons_hour_p]);
                //lcd.SelectUserFont(BPG_Arial20x20);         // Seleccion de tipo y tamaño de letras
                }
//%%%%%%%%%%%%%  FIN DEBUG2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
    }               
                
//===========================TOUCH & ACTIONS ===================================================================================================                
                lcd.fillroundrect(PrintScreenFillRectB1,5,2, RGB(50,100,0));
                lcd.roundrect(PrintScreenRectB1, 8,3, RGB(0,0,255));
                lcd.fillroundrect(PrintScreenFillRectB3,10,10, RGB(100,0,0));
                lcd.roundrect(PrintScreenRectB3, 12,12, RGB(255,0,0));
                lcd.foreground(RGB(0,0,255));
                lcd.background(RGB(50,100,0));
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.puts(butt_x1-18, butt_y1+4, "CURVA");
                lcd.SelectUserFont(BPG_Arial10x10);
                lcd.foreground(RGB(255,0,0));
                lcd.background(RGB(100,0,0));
                lcd.puts(butt_x3-10, butt_y3+10, "OFF");
                lcd.background(Black);
                            
                for (int i=0;i<2000;i++) {                 // Barrido para el touch
                    point_t p;
                    if (lcd.TouchPanelReadable(&p)) {
                        menu_flag1=Intersect(PrintScreenRectB1, p);   // Levanta menu_flag1
                        menu_flag3=Intersect(PrintScreenRectB3, p);   // Levanta menu_flag3
                        if (menu_flag1){    
                            lcd.foreground(RGB(255,0,0));
                            lcd.background(RGB(50,255,0));
                            lcd.puts(butt_x1-18, butt_y1+4, "CURVA");              // Indica boton presionado
                            i=2000;
                            menu_flag2=0; 
                            }                              // Baja menu_flag2
                        else {
                            if (menu_flag3) despedida(); 
                            }
                    }
                wait_ms(2);
                }
                lcd.background(Black);
            }                                   // Fin if menu_flag1
            
            else {                              // Boton 1 presionado                 
                
                    if(!menu_flag2) {           //  Boton 2 no presionado
                    
                        //if(build_default_Mtrx(NAVIGATION_VMATRIX)==-1) lcd.printf("Error al crear la Matriz default...\r\n");     // DEBUG Curve
                        NAVIGATION_V_SMOOTH_MTRX.smooth(4, NAVIGATION_VMATRIX); // Genera matriz de datos filtrados con pasabajos

                        print_VCO_curve(NAVIGATION_VMATRIX,0);                  // Valores recolectados
                        
                        wait(2);
                        print_VCO_curve(NAVIGATION_VMATRIX,1);                  // Interpolados (puntos)
                        wait(2);
                        print_VCO_curve(NAVIGATION_V_SMOOTH_MTRX,1);            // Suavizado (puntos)
                        wait(2);
                
                        print_VCO_curve(NAVIGATION_VMATRIX,2);                  // Interpolados (lineas)
                        wait(2);
                        print_VCO_curve(NAVIGATION_V_SMOOTH_MTRX,2);            // Suavizados (lineas)
                        
                        
                        lcd.SelectUserFont(BPG_Arial10x10);
                        lcd.fillroundrect(PrintScreenFillRectB2,5,2, BrightBlue);
                        lcd.roundrect(PrintScreenRectB2, 8,5, White);
                        lcd.foreground(RGB(0,255,0));
                        lcd.background(BrightBlue);
                        for (int j=0;j<2000;j++) {                              // Barrido para el touch
                            point_t p2;

                            lcd.puts(butt_x2-21, butt_y2 +4, "VOLVER");
                            //lcd.background(Black);
                            if (lcd.TouchPanelReadable(&p2)) {
                                menu_flag2=Intersect(PrintScreenRectB2, p2);
                                if (menu_flag2) {
                                    lcd.foreground(Red);
                                    lcd.puts(butt_x2-40, butt_y2 +4, "VOLVER");
                                    menu_flag1=0;                               // Bajo menu_flag1;
                                    j=2000;
                                    print_fondo1(0,0,0,0,0,255);              //Imprimo fondo de pantalla ppal.
                                    print_fondo2(50,50,255,0,0,255);
                                }
                            }
                        }     
    
                    }                                                           // Fin if boton2 no presionado
                
                }                                                               // Fin else (boton 1 presionado)
                
                lcd.foreground(RGB(0,255,0));
            }  //Fin while 1  

    }