#include "common_include.h"

#if ((NU2) || (QYC))
typedef struct
{
    uint8_t addr;                    /*!<   */
    uint16_t RegVal;                  /*!<  */
}SoundIICConfig;

static SoundIICConfig SOUND_IIC_DAC_Int[] = {
{0x03,0xEFBF},
{0x04,0x4440},
{0x05,0x0068},
{0x06,0x1408},//4:22.05k  7:44.1k  8:48k
{0x07,0x0361},
{0x08,0x210C},
{0x09,0x3B42},//0x3C43:8om 1w   0x3B42:4ohm 2w
{0x0A,0x0030},
{0x0B,0x01E0},
{0x0C,0x0064},
{0x0D,0xA0DB},
{0x0E,0x2716},
{0x0F,0x5F00},
{0x20,0x0001},
{0x38,0x0060},
{0x50,0x0282},
{0x52,0x20C6},
{0x53,0xA040},
{0x54,0xFF19},
{0x55,0x00D8},
{0x56,0x22D1},
{0x59,0x000C},
{0x5A,0x2100},
{0x60,0x0C0B},
{0x61,0x6379},
{0x62,0x04F1},
{0x63,0x260F},
{0x64,0x15C3},
{0x65,0x3D82},
{0x66,0x7F07},
{0x67,0x0002},
{0x68,0x3002},
{0x69,0x04A0},
{0x6A,0xA068},
{0x6B,0x8884},
{0x70,0xFF00},
{0x71,0x00C0},
}; 

void SOUND_IIC_SDA_OUT_HIGH(void);
void SOUND_IIC_SCL_OUT_HIGH(void);
void SOUND_IIC_SDA_OUT_LOW(void);
void SOUND_IIC_SCL_OUT_LOW(void);

#define SOUND_IIC_SCL_HIGH SOUND_IIC_SCL_OUT_HIGH()
#define SOUND_IIC_SCL_LOW SOUND_IIC_SCL_OUT_LOW()
#define SOUND_IIC_SDA_HIGH SOUND_IIC_SDA_OUT_HIGH()
#define SOUND_IIC_SDA_LOW SOUND_IIC_SDA_OUT_LOW()

#define SOUND_IIC_DeviceAddr (0x34 << 1)

void SOUND_IIC_DelayUs(uint32_t time);
void SOUND_IIC_DelayUs(uint32_t time)
{
    uint32_t i;
    for (i = 0; i < (time / 4); i++) {             //this counts only adapt s6j324
        NOP();
        bsp_HDOG_Feed();
    }
}

void SOUND_IIC_SDA_IN(void);
void SOUND_IIC_SDA_IN(void)
{
    stc_port_pin_config_t stc_port_pin_config = {
        .enOutputFunction      = PortOutputResourceGPIO,
        .enOutputDrive         = PortOutputDriveA,
        .enPullResistor        = PortPullResistorNone,
        .enInputLevel          = PortInputLevelCmosA,
        .bInputEnable          = TRUE,
        .bNoiseFilterEnable    = FALSE,
        .enGpioDirection       = PortGpioInput,
        .enGpioInitOutputLevel = PortGpioHigh
    };
    Port_SetPinConfig(P_TTL_SOUND_SDA_OUT, &stc_port_pin_config);
}

void SOUND_IIC_SCL_OUT_HIGH(void)
{
    stc_port_pin_config_t stc_port_pin_config = {
        .enOutputFunction      = PortOutputResourceGPIO,
        .enOutputDrive         = PortOutputDriveA,
        .enPullResistor        = PortPullResistorNone,
        .enInputLevel          = PortInputLevelCmosA,
        .bInputEnable          = TRUE,
        .bNoiseFilterEnable    = FALSE,
        .enGpioDirection       = PortGpioInput,
        .enGpioInitOutputLevel = PortGpioHigh
    };
    Port_SetPinConfig(P_TTL_SOUND_SCL_OUT, &stc_port_pin_config);
}


void SOUND_IIC_SDA_OUT_HIGH(void)
{
    stc_port_pin_config_t stc_port_pin_config = {
        .enOutputFunction      = PortOutputResourceGPIO,
        .enOutputDrive         = PortOutputDriveA,
        .enPullResistor        = PortPullResistorNone,
        .enInputLevel          = PortInputLevelCmosA,
        .bInputEnable          = TRUE,
        .bNoiseFilterEnable    = FALSE,
        .enGpioDirection       = PortGpioInput,
        .enGpioInitOutputLevel = PortGpioHigh
    };
    Port_SetPinConfig(P_TTL_SOUND_SDA_OUT, &stc_port_pin_config);
}

