#include "common_include.h"

#define TAS2505_SCL_HIGH Port_SetPortPinLevel(2, 27, PortGpioHigh)
#define TAS2505_SCL_LOW Port_SetPortPinLevel(2, 27, PortGpioLow)
#define TAS2505_SDA_HIGH Port_SetPortPinLevel(2, 26, PortGpioHigh)
#define TAS2505_SDA_LOW Port_SetPortPinLevel(2, 26, PortGpioLow)

#define TAS2505DeviceAddr 0x30

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

void TAS2505_SDA_IN(void);
void TAS2505_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(2, 26, &stc_port_pin_config);
    //Port_EnableInput();
}

void TAS2505_SDA_OUT(void);
void TAS2505_SDA_OUT(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(2, 26, &stc_port_pin_config);
}

uint8_t TAS2505_SDA_GetValue(void);
uint8_t TAS2505_SDA_GetValue(void)
{
    uint8_t i;
    en_port_gpio_level_t temp;
    Port_GetPortPinLevel(2, 26, (en_port_gpio_level_t*)(&temp));
    i = (uint8_t)(temp);
    return i;
}

void TAS2505_IIC_Start(void);
void TAS2505_IIC_Start(void)
{
    TAS2505_SDA_OUT();
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_LOW;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_LOW;
    TAS2505_IIC_DelayUs(300);
}

void TAS2505_IIC_Stop(void);
void TAS2505_IIC_Stop(void)
{
    TAS2505_SDA_OUT();
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_LOW;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_LOW;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_HIGH;
    TAS2505_IIC_DelayUs(300);
}

void TAS2505_IIC_ACK(void);
void TAS2505_IIC_ACK(void)
{
    TAS2505_SDA_OUT();
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_LOW;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_LOW;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_HIGH;
    TAS2505_IIC_DelayUs(6);
}

void TAS2505_IIC_NACK(void);
void TAS2505_IIC_NACK(void)
{
    TAS2505_SDA_OUT();
    TAS2505_IIC_DelayUs(6);
    TAS2505_SDA_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_HIGH;
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_LOW;
    TAS2505_IIC_DelayUs(6);
}

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

    TAS2505_SDA_IN();
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_HIGH;
    TAS2505_IIC_DelayUs(6);
    while((ack) && (--i != 0)) {
        ack = TAS2505_SDA_GetValue();
        //ClearWatchdog();
        bsp_HDOG_Feed();
    }
    
    TAS2505_IIC_DelayUs(6);
    TAS2505_SCL_LOW;
    TAS2505_IIC_DelayUs(6);
    return(ack);
}

uint8_t TAS2505_IIC_SendByte(uint8_t Data);
uint8_t TAS2505_IIC_SendByte(uint8_t Data)
{
    uint8_t temp;
    uint8_t d = Data;
    
    TAS2505_SDA_OUT();
    TAS2505_IIC_DelayUs(6);
    for (temp = 8; temp != 0; temp--) {
        if (d & 0x80) {
            TAS2505_SDA_HIGH;
        } else {
            TAS2505_SDA_LOW;
        }
        TAS2505_IIC_DelayUs(6);
        TAS2505_SCL_HIGH;
        TAS2505_IIC_DelayUs(6);
        TAS2505_SCL_LOW;
        TAS2505_IIC_DelayUs(6);
        d = d <<1;
        TAS2505_IIC_DelayUs(6);
    }
    TAS2505_IIC_DelayUs(6);
    return 1;
}

uint8_t TAS2505_IIC_ReadByte(void);
uint8_t TAS2505_IIC_ReadByte(void)
{
    uint8_t temp;
    uint8_t rbyte = 0;
    uint8_t SDA = 0;
    
    TAS2505_SDA_IN();
    TAS2505_IIC_DelayUs(6);

    for (temp = 8; temp != 0; temp--) {
        TAS2505_SCL_HIGH;
        TAS2505_IIC_DelayUs(6);
        rbyte = rbyte << 1;
        TAS2505_IIC_DelayUs(6);
        SDA = TAS2505_SDA_GetValue();
        rbyte = rbyte | ((uint8_t)(SDA));
        TAS2505_IIC_DelayUs(6);
        TAS2505_SCL_LOW;
        TAS2505_IIC_DelayUs(6);
    }
    return(rbyte);
}

