TRABAJO PRACTICO - EJERCICIO 3 - TERMINADO

Dependencies:   mbed tsi_sensor

Revision:
1:ad8aebd0e5c7
Parent:
0:ec6eb1da0a1c
--- a/main.cpp	Wed May 29 22:19:14 2019 +0000
+++ b/main.cpp	Mon Jun 10 18:01:52 2019 +0000
@@ -4,84 +4,387 @@
 #define ELEC0 9
 #define ELEC1 10
 
+// Funcion enum que utilizo para usar palabras como valores (para mas claridad en el codigo)
+enum { HABILITADO,
+       CABLE1,
+       CABLE2,
+       CABLE3,
+       CABLE4,
+       DISPONIBLE,
+       USADO,
+       DESHABILITADO,
+       CORRECTO,
+       VICTORIA,
+       DERROTA
+     };
+
+// Funciones enum que indican el estado de las maquinas de estados
+enum { ESPERO_INICIO,
+       CAMBIO_DISPLAY,
+       RESTO_DISPLAY
+     };
+enum { PAUSA,
+       ESPERO_CABLE,
+       COMPARO
+     };
 enum { NADA,
        PULSADO
      };
+enum { ESPERO,
+       PRENDO,
+       APAGO
+     };
+
 
 TSIAnalogSlider tsi(ELEC0, ELEC1, 40);
 
 // Prototipos de funciones de maquinas de estados
+void MAQ_cuentareg();   //Prototipo funcion de la cuenta regresiva
 
-void MAQ_lecturaTSI();
+void MAQ_bomba();   // Prototipo funcion general del juego
 
-void LEER_TSI();    //Prototipo funcion de lectura del TSI
+void MAQ_parpadeo();    //Prototipo funcion para parpadear display y led
+
+void MAQ_lecturaTSI();  //Prototipo funcion para solo leer 1 vez que se presiona el TSI
+void LEER_TSI();    //Prototipo funcion para guardar el valor analogico del TSI en todo momento
 void pulsacion_TSI();   //Prototipo funcion para leer 1 solo valor del TSI cada 2.5mseg
 
+void segundos();    //Funcion para realizar cambiar el display cada 1 segundo
+
+void parpadeo1();
+void parpadeo2();
 
 void genero_secuencia(); // Funcion que utilizo para generar la secuencia aleatoria.
 
 //Variables que indican el estado de las maquinas (empiezo en estado de reset)
 
 int estado_maq_tsi = NADA;
+int estado_maq_display = ESPERO_INICIO;
+int estado_maq_bomba = PAUSA;
+int estado_maq_parpadeo = ESPERO;
 
 //Variables que habilitan maquinas de estados
+int hab_display = DESHABILITADO;
 
 //Variables que me indican el fin de una maquina de estados
+int fin_display = DESHABILITADO;
+int fin_juego = NADA;
+
 
 //Variables que acumulan datos
-int tiempo = 0;    // Variable para contar el 1 segundo para el encendido y apagado de leds
 int var_pulsacion = 25;     // Variable para contar los 2.5mseg de la funcion pulsacion_TSI()
 
-int teclado = NADA;   // Variable que contiene el valor del TSI en todo momento
-int ingreso = NADA;         // Variable que contiene el color presionado en el TSI, que se lee y luego es borrado
+int teclado = NADA;         // Variable que contiene el valor analogico del TSI en todo momento
+int ingreso = NADA;         // Variable que contiene si se presionó el TSI, que se lee y luego se borra
+
+int segundo = 100;      // Variable que cuenta desde 100 hasta 0 para contar 1 segundo
+int tiempo = 60;    // Variable que utilizo para establecer cuanto tiempo contar
+
+int secuencia[4];   // Variable que contiene la secuencia aleatoria
+
+int memoria1 = DESHABILITADO;
+int memoria2 = DESHABILITADO;
+
 
 Ticker lectura; // Ticker lectura del TSI
-Ticker temporizador;    // Ticker para contar 1 segundo en los leds
 Ticker pulsacion;   // Ticker para usar la funcion pulsacion_TSI()
 
+Ticker cuenta;  //Ticker para realizar la cuenta regresiva
+
+Timeout blink1;
+Timeout blink2;
+
 // DEFINO SALIDAS
 DigitalOut ledrojo(LED_RED);
 DigitalOut ledverde(LED_GREEN);
 
