/*
  ******************************************************************************
  * @file    app.c
  * @version V1.0.0
  * @date    2021
  * @brief   DMA demo source code.
  ******************************************************************************
*/
#include "app.h"
#include "bsp_spi.h"

#define BUFFER_LENGTH    (256)

#define CHAR_START    (0xAA)
#define CHAR_END      (0x55)

uint8_t gu8_TxBuffer[BUFFER_LENGTH];
uint8_t gu8_RxBuffer[BUFFER_LENGTH];

extern SPI_DataTypeDef    spi_data;

void SPI_MspInit(SPI_TypeDef *spix)
{
    /* 
      NOTE : This function should be modified by the user.
    */
    
    /* For Example */
    GPIO_InitTypeDef GPIO_Handle; 
    
    /* SPI1 */
    if (spix == SPI1)
    {
    }
    /* SPI2 */
    else if (spix == SPI2) 
    {
        /* Enable Clock */
        System_Module_Enable(EN_SPI2);
        
        /* SPI2 CS   PB12 */
        /* SPI2 SCK  PB13 */
        /* SPI2 MOSI PB15 */
        /* SPI2 MISO PB14 */
        GPIO_Handle.Pin            = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
        GPIO_Handle.Mode           = GPIO_MODE_AF_PP;
        GPIO_Handle.Pull           = GPIO_PULLUP;
        GPIO_Handle.Alternate      = GPIO_FUNCTION_4;
        GPIO_Init(GPIOB, &GPIO_Handle);

        /* SPI2 IO3 PC6 */
        /* SPI2 IO2 PC7 */
        GPIO_Handle.Pin            = GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Handle.Mode           = GPIO_MODE_AF_PP;
        GPIO_Handle.Pull           = GPIO_PULLUP;
        GPIO_Handle.Alternate       = GPIO_FUNCTION_2;
        GPIO_Init(GPIOC, &GPIO_Handle);
        
        /* Clear Pending Interrupt */
        NVIC_ClearPendingIRQ(SPI2_IRQn);
        
        /* Enable External Interrupt */
        NVIC_EnableIRQ(SPI2_IRQn);
    }
}

/************************************************************************
 * function   : SPI_Slave_Comm_Test
 * Description: SPI Slave Communicate Test.
 ************************************************************************/ 
void SPI_Slave_Comm_Test(void)
{
    uint32_t i;
    SPI_StatusTypeDef status = SPI_OK;

//    Spi_Gpio_Init();
    Spi_Init();
    
    printfS("SPI Slave Test is Ready!!! \r\n");
#if 0   
    while (1) 
    {
                                
        SPI_Receive_IT(gu8_RxBuffer, sizeof(gu8_RxBuffer));
        while(SPI_GetRxState() != SPI_RX_STATE_IDLE);

        SPI_Transmit(gu8_RxBuffer, spi_data.Rx_Count, 0);
    
        printf("Rx_Count = %d. Tx_Count = %d.\r\n", spi_data.Rx_Count, spi_data.Tx_Count);
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu8_RxBuffer[i] = 0;
        }
    }
#else
    while (1) 
    {
                                
        status = SPI_Receive(gu8_RxBuffer, sizeof(gu8_RxBuffer), 2000);
        //while(SPI_GetRxState() != SPI_RX_STATE_IDLE);
        if(spi_data.Rx_Count)
        {
            SPI_Transmit(gu8_RxBuffer, spi_data.Rx_Count, 0);
        
            printf("Rx_Count = %d. Tx_Count = %d.\r\n", spi_data.Rx_Count, spi_data.Tx_Count);
            for (i = 0; i < BUFFER_LENGTH; i++)
            {
                gu8_RxBuffer[i] = 0;
            }
        }
    }
#endif
}

/************************************************************************
 * function   : SPI_Slave_Comm_IT
 * Description: SPI Slave Communicate Interrupt Test.
 ************************************************************************/ 
