/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    GKI_i2c.c
* Description:  I2C_Driver_BitBang
*               Note -- This source is for reference only
*
* Copyright (c) 2016 Amped'RF Inc. All rights reserved.
*******************************************************************************/
#include "SDK_Common.h"
#include "GKI_lib.h"


#define io_SCL      io_I2C_SCL
#define io_SDA      io_I2C_SDA
#define SCL_H       GKI_io_WriteBit(io_SCL, 1)
#define SCL_L       GKI_io_WriteBit(io_SCL, 0)
#define SDA_H       GKI_io_WriteBit(io_SDA, 1)
#define SDA_L       GKI_io_WriteBit(io_SDA, 0)
#define SCL_read    GKI_io_ReadBit(io_SCL)
#define SDA_read    GKI_io_ReadBit(io_SDA)



extern u16 io_I2C_SCL, io_I2C_SDA;
extern void TM_usDelay(uint32 usDelay);
extern void TM_print(char *fmt, ...);
extern void TM_printlf(char *fmt, ...);
extern void TM_printflush(void);

//====================================================
void Print_I2C_Data(uint8 pBuff[],uint16 length)
{
    TM_print("Print I2C Data:");
    for(uint16 i=0;i<length;i++)
    {
        TM_print("  %2x ", pBuff[i]);
    }
    TM_printlf("");
    TM_printflush();
}
void I2C_WaitUS(uint32 us)
{

    TM_usDelay(us);
}

#ifdef I2C_TEST

    void I2C_Rate_Test(uint8 delay)
    {
        uint8 i=10;
        while(i)
        {
           SDA_H;
           I2C_WaitUS(delay);
    	   SCL_H;
           I2C_WaitUS(delay);
           SDA_L;
           I2C_WaitUS(delay);
           SCL_L;
           I2C_WaitUS(delay);
           i--;
        }
    }
#endif




//-----------------------------------------------------------------
//-----------------------------------------------------------------
void I2C_GPIO_Config(void)
{
    static bool initialized=false;

    if (!initialized)
    {
        GKI_io_Config(io_SCL, GKI_IO_OUT_OD | GKI_IO_Speed_50MHz);
        SCL_H;
        GKI_io_Config(io_SDA, GKI_IO_OUT_OD | GKI_IO_Speed_50MHz);
        SDA_H;
        initialized = true;
    }
}







/*
void I2C_WaitMS(uint32 ms)
{

   uint32 tm=GKI_rtc_GetCounter() + TM_TICKS_PER_SECOND*ms/1000;//maybe it is error
    while (GKI_rtc_GetCounter()<tm)
        ;
}
*/



static
BOOL I2C_Start(void)
{

	SDA_H;
    I2C_WaitUS(I2C_START_DELAY_TIME);
	SCL_H;
	I2C_WaitUS(I2C_START_DELAY_TIME);
	if(!SDA_read)return False;	//SDA?????????,??
	SDA_L;
	I2C_WaitUS(I2C_START_DELAY_TIME);
	if(SDA_read) return False;	//SDA??????????,??
	SDA_L;
	I2C_WaitUS(I2C_START_DELAY_TIME);
	return True;
}

static
void I2C_Stop(void)
{
	SCL_L;
	I2C_WaitUS(I2C_STOP_DELAY_TIME);
	SDA_L;
	I2C_WaitUS(I2C_STOP_DELAY_TIME);
	SCL_H;
	I2C_WaitUS(I2C_STOP_DELAY_TIME);
	SDA_H;
	I2C_WaitUS(I2C_STOP_DELAY_TIME);

}

static
void I2C_Ack(void)
{
	SCL_L;
	I2C_WaitUS(I2C_ACK_DELAY_TIME);
	SDA_L;
	I2C_WaitUS(I2C_ACK_DELAY_TIME);
	SCL_H;
	I2C_WaitUS(I2C_ACK_DELAY_TIME);
	SCL_L;
	I2C_WaitUS(I2C_ACK_DELAY_TIME);
}

static
void I2C_NoAck(void)
{
	SCL_L;
	I2C_WaitUS(I2C_NO_DELAY_TIME);
	SDA_H;
	I2C_WaitUS(I2C_NO_DELAY_TIME);
	SCL_H;
	I2C_WaitUS(I2C_NO_DELAY_TIME);
	SCL_L;
	I2C_WaitUS(I2C_NO_DELAY_TIME);
}

