/*********************************************************************************************
Copyright <2024> <Icore Technology (Nanjing)  Co.,Ltd>
All Rights Reserved,
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.
**********************************************************************************************/

/*
*********************************************************************************************************
*                                              rx32s61xx
*                                           Library Function
*
*                                   Copyright 2024, RX Tech, Corp.
*                                        All Rights Reserved
*
*
* Project      : rx32s61xx
* File         : main.c
* By           : RX_SD_Team
* Version      : V1.0.0
* Description  : Only rx32s61xx
*********************************************************************************************************
*/
#include "main.h"

/*
*********************************************************************************************************
*                                           Global macro/Structure
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             Global variable
*********************************************************************************************************
*/
#define DATA_NUMBER             (10)
uint8_t TBuffer[DATA_NUMBER] = {0x10,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A};

__IO uint8_t TNum = 0;
											
uint8_t RBuffer[DATA_NUMBER] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

__IO uint8_t RNum = 0;

/*
*********************************************************************************************************
*                                           Global Function declaration
*********************************************************************************************************
*/

void Delay_us( uint32_t us )
{
	uint32_t Fsys;
	Fsys=RCC_Get_SystemClock()/1000000;
	//maximum:199728us 
	if( us*Fsys > SysTick_LOAD_RELOAD_Msk ) return;
	SysTick->CTRL = 0;      //Disable SysTick
	SysTick->LOAD = Fsys*us;//Set count number:72*us, 72 means 1us when SystemCoreClock is 72MHz
	SysTick->VAL  = 0;      //Clear current count number and count flag
	SysTick->CTRL = 5;      //Enable SysTick and Select SystemCoreClock as SysTick clock source
	while((SysTick->CTRL&0x10000)==0);//Wait for count flag set
	SysTick->CTRL = 0;      //Disable SysTick
}

void Delay_ms( uint32_t ms )
{
	uint32_t i;
	for(i=ms;i>0;i--)
	{
		Delay_us(1000);
	}
}

void SystemClock_Config(void)
{
	// set flash lantency
	FLASH_Set_Latency(FLASH_Latency_3);
	
  RCC_Enable_HSI();
  while(RCC_Get_HSIRDY() != 1)
  {
  }
  RCC_Set_PLLMUL(RCC_CFGR_PLLMUL_19x);
  RCC_Enable_PLL();
  while(RCC_Get_PLLRDY() != 1)
  {
  }
  RCC_Set_AHBPrescaler(RCC_CFGR_HPRE_DIV1);
  RCC_Set_APB1Prescaler(RCC_CFGR_PPRE1_DIV2);
  RCC_Set_APB2Prescaler(RCC_CFGR_PPRE2_DIV1);
  RCC_Set_SysClkSource(RCC_CFGR_SW_PLL);
  while(RCC_Get_SysClkSource() != RCC_CFGR_SWS_PLL)
  {
  }
  RCC_Set_ADCClkSource(RCC_CFGR_ADCCLK_SEL_PLL2);
  RCC_Set_ADCPrescaler(RCC_CFGR_ADCPRE_DIV5);
}

void I2C1_GPIO_Init(void)
{
	/* (1) Enables GPIO clock  **********************/
	/* Enable the peripheral clock of GPIOD */
  RCC_Enable_AHBClock(RCC_AHBENR_IOPDEN);

	/* Configure SCL Pin PD5 AF7 as : Alternate function, High Speed, Open drain, Pull up */
	GPIO_Set_PinMode(GPIOD, GPIO_PIN_5, GPIO_MODE_AF_PP);
	GPIO_Set_AF(GPIOD, GPIO_PIN_5, GPIO_AF7);
	GPIO_Set_PinOutSpeed(GPIOD, GPIO_PIN_5, GPIO_OSPEEDR_High);
	GPIO_Set_PinOutputType(GPIOD, GPIO_PIN_5, GPIO_OTYPER_OUT_Opendrain);
	GPIO_Set_PinPull(GPIOD, GPIO_PIN_5, GPIO_PUPDR_Pullup);

	/* Configure SDA Pin PD4 AF7 as : Alternate function, High Speed, Open drain, Pull up */
	GPIO_Set_PinMode(GPIOD, GPIO_PIN_4, GPIO_MODE_AF_PP);
	GPIO_Set_AF(GPIOD, GPIO_PIN_4, GPIO_AF7);
	GPIO_Set_PinOutSpeed(GPIOD, GPIO_PIN_4, GPIO_OSPEEDR_High);
	GPIO_Set_PinOutputType(GPIOD, GPIO_PIN_4, GPIO_OTYPER_OUT_Opendrain);
	GPIO_Set_PinPull(GPIOD, GPIO_PIN_4, GPIO_PUPDR_Pullup);
	
	/* (3) Configure I2C1 functional parameters ********************************/
	/* Disable I2C1 prior modifying configuration registers */
	I2C_Disable(I2C1);
}

void I2C1_Master_Init(void)
{
	/*Config I2C1 GPIO*/
	I2C1_GPIO_Init();
	/* Configure the SCL Clock Speed */
	//I2C_SPEEDCLOCK=ClockSpeed,100000 or 200000 or 400000kbit/s
	I2C_Set_Speed(I2C1, PCLK_1_Frequency, I2C_SPEEDCLOCK_0, I2C_DUTYCYCLE_2);
	I2C_Enable(I2C1);
}

void I2C1_Master_IT_Init(void)
{
	/*Config I2C1 GPIO*/
	I2C1_GPIO_Init();
	
	/* Configure NVIC for master i2c1 */
  NVIC_SetPriority(I2C1_IRQn, 0);  
  NVIC_EnableIRQ(I2C1_IRQn);
	
	/* Configure the SCL Clock Speed */
	I2C_Set_Speed(I2C1, PCLK_1_Frequency, I2C_SPEEDCLOCK_2, I2C_DUTYCYCLE_2);
	
	/* Enable master i2c1 events interrupts */
  I2C_Enable_IT(I2C1,I2C_CR2_ITEVTEN);
	
}

void I2C1_Slave_IT_Init(void)
{
	/*Config I2C1 GPIO*/
  I2C1_GPIO_Init();
	/* Configure NVIC for slave i2c1 */
  NVIC_SetPriority(I2C1_IRQn, 0);  
  NVIC_EnableIRQ(I2C1_IRQn);
	
	/* Configure the own address1 */
	I2C_Set_OwnAddress1(I2C1, (I2C_Slave_Addr1), I2C_OWNADDRESS1_7BIT);
	
	/* Enable slave i2c1 events interrupts */
  I2C_Enable_IT(I2C1,I2C_CR2_ITEVTEN);
	
}


void GPIO_Debug(void)
{
  RCC_Enable_AHBClock(RCC_AHBENR_IOPCEN);

	/* Configure IO PC0 output */
	GPIO_Set_PinMode(GPIOC, GPIO_PIN_0, GPIO_MODER_MODER_Output);
	GPIO_Set_PinOutSpeed(GPIOC, GPIO_PIN_0, GPIO_OSPEEDR_High);
	GPIO_Set_PinOutputType(GPIOC, GPIO_PIN_0, GPIO_OTYPER_OUT_Pushpull);
	GPIO_Set_PinPull(GPIOC, GPIO_PIN_0, GPIO_PUPDR_Pullup);

	/* Configure IO PC1 output */
	GPIO_Set_PinMode(GPIOC, GPIO_PIN_1, GPIO_MODER_MODER_Output);
	GPIO_Set_PinOutSpeed(GPIOC, GPIO_PIN_1, GPIO_OSPEEDR_High);
	GPIO_Set_PinOutputType(GPIOC, GPIO_PIN_1, GPIO_OTYPER_OUT_Pushpull);
	GPIO_Set_PinPull(GPIOC, GPIO_PIN_1, GPIO_PUPDR_Pullup);
}
void MCO_Init()
{
  RCC_Enable_AHBClock(RCC_AHBENR_IOPAEN);
	
  /*******************************************************************
	       AFIO (MCO(PA8))
	*******************************************************************/
	/* Configure IO PA8 MCO  */	
	GPIO_Set_PinMode(GPIOA, GPIO_PIN_7, GPIO_MODE_AF_PP);
	GPIO_Set_AF(GPIOA, GPIO_PIN_7,GPIO_AF0);
	GPIO_Set_PinOutSpeed(GPIOA, GPIO_PIN_7, GPIO_OSPEEDR_High);
	GPIO_Set_PinOutputType(GPIOA, GPIO_PIN_7, GPIO_OTYPER_OUT_Pushpull);
	GPIO_Set_PinPull(GPIOA, GPIO_PIN_7, GPIO_PUPDR_Pullup);
	
}

/**
  * @brief  Function called from slave i2c irq handler when TXE flag is set
  *         Function is in charge of transmit a byte on i2c lines.
  * @param  None
  * @retval None
  */
void SlaveReadyToTransmitCallback(void)
{
  /* Send the byte requested by the master */
  I2C_Transmit_Data8(I2C1, TBuffer[TNum++]);
  
  /* Transmiton complete */
  if(TNum == DATA_NUMBER) {
    /* Disable buffer interrupts */
    I2C_Disable_IT(I2C1,I2C_CR2_ITBUFEN);
    /* Disable event interrupts */
		I2C_Disable_IT(I2C1,I2C_CR2_ITEVTEN);
  }
}

/**
  * @brief  Compares two 8-bit buffers and returns the comparison result.
  * @param  Buffer1: pointer to the source buffer to be compared to.
  * @param  Buffer2: pointer to the second source buffer to be compared to the first.
  * @param  BufferLength: buffer's length.
  * @retval 0: Comparison is OK (the two Buffers are identical)
  *         Value different from 0: Comparison is NOK (Buffers are different)
  */
uint8_t BufferCmp8(uint8_t* Buffer1, uint8_t* Buffer2, uint8_t BufferLength)
{
  while (BufferLength--) {
    if (*Buffer1 != *Buffer2) {
      return 1;
    }
    Buffer1++;
    Buffer2++;
  }
  return 0;
}

/**
  * @brief  Function called from master i2c irq handler when RXNE flag is set
  *         Function is in charge of reading byte received on i2c lines.
  * @param  None
  * @retval None
  */
void MasterReceptionCallback(void)
{
  if(RNum < (DATA_NUMBER-3)) {
    /* Read character in receive data register.
    RXNE flag is cleared by reading data in RXDR register */
    RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
  }
  else if((RNum == (DATA_NUMBER-2)) || (RNum == (DATA_NUMBER-3))) {
    /* Disable buffer interrupts */
    I2C_Disable_IT(I2C1,I2C_CR2_ITBUFEN);
  }
  // /* Reception complete */
  else if(RNum == DATA_NUMBER) {
    /* Disable buffer interrupts */
    I2C_Disable_IT(I2C1,I2C_CR2_ITBUFEN);
    /* Generate stop condition */
    I2C_Generate_StopCondition(I2C1);
    /* Read character in receive data register.
    RXNE flag is cleared by reading data in RXDR register */
    RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
    /* Call function master transmit callback */
    MasterCompleteCallback();
  }
}

/**
  * @brief  Function called from I2C IRQ Handler when STOP flag is set
  *         Function is in charge of checking data received,
  *         LED2 is On if data are correct.
  * @param  None
  * @retval None
  */
void MasterCompleteCallback(void)
{
  if(RNum == (DATA_NUMBER-3)) {
    /* Prepare the generation of a non acknowledge condition after next received bytes */
    I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_NACK);
    /* Read character in receive data register.
    RXNE flag is cleared by reading data in RXDR register */
    RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
    /* Disable buffer interrupts */
    I2C_Disable_IT(I2C1,I2C_CR2_ITBUFEN);
  }  
  else if(RNum == (DATA_NUMBER-2)) {
    /* Generate stop condition */
    I2C_Generate_StopCondition(I2C1);
    /* Read character in receive data register.
    RXNE flag is cleared by reading data in RXDR register */
    RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
    /* Read character in shift data register.
    RXNE flag is cleared by reading data in RXDR register */
    RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
  }
  else {
    if(RNum < DATA_NUMBER) {
      /* Read character in shift data register.
      RXNE flag is cleared by reading data in RXDR register */
      RBuffer[RNum++] = I2C_Receive_Data8(I2C1);
    }
  }
  if(RNum == DATA_NUMBER) {
    /* Disable event interrupts */
    I2C_Disable_IT(I2C1,I2C_CR2_ITEVTEN);
    
    /* Check the datas */
    if(BufferCmp8((uint8_t*)RBuffer, (uint8_t*)TBuffer, TNum) == 0) {
      /* Expected bytes have been received */
      GPIO_Toggle_Pin(GPIOC,GPIO_PIN_0);
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_0); 
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_0);
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_0);
    }
    else {
      GPIO_Toggle_Pin(GPIOC,GPIO_PIN_1);
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_1);
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_1);
			GPIO_Toggle_Pin(GPIOC,GPIO_PIN_1);
    }
  }
}

void Button_GPIO_Init(void)
{
  RCC_Enable_AHBClock(RCC_AHBENR_IOPDEN);
  GPIO_InitTypeDef Button_GPIO_InitStruct = {0};

  Button_GPIO_InitStruct.Pin   = GPIO_PIN_0;
  Button_GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;
  Button_GPIO_InitStruct.Pull  = GPIO_PUPDR_Pulldown;
  Button_GPIO_InitStruct.Alternate = GPIO_AF0;
  Button_GPIO_InitStruct.Speed = GPIO_OSPEEDR_Low;
  GPIO_Init(GPIOD, &Button_GPIO_InitStruct);
}

int main(void)
{
  SystemClock_Config();
  
	RCC_Enable_APB1Clock(RCC_APB1ENR_I2C1EN);
  
  GPIO_Debug();
  Button_GPIO_Init();
  
  while (GPIO_Read_PinIDR(GPIOD, GPIO_PIN_0)==0)
  {
  }
  
  /*config I2C IT*/
	I2C1_Master_IT_Init();
	
	/*Enable I2C*/
	I2C_Enable(I2C1);
	
	/******************* Prepare acknowledge *********************************/
  /* Prepare acknowledge for Master data reception */
  I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_ACK);
  
  /* Master generate start condition */
  I2C_Generate_StartCondition(I2C1);
  
  while(1)
  {
    
  }
}
