#include "periph_iic.h"

void IIC_DeInit(void)
{
    volatile int i;
    SYS_CTRL->SYS_RESET |= (1 << 16);
    for(i=0; i<10; i++);
    SYS_CTRL->SYS_RESET &= (~(1 << 16));
    // Clk
    *(volatile int *)(0x40000028) &= (~(1<<10));
}

void IIC_Init(IIC_InitTypeDef* IIC_InitTypeDef){
    uint32_t tmpreg = 0;	
    // Clk enable
    *(volatile int *)(0x40000028) |= (1<<10);

    IIC->IC_TX_TL = IIC_InitTypeDef->iic_tx_threshold;
    IIC->IC_RX_TL = IIC_InitTypeDef->iic_rx_threshold;
    
    if (IIC_InitTypeDef->iic_mode == IIC_MODE_MASTER){
        IIC->IC_TAR = IIC_InitTypeDef->iic_target_addr;

        if ((READ_CPU_CLOCK == READ_CPU_CLOCK_48M)){
            if(IIC_InitTypeDef->iic_speed_mode == IIC_SPEED_MODE_SS){
				tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_SS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
				IIC->IC_CON = tmpreg;
                IIC->IC_SS_SCL_HCNT = 231;  
                IIC->IC_SS_SCL_LCNT = 231;  
            }
            else if (IIC_InitTypeDef->iic_speed_mode == IIC_SPEED_MODE_FS){
				tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_FS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
				IIC->IC_CON = tmpreg;
                IIC->IC_FS_SCL_HCNT = 51;  
                IIC->IC_FS_SCL_LCNT = 51;
            }
            else{
				tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_FS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
				IIC->IC_CON = tmpreg;				
                IIC->IC_FS_SCL_HCNT = 15;  
                IIC->IC_FS_SCL_LCNT = 15;                
            }  
        }
        else{
            if(IIC_InitTypeDef->iic_speed_mode == IIC_SPEED_MODE_SS){
				tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_SS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
				IIC->IC_CON = tmpreg;
                IIC->IC_SS_SCL_HCNT = 113;  
                IIC->IC_SS_SCL_LCNT = 112;  
            }
            else{
				tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_FS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
				IIC->IC_CON = tmpreg;
                IIC->IC_FS_SCL_HCNT = 23;  
                IIC->IC_FS_SCL_LCNT = 22;
            } 
        }
    }
    else{
        tmpreg = IIC_InitTypeDef->iic_mode | IIC_SPEED_MODE_SS | IIC_InitTypeDef->iic_target_addr_mode | IIC_InitTypeDef->iic_slave_addr_mode | IIC_RESTART_EN;
        IIC->IC_CON = tmpreg;
	    IIC->IC_SAR = IIC_InitTypeDef->iic_slave_addr;
	}
}
void IIC_StructInit(IIC_InitTypeDef* IIC_InitStruct){
    IIC_InitStruct->iic_mode = IIC_MODE_MASTER;
    IIC_InitStruct->iic_rx_threshold = 5;
    IIC_InitStruct->iic_tx_threshold = 5;
    IIC_InitStruct->iic_speed_mode = IIC_SPEED_MODE_SS;
    IIC_InitStruct->iic_slave_addr_mode = IIC_SLAVE_ADDR_MODE_7BIT;
    IIC_InitStruct->iic_target_addr_mode = IIC_TARGET_ADDR_MODE_7BIT;
}

void IIC_Cmd(FunctionalState NewState)
{
  if (NewState != DISABLE)
  {
    IIC->IC_ENABLE |= ENABLE;
  }
  else
  {
   IIC->IC_ENABLE &= ~ENABLE;
  }
}

void IIC_SendByte(uint8_t data)
{
    while(IIC->IC_TXFLR > 5){} //txfifo为空将会发送stop信号
 	IIC->IC_DATA_CMD = data;
}

uint8_t IIC_MasterReceiveByte(void)
{
    IIC->IC_DATA_CMD = IIC_CMD_READ;
	while (IIC->IC_RXFLR > 0){}
	return IIC->IC_DATA_CMD;
} 

uint8_t IIC_SlaveReceiveByte(void)
{
    while (IIC->IC_RXFLR > 0){}
	return IIC->IC_DATA_CMD;
}


