/******************************************************************************
* 
* Librería para el manejo de la memoria 24LC64 con protocolo i2c. Por 
* defecto se usa el HW i2c del Micro, pero se puede configurar en modo SW
* en cualquier micro modificando los #define.
*
* Programador: Pandemonium.
* Compilador: CCS C.
*
* #defines:
*
* USE_I2C_HW: indica al compilador que se usará i2c hardware
*
* USE_I2C_SW: se emulará i2c por software a través de los pines definidos
*
* EEPROM_SDA: si no se define en el archivo de cabecera, se configura por
* defecto el PIN_B1
*
* EEPROM_SDA: si no se define en el archivo de cabecera, se configura por
* defecto el PIN_B0
*
* WRITE_BUFFER: si se define en la cabecera, se compilará el código para
* la escritura a la memoria por búffer de pagina de 32 bytes. Esto causará
* que la escritura de 32 bytes se demoren igual que escribir uno sólo con
* el método normal (sin EEPROM_WRITE_BUFFER definido) y también se habilitará
* la activación para la compilacion de las funciones "save_eeprom" y 
* "erase_eeprom"
* 
* READ_BUFFER: si se define en la cabecera, se compilará el código para la
* lectura de la memoria en secuencia a la cantidad de bytes definida
* en EEPROM_READ_BUFFER. También habilita la compilación de la función
* "load_eeprom" Nota: Se debe tener en cuenta que al definir esta función se
* tiene el espacio para el búffer de recepción definido a través de
* EEPROM_READ_BUFFER
*
* EEPROM_READ_BUFFER: define la cantidad de bytes para el búffer de recepción
* de datos en la lectura secuencial de la memoria. Si READ_BUFFER no se ha
* invocado en la cabecera, EEPROM_READ_BUFFER no tendrá efecto en la compilación 
*
* EEPROM_WRITE_BUFFER: es el tamaño máximo definido para las páginas de la
* memoria. 24LC64=32. No modificar este número para esta memoria.
* 
* Funciones:
*
* init_ext_eeprom(): configura los pines definidos para la comunicación i2c
* 
* write_ext_eeprom(addr_page, data[]): Si se ha invocado WRITE_BUFFER en la
* cabecera, esta función guardará el contenido del buffer "data" en la memoria
* en secuencia de 32 bytes por página, sino; guarda un byte de dato en la
* dirección "addr_page", NOTA: para la escritura por paginación se sugiere
* direccionar con múltiplos de 32 bytes (tamaño de las páginas en la 24LC64)
* Ej: addr_page = 0, 32, 64, 96, 128, etc.
*
* save_eeprom(addr_page, *data): Esta función permite escribir una cadena de
* cualquier tamaño a la dirección de la página (addr_page) de la memoria. Se
* encarga además de partir la cadena en bloques de 32 bytes y administrarlos
* a la funcion "write_ext_eeprom", de esta forma; se podrá escribir datos en
* la memoria de tamaño inferior o superior a 32 bytes. Esta función sólo será
* compilada si se ha invocado en la cabecera a WRITE_BUFFER
*
* erase_eeprom(addr_page): Esta función borra la página en la dirección
* "addr_page" especificada. Si en el parámetro se escribe "ERASE_ALL", será
* implementado el borrado completo de la memoria iniciandose en la dirección 0
* (cero). Esta función sólo será compilada si se ha invocado en la cabecera
* WRITE_BUFFER
*
* read_ext_eeprom(address): Si se ha invocado READ_BUFFER en la cabecera, esta
* función cargará la cantidad de bytes definidos en EEPROM_READ_BUFFER en el
* buffer "buffer_read[]", iniciando en la dirección "address". si no se ha
* invocado EEPROM_READ_BUFFER, solamente retorna un byte leido en la dirección
* "address"
*
* load_eeprom(address): Limpia el búffer "buufer_read" y carga los nuevos datos
* en este apuntados desde la dirección "address". Esta función sólo será
* compilada si se ha invocado en la cabecera a READ_BUFFER
*******************************************************************************/

#if defined(USE_I2C_HW)
 #use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL, force_hw)
#elif defined(USE_I2C_SW)
 #use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL)
#else
 #error Se debe definir el bus i2c. "I2C_HW" o "I2C_SW"
#endif

#if defined(WRITE_BUFFER)
 #undef WRITE_BUFFER
 #define WRITE_BUFFER
#else
 #define WRITE_SIMPLE
#endif

#if defined(READ_BUFFER)
 #undef READ_BUFFER
 #define READ_BUFFER
 #ifndef EEPROM_READ_BUFFER
 #define EEPROM_READ_BUFFER 33
 #endif
#else
 #define READ_SIMPLE
#endif

#ifndef EEPROM_SDA
#define EEPROM_SDA  PIN_B1
#endif
#ifndef EEPROM_SCL
#define EEPROM_SCL  PIN_B0
#endif
#define EEPROM_WRITE_BUFFER 33
#define EEPROM_SIZE   8192
#define ERASE_ALL 1


void init_ext_eeprom(){
   output_FLOAT(EEPROM_SCL);
   output_FLOAT(EEPROM_SDA);
}


#if defined(WRITE_SIMPLE)
void write_ext_eeprom(long int addr_page, char data){
   short int status;
   int addrL, addrH;
#eLse
void write_ext_eeprom(long int addr_page, char data[EEPROM_WRITE_BUFFER]){
   short int status;
   int addrL, addrH, i, longitud; 
   for(longitud=0; data[longitud]!='\0'; longitud++);  
#endif
   addrH = (int)(addr_page>>8)&0x1F;
   addrL = (int)(addr_page); 
   i2c_start();
   i2c_write(0xa0);
   i2c_write(addrH);
   i2c_write(addrL);
#if defined(WRITE_SIMPLE)   
   i2c_write(data);
#else
  if(longitud<=32)
   for(i=0; i<longitud; i++)
    i2c_write(data[i]);
  else
   for(i=0; i<32; i++)
    i2c_write(data[i]);
#endif    
   i2c_stop();
   i2c_start();
   status=i2c_write(0xa0);
   while(status==1){
    i2c_start();
    status=i2c_write(0xa0);
   }
   i2c_stop();
}

#if defined(WRITE_BUFFER)
void save_eeprom(long int addr_page, char *data)
{
 long int i, j, k;
 char dato[EEPROM_WRITE_BUFFER];
 
 k=0;
 j=0;
 do{
  for(i=0; i<EEPROM_WRITE_BUFFER; i++)
   dato[i]='\0';
  i=0;
  while(i<(EEPROM_WRITE_BUFFER-1)){
   dato[i]=data[j];
   i++;
   j++;
   if(data[j]=='\0')
    break;
  }
  write_ext_eeprom(addr_page+k, dato);
  k+=i;
  }while(data[j]!='\0');
} 

void erase_eeprom(long int addr_page){
 char dato[EEPROM_WRITE_BUFFER];              
 long int i;
 for(i=0; i<EEPROM_WRITE_BUFFER-1; i++)
  dato[i] = 0xFF;
  
 if(addr_page==ERASE_ALL){
  i=0;
  while(i<EEPROM_SIZE){
   write_ext_eeprom(i, dato);
   i+=EEPROM_WRITE_BUFFER-1;
  }
 }
 else
  write_ext_eeprom(addr_page, dato);
}
#endif

#if defined(READ_SIMPLE)
char read_ext_eeprom(long int address){
 char data;
 int addrL, addrH;
#else
char buffer_read[EEPROM_READ_BUFFER];
void read_ext_eeprom(long int address){
 long int i;
 int addrL, addrH;
#endif 
  addrH = (int)(address>>8)&0x1F;
  addrL = (int)(address);
  i2c_start();
  i2c_write(0xa0);
  i2c_write(addrH);
  i2c_write(addrL);
  i2c_start();
  i2c_write(0xa1);
#if defined(READ_SIMPLE)
  data=i2c_read(0);
  i2c_stop();
  return(data);
#else
 for(i=0; i<EEPROM_READ_BUFFER-1; i++)
  buffer_read[i] = i2c_read(1);
 buffer_read[i]=i2c_read(0); 
 i2c_stop();
#endif 
}

#if defined(READ_BUFFER)
void load_eeprom(long int address){
 int i;
 
 for(i=0; i<EEPROM_READ_BUFFER; i++)
  buffer_read[i]='\0';
 read_ext_eeprom(address);
}
#endif
/******************************************************************************/
