#include "drv_clk.h"
#include "drv_spi.h"
#include "drv_dma.h"
#include "drv_gpio.h"


#include "kit_debug.h"


#define SPI_SYNC_TIMEOUT                (2550u)
#define CR1_SPI_EN                      ((uint16_t)0x0040)
#define SPI_NSS_Soft                    ((uint16_t)0x0200)
#define SPI_Mode_Master                 ((uint16_t)0x0104)
#define SPI_Direction_1Line_Tx          ((uint16_t)0xC000)
#define SPI_I2S_DMAReq_Tx               ((uint16_t)0x0002)
#define SPI_I2S_DMAReq_Rx               ((uint16_t)0x0001)
#define SPI_I2S_FLAG_TXE                ((uint16_t)0x0002)
#define SPI_I2S_FLAG_BSY                ((uint16_t)0x0080)
#define SPI_I2S_FLAG_RXNE               ((uint16_t)0x0001)

#define GPIO_REMAP_SPI1             ((uint32_t)0x00000001)
#define GPIO_REMAP_SPI3             ((uint32_t)0x10000000)

typedef struct
{
    DmaStream  rx_dma_stream;
    DmaStream  tx_dma_stream;
    DmaChannel dma_channel;
    
    SPI_TypeDef   *reg;
}Stm32SpiProp;

static kit_ret_e drv_spi_set_clock_gpio(SpiDev dev, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx);
    
static const Stm32SpiProp stm32_spi[kSpiDev_End] = 
{
    {kDma2Stream_2, kDma2Stream_3, kDmaChannel_3,   SPI1},
    {kDma1Stream_3, kDma1Stream_4, kDmaChannel_0,   SPI2},  
    {kDma2Stream_0, kDma2Stream_5, kDmaChannel_0,   SPI3}
};

/********************************************************************************
  Func   SPI1_REMAP = 0 	SPI1_REMAP = 1	SPI3_REMAP = 0 	SPI3_REMAP = 1
SPI_SCK 	PA5 	            PB3	            PB3 	        PC10
SPI_MISO 	PA6 	            PB4	            PB4 	        PC11
SPI_MOSI 	PA7 	            PB5	            PB5 	        PC12

APB1频率 = 168M/4 = 42M
APB2频率 = 168M/2 = 84M
********************************************************************************/
static kit_ret_e drv_spi_set_clock_gpio(SpiDev dev, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
    kit_ret_e res = kKit_Ret_Ok;
    
    uint32_t sck_io = drv_gpio_get_actual_io(sck_idx);
    uint32_t miso_io = drv_gpio_get_actual_io(miso_idx);
    uint32_t mosi_io = drv_gpio_get_actual_io(mosi_idx);   
    switch (dev)
    {
        case kSpiDev_1:
            RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
            res |= drv_clk_set_status(kBspClk_APB2, RCC_APB2Periph_SPI1);
            if((sck_io == GPIO_PORT_PIN(kGpioPort_A, 5)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_A, 7))) 
            { 
                drv_gpio_set_af(kGpioPort_A, 5, 5);
				drv_gpio_set_af(kGpioPort_A, 7, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_A, 6))
                {
                    drv_gpio_set_af(kGpioPort_A, 6, 5);
                }
            }
            else if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5))) 
            {
                drv_gpio_set_af(kGpioPort_B, 3, 5);
				drv_gpio_set_af(kGpioPort_B, 5, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 4))
                {
                    drv_gpio_set_af(kGpioPort_B, 4, 5);
                }
            }
            else if((sck_io == GPIO_PORT_PIN(kGpioPort_A, 5)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5)))
            {
                drv_gpio_set_af(kGpioPort_A, 5, 5);
				drv_gpio_set_af(kGpioPort_B, 5, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_A, 6))
                {
                    drv_gpio_set_af(kGpioPort_A, 6, 5);
                }
            }
            else
            {
                res |= kKit_Ret_ParamErr;
            } 
            break;
        
        case kSpiDev_2:
            RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
            if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 13)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 15)))
            {
                drv_gpio_set_af(kGpioPort_B, 13, 5);
				drv_gpio_set_af(kGpioPort_B, 15, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 14))
                {
                    drv_gpio_set_af(kGpioPort_B, 14, 5);
                }
            }
            else if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 10)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 15)))
            {
                drv_gpio_set_af(kGpioPort_B, 10, 5);
				drv_gpio_set_af(kGpioPort_B, 15, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 14))
                {
                    drv_gpio_set_af(kGpioPort_B, 14, 5);
                }
            }
            #if defined(STM32F429_439xx)
            else if((sck_io == GPIO_PORT_PIN(kGpioPort_D, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_C, 3)))
            {
                drv_gpio_set_af(kGpioPort_D, 3, 5);
				drv_gpio_set_af(kGpioPort_C, 3, 5);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_C, 2))
                {
                    drv_gpio_set_af(kGpioPort_C, 2, 5);
                }
            }
            #endif
            else
            {
                res |= kKit_Ret_ParamErr;
            } 
            break;     
        case kSpiDev_3:
            RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
            if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5))) 
            { 
                drv_gpio_set_af(kGpioPort_B, 3, 6);
				drv_gpio_set_af(kGpioPort_B, 5, 6);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 4))
                {
                    drv_gpio_set_af(kGpioPort_B, 4, 6);
                }
            }
            else if((sck_io == GPIO_PORT_PIN(kGpioPort_C, 10)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_C, 12))) 
            {
                drv_gpio_set_af(kGpioPort_C, 10, 6);
				drv_gpio_set_af(kGpioPort_C, 12, 6);
                if(miso_io == GPIO_PORT_PIN(kGpioPort_C, 11))
                {
                    drv_gpio_set_af(kGpioPort_C, 11, 6);
                }
            }             
            else
            {
                res =  kKit_Ret_ParamErr;
            }             
            break;             
        default:
            res =  kKit_Ret_ParamErr;
            break;
    }
    
    return res;
}

