TRABAJO PRACTICO - EJERCICIO 3 - TERMINADO

Dependencies:   mbed tsi_sensor

main.cpp

Committer:
matirodriguez
Date:
2019-06-10
Revision:
1:ad8aebd0e5c7
Parent:
0:ec6eb1da0a1c

File content as of revision 1:ad8aebd0e5c7:

#include "mbed.h"
#include "tsi_sensor.h"

#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_bomba();   // Prototipo funcion general del juego

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 var_pulsacion = 25;     // Variable para contar los 2.5mseg de la funcion pulsacion_TSI()

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 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();
        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;
    auxiliar = tsi.readPercentage();    //Guardo de manera auxiliar el valor entre 0 y 1 del TSI

// Asocio el valor del tsi numerico con un color, dividiendo en 4 valores posibles (0, <0.33, <0.66, <1)

    if(auxiliar >= 0) {
        teclado = NADA;
    }
    if((auxiliar > 0.05)&&(auxiliar <= 1)) {
        teclado = PULSADO;
    }
}

void pulsacion_TSI()
{
    if(var_pulsacion > 0) {
        var_pulsacion--;
    }
}

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 el caso especifico, siempre se encontrará en NADA

                if(teclado==PULSADO) {
                    estado_maq_tsi = PULSADO;
                    ingreso = PULSADO;  // El valor del TSI lo cambio en la transicion entre estados para asegurarme que solo se pueda leer 1 vez
                }
                break;

            case PULSADO:
                if(teclado == NADA) {
                    estado_maq_tsi = NADA;
                }
                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");
}