void SOUND_IIC_SCL_OUT_LOW(void)
{
    stc_port_pin_config_t stc_port_pin_config = { 
        .enOutputFunction      = PortOutputResourceGPIO,
        .enOutputDrive         = PortOutputDriveA,
        .enPullResistor        = PortPullResistorNone,
        .enInputLevel          = PortInputLevelCmosA,
        .bInputEnable          = FALSE,
        .bNoiseFilterEnable    = TRUE,
        .enGpioDirection       = PortGpioOutput,
        .enGpioInitOutputLevel = PortGpioLow
    };
    Port_SetPinConfig(P_TTL_SOUND_SCL_OUT, &stc_port_pin_config);
}
void SOUND_IIC_SDA_OUT_LOW(void);
void SOUND_IIC_SDA_OUT_LOW(void)
{
    stc_port_pin_config_t stc_port_pin_config = { 
        .enOutputFunction      = PortOutputResourceGPIO,
        .enOutputDrive         = PortOutputDriveA,
        .enPullResistor        = PortPullResistorNone,
        .enInputLevel          = PortInputLevelCmosA,
        .bInputEnable          = FALSE,
        .bNoiseFilterEnable    = TRUE,
        .enGpioDirection       = PortGpioOutput,
        .enGpioInitOutputLevel = PortGpioLow
    };
    Port_SetPinConfig(P_TTL_SOUND_SDA_OUT, &stc_port_pin_config);
}

uint8_t SOUND_IIC_SDA_GetValue(void);
uint8_t SOUND_IIC_SDA_GetValue(void)
{
    uint8_t i;
    en_port_gpio_level_t temp;
    Port_GetPortPinLevel(P_TTL_SOUND_SDA_OUT, (en_port_gpio_level_t*)(&temp));
    i = (uint8_t)(temp);
    return i;
}

void SOUND_IIC_Start(void);
void SOUND_IIC_Start(void)
{
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SDA_LOW;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_LOW;
    SOUND_IIC_DelayUs(300);
}

void SOUND_IIC_Stop(void);
void SOUND_IIC_Stop(void)
{
    SOUND_IIC_SDA_LOW;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(300);
}

void SOUND_IIC_ACK(void);
void SOUND_IIC_ACK(void)
{
    SOUND_IIC_SDA_LOW;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_LOW;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(6);
}

void SOUND_IIC_NACK(void);
void SOUND_IIC_NACK(void)
{
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_LOW;
    SOUND_IIC_DelayUs(6);
}

uint8_t SOUND_IIC_WaitAck(void);
uint8_t SOUND_IIC_WaitAck(void)
{
    uint8_t ack = 1;
    uint16_t i = 8500;

    SOUND_IIC_SDA_IN();
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_DelayUs(6);
    while((ack) && (--i != 0)) {
        ack = SOUND_IIC_SDA_GetValue();
        //ClearWatchdog();
        bsp_HDOG_Feed();
    }
    
    SOUND_IIC_DelayUs(6);
    SOUND_IIC_SCL_LOW;
    SOUND_IIC_DelayUs(6);
    return(ack);
}

uint8_t SOUND_IIC_SendByte(uint8_t Data);
uint8_t SOUND_IIC_SendByte(uint8_t Data)
{
    uint8_t temp;
    uint8_t d = Data;

    for (temp = 8; temp != 0; temp--) {
        if (d & 0x80) {
            SOUND_IIC_SDA_HIGH;
        } else {
            SOUND_IIC_SDA_LOW;
        }
        SOUND_IIC_DelayUs(6);
        SOUND_IIC_SCL_HIGH;
        SOUND_IIC_DelayUs(6);
        SOUND_IIC_SCL_LOW;
        SOUND_IIC_DelayUs(6);
        d = d <<1;
        SOUND_IIC_DelayUs(6);
    }
    SOUND_IIC_DelayUs(6);
    return 1;
}

uint8_t SOUND_IIC_ReadByte(void);
uint8_t SOUND_IIC_ReadByte(void)
{
    uint8_t temp;
    uint8_t rbyte = 0;
    uint8_t SDA = 0;
    
    SOUND_IIC_SDA_IN();
    SOUND_IIC_DelayUs(6);

    for (temp = 8; temp != 0; temp--) {
        SOUND_IIC_SCL_HIGH;
        SOUND_IIC_DelayUs(6);
        rbyte = rbyte << 1;
        SOUND_IIC_DelayUs(6);
        SDA = SOUND_IIC_SDA_GetValue();
        rbyte = rbyte | ((uint8_t)(SDA));
        SOUND_IIC_DelayUs(6);
        SOUND_IIC_SCL_LOW;
        SOUND_IIC_DelayUs(6);
    }
    return(rbyte);
}