uint8_t TAS2505_IIC_WritePage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len);
uint8_t TAS2505_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;
        TAS2505_IIC_Start();
        TAS2505_IIC_SendByte(PhyAdd);
        if (TAS2505_IIC_WaitAck()) {
            TAS2505_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        TAS2505_IIC_SendByte(MemAdd);
        if (TAS2505_IIC_WaitAck()) {
            TAS2505_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        for (i = 0; i < len; i++) {
            TAS2505_IIC_SendByte(*Data);
            if (TAS2505_IIC_WaitAck()) {
                TAS2505_IIC_Stop();
                break;
            }
            Data++;
        }
        TAS2505_IIC_Stop();
        return 1;
    } while (1);
    return 0;
}

uint8_t TAS2505_IIC_ReadPage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len);
uint8_t TAS2505_IIC_ReadPage(uint8_t PhyAdd, uint8_t MemAdd, uint8_t *Data, uint8_t len)
{
    uint8_t  b = 3;
    uint8_t  i;
    
    do {
        TAS2505_IIC_Start();
        TAS2505_IIC_SendByte(PhyAdd);
        if (TAS2505_IIC_WaitAck()) {
            TAS2505_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        TAS2505_IIC_SendByte(MemAdd);
        if (TAS2505_IIC_WaitAck()) {
            TAS2505_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        TAS2505_IIC_Start();
        TAS2505_IIC_SendByte(PhyAdd | 0x01);
        if (TAS2505_IIC_WaitAck()) {
            TAS2505_IIC_Stop();
            b--;
            if (b) {
                continue;
            } else {
                break;
            }
        }
        for(i = 0 ; i < (len -1); i++) {
            *Data = TAS2505_IIC_ReadByte();
            TAS2505_IIC_ACK();
            Data++;
        }
        *Data = TAS2505_IIC_ReadByte();
        TAS2505_IIC_NACK();
        TAS2505_IIC_Stop();
        return 1;
    } while (1);
    return 0;
}

static void TAS2505WriteReg(uint8_t addr, uint8_t data)
{
    TAS2505_IIC_WritePage(TAS2505DeviceAddr, addr, &data, 1);
}

static uint8_t TAS2505ReadReg(uint8_t addr)
{
    uint8_t data;
    TAS2505_IIC_ReadPage(TAS2505DeviceAddr, addr, &data, 1);
    return data;
}


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

uint8_t ReadBuffer[100];
void InitTAS2505(void)
{
    uint16_t i;
    stc_port_pin_config_t stc_port_pin_config_out = { .enOutputFunction      = PortOutputResourceGPIO,  // 
                                                     .enOutputDrive         = PortOutputDriveA,
                                                     .enPullResistor        = PortPullResistorNone,
                                                     .enInputLevel          = PortInputLevelCmosA,
                                                     .bInputEnable          = FALSE,
                                                     .bNoiseFilterEnable    = TRUE,
                                                     .enGpioDirection       = PortGpioOutput,
                                                     .enGpioInitOutputLevel = PortGpioHigh};
     
    Port_SetPinConfig(2, 26, &stc_port_pin_config_out);
    Port_SetPinConfig(2, 27, &stc_port_pin_config_out);
    
    Port_SetPortPinLevel(2, 26, PortGpioHigh);   // High
    Port_SetPortPinLevel(2, 27, PortGpioHigh);   // High
    
    uint8_t ResetFlag = 0;
    uint8_t InitCount = 0;
    for(i = 0;i < (sizeof(TAS2505_DAC_Int) / sizeof(TAS2505_DAC_Int[0])); i++)
    {
        if (ResetFlag) {
            i = 0;
            ResetFlag = 0;
        }
        bsp_HDOG_Feed();
        TAS2505WriteReg(TAS2505_DAC_Int[i].addr, TAS2505_DAC_Int[i].RegVal);
        TAS2505_IIC_DelayUs(300);
        ReadBuffer[i] = TAS2505ReadReg(TAS2505_DAC_Int[i].addr);
        TAS2505_IIC_DelayUs(300);
        if ((ReadBuffer[i] != TAS2505_DAC_Int[i].RegVal) && (i != 1) && (i != 17)) {
            InitCount++;
            if(InitCount < 10) {
                ResetFlag = 1;
            }
        }
    } 
      
}