/*********************************************************************************************
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.
**********************************************************************************************/

/*
*********************************************************************************************************
*                                              rx32h6xx
*                                           Library Function
*
*                                   Copyright 2024, RX Tech, Corp.
*                                        All Rights Reserved
*
*
* Project      : rx32h6xx
* File         : main.c
* By           : RX_SD_Team
* Version      : V1.0.0
* Description  : Only rx32h6xx
*********************************************************************************************************
*/
#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;

uint8_t eepromMEM[DATA_NUMBER] = {0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0};

__IO uint8_t eepromNum = 9;
/*
*********************************************************************************************************
*                                           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_DIV4);
  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_Init(void)
{
	/*Config I2C1 GPIO*/
	I2C1_GPIO_Init();
	
	/* Configure the SCL Clock Speed */
	I2C_Set_Speed(I2C1, PCLK_1_Frequency, I2C_SPEEDCLOCK_1, I2C_DUTYCYCLE_2);
	
  /* Prepare acknowledge for Master data reception */
  I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_ACK);
  
  /* Enable master i2c1*/
  I2C_Enable(I2C1);
}

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  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;
}

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);
}

/**
  * @brief  Read bytes from EEPROM
  * @param  slave_addr: Slave addresses
  * @param  p_mem_addr: Device memory address
  * @param  memLen: Memory length
  * @param  p_data: Receive data address
  * @param  dataLen: Receive data length
  * @retval None
  */
void EEPROM_ReadBytes(uint8_t slave_addr, uint8_t* p_mem_addr, uint8_t memLen, uint8_t* p_data, uint8_t dataLen)
{
    /* Generating starting condition */
    I2C_Generate_StartCondition(I2C1);
    /* Wait for the starting condition to be generated */
    while (!I2C_Get_Flag(I2C1, I2C_FLAG_SB));
    /* Send addresses */
    I2C_Transmit_Data8(I2C1, slave_addr);
    /* Wait for the address flag */
    while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR));
    /* Clear the address flag */
    I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);

    /* Send register address */
    for (int16_t i=0; i<memLen; i++) 
    {
        I2C_Transmit_Data8(I2C1, p_mem_addr[i]);
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF)); 
    }

    /* Generating starting condition */
    I2C_Generate_StartCondition(I2C1);
    /* Wait for the starting condition to be generated */
    while (!I2C_Get_Flag(I2C1, I2C_FLAG_SB));

    switch(dataLen)
    {
      /*--------------------------------------------------*/
      case 3:
        /* Send addresses and read operations */
        I2C_Transmit_Data8(I2C1, slave_addr | I2C_REQUEST_READ);
        /* Wait for the address flag */
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR)); 
        /* Clear the address flag */
        I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);
        /* Processing data */
        for (int16_t i=0; i<dataLen; i++)
        {
            if (i == dataLen-3) 
            {
                while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF));           
                I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_NACK);
                p_data[i] = I2C_Receive_Data8(I2C1);
            }           
            if (i == dataLen-2) 
            {
                I2C_Generate_StopCondition(I2C1);
                p_data[i] = I2C_Receive_Data8(I2C1);
            }      
            if (i == dataLen-1) 
            {            
                while (!I2C_Get_Flag(I2C1,I2C_FLAG_RXNE));   
                p_data[i] = I2C_Receive_Data8(I2C1);
            }          
        }
        break;
      /*--------------------------------------------------*/
      case 2:
        /* Send addresses and read operations */
        I2C_Transmit_Data8(I2C1, slave_addr | I2C_REQUEST_READ);
        /* Set POS and ACK bits */
        I2C_Enable_POSBit(I2C1);
        I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_ACK);
        /* Wait for the address flag */
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR)); 
        /* Clear the address flag */
        I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);
        I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_NACK); 
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF));
        I2C_Generate_StopCondition(I2C1);         
        /* Processing data */    
        for (int16_t i=0; i<dataLen; i++)
        {    
            if (i == dataLen-2) 
            {
                p_data[i] = I2C_Receive_Data8(I2C1);
            }      
            if (i == dataLen-1) 
            {             
                p_data[i] = I2C_Receive_Data8(I2C1);
            }          
        }
        break;
      /*--------------------------------------------------*/
      case 1:
        /* Send addresses and read operations */
        I2C_Transmit_Data8(I2C1, slave_addr | I2C_REQUEST_READ);
        /* Wait for the address flag */
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR)); 
        /* Clear the ACK */
        I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_NACK);
        /* Clear the address flag */
        I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);
        /* Generating stop condition */
        I2C_Generate_StopCondition(I2C1);
        /* Processing data */   
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_RXNE));
        p_data[0] = I2C_Receive_Data8(I2C1);      
        break;          
      /*--------------------------------------------------*/
      default:
        /* Send addresses and read operations */
        I2C_Transmit_Data8(I2C1, slave_addr | I2C_REQUEST_READ);
        /* Wait for the address flag */    
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR)); 
        /* Clear the address flag */
        I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);    
        /* Processing data */     
        for (int16_t i=0; i<dataLen; i++)
        {
            if (i < dataLen-3) 
            {
                while (!I2C_Get_Flag(I2C1,I2C_FLAG_RXNE));             
                p_data[i] = I2C_Receive_Data8(I2C1); 
            } 
            if (i == dataLen-3) 
            {
                while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF));           
                I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_NACK);
                p_data[i] = I2C_Receive_Data8(I2C1);
            }           
            if (i == dataLen-2) 
            {
                I2C_Generate_StopCondition(I2C1);
                p_data[i] = I2C_Receive_Data8(I2C1);
            }      
            if (i == dataLen-1) 
            {            
                while (!I2C_Get_Flag(I2C1,I2C_FLAG_RXNE));   
                p_data[i] = I2C_Receive_Data8(I2C1);
            }          
        }        
        break;
        /*--------------------------------------------------*/
      
    } /* switch case end */       
    /*-----------------------------------------------------------------*/

    /* Reconfigure the ACK */
    I2C_Set_AcknowledgeNextData(I2C1, I2C_CR1_ACK);
}


