//ds1302.c:

/************ DS1302程序 ************
* 版本.........: 1.0
* 作者.........: 陈利栋
* 文件名.......: ds1302.c
* 创建时间.....: 2010.11.11
* 最后修改.....: 2010.11.11
************************************/
#include "ds1302.h"
#include "ds1302_config.h"

volatile unsigned char DS1302_Update = 0;
DS1302_DateTime_t DS1302_DateTime;


// 发送一个字节,不操作CE
static void DS1302_TxByte ( unsigned char byte )
{
    unsigned char i = 0;

    DS1302_IO_OUT;

    for ( i = 0; i < 8; i++ )
    {
        DS1302_SCLK_0;
        DS1302_DELAY_T_CL;

        if ( byte & 0x01 )
        {
            DS1302_IO_1;
        }
        else
        {
            DS1302_IO_0;
        }

        DS1302_DELAY_T_DC;
        DS1302_SCLK_1;
        DS1302_DELAY_T_CH;
        byte >>= 1;
    }
}

// 接收一个字节,不操作CE
static unsigned char DS1302_RxByte ( void )
{
    unsigned char i = 0;
    unsigned char byte = 0;

    DS1302_IO_IN;
    DS1302_IO_1;

    for ( i = 0; i < 8; i++ )
    {
        DS1302_SCLK_0;
        DS1302_DELAY_T_CDD;
        byte >>= 1;

        if ( DS1302_IO_VALUE )
        {
            byte |= 0x80;
        }

        DS1302_SCLK_1;
        DS1302_DELAY_T_CH;
    }

    return byte;
}

static void DS1302_WriteByte ( unsigned char address, unsigned char _data )
{
    DS1302_SCLK_0;
    DS1302_CE_1;
    DS1302_DELAY_T_CC;
    DS1302_TxByte ( address );
    DS1302_TxByte ( _data );
    DS1302_SCLK_0;
    DS1302_DELAY_T_CCH;
    DS1302_CE_0;
    DS1302_DELAY_T_CWH;
}

static unsigned char DS1302_ReadByte ( unsigned char address )
{
    unsigned char _data = 0;

    DS1302_SCLK_0;
    DS1302_CE_1;
    DS1302_DELAY_T_CC;
    DS1302_TxByte ( address | 0x01 );
    _data = DS1302_RxByte();
    DS1302_SCLK_0;
    DS1302_DELAY_T_CCH;
    DS1302_CE_0;
    DS1302_DELAY_T_CWH;

    return _data;
}

#if DS1302_AUTO_TO_DEC == 1

static unsigned char DecToBcd ( unsigned char d )
{
    return ( ( ( ( d ) / 10 ) << 4 ) + ( ( d ) % 10 ) );
}

static unsigned char BcdToDec ( unsigned char b )
{
    return ( ( ( ( b ) >> 4 ) * 10 ) + ( ( b ) & 0x0f ) );
}

#endif /* DS1302_AUTO_TO_DEC == 1 */

void DS1302_SetDateTime ( void )
{
    unsigned char temp = 0;

    DS1302_WriteByte ( DS1302_WRITE_PROTECT_ADDR, 0x00 );      // 关闭写保护

    DS1302_WriteByte ( DS1302_YEAR_ADDR,   DEC_TO_BCD ( DS1302_DateTime.Year ) );
    DS1302_WriteByte ( DS1302_MONTH_ADDR,  DEC_TO_BCD ( DS1302_DateTime.Month ) );
    DS1302_WriteByte ( DS1302_DATE_ADDR,   DEC_TO_BCD ( DS1302_DateTime.Date ) );
    DS1302_WriteByte ( DS1302_MINUTE_ADDR, DEC_TO_BCD ( DS1302_DateTime.Minute ) );
    DS1302_WriteByte ( DS1302_SECOND_ADDR, DEC_TO_BCD ( DS1302_DateTime.Second ) );
    DS1302_WriteByte ( DS1302_DAY_ADDR,    DEC_TO_BCD ( GetDayFromDate ( DS1302_DateTime.Year, DS1302_DateTime.Month, DS1302_DateTime.Date ) ) );

    temp = DEC_TO_BCD ( DS1302_DateTime.Hour );

    if ( DS1302_DateTime.HourMode == _12_hours )
    {
        temp |= 0x80;
        temp |= ( DS1302_DateTime.AM_PM == pm ? 0x20 : 0 );
    }

    DS1302_WriteByte ( DS1302_HOUR_ADDR, temp );

    DS1302_WriteByte ( DS1302_WRITE_PROTECT_ADDR, 0x80 );      // 写入完毕后设置写保护
}

