/**
 * \file    drv_i2c.h
 * \brief   I2C interface drivers header file
 *
 * \par     Copyright (c) 2018 UWE Technologies Corp., Ltd. All Rights Reserved.
 * \author  James
 * \date    2018-04-23
 * \version 
 * 
 * \history 
 *  Date        Note
 *  2018-04-23  Original Creation
 * 
 */
 
#ifndef __DRV_I2C_H_
#define __DRV_I2C_H_


#include "types.h"
#include "drv_reg_intf.h"
#include "reg_def_i2c.h"
#include "timer.h"
#include "drv_interrupt.h"

#pragma pack(1)


/** DRV I2C index */
typedef enum DRV_I2C_INDEX_e
{
    DRV_I2C_ID_0,  ///< I2C ID 0
    DRV_I2C_ID_1,  ///< I2C ID 1
    DRV_I2C_ID_MAX
} DRV_I2C_ID_t;

/** \name  Status and errors code
 * \{ 
 */
#define I2C_OK                          0     ///< transfer ended No Errors
#define I2C_BUSY                        1     ///< Interface I2C is busy
#define I2C_BUS_ERROR                   2     ///< Bus error
#define I2C_NO_DATA                     3     ///< No data in block
#define I2C_NO_ACK_ON_DATA              4     ///< No ACK on data
#define I2C_NO_ACK_ON_ADDRESS           5     ///< No ACK on address
#define I2C_DEVICE_NON_PRESENT          6     ///< Device not present
#define I2C_ARBITRATION_LOST            7     ///< Arbitration lost
#define I2C_TIME_OUT                    8     ///< Time out occurred
#define I2C_SLAVE_ERROR                 9     ///< Slave mode error
#define I2C_INIT_ERROR                  10     ///< Some errors appear during initialization I2C
#define I2C_CLOSE_ERROR                 11     ///< Problem with close I2C
#define I2C_INCOMPLETE_TRANSFER         12     ///< Not all data has been transfered
#define I2C_BUFFER_OVERFLOV_ERR         13     ///< Bufer for data overflow
#define I2C_WRONG_BITRATE               14     ///< Wrong bitrate
#define I2C_DATA_TRANSFER               255     ///< Transfer is running
/** \}*/



/** \name  I2C Frequency definition
 * \brief I2C Frequency = CPUCLK / (4 x ( CNT1_DIV + 1 ) x ( CNT2_DIV + 1 ) )
 * the maximal frequency is 2073ĄŁ6KHz @ 33.1776MHz
 * \{
 */
typedef enum DRV_I2C_FREQ_e
{
    I2C_FREQ_INVALID    = 0x0,
    I2C_FREQ_2073K      = 0x11,
    I2C_FREQ_1382K      = 0x12,
    I2C_FREQ_1036K      = 0x13,
    I2C_FREQ_921K       = 0x22,
    I2C_FREQ_829K       = 0x14,
    I2C_FREQ_400K       = 0x25,
    I2C_FREQ_300K       = 0x36,
    I2C_FREQ_200K       = 0x56,
    I2C_FREQ_100K       = 0x5D,
    I2C_FREQ_VALID_END  = 0xFF
} DRV_I2C_FREQ_t;
/** \}*/

/** define register information */

/** \name  I2C status register value
 * \{ 
 */
/** Illegal start or stop condition */
#define I2C_STA_BUS_ERROR               0x00

/** Start condition transmitted */
#define I2C_STA_START                   0x08

/** Repeated start condition transmitted */
#define I2C_STA_REP_START               0x10

/* Master Transmitter */
/** SLA+W transmitted, ACK received */
#define I2C_STA_MT_SLA_ACK              0x18

/** SLA+W transmitted, NAK received */
#define I2C_STA_MT_SLA_NAK              0x20

/** Data transmitted, ACK received */
#define I2C_STA_MT_DATA_ACK             0x28

