/*
  ******************************************************************************
  * @file    APP.c
  * @author  PJ
  * @version V1.0.0
  * @date    2021
  * @brief   I2C Slave demo source code.
  ******************************************************************************
*/
#include "app.h"

uint8_t TxBuffer[BUFFER_LENGTH];
uint8_t RxBuffer[BUFFER_LENGTH];

I2C_Handler_t hi2c;

volatile bool TX_DMA_Status = false;
static volatile uint8_t gu8_RX_Complete;

void I2C1_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_Handle;
	
	 /* Enable GPIO Clock */
    __RCC_GPIOB_CLK_ENABLE();
    
	GPIO_Handle.Pin            = GPIO_PIN_6 | GPIO_PIN_7;
	GPIO_Handle.Mode           = GPIO_MODE_AF_PP;
	GPIO_Handle.Pull           = GPIO_PULLUP;
    GPIO_Handle.Drive          = GPIO_DRIVE_LEVEL3;
	GPIO_Handle.Alternate      = GPIO_FUNCTION_5;
	GPIO_Init(GPIOB, &GPIO_Handle);
    
    printfS("I2C1 PINs selected:\r\n");
    printfS("SCL:PB6\r\n");
    printfS("SDA:PB7\r\n\r\n");
    
}

void I2C1_Init(void)
{
    I2C_InitTypeDef I2C_InitStruct;
    
    __RCC_I2C1_CLK_ENABLE();
    
    I2C_InitStruct.Clock_Speed = CLOCK_SPEED_STANDARD;
                  
    I2C_InitStruct.I2C_Mode = I2C_MODE_SLAVE;
                  
    I2C_InitStruct.Stretch_Mode = STRETCH_MODE_DISABLE;
                  
    I2C_InitStruct.Own_Address = 0;
                  
    I2C_InitStruct.Tx_Auto_En = TX_AUTO_ENABLE;
                  
    I2C_InitStruct.filter_enable = FILTER_ALGO_DISABLE;
       
    I2C_InitStruct.Own_Address = SLAVE_ADDRESS;

    I2C_Init(I2C1, &I2C_InitStruct);
    
    NVIC_ClearPendingIRQ(I2C1_IRQn);
    NVIC_EnableIRQ(I2C1_IRQn);

    /* I2C module enable */
    I2C_Cmd(I2C1, ENABLE);
}

void I2C_Slave_Polling_Test(void)
{
    uint32_t i;
    uint32_t lu32_RxLength = 0;
    uint32_t lu32_TxLength = 0;
    
    I2C1_Init();
    I2C1_GPIO_Init();
    
    while (1) 
    {
        printfS("I2C Slave Test is Ready (Polling Mode)--> \r\n");

        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = 0;
            RxBuffer[i] = 0;
        }
        
        while(I2C_OK != I2C_Slave_Receive(I2C1, RxBuffer, BUFFER_LENGTH, 1000));

        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = RxBuffer[i];
        }
		
        I2C_Slave_Transmit(I2C1, TxBuffer, BUFFER_LENGTH, 1000);
        
       
        printfS("I2C Slave Test End (Polling Mode)!!! \r\n");
		printfS("---------------------------------------------- \r\n");
    }
}

void I2C_Slave_Interrupt_Test(void)
{
    uint32_t i;
    
    I2C1_Init();
    I2C1_GPIO_Init();

    while (1) 
    {
        printfS("I2C Slave Test is Ready(Interrupt Mode)!!! \r\n");

        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = 0;
            RxBuffer[i] = 0;
        }

        I2C_Slave_Receive_IT(I2C1, &hi2c, RxBuffer, BUFFER_LENGTH);
        while (hi2c.state != I2C_STATE_IDLE);
	
        
        for (i = 0; i < hi2c.Rx_Count; i++)
        {
            TxBuffer[i] = RxBuffer[i];
        }


        I2C_Slave_Transmit_IT(I2C1, &hi2c, RxBuffer, hi2c.Rx_Count);
        while(hi2c.state != I2C_STATE_IDLE);
		

        printfS("Rx Count: %d, Tx Count: %d \r\n", hi2c.Rx_Count, hi2c.Tx_Count);

        printfS("I2C Slave Test End (Interrupt Mode)!!! \r\n");
		printfS("---------------------------------------------- \r\n");
    }
}


void I2C_STOPF_Callback(void)
{
    uint32_t timeout = DMA_TIMEOUT;
    uint32_t ChannelIndex;
    
    gu8_RX_Complete = 1;
    
    hi2c.Rx_Count = hi2c.Rx_Size - (hi2c.DMA_Rx_ch->CHCTRL & 0xFFF);
    
    ChannelIndex = ((uint32_t)(DMA1_Channel0) - (uint32_t)(DMA1_Channel0)) >> 5;

    /* DMA Channel Abort */
    DMA_AbortCmd(DMA1_Channel0, ENABLE);
    
    /* Wait until data clearing in FIFO  */    
    while (DMA1_Channel0->CHCONFIG & DMA_CHCONFIG_ACTIVE)
    {
        if (--timeout == 0u)
            break;
    }
    
    DMA_AbortCmd(DMA1_Channel0, DISABLE);
    
    /* DMA Channel Disable */
    DMA_Cmd(DMA1_Channel0, DISABLE);
    
    /* Disable interrupt */
    DMA_ITConfig(DMA1_Channel0, DMA_CHCONFIG_IHFTC | DMA_CHCONFIG_ITC | DMA_CHCONFIG_IHFTC, DISABLE);
    
    /* Clear TC ERR Falg */
    DMA1->INTTCCLR  |= (1U << ChannelIndex) | (1U << (ChannelIndex + 8U));
    DMA1->INTERRCLR |= (1U << ChannelIndex);

    /* Wait until the channel is closed  */
    timeout = DMA_TIMEOUT;
    while (DMA1->ENCHSTATUS & ChannelIndex)
    {
        if (--timeout == 0u)
            break;;
    }    

}

