/******************************************************************************
* $Revision: 423 $
* $Date:: 2017-04-07 16:03:30 +0900#$
*****************************************************************************/

/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/

/*****************************************************************************
** \file rtc.c
**
** A detailed description is available at
** @link RtcGroup Real time clock (RTC) description @endlink
**
** History:
**   - 2014-05-16  0.01  HS  Initial version for Traveo
*****************************************************************************/

#include "common_include.h"


uint32_t u32Count = 0;
uint8_t  m_u8Hours = 0;
uint8_t  m_u8Minutes = 0;
uint8_t  m_u8Seconds = 0;


static stc_rtc_intern_data_t m_stcRtcInternData;

void Rtc_Callback(void)
{
  
}

/*------------------------------------------------------------------
Function:       // bsp_RtcMode_Isr
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
__irq __arm void bsp_RtcMode_Isr(void)
{
    /* Clear interrupt flag */
    
    PDL_WRITE_REG_SYNC(RTC_WINC, RTC_WINS);

    if (m_stcRtcInternData.pfnCallback != NULL)
    {
        m_stcRtcInternData.pfnCallback();
    }

    IRC0_IRQHC = INTERRUPTS_IRQ_NUMBER_98;
}

/*------------------------------------------------------------------
Function:       // BSP_RTC_Init
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
void BSP_RTC_Init(void)
{
    m_stcRtcInternData.pfnCallback = &Rtc_Callback;
    
    RTC_WTCR_ST =1;
    while (0 == RTC_WTSR_RUN);
    RTC_WTCR_ST =0;
    
    RTC_WTCR_CSM = 0;         
    
    RTC_WRT   = 0x00000000;
    
    RTC_WTBR = 0x1E847F;      
    
    RTC_WTCR_UPDT = 1;        
    
    RTC_WTCR_RCKSEL = 0;       /*Main clock*/

    RTC_WINC = 0x7F;
    while(RTC_WINS !=  0);
    
    RTC_PWUTRGCR = 0x00032000;
    while(RTC_PWUTRGSR ==  0x0001);
    
    /* Interrupt Controller*/
    IRC0_UNLOCK = 0x17ACC911;
    IRC0_IRQHC = 98;
    IRC0_IRQCES3_IRQCES98 = 0x1;
    IRC0_UNLOCK = 0x17B10C11;
      
    RTC_WINE_SECE    = 0;     
    RTC_WINE_MINE    = 0;     
    RTC_WINE_HOURE   = 0;     
    RTC_WINE_DAYE    = 0;     
    RTC_WINE_SUBSECE = 0;     
    RTC_WINE_CALDE   = 0;     
    RTC_WINE_CFDE    = 0;      /*Calibration failure detection interrupt*/
    
    RTC_WTCR_ST = 1;
}
/*------------------------------------------------------------------
Function:       // Rtc_Stop
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
void Rtc_Stop(void)
{
    /* Disable interrupt */
    RTC_WINE_SECE = 0;
    
    /* Stop RTC and clear time settings */
    RTC_WTCR_ST =1;
    while (0 == RTC_WTSR_RUN);
    RTC_WTCR_ST =0;
}


/*------------------------------------------------------------------
Function:       // bsp_RTC_GetTime
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
void bsp_RTC_GetTime(uint8_t* pu8Hours, uint8_t* pu8Minutes, uint8_t* pu8Seconds)
{
    //*pu16Days   = RTC_RTR1_WTDR;
    *pu8Hours   = RTC_WRT_WTHR;
    *pu8Minutes = RTC_WRT_WTMR;
    *pu8Seconds = RTC_WRT_WTSR; 
}

/*------------------------------------------------------------------
Function:       // bsp_RTC_Service_GetTime
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
void bsp_RTC_Service_GetTime(uint16_t* pu16Days,uint8_t* pu8Hours, uint8_t* pu8Minutes)
{
    *pu16Days   = RTC_RTR1_WTDR;
    *pu8Hours   = RTC_WRT_WTHR;
    *pu8Minutes = RTC_WRT_WTMR;
}

/*------------------------------------------------------------------
Function:       // bsp_RTC_CalTime
Description:    // 
Input:          // 
Output:         //
Return:         //
Others:         //
-------------------------------------------------------------------*/
void bsp_RTC_CalTime(void)
{
    
    bsp_RTC_GetTime(&m_u8Hours, &m_u8Minutes, &m_u8Seconds);
}

/*! @} */
//#endif /* PDL_PERIPHERAL_RTC_ACTIVE */

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/