uint32_t IIC_MasterRecv(uint8_t * buf, uint32_t len)
{ 
    uint32_t tc = 0, rc = 0;
    // write cmd and read data
    while(tc < len){
        // check tx fifo and send cmd
        if(IIC->IC_TXFLR <= 6){
            IIC->IC_DATA_CMD = IIC_CMD_READ;
            tc ++;
        }
        // read data
        if(IIC->IC_RXFLR >= 4){
            buf[rc] = IIC->IC_DATA_CMD;
            rc++;
        }
    }
    // read remaining data
    while(rc < len){
        if(IIC->IC_RXFLR > 0){
            buf[rc] = IIC->IC_DATA_CMD;
            rc++;
        }
    }
    return rc;
}	

uint32_t IIC_SlaveRecv(uint8_t * buf, uint32_t len)
{
    uint32_t rc = 0;
    while(rc < len){
        if(IIC->IC_RXFLR > 0){
            buf[rc] = IIC->IC_DATA_CMD;
            rc++;
        }
    }
    return rc;
}


uint8_t IIC_TXFLR(void)
{
    return IIC->IC_TXFLR;
}

uint8_t IIC_RXFLR(void)
{
    return IIC->IC_RXFLR;
}

/**
 * 判断IIC标志位
 * param: Flag:
            #define IIC_FLAG_ACTIVITY 
            #define IIC_FLAG_TX_FIFO_NOT_FULL
            #define IIC_FLAG_TX_FIFO_EMPTY 
            #define IIC_FLAG_RX_FIFO_NOT_EMPTY 
            #define IIC_FLAG_RX_FIFO_FULL
            #define IIC_FLAG_MASTER_ACTIVITY 
            #define IIC_FLAG_SLAVE_ACTIVITY 
 * 
 */
FlagStatus IIC_GetUsrStatus(uint16_t Flag)
{
    FlagStatus bitstatus = RESET;

    /* Check the status of the specified IIC flag */
    if ((IIC->IC_STAUS & Flag) != RESET)
    {
        /* IIC_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* IIC_FLAG is reset */
        bitstatus = RESET;
    }
    /* Return the IIC_FLAG status */
    return  bitstatus;
}

/**
 * IIC中断配置
 * param: IIC_IT:
            #define IIC_IT_START_DET 
            #define IIC_IT_STOP_DET  
            #define IIC_IT_ACTIVITY 
            #define IIC_IT_RX_DONE  
            #define IIC_IT_TX_ABRT  
            #define IIC_IT_RD_REQ   
            #define IIC_IT_TX_EMPTY 
            #define IIC_IT_TX_OVER 
            #define IIC_IT_RX_FULL
            #define IIC_IT_RX_OVER
            #define IIC_IT_RX_UNDER
            #define IIC_IT_ALL
 * 
 */

void IIC_ITConfig(uint16_t IIC_IT, FunctionalState NewState)
{
    if (NewState != DISABLE)
    {
        /* Enable the selected IIC interrupt */
        IIC->IC_INTR_MASK |= IIC_IT;
    }
    else
    {
        /* Disable the selected IIC interrupt */
        IIC->IC_INTR_MASK &= ~IIC_IT;
    }
}

ITStatus IIC_GetITStatus(uint16_t IIC_IT)
{
    ITStatus bitstatus = RESET;
    uint8_t itpos = 0;

    itpos =IIC->IC_INTR_STAT & IIC_IT;
    /* Check the status of the specified IIC interrupt */
    if (itpos != RESET)
    {
        /* IIC_IT is set */
        bitstatus = SET;
    }
    else
    {
        /* IIC_IT is reset */
        bitstatus = RESET;
    }
    /* Return the IIC_IT status */
    return bitstatus;
}

void IIC_ClrITStatus(uint16_t IIC_IT)
{
    uint16_t itpos = IIC_IT;
    if (IIC_IT == IIC_IT_ALL){
        IIC->IC_CLR_INTR;
    }
    else{
        for(int i=0;i<11;i++){
            itpos = ((IIC_IT >> i) & 0x01);
            if(itpos){
                REG_RD(IIC_CLR_INTR_BASE + (4*i));
            }
        }
    }
}