static
BOOL I2C_WaitAck(void) 	 //???:=1?ACK,=0?ACK
{
    SCL_L;  // 1
    I2C_WaitUS(I2C_WAIT_ACK_DELAY_TIME);
    SDA_H;	// 2
    I2C_WaitUS(I2C_WAIT_ACK_DELAY_TIME);
    SCL_H; // 3
    I2C_WaitUS(I2C_WAIT_ACK_READ_DELAY_TIME);
    if(SDA_read)
    {
        I2C_WaitUS(I2C_WAIT_ACK_DELAY_TIME);
        SCL_L;
#ifdef DEBUG_I2C
        TM_printlf("I2C_WaitAck() NAK timeout");
        TM_printflush();
#endif
        return False;       // NACK
    }
    SCL_L; // 4

    return True;            // ACK
}

static
void I2C_SendByte(uint8 SendByte) //data high-->low//
{
    uint8 i=8;
    while(i--)
    {
      SCL_L;
      //I2C_WaitUS(I2C_DELAY_TIME);//double delay, delete this one.
      if(SendByte&0x80)
        SDA_H;
      else
        SDA_L;
      SendByte<<=1;
      I2C_WaitUS(I2C_DELAY_TIME);
      SCL_H;
      I2C_WaitUS(I2C_DELAY_TIME);
    }
    SCL_L;
}

static
uint8 I2C_ReceiveByte(void)  //data high-->low//
{
    uint8 i=8;
    uint8 ReceiveByte=0;

    SDA_H;
    while(i--)
    {
      ReceiveByte<<=1;
      SCL_L;
      I2C_WaitUS(I2C_READ_DELAY_TIME);
//      I2C_WaitUS(I2C_DELAY_TIME);
	  SCL_H;
//I2C_WaitUS(I2C_DELAY_TIME);
      I2C_WaitUS(I2C_READ_DELAY_TIME);
      if(SDA_read)
      {
        ReceiveByte|=0x01;
      }
    }
    SCL_L;
    return ReceiveByte;
}

//=============================================
//address:remote address
//I2C_Direction:I2C_ADDRESS_WRITE or I2C_ADDRESS_READ
//=============================================
static
uint8 I2C_Set_Address_WriteOrRead(uint8 address,uint8 I2C_Direction)
{
  if (I2C_Direction != I2C_ADDRESS_WRITE)
  {
    /* Set the address bit0 for read */
    address |= DEVICE_ADD_BIT0_Set;
  }
  else
  {
    /* Reset the address bit0 for write */
    address &= DEVICE_ADD_BIT0_Reset;
  }
  return address;

}



//only 1 byte
//??1????       ?????    ?????       ????(24c16?SD2403)
BOOL I2C_WriteByte(uint8 sendByte, uint16 writeRegisterAddress, uint8 deviceAddress)
{
    if(!I2C_Start())return False;

    deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_WRITE);
    I2C_SendByte(deviceAddress);

    if(!I2C_WaitAck()){I2C_Stop(); return False;}

    I2C_SendByte((uint8)(writeRegisterAddress & 0x00FF));

    I2C_WaitAck();
    I2C_SendByte(sendByte);

    I2C_WaitAck();

    I2C_Stop();

    //Systick_Delay_1ms(10);
    return True;
}



//I2C Communication Protoco(write)
//funcion:
//        BOOL I2C_BufferWrite(uint8* pBuffer, uint8 length,     uint16 writeRegisterAddress, uint8 deviceAddress)
//------------------------------------------
//Writing to the Coprocessor
// 1 .Send the I2C start sequence.
// 2. Send the I2C write address of the CP.
// 3. Check for an ACK from the slave; if it is not received, wait 500us and then loop back to Step 1
// 4. Send the register address at which to begin writing
// 5. Send the data bytes
// 6. Send the I2C stop sequence
//-------------------------------------------
//return:
//       True: I2C is OK.
//       False:I2C is NG.  NG: 1.I2C is busy  2."ACK" is error
//-------------------------------------------