void DS1302_GetDateTime ( void )
{
    unsigned char temp = 0;

    DS1302_Update = 0;

    DS1302_DateTime.Year   = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_YEAR_ADDR ) );
    DS1302_DateTime.Month  = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_MONTH_ADDR ) );
    DS1302_DateTime.Date   = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_DATE_ADDR ) );
    DS1302_DateTime.Minute = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_MINUTE_ADDR ) );
    DS1302_DateTime.Second = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_SECOND_ADDR ) );
    DS1302_DateTime.Day    = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_DAY_ADDR ) );

    temp = DS1302_ReadByte ( DS1302_HOUR_ADDR );

    if ( temp & 0x80 )
    {
        DS1302_DateTime.HourMode = _12_hours;
        DS1302_DateTime.AM_PM = ( ( temp & 0x20 ) ? pm : am );
        temp &= 0x1f;
    }

    DS1302_DateTime.Hour = BCD_TO_DEC ( temp );
}

void DS1302_Scan ( void )
{
    static unsigned second_last = 0;

    DS1302_DateTime.Second = BCD_TO_DEC ( DS1302_ReadByte ( DS1302_SECOND_ADDR ) );

    if ( second_last != DS1302_DateTime.Second )
    {
        second_last = DS1302_DateTime.Second;
        DS1302_Update = 1;
    }
}

void DS1302_Init ( void )
{
#if DS1302_def
    // 端口初始化
    DS1302_CE_0;
    DS1302_CE_OUT;
    DS1302_SCLK_0;
    DS1302_SCLK_OUT;

    DS1302_WriteByte ( DS1302_WRITE_PROTECT_ADDR, 0x00 );     // 关闭写保护
    DS1302_WriteByte ( DS1302_TRICKLE_CHARGE_ADDR, 0xa7 );    // 使能涓流充电 1 Diode, 8kΩ

    if ( DS1302_ReadByte ( DS1302_SECOND_ADDR ) & 0x80 )      // 振荡器未启动
        DS1302_WriteByte ( DS1302_SECOND_ADDR, 0x00 );        // 启动振荡器

    DS1302_WriteByte ( DS1302_WRITE_PROTECT_ADDR, 0x80 );     // 打开写保护
#endif
}

void DS1302_Key_Handler ( void )
{
    if ( Keys[14].Res == LONG_KEY_FLAG )
    {
        Keys[14].Res = NO_KEY_FLAG;

        DS1302_DateTime.Year = 14;
        DS1302_DateTime.Month = 10;
        DS1302_DateTime.Date = 5;
        DS1302_DateTime.Hour = 22;
        DS1302_DateTime.Minute = 35;
        DS1302_DateTime.Second = 0;
        DS1302_DateTime.Day = 7;
        DS1302_DateTime.HourMode = _24_hours;
        DS1302_DateTime.AM_PM = pm;
#if DS1302_def
        DS1302_SetDateTime();
#endif
    }
}

// 计算2000～2099年任一天星期几
// year        : 00-99
// month       : 01-12
// day         : 01-31
// 返回 1 -> 7 : 星期一 -> 星期天
unsigned char GetDayFromDate ( unsigned char year, unsigned char month, unsigned char date )
{
    if ( month == 1 || month == 2 )
    {
        month += 12;

        if ( year > 0 )
            year--;
        else
            year = 4;
    }

    return ( 1 + ( ( date + 2 * month + 3 * ( month + 1 ) / 5 + year + year / 4 ) % 7 ) );
}


/////////////////////



