// _232_buffered.c

#include <16f876a.h>                          // Definiciones del PIC 16F876A
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT  // Los Fuses de siempre
#use delay(clock=4000000)                     // Oscilador a 4 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estándar

// CONSTANTES /////////////////////////////////////////////////////////////////

int const lenbuff=32;                  // Longitud de buffer, Ajustar
                                       // a lo que desees (o te sea posible)

// VARIABLES EN RAM ///////////////////////////////////////////////////////////

int  xbuff=0x00;                       // Índice: siguiente char en cbuff
char cbuff[lenbuff];                   // Buffer
char rcvchar=0x00;                     // último caracter recibido
int1 flagcommand=0;                    // Flag para indicar comando disponible 

// Declaración de Funciones ///////////////////////////////////////////////////

void inicbuff(void);                   // Borra buffer 
int  addcbuff(char c);                 // añade caracter recibido al buffer
void echos(char c);                    // Eco selectivo sobre RS232
void procesa_comando(void);            // Procesa comando

// INTERRUPCIONES /////////////////////////////////////////////////////////////

#int_rda
void serial_isr() {                    // Interrupción recepción serie USART

   rcvchar=0x00;                       // Inicializo caracter recibido                    
   if(kbhit()){                        // Si hay algo pendiente de recibir ...
      rcvchar=getc();                  // lo descargo y ...
      addcbuff(rcvchar);               // lo añado al buffer y ...
      echos(rcvchar);                  // hago eco (si procede).
   }
}

// Desarrollo de Funciones ////////////////////////////////////////////////////

void echos(char c){                    // Echo selectivo ----------------------

      switch(c){
         case 0x0D: printf(" [Ent] "); // Si he pulsado la tecla [Intro]
                    break;
         case 0x08: printf(" [Del] "); // Si he pulsado la tecla [Retroceso]
                    break;
         case 0x1B: printf(" [Esc] "); // Si he pulsado la tecla [Escape]
                    break;
         default:   putc(rcvchar);     // Echo de cualquier otro caracter
      }
}

void inicbuff(void){                   // Inicia a \0 cbuff -------------------
   int i;

   for(i=0;i<lenbuff;i++){             // Bucle que pone a 0 todos los
      cbuff[i]=0x00;                   // caracteres en el buffer
   }
   xbuff=0x00;                         // Inicializo el indice de siguiente
                                       // caracter
}

int addcbuff(char c){                  // Añade a cbuff -----------------------

      switch(c){
         case 0x0D:                    // Enter -> Habilita Flag para procesar
            flagcommand=1;             // Comando en Main
            break;
         case 0x08:                    // Del   -> Borra último caracter del Buffer
            if(xbuff>0) cbuff[--xbuff]=0x00;
            break;
         case 0x01B:                   // Esc   -> Borra el Buffer completamente
            inicbuff();
            break;
         default:
            cbuff[xbuff++]=c;          // Añade caracter recibido al Buffer
      }
}


// Programa Principal /////////////////////////////////////////////////////////

void main() {

   inicbuff();                                   // Borra buffer al inicio
 
   printf("\r\n\** RS232 Buffered **\r\n\r\n");  // Presenta menú
   printf("[Enter] Procesa comando\r\n");
   printf("[Escape] Borra todo el buffer\r\n");
   printf("[Delete] Borra último carácter del buffer\r\n");
   printf("[\\w] Comando Escribe\r\n");
   printf("[\\r] Comando Lee\r\n");
   printf("\r\n");

   enable_interrupts(int_rda);                   // Habilita Interrupción RDA
   enable_interrupts(global);                    // Habilita interrupciones

   do {
   
      if(flagcommand) procesa_comando();         // Si hay comando pendiente
                                                 // de procesar ... lo procesa.

   } while (TRUE);

}

// Procesador de Comandos /////////////////////////////////////////////////////

void procesa_comando(void){

   int i;
   char arg[lenbuff];                   // Argumento de comando (si lo tiene)

   flagcommand=0;                       // Desactivo flag de comando pendiente.
   printf("\r\nProcesando ... ");       // Monitorizo procesando ...

   for(i=0;i<lenbuff;i++){             // Bucle que pone a 0 todos los
      arg[i]=0x00;                     // caracteres en el argumento
   }

   if(cbuff[0]=='\\'&&cbuff[1]=='r'){   // Comparo inicio del buffer con comando "\r"
   
      printf("Leyendo ... ");           // Aqui lo que deseemos hacer con comando "\r"
      
   }

   if(cbuff[0]=='\\'&&cbuff[1]=='w'){   // Comparo inicio del buffer con comando "\w"
      i=2;
      do{                               // Extraemos argumento del buffer 
         arg[i-2]=cbuff[i];             // a partir del 3er byte y hasta \0.
      }while(cbuff[++i]!=0x00);
      
      printf("Escribiendo %s ... ",arg);// Aqui lo que deseemos hacer con comando "\w"
                                        // Monitorizamos el argunmento.
   }

   inicbuff();                          // Borro buffer.

   printf("Procesado.\r\n\r\n");        // Monitorizo procesado.
}