+BusOut decenas(PTA4,PTA5,PTC8,PTC9);    // Salidas para el display de las decenas
+BusOut unidades(PTC7, PTC0, PTC3, PTC4);   // Salidas para el display de las unidades
+
+// DEFINO ENTRADAS
+
+BusIn entradas(PTC12,PTC13,PTC16,PTC17);   // Entradas donde estarán los cables a desconectar
 
 AnalogIn noise(PTB0);   // Entrada que usaré para generar la secuencia aleatoria con el ruido que me genere
 
+
 int main(void)
 {
 
+    entradas.mode(PullUp);  // Coloco las entradas con un pullup interno
+
 // Uno las funciones con el ticker correspondiente
     lectura.attach(&LEER_TSI,0.1);
     pulsacion.attach(&pulsacion_TSI,0.001);
+    cuenta.attach(&segundos,0.01);
+
 
 // Apago los leds al iniciar
     ledrojo = 1;
     ledverde= 1;
-
+// Pongo los displays en  0 (Se tienen que negar las salidas)
+    decenas = 0 ^ 0xF;
+    unidades = 0 ^ 0xF;
     while (true) {
 
 // Constantemente uso las maquinas de estados
-
         MAQ_lecturaTSI();
-        if(ingreso != NADA) {
-
-            ingreso = NADA;
-            if(ledverde == 0) {
-                
-                
-                
-                
-                
-                ledrojo=0;
-            }
-            if((ledverde==1)&&(ledrojo==1)) {
-                ledverde=0;
-            }
-            ledrojo=1;
-        }
+        MAQ_cuentareg();
+        MAQ_bomba();
+        MAQ_parpadeo();
 
     }
 }
 