/*******************重要寄存器默认值*******************
 *SPI_CR1-BIDIMODE(15)        默认“双线双向”模式
 *SPI_CR1-DFF(11)             默认8位数据帧格式
 *SPI_CR1-SSM(9)              默认硬件控制CS
 *SPI_CR1-LSBFIRST(7)         默认先发送MSB
 *spi1 时钟源位APB2 速度= CLOCK_APB2_FREQ/Divx
 *TXE置位表示数据数据从发送缓冲器传输到移位寄存器,并不一定发送完成
 *RXNE置位表示移位寄存器中接收到的数据字被传送到接收缓冲器
********************************************************/
#define SPI_CR1_FRF     KIT_BIT_MASK_32(4)
kit_ret_e drv_spi_init(SpiDev dev, SpiFreq freq, SpiMode mode, SpiFrame spi_frame, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
    uint16_t  cr1;
    kit_ret_e res;
    
    KIT_ASSERT_PARAM((dev < kSpiDev_End) && (freq < kSpiFreq_End) && (mode < kSpiMode_End) && (spi_frame < SpiFrame_End));

    res = drv_spi_set_clock_gpio(dev, sck_idx, miso_idx, mosi_idx);
    if(res == kKit_Ret_Ok)
    {
        cr1 = stm32_spi[dev].reg->CR1; 
        cr1 |= freq << 3;        
        cr1 |= (mode | (spi_frame << 7));
        //主机模式 cs软件控制 8位数据
        cr1 |= (SPI_NSS_Soft | SPI_Mode_Master | CR1_SPI_EN);
        if(miso_idx == NULL)
            cr1 |= SPI_Direction_1Line_Tx;
        
        stm32_spi[dev].reg->CR1 = cr1;
    }
    
    KIT_ASSERT_RES(dev, res);
    return res;
}

kit_ret_e drv_spi_init1(SpiDev dev, SpiFreq freq, uint32_t spi_config, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
    uint16_t  cr1;
    kit_ret_e res;
    
    KIT_ASSERT_PARAM((dev < kSpiDev_End) && (freq < kSpiFreq_End));

    res = drv_spi_set_clock_gpio(dev, sck_idx, miso_idx, mosi_idx);
    if(res == kKit_Ret_Ok)
    {
        cr1 = freq << 3;        
        cr1 |= (uint16_t)spi_config;
        
        stm32_spi[dev].reg->CR1 |= cr1;
        stm32_spi[dev].reg->CR2 |= (spi_config >> 16);
    }
    
    KIT_ASSERT_RES(dev, res);
    return res;
}

kit_ret_e drv_spi_set_dma(SpiDev dev, bool is_rx_en, bool is_tx_en)
{
    uint16_t    cr2;
    kit_ret_e   res;
    SPI_TypeDef *reg;
    
    KIT_ASSERT_PARAM(dev < kSpiDev_End);
    
    if(dev < kSpiDev_End)
    {
        reg = stm32_spi[dev].reg;
        cr2 = reg->CR2;
        if(is_rx_en == true)
        {
            drv_dma_init(stm32_spi[dev].rx_dma_stream, stm32_spi[dev].dma_channel, DMA_CFG_DATA_DIR_P2M|DMA_CFG_CYCLE_NONE|DMA_CFG_DATA_M_I|DMA_CFG_DATA_P_N|DMA_CFG_DATA_LEN_1B, (uint32_t)&reg->DR);
            cr2 |= SPI_I2S_DMAReq_Rx;
        } 
        else
            cr2 &= ~SPI_I2S_DMAReq_Rx;
        
        if(is_tx_en == true)
        {
            drv_dma_init(stm32_spi[dev].tx_dma_stream, stm32_spi[dev].dma_channel, DMA_CFG_DATA_DIR_M2P|DMA_CFG_CYCLE_NONE|DMA_CFG_DATA_M_I|DMA_CFG_DATA_P_N|DMA_CFG_DATA_LEN_1B, (uint32_t)&reg->DR);
            cr2 |= SPI_I2S_DMAReq_Tx;
        }
        else
            cr2 &= ~SPI_I2S_DMAReq_Tx;
        
        reg->CR2 = cr2;
        res = kKit_Ret_Ok;
    }
    else
    {
        res = kKit_Ret_OutRange;
    }
    
    return res;    
}
/********************************************************************
向DR写数据后SPI并不会立即启动发送此时BSY仍然为0，TXE为0，延迟2个APB时
钟周期后发送启动TXE变为1，BSY变为1，等到数据发送完成BSY再变为0
**********************************************************************/

