// DAC驱动(GPIO模拟I2C)
// 杭州秒寻科技有限公司
// 周涛
// 2023-09-29

#include "includes.h"

// 延时
void driver_dacgpio_delay()
{
    driver_delay_nxus(5); // 延时5微妙
}

// 写时钟
// byBitValue:值，只能是0或者1
void driver_dacgpio_w_scl(uint8 byBitValue)
{
    GPIO_WriteBit(DRIVER_DACGPIO_SCL_PORT, DRIVER_DACGPIO_SCL_PIN, (BitAction)byBitValue);
    driver_dacgpio_delay();
}

// 写数据
// byBitValue:值，只能是0或者1
void driver_dacgpio_w_sda(uint8 byBitValue)
{
    GPIO_WriteBit(DRIVER_DACGPIO_SDA_PORT, DRIVER_DACGPIO_SDA_PIN, (BitAction)byBitValue);
    driver_dacgpio_delay();
}

// 读数据
uint8 driver_dacgpio_r_sda()
{
    uint8 byBitValue = 0;

    byBitValue = GPIO_ReadInputDataBit(DRIVER_DACGPIO_SDA_PORT, DRIVER_DACGPIO_SDA_PIN);
    driver_dacgpio_delay();

    return byBitValue;
}

// 初始化用到的GPIO管脚
void driver_dacgpio_init()
{
    GPIO_InitTypeDef stGpio = {0};

    // 组织GPIO公共数据
    stGpio.GPIO_Speed = GPIO_Speed_25MHz;
    stGpio.GPIO_PuPd = GPIO_PuPd_NOPULL;

    // 初始化复位管脚
    RCC_AHB1PeriphClockCmd(DRIVER_DACGPIO_RESET_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_OUT;
    stGpio.GPIO_OType = GPIO_OType_PP;
    stGpio.GPIO_Pin = DRIVER_DACGPIO_RESET_PIN;
    GPIO_Init(DRIVER_DACGPIO_RESET_PORT, &stGpio);
    GPIO_WriteBit(DRIVER_DACGPIO_RESET_PORT, DRIVER_DACGPIO_RESET_PIN, (BitAction)0x01); // 复位
    driver_delay_nxus(500);

    // 静音管脚
    RCC_AHB1PeriphClockCmd(DRIVER_DACGPIO_AMUTE_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_OUT;
    stGpio.GPIO_OType = GPIO_OType_PP;
    stGpio.GPIO_Pin = DRIVER_DACGPIO_AMUTE_PIN;
    GPIO_Init(DRIVER_DACGPIO_AMUTE_PORT, &stGpio);
    GPIO_WriteBit(DRIVER_DACGPIO_AMUTE_PORT, DRIVER_DACGPIO_AMUTE_PIN, (BitAction)0x01); // 不静音

    /// 初始化SCL
    RCC_AHB1PeriphClockCmd(DRIVER_DACGPIO_SCL_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_OUT;
    stGpio.GPIO_OType = GPIO_OType_PP;
    stGpio.GPIO_Pin = DRIVER_DACGPIO_SCL_PIN;
    GPIO_Init(DRIVER_DACGPIO_SCL_PORT, &stGpio);

    /// 初始化SDA
    RCC_AHB1PeriphClockCmd(DRIVER_DACGPIO_SDA_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_IN | GPIO_Mode_OUT;
    stGpio.GPIO_OType = GPIO_OType_OD;
    stGpio.GPIO_Pin = DRIVER_DACGPIO_SDA_PIN;
    GPIO_Init(DRIVER_DACGPIO_SDA_PORT, &stGpio);

    driver_dacgpio_w_sda(1);
    driver_dacgpio_w_scl(1);
}

// 芯片复位
void driver_dacgpio_reset()
{
    GPIO_WriteBit(DRIVER_DACGPIO_RESET_PORT, DRIVER_DACGPIO_RESET_PIN, (BitAction)0x00);
    driver_delay_nxus(100);
    GPIO_WriteBit(DRIVER_DACGPIO_RESET_PORT, DRIVER_DACGPIO_RESET_PIN, (BitAction)0x01);
    driver_delay_nxus(500); // 释放之后需要等待3846个系统时钟(12.288MHz)周期，约312个us
}

// DAC模拟输出静音
// byMute:静音，0：静音，1：不静音
void driver_dacgpio_amute(uint8 byMute)
{
    GPIO_WriteBit(DRIVER_DACGPIO_AMUTE_PORT, DRIVER_DACGPIO_AMUTE_PIN, (BitAction)byMute);
}

// 产生开始信号
void driver_dacgpio_start()
{
    // 释放SDA和SCL（拉高）
    driver_dacgpio_w_sda(1);
    driver_dacgpio_w_scl(1);

    // 生成开始信号
    driver_dacgpio_w_sda(0);
    driver_dacgpio_w_scl(0);
}

// 产生结束信号
void driver_dacgpio_stop()
{
    driver_dacgpio_w_sda(0);
    driver_dacgpio_w_scl(1);
    driver_dacgpio_w_sda(1);
}

// 发送一个字节
// byData:一个字节的数据
void driver_dacgpio_send_byte(uint8 byData)
{
    for (uint8 i = 0; i < 8; i++)
    {
        driver_dacgpio_w_sda((byData << i) & 0x80); // 将数据最高位放到数据线上

        ////驱动时钟走一个周期
        driver_dacgpio_w_scl(1); // 释放时钟
        driver_dacgpio_w_scl(0); // 拉低时钟
    }

    return;
}

// 接收一个字节
// 返回值:一个字节的数据
uint8 driver_dacgpio_receive_byte()
{
    uint8 byData = 0;

    driver_dacgpio_w_sda(1); // 释放SDA，以便从机写入数据

    // 接收8位数据
    for (uint8 i = 0; i < 8; i++)
    {
        driver_dacgpio_w_scl(1); // 释放时钟
        if (driver_dacgpio_r_sda() == 1)
        {
            byData |= 0x80 >> i;
        }
        driver_dacgpio_w_scl(0); // 时钟拉低
    }

    return byData;
}

// 发送应答信号
// byAck:应答值
void driver_dacgpio_send_ack(uint8 byAck)
{
    driver_dacgpio_w_sda(byAck);

    ////驱动时钟走一个周期
    driver_dacgpio_w_scl(1); // 释放时钟
    driver_dacgpio_w_scl(0); // 拉低时钟

    return;
}

// 接收应答
uint8 driver_dacgpio_receive_ack()
{
    uint8 byData = 0;

    driver_dacgpio_w_sda(1); // 释放SDA，以便从机写入数据
    driver_dacgpio_w_scl(1); // 释放时钟
    byData = driver_dacgpio_r_sda();
    driver_dacgpio_w_scl(0); // 时钟拉低

    return byData;
}

/***************************************上面的函数全部是基本时序函数********************************************/
/***************************************下面的函数全部是基本业务函数********************************************/

// 向指定寄存器写入数据
// bySlaveAddress:从机地址
// byRegAddress:芯片的寄存器地址
// pbyData:待写入数据
// wLen:待写入数据长度
uint8 driver_dacgpio_write_data(uint8 bySlaveAddress, uint8 byRegAddress, uint8 *pbyData, uint16 wLen)
{
    uint8 byAck = 0;

    // 容错处理
    if (pbyData == NULL || wLen <= 0)
    {
        return 0;
    }

    driver_dacgpio_start(); // 开启发送

    // 发送从机地址
    driver_dacgpio_send_byte((bySlaveAddress & 0xFE)); // 写
    byAck = driver_dacgpio_receive_ack();
    if (byAck)
    {
        return 0;
    }

    // 发送寄存器地址
    driver_dacgpio_send_byte(byRegAddress);
    byAck = driver_dacgpio_receive_ack();
    if (byAck)
    {
        return 0;
    }

    ////发送数据
    for (uint16 i = 0; i < wLen; i++)
    {
        driver_dacgpio_send_byte(*pbyData);
        byAck = driver_dacgpio_receive_ack();
        if (byAck)
        {
            return 0;
        }
        pbyData++;
    }

    driver_dacgpio_stop(); // 终止发送

    return 1;
}

// 从指定寄存器读回数据
// bySlaveAddress:从机地址
// byRegAddress:芯片的寄存器地址
// pbyData:读回的数据(返回参数)
// wLen:待读回数据的长度
uint8 driver_dacgpio_read_data(uint8 bySlaveAddress, uint8 byRegAddress, uint8 *pbyData, uint16 wLen)
{
    uint8 byAck = 0;
    uint8 byData = 0;

    // 容错处理
    if (pbyData == NULL || wLen <= 0)
    {
        return 0;
    }

    driver_dacgpio_start(); // 开启发送

    // 发送从机地址
    driver_dacgpio_send_byte(bySlaveAddress & 0xFE); // 写
    byAck = driver_dacgpio_receive_ack();
    if (byAck)
    {
        return 0;
    }

    // 发送寄存器地址
    driver_dacgpio_send_byte(byRegAddress);
    byAck = driver_dacgpio_receive_ack();
    if (byAck)
    {
        return 0;
    }

    driver_dacgpio_start(); // 开启发送

    // 发送从机地址
    driver_dacgpio_send_byte(bySlaveAddress | 0x01); // 读
    byAck = driver_dacgpio_receive_ack();
    if (byAck)
    {
        return 0;
    }

    ////接收数据
    for (uint16 i = 0; i < wLen; i++)
    {
        byData = driver_dacgpio_receive_byte();
        *pbyData = byData;
        if (i == (wLen - 1))
        {
            driver_dacgpio_send_ack(1); // 读到最后一个字节，主机不给从机应答
        }
        else
        {
            driver_dacgpio_send_ack(0);
            pbyData++;
        }
    }

    driver_dacgpio_stop(); // 终止发送

    return 1;
}
