#INCLUDE <18f4550.h>
#INCLUDE <stdio.h>
#INCLUDE <string.h>

#USE delay(clock=16000000)

#INCLUDE <lcd1100_combo.c>

#FUSES HSPLL, NOPROTECT, BROWNOUT_NOSL, NOWDT, NOBROWNOUT, PUT ,NOCPD, NOSTVREN
#FUSES NODEBUG, NOLVP, NOWRT, NOWRTD, IESO, NOFCMEN, NOPBADEN, NOWRTC, NOWRTB
#FUSES NOEBTR, NOEBTRB, NOCPB, MCLR, NOLPT1OSC, NOXINST, PLL4, CPUDIV1
#FUSES USBDIV, VREGEN, NOICPRT

#BYTE PORT_B=0XF81

void menu();
void principal();
void sennal();
void estado();
void onda();
void amplitud();
void frecuencia();
void periodo();
void duty();
void volver(int funcion);

static int opc_total=0;
volatile static char opciones[8][16]={"","","","","","","",""};
static int i=0;
static int tipo=0;
static int amp=0;
static int frec=0;
static int ctrab=0;
static int funcion=0;
static int posicion=0;
static int x=0;
static int y=0;
static int salir=0;
static char magnitud[2]={};
const char imagen[9][96]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,240,240,240,240,240,240,240,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,240,240,240,
240,240,240,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,240,240,240,240,240,240,240,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,3,15,63,255,255,255,255,255,255,252,248,240,224,192,128,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,128,192,224,
240,248,252,255,255,255,255,255,255,63,15,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,7,15,31,
63,127,255,255,255,255,255,254,252,252,248,248,240,240,255,255,255,255,255,255,255,255,240,240,248,248,252,252,254,255,255,255,255,255,127,63,31,15,
7,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,240,240,240,240,240,240,240,240,240,240,240,240,
241,241,243,243,247,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,247,247,243,243,241,241,240,240,240,240,240,240,240,
240,240,240,240,240,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,15,15,15,15,15,15,15,15,15,15,15,143,
143,207,207,239,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,239,239,207,207,143,143,15,15,15,15,15,15,15,15,15,15,15,
15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,224,240,248,252,254,255,255,255,255,255,127,
63,63,31,31,15,15,255,255,255,255,255,255,255,255,15,15,31,31,63,63,127,255,255,255,255,255,254,252,248,240,224,192,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,240,252,255,255,255,255,255,255,63,31,15,7,3,1,0,0,0,0,0,0,0,0,255,255,255,255,
255,255,255,255,0,0,0,0,0,0,0,0,1,3,7,15,31,63,255,255,255,255,255,255,252,240,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,12,15,15,15,15,15,15,15,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,15,15,15,15,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,15,15,15,15,15,15,15,
14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

#INT_EXT NOCLEAR
void EXT_isr()
{
    while(!bit_test(PORT_B,0)){delay_ms(100);}
    output_toggle(PIN_C2);
    salir=0; //Paro la generación de señal (si estan habilitadas las interrupciones)
    clear_interrupt(INT_EXT);
    disable_interrupts(INT_EXT);
}

void main(void)
{
    //CONFIGURACIÓN DE PUERTOS
    set_tris_a (0b00000000);
    port_b_pullups (TRUE);
    set_tris_b (0x07);
    set_tris_c (0b00000000);
    output_c (0x00);
    set_tris_d (0b00000000);
    output_d (0x80); // 0V del DAC
    set_tris_e (0b00000000);
    output_e (0x00);
    
    //INICIALIZACIÓN DEL DISPLAY
    lcd_init();
    delay_ms(200);
    lcd_clear();
    gotoxy(0,0);
    
    for(y=0;y<9;y++)
    {
        for(x=0;x<96;x++)
        {
            lcd_write(DATA,imagen[y][x]);
        }
    }
    while(bit_test(PORT_B,0)&&bit_test(PORT_B,1)&&bit_test(PORT_B,2)){delay_ms(100);}
    lcd_clear();
    gotoxy(2,0);
    printf(print_char,"Generador de");
    gotoxy(2,1);
    printf(print_char,"señales");
    gotoxy(2,2);
    printf(print_char,"UTN-FRVM 2013");
    gotoxy(2,5);
    printf(print_char,"Matias D. Vico");
    while(bit_test(PORT_B,0)&&bit_test(PORT_B,1)&&bit_test(PORT_B,2)){delay_ms(100);}
    
    //CONFIGURACIÓN DE INTERRUPCIONES
    clear_interrupt(INT_EXT);
    //enable_interrupts(INT_EXT);
    ext_int_edge(0,H_TO_L);
    enable_interrupts(GLOBAL);
    
    for(;;)
    {
        if(salir==0)
        {
            salir=1;
            principal();
        }
    } //CONVERTIR EN UN SLEEP DESPUES DE UN TIEMPO DADO SIN USO
}
    
