/////////////////////////////////////////////////////////////////////////////////////////
//
// Strings_Demo v.1.0
//
// © 28.02.2006 By RedRaven (RedPic)
//
// Para Foro Todo Pic
//
// Idioma: CCS PICC v.3.242
//
/////////////////////////////////////////////////////////////////////////////////////////

#include <16f876a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <stdlib.h>

// Constantes y definiciones ////////////////////////////////////////////////////////////

int const MAXLENBUFF=42;                         // Maxima longitud del buffer de recepción RS232
int const MAXLENCOMMAND=10;                      // Maxima longitud de un comando (sin argumentos)
int const MAXLENARG=8;                           // Maxima longitud de cada uno de los argumentos s1 y s2

// Variables Globales ///////////////////////////////////////////////////////////////////

char buffrec[MAXLENBUFF];                        // Buffer de Recepcion
int  xbuffrec=0x00;                              // índice del Buffer de Recepcion

int1 new_command=0;                              // Flag para indicar comando disponible
int1 pdte_send_prompt=0;                         // Flags para enviar echos fuera de la int_rda
int1 pdte_send_tmp_prompt=0;

char s1[MAXLENARG];                              // Argumento 1
char s2[MAXLENARG];                              // Argumento 2
char sr[MAXLENBUFF];                             // Resultado de nuestras manipulaciones de Strings

// Declaracion de Funciones /////////////////////////////////////////////////////////////

void On_reset(void);                             // Tras RESET del Micro
void Send_listen(void);                          // Monitoriza RS232 : Comienzo
void Send_opts(void);                            // Monitoriza RS232 : Presenta opciones
void Send_prompt(void);                          // Monitoriza RS232 : Presenta el Cursor
void Send_tmp_prompt(void);                      // Monitoriza RS232 : Presenta el Cursor y el comando actual
void Ini_buffrec(void);                          // Borra el buffer de recepción
void Add_buffrec(char c);                        // Añade un caracter al buffer de recepción
void Procesa_comando(void);                      // Procesado de comandos


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

// INTERRUPCION RDA - Recepción USART -

#int_rda
void serial_isr() {
   if(kbhit()){                                  // Si hay algo pendiente de recibir ...
      Add_buffrec(getc());                       // lo recibo y lo añado al Buffer de Recepcion
   }
}

// Control del Buffer de recepcion ---------------------------------------

void Ini_buff_rec(void){                         // Inicia a "\0" el Buffer de Recepcion

   int i;
   for(i=0;i<MAXLENBUFF;i++){                    // Bucle que pone a 0 todos los
      buffrec[i]=0x00;                           // caracteres en el Buffer de Recepcion
   }
   xbuffrec=0x00;                                // Inicializo el indice de siguiente caracter recibido
}

void Add_buffrec(char c){                         // Añade caracter al Buffer de Recepcion

      switch(c){
         case 0x0D:                              // [Enter] -> Habilita Flag para procesar comando en Main
            buffrec[xbuffrec++]=' ';             // Añade un espacio en blanco al final y ...
            new_command=1;                       // Habilita Flag para procesar comando en Main
            break;
         case 0x08:                              // [Del]   -> Borra último caracter del Buffer
            if(xbuffrec>0){                      //            Si hay algo en el buffer
               buffrec[--xbuffrec]=0x00;         //            decremento el índice, escribo un cero y ...
               pdte_send_tmp_prompt=1;           //            habilito flag para refrescar el prompt
            }
            break;
         case 0x01B:                             // [Esc]   -> Borra el Buffer completamente y ...
            Ini_buff_rec();                      //            habilito flag para refrescar el prompt
            pdte_send_prompt=1;
            break;
         case 0x009:                             // [Tab]   -> Refresca el prompt y el comando tal como esté
            pdte_send_tmp_prompt=1;
            break;
         default:
            buffrec[xbuffrec++]=c;               // Añade caracter recibido al Buffer
            putc(c);                             // y lo monitorizo
      }
}

// Rutinas y Funciones de RROS ///////////////////////////////////////////

void On_reset(void){                             // Inicializacion del Micro tras RESET

	disable_interrupts(GLOBAL);	                // todas las interrupciones desactivadas

   delay_ms(100);

   Ini_buff_rec();                               // Inicializo Buffer de recepcion
   new_command=0;                                // Desactivo flag de comando pendiente.
   pdte_send_prompt=0;                           // Desactivo Flags para enviar echo fuera de la int_rda
   pdte_send_tmp_prompt=0;

   enable_interrupts(int_rda);                   // interrupcion RDA habilitada
   enable_interrupts(global);	                   // todas las interrupciones activadas

   Send_listen();                                // Presenta Comienzo
   Send_prompt();                                // Presenta el Cursor

}

void Send_listen(void){                          // Presenta Comienzo

   printf("\r\nStrings Demo v1.0");
   Send_opts();
}

void Send_opts(void){                            // Relación de comandos válidos

   printf("\r\n\n");
   printf("[?] ver comandos válidos\r\n");
   printf("[strcat ABC abc] añade s2=abc a s1=ABC\r\n");
   printf("[strlwr ABC] convierte ABC a minúsculas\r\n");
   printf("[strstr ABC abc] busca s2=abc dentro de s1=ABC\r\n");

}

void Send_prompt(void){                          // Presenta el cursor

   printf("\r\n>");
}

void Send_tmp_prompt(void){                      // Presenta el cursor con el comando actual

   printf("\r>%s",buffrec);
}

// MAIN Programa Principal ///////////////////////////////////////////////