//发送一个字节
kit_ret_e drv_spi_sync_send_receive(SpiDev dev, uint8_t *data) 
{
    kit_ret_e    res = kKit_Ret_Ok;
    SPI_TypeDef  *reg;
    uint32_t timeout = SPI_SYNC_TIMEOUT;
    
    KIT_ASSERT_PARAM((dev < kSpiDev_End) && (data != NULL));

    reg = stm32_spi[dev].reg;
    //send data
    while((reg->SR & SPI_I2S_FLAG_TXE) == 0)
    {
        if(timeout-- < 1)
        {           
            return kKit_Ret_TimeOut;
        }
    }     
    reg->DR = *data;
    
    timeout = SPI_SYNC_TIMEOUT;
    //recved data
    while((reg->SR & (SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY)) != SPI_I2S_FLAG_RXNE)
    {
        if(timeout-- < 1)
        {           
            res = kKit_Ret_TimeOut;
            break;
        }
    }
    *data = reg->DR;
    
    return res;
}

//发送一个字节
uint8_t drv_spi_sync_send_rev(SpiDev dev, uint8_t data) 
{
    SPI_TypeDef  *reg;
    uint32_t timeout = SPI_SYNC_TIMEOUT;
    
    KIT_ASSERT_PARAM((dev < kSpiDev_End) );

    reg = stm32_spi[dev].reg;
    //send data
    while((reg->SR & SPI_I2S_FLAG_TXE) == 0)
    {
        if(timeout-- < 1)
        {           
            return kKit_Ret_TimeOut;
        }
    }     
    reg->DR = data;
    
    timeout = SPI_SYNC_TIMEOUT;
    //recved data
    while((reg->SR & (SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY)) != SPI_I2S_FLAG_RXNE)
    {
        if(timeout-- < 1)
        {           
            break;
        }
    }
    return reg->DR;
}


//读写多个字节
kit_ret_e drv_spi_series_sync_send_receive(SpiDev dev, uint8_t *tx_buf, uint16_t tx_len, uint8_t *rx_buf, uint16_t rx_len)
{
    uint32_t  i;
    kit_ret_e res = kKit_Ret_Ok;
    
    KIT_ASSERT_PARAM(dev < kSpiDev_End);
    KIT_ASSERT_PARAM(((tx_buf == NULL) && (tx_len == 0)) || ((tx_buf != NULL) && (tx_len > 0)));
    KIT_ASSERT_PARAM(((rx_buf == NULL) && (rx_len == 0)) || ((rx_buf != NULL) && (rx_len > 0)));

    //send
    for(i = 0; i < tx_len; i++)
        res |= drv_spi_sync_send_receive(dev, tx_buf + i);	
    
	
    //receive
    for(i = 0; i < rx_len; i++)
        res |= drv_spi_sync_send_receive(dev, rx_buf + i);
    
    return res;
}



kit_ret_e drv_spi_dma_sync_send(SpiDev dev, uint8_t *tx_buf,  uint16_t tx_len)
{    
    kit_ret_e res;
    
    KIT_ASSERT_PARAM(dev < kSpiDev_End);
    KIT_ASSERT_PARAM(((tx_buf == NULL) && (tx_len == 0)) || ((tx_buf != NULL) && (tx_len > 0)));
    
    //接收前读一次SPI2->DR，保证接收缓冲区为空
    stm32_spi[dev].reg->DR;
    res = kit_wait_flag((volatile uint32_t *)&stm32_spi[dev].reg->SR, SPI_I2S_FLAG_TXE, SPI_SYNC_TIMEOUT);
    if(res == kKit_Ret_Ok)
    {
        res = drv_dma_send(stm32_spi[dev].tx_dma_stream, tx_buf, tx_len);
    }

    return res;
}

kit_ret_e drv_spi_dma_sync_receive(SpiDev dev, uint8_t *rx_buf,  uint16_t rx_len)
{    
    kit_ret_e res;
    
    KIT_ASSERT_PARAM(dev < kSpiDev_End);
    KIT_ASSERT_PARAM(((rx_buf == NULL) && (rx_len == 0)) || ((rx_buf != NULL) && (rx_len > 0)));
    
    //接收前读一次SPI2->DR，保证接收缓冲区为空
    stm32_spi[dev].reg->DR;
    res = kit_wait_flag((volatile uint32_t *)&stm32_spi[dev].reg->SR, SPI_I2S_FLAG_TXE, SPI_SYNC_TIMEOUT);
    if(res == kKit_Ret_Ok)
    {
        res = drv_dma_receive(stm32_spi[dev].rx_dma_stream, stm32_spi[dev].tx_dma_stream, rx_buf, rx_len);
    }

    return res;
}