void volver(int funcion)
{        
    static const char opc_volver[8][16]={"SALIR?","Si","No","","","","",""};
    for(y=0;y<=7;y++)
    {
        strcpy(opciones[y],opc_volver[y]);
    }
    opc_total=1;
            
    switch(funcion)
    {
        //MENU SALIR
        case 0:
        {
            lcd_clear();
            menu();
            switch(posicion)
            {
                //SI
                case 0: 
                {
                    lcd_clear();
                    gotoxy(30,3);
                    printf(print_char, "SLEEP");
                    clear_interrupt(INT_EXT);
                    enable_interrupts(INT_EXT);
                    sleep();
                    delay_ms(2000);
                    break;
                }
                //NO
                case 1:
                {
                    //enable_interrupts(INT_EXT);
                    return;
                    //break;
                }
            }
        }
        //MENU MENU
        case 1:
        {
            //enable_interrupts(INT_EXT);
            //salir=0;
            return;
            //break;
        }
    }
}

void principal()
{
    static const char opc_menu[8][16]={"MENU PRINCIPAL","Estado","Tipo de onda","Amplitud","Frecuencia","Periodo","Duty cicle","Apagar"};
    disable_interrupts(INT_EXT); // sobraría...
    //char opc_menu[8][16]={"MENU PRINCIPAL","Estado","Tipo de onda","Amplitud","Frecuencia","Periodo","Duty cicle","Apagar"};
    /*for(y=0;y<=7;y++)
    {
        strcpy(opciones[y],opc_menu[y]);
    }*/
    opc_total=6;    
    lcd_clear();
    posicion=0;
    salir=1;
    clear_interrupt(INT_EXT);//asdfasdgfergerger
        for(y=0;y<=7;y++)
    {
        strcpy(opciones[y],opc_menu[y]);
    }
    menu();
    switch(posicion)
    {
        case 0:
        {
            estado();
            break;
        }
        case 1:
        {
            onda();
            break;
        }
        case 2:
        {
            amplitud();
            break;
        }
        case 3:
        {
            frecuencia();
            break;
        }
        case 4:
        {
            periodo();
            break;
        }
        case 5:
        {
            duty();
            break;
        }
        case 6:
        {
            volver(0);
            break;
        }
    }
}

void menu()
{
    disable_interrupts(INT_EXT);
    clear_interrupt(INT_EXT);
    salir=1;
    posicion=0;
    gotoxy(0,0);
    printf(print_char,opciones[0]);
    gotoxy(0,1);
    printf(print_char,">");
    for(i=1;i<=7;i++)
    {
        gotoxy(10,i);
        printf(print_char,opciones[i]);
    }
    salir=1;
    while(salir)
    {  
        if(!bit_test(PORT_B,1))
        {
            while(!bit_test(PORT_B,1)){delay_ms(100);}
            if(posicion>0)
            {
                posicion--;
                gotoxy(0,posicion+2);
                printf(print_char," ");
                gotoxy(0,posicion+1);
                printf(print_char,">");
            }
        }
        if(!bit_test(PORT_B,2))
        {
            while(!bit_test(PORT_B,2)){delay_ms(100);}
            if(posicion<opc_total)
            {
                posicion++;
                gotoxy(0,posicion);
                printf(print_char," ");
                gotoxy(0,posicion+1);
                printf(print_char,">");
            }
        }
        if(!bit_test(PORT_B,0))
        {
            while(!bit_test(PORT_B,0)){delay_ms(100);}
            salir=0;
        }
    }
}