uint8_t SOUND_IIC_WritePage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len);
uint8_t SOUND_IIC_WritePage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len)
{
    uint8_t  b = 3;
    uint8_t  i;
    uint8_t  *OldData;
    OldData = Data;

    do {
        Data = OldData;
        SOUND_IIC_Start();
        SOUND_IIC_SendByte(PhyAdd);
        if (SOUND_IIC_WaitAck()) {
            SOUND_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        SOUND_IIC_SendByte(MemAdd);
        if (SOUND_IIC_WaitAck()) {
            SOUND_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        for (i = 0; i < len; i++) {
            SOUND_IIC_SendByte(*Data);
            if (SOUND_IIC_WaitAck()) {
                SOUND_IIC_Stop();
                break;
            }
            Data++;
        }
        SOUND_IIC_Stop();
        return 1;
    } while (1);
    return 0;
}

uint8_t SOUND_IIC_ReadPage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len);
uint8_t SOUND_IIC_ReadPage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len)
{
    uint8_t  b = 3;
    uint8_t  i;
    
    do {
        SOUND_IIC_Start();
        SOUND_IIC_SendByte(PhyAdd);
        if (SOUND_IIC_WaitAck()) {
            SOUND_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        SOUND_IIC_SendByte(MemAdd);
        if (SOUND_IIC_WaitAck()) {
            SOUND_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        SOUND_IIC_Start();
        SOUND_IIC_SendByte(PhyAdd | 0x01);
        if (SOUND_IIC_WaitAck()) {
            SOUND_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        for(i = 0 ; i < (len -1); i++) {
            *Data = SOUND_IIC_ReadByte();
            SOUND_IIC_ACK();
            Data++;
        }
        *Data = SOUND_IIC_ReadByte();
        SOUND_IIC_NACK();
        SOUND_IIC_Stop();
        return 1;
    } while (1);
    return 0;
}

static void SOUND_IIC_WriteReg(uint8_t addr, uint16_t data)
{
    uint8_t TmpData[2] = {(data >> 8 & 0xff), (data & 0xff)};
    SOUND_IIC_WritePage(SOUND_IIC_DeviceAddr, addr, &TmpData[0], 2);
}

static uint16_t SOUND_IIC_ReadReg(uint8_t addr)
{
    uint8_t data[2];
    SOUND_IIC_ReadPage(SOUND_IIC_DeviceAddr, addr, &data[0], 2);
    return ((data[0] << 8) + data[1]);
}


uint8_t regaddr = 0;
uint8_t regdata = 0;
uint8_t wregaddr = 0;
uint8_t wregdata = 0;

void InitSOUND_IIC(void)
{
    uint16_t i;
    uint16_t TmpBuffer[(sizeof(SOUND_IIC_DAC_Int) / sizeof(SOUND_IIC_DAC_Int[0]))];
    uint8_t ResetFlag = 0;
    uint8_t InitCount = 0;

    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(300);
    for(i = 0;i < (sizeof(SOUND_IIC_DAC_Int) / sizeof(SOUND_IIC_DAC_Int[0])); i++)
    {
        bsp_HDOG_Feed();
        SOUND_IIC_WriteReg(SOUND_IIC_DAC_Int[i].addr, SOUND_IIC_DAC_Int[i].RegVal);
        SOUND_IIC_DelayUs(30);
        TmpBuffer[i] = SOUND_IIC_ReadReg(SOUND_IIC_DAC_Int[i].addr);
        SOUND_IIC_DelayUs(30);
        if (InitCount < 10) {
            if (TmpBuffer[i] != SOUND_IIC_DAC_Int[i].RegVal) {
                i = 0;
                InitCount ++;
            }
        }
    } 
}

void Sound_IIC_Sleep(void)
{
    uint16_t i;
    uint8_t InitCount = 0;
    uint16_t ReadData = 0;

    SOUND_IIC_SCL_HIGH;
    SOUND_IIC_SDA_HIGH;
    SOUND_IIC_DelayUs(300);
    for (i = 0; i < 10; i ++) {
        SOUND_IIC_WriteReg(0x4, 0x4443);
        SOUND_IIC_DelayUs(30);
        ReadData = SOUND_IIC_ReadReg(0x4);
        if (ReadData == 0x4443) {
            break;
        }
    }
}
#endif
