#include "bsp_DS1302.h"

#define bsp_DS1302_DELAY() do{ \
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
        __NOP();__NOP();__NOP();__NOP();\
    }while(0)

#define RST_CLR     HAL_GPIO_WritePin(DS1302_RST_GPIO_Port,  DS1302_RST_Pin, GPIO_PIN_RESET   )
#define RST_SET     HAL_GPIO_WritePin(DS1302_RST_GPIO_Port,  DS1302_RST_Pin, GPIO_PIN_SET     )

#define IO_CLR      HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port,   DS1302_DIO_Pin, GPIO_PIN_RESET  )
#define IO_SET      HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port,   DS1302_DIO_Pin, GPIO_PIN_SET    )
#define IO_READ     HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port,   DS1302_DIO_Pin                  )

#define SCK_CLR     HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET    )
#define SCK_SET     HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET      )

static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);

bsp_DS1302_t DS1302 =
{
    .Init = bsp_DS1302Init,
    .Task = bsp_DS1302_Task,
    .Set = bsp_DS1302_Set,
};

bsp_DS1302_t *pDS1302 = &DS1302;

static void bsp_DS1302DataInput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体

    GPIO_InitStruct.Pin = DS1302_DIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}

static void bsp_DS1302DataOutput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体

    GPIO_InitStruct.Pin = DS1302_DIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}

/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
    u8 i;
    RST_SET;                    /*启动bsp_DS1302总线*/

    bsp_DS1302_DELAY();
    /*写入目标地址：addr*/
    Addr = Addr & 0xFE;/*最低位置零*/

    for (i = 0; i < 8; i++)
    {
        if (Addr & 0x01)
        {
            IO_SET;
        }

        else
        {
            IO_CLR;
        }

        bsp_DS1302_DELAY();
        SCK_SET;
        bsp_DS1302_DELAY();
        SCK_CLR;
        bsp_DS1302_DELAY();
        Addr = Addr >> 1;
    }

    /*写入数据：d*/
    for (i = 0; i < 8; i++)
    {
        if (Data & 0x01)
        {
            IO_SET;
        }

        else
        {
            IO_CLR;
        }

        bsp_DS1302_DELAY();
        SCK_SET;
        bsp_DS1302_DELAY();
        SCK_CLR;
        bsp_DS1302_DELAY();
        Data = Data >> 1;
    }

    RST_CLR;                    /*停止bsp_DS1302总线*/
    bsp_DS1302_DELAY();
}

/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
    u8 i;
    u8 temp;
    RST_SET;                    /*启动bsp_DS1302总线*/
    bsp_DS1302_DELAY();

    /*写入目标地址：addr*/
    Addr = Addr | 0x01;/*最低位置高*/

    for (i = 0; i < 8; i++)
    {
        if (Addr & 0x01)
        {
            IO_SET;
        }

        else
        {
            IO_CLR;
        }

        bsp_DS1302_DELAY();
        SCK_SET;
        bsp_DS1302_DELAY();
        SCK_CLR;
        bsp_DS1302_DELAY();
        Addr = Addr >> 1;
    }

    bsp_DS1302DataInput();

    /*输出数据：temp*/
    for (i = 0; i < 8; i++)
    {
        temp = temp >> 1;

        if (IO_READ)
        {
            temp |= 0x80;
        }

        else
        {
            temp &= 0x7F;
        }

        bsp_DS1302_DELAY();
        SCK_SET;
        bsp_DS1302_DELAY();
        SCK_CLR;
        bsp_DS1302_DELAY();
    }

    RST_CLR;                    /*停止bsp_DS1302总线*/
    bsp_DS1302_DELAY();
    bsp_DS1302DataOutput();
    return temp;
}

static u8 HexToBCD(u8 code)
{
    u8 temp;
    temp = ((code / 10) << 4) + (code % 10);
    return temp;
}

static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
    if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
    (pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
    {
        return USR_FALSE;

    }
    else
    {
        bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x00);           //关闭写保护
        bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, 0x80);               //暂停

        bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
        bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
        bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
        bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
        bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
        bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));

        bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x80);           //打开写保护
        return USR_TRUE;
    }
}

static void bsp_DS1302_Task(void)
{
    u8 RegData;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
    pDS1302->Time.Year = (RegData / 16) * 10 + RegData % 16;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
    pDS1302->Time.Month = (RegData / 16) * 10 + RegData % 16;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
    pDS1302->Time.Day = (RegData / 16) * 10 + RegData % 16;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
    pDS1302->Time.Hour = (RegData / 16) * 10 + RegData % 16;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
    pDS1302->Time.Minute = (RegData / 16) * 10 + RegData % 16;

    RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
    pDS1302->Time.Second = (RegData / 16) * 10 + RegData % 16;

}

static void bsp_DS1302Init(void)
{
    RST_SET;
    SCK_CLR;
    bsp_DS1302_Task();

    if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
        (pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
    {
        pDS1302->Time.Year = 26;
        pDS1302->Time.Month = 1;
        pDS1302->Time.Day = 1;
        pDS1302->Time.Hour = 0;
        pDS1302->Time.Minute = 0;
        pDS1302->Time.Second = 0;
        bsp_DS1302_Set(&pDS1302->Time);
    }
}