_TimeInfo TimeInfo;
uint32_t Set_rtc_time = 0;
void RTC_Service_SetTime(void)
{
    m_stcRtcInternData.pfnCallback = &Rtc_Callback;
    
    RTC_WTCR_ST =1;
    while (0 == RTC_WTSR_RUN);
    RTC_WTCR_ST =0;
    
    RTC_WTCR_CSM = 0; 
    
    Set_rtc_time = ((0 & 0x1f) | ((1 & 0x3f) << 8) | ((1 & 0x1f) << 16)) ;
    RTC_WRT = Set_rtc_time;
    
    RTC_RTR1_WTDR = 1;//RtcParameter.rtc_d;
    
    RTC_WTBR = 0x1E847F;      
    
    RTC_WTCR_UPDT = 1;        
    
    RTC_WTCR_RCKSEL = 0;       /*Main clock*/

    RTC_WINC = 0x7F;
    while(RTC_WINS !=  0);
    
    RTC_PWUTRGCR = 0x00032000;
    while(RTC_PWUTRGSR ==  0x0001);
    
    
    RTC_WTCR_ST = 1;
    

}

static int __isleap(int32_t year)
{
    return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
}

/* do a mathdiv for long type */
static int32_t math_div(int32_t a, int32_t b)
{
    return a / b - (a % b < 0);
}

/* How many leap years between y1 and y2, y1 must less or equal to y2 */
static int32_t leaps_between(int32_t y1, int32_t y2)
{
    int32_t leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) + math_div(y1 - 1, 400);
    int32_t leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) + math_div(y2 - 1, 400);
    return leaps2 - leaps1;
}

/* How many days come before each month (0-12). */
static const unsigned short __mon_yday[2][13] = {
    /* Normal years. */
    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
    /* Leap years. */
    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};

#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)



void time64_to_tm(uint32_t totalsecs, int offset)
{
    int32_t days, rem, y;
    int remainder;
    const unsigned short *ip;
    remainder = totalsecs % SECS_PER_DAY;
    days = totalsecs / SECS_PER_DAY;
    rem = remainder;
    rem += offset;
    while (rem < 0)
    {
        rem += SECS_PER_DAY;
        --days;
    }
    while (rem >= SECS_PER_DAY)
    {
        rem -= SECS_PER_DAY;
        ++days;
    }
    TimeInfo.tm_hour = rem / SECS_PER_HOUR;
    rem %= SECS_PER_HOUR;
    TimeInfo.tm_min = rem / 60;
    TimeInfo.tm_sec = rem % 60;
    /* January 1, 1970 was a Thursday. */
    TimeInfo.tm_wday = (4 + days) % 7;
    if (TimeInfo.tm_wday < 0)
        TimeInfo.tm_wday += 7;
    y = 1970;

    while (days < 0 || days >= (__isleap(y) ? 366 : 365))
    {
        /* Guess a corrected year, assuming 365 days per year. */
        int32_t yg = y + math_div(days, 365);
        /* Adjust DAYS and Y to match the guessed year. */
        days -= (yg - y) * 365 + leaps_between(y, yg);
        y = yg;
    }
    TimeInfo.tm_year = y;
    TimeInfo.tm_yday = days;
    ip = __mon_yday[__isleap(y)];
    for (y = 11; days < ip[y]; y--)
        continue;
    days -= ip[y];
    TimeInfo.tm_mon = y + 1;
    TimeInfo.tm_mday = days + 1;
    TimeInfo.A[0] = 1;
    TimeInfo.A[1] = 1;
    TimeInfo.A[2] = 1;
    TimeInfo.A[3] = 1;
}


/*
?* mktime64 - Converts date to seconds.
?* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
?* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
?* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
?*
?* [For the Julian calendar (which was used in Russia before 1917,
?* Britain & colonies before 1752, anywhere else before 1582,
?* and is still in use by some communities) leave out the
?* -year/100+year/400 terms, and add 10.]
?*
?* This algorithm was first published by Gauss (I think).
?*
?* A leap second can be indicated by calling this function with sec as
?* 60 (allowable under ISO 8601). ?The leap second is treated the same
?* as the following second since they don't exist in UNIX time.
?*
?* An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
?* tomorrow - (allowable under ISO 8601) is supported.
?*/
uint32_t mktime64(const unsigned int year0, const unsigned int mon0,
                  const unsigned int day, const unsigned int hour,
                  const unsigned int min, const unsigned int sec)
{
    unsigned int mon = mon0, year = year0;

    /* 1..12 -> 11,12,1..10 */
    if (0 >= (int)(mon -= 2))
    {
        mon += 12; /* Puts Feb last since it has leap day */
        year -= 1;
    }

    return ((((uint32_t)(year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + year * 365 - 719499) *  24 + hour /* now have hours - midnight tomorrow handled here */ ) * 60 + min /* now have minutes */ ) * 60 + sec; /* finally seconds */
}