void SPI_Slave_Comm_IT(void)
{
    uint32_t i;

//    Spi_Gpio_Init();
    Spi_Init();

    printfS("SPI Slave Test is Ready!!! \r\n");

    while (1) 
    {
        SPI_Receive_IT(gu8_RxBuffer, sizeof(gu8_RxBuffer));
        while(SPI_GetRxState() != SPI_RX_STATE_IDLE);

        SPI_Transmit_IT(gu8_RxBuffer, spi_data.Rx_Count);
        while(SPI_GetTxState() != SPI_TX_STATE_IDLE);
        
        printf("Rx_Count = %d. Tx_Count = %d.\r\n", spi_data.Rx_Count, spi_data.Tx_Count);
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu8_RxBuffer[i] = 0;
        }
    }
}

/************************************************************************
 * function   : SPI_Slave_DMA_Test
 * Description: SPI Slave DMA Test.
 ************************************************************************/ 
void SPI_Slave_DMA_Test(void)
{
    uint32_t i;
    
    uint32_t lu32_DataLength = 50;

    printfS("SPI Slave DMA Test is Ready!!! \r\n");
    
//    Spi_Gpio_Init();
    Spi_Init();
    
    /* Enable DMA Clock */
    System_Module_Enable(EN_DMA);

    while (1) 
    {
        SPI_Receive_DMA(gu8_RxBuffer, lu32_DataLength);
        while(SPI_GetRxState() != SPI_RX_STATE_IDLE);

        SPI_Transmit_DMA(gu8_RxBuffer, lu32_DataLength);
        while(SPI_GetTxState() != SPI_TX_STATE_IDLE);
        
        for (i = 0; i < BUFFER_LENGTH;  i++)
        {
            gu8_RxBuffer[i] = 0;
        }
    }
}

/************************************************************************
 * function   : SPI_Slave_FullDuplex_Test
 * Description: SPI Slave Full Duplex Test. 
 ************************************************************************/ 
void SPI_Slave_FullDuplex_Test(void)
{
    uint32_t i;
    
    uint32_t lu32_COM_OK  = 0;
    uint32_t lu32_COM_Err = 0;
    uint32_t lu32_DataLength = 50;

//    Spi_Gpio_Init();
    Spi_Init();
    
    printfS("SPI Slave Full Duplex Test is Ready!!! \r\n");
    
    while (1) 
    {
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu8_TxBuffer[i] = i+1;
            gu8_RxBuffer[i] = 0;
        }
                                
        SPI_TransmitReceive(gu8_TxBuffer, gu8_RxBuffer, lu32_DataLength, 0);
        
        for (i = 0; i < lu32_DataLength; i++)
        {
            if (gu8_TxBuffer[i] != (gu8_RxBuffer[i]+1)) 
            {
                printfS("There is one mistake : gu8_TxBuffer[%d]: 0x%02x != gu8_RxBuffer[%d]: 0x%02x \r\n", i,gu8_TxBuffer[i], i, gu8_RxBuffer[i]);
                
                lu32_COM_Err++;
            }
            else 
            {
                lu32_COM_OK++;
            }
        }
        
        printfS("SPI Slave Full Duplex Test OK count %d times \r\n",  lu32_COM_OK);
        printfS("SPI Slave Full Duplex Test Err count %d times \r\n", lu32_COM_Err);
        lu32_COM_Err = 0;
        lu32_COM_OK = 0;
    }
}

/************************************************************************
 * function   : SPI_Slave_Test
 * Description: SPI Slave Test.
 ************************************************************************/ 
void SPI_Slave_Test(enum_TEST_MODE_t fe_Mode)
{
    printfS("---------- SPI Slave Test ----------\r\n");
        
    switch (fe_Mode)
    {
        case TEST_SLAVE_COMM: 
            SPI_Slave_Comm_Test();
            break; 
        
        case TEST_SLAVE_IT: 
            SPI_Slave_Comm_IT();
            break; 
        
        case TEST_SLAVE_DMA: 
            SPI_Slave_DMA_Test();
            break;
       
        case TEST_SLAVE_FULL_DUPLEX: 
            SPI_Slave_FullDuplex_Test();
            break;
       
        default: break;     
    }
}