//write data         buff address    buff length       register Address              device address(CP,e2prom)
//KLL 2011.12.30 Modify according to 2.0C CP protocol
BOOL I2C_BufferWrite(uint8* pBuffer, uint8 length,     uint16 writeRegisterAddress, uint8 deviceAddress)
{
    unsigned char NoACKcnt;
    NoACKcnt=0;
    while(1)
    {
       //1.Send the I2C start sequence
       if(!I2C_Start())return False;

       //2.Send the I2C write address of the CP.
       deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_WRITE);
       I2C_SendByte(deviceAddress);

       //3.Check for an ACK from the slave;if it is not received,wait 500us,loop back to step1
       if(!I2C_WaitAck())
          {
            I2C_Stop();
            NoACKcnt++;
            if(NoACKcnt>=5)return False;
            else
            {
              TM_usDelay(500);
              continue;    //wait for 500us,loop back tostep1
            }
          }
       else break;
    }
    //4.Send the register address at which to begin writing
    I2C_SendByte((uint8)(writeRegisterAddress & 0x00FF));   //???????
    if(!I2C_WaitAck()){I2C_Stop(); return False;}
    //5.Send the data bytes
    while(length--)
    {
      I2C_SendByte(* pBuffer);
      I2C_WaitAck();
      pBuffer++;
    }
    //6 Send the I2C stop sequence
    I2C_Stop();

    //Systick_Delay_1ms(10);
    return True;
}
/*
BOOL I2C_BufferWrite(uint8* pBuffer, uint8 length,     uint16 writeRegisterAddress, uint8 deviceAddress)
{
    if(!I2C_Start())return False;

    deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_WRITE);
    I2C_SendByte(deviceAddress);

    if(!I2C_WaitAck()){I2C_Stop(); return False;}

    I2C_SendByte((uint8)(writeRegisterAddress & 0x00FF));   //???????
    if(!I2C_WaitAck()){I2C_Stop(); return False;}

    while(length--)
    {
      I2C_SendByte(* pBuffer);
      I2C_WaitAck();
      pBuffer++;
    }
    I2C_Stop();

    //Systick_Delay_1ms(10);
    return True;
}
*/



//I2C Communication Protoco(read)
//function:
//          BOOL I2C_ReadByte(uint8* pBuffer,uint16 length, uint8 readRegisterAddress,  uint8 deviceAddress)
//-------------------------------------------------
//To read data from the coprocessor, follow these steps:
// 1.Send the I2C start sequence.
// 2.Send the I2C write address of the CP.
// 3.Check for an ACK from the slave; if it is not received, wait 500 us and then loop back to Step 1
// 4.Send the register address at which to begin reading
// 5.Optional: send the I2C stop sequence
// 6.Send the I2C start sequence
// 7.Send the I2C read address of the CP.
// 8. Check for an ACK from the slave; if it is not received, wait 500 us and then loop back to Step 6.
// 9. Read the data bytes
// 10.Send the I2C stop sequence.
//--------------------------------------------------
//return:
//       True: I2C is OK.
//       False:I2C is NG.  NG: 1.I2C is busy  2."ACK" is error
//-------------------------------------------
//??1???         ??????  ?????      ?????       ????(24c16?SD2403)
//read a buffer size

//KLL 2011.12.30 Modify according to 2.0C CP protocol
BOOL I2C_ReadByte(uint8* pBuffer,uint16 length, uint8 readRegisterAddress,  uint8 deviceAddress)
{
    //get cp address
    deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_WRITE);
    uint8 MaxCounter=4;
    // 1.Send the I2C start sequence.
    // 2.Send the I2C write address of the CP.
    // 3.Check for an ACK from the slave; if it is not received, loop back to Step 1
    // so, we loop back 4 or more

#ifdef DEBUG_I2C
    TM_printlf("deviceAddress = 0x%02x", deviceAddress);
    TM_printflush();
