/*!
 * @file       apm32f10x_spi.c
 *
 * @brief      This file provides all the SPI firmware functions
 *
 * @details    
 *
 * @version        V1.0.0
 *
 * @date       2019-8-6
 *
 */
#include "apm32f10x_spi.h"
#include "apm32f10x_rcm.h"

/*!
 * @brief        Reset the specified SPI peripheral
 *
 * @param        spi: SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_Reset(SPI_T* spi)
{
    if(spi == SPI1)
    {
        RCM_EnableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
        RCM_DisableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
    }
    else if(spi == SPI2)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_SPI2);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_SPI2);
    }
    else if(spi == SPI3)
    {
        RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_SPI3);
        RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_SPI3);
    }
}

/*!
 * @brief        Config the SPI peripheral according to the specified parameters in the configStruct
 *
 * @param        spi: SPI peripheral
 *
 * @param        configStruct: pointer to a SPI_ConfigStruct_T structure
 *
 * @retval        None
 *
 * @note 
 */
void SPI_Config(SPI_T* spi, SPI_ConfigStruct_T* configStruct)
{
    spi->CTRL1_B.CLKPHA = BIT_RESET;
    spi->CTRL1_B.CLKPOL = BIT_RESET;
    spi->CTRL1_B.MSTMODE = BIT_RESET;
    spi->CTRL1_B.BRC = BIT_RESET;
    spi->CTRL1_B.LSBF = BIT_RESET;
    spi->CTRL1_B.ISS = BIT_RESET;
    spi->CTRL1_B.SSC = BIT_RESET;
    spi->CTRL1_B.UMRXO = BIT_RESET;
    spi->CTRL1_B.BMTX = BIT_RESET;
    spi->CTRL1_B.BMEN = BIT_RESET;
    spi->CTRL1 |= (uint16_t)((uint32_t)configStruct->direction | configStruct->mode |
                  configStruct->dataSize | configStruct->cpol |  
                  configStruct->cpha | configStruct->nss |  
                  configStruct->baudRatePrescaler | configStruct->firstBit);
    
    spi->CRCPOLY = configStruct->crcPolynomial;
    
}

/*!
 * @brief        Fills each SPI_ConfigStruct_T member with its default value
 *
 * @param        configStruct: pointer to a SPI_ConfigStruct_T structure which will be initialized
 *
 * @retval        None
 *
 * @note 
 */
void SPI_StructInit(SPI_ConfigStruct_T* configStruct)
{
    configStruct->direction = SPI_DERECTION_2LINES_FULLDUPLEX;
    configStruct->mode = SPI_MODE_SLAVE;
    configStruct->dataSize = SPI_DATASIZE_8B;
    configStruct->cpol = SPI_CPOL_LOW;
    configStruct->cpha = SPI_CPHA_1EDGE;
    configStruct->nss = SPI_NSS_HARD;
    configStruct->baudRatePrescaler = SPI_BAUDRATE_PRESCALER_2;
    configStruct->firstBit = SPI_FIRSTBIT_MSB;
    configStruct->crcPolynomial = 7;
}

/*!
 * @brief        Enables the specified SPI peripheral
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_Enable(SPI_T* spi)
{
    spi->CTRL1_B.SPIEN = BIT_SET;
}

/*!
 * @brief        Disable the specified SPI peripheral
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_Disable(SPI_T* spi)
{
    spi->CTRL1_B.SPIEN = BIT_RESET;
}

void SPI_Int_Enable(SPI_T* spi, uint8_t SPI_Int)
{

}


/*!
 * @brief        Set the SPI NSS internal by Software
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_NSSInternalSoftwareSet(SPI_T* spi)
{
    spi->CTRL1_B.ISS = BIT_SET;
}

/*!
 * @brief        Reset the SPI NSS internal by Software
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_NSSInternalSoftwareReset(SPI_T* spi)
{
    spi->CTRL1_B.ISS = BIT_RESET;
}

/*!
 * @brief        Enables the specified SPI SS output
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_SSOutputEnable(SPI_T* spi)
{
    spi->CTRL2_B.SSOEN = BIT_SET;
}

/*!
 * @brief        Disable the specified SPI SS output
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_SSOutputDisable(SPI_T* spi)
{
    spi->CTRL2_B.SSOEN = BIT_RESET;
}

/*!
 * @brief        Configures the specified SPI data size
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @param        dataSize: Select the SPI data Size
 *
 * @retval        None
 *
 * @note 
 */
void SPI_DataSizeConfig(SPI_T* spi, uint16_t dataSize)
{
    spi->CTRL1 &= (uint16_t)~SPI_DATASIZE_16B;
    spi->CTRL1 |= dataSize;
}

/*!
 * @brief        Enables the specified SPI CRC transmission
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_TransmitCRC_Enable(SPI_T* spi)
{
    spi->CTRL1_B.CRCNXT = BIT_SET;
}

/*!
 * @brief        Enables the specified SPI CRC value calculation of the transferred bytes
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_CalculateCRC_Enable(SPI_T* spi)
{
    spi->CTRL1_B.CRCEN = BIT_SET;
}

/*!
 * @brief        Disable the specified SPI CRC value calculation of the transferred bytes
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        None
 *
 * @note 
 */
void SPI_CalculateCRC_Disable(SPI_T* spi)
{
    spi->CTRL1_B.CRCEN = BIT_RESET;
}

/*!
 * @brief        Reads the specified SPI transmit CRC register value
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        The SPI transmit CRC register value
 *
 * @note 
 */
uint16_t SPI_ReadCRC_TX(SPI_T* spi)
{
    return spi->TXCRC_B.TXCRC;
}

/*!
 * @brief        Reads the specified SPI receive CRC register value
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        The SPI receive CRC register value
 *
 * @note 
 */
uint16_t SPI_ReadCRC_RX(SPI_T* spi)
{
    return spi->RXCRC_B.RXCRC;
}

/*!
 * @brief        Reads the specified SPI CRC Polynomial register value
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @retval        The SPI CRC Polynomial register value
 *
 * @note 
 */
uint16_t SPI_ReadCRCPolynomial(SPI_T* spi)
{
    return spi->CRCPOLY_B.CRCPOLY;
}

/*!
 * @brief        Configures the specified SPI data transfer direction
 *
 * @param        spi: Select the SPI or the SPI peripheral
 *
 * @param        direction: Select the SPI data transfer direction
 *
 * @retval        None
 *
 * @note 
 */
void SPI_BiDirectionalLineConfig(SPI_T* spi, uint16_t direction)
{
    if(direction == SPI_DIRECTION_TX)
    {
        spi->CTRL1 |= SPI_DIRECTION_TX;
    }
    else
    {
        spi->CTRL1 &= SPI_DIRECTION_RX;
    }
}
