/*
 * \file stm32f10x_systick.c
 * \brief   Provides systick timer functionality.
 *
 * Copyright (C) 2013 Christos Choutouridis <houtouridis.ch@gmail.com>
 * All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Christos Choutouridis. The intellectual
 * and technical concepts contained herein are proprietary to
 * Christos Choutouridis and are protected by copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Christos Choutouridis.
 *
 * Author:     Christos Choutouridis <houtouridis.ch@gmail.com>
 * Date:       11/2013
 * Version:    0.2
 */

#include <stm32f10x_systick.h>

/* ================== Private data ======================= */

static clock_t volatile __sys_freq;    /*!< SysTick Interrupt Frequency */


__weak void SysTick_Callback (void) {
   /*! \note
    *    This function Should not be modified, when the callback is needed,
    *    the SysTick_Callback could be implemented in the user file
    */
}

/*!
 * \brief
 *    This is the SysTick ISR
 * \note
 *    To reduce the overhead of yet another API function to call from user's
 *    driver implementation. Driver defines an ISR here and a weak Callback.
 */
void SysTick_Handler(void) {
   SysTick_Callback ();
}

/*!
 * \brief  System Tick Configuration
 *
 * The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
 * Counter is in free running mode to generate periodic interrupts.
 *
 * \param [in]  ticks  Number of ticks between two interrupts.
 * \return          0  Function succeeded.
 * \return          1  Function failed.
 *
 */
static uint32_t _Config(uint32_t ticks)
{
   if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);     /* Reload value impossible */

   SysTick->LOAD  = ticks - 1;                                 /* set reload register */
   SysTick->VAL   = 0;                                         /* Load the SysTick Counter Value */
   SysTick->CTRL  = SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
   NVIC_SetPriority (SysTick_IRQn, 3U);                        /*Configure the SysTick IRQ */
   return (0);                                                 /* Function successful */
}

/*!
 * De-Initialize the SysTick
 */
void SysTick_DeInit (void)
{
   __sys_freq = 0;
   SysTick->CTRL  &= ~ (SysTick_CTRL_ENABLE_Msk |
                        SysTick_CTRL_TICKINT_Msk);             /* Enable SysTick IRQ and SysTick Timer */
}


/*!
 * Initialize and Start the SysTick with __sys_freq
 */
void SysTick_Init (clock_t sf)
{
   /*Configure the SysTick to have interrupt in sf time basis*/
    if (_Config ((SystemCoreClock>>3)/sf) != 0)
       __sys_freq = 0;
    else
       __sys_freq = sf;
}




/* ================== OS Like Functionalities ================== */

/*!
 * \brief Get the __sys_freq.
 */
inline clock_t get_freq (void){
   return __sys_freq;
}

/*!
 * \brief Reconfigure the SysTick and update __sys_freq
 */
int set_freq (clock_t sf)
{
   if ((__sys_freq != sf) && (_Config ((SystemCoreClock>>3)/sf) == 0)) {
      __sys_freq = sf;
   }
   return 0;
}