void deslizable()
{
    clear_interrupt(INT_EXT);//asdfasdgfergerger
    salir=1;
    posicion=25;
    //lcd_rect(22,28,73,35,1,1);
    //lcd_rect(posicion+23,28,74,35,0,0);
    gotoxy(35,4);
    printf(print_char,"%02.0f %s",(((float)posicion)*100.0)/50.0,magnitud);
    while(salir)
    {
        if(!bit_test(PORT_B,1))
        {
            while(!bit_test(PORT_B,1)){delay_ms(100);}
            if(posicion+22<72)
            {
                posicion++;
                //lcd_rect(22,28,74,35,1,1);
                //lcd_rect(posicion+23,28,74,35,0,0);
                gotoxy(35,4);
                printf(print_char,"     ");
                gotoxy(35,4);
                printf(print_char,"%02.0f %s",(((float)posicion)*100.0)/50.0,magnitud);
            }
        }
        if(!bit_test(PORT_B,2))
        {
            while(!bit_test(PORT_B,2)){delay_ms(100);}
            if(posicion+22>22)
            {
                posicion--;
                //lcd_rect(22,28,74,35,1,1);
                //lcd_rect(posicion+23,28,74,35,0,0);
                gotoxy(35,4);
                printf(print_char,"     ");
                gotoxy(35,4);
                printf(print_char,"%02.0f %s",(((float)posicion)*100.0)/50.0,magnitud);
            }
        }
        if(!bit_test(PORT_B,0))
        {
            while(!bit_test(PORT_B,0)){delay_ms(100);}
            salir=0;
        }
    }
}

void estado()
{
    static const char opc_estado[8][16]={"ESTADO","Activo","Inactivo","Atras","","","",""};
    for(y=0;y<=7;y++)
    {
        strcpy(opciones[y],opc_estado[y]);
    }
    opc_total=2;
    lcd_clear();
    menu();
    switch(posicion)
    {
        //ACTIVO
        case 0: 
        {
            while(!bit_test(PORT_B,0)){delay_ms(100);}
            salir=1;
            sennal();
            break;
        }
        //INACTIVO
        case 1:
        {
            while(!bit_test(PORT_B,0)){delay_ms(100);}
            output_d(0x80);
            volver(1);
            break;
        }
        //ATRAS
        case 2:
        {
            volver(1);
            break;
        }
    }
}

void onda()
{
    static const char opc_onda[8][16]={"TIPO DE SEÑAL","Rampa","Triangular","Cuadrada","Senoidal","Atras","",""};
    for(y=0;y<=7;y++)
    {
        strcpy(opciones[y],opc_onda[y]);
    }
    opc_total=4;
    lcd_clear();   
    menu();
    switch(posicion)
    {
        case 0:
        {
            tipo=0;
            volver(1);
            break;
        }
        case 1:
        {
            tipo=1;
            volver(1);
            break;
        }
        case 2:
        {
            tipo=2;
            volver(1);
            break;
        }
        case 3:
        {
            tipo=3;
            volver(1);
            break;
        }
        case 4:
        {
            volver(1);
            break;
        }
    }
}

void amplitud()
{
    amp=0;
    strcpy(magnitud,"v");
    posicion=amp;
    lcd_clear();
    gotoxy(0,0);
    printf(print_char,"AMPLITUD");
    deslizable();
    amp=posicion;
    //posicion=0;
    //salir=0; //solo momentaneo mientras la funcion deslizable() este comentada
    //clear_interrupt(INT_EXT);//solo momentaneo mientras la funcion deslizable() este comentada
    //volver(1);
    //break;
    //100% amp=0xFF;
    //80% amp=0xCC;
    //60% amp=0x99;
    //40% amp=0x66;
    //20% amp=0x33;
    //10% amp=0x19;
}

void frecuencia()
{
    frec=0;
    strcpy(magnitud,"Hz");
    posicion=frec;
    lcd_clear();
    gotoxy(0,0);
    printf(print_char,"FRECUENCIA");
    deslizable();
    frec=posicion;
    volver(1);
}

void periodo()
{
    frec=0;
    strcpy(magnitud,"s");
    posicion=frec;
    lcd_clear();
    gotoxy(0,0);
    printf(print_char,"PERIODO");
    deslizable();
    frec=posicion;
    volver(1);
}

void duty()
{
    ctrab=0;
    strcpy(magnitud,"%");
    posicion=ctrab;
    lcd_clear();
    gotoxy(0,0);
    printf(print_char,"DUTY CICLE");
    deslizable();
    ctrab=posicion;
    volver(1);
}

void sennal ()
{
    static const char opc_onda[8][16]={"","Rampa","Triangular","Cuadrada","Senoidal","","",""};
    const int seno[200]={127,131,135,139,143,147,151,155,159,163,166,170,174,178,181,185,188,192,195,199,202,205,208,211,214,217,220,223,225,228,230,232,235,237,
    239,240,242,244,245,247,248,249,250,251,252,253,253,254,254,254,254,254,254,253,253,252,252,251,250,249,247,246,245,243,241,240,238,236,233,231,229,
    226,224,221,219,216,213,210,207,204,200,197,194,190,187,183,180,176,172,168,165,161,157,153,149,145,141,137,133,129,125,121,117,113,109,105,101,97,93,
    89,86,82,78,74,71,67,64,60,57,54,50,47,44,41,38,35,33,30,28,25,23,21,18,16,14,13,11,9,8,7,5,4,3,2,2,1,1,0,0,0,0,0,0,1,1,2,3,4,5,6,7,9,10,12,14,15,17,
    19,22,24,26,29,31,34,37,40,43,46,49,52,55,59,62,66,69,73,76,80,84,88,91,95,99,103,107,111,115,119,123,127};
    /*int salida[200]={127,131,135,139,143,147,151,155,159,163,166,170,174,178,181,185,188,192,195,199,202,205,208,211,214,217,220,223,225,228,230,232,235,237,
    239,240,242,244,245,247,248,249,250,251,252,253,253,254,254,254,254,254,254,253,253,252,252,251,250,249,247,246,245,243,241,240,238,236,233,231,229,
    226,224,221,219,216,213,210,207,204,200,197,194,190,187,183,180,176,172,168,165,161,157,153,149,145,141,137,133,129,125,121,117,113,109,105,101,97,93,
    89,86,82,78,74,71,67,64,60,57,54,50,47,44,41,38,35,33,30,28,25,23,21,18,16,14,13,11,9,8,7,5,4,3,2,2,1,1,0,0,0,0,0,0,1,1,2,3,4,5,6,7,9,10,12,14,15,17,
    19,22,24,26,29,31,34,37,40,43,46,49,52,55,59,62,66,69,73,76,80,84,88,91,95,99,103,107,111,115,119,123,127};*/
    i=199;
    
    clear_interrupt(INT_EXT);
    enable_interrupts(INT_EXT);
    //enable_interrupts(GLOBAL);
    
    lcd_clear();
    gotoxy(0,0);
    printf(print_char,"Generando:");
    gotoxy(0,1);
    printf(print_char,"* %s",opc_onda[tipo+1]);
    gotoxy(0,2);
    printf(print_char,"Amplitud:");
    gotoxy(0,3);
    printf(print_char,"* %2.2f",(float)amp*(float)5/(float)255);
    gotoxy(0,4);
    printf(print_char,"Frecuencia:");
    gotoxy(0,5);
    printf(print_char,"* %4.0f",(float)frec);
    
    switch(tipo)
    {
        //SEÑAL RAMPA
        case 0:
        {
            while(salir)
            {
                output_d(amp);
                amp++;
            
            //delay_ms(3000);
            //clear_interrupt(INT_EXT);
            //enable_interrupts(INT_EXT);
            //for(i=0;i<=199;i++)
            //{
            //    salida[i]=i*amp;
            //}
            //i=0;
            //while(salir)
            //{
            //    output_d(salida[i]);
            //    delay_ms(frec);
            //}
            }
            break;
        }
        //SEÑAL TRIANGULAR
        case 1:
        {
            while(salir)
            {
                for(amp=0;amp<=0xFE;amp++)
                {
                    output_d(amp);
                    //delay_ms(frec);
                    delay_ms(1);
                }
                for(amp=0xFF;amp>=1;amp--)
                {
                    output_d(amp);
                    //delay_ms(frec);
                    delay_ms(1);
                }
                
            }
            return;
            break;
        }
        //SEÑAL CUADRADA
        case 2:
        {
            while(salir)
            {
                output_d(0xFF);
                delay_us(100);
                output_d(0x00);
                delay_us(100);
            }
            return;
            break;
        }
        //SEÑAL SENOIDAL
        case 3:
        {
            while(salir)
            //for(t=0;t<=200;t++)
            {
                output_d(seno[i]);
                //delay_ms(frec);
                //delay_ms(1);
                i--;
                if(i==0){i=199;}
                
            }
            return;
            break;
        }
        //SEÑAL IMPULSO
        case 4:
        {
            while(salir)
            {
                output_d(0xFF);
                delay_us(frec);
                output_d(0x00);
                delay_ms(frec);
            }
            return;
            break;
        }
    }
}
