Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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,<td_f,<td_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
}