/************************************************************************
 * function   : I2C_Slave_DMA_Test
 * Description: I2C Slave DMA Test
 ************************************************************************/ 
void I2C_Slave_DMA_Test(void)
{
    uint32_t i;
	uint8_t Status;
    DMA_InitTypeDef InitData;
    
    I2C1_Init();
    I2C1_GPIO_Init();

    hi2c.DMA_Rx_ch = DMA1_Channel0;

    __RCC_DMA1_CLK_ENABLE();    

    DMA_StructInit(&InitData);
        
    InitData.DataFlow = DMA_DATAFLOW_P2M;
    InitData.ReqID = DMA1_REQ10_I2C1_RECV;
    InitData.SrcInc      = DMA_SRCINC_DISABLE;
    InitData.DestInc     = DMA_DESTINC_ENABLE;
    DMA_Init(DMA1_Channel0, &InitData);    
    
    InitData.DataFlow = DMA_DATAFLOW_M2P;
    InitData.ReqID = DMA1_REQ9_I2C1_SEND;
    InitData.SrcInc      = DMA_SRCINC_ENABLE;
    InitData.DestInc     = DMA_DESTINC_DISABLE;    
    DMA_Init(DMA1_Channel1, &InitData);

    NVIC_ClearPendingIRQ(DMA1_IRQn);
    NVIC_SetPriority(DMA1_IRQn, 5);
    NVIC_EnableIRQ(DMA1_IRQn);
	
    hi2c.DMA_Tx_ch = DMA1_Channel1;
    
	hi2c.I2C_STOPF_Callback = (void *)I2C_STOPF_Callback;

    while (1) 
    {
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = 0;
            RxBuffer[i] = 0;
        }
        
        printfS("I2C Slave Test is Ready (DMA Mode)!!! \r\n");

        hi2c.Rx_Size = BUFFER_LENGTH ;
       
        /* DMA Enable */
        SET_BIT(I2C1->CR, I2C_CR_DMA_EN);

        /* Clear STOPF Interrupt Flag */
        I2C1->SR = READ_BIT(I2C1->SR, I2C_SR_STOPF);
        /* STOPF Interrupt Enable */
        SET_BIT(I2C1->CR, I2C_CR_STOPF_INTEN);

        /* Set source address and desination address */
        DMA_SrcAddrConfig(DMA1_Channel0, (uint32_t)&I2C1->DR);
        
        DMA_DestAddrConfig(DMA1_Channel0, (uint32_t)RxBuffer);        

        /* Set Transfer Size and enable LLI interrupt */
        DMA_SetTransferSize(DMA1_Channel0, BUFFER_LENGTH);

        /* DMA Channel Enable */
        DMA_Cmd(DMA1_Channel0, ENABLE);
		
        while (gu8_RX_Complete != 1);

        gu8_RX_Complete = 0;
        
        memcpy(TxBuffer, RxBuffer, hi2c.Rx_Count);

        I2C_ClearFlag(I2C1, I2C_SR_MTF);
        
        /* Must Set TXE_SEL In DMA Mode !!! */
        SET_BIT(I2C1->CR, I2C_CR_TXE_SEL);
        /* DMA Enable */
        SET_BIT(I2C1->CR, I2C_CR_DMA_EN);
                
        /* Set source address and desination address */
        DMA_SrcAddrConfig(DMA1_Channel1, (uint32_t)TxBuffer);
        
        DMA_DestAddrConfig(DMA1_Channel1, (uint32_t)&I2C1->DR);        
 
        /* Set Transfer Size and enable LLI interrupt */
        DMA_SetTransferSize(DMA1_Channel1, hi2c.Rx_Count);
       
        /* Enable interrupt */
        DMA_ITConfig(DMA1_Channel1, DMA_CHCONFIG_IHFTC, DISABLE);
        
        DMA_ITConfig(DMA1_Channel1, DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE , ENABLE);
            
        /* DMA Channel Enable */
        DMA_Cmd(DMA1_Channel1, ENABLE);
		
        while(!TX_DMA_Status);
        TX_DMA_Status = false;
        
        printfS("Rx Count: %d\r\n", hi2c.Rx_Count);        
    }
}

/************************************************************************
 * function   : I2C_Slave_Test
 * Description: I2C Slave Test. 
 ************************************************************************/ 
void I2C_Slave_Test(enum_TEST_MODE_t fe_Mode)
{

    printfS("---------- I2C Slave Test ----------\r\n");
    
    switch (fe_Mode)
    {
        /* Polling Mode */
        case TEST_SLAVE_POLLING: 
            I2C_Slave_Polling_Test();
            break;
        
        /* Interrupt Mode */
        case TEST_SLAVE_INTERRUPT: 
            I2C_Slave_Interrupt_Test();
            break;
        
        /* DMA Mode */
        case TEST_SLAVE_DMA: 
            I2C_Slave_DMA_Test();
            break;
        
        default: 
            break; 
    }

}

