/**
  *****************************************************************************************************
  * @file    kpm32xx_ddl.c
  * @author  Kiwi Software Team
  * @brief   Common DDL module driver.
  *          This file provides software functions to manage CPU Systick functionalities, including:
  *           + Systick Initializes
  *           + Configure Systick Frequency
  *           + System Delay Function
  *           + Suspend/Resume Systick
  * @note
  *          V1.0.0, 2024/12/20.
  *
  * Copyright (c) 2024, Kiwi Instruments Co,. Ltd.
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *
  *   3. Neither the name of the copyright holder nor the names of its contributors
  *      may be used to endorse or promote products derived from this software without
  *      specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************************************
  */


#include "kpm32xx_ddl.h"

#ifdef DDL_MODULE_ENABLED

__IO uint32_t uwTicks;
uint32_t uwTickPriority = (1UL << __NVIC_PRIO_BITS);
DDL_TickFreq_T uwTickFreq = DDL_TICKFREQ_DEFAULT;  /* 1KHz */


/**
  * @brief  Initialize systick.
  * @retval DDL status
  */
DDL_Status_T DDL_Init(void)
{
	DDL_Status_T  status = DDL_OK;

	if (DDL_InitTick(TICK_INT_PRIORITY) != DDL_OK)
	{
		status = DDL_ERROR;
	}

	return status;
}


/**
  * @brief  This function configures time source to have 1ms 10ms or 100ms time base with a dedicated
  *         Tick interrupt priority.
  * @param  tickPriority Tick interrupt priority.
  * @retval HAL status
  */
__weak DDL_Status_T DDL_InitTick(uint32_t tickPriority)
{
	DDL_Status_T  status = DDL_OK;

	if ((uint32_t)uwTickFreq != 0U)
	{
		/* Configure the SysTick to have interrupt in 1ms 10ms or 100ms time basis
		 * depending on the definition of uwTickFreq.
		 */
		if (SysTick_Config(systemCoreClock / (1000U /(uint32_t)uwTickFreq)) == 0U)
		{
			/* Configure the SysTick IRQ priority */
			if (tickPriority < (1UL << __NVIC_PRIO_BITS))
			{
				NVIC_SetPriority(SysTick_IRQn, tickPriority);
				uwTickPriority = tickPriority;
			}
			else
			{
				status = DDL_ERROR;
			}
		}
		else
		{
			status = DDL_ERROR;
		}
	}
	else
	{
		status = DDL_ERROR;
	}

	return status;
}


/**
  * @brief  This function is called to increment a software "Tick".
  * @retval None
  */
__weak void DDL_IncTick(void)
{
	uwTicks += (uint32_t)uwTickFreq;
}


/**
  * @brief  Return tick value in millisecond.
  * @retval tick value
  */
__weak uint32_t DDL_GetTick(void)
{
	return uwTicks;
}


/**
  * @brief  This function returns Systick priority.
  * @retval tick priority
  */
uint32_t DDL_GetTickPrio(void)
{
	return uwTickPriority;
}


/**
  * @brief  Set new tick tickFreq.
  * @retval status
  */
DDL_Status_T DDL_SetTickFreq(DDL_TickFreq_T tickFreq)
{
	DDL_Status_T status  = DDL_OK;
	DDL_TickFreq_T prevTickFreq;
	ASSERT_PARAM(IS_TICKFREQ(tickFreq));

	if (uwTickFreq != tickFreq)
	{
		prevTickFreq = uwTickFreq;

		uwTickFreq = tickFreq;

		status = DDL_InitTick(uwTickPriority);
		if (status != DDL_OK)
		{
			uwTickFreq = prevTickFreq;
		}
	}

  return status;
}


/**
  * @brief  Get new tick tickFreq.
  * @retval Tick frequency
  */
DDL_TickFreq_T DDL_GetTickFreq(void)
{
	return uwTickFreq;
}

/**
  * @brief  This function provides delay in milliseconds.
  * @note   Caution: The SysTick interrupt must have higher priority, in case that it's called
  *         in a certain peripheral ISR. Otherwise, the caller ISR process will be blocked.
  * @param  Delay  delay time, in milliseconds.
  * @retval None
  */
__weak void DDL_Delay(uint32_t delay)
{
	uint32_t tickStart = DDL_GetTick();
	uint32_t wait = delay;

	if (wait < DDL_MAX_DELAY)
	{
		wait += (uint32_t)(uwTickFreq);
	}

	while ((DDL_GetTick() - tickStart) < wait)
	{

	}
}


/**
  * @brief  Suspend Tick increment.
  * @note   DDL_SuspendTick() will disable Systick interrupt.
  *
  * @retval None
  */
__weak void DDL_SuspendTick(void)
{
	/* Disable SysTick Interrupt */
	CLEAR_BIT(SysTick->CTRL,SysTick_CTRL_TICKINT_Msk);
}


/**
  * @brief  Resume Tick increment.
  * @note   DDL_ResumeTick() will enable Systick interrupt.
  *
  * @retval None
  */
__weak void DDL_ResumeTick(void)
{
	/* Enable SysTick Interrupt */
	SET_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
}

#endif /* DDL_MODULE_ENABLED */

