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

/*******************************************************************************
    @file     i2c_slave.c
    @brief    i2c slave function
    @version  1.0

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

/*******************************************************************************
    @ Module           :  Includes
    @ Description    :  NULL
*******************************************************************************/
#include "i2c_slave.h"
#include "gpio.h"
#include "error.h"
#include "osal.h"
#include "clock.h"
#include "log.h"

/*******************************************************************************
    @ Module           :  IIC_Slave status
    @ Description    :  NULL
*******************************************************************************/
typedef enum
{
    Slave_Closed = 0,
    Slave_Opened,
} IIC_Slave_status;

/*******************************************************************************
    @ Module           :  IIC_Slave_cfg structure
    @ Description    :  NULL
*******************************************************************************/
typedef struct
{
    AP_I2C_TypeDef*      addr;                                  // get by software
    MODULE_e                    module;                                 // get by software
    uint8_t                     INTR_ID;                                // get by software
    gpio_pin_e              SDA_PIN;                                // I2C Pin
    gpio_pin_e              SCL_PIN;
    Fmux_Type_e             Fmux_SCL;                               // get by software
    Fmux_Type_e             Fmux_SDA;                               // get by software
    IIC_Slave_status    state;
} IIC_Slave_cfg;

/*******************************************************************************
    @ Module           :  Global Variable
    @ Description    :  NULL
*******************************************************************************/
IIC_Slave_cfg Slave_cfg_g[IIC_COUNT];

/*******************************************************************************
    @ Module           :  Internal Function statement
    @ Description    :  NULL
*******************************************************************************/
void I2C_Slave_Handler(I2C_Evt_t* pev);

/*******************************************************************************
    @ Module           :  Function Statement
    @ Description    :  NULL
*******************************************************************************/
uint8_t Hal_I2C_Slave_Init(I2C_Slave_Parameter* para,uint8_t* handle)
{
    uint8_t ret;
    LOG("Hal_I2C_Slave_Init wakeup id:%02X \r\n",para->id);
    ret = Hal_IIC_Valid_Check(para->id);

    if( ret == TRUE )
    {
        return PPLUS_ERR_IIC_BUSY;
    }
    else if( ret == PPlus_ERR_IIC_ID)
    {
        return PPlus_ERR_IIC_ID;
    }
    else
    {
        if( Hal_IIC_Addr_Valid(para->Slave_Address) !=  PPlus_IIC_SUCCESS)
            return PPlus_ERR_IIC_ADDRESS;

        osal_memset(&Slave_cfg_g[para->id],0,sizeof(IIC_Slave_cfg));
        // pre-para get
        Slave_cfg_g[para->id].addr = Hal_Get_IIC_Instance(para->id);
        Slave_cfg_g[para->id].module = Hal_GetIIC_ModuleID(para->id);
        Slave_cfg_g[para->id].INTR_ID = Hal_GetIIC_IRQID(para->id);
        Hal_GetIIC_PIN_Fmux(para->id,&(Slave_cfg_g[para->id].Fmux_SCL),&(Slave_cfg_g[para->id].Fmux_SDA));
        Slave_cfg_g[para->id].state = Slave_Closed;
        // io init
        Slave_cfg_g[para->id].SCL_PIN = para->SCL_PIN;
        Slave_cfg_g[para->id].SDA_PIN = para->SDA_PIN;
        hal_gpio_fmux_set(para->SCL_PIN, Slave_cfg_g[para->id].Fmux_SCL);
        hal_gpio_fmux_set(para->SDA_PIN, Slave_cfg_g[para->id].Fmux_SDA);
        hal_gpio_pull_set(para->SCL_PIN,STRONG_PULL_UP);
        hal_gpio_pull_set(para->SDA_PIN,STRONG_PULL_UP);
        // init
        hal_clk_gate_enable(Slave_cfg_g[para->id].module);
        Slave_cfg_g[para->id].addr->IC_ENABLE = FALSE;
        Slave_cfg_g[para->id].addr->IC_CON = para->workmode | para->AddressMode;
        Slave_cfg_g[para->id].addr->IC_SAR = para->Slave_Address;
        Slave_cfg_g[para->id].addr->IC_RX_TL = para->RX_FIFO_Len - 1;
        Slave_cfg_g[para->id].addr->IC_TX_TL = para->Tx_FIFO_Len - 1;
        Slave_cfg_g[para->id].addr->IC_INTR_MASK = para->IRQ_Source;
        Hal_IIC_Register_CallBack(para->id,para->evt_handler);
        Hal_I2c_Slave_Open(para->id);
        // NVIC Config
        NVIC_EnableIRQ((IRQn_Type)(Slave_cfg_g[para->id].INTR_ID));
        NVIC_SetPriority((IRQn_Type)(Slave_cfg_g[para->id].INTR_ID), IRQ_PRIO_HAL);
        *handle = para->id;
        return PPlus_IIC_SUCCESS;
    }
}