/**
  * @brief  Write bytes to EEPROM
  * @param  slave_addr: Slave addresses
  * @param  p_mem_addr: Device memory address
  * @param  memLen: Memory length
  * @param  p_data: Send data address
  * @param  dataLen: Send data length
  * @retval None
  */
void EEPROM_WriteBytes(uint8_t slave_addr, uint8_t* p_mem_addr, uint8_t memLen, uint8_t* p_data, uint8_t dataLen)
{
    /* Generating starting condition */
    I2C_Generate_StartCondition(I2C1);
    /* Wait for the starting condition to be generated */
    while (!I2C_Get_Flag(I2C1, I2C_FLAG_SB));
    /* Send addresses and write operations */
    I2C_Transmit_Data8(I2C1, slave_addr);
    while (!I2C_Get_Flag(I2C1,I2C_FLAG_ADDR));
    /* Clear the address flag */
    I2C_Clear_Flag(I2C1,I2C_FLAG_ADDR);

    /* Send register address */
    for (int16_t i=0; i<memLen; i++) 
    {
        I2C_Transmit_Data8(I2C1, p_mem_addr[i]);
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF));  
    }

    /* Send data */
    for (int16_t i=0; i<dataLen; i++) 
    {
        I2C_Transmit_Data8(I2C1, p_data[i]);
        while (!I2C_Get_Flag(I2C1,I2C_FLAG_BTF));  
    }
    /* Generating stop condition */
    I2C_Generate_StopCondition(I2C1);
}

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 */
	I2C1_Init();
		
  /***********************************************************/
  /* I2C Transmit Data to EEPROM */
  EEPROM_WriteBytes(I2C_Slave_Addr1, eepromMEM, 2, TBuffer, eepromNum);
  Delay_ms(10);
  
  /* I2C Receive Data from EEPROM */
  EEPROM_ReadBytes(I2C_Slave_Addr1, eepromMEM, 2, RBuffer, eepromNum);  
  Delay_ms(10);
    
  /* Check the datas */
  if(BufferCmp8((uint8_t*)RBuffer, (uint8_t*)TBuffer, eepromNum) == 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);
  }  
  
  while(1)
  {

  }
}