/** Data transmitted, NAK received */
#define I2C_STA_MT_DATA_NAK             0x30

/** Arbitration lost in SLA+W or data */
#define I2C_STA_MT_ARB_LOST             0x38

/* Master Receiver */
/** Arbitration lost in SLA+R or NAK */
#define I2C_STA_MR_ARB_LOST             0x38

/** SLA+R transmitted, ACK received */
#define I2C_STA_MR_SLA_ACK              0x40

/** SLA+R transmitted, NAK received */
#define I2C_STA_MR_SLA_NAK              0x48

/** Data received, ACK returned */
#define I2C_STA_MR_DATA_ACK             0x50

/** Data received, NAK returned */
#define I2C_STA_MR_DATA_NAK             0x58

/* Slave Transmitter */
/** SLA+R received, ACK returned */
#define I2C_STA_ST_SLA_ACK              0xA8

/** Arbitration lost in SLA+RW, SLA+R received, ACK returned */
#define I2C_STA_ST_ARB_LOST_SLA_ACK     0xB0

/** Data transmitted, ACK received */
#define I2C_STA_ST_DATA_ACK             0xB8

/** Data transmitted, NAK received */
#define I2C_STA_ST_DATA_NAK             0xC0

/** Last data byte transmitted, ACK received */
#define I2C_STA_ST_LAST_DATA            0xC8

/* Slave Receiver */
/** SLA+W received, ACK returned */
#define I2C_STA_SR_SLA_ACK              0x60

/** Arbitration lost in SLA+RW, SLA+W received, ACK returned */
#define I2C_STA_SR_ARB_LOST_SLA_ACK     0x68

/** General call received, ACK returned */
#define I2C_STA_SR_GCALL_ACK            0x70

/** Arbitration lost in SLA+RW, general call received, ACK returned */
#define I2C_STA_SR_ARB_LOST_GCALL_ACK   0x78

/** Data received, ACK returned */
#define I2C_STA_SR_DATA_ACK             0x80

/** Data received, NAK returned */
#define I2C_STA_SR_DATA_NAK             0x88

/** General call data received, ACK returned */
#define I2C_STA_SR_GCALL_DATA_ACK       0x90

/** General call data received, NAK returned */
#define I2C_STA_SR_GCALL_DATA_NAK       0x98

/** Stop or repeated start condition received while selected */
#define I2C_STA_SR_STOP                 0xA0

/** no state information available */
#define I2C_STA_NO_INFO		            0xF8
/** \}*/


#define T_WAKE_I2C_FAIL                 (100000UL)


/** \name  I2C control register value
 * \{ 
 */
#define I2C_CR2                         0x80
#define I2C_EN                          0x40
#define I2C_STA                         0x20
#define I2C_STO                         0x10
#define I2C_SI                          0x08
#define I2C_ACK                         0x04
#define I2C_CR1                         0x02
#define I2C_CR0                         0x01
/** \}*/

/** slave address of local I2C slave */
#define SLAVE_ADDRESS_0                 0xA0
#define SLAVE_ADDRESS_1                 0xA8