void main(void)
{
   On_reset();

   do {

      // Deteccion de la necesidad de procesar comandos pendientes ///////
      if(new_command==1){                        // Si hay un nuevo comando ...
         new_command=0;                          // deshabilito el aviso y ...
         Procesa_comando();                      // Procesado de comandos
         Ini_buff_rec();                         // inicializo todo para nuevo comando y ...
         pdte_send_prompt=1;                     // mando prompt.
      }

      // Deteccion de la necesidad de enviar echos ///////////////////////
      if(pdte_send_prompt==1){                   // Si esta pendiente de enviar prompt ... 
         pdte_send_prompt=0;                     // marco que ya no lo está y ...
         Send_prompt();                          // lo envío.
      }
      if(pdte_send_tmp_prompt==1){               // Si esta pendiente de enviar prompt temporal ... 
         pdte_send_tmp_prompt=0;                 // marco que ya no lo está y ...
         Send_tmp_prompt();                      // lo envío.
      }

  	} while(TRUE);
}

// Funciones necesarias ... //////////////////////////////////////////////

int extrae_argumentos(int cuantos){

   int i,c;
   int error=0;                                  // Para devolver código de error si se da el caso
   char *ptri;
   char *ptrf;
   
   for(i=0;i<MAXLENARG;i++){                     // Bucle que pone a 0 todos los
      s1[i]='\0';                                // caracteres en s1 y s2 antes de extraer
      s2[i]='\0';
   }

   c=1;
   for(i=0;i<MAXLENBUFF;i++){                    // Bucle que marca los separadores " " (espacios)
      if(buffrec[i]==' '){                       // en el buffer de recepción
         buffrec[i]=c++;                         // escribiendo 0x01 en el primero, 0x02 en el segundo ... etc.
      }                                          // con lo que s1 estará entre 0x01 y 0x02 y ...
   }                                             // s2 estará entre 0x02 y 0x03.

   if(cuantos==1){                               // Si necesito dos argumentos y ...
      if(c!=3){                                  // Error: tengo menos o mas de un argumento
         error=1;                                // ya que hemos puesto un numero distinto a 2 de marcas
         goto retorno;                           // observa que para 2 marcas c vale 3
      }
   }
   if(cuantos==2){                               // Si necesito dos argumentos y ...
      if(c!=4){                                  // Error: tengo menos o mas de dos argumentos
         error=1;                                // ya que hemos puesto un numero distinto a 3 de marcas
         goto retorno;                           // observa que para 3 marcas c vale 4
      }
   }

   ptri=strchr(buffrec,0x01);                    // obtengo el puntero donde aparece 0x01
   ptrf=strchr(buffrec,0x02);                    // obtengo el puntero donde aparece 0x02
   if(ptri!=0 && ptrf!=0){                       // Si he encontrado 0x01 y 0x02
      ptri+=1;                                   // avanzo 1 ptri para saltarme 0x01
      strncpy(s1,ptri,ptrf-ptri);                // Luego s1 lo extraigo entre ptri y ptrf
   }

   if(cuantos==1){                               // Si solo necesito un argumento he terminado
      goto retorno;
   }

   ptri=strchr(buffrec,0x02);                    // obtengo el puntero donde aparece 0x02
   ptrf=strchr(buffrec,0x03);                    // obtengo el puntero donde aparece 0x03
   if(ptri!=0 && ptrf!=0){                       // Si he encontrado 0x01 y 0x02
      ptri+=1;                                   // avanzo 1 ptri para saltarme 0x02
      strncpy(s2,ptri,ptrf-ptri);                // Luego s2 lo extraigo entre ptri y ptrf
   }

retorno:

   return(error);
} 

// Procesa_comando: Hace cosas o manda hacerlas ... //////////////////////

void Procesa_comando(void){

   int1 procesado_ok=0;                          // Flag para comprobar si he procesado algo válido
   char xcommand[MAXLENCOMMAND];                 // Comprobador de comando recibido
   int  error;
   char *ptrx;

   // COMANDO = "" intro en blanco ---------------------------------------
   strcpy(xcommand,"");
   if(!strcmp(buffrec,xcommand)){
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "?" ------------------------------------------------------
   strcpy(xcommand,"?");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      Send_opts();
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "strcat" -------------------------------------------------
   strcpy(xcommand,"strcat");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      error=extrae_argumentos(2);
      if(error!=0){
         printf("\r\nError: numero erróneo de argumentos");
      }
      else{
         strcpy(sr,s1);
         strcat(sr,s2);
         printf("\r\n\n%s + %s = %s\r\n",s1,s2,sr);
      }
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "strlwr" -------------------------------------------------
   strcpy(xcommand,"strlwr");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      error=extrae_argumentos(1);
      if(error!=0){
         printf("\r\nError: numero erróneo de argumentos");
      }
      else{
         strcpy(sr,s1);
         strlwr(sr);
         printf("\r\n\n%s -> %s\r\n",s1,sr);
      }
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "strstr" -------------------------------------------------
   strcpy(xcommand,"strstr");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      error=extrae_argumentos(2);
      if(error!=0){
         printf("\r\nError: numero erróneo de argumentos");
      }
      else{
         strcpy(sr,s1);
         ptrx=strstr(sr,s2);
         if(ptrx==0){
            printf("\r\n\n%s no está en %s\r\n",s2,s1);
         }
         else{
            printf("\r\n\n%s empieza en el caracter %uº de %s\r\n",s2,(ptrx-&sr[0])+1,s1);
         }
      }
      procesado_ok=1;
      goto fin_procesa;
   }
fin_procesa:

   // COMANDO ERRÓNEO - ¿ezo qué é lo que é ?-----------------------------
   if(procesado_ok==0){
      printf("\r\n?%s",buffrec);
   }
}

