#include <16f877a.h>

#include <stdlib.h>            //Para la función atoi
#include <STDIO.H>             //Para las funciones RS232
#include <STRING.H>            //Para funciones con strings

//------------------------- Directivas para el compilador ------------------------

#zero_ram

#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//----------------------- Funciones para controlar la memoria ---------------------

int mmc_init();
int mmc_response(unsigned char response);
int mmc_read_block(unsigned long block_number);
int mmc_write_block(unsigned long block_number);
int senal(unsigned long block_number);
int text(unsigned long block_number);

void menu(void);


char cadena[4];                //Cantidad de caracteres a recibir. Ej 125 y el "enter".
char texto[40];
int retardo = 1;
int  adc_temperatura=0x00;
char Keypress=' ';
long int x;
int c,b;

//------------------------- Interrrupcion del puerto serie -----------------------

#int_rda
 void rda_isr()
  {
   Keypress=0x00;
   if(kbhit())  {Keypress=getc();}
  }


//-------------------------------- MMC Init ----------------------------------------
//- Inicializa la memoria en modo SPI y setea el tamaño del bloque, retorna 0 si OK-

int mmc_init()
{
 int i;
 SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED);
 *0x94 |= 0x40;                          // setea CKE = 1 - clock idle low
 *0x14 &= 0xEF;                          // setea CKP = 0 - el dato es valido en el flnco ascendente
 OUTPUT_HIGH(PIN_C2);                    // setea SS = 1 (off)

 for(i=0;i<10;i++)                       // Inicializa la memoria en modo SPI enviando clks altos

    { SPI_WRITE(0xFF);}

 OUTPUT_LOW(PIN_C2);                     // setea SS = 0 (on)

 SPI_WRITE(0x40);                        // Envio comando de reset
 SPI_WRITE(0x00);                        // Todos los argumntos son 0x00 para el comando de reset
 SPI_WRITE(0x00);
 SPI_WRITE(0x00);
 SPI_WRITE(0x00);
 SPI_WRITE(0x95);                        // checksum precalculado

 if(mmc_response(0x01)==1) return 1;     // Si respuesta = 1 se supero el tiempo de espera para 0x01 desde la SD

 puts("Respuesta correcta de la SD!\n\r");
 i = 0;
 while((i < 255) && (mmc_response(0x00)==1))     // Enviamos el comando hasta tener la respuesta esperada
   {
        SPI_WRITE(0x41);                // Enviamos el comando para sacar la memoria del estado idle
        SPI_WRITE(0x00);                // Todos los argumentos son 0x00 para el comando uno
        SPI_WRITE(0x00);
        SPI_WRITE(0x00);
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF
        i++;
   }

 if(i >= 254) return 1;                 // Si >= 254 se supero el tiempo de espera para 0x00 desde la SD

 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)
 SPI_WRITE(0xFF);
 OUTPUT_LOW(PIN_C2);                    // Chip Select = 0 (on)

        SPI_WRITE(0x50);
        SPI_WRITE(0x00);
        SPI_WRITE(0x00);
        SPI_WRITE(0x02);                // Con esto configuramos el tamaño de bloque = 512
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF

 if((mmc_response(0x00))==1) return 1;

 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)
 puts("Memoria inicializada!\n\r");

 return 0;

}



//-------------------------------- MMC Write Block ----------------------------------------
//---------------- Escribe en la memoria un bloque de datos de 512 Bytes ------------------

int mmc_write_block(unsigned long block_number)
{
 unsigned long i;
 unsigned long varh,varl;

 varl=((block_number&0x003F)<<9);
 varh=((block_number&0xFFC0)>>7);

 OUTPUT_LOW(PIN_C2);                    // Chip select = 0 (on)

        SPI_WRITE(0x58);                // Comando para escritura de bloque
        SPI_WRITE(make8(varh,1));
        SPI_WRITE(make8(varh,0));
        SPI_WRITE(make8(varl,1));
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF

 if((mmc_response(0x00))==1) return 1;

 SPI_WRITE(0xFE);                       // Envio el data token

 for(i=0;i<512;i++)                     // Guardo en la memoria las 512 muestras del ADC
  {
   delay_ms(retardo);
   adc_temperatura=read_adc();
   SPI_WRITE(adc_temperatura);
  }

 SPI_WRITE(0xFF);
 SPI_WRITE(0xFF);

 if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)
 return 0;

}



//------------------------------- MMC Read Block ----------------------------------
//------- Lee bloques de 512 bytes de la memoria y los envia por RS232 ------------

int mmc_read_block(unsigned long block_number)
{

 unsigned long i;
 unsigned long varh,varl;
 int dato;

 varl=((block_number&0x003F)<<9);
 varh=((block_number&0xFFC0)>>7);

 OUTPUT_LOW(PIN_C2);                    // Chip select = 0 (on)

        SPI_WRITE(0x51);                // Envio el comando de lectura de bloque
        SPI_WRITE(make8(varh,1));
        SPI_WRITE(make8(varh,0));
        SPI_WRITE(make8(varl,1));
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF

 if((mmc_response(0x00))==1)
    {
        //puts("Fallo al enviar el comando\n\r");
        return 1;  // Si la respuesta es 1 fallo el envio del comando
    }


 if((mmc_response(0xFE))==1)
    {
        //puts("Token incorrecto\n\r");
        return 1;  // Esperando el  data token
    }

 for(i=0;i<512;i++)
        {
         //dato =SPI_READ(0xFF);
         //printf("%u\r",dato);   // Leemos 512 bytes
         putc(SPI_READ(0xFF));
        }

 SPI_READ(0xFF);                        
 SPI_READ(0xFF);
 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)
 SPI_WRITE(0xFF);                       // Le enviamos algunos clocks para asegurar que termina el proceso
 //puts("\n\rFin de lectura de bloque\n\r");

 return 0;

}