#ifdef I2C_USE_48_BTYE_BUFF_SIZE
/** buffer size  */
#define I2C_BUFFER_SIZE                 48
#else
#define I2C_BUFFER_SIZE                 16
#endif
typedef struct i2c_info_s
{
    /** Address of slave I2C device */
    u32_t sla_addr:8;
    /** information about last I2C interface status */
    u32_t last_status:8;
    /** Flag is used to control enabling and disabling I2C interrupts */
    u32_t intr_en_flag:1;
    u32_t reserved:15;

    /** Length of tx data */
    u32_t tx_data_len:8;
    /** Index of tx data */
    u32_t tx_data_index:8;
    /** Length of receive data */
    u32_t rx_data_len:8;
    /** Index of receive data */
    u32_t rx_data_index:8;

    timer_t timer;

    /** i2c buffer for tx data */
    u8_t tx_data[I2C_BUFFER_SIZE];
    /** i2c buffer for data received */
    u8_t rx_data[I2C_BUFFER_SIZE];

    /* function pointer to i2c receive routine */
    /* sla_rx_func is called when this processor is addressed as a slave for
     * reading */
    void (*sla_rx_func)(DRV_I2C_ID_t id, u8_t* received_data, u8_t received_len);
    /* sla_tx_func is called when this processor is addressed as a slave for
     * writing */
    u8_t (*sla_tx_func)(DRV_I2C_ID_t id, u8_t tx_data_len_max, u8_t* transmit_data);

#if I2C_ISR_DBG_ENABLED
    u8_t sta_buf[32];
    u32_t sta_buf_idx:8;
    u32_t intr_occurence_cnt:24;
#endif /* I2C_ISR_DBG_ENABLED */

    /* bus lock for multi-task */
    void * bus_lock;

} i2c_info_t;

#pragma pack()

extern i2c_info_t g_i2c_info[DRV_I2C_ID_MAX];
extern u32_t g_i2c_addr_offset_map[DRV_I2C_ID_MAX];

/** Enable interrupt */
#define drv_i2c_interrupt_enable(id)    (drv_intr_ext_en_set(id+IPIC_CFG_INTR_IDX_I2C_INT,TRUE))

/** Disable interrupt */
#define drv_i2c_interrupt_disable(id)   (drv_intr_ext_en_set(id+IPIC_CFG_INTR_IDX_I2C_INT,FALSE))

#define drv_i2c_en_get(id)              (drv_intr_ext_en_get(id+IPIC_CFG_INTR_IDX_I2C_INT))

/** Wait for interface busy */
#define i2c_wait_busy(id)           while(g_i2c_info[id].last_status == I2C_DATA_TRANSFER)

/** Set slave address and configure as write mode */
#define i2c_master_write_mode_set(id,address)   (g_i2c_info[id].sla_addr=(address)&0xFE)

/** Set slave address and configure as read mode */
#define i2c_master_read_mode_set(id,address)    (g_i2c_info[id].sla_addr=(address)|0x01)

/** Set master read length */
#define i2c_master_read_len_set(id,v)           (g_i2c_info[id].rx_data_len=v)

/** Set master write length */
#define i2c_master_write_len_set(id,v)          (g_i2c_info[id].tx_data_len=v)

/** \name  I2C control action definition
 * \{ 
 */
#define drv_i2c_wait_event(id)      while(!(DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])&I2C_SI))
#define drv_i2c_wait_hw_stop(id)    while(DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])&I2C_STO)
#define drv_i2c_set_start(id)       (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])|=I2C_STA)
#define drv_i2c_clear_start(id)     (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])&=~I2C_STA)
#define drv_i2c_set_stop(id)        (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])|=I2C_STO)
#define drv_i2c_set_ack(id)         (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])|=I2C_ACK)
#define drv_i2c_clear_ack(id)       (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])&=~I2C_ACK)
#define drv_i2c_clear_si(id)        (DRV_REG_GET(I2C_CTRL_REG+g_i2c_addr_offset_map[id])&=~I2C_SI)


/** \brief I2C Initialization, called by system initialization only once
 */
void drv_i2c_init(void);

/** \brief I2C interface Initialization
 */
void drv_i2c_intf_init(DRV_I2C_ID_t i2c_id);

/** \brief Open I2C interface
 *
 * \param i2c_id        The I2C ID
 * \param sla_addr      I2C slave address
 */
void drv_i2c_open(DRV_I2C_ID_t i2c_id, u8_t sla_addr);

/** \brief Close I2C interface
 *
 * \param i2c_id        The I2C ID
 */
void drv_i2c_close(DRV_I2C_ID_t i2c_id);

/** \brief I2C Master Mode start send
 *
 * \param i2c_id        The I2C ID
 */
void drv_i2c_master_start(DRV_I2C_ID_t i2c_id);