/*******************************************************************************
    @ Module           :  Open I2C Slave
    @ Description    :  NULL
*******************************************************************************/
uint8_t Hal_I2c_Slave_Open(uint8_t handle)
{
    if( Slave_cfg_g[handle].state == Slave_Closed )
    {
        Slave_cfg_g[handle].state = Slave_Opened;
        Slave_cfg_g[handle].addr->IC_ENABLE = TRUE;
        return PPlus_IIC_SUCCESS;
    }
    else
        return PPlus_ERR_IIC_FAILURE;
}

/*******************************************************************************
    @ Module           :  Close I2C Slave
    @ Description    :  NULL
*******************************************************************************/
void Hal_I2c_Slave_Close(uint8_t handle)
{
    Slave_cfg_g[handle].addr->IC_ENABLE = FALSE;
}

/*******************************************************************************
    @ Module           :  Close I2C Slave
    @ Description    :  Should check close states,if closed completed
                                         a delay occurs when IC_ENABLE is set to 0, because close iic module depends
                                         on the iic bus activity
*******************************************************************************/
uint8_t Hal_Check_I2C_Slave_Closed(uint8_t handle)
{
    if( Hal_Check_IIC_Closed(Slave_cfg_g[handle].addr) == PPlus_IIC_SUCCESS )
    {
        Slave_cfg_g[handle].state = Slave_Closed;
        return PPlus_IIC_SUCCESS;
    }
    else
        return PPLUS_ERR_IIC_ENABLE;
}

/*******************************************************************************
    @ Module           :  Close I2C Slave
    @ Description    :  NULL
*******************************************************************************/
uint8_t Hal_I2C_Slave_Deinit(uint8_t* handle)
{
    LOG("HAL I2C SLAVE DINIT handle Value %d \n",*handle);

    if( Hal_IIC_unRegister_CallBack(*handle) != PPlus_IIC_SUCCESS )
        return PPlus_ERR_IIC_FAILURE;

    *handle = PPlus_INVALID_HANDLE;
    return PPlus_IIC_SUCCESS;
}

/*******************************************************************************
    @ Module           :  Read data from rx fifo
    @ Description    :  NULL
*******************************************************************************/
void Hal_I2C_Slave_ReadRX_FIFO(uint8_t handle,uint8_t* p,uint8_t len)
{
    for(uint8_t i =0; i<len; i++)
        *p++ = Hal_IIC_Read_RXFIFO(Slave_cfg_g[handle].addr);
}

/*******************************************************************************
    @ Module           :  Clear interrupt status
    @ Description    :  NULL
*******************************************************************************/
void Hal_I2C_Slave_CLR_IRQs(uint8_t handle,uint32_t irqs)
{
    Hal_INTR_SOURCE_Clear(Slave_cfg_g[handle].addr,irqs);
}

/*******************************************************************************
    @ Module           :  Hal_I2C_Slave_WriteTX_FIFO
    @ Description    :  NULL
*******************************************************************************/
void Hal_I2C_Slave_WriteTX_FIFO(uint8_t handle,uint8_t* p,uint8_t len)
{
    for(uint8_t i=0; i<len; i++)
        Hal_IIC_Write_TXFIFO(Slave_cfg_g[handle].addr,*p++);
}

/*******************************************************************************
    @ Module           :  I2C Slave Init steps:
    @ Description    :  NULL
*******************************************************************************/
/*
    1、IC_ENABLE=0;
    2、IC_SAR = ? （Master和Slave不能设置相同的地址类型？）
    3、IC_CON(配置地址模式和SLAVE模式)
    4、IC_ENABLE=1;
*/
/*******************************************************************************
    @ Module           :  I2C Slave 单字节发?
    @ Description    :  NULL
*******************************************************************************/
/*
    1、IIC MASTER 寻址
    2、IIC SLAVE ACK
    3、IIC SLAVE 触发 RD_REQ 中断?同时 HOLD THE SCL LOW , WAIT UNTIL THE SOFTWARE RESPONDS(数据响应?
        SOFTWARE RESPONDS的时间间隔，10倍SCL周期 ?00K--->25us）（一个byte传输完成的时间）
    4、读请求触发前，如果TXFIFO,总线触发TX_ABRT中断，清除旧数据   （通过软件读取 IC_CLR_TX_ABRT register，释放总线?
    5、写数据?IC_DATA_CMD
    6、清除RD_REQ,TX_ABRT中断标志位（如果中断被屏蔽，则需要清除IC_RAW_INTR_STAT?
    7、总线释放SCL并传输数据（?对应?
    8、MASTER 通过RESTART ?STOP 继续操作总线
*/
/*******************************************************************************
    @ Module           :  I2C Slave 单字节接?
    @ Description    :  NULL
*******************************************************************************/
/*
    1、IIC MASTER 寻址
    2、IIC SLAVE ACK
    3、receives the transmitted byte and places it in the receive buffer
        如果RX FIFO已经满了，再来数据的时候，将会触发R_RX_OVER中断，于此同时，
        IIC数据将会继续传输（没有NACK信号），并无法保证后续数据的完整
    4、RX_FULL 中断
    5、从IC_DATA_CMD 中读取数?
    6、MASTER 通过RESTART ?STOP 继续操作总线
*/