#endif

    for (uint8 counter=0; counter <=MaxCounter;counter++)
    {
        // 1.I2C start
        if(!I2C_Start())
        {
          return False;
        }
        // 2.send the i2c write address of the cp
        I2C_SendByte(deviceAddress);
        // 3.check ack
        if(!I2C_WaitAck())
        {
          //Check for an ACK from the slave; if it is not received, wait 500 us and then loop back to Step 1
          I2C_Stop();
          if (counter == MaxCounter)
          {
            //TM_printlf("I2C cp address fail");
            //TM_printflush();
            return False;
          }
          else
            {
              TM_usDelay(500);
              continue;
            }
        }
        else
        {
           break;
        }

    }
    // 4.Send the register address at which to begin reading.
    I2C_SendByte((uint8)(readRegisterAddress & 0x00FF));
    if(!I2C_WaitAck())
    {
      I2C_Stop();
      return False;
    }
    //5.Optional: send the I2C stop sequence.
    //I2C_Stop();

    //I2C_WaitUS(I2C_RESTART_DELAY_TIME);
    for (uint8 counter=0; counter <=MaxCounter;counter++)
    {
      //6.Send the I2C start sequence.
      I2C_Start();
      //7.Send the I2C read address of the CP
      deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_READ);
      I2C_SendByte(deviceAddress);
      //8. Check for an ACK from the slave; if it is not received, wait 500 us and then loop back to Step 6
      if(!I2C_WaitAck())
      {
        //I2C_Stop();1,each no ack has a stop
        if (counter == MaxCounter)
        {
           //TM_printlf("I2C cp address fail");
           //TM_printflush();
           return False;
        }
        else
        {
            TM_usDelay(500);
            continue;
         }
        }
        else
        {
           break;
        }
       }

    //9. Read the data bytes
    while(length)
    {
      *pBuffer = I2C_ReceiveByte();
      if(length == 1)I2C_NoAck();
      else I2C_Ack();
      pBuffer++;
      length--;
    }
    //10.Send the I2C stop sequence.
    I2C_Stop();
    return True;
}
/*
BOOL I2C_ReadByte(uint8* pBuffer,uint16 length, uint8 readRegisterAddress,  uint8 deviceAddress)
{
    //get cp address
    deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_WRITE);
    uint8 MaxCounter=2;
    // 1.Send the I2C start sequence.
    // 2.Send the I2C write address of the CP.
    // 3.Check for an ACK from the slave; if it is not received, loop back to Step 1
    // so, we loop back twice or more

    for (uint8 counter=0; counter <=MaxCounter;counter++)
    {
        // 1.I2C start
        if(!I2C_Start())
        {
          return False;
        }
        // 2.send the i2c write address of the cp
        I2C_SendByte(deviceAddress);
        // 3.check ack
        if(!I2C_WaitAck())
        {
          //Check for an ACK from the slave; if it is not received, loop back to Step 1
          I2C_Stop();
          if (counter == MaxCounter)
          {
            TM_printlf("I2C cp address fail");
            TM_printflush();
            return False;
          }
        }
        else
        {
           break;
        }

    }
    // 4.Send the register address at which to begin reading.
    I2C_SendByte((uint8)(readRegisterAddress & 0x00FF));
    if(!I2C_WaitAck())
    {
      I2C_Stop();
      return False;
    }
    //5.Optional: send the I2C stop sequence.
    //I2C_Stop();

    //I2C_WaitUS(I2C_RESTART_DELAY_TIME);
    //6.Send the I2C start sequence.
    I2C_Start();
    //7.Send the I2C read address of the CP
    deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_READ);
    I2C_SendByte(deviceAddress);
    //8. Check for an ACK from the slave; if it is not received
    if(!I2C_WaitAck())
    {
      //I2C_Stop();  // should retry step 6 after 500us

      TM_printlf("I2C_ReadByte() Ack Retry");
      TM_printflush();

      //6.Send the I2C start sequence.
      TM_usDelay(500);
      I2C_Start();
      //7.Send the I2C read address of the CP
      deviceAddress=I2C_Set_Address_WriteOrRead(deviceAddress,I2C_ADDRESS_READ);
      I2C_SendByte(deviceAddress);
      //8. Check for an ACK from the slave; if it is not received
      if(!I2C_WaitAck())
      {
        I2C_Stop();  // should retry step 6 after 500us
        return False;
      }
    }

    //9. Read the data bytes
    while(length)
    {
      *pBuffer = I2C_ReceiveByte();
      if(length == 1)I2C_NoAck();
      else I2C_Ack();
      pBuffer++;
      length--;
    }
    //10.Send the I2C stop sequence.
    I2C_Stop();
    return True;
}*/
