/*
 *  Routines to access hardware
 *
 *  Copyright (c) 2013 Realtek Semiconductor Corp.
 *
 *  This module is a confidential and proprietary property of RealTek and
 *  possession or use of this module requires written permission of RealTek.
 */

#include "device.h"
#include <time.h>
#include "timer_api.h"
#include "main.h"


#define SW_RTC_TIMER_ID        TIMER4

static gtimer_t sw_rtc;
static volatile struct tm rtc_timeinfo;

const static u8 dim[14] = { 
	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28 };

static inline bool is_leap_year(unsigned int year)
{
	return (!(year % 4) && (year % 100)) || !(year % 400);
}

	
static u8 days_in_month (u8 month, u8 year)
{
	u8 ret = dim [ month - 1 ];
	if (ret == 0)
		ret = is_leap_year (year) ? 29 : 28;
	return ret;
}	

static void sw_rtc_tick_handler(uint32_t id)
{
    if(++rtc_timeinfo.tm_sec > 59) {                               // Increment seconds, check for overflow
        rtc_timeinfo.tm_sec = 0;                                   // Reset seconds
        if(++rtc_timeinfo.tm_min > 59) {                           // Increment minutes, check for overflow
            rtc_timeinfo.tm_min = 0;                               // Reset minutes
            if(++rtc_timeinfo.tm_hour > 23) {                      // Increment hours, check for overflow
                rtc_timeinfo.tm_hour = 0;                          // Reset hours
                ++rtc_timeinfo.tm_yday;                            // Increment day of year
                if(++rtc_timeinfo.tm_wday > 6)                     // Increment day of week, check for overflow
                    rtc_timeinfo.tm_wday = 0;                      // Reset day of week
                                                        // Increment day of month, check for overflow
                if(++rtc_timeinfo.tm_mday >
                    days_in_month(rtc_timeinfo.tm_mon, rtc_timeinfo.tm_year)) {
                    rtc_timeinfo.tm_mday = 1;                      // Reset day of month
                    if(++rtc_timeinfo.tm_mon > 11) {               // Increment month, check for overflow
                        rtc_timeinfo.tm_mon = 0;                   // Reset month
                        rtc_timeinfo.tm_yday = 0;                  // Reset day of year
                        ++rtc_timeinfo.tm_year;                    // Increment year
                    }                                   // - year       
                }                                       // - month
            }                                           // - day
        }                                               // - hour
    }                                     
}

static void rtc_init(void)
{
    // Initial a periodical timer
    gtimer_init(&sw_rtc, SW_RTC_TIMER_ID);
    
    // Tick every 1 sec
    gtimer_start_periodical(&sw_rtc, 1000000, (void*)sw_rtc_tick_handler, (uint32_t)&sw_rtc);
}

static void rtc_deinit(void)
{
    gtimer_stop(&sw_rtc);
    gtimer_deinit(&sw_rtc);
}

static void rtc_set_time(uint32_t year, uint8_t mon, uint8_t mday, uint8_t wday, 
    uint8_t hour, uint8_t min, uint8_t sec)
{
    int i;
    
    gtimer_stop(&sw_rtc);
    rtc_timeinfo.tm_sec = sec;
    rtc_timeinfo.tm_min = min;
    rtc_timeinfo.tm_hour = hour;
    rtc_timeinfo.tm_mday = mday-1;  
    rtc_timeinfo.tm_wday = wday-1;
    rtc_timeinfo.tm_yday = 0;
    for (i=0;i<(mon-1);i++) {
        rtc_timeinfo.tm_yday += days_in_month(i,year);
    }
    rtc_timeinfo.tm_yday += (mday-1);
    rtc_timeinfo.tm_mon = mon-1;
    rtc_timeinfo.tm_year = year;
    gtimer_start(&sw_rtc);
}

static void rtc_read_time(struct tm *timeinfo)
{
    _memcpy((void*)timeinfo, (void*)&rtc_timeinfo, sizeof(struct tm));
    timeinfo->tm_mon++;
    timeinfo->tm_mday++;
    timeinfo->tm_wday++;
    timeinfo->tm_yday++;
}

void main(void)
{
    struct tm timeinfo;

    rtc_init();
    
    // Give RTC a initial value: 2015/4/15 (Wed) 12:00:00
    rtc_set_time(2015, 4, 15, 3, 12, 0, 0);

    while (1) {
        rtc_read_time(&timeinfo);
        DBG_8195A("%d-%d-%d[%d] %d:%d:%d\r\n", timeinfo.tm_year, timeinfo.tm_mon, timeinfo.tm_mday,
            timeinfo.tm_wday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
        wait_ms(1000);
    }
    rtc_deinit();
}