/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    GKI_misc.c
* Description:  Misc abstraction layer
*
* Copyright (c) 2016 Amped'RF Technology Inc, All rights reserved.
*******************************************************************************/
#ifdef SDK
#include "SDK_Common.h"
#include "GKI_lib.h"


void GKI_misc_Enable_Peripherals(void)
{
#if defined(STM32F10x)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,  ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,  ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,  ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
#elif defined(STM32F2xx) || defined(STM32F4xx)

#endif
}


/*******************************************************************************
* GKI_misc_Reset_Peripherals - was Reset_ABP_Peripherals
* Reset all APB1 & APB2 Peripherals
*******************************************************************************/
void GKI_misc_Reset_Peripherals(void)
{
#if defined(STM32F10x)
    u32 APB1_ENB = {
        //RCC_APB1Periph_TIM2    |
        //RCC_APB1Periph_TIM3    |
        //RCC_APB1Periph_TIM4    |
        //RCC_APB1Periph_TIM5    |
        //RCC_APB1Periph_TIM6    |
        //RCC_APB1Periph_TIM7    |
        //RCC_APB1Periph_WWDG    |
        //RCC_APB1Periph_SPI2    |
        //RCC_APB1Periph_SPI3    |
        RCC_APB1Periph_USART2  |
        //RCC_APB1Periph_USART3  |
        //RCC_APB1Periph_UART4   |
        //RCC_APB1Periph_UART5   |
        //RCC_APB1Periph_I2C1    |
        //RCC_APB1Periph_I2C2    |
        //RCC_APB1Periph_USB     |
        //RCC_APB1Periph_CAN     |
        RCC_APB1Periph_BKP     |
        RCC_APB1Periph_PWR     |
        //RCC_APB1Periph_DAC     |
        0
    };
    u32 APB2_ENB = {
        RCC_APB2Periph_AFIO    |
        RCC_APB2Periph_GPIOA   |
        RCC_APB2Periph_GPIOB   |
        RCC_APB2Periph_GPIOC   |
        //RCC_APB2Periph_GPIOD   |
        //RCC_APB2Periph_GPIOE   |
        //RCC_APB2Periph_GPIOF   |
        //RCC_APB2Periph_GPIOG   |
        //RCC_APB2Periph_ADC1    |
        //RCC_APB2Periph_ADC2    |
        RCC_APB2Periph_TIM1    |
        //RCC_APB2Periph_SPI1    |
        //RCC_APB2Periph_TIM8    |
        RCC_APB2Periph_USART1  |
        //RCC_APB2Periph_ADC3    |
        0
    };

    // Reset all APB1 peripherals
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_ALL, DISABLE);
    RCC_APB1PeriphClockCmd(APB1_ENB, ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_ALL, DISABLE);

    // Reset all APB2 peripherals
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL, DISABLE);
    RCC_APB2PeriphClockCmd(APB2_ENB, ENABLE);
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ALL, DISABLE);
#endif
}


/*******************************************************************************
* SerialKeyPressed
* Check for key press
*******************************************************************************/
u32 SerialKeyPressed(u8 *key)
{
  if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
  {
    *key = (u8)USART1->DR;
    return 1;
  }
  else
  {
    return 0;
  }
}




/*******************************************************************************
* GKI_rcc_Configuration
* rcc configuration
*******************************************************************************/
void GKI_rcc_Configuration(void)
{
#if defined(STM32F2xx) || defined(STM32F4xx)
    // RCC_DeInit();
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    GPIO_PinAFConfig(_BASE(IO_MAIN_TX), _PIN(IO_MAIN_TX),  GPIO_AF_USART1);
    GPIO_PinAFConfig(_BASE(IO_MAIN_RX), _PIN(IO_MAIN_RX),  GPIO_AF_USART1);
    GPIO_PinAFConfig(_BASE(IO_HCI_TX),  _PIN(IO_HCI_TX),   GPIO_AF_USART2);
    GPIO_PinAFConfig(_BASE(IO_HCI_RX),  _PIN(IO_HCI_RX),   GPIO_AF_USART2);

    // Enable Prefetch Buffer and X wait states
    FLASH_PrefetchBufferCmd(ENABLE);
    FLASH_SetLatency(FLASH_Latency_7);

    // Timer
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    TIM_TimeBaseInitTypeDef Timer;
    TIM_TimeBaseStructInit(&Timer);
    Timer.TIM_Period            = 0xFFFFFFFF;
    Timer.TIM_Prescaler         = 0x0000;
    Timer.TIM_ClockDivision     = TIM_CKD_DIV4;
    Timer.TIM_CounterMode       = TIM_CounterMode_Up;
    Timer.TIM_RepetitionCounter = 0x0000;
    TIM_TimeBaseInit(TIM1, &Timer);
    TIM_Cmd(TIM1, ENABLE);
#endif
}



/*******************************************************************************
* GKI_READ_IPSR
* Read interrupt flag
*******************************************************************************/
u16 GKI_READ_IPSR(void)
{
#if defined(STM32F10x)
    return __READ_IPSR();
#elif defined(STM32F2xx)
    return __READ_IPSR();
#else
    return __get_IPSR();
#endif
}



/*******************************************************************************
* GKI_READ_IPSR
* Read interrupt flag
*******************************************************************************/
void GKI_misc_LowPowerMode(void)
{
    NVIC_SystemLPConfig(NVIC_LP_SEVONPEND,   ENABLE);
    NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP,   DISABLE);
    NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT, DISABLE);
    __WFE();
}


/*******************************************************************************
* UT_CRC32Buffer
* Compute CRC-32 Polynomial using STM32 Hardware
*******************************************************************************/
uint32 UT_CRC32Buffer(uint8 *pBuf, uint16 BufLen)
{
#if defined(STM32F10x)
    uint16 i;
    uint8 buf[4];

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
    CRC_ResetDR();

    while (BufLen >= 4) {
        CRC_CalcCRC(*(u32 *)pBuf);
        pBuf += 4;
        BufLen -= 4;
    }

    // Zero pad end of buffer
    if (BufLen>0) {
        *(uint32 *)buf = 0;
        for (i=0; i<BufLen; i++) {
            buf[i] = pBuf[i];
        }
        CRC_CalcCRC(*(u32 *)buf);
    }

    return CRC_GetCRC();

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

    return 0;
#endif
}


/*******************************************************************************
* GKI_tim_SetUpTickTimer
* Delay in microseconds
*******************************************************************************/
#include "TM_SystemResource.h"
void GKI_tim_SetUpTickTimer(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
	TIM_DeInit(TIM5);
	memset(&TIM_TimeBaseInitStruct, 0, sizeof(TIM_TimeBaseInitStruct));
	TIM_TimeBaseInitStruct.TIM_Period						= 0xffffffff;
    TIM_TimeBaseInitStruct.TIM_Prescaler                    = 0;//PreScale-1;
    TIM_TimeBaseInitStruct.TIM_CounterMode                  = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_ClockDivision                = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter            = 0;
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStruct);

    TIM_Cmd(TIM5, ENABLE);                                 // Start timer
}


/*******************************************************************************
* GKI_tim_SetUpTickTimer
* Delay in microseconds
*******************************************************************************/
void GKI_WaitMicro(u32 usDelay)
{
    static bool initialized = false;
	static uint32 TIMER_TICK_CLOCK, K;
	uint32 TimerCntPre, TimerCntNow, TimerCntStop, INTERVAL_SET;
	TIM5->CNT = 0;
	//TimerCntPre = 0;//TimerCntPre = TIM_GetCounter(TIM5);
    if (!initialized)
    {
    	GKI_tim_SetUpTickTimer();
		RCC_ClocksTypeDef RCC_Clocks;
		RCC_GetClocksFreq(&RCC_Clocks);
    	TIMER_TICK_CLOCK = RCC_Clocks.PCLK1_Frequency;
		u32 APB1_PreScaler = (RCC->CFGR & RCC_CFGR_PPRE1);
		if (APB1_PreScaler != RCC_CFGR_PPRE1_DIV1 ) {
			TIMER_TICK_CLOCK *= 2;
		}
		K = TIMER_TICK_CLOCK / 1000000;
		initialized = true;
		TimerCntPre = TIM_GetCounter(TIM5);
    }
	INTERVAL_SET = (uint32)K * usDelay;
	//TimerCntStop = TimerCntPre + INTERVAL_SET;
	TimerCntStop = INTERVAL_SET;
	TimerCntNow = TIM5->CNT;
	while(TimerCntNow < TimerCntStop){
		TimerCntNow = TIM5->CNT;
	}
	//TIM5->CNT = 0;
	/*static uint8 test_flag;
	if(test_flag<1){
	  	test_flag++;
		if(test_flag == 1){
			char msg[128];
			sprintf(msg, "initialized=%d, dly=%ld, set=%ld, clk=%ld, pre=%ld, now=%ld\r\n", initialized, usDelay, INTERVAL_SET, TIMER_TICK_CLOCK, TimerCntPre, TimerCntNow);
			GKI_putstring(msg);
			test_flag = 1;
		}
	}*/
}


/*******************************************************************************
* GKI_goto_bootloader
*******************************************************************************/
void GKI_goto_bootloader(void)
{
    ENTER_CRITICAL();
    //NVIC_SETPRIMASK();
    //NVIC_DeInit();                      // Deinitialize NVIC
    NVIC_SetVectorTable(0x08000000, 0); // Bootloader Vector = 0x08000000
    //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, DISABLE);
    //CC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, DISABLE);
    GKI_misc_Reset_Peripherals();
    NVIC_SystemReset();
    EXIT_CRITICAL();
}


/*******************************************************************************
* GKI_Reboot
* Reboot module
*******************************************************************************/
void GKI_Reboot(void)
{
    ENTER_CRITICAL();
    NVIC_SystemReset();
    EXIT_CRITICAL();
}





/*******************************************************************************
* UT_PrettyNumber
* Format a number
*******************************************************************************/
static char *UT_PrettyNumber(char *buf, sint32 num)
{
    char numtext[20], *n;
    char *b=buf;
    int len;
    if (num<0) {
        *buf++ = '-';
        num = abs(num);
    }
    sprintf(numtext, "%d", num);
    n = numtext;
    len = strlen(numtext);
    while (len) {
        *b++ = *n++;
        len--;
        if ((len > 0) && (len%3 == 0))
            *b++ = ',';
    }
    *b = '\0';

    return buf;
}



/*******************************************************************************
* GKI_ShowCpu
* Show CPU speed settings
*******************************************************************************/
void GKI_ShowCpu(void)
{
#if defined(STM32F10x)

    RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq(&RCC_Clocks);
    const char Fmt0[]="   %c %3.3s: %10.10s Hz";
    const char Fmt1[]="%8.8s: %10.10s Hz";
    const char Fmt2[]="%8.8s: %10.10s Baud";
    const char Fmt3[]="%8.8s: %10.10s Hz - Out of spec";
    char * pFmt;
    const char *SysClkSrcTxt[]={"HSI","HSE","PLL","???"};
    const char *PllClkSrcTxt[]={"HSI","HSE"};
    uint32 PllClkSrc;
    uint32 SysClkSrc;
    char buf[20];
    u32 tmpreg = 0;
    //u32 CFGR_PLL_Mask             =((u32)0xFFC0FFFF);
    u32 CFGR_PLLMull_Mask         =((u32)0x003C0000);
    u32 CFGR_PLLSRC_Mask          =((u32)0x00010000);
    u32 CFGR_PLLXTPRE_Mask        =((u32)0x00020000);
    u32 CFGR_HPRE_Mask            =((u32)0x000000F0);

    PllClkSrc = (RCC->CFGR & 0x00010000)>>16;
    SysClkSrc = RCC_GetSYSCLKSource()>>2;

    tmpreg = RCC->CFGR;

    //TM_printlf("PLL      = 0x%08x", tmpreg&CFGR_PLL_Mask);
    TM_printlf("PLLSRC   = 0x%08x", tmpreg&CFGR_PLLSRC_Mask);
    TM_printlf("PLLXTPRE = 0x%08x", tmpreg&CFGR_PLLXTPRE_Mask);
    TM_printlf("PLLMull  = 0x%08x", tmpreg&CFGR_PLLMull_Mask);
    TM_printlf("HPRE     = 0x%08x", tmpreg&CFGR_HPRE_Mask);

    TM_printlf("SYSCLK Source = %s", SysClkSrcTxt[SysClkSrc]);
    TM_printlf("PLLCLK Source = %s", PllClkSrcTxt[PllClkSrc]);

    TM_printlf("   Clock  Speed");
    TM_printlf((char *)Fmt1, "HSE",      UT_PrettyNumber(buf, HSE_Frequency));

    pFmt = (char *)(RCC_Clocks.SYSCLK_Frequency>72000000 ? Fmt3 : Fmt1);
    TM_printlf((char *)pFmt, "SYSCLK",   UT_PrettyNumber(buf, RCC_Clocks.SYSCLK_Frequency));

    TM_printlf((char *)Fmt1, "HCLK",     UT_PrettyNumber(buf, RCC_Clocks.HCLK_Frequency));

    pFmt = (char *)(RCC_Clocks.PCLK1_Frequency>36000000 ? Fmt3 : Fmt1);
    TM_printlf((char *)pFmt, "PCLK1",    UT_PrettyNumber(buf, RCC_Clocks.PCLK1_Frequency));

    TM_printlf((char *)Fmt1, "PCLK2",    UT_PrettyNumber(buf, RCC_Clocks.PCLK2_Frequency));
    TM_printlf((char *)Fmt2, "HCI Uart", UT_PrettyNumber(buf, TM_UartDev[eTM_HciUart].Baudrate));
    TM_printflush();

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

    RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq(&RCC_Clocks);
    const char Fmt1[]="%8.8s: %11.11s Hz";
    char buf[20];
    char *HSE="HSE";
    char *HSI="HSI";
    uint8 sysclksrc = RCC_GetSYSCLKSource();
    uint32 pllclksrc = (RCC->PLLCFGR & RCC_PLLSource_HSE);

    if (sysclksrc == 0)
        HSI = "* HSI";
    else if (sysclksrc == 4)
        HSE = "* HSE";
    else if (pllclksrc & RCC_PLLSource_HSE)
        HSE = "* HSE";
    else
        HSI = "* HSI";

    TM_printlf("   Clock  Speed");
    TM_printlf((char *)Fmt1, HSE,        UT_PrettyNumber(buf, HSE_VALUE));
    TM_printlf((char *)Fmt1, HSI,        UT_PrettyNumber(buf, HSI_VALUE));
    TM_printlf((char *)Fmt1, "SYSCLK",   UT_PrettyNumber(buf, RCC_Clocks.SYSCLK_Frequency));
    TM_printlf((char *)Fmt1, "HCLK",     UT_PrettyNumber(buf, RCC_Clocks.HCLK_Frequency));
    TM_printlf((char *)Fmt1, "PCLK1",    UT_PrettyNumber(buf, RCC_Clocks.PCLK1_Frequency));
    TM_printlf((char *)Fmt1, "PCLK2",    UT_PrettyNumber(buf, RCC_Clocks.PCLK2_Frequency));
    TM_printflush();

#endif
}


//------------------------------------------------------------------------------
// Configure and start Watchdog for GKI_WATCHDOG_MS + 1 ms
//------------------------------------------------------------------------------
void GKI_WatchdogConfig(u32 ms)
{
    /*
    u8  Counter=0;
    u8  WindowValue=0;
    u32 Prescaler;
    RCC_ClocksTypeDef RCC_Clocks;

    RCC_GetClocksFreq(&RCC_Clocks);

    Prescaler = RCC_Clocks.PCLK1_Frequency / ms;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
    WWDG_SetPrescaler(WWDG_Prescaler_8);

    WWDG_SetWindowValue(WindowValue);

    WWDG_EnableIT();

    WWDG_Enable(Counter);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TM_ExtPriority;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    WWDG_EnableIT();
    */
}

//------------------------------------------------------------------------------
// Reset Watchdog
//------------------------------------------------------------------------------
void GKI_WatchdogReset(void)
{
  //  WWDG_SetCounter(20);
}


//------------------------------------------------------------------------------
// ISR for Watchdog
//------------------------------------------------------------------------------
void GKI_WatchdogISR(void)
{
    GKI_putstring("GKI_WatchdogISR()\r\n");
}


//------------------------------------------------------------------------------
// Calc Block CRC
//------------------------------------------------------------------------------
u32 GKI_misc_CalcBlockCRC(u32 *wrd)
{
    u32 result;
#if defined(STM32F10x)
    RCC_AHBP    eriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
    CRC_ResetDR();
    result = CRC_CalcBlockCRC(wrd, 1);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, DISABLE);
#else
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
    CRC_ResetDR();
    result = CRC_CalcBlockCRC((uint32_t *)wrd, 1);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, DISABLE);
#endif
    return result;
}

// Obsolete functions
void GKI_F2Test(void) {}

#endif // SDK
