/////////////////////////////////////////////////////////////////////////////////////////
//
// RROS para RRBOARD1 v.2.0
//
// © 26.02.2006 By RedRaven
//
// Hardware: PIC16F628
//
//           RA0..RA3 Leds
//           RB1      USART RX
//           RB2      USART TX
//           RB5      Buzzer Driver
//           RB6,RB7  ICSP
//
//           Xtal Ext. 4.00 Mhz
//
// Idioma: CCS PICC v.3.242
//
//
/////////////////////////////////////////////////////////////////////////////////////////

#include <16f628.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=19200, xmit=PIN_B2, rcv=PIN_B1)

#include <stdlib.h>

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

int const MAXLENBUFF=24;                         // Maxima longitud de los bufferes
int const MAXLENCOMMAND=12;                      // Maxima longitud de un comando (sin argumentos)
int const NUMPAGSEEPROM=7;                       // Numero de paginas (de 16 bytes) de la EEPROM interna

// 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 echo fuera de la int_rda
int1 pdte_send_tmp_prompt=0;
char xcommand[MAXLENCOMMAND];                    // Comprobador de comando recibido

// 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
int  Extrae_arg_hex(char tipo, int lenarg);      // Extrae del comando el valor hex tras -tipo
int  aschex2int(char d);                         // Convierte un caracter ascii a hex
void Procesa_comando(void);                      // Procesado de comandos
void Vuelca_EEPROM(void);                        // Vuelca el contenido de la EEPROM
void Rellena_EEPROM(int x);                      // Rellena toda la EEPROM con x
void Write_port(int port, int valor);            // Pone a valor el estado del puerto port


// 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
            new_command=1;
            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);

   // Hardware específico /////////////////////////
 	output_low(PIN_A0);                           // RA0..RB3 a 0
 	output_low(PIN_A1);
 	output_low(PIN_A2);
 	output_low(PIN_A3);
 	output_low(PIN_B5);                           // RB5 a 0
   ////////////////////////////////////////////////

   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("RR.PIC.OS v2.0\r\n\n");
   printf("? for valid commands\r\n");
}

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

   printf("\r\n\n");
   Send_listen();
   printf("\n");
   printf("[?] comandos válidos\r\n");
   printf("[eedump] contenido de eeprom\r\n");
   printf("[eeread -dDD] lee byte en dir DDh\r\n");
   printf("[eewrite -dDD -bBB] escribe byte BBh en dir DDh\r\n");
   printf("[eefill -bBB] eeprom a BBh\r\n");
   printf("[setport -pX -bBB] escribe byte BBh en puerto X\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);
}

int Extrae_arg_hex(char tipo, int lenarg){       // Extrae del comando el valor hex tras -tipo

   char cc[3], *ptr, Hex[3]="\0";                // Variables necesarias para extraer direccion de buffrec
   int  r=0;


   strcpy(cc,"-X");                              // Compongo identificador de argumento para extraerlo
   cc[1]=tipo;

   ptr=strstr(buffrec,cc);                       // Obtengo puntero de donde comienza "-X" dentro de buffrec
   if(!ptr==0){                                  // Si realmente existe "-X" dentro de buffrec ...
      ptr+=2;                                    // avanzo el puntero 2 posiciones para saltarme "-X" y ...
      strncpy(Hex,ptr,lenarg);                   // copio el trozo siguiente a Hex ...
      Hex[lenarg]='\0';                          // y lo finalizo con '\0' para obterner Hex="DD\0".
      if(lenarg>1){
         r =(16*aschex2int(Hex[0]));             // Convierto de Hex Ascii 1 ó 2 digitos
         r+=(aschex2int(Hex[1]));
      }
      else{
         r=(aschex2int(Hex[0]));
      }
   }
   return(r);
}

int aschex2int(char d){                          // Convierte un caracter ascii a hex

   int r=0;

   if(isxdigit(d)){                              // Si es un digito hexadecimal ...
      if(isdigit(d)){                            // si es un digito decimal ...
         r=d-'0';                                // devuelvo su diferencia con el valor ascii del caracter '0'
      }
      if(isalpha(d)){                            // si es alfanumerico ...
         d=toupper(d);                           // lo paso a mayusculas y ...
         r=10+(d-'A');                           // devuelvo 10 mas su diferencia con el valor ascii de la letra 'A'
      }
   }
   return(r);
}

// 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){
         pdte_send_prompt=0;
         Send_prompt();
      }
      if(pdte_send_tmp_prompt==1){
         pdte_send_tmp_prompt=0;
         Send_tmp_prompt();
      }

  	} while(TRUE);
}

// Funciones de Comando //////////////////////////////////////////////////

void Vuelca_EEPROM(void){                        // Vuelca el contenido de la EEPROM

   int i,j;

   printf("\r\n\n** ");                          // Pongo cabecera de direcciones
   for(i=0;i<16;i++) printf("%X ",i);
   printf("\r\n");
   for(i=0; i<=NUMPAGSEEPROM; ++i) {             // Vuelco contenido paginado
      printf("%2x ",i*16);
      for(j=0; j<=15; ++j) {
         printf( "%2x ", read_eeprom( i*16+j ) );
      }
      printf("\n\r");
   }
}

void Rellena_EEPROM(int x){                      // Rellena toda la EEPROM con x

   int i,j;

   for(i=0; i<=NUMPAGSEEPROM; ++i) {             // Escribo toda la eeprom
      for(j=0; j<=15; ++j) {
         write_eeprom(i*16+j,x);
      }
   }
}

void Write_port(int port, int valor){            // Pone a valor el estado del puerto port

   switch(port){
      case(10): output_a(valor);                 // Puerto A
                break;
      case(11): output_b(valor);                 // Puerto B
                break;
      default:
         printf("\r\nPort %1X?",port);
   }
}

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

void Procesa_comando(void){

   int1 procesado_ok=0;
   int waddress, wbyte;

   // 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 = "setport" - saca un byte por un puerto -------------------
   strcpy(xcommand,"setport");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      waddress=Extrae_arg_hex('p',1);
      wbyte=Extrae_arg_hex('b',2);
      Write_port(waddress,wbyte);
      printf("\r\n%2x->%1X Ok",wbyte,waddress);
      procesado_ok=1;
      goto fin_procesa;
   }

   // COMANDOS EEPROM ////////////////////////////////////////////////////

   // COMANDO = "eedump" - vuelca contenido de eeprom -----------------------
   strcpy(xcommand,"eedump");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      Vuelca_EEPROM();
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "eeread" - lee una posicion de la eeprom --------------------
   strcpy(xcommand,"eeread");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      waddress=Extrae_arg_hex('d',2);
      wbyte=read_eeprom(waddress);
      printf("\r\nd%2x==b%2x",waddress,wbyte);
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "eewrite" - escribe una posicion de la eeprom ----------------
   strcpy(xcommand,"eewrite");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      waddress=Extrae_arg_hex('d',2);
      wbyte=Extrae_arg_hex('b',2);
      write_eeprom(waddress,wbyte);
      printf("\r\n%2x->%2x Ok",wbyte,waddress);
      procesado_ok=1;
      goto fin_procesa;
   }
   // COMANDO = "eefill" - rellena la eeprom a un valor ---------------------
   strcpy(xcommand,"eefill");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      wbyte=Extrae_arg_hex('b',2);
      Rellena_EEPROM(wbyte);
      procesado_ok=1;
      goto fin_procesa;
   }

fin_procesa:

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