+void MAQ_parpadeo()
+{
+    int auxiliar;
+
+    switch(estado_maq_parpadeo) {
+        case ESPERO:
+            if(fin_juego != NADA) { // Si el juego terminó, habilito la maquina de estados
+                estado_maq_parpadeo = APAGO;
+                blink1.attach(&parpadeo1,0.25); // Uso un Timeout para cambiar de estado una vez pasaron 0.25 segundos
+            }
+            break;
+
+        case APAGO:
+            unidades = 0;   // Apago los displays
+            decenas = 0;    
+            ledverde=0; // Prendo el led verde
+            if(fin_juego == DERROTA) {
+                ledrojo = 0;
+                ledverde=1;
+            }
+            break;
+
+        case PRENDO:
+            auxiliar = tiempo / 10;
+            decenas = auxiliar ^ (0xF); // Como utilizo salidas que se prenden con 0, invierto el numero.
+            unidades = (tiempo - auxiliar * 10) ^ (0xF);
+            if(fin_juego == DERROTA) {
+                ledrojo = 1;    
+            }
+            break;
+    }
+}
+
+void parpadeo1()    //Funcion que vinculo al timeout para cambiar de estado cada 0.25 segundos
+{
+    if(fin_juego != NADA) {
+        estado_maq_parpadeo = PRENDO;
+        blink2.attach(&parpadeo2,0.25);
+    } else {
+        estado_maq_parpadeo = ESPERO;
+    }
+}
+
+void parpadeo2()    //Funcion que vinculo al timeout para cambiar de estado cada 0.25 segundos
+{
+    if(fin_juego != NADA) {
+        estado_maq_parpadeo = APAGO;
+        blink1.attach(&parpadeo1,0.25);
+    } else {
+        estado_maq_parpadeo = ESPERO;
+    }
+}
+
+
+void MAQ_bomba()
+{
+    static int aux;
+    static int nivel;
+    static int diferencia;
+    static int correctos[]= {NADA,NADA,NADA,NADA,NADA};
+    //   Nada, C1,  C2,  C3,  C4
+    switch(estado_maq_bomba) {
+        case PAUSA:
+            if(ingreso == PULSADO) {
+               
+//Reseteo las variables
+                ingreso = NADA;
+
+                fin_juego = NADA;
+                estado_maq_parpadeo = ESPERO;
+
+                correctos[CABLE1] = NADA;
+                correctos[CABLE2] = NADA;
+                correctos[CABLE3] = NADA;
+                correctos[CABLE4] = NADA;
+
+                ledrojo = 1; //Apago los leds
+                ledverde = 1;
+
+                genero_secuencia();     //Genero la secuencia aleatoria
+
+                nivel = 0;
+
+                hab_display = HABILITADO;
+
+                aux = entradas;
+
+                estado_maq_bomba = ESPERO_CABLE;
+
+                estado_maq_display = ESPERO_INICIO;
+
+            }
+            break;
+
+        case ESPERO_CABLE:
+            if(aux != entradas) {   // Si se detecta una diferencia con respecto a un valor anterior en la entrada
+                estado_maq_bomba = COMPARO;
+                diferencia = (aux) ^ (entradas);    // Guardo dicha diferencia en una variable
+            }
+            if(fin_display  == HABILITADO) {    // Si se termina el tiempo:
+                fin_display = DESHABILITADO;
+                ledrojo = 0;
+                estado_maq_bomba = PAUSA;
+                fin_juego = DERROTA;
+                tiempo = 0;
+            }
+            break;
+
+        case COMPARO:
+
+            estado_maq_bomba = ESPERO_CABLE;
+
+
+            switch(diferencia) {    // Uso un switch para variar entre los casos de los cables que se sacaron 
+            //Uso una memoria para ver si el cable ya se retiro y no tenerlo mas en cuenta
+            //Si el valor no corresponde, el jugador pierde
+                case 0b0001:
+                    if(correctos[CABLE1]==NADA) {
+                        correctos[CABLE1]=CORRECTO;
+                        if(secuencia[nivel]!=CABLE1) {
+                            estado_maq_bomba = PAUSA;
+                            ledrojo = 0;
+                            estado_maq_display = ESPERO_INICIO;
+                            fin_juego = DERROTA;
+                        } else {
+                            nivel++;
+                            estado_maq_bomba = ESPERO_CABLE;
+                            aux = entradas;
+                        }
+                    }
+                    break;
+
+                case 0b0010:
+                    if(correctos[CABLE2]==NADA) {
+                        correctos[CABLE2]=CORRECTO;
+                        if(secuencia[nivel]!=CABLE2) {
+                            estado_maq_bomba = PAUSA;
+                            ledrojo = 0;
+                            estado_maq_display = ESPERO_INICIO;
+                            fin_juego = DERROTA;
+                        } else {
+                            nivel++;
+                            estado_maq_bomba = ESPERO_CABLE;
+                            aux = entradas;
+                        }
+                    }
+
+                    break;
+
+                case 0b0100:
+                    if(correctos[CABLE3]==NADA) {
+                        correctos[CABLE3]=CORRECTO;
+                        if(secuencia[nivel]!=CABLE3) {
+                            estado_maq_bomba = PAUSA;
+                            ledrojo = 0;
+                            estado_maq_display = ESPERO_INICIO;
+                            fin_juego = DERROTA;
+                        } else {
+                            nivel++;
+                            estado_maq_bomba = ESPERO_CABLE;
+                            aux = entradas;
+
+                        }
+                    }
+
+                    break;
+
+                case 0b1000:
+                    if(correctos[CABLE4]==NADA) {
+                        correctos[CABLE4]=CORRECTO;
+                        if(secuencia[nivel]!=CABLE4) {
+                            estado_maq_bomba = PAUSA;
+                            ledrojo = 0;
+                            estado_maq_display = ESPERO_INICIO;
+                            fin_juego = DERROTA;
+                        } else {
+                            nivel++;
+                            estado_maq_bomba = ESPERO_CABLE;
+                            aux = entradas;
+
+                        }
+                    }
+
+                    break;
+            }
+            printf("%i\n",nivel);
+            // Si nivel es 4 significa que el jugador ganó
+            if(nivel == 4) {
+                estado_maq_bomba = PAUSA;
+                estado_maq_display = ESPERO_INICIO;
+                fin_juego = VICTORIA;
+            }
+            if(fin_display == HABILITADO) {// Si el tiempo llego al final:
+                ledrojo = 0;
+                tiempo = 0;
+                estado_maq_bomba = PAUSA;
+                fin_display = DESHABILITADO;
+                fin_juego = DERROTA;
+
+            }
+            break;
+    }
+}
+
+void MAQ_cuentareg()
+{
+    int auxiliar;
+
+    switch(estado_maq_display) {
+        case ESPERO_INICIO:
+            if(hab_display == HABILITADO) { // Si se habilita, pongo el tiempo al maximo y cuento 60 segundos
+                hab_display = DESHABILITADO;
+                estado_maq_display = CAMBIO_DISPLAY;
+                tiempo = 60;    
+                segundo=100;
+            }
+            break;
+        case CAMBIO_DISPLAY:
+    // Cambio el valor de los displays por el que corresponde al tiempo
+            auxiliar = tiempo / 10;
+            decenas = auxiliar ^ (0xF);
+            unidades = (tiempo - auxiliar * 10) ^ (0xF);
+
+            if(segundo == 0) {
+                estado_maq_display = RESTO_DISPLAY;
+            }
+            break;
+        case RESTO_DISPLAY:
+        // Cada 1 segundo resto 1 valor al tiempo
+        // Si el tiempo es menor a 0, marco como que se terminó la cuenta
+            tiempo--;
+            if(tiempo < 0) {
+                estado_maq_display = ESPERO_INICIO;
+                fin_display = HABILITADO;
+
+            } else {
+                estado_maq_display = CAMBIO_DISPLAY;
+                segundo=100;
+            }
+            break;
+    }
+}
+
+void segundos()
+{
+    segundo--;
+}
+
+
 void LEER_TSI()
 {
     float auxiliar = 0;
@@ -107,15 +410,16 @@
 void MAQ_lecturaTSI()
 {
     if(var_pulsacion < 1) { // Si se llegaron a los 2.5ms:
+
         var_pulsacion = 25; // Vuelvo a establecer 2.5ms para el proximo ciclo
+
         switch(estado_maq_tsi) {
             case NADA:
-                ingreso = NADA; // La variable ingreso, salvo en los casos especificos, siempre se encontrará en NADA
+                ingreso = NADA; // La variable ingreso, salvo en el caso especifico, siempre se encontrará en NADA
 
-                // En vez de usar cadenas de if en las transiciones, utilizo un switch
                 if(teclado==PULSADO) {
                     estado_maq_tsi = PULSADO;
-                    ingreso = PULSADO;
+                    ingreso = PULSADO;  // El valor del TSI lo cambio en la transicion entre estados para asegurarme que solo se pueda leer 1 vez
                 }
                 break;
 
@@ -126,4 +430,65 @@
                 break;
         }
     }
+}
+
+void genero_secuencia()
+{
+    int auxiliar;   // Variable que voy a usar para contener un numero aleatorio
+
+    // Variables que uso para saber si el cable que intento establecer en la secuencia ya se usó anteriormente
+    int cable1 = DISPONIBLE;
+    int cable2 = DISPONIBLE;
+    int cable3 = DISPONIBLE;
+    int cable4 = DISPONIBLE;
+
+    srand(int (noise * 10000)); // Cambio la semilla de la funcion rand usando un valor de ruido en una entrada analogica al aire
+
+    for(int i = 0; i <=3 ; i++) {  // Creo un for para recorreR las 4 posiciones de memoria del vector "secuencia[]"
+
+        auxiliar = rand();  //Genero un valor aleatorio y lo guardo en mi variable auxiliar
+
+        // Dependiendo de cuanto resto me de al dividir por 4, asignare ese valor aleatorio con un cable distinto
+        // Si el cable que intento establecer en la secuencia se encuentra usado, resto un valor de "i" para volver a intentar
+        // con otro valor aleatorio.
+        // Este procedimiento se repite hasta que pueda llenar los 4 valores de la secuencia
+
+        if((auxiliar % 4) == 0) {
+            if(cable1 == DISPONIBLE) {
+                secuencia[i] = CABLE1;
+                cable1 = USADO;
+            } else {
+                i--;
+            }
+        }
+        if((auxiliar % 4 ) == 1) {
+            if(cable2 == DISPONIBLE) {
+                secuencia[i] = CABLE2;
+                cable2 = USADO;
+            } else {
+                i--;
+            }
+        }
+        if((auxiliar % 4 ) == 2) {
+            if(cable3 == DISPONIBLE) {
+                secuencia[i] = CABLE3;
+                cable3 = USADO;
+            } else {
+                i--;
+            }
+        }
+        if((auxiliar % 4 ) == 3) {
+            if(cable4 == DISPONIBLE) {
+                secuencia[i] = CABLE4;
+                cable4 = USADO;
+            } else {
+                i--;
+            }
+        }
+    }
+    // Muestro la secuencia en el puerto serie
+    for(int i = 0; i<4; i++) {
+        printf("%i",secuencia[i]);
+    }
+    printf("\n");
 }
\ No newline at end of file