void menu (void)
{

 printf("\n\r Para leer un sector presione r \n\r" );
 printf("\n\r Para escribir un sector presione w \n\r" );
 printf("\n\r Para escribir un texto presione t \n\r" );
 printf("\n\r Para generar una señal presione s\n\r" );
 printf("\n\r Para digitalizar una señal presione d\n\r" );
}

//-----------------------------   MMC get response -------------------------------------
//------ Lee repetdamente la SD hasta obtener la respuesta buscada o sale por timeout --

int mmc_response(unsigned char response)
{
        unsigned long count = 0xFFFF;           // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
        while(SPI_READ(0xFF) != response && --count > 0);
        if(count==0) return 1;                  
        else return 0;                         
}


int senal(unsigned long block_number)
{
 unsigned long i;
 unsigned long varh,varl;
 int j=0;

 varl=((block_number&0x003F)<<9);
 varh=((block_number&0xFFC0)>>7);


 OUTPUT_LOW(PIN_C2);                    // Chip select = 0 (on)

        SPI_WRITE(0x58);                // Comando para escritura de bloque
        SPI_WRITE(make8(varh,1));
        SPI_WRITE(make8(varh,0));
        SPI_WRITE(make8(varl,1));
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF

 if((mmc_response(0x00))==1) return 1;

 SPI_WRITE(0xFE);                       // Envio el data token

 for(i=0;i<512;i++)
  {

   if(i<255)
    SPI_WRITE(i);
   else
    SPI_WRITE(255-i);
  }

 SPI_WRITE(0xFF);
 SPI_WRITE(0xFF);

 if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)

 return 0;

}



int text(unsigned long block_number)
{
 unsigned long i;
 unsigned long varh,varl;
 int j=0;

 varl=((block_number&0x003F)<<9);
 varh=((block_number&0xFFC0)>>7);


 OUTPUT_LOW(PIN_C2);                    // Chip select = 0 (on)

        SPI_WRITE(0x58);                // Comando para escritura de bloque
        SPI_WRITE(make8(varh,1));
        SPI_WRITE(make8(varh,0));
        SPI_WRITE(make8(varl,1));
        SPI_WRITE(0x00);
        SPI_WRITE(0xFF);                // El checksum no es requerido pero igual siempre le enviamos 0xFF

 if((mmc_response(0x00))==1) return 1;

 SPI_WRITE(0xFE);                       // Envio el data token

 for(i=0;i<512;i++)
  {
    if(i<40)
    SPI_WRITE(texto[i]);
    else
    SPI_WRITE(0x20);
  }

 SPI_WRITE(0xFF);
 SPI_WRITE(0xFF);

 if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
 OUTPUT_HIGH(PIN_C2);                   // Chip Select = 1 (off)

 return 0;

}









//-----------------------------   Programa principal -------------------------------------

void main()
 {
   setup_adc_ports(AN0_AN1_AN2_AN3_AN4);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(1);

   enable_interrupts(int_rda);
   enable_interrupts(global);

   printf("\n********************************************\r\n");
   printf("\n\r UTN - Facultad Regional Parana\n\r" );
   printf("\n Tecnicas Digitales II\n\r" );
   printf("\n Proyecto Holter\n\r" );
   printf("\n Para inicializar la memoria presione i\n\n\r" );
   printf("\n********************************************\r\n\n");

   printf("\n\r Para ver el menu presione m\n\r" );

   do {

      if(Keypress!=0x00)
      {
         switch(Keypress)
                        {
                           case 'i': if (mmc_init()==0)
                                         { printf("\n Arranco la memoria \n\n\r" ); }

                                     else  printf("\n Fallo al iniciar la memoria \n\r" );
                           break;

                           case 'm': menu();
                           break;

                           case 's': printf("\n Generando Senial \n\r" );
                                     senal(563);
                                     printf("\n Senial Generada \n\r" );
                                     mmc_read_block(563);
                           break;


                           case 'r': disable_interrupts(global);
                                     printf("\n Que sector quiere leer? \n\r" );
                                     gets(cadena);                               // Guarda caracteres hasta que recibe enter.
                                     x = atoi32(cadena);                         // Convierte los 3 caracteres ascii recibidos a un numero entero.
                                     printf("\n Leyendo sector %x \n\n\r",x );
                                     b=0;
                                     while(b==0)
                                      {
                                       if(mmc_read_block(x)==0)
                                       { b=1; }
                                      }


                                     enable_interrupts(global);
                           break;


                           case 'w': disable_interrupts(global);
                                     printf("\n En que sector lo quiere guardar? \n\r");
                                     gets(cadena);
                                     x = atoi32(cadena);
                                     c=0;
                                     if(mmc_write_block(x)==0)
                                       {
                                        printf("\n Guardado en el sector %x \n\r",x );
                                       }


                                      enable_interrupts(global);
                           break;


                           case 'd': disable_interrupts(global);
                                     mmc_read_block(536);
         x = 536;
         c=0;
         while(c<20)
            {
             b=0;
             mmc_write_block(x);
             while(b==0)
              {
               if(mmc_read_block(x)==0)
               { b=1; }
              }
             x++;
             c++;
            }
                                     enable_interrupts(global);
                           break;

                            case 't':
                                     disable_interrupts(global);
                                     printf("\n Ingrese el texto a guardar en la memoria \n\r");
                                     gets(texto);
                                     puts(texto);
                                     text(536);
                                     mmc_read_block(536);
                                     printf("\n Texto guardado  \n\r");
                                     enable_interrupts(global);
                           break;


                        }
         Keypress=0x00;
       }
   } while (TRUE);
 }