//平年的月份日期表,月份缩写表
const u8 Days_Table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const u8 Month_Table[12][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

const u8* Week_Table[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

//月修正数据表
u8 const _Week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};



//判断是否是闰年函数
//
//判断方法：
//		普通年能整除4且不能整除100的为闰年。（如2004年就是闰年,1900年不是闰年）
//		世纪年能整除400的是闰年。(如2000年是闰年，1900年不是闰年)
//
//返回: 1,是闰年 	0,不是闰年
u8 Is_LeapYear ( u16 year )
{
    if ( ( ( year % 4 == 0 ) && ( year % 100 != 0 ) ) || ( year % 400 == 0 ) )
        return 1;
    else
        return 0;
}


//将时间转化为到1970年1月1日的总秒数
//Bugs:此函数秒数会多20左右，所以函数返回值做了校正,校正后没有问题
//待优化
u32 Date_TO_Sec ( u16 year, u8 month, u8 date, u8 hour, u8 minute, u8 second )
{
    u16 t = 0;
    u32 sec = 0;

    year += 2000;

    if ( ( year >= 1970 ) && ( year <= 2106 ) )		 //判断是否为合法年份，RTC的时间是从1970开始，只能由32位表示秒数，最大只能到2106年左右
    {
        for ( t = 1970 ; t < year; t++ ) 		 //所有年份秒数累加
        {
            if ( Is_LeapYear ( t ) )			 //判断是否为闰年
            {
                sec += 366 * 24 * 60 * 60;
            }
            else
            {
                sec += 365 * 24 * 60 * 60;
            }
        }


        for ( t = 0; t < month - 1; t++ )						 //月份秒数累加
        {
            sec += ( u32 ) Days_Table[t] * 24 * 60 * 60;

            if ( Is_LeapYear ( year ) && ( t == 1 ) ) 				//闰年加一天的秒钟数
            {
                sec += 24 * 60 * 60;
            }
        }

        sec += ( u32 ) ( date - 1 ) * 24 * 60 * 60;						//本月日期的秒数累加
        sec += ( u32 ) ( hour ) * 60 * 60;
        sec += ( u32 ) ( minute ) * 60;
        sec += second;

    }

    return sec;//-20;										//校正20秒，原因不详

}



//获取RTC时间
void Sec_TO_Date ( u32 secs )
{
    u32 days = 0, temp = 0, years = 1970, months = 0;

#if 0
    secs = RTC->CNTH; 	//读取RTC的当前时间值（距1970年的总秒数）
    secs <<= 16;
    secs += RTC->CNTL;
#else

#endif
    //printf("\nRtc_Get  Sec = %x\n",secs);

    days = secs / ( 24 * 60 * 60 );

    if ( days > 0 )			//超过一天
    {
        temp = days;

        while ( temp >= 365 )
        {
            if ( Is_LeapYear ( years ) )				//是闰年
            {
                if ( temp >= 366 )
                {
                    temp -=	366;	//闰年的天数
                }
                else
                {
                    break;
                }
            }
            else
            {
                temp -= 365;
            }

            years++;
        }

        DS1302_DateTime.Year = years - 2000;			 //得到年份

        while ( days >= 28 )
        {
            if ( Is_LeapYear ( years ) && ( months == 1 ) )	 //判断是否为闰年的第二月
            {
                if ( temp >= 29 )
                    temp -= 29;
                else
                    break;
            }
            else
            {
                if ( temp >= Days_Table[months] )
                    temp -= Days_Table[months];
                else
                    break;
            }

            months++;
        }

        DS1302_DateTime.Month = months + 1;			//得到月数
        DS1302_DateTime.Date  = temp + 1;				//得到日期
    }

    temp = secs % ( 24 * 60 * 60 );						//得到剩余秒数
    DS1302_DateTime.Hour = temp / ( 60 * 60 );			//得到小时
    DS1302_DateTime.Minute = ( temp % ( 60 * 60 ) ) / 60;
    DS1302_DateTime.Second = ( temp % ( 60 * 60 ) ) % 60;
    DS1302_DateTime.Day = GetDayFromDate ( DS1302_DateTime.Year, DS1302_DateTime.Month, DS1302_DateTime.Date );
    DS1302_DateTime.HourMode = _24_hours;
    DS1302_DateTime.AM_PM = pm;
}

//计算今天是一年中的第多少天
int sum_Yday ( int a, int b, int c )
{
    int i;

    char h1[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    char h2[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    for ( i = 1; i < b; i++ )
    {
        if ( a % 4 == 0 && a % 100 != 0 || a % 400 == 0 )
            c = h1[i] + c;
        else
            c = h2[i] + c;
    }

    return ( c );
}

