/****************************************************************************

      i2c16.c         (optimized version to minimize code size)
      v1.0 (22/04/2003)

      i2c protocol with 16 bits address memory acces
      Library for HI-TECH PIC C - master mode only.
      Optimized version to reduce code size
      Supported divices: 24xx32, 24xx64, 24xx65, 24xx128, 24xx256

      This library use i2c library for low level I/O.

      Written by Philippe Corbes <philippe.corbes@laposte.net>
      This code is free for personal use. 
      You need my agreement for a commercial use. 


  ****************************************************************************/

  #include <pic.h>
  #include "delay.h"
  #include "i2c.h"
  #include "i2c16.h"

  //Global struct for I2C link
  struct I2C16  i2c16 ;



  /*
   *  Start a transaction, select a component and init Address
   *
   *  Input:  - i2c16.component
   *          - i2c16.address
   *  Output: update i2c16.error
   *          - I2C_BUSY on Line busy by an other node
   *          - I2C_ERROR on bus error
   *          - I2C_ACK_TIMEOUT if no ack received eq no ack 
  */
  void
  i2c16_start(void)
  {
      if ((i2c16.error = i2c_start()) == I2C_OK)
          if ((i2c16.error = i2c_write(i2c16.component)) == I2C_OK)
              if ((i2c16.error = i2c_write(i2c16.address>>8)) == I2C_OK)
                  i2c16.error = i2c_write(i2c16.address);
  }


  /*
   *  Read a byte from the slave and acknowledges the transfer
   *
   *  Input:  - i2c16.component
   *          - i2c16.address
   *  Output: update i2c16.error
   *          - the byte if no error
   *          - I2C_BUSY on Line busy by an other node
   *          - I2C_ERROR on bus error
   *          - I2C_ACK_TIMEOUT on ack timeout
   */
  void
  i2c16_read(void)
  {
      i2c16_start();
      if (i2c16.error == I2C_OK) {
          if ((i2c16.error = i2c_repStart()) == I2C_OK) {
              if ((i2c16.error = i2c_write(i2c16.component + 1)) == I2C_OK) {
                  i2c16.error = i2c_read(I2C_LAST);
              }
          }
          i2c_stop();
      }
  }

  /*
   *  Write specified data byte in i2c device 
   *
   *  Input:  - i2c16.component
   *          - i2c16.address
   *  Output: update i2c16.error
   *          - I2C_OK if ack received from slave
   *          - I2C_BUSY on Line busy by an other node
   *          - I2C_ERROR on bus error
   *          - I2C_ACK_TIMEOUT on ack timeout
   */
  void
  i2c16_write(    unsigned char   abyte )
  {
      i2c16_start();
      if (i2c16.error == I2C_OK) {
          i2c16.error = i2c_write(abyte);
          i2c_stop();
          DelayMs(I2C_EEPROM_UPDATE);
      }
  }


  /*
   *  Read a numbrer of bytes and strore them at '*data'
   *  The number of bytes to read is specified by 'length'
   *
   *  Input:  - i2c16.component
   *          - i2c16.address
   *  Output: update i2c16.error
   *          - the lastbyte if no error
   *          - I2C_ERROR on bus error
   *          - I2C_BUSY on Line busy by an other node
   *          - I2C_ACK_TIMEOUT if no ack received eq no ack 
   */
  void
  i2c16_read_seq( unsigned char   length,
                  unsigned char   *abyte)
  {
      i2c16_start();
      if (i2c16.error == I2C_OK) {
          if ((i2c16.error = i2c_repStart()) == I2C_OK) {
              i2c16.error = i2c_write(i2c16.component+1);

              // read with acnowledge to signal we desire additionnal data
              length -=1;
              while(((length--) > 0) && (i2c16.error >= I2C_OK)) {
                  if ((i2c16.error = i2c_read(I2C_MORE)) >= I2C_OK) {
                      *abyte++ = i2c16.error;
                  }
              }

              if (i2c16.error >= I2C_OK) {
                  // read with no ack to signal this is the last data
                  if ((i2c16.error = i2c_read(I2C_LAST)) >= I2C_OK) {
                      *abyte = i2c16.error;
                  }
              }
          }
          i2c_stop();
      }
  }

  /*
   *  Write a numbrer of bytes from '*data' to the i2c component
   *  The number of bytes to write is specified by 'length'
   *
   *  Input:  - i2c16.component
   *          - i2c16.address
   *  Output: update i2c16.error
   *          - I2C_OK if ack received from slave
   *          - I2C_BUSY on Line busy by an other node
   *          - I2C_ERROR on bus error
   *          - I2C_ACK_TIMEOUT on ack timeout
   */
  void
  i2c16_write_seq(unsigned char   length,
                  unsigned char   *abyte)
  {
      i2c16_start();
      while(((length--) > 0) && (i2c16.error >= I2C_OK))
          i2c16.error = i2c_write(*abyte++);
      i2c_stop();
      DelayMs(I2C_EEPROM_UPDATE);
  }