/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    GKI_rtc.c
* Description:  RTC abstraction layer
*
* Copyright (c) 2013 Amped'RF Inc., AR Technology  All rights reserved.
*******************************************************************************/
#include "Common.h"
#include "GKI_lib.h"
#include "AT_pvt.h"
#include "AT_Spp.h"

#define TM_TICKS_PER_SECOND         (4000)
#define TM_TICKS_PER_MILLISECOND    (TM_TICKS_PER_SECOND/1000)
#define TM_MS_TICKS                 TM_TICKS_PER_MILLISECOND

//#define ENABLE_LIB

//------------------------------------------------------------------------------
// Globals
//------------------------------------------------------------------------------
u32 RTC_AlarmValue=0;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
u32  GKI_rtc_GetCounter(void)
{
#if defined(STM32F10x)
    return RTC_GetCounter();
#elif defined(STM32F2xx) || defined(STM32F4xx)
    return TIM_GetCounter(TIM2);
#endif
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void  GKI_rtc_SetCounter(u32 tm)
{
#if defined(STM32F10x)
    RTC_SetCounter(tm);
#elif defined(STM32F2xx) || defined(STM32F4xx)
    TIM_SetCounter(TIM2, tm);
#endif
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GKI_rtc_SetAlarm(u32 tm)
{
#if defined(STM32F10x)
    RTC_SetAlarm(tm);
#elif defined(STM32F2xx) || defined(STM32F4xx)
    TIM_SetCompare1(TIM2, tm);
#endif
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GKI_rtc_ClearFlag(void)
{
#if defined(STM32F10x)
    RTC_ClearFlag(RTC_FLAG_ALR|RTC_FLAG_OW);
#elif defined(STM32F2xx) || defined(STM32F4xx)
    TIM_GetITStatus(TIM2, TIM_IT_CC1);
#endif
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GKI_rtc_ClearITPending(void)
{
    // Clear Alarm & Overflow pending flags
#if defined(STM32F10x)
    RTC_ClearITPendingBit(RTC_IT_ALR|RTC_IT_OW);
#elif defined(STM32F2xx) || defined(STM32F4xx)
    TIM_GetITStatus(TIM2, TIM_IT_CC1);
#endif
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GKI_rtc_ITConfig(FunctionalState NewState)
{
#if defined(STM32F10x)
    RTC_ITConfig(RTC_IT_ALR, NewState);
#elif defined(STM32F2xx) || defined(STM32F4xx)
    GKI_rtc_Setup();
#endif
}


//----------------------------------------------------------------------------
// RTC setup
//----------------------------------------------------------------------------
void GKI_rtc_Setup(void)
{
#if defined(STM32F10x)

    RCC_RTCCLKCmd(ENABLE);                  // Enable the RTC Clock
    RTC_WaitForSynchro();                   // Wait for APB registers synchronisation
    RTC_WaitForLastTask();                  // Wait until last write operation

    RTC_SetPrescaler(1);                            // 32768 KHz
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_SetCounter(0);                              // Zero RTC counter
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_ClearFlag(RTC_FLAG_ALR|RTC_FLAG_OW);        // Clear Alarm & Overflow flags
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_ClearITPendingBit(RTC_IT_ALR|RTC_IT_OW);    // Clear Alarm & Overflow pending flags
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_ITConfig(RTC_IT_OW, ENABLE);                // Enable Overflow
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_ITConfig(RTC_IT_ALR, ENABLE);               // Enable RTC alarms
    RTC_WaitForLastTask();                          // Wait until last write operation
    RTC_AlarmValue = 0xFFFFFFFF;

    // Setup RTC Channel
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                      = RTC_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = TM_RtcPriority;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

#elif defined(STM32F2xx) || defined(STM32F4xx)

    static bool initialized = false;

    if (!initialized) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
        GKI_rtc_SetCounter(0);
        GKI_rtc_Config();
        initialized = true;
    }

#endif
}


//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void GKI_rtc_Config(void)
{
    RCC_ClocksTypeDef       RCC_Clocks;
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    u16 PrescalerValue = 0;
    u32 rtc_counter;

    // save counter
    rtc_counter = GKI_rtc_GetCounter();

    // Get clock frequencies
    RCC_GetClocksFreq(&RCC_Clocks);

    // Enable TIM2 clock
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // Enable TIM2 Interrupt
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Compute the prescaler value */
    // PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1;
    PrescalerValue = ((RCC_Clocks.PCLK1_Frequency / 4) / 1000) - 1;

    // Time base configuration
    TIM_TimeBaseStructure.TIM_Period                = 0xFFFFFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler             = PrescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision         = TIM_CKD_DIV4;
    TIM_TimeBaseStructure.TIM_CounterMode           = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    // Output Compare Active Mode configuration: Channel1
    TIM_OCInitStructure.TIM_OCMode                  = TIM_OCMode_Toggle;
    TIM_OCInitStructure.TIM_OutputState             = TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_Pulse                   = TM_TICKS_PER_MILLISECOND;
    TIM_OCInitStructure.TIM_OCPolarity              = TIM_OCPolarity_High;
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
 //  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
 //  TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);         // TIM IT enable
    TIM_Cmd(TIM2, ENABLE);                          // TIM2 enable counter

    // restore counter
    GKI_rtc_SetCounter(rtc_counter);
}


//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void GKI_rtc_ReConfig(void)
{
    u32 rtc_compare;

    // Save alarm time
    rtc_compare = TIM2->CCR1;

    GKI_rtc_Config();

    // Restore alarm time
    TIM2->CCR1 = rtc_compare;
}

//----------------------------------------------------------------------------
//Init F4 RTC moudle
//----------------------------------------------------------------------------
bool gbLSI_Enable = false;
bool gbRTC_Working = false;

void GKI_F4_LSI_Disable(void)
{
	RCC_LSICmd(DISABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==SET);  
	gbLSI_Enable = false;
}

void GKI_F4_LSI_Enable(void)
{
 	RCC_LSICmd(DISABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==SET);
	RCC_LSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET); 
	gbLSI_Enable = true;
}

bool GKI_F4_RTC_Config(void)
{
 	static bool bInitialized = false;
	bool bSuccess = true;
	if(false == bInitialized){
	  	
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
		  
		PWR_BackupAccessCmd(ENABLE);
		RCC_BackupResetCmd(ENABLE);
		RCC_BackupResetCmd(DISABLE);
		   
		GKI_F4_LSI_Enable();
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);		
		  
		PWR_BackupAccessCmd(DISABLE);	
		RCC_RTCCLKCmd(ENABLE);
		RTC_WaitForSynchro();
		
		//if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x9527)
		{
		  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
			PWR_BackupAccessCmd(ENABLE);
			
			RCC_LSICmd(DISABLE);
			while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==SET);
			RCC_LSICmd(ENABLE);
			while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET); 
			RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);	
			
			RCC_RTCCLKCmd(ENABLE);
			RTC_WaitForSynchro();
			
    		RTC_WriteProtectionCmd(DISABLE);
			
    		RTC_EnterInitMode();			
			RTC_InitTypeDef RTC_InitStructure;
    		RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    		RTC_InitStructure.RTC_AsynchPrediv = 0x7D-1;
    		RTC_InitStructure.RTC_SynchPrediv = 0xFF-1;
			if(ERROR == RTC_Init(&RTC_InitStructure)){
				return false;
			}
			RTC_TimeTypeDef RTC_TimeStructure;
    		RTC_TimeStructure.RTC_Seconds = 0x50;//0x00;
    		RTC_TimeStructure.RTC_Minutes = 0x59;//0x01;
    		RTC_TimeStructure.RTC_Hours = 0x23;//0x01;
    		RTC_TimeStructure.RTC_H12 = RTC_H12_AM;
			if(ERROR == RTC_SetTime(RTC_Format_BCD,&RTC_TimeStructure)){
				return false;
			} 
			RTC_DateTypeDef RTC_DateStructure;
    		RTC_DateStructure.RTC_Date = 25;
    		RTC_DateStructure.RTC_Month = 9;
    		RTC_DateStructure.RTC_WeekDay= RTC_Weekday_Friday;
    		RTC_DateStructure.RTC_Year = 15;		
			if(ERROR == RTC_SetDate(RTC_Format_BIN,&RTC_DateStructure)){
				return false;
			}		
			RTC_OutputConfig(RTC_Output_AlarmA, RTC_OutputPolarity_Low);		
    		RTC_ExitInitMode();
			
    		RTC_WriteBackupRegister(RTC_BKP_DR0,0X9527);
    		RTC_WriteProtectionCmd(ENABLE);
		}
		
		
		NVIC_InitTypeDef NVIC_InitStructure;
			
		EXTI_InitTypeDef EXTI_InitStructure;
		EXTI_ClearITPendingBit(EXTI_Line17);
		EXTI_InitStructure.EXTI_Line = EXTI_Line17;
		EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
		EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
		EXTI_Init(&EXTI_InitStructure);
	
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); 
		NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
		NVIC_Init(&NVIC_InitStructure); 
		
		bInitialized = true;
	}
	gbRTC_Working = true;
	return bSuccess;
}

extern bool bAlarmTest;
void GKI_SetReconnectAlarm(uint8 Sec)
{
  	uint32 TimeSet;
	RTC_TimeTypeDef RtcTime; 
	tSIG_ReconnectInfo *pReconnectInfo;
	char bdaddr_buf[16];
	
	if(!bAlarmTest){
		pReconnectInfo = TM_LAST_CONNECTION;
		if (pReconnectInfo!=NULL)
		{
			UT_BdAddrToStr(&(pReconnectInfo->BdAddr), bdaddr_buf);
			if(!strcmp(bdaddr_buf, "000000000000")){
				return;  
			}
		}
	}
	
	while(!GKI_F4_RTC_Config());
	if(!gbLSI_Enable){
		GKI_F4_LSI_Enable();  
	}
	
	RTC_GetTime(RTC_Format_BIN, &RtcTime);
	TimeSet = RtcTime.RTC_Hours * 3600 + RtcTime.RTC_Minutes * 60 + RtcTime.RTC_Seconds + Sec;
	if(TimeSet >= 24 * 3600){
		TimeSet -= 24 * 3600;  
	}  
	
	RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
	RTC_AlarmTypeDef RTC_AlarmStructure;
	RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31;
	RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
	RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = TimeSet / 3600;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = (TimeSet % 3600) / 60;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = TimeSet % 60;
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStructure);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	
	RTC_ClearFlag(RTC_FLAG_ALRAF);
	EXTI_ClearITPendingBit(EXTI_Line17);
	
	RTC_ITConfig(RTC_IT_ALRA,ENABLE);
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);
}

void GKI_printfRtcTime(void)
{
  	RTC_TimeTypeDef RtcTime;
	RTC_GetTime(RTC_Format_BIN, &RtcTime);
	
	char msg[128];
	snprintf(msg, 128, "RTC time: %2d : %2d : %2d\r\n", RtcTime.RTC_Hours, RtcTime.RTC_Minutes, RtcTime.RTC_Seconds);
	GKI_putstring(msg); 
}

void GKI_printfAlarmATime(void)
{
  	RTC_AlarmTypeDef RtcAlarmTime;
	
	RTC_GetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RtcAlarmTime);
	RTC_TimeTypeDef *pRtcAlarmTime = &(RtcAlarmTime.RTC_AlarmTime);
	
	char msg[128];
	snprintf(msg, 128, "ALM time: %2d : %2d : %2d\r\n", pRtcAlarmTime->RTC_Hours, pRtcAlarmTime->RTC_Minutes, pRtcAlarmTime->RTC_Seconds);
	GKI_putstring(msg);
}

void Task_AutoReconnect(void);
void RTC_Alarm_IRQHandler(void)
{
	if(RTC_GetITStatus(RTC_IT_ALRA)!=RESET){	
		RTC_ClearITPendingBit(RTC_IT_ALRA);
		EXTI_ClearITPendingBit(EXTI_Line17);
		RTC_AlarmCmd(RTC_Alarm_A, DISABLE);	
		if(!bAlarmTest){
			Task_AutoReconnect();
		}
		if(bAlarmTest){
		  	bAlarmTest = false;
	  		GKI_putstring("alarm timeout\r\n");
		}
		gbRTC_Working = false;
	}
}

#ifdef TI2564
extern bool DsmWakePending;
extern bool Rf2564DSMflag;
#endif
void Task_AutoReconnect(void)
{
  	tAT_AppVar	*pAtVar = AT_GetAppVarPtr();
  	
#ifdef TI2564	
	tAT_SmartDev *pSmartDev = &pAtVar->SmartCable;
	if ((Rf2564DSMflag==true) && (DsmWakePending==false)){
		GKI_io_WriteBit(IO_HCI_RTS, 0);
		TM_Rf2564WakeReq();
		if (pSmartDev->Active == true){
			GKI_SetReconnectAlarm(2);
		}				 
	}
	else if (DsmWakePending == true){
		if (pSmartDev->Active == true){
			GKI_SetReconnectAlarm(2);
		}
	}
	if(Rf2564DSMflag==false)
#endif
	{  
		tBP_Signal    *pSignal= NULL;	
		ENTER_CRITICAL();
		pSignal = BP_IsrAllocSignal(SIG_AUTO_RECONNECT, 0);	
		if(pSignal){
			BP_IsrSend(BP_AT, pSignal);	
		}
		EXIT_CRITICAL();
	} 
}

//--------------------------------------------------------------
//