/**
  *****************************************************************************************************
  * @file    main.c
  * @author  Kiwi Software Team
  * @brief   This example code demonstrates how Fault_PCI(FPCI) works.
  * @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 "main.h"
#include "kpm32xx_demoboard_ddl.h"
#include <string.h>


TIMH_ClkInit_T     timhClkStruct  = {0};
TIMH_BaseInit_T    timh0_BaseInit = {0};
TIMH_yPCI_Init_T   fpciInit       = {0};
TIMH_Overwrite_T   overWrite      = {0};

EBUS_Init_T        eBusStruct;

void Error_Handler(void);


#if defined (__DEBUG_CONSOLE_PRINT__)
/**
  * @brief  This function is implemented for UART print PinMux configuration.
  * @param  None
  * @retval None
  */
void DebugConsole_PinMux_Config(void)
{
	/* SCI1 UART Tx */
	DDL_GPIO_Config2AltFunc(GPIOA, GPIO_PIN_7, GPIOA7_AF1_SCI1_TX_SDA_MOSI);
}
#endif


/**
  * @brief  This function is implemented for system clock configuration.
  *         where:
  *         System Clock source            = PLL (HIRC)
  *         System Clock frequency         = 100MHz
  * @param  None
  * @retval None
  */
void SystemClock_Config(void)
{
	RCC_PLLInit_T pllInitStruct    = {0};
	RCC_ClkInit_T rccClkInitStruct = {0};

	DDL_RCC_PllStructInit(&pllInitStruct);
	/* FCLK : 100MHz */
	pllInitStruct.pllPrescaler  = 4;
	if (DDL_RCC_PllConfig(&pllInitStruct) != DDL_OK)
	{
		while(1) ;
	}

	/* Select PLL as system clock source */
	rccClkInitStruct.sysClkSource  = RCC_SYSCLKSOURCE_PLLCLK;
	rccClkInitStruct.sysClkDivider = 0;
	if (DDL_RCC_ClkSrcConfig(&rccClkInitStruct) != DDL_OK)
	{
		while(1) ;
	}
}


/**
  * @brief  gpio and ioport Configuration
  * @param  None
  * @retval None
  */
static void gpio_and_ioport_init(void)
{
	IOPORT_Init_T ioPortInit;
	
	/* PA3 -> IO_Port PIN3 */
	ioPortInit.ioPortPin   = IOPORT_PIN_3;
	ioPortInit.edgeDect    = IOPORT_EDGEDECT_RISING;
	ioPortInit.ioSelect    = IOPORT_BITA;
	DDL_IOPort_Config(IOPORT, &ioPortInit);	
	
	/* PA0  */
	DDL_GPIO_Config2Output(GPIOA, GPIO_PIN_0, 0, GPIO_NOPULL);
}


/**
  * @brief  EBUS init
  * @param  None  
  * @retval None
  */
void ebus_init(void)
{
    DDL_EBUS_Instance_Active();
    DDL_EBUS_StructInit(&eBusStruct);
	
	eBusStruct.channel  = EBUS_CHN_8;
	eBusStruct.syncMode = EBUS_CHN_SYNC_MODE;
	eBusStruct.detSrc   = EBUS_CHN_DETSRC_SYNC;
	eBusStruct.mstrSrc  = EBUS_CHN_MSTR_IO3_SOURCE; /* IO_Port PIN3 */
	
	DDL_EBUS_Init(EBUS, &eBusStruct);
	printf("Break signal go through ebus channel_%d.\n", EBUS_CHN_8);
}


/**
  * @brief  TIMH0 Configuration
  * @param  None  
  * @retval None
  */
void timh0_init(void)
{
	/* Make TIMH active */
	DDL_TIMH_Instance_Activate();
	
	/* Config TIMH's clock by setting general functions register */
	DDL_TIMH_ClkStructInit(&timhClkStruct);
	DDL_TIMH_Clock_Init(&timhClkStruct);

	/* TIMHx's Init struct reset to default value */
	DDL_TIMH_BaseStructInit(&timh0_BaseInit);

	/* config TIMH_0's init struct */
	timh0_BaseInit.dutyCycle	= 0x4FF;
	timh0_BaseInit.period		= 0xFFF;
	timh0_BaseInit.phase		= 0;	
	timh0_BaseInit.clockSource	= TIMHx_CLOCKSOURCE_CLK_IN;
	timh0_BaseInit.counterMode 	= TIMH_CNT_MODE_INDEPENDENT_EDGE;
	timh0_BaseInit.outputMode   = TIMH_OUTPUT_COMPLEMENTARY;

	DDL_TIMH_Init(TIMH0, &timh0_BaseInit);
}


static void GpioAF_TIMH_Init(void)
{
	/* PC5(TIMH_CH0) & PC8(TIMH_CH0N) */
	DDL_GPIO_Config2AltFunc(GPIOC, GPIO_PIN_5, GPIOC5_AF3_TIMH_CH0);
	DDL_GPIO_Config2AltFunc(GPIOC, GPIO_PIN_8, GPIOC8_AF3_TIMH_CH0N);
}


/**
  * @brief  Fault_PCI(FPCI) Configuration
  * @param  None  
  * @retval None
  */
void Init_Fpci(void)
{
	DDL_TIMH_Overwrite_StructInit(&overWrite);
	DDL_TIMH_yPCI_StructInit(&fpciInit);
	
	/*
	 * config FPCI source and overwrite level
	 * !! FPCI Source_8 link to EBUS channel 8 !! 
	 */
	fpciInit.pciSource 	 = PCI_PSS_EBUS_CHANNEL_8; 
	overWrite.faultPwm_H = 0;
	overWrite.faultPwm_L = 0;

	/*pci setup*/
	DDL_TIMH_FPCI_Setup(TIMH0, &fpciInit, &overWrite);
}


/**
  * @brief  Break signal enable
  * @param  None  
  * @retval None  
  * @note   PA0 = 1
  */
void Break_Signal_Enable(void)
{
	DDL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
}


/**
  * @brief  Break signal disable
  * @param  None  
  * @retval None   
  * @note   PA0 = 0
  */
void Break_Signal_Disable(void)
{
	DDL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
}


/**
  * @brief modify the overwrite value of FPCI(TIMH0).
  * @param pwmH --> overWrite.faultPwm_H
  * @param pwmL --> overWrite.faultPwm_L
  * @retval None
  */
void Modify_Overwrite_FPCI(uint8_t pwmH,uint8_t pwmL)
{
	/* strongly recommend read the value of register first!! */
	*((uint32_t *)(&overWrite)) = TIMH0->IOCON;
	
	/* secondly, modify overwrite value. */
	overWrite.faultPwm_H      = pwmH;
	overWrite.faultPwm_L      = pwmL;
	DDL_TIMH_Overwrite_Config(TIMH0, &overWrite);
	
	/*
     * PA0 set 1, break signal input to FPCI, then PCI active signal = 1. 
     * pwm waveform will fourced output as 'overWrite.faultPwm_H' and 'overWrite.faultPwm_L' config.
	 */
	Break_Signal_Enable();
	DDL_Delay(2);
	
	/* pwm waveform output restore and last 2ms. */
	Break_Signal_Disable();
	DDL_Delay(2);	
}


/**
  * @brief  Demo main.
  * @param  None
  * @retval None
  * @note  
  * What is this demo doing :
  *
  * FPCI of timh0 control pwm waveform(break the waveform). 
  * peripheral(ioport/PA3) link to FPCI with EBUS.
  * PA0 will generate a break signal by sofeware.
  * 
  * PA0(Break signal) --> PA3(Ioport) --> EBUS --> FPCI(timh0)
  * 
  * 1. Connect PA0 to PA3.
  * 
  * 2. PA0 ouput as hardware break signal. This signal is source of falut_pci(FPCI).
  *    PA0 = 1 , break enable.
  *    PA0 = 0 , break disable.
  * 
  * 3. PA3 as hardware break signal input.
  * 
  * 4. You will see the pwm waveform like this:
  *	                _   _         _   _         _   ________   _   ________
  *   PWM_H(PC5) : | |_| |___0___| |_| |___0___| |_|    1   |_| |_|    1   |_
  *                   _             _   _______   _          _   _            ...
  *   PWM_L(PC8) : |_| |_____0_____| |_|   1   |_| |____0___| |_| |____0_____
  * 
  * 
  * !!More detail of the waveform please refer to : timh\fault_pci_FPCI\doc\
  */
int main(void)
{
	/* Reset of all peripherals. */
	DDL_Init();
	DDL_Delay(1000);
	SystemClock_Config();

#if defined (__DEBUG_CONSOLE_PRINT__)
	DebugConsole_PinMux_Config();
	DDL_SCI_Instance_Active(SCI1);
	DDL_SCIUart_DebugConsole_Init(SCI1);
	printf("TIMH FPCI demo start...\nConnect PA0 and PA3.\n");
#endif

	/* init EBUS */
	ebus_init();
	
	/* init gpio and ioport */
	DDL_GPIO_Instance_Active();
	gpio_and_ioport_init();
	GpioAF_TIMH_Init();
	BSP_LEDx_Init(LED_S2);
	
	/* init timh0 */
	timh0_init();
	
	/* init fault_pci(FPCI) */
	Init_Fpci();

	/* pwm waveform start output */
	DDL_TIMH_PWM_Start(TIMH0);
	DDL_Delay(2);
	
	
	/* 
	 * 1st type overwrite value :
	 * PWM_H = 0
	 * PWM_L = 0
	 */
	Break_Signal_Enable();
	DDL_Delay(2);
	
	/* pwm waveform output restore and last for 2ms. */
	Break_Signal_Disable();
	DDL_Delay(2);


	/* 
	 * 2nd type overwrite value :
	 * PWM_H = 0
	 * PWM_L = 1
	 */
	Modify_Overwrite_FPCI(0,1);
	
	
	/* 
	 * 3rd type overwrite value :
	 * PWM_H = 1
	 * PWM_L = 0
	 */	
	Modify_Overwrite_FPCI(1,0);


	/* 
	 * 4th type overwrite value :
	 * PWM_H = 1
	 * PWM_L = 1
	 *
	 * !! Attention, this type value will force PWM_H output 1 and PWM_L output 0.
	 *    more detail please refer to spec. of TIMH(chapter_17.4.4.3 -> table_274).
	 */	
	Modify_Overwrite_FPCI(1,1);


	/*stop PWM*/
	DDL_TIMH_PWM_Stop(TIMH0);
	
	while (1)
	{
		/* LED Twinkle */
		BSP_LEDx_Twinkle(LED_S2);
		DDL_Delay(200);
	}
}


/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None  
  * @retval None
  */
void Error_Handler(void)
{
    while (1);
}