/** \brief Set I2C master interface frequency
 *
 * \param i2c_id        The I2C ID
 * \param freq          I2C frequency type, see DRV_I2C_FREQ_t
 */
void drv_i2c_master_freq_set(DRV_I2C_ID_t i2c_id, DRV_I2C_FREQ_t freq);

/** \brief I2C master transmit and receive data
 *
 * \param i2c_id        The I2C ID
 * \param addr          Address of slave I2C device
 * \param ptx_data      Transmit data buffer
 * \param tx_len        Length of transmit data buffer
 * \param prx_data      Receive data buffer
 * \param rx_len        Length of received data buffer
 * \return 
 */
u8_t drv_i2c_master_transmit(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t *ptx_data, u8_t tx_len, u8_t *prx_data, u8_t rx_len);

#if I2C_MODULE_SLA_ENABLED
/** \brief Set I2C slave mode device address
 *
 * \param i2c_id        The I2C ID
 * \param addr          Address of slave I2C device
 */
void drv_i2c_sla_addr_set(DRV_I2C_ID_t i2c_id, u8_t addr);

/** \brief Set I2C slave mode cleanup
 *
 * \param i2c_id        The I2C ID
 */
void drv_i2c_sla_cleanup(DRV_I2C_ID_t i2c_id);

/** \brief Set the user function which handles receiving (incoming) data as a slave.
 *
 * \param i2c_id        The I2C ID
 * \param sla_rx_func   user receive callback function
 */
void drv_i2c_sla_rx_handler_set(DRV_I2C_ID_t i2c_id, void (*sla_rx_func)(DRV_I2C_ID_t id, u8_t* received_data, u8_t received_len));

/** \brief Set the user function which handles transmitting (outgoing) data as a slave.
 *
 * \param i2c_id        The I2C ID
 * \param sla_tx_func   user transmit callback function
 */
void drv_i2c_sla_tx_handler_set(DRV_I2C_ID_t i2c_id, u8_t (*sla_tx_func)(DRV_I2C_ID_t id, u8_t tx_data_len_max, u8_t* transmit_data));
#endif /* I2C_MODULE_SLA_ENABLED */


#if I2C_MODULE_REG_ENABLED
/** Get register via I2C interface */
u8_t drv_i2c_reg_get(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg);

/** Set register via I2C interface */
void drv_i2c_reg_set(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t val);

/** Get register field with width via I2C interface */
u8_t drv_i2c_reg_field_get(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t width);

/** Set register field with width */
void drv_i2c_reg_field_set(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t width, u8_t val);

/** Get multiple registers */
void drv_i2c_reg_mget(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t cnt, u8_t *p_val);

/** Set multiple registers */
void drv_i2c_reg_mset(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t cnt, u8_t *p_val);

/** Get register field with field set */
u8_t drv_i2c_reg_field_get2(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t field_set);

/** Set register field with field set and mask */
void drv_i2c_reg_field_set2(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t field_set, u8_t field_mask, u8_t val);

#if I2C_MODULE_REG_16_ENABLED
u16_t drv_i2c_reg_get_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg);

/** Set 2 bytes register */
void drv_i2c_reg_set_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u16_t val);

/** Get register field with width */
u16_t drv_i2c_reg_field_get_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t width);

/** Set register field with width */
void drv_i2c_reg_field_set_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u8_t width, u16_t val);

/** Get register field with field set */
u16_t drv_i2c_reg_field_get2_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u16_t field_set);

/** Set register field with field set and mask */
void drv_i2c_reg_field_set2_u16(DRV_I2C_ID_t i2c_id, u8_t addr, u8_t reg, u8_t field, u16_t field_set, u16_t field_mask, u16_t val);
#endif /* I2C_MODULE_REG_16_ENABLED */
#endif /* I2C_MODULE_REG_ENABLED */


#endif /* #ifndef __DRV_I2C_H_ */

