/////////////////////////////////////////////////////////////////////////////////////////
//
// RROS para RRBOARD1 : SRF04 Test
//
// © 18.03.2006 By RedRaven
//
// Hardware: PIC16F628
//
//           RA0      SRF04 Input Echo
//           RA1      SRF04 Trigger
//           RA2,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 <16f628a.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B1)

#include <stdlib.h>

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

#define SRF04_PORT_TRIGGER PIN_A1                // Pin usado para el pulso de Disparo 
#define SRF04_PORT_ECHO    PIN_A0                // Pin usado para recibir el eco ultrasónico

#define TIME_TRIGGER_uS  10                      // Longitud del pulso de disparo 10 uS (microsegundos)
#define TIME_NEXT_TRIGGER_mS 10                  // Espacio entre echo y siguiente disparo 10 mS (milisegundos)
#define MAX_ECHO_RESPONSE_Ticks 35000            // Maximo tiempo de espera del eco en Ticks de Timer1 (35 ms)
#define CALC_DISTANCE(t) (t / 58)                // Convierte de Ticks a distancia
#define DISTANCE_INFINITE (0xffff)               // Distancia infinita, no hay obstaculo en el rango de medida


// De RROS

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 ///////////////////////////////////////////////////////////////////

long echo_delay;
long distance = DISTANCE_INFINITE;

// De RROS

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
void Procesa_comando(void);                      // Procesado de comandos

void realiza_medida(void);                       // Realiza una medida completa

// 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);

   output_low(SRF04_PORT_TRIGGER);               // A bajo el pin del disparador
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);     // Timer1 con preescaler 1:1

   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_opts();                                  // Presenta Comienzo
   Send_prompt();                                // Presenta el Cursor

}

void Send_listen(void){                          // Presenta Comienzo

   printf("SRF04 Ultrasonic Ranger Test\r\n\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("[r] realiza una medición\r\n\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){
         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 realiza_medida(void){

  delay_ms(TIME_NEXT_TRIGGER_mS);                // Espero para asegurarme que hay espacio entre eco y disparo
  output_high(SRF04_PORT_TRIGGER);               // Envío el pulso de disparo
  delay_us(TIME_TRIGGER_uS);                     // espero el ancho de pulso requerido
  output_low(SRF04_PORT_TRIGGER);                // termino el pulso
  for ( ; !input(SRF04_PORT_ECHO); );            // Espero el inicio del pulso del eco (flanco de subida) 
  set_timer1(0);                                 // Cuando llegue pon a cero el Timer1
  for ( ; input(SRF04_PORT_ECHO); );              // Espero al final del pulso del eco (flanco de bajada) 
  echo_delay = get_timer1();
  if (echo_delay >= MAX_ECHO_RESPONSE_Ticks){
    distance = DISTANCE_INFINITE;
  }
  else {
    distance = CALC_DISTANCE(echo_delay);
  }
}

// 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 = "r" ------------------------------------------------------
   strcpy(xcommand,"r");
   if(!strncmp(buffrec,xcommand,strlen(xcommand))){
      realiza_medida();
      printf(" -> %lu cm (%lu) \r\n",distance,echo_delay);
      procesado_ok=1;
      goto fin_procesa;
   }

fin_procesa:

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

}

