#include "sr_spi.h"

#ifdef SR_USE_SPI

#include "sr_gpio.h"

#ifdef SR_USE_SPI1
SPI_HandleTypeDef spi1Handle;

#endif

#ifdef SR_USE_SPI2
SPI_HandleTypeDef spi2Handle;

#endif

static BSP_SPI_INFO_T _SpiInfo[] =
{

#ifdef SR_USE_SPI1
		{		
			.trdHandle = &spi1Handle,
			.instance = SPI1,
			.srId = SR_SPI1,
		},
#endif

#ifdef SR_USE_SPI2
		{
			.trdHandle = &spi2Handle,
			.instance = SPI2,
			.srId = SR_SPI2,
		},
#endif

};

static SR_SPI_DEV_T gs_spiDevice[sizeof(_SpiInfo) / sizeof(_SpiInfo[0])] = {0};


//函数声明
static uint32_t  _GetSpiClkPrescaler(SPI_TypeDef  *instance,uint32_t speed);


SR_DEVICE_T *BspSpiOpen(SR_SPI_ID_E spiId)
{
    uint8_t i;
	uint8_t devNum = sizeof(_SpiInfo) / sizeof(BSP_SPI_INFO_T);
	SR_SPI_DEV_T *spiDev = SR_NULL;

	for (i = 0; i < devNum; i++)
	{
		if (spiId == _SpiInfo[i].srId)
		{
			spiDev = &gs_spiDevice[i];
			spiDev->parent.deviceData = &_SpiInfo[i]; // 绑定设备信息数据
			break;
		}
	}

	return (spiDev) ? (&(spiDev->parent)) : SR_NULL;

}

int BspSpiClose(SR_DEVICE_T *dev)
{
    BSP_SPI_INFO_T *info = (BSP_SPI_INFO_T *)dev->deviceData;
	SR_SPI_DEV_T *spiDev = (SR_SPI_DEV_T *)dev;

    // 检查有效性检查
    if(!dev || !info || !info->trdHandle) return SR_INVALID;

    //CS 引脚去初始化
    SR_HalGpioDeinit(spiDev->csId); 

    // 调用原厂接口
    HAL_StatusTypeDef halRet;
	SPI_HandleTypeDef *handle = (SPI_HandleTypeDef *)info->trdHandle;

    halRet =  HAL_SPI_DeInit(handle);

    return (halRet == HAL_OK) ? SR_OK : SR_FAIL;

}
int BspSpiConfig(SR_DEVICE_T *dev, SR_SPI_CFG_T *cfg)
{
    BSP_SPI_INFO_T *info = (BSP_SPI_INFO_T *)dev->deviceData;
	SR_SPI_DEV_T *spiDev = (SR_SPI_DEV_T *)dev;
	int ret = -1;
	
	// 检查有效性检查
    if(!dev || !cfg || !info || !info->trdHandle) return SR_INVALID;

    //保存cs id和极性
    spiDev->csId = cfg->csId;
    spiDev->csPol = cfg->csPol;

   
    //CS 引脚初始化
    SR_GPIO_CFG_T gpioCfg = {0};
	
	gpioCfg.gpioMode = SR_GPIO_OUTPUT;		   // 输出
	gpioCfg.pull = SR_GPIO_NP;				   // 无上下拉
	gpioCfg.initLvl = (cfg->csPol)? SR_GPIO_LOW:SR_GPIO_HIGH; // 初始低电平
	ret = SR_HalGpioInit(cfg->csId, &gpioCfg);  // 初始化
    if(ret != SR_OK)  return SR_FAIL;

    // 调用原厂接口
    HAL_StatusTypeDef halRet;
	SPI_HandleTypeDef *handle = (SPI_HandleTypeDef *)info->trdHandle;

    handle->Instance = info->instance;
    handle->Init.Mode = cfg->mode;
    handle->Init.Direction = SPI_DIRECTION_2LINES;  //默认全双工
    handle->Init.DataSize = cfg->dw;
    handle->Init.CLKPolarity = cfg->cpol;
    handle->Init.CLKPhase = cfg->cpha;
    handle->Init.NSS = SPI_NSS_SOFT;  //默认软件片选
    handle->Init.BaudRatePrescaler = _GetSpiClkPrescaler(info->instance,cfg->speed);
    handle->Init.FirstBit = cfg->order;
    handle->Init.TIMode = SPI_TIMODE_DISABLE;
    handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    handle->Init.CRCPolynomial = 10;

    halRet = HAL_SPI_Init(handle);
    
    if(halRet != HAL_OK)
    {
        SR_HalGpioDeinit(cfg->csId);   //CS 引脚去初始化
        return SR_FAIL;
    }
    
    return SR_OK;
}

int BspSpiReadReg(SR_DEVICE_T *dev, uint32_t reg,uint16_t regLen, uint8_t *buff, uint16_t buffLen)
{
    BSP_SPI_INFO_T *info = (BSP_SPI_INFO_T *)dev->deviceData;
	SR_SPI_DEV_T *spiDev = (SR_SPI_DEV_T *)dev;
    uint8_t i,regAddr[4] = {0};


    // 检查有效性检查
    if(!dev || !info || !info->trdHandle || (regLen<=0 || regLen>4)) return SR_INVALID;

    // 复制寄存器地址
    for (i = 0; i < regLen; i++)
        regAddr[i] = (reg >> (8 * (regLen - 1 - i)) & 0xFF);

    // CS 使能处理
    SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_HIGH:SR_GPIO_LOW);

    // 调用原厂接口
    HAL_StatusTypeDef halRet;
	SPI_HandleTypeDef *handle = (SPI_HandleTypeDef *)info->trdHandle;

        //WARN：目前只考虑了8bit数据宽度，待优化
    halRet =  HAL_SPI_Transmit(handle, regAddr, regLen, 1000); // 发送寄存器地址
    if(halRet == HAL_OK) 
    {
        halRet = HAL_SPI_Receive(handle, buff, buffLen, 1000);   // 发送数据
    }

    // CS 失能处理
    SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_LOW : SR_GPIO_HIGH);

    return (halRet == HAL_OK) ? SR_OK : SR_FAIL;

}

int BspSpiWriteReg(SR_DEVICE_T *dev, uint32_t reg,uint16_t regLen,uint8_t *buff, uint16_t buffLen)
{
    BSP_SPI_INFO_T *info = (BSP_SPI_INFO_T *)dev->deviceData;
	SR_SPI_DEV_T *spiDev = (SR_SPI_DEV_T *)dev;
    uint8_t i,regAddr[4] = {0};


    // 检查有效性检查
    if(!dev || !info || !info->trdHandle || (regLen<=0 || regLen>4)) return SR_INVALID;

    // 复制寄存器地址
    for (i = 0; i < regLen; i++)
        regAddr[i] = (reg >> (8 * (regLen - 1 - i)) & 0xFF);

    // CS 使能处理
    SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_HIGH:SR_GPIO_LOW);

    // 调用原厂接口
    HAL_StatusTypeDef halRet;
	SPI_HandleTypeDef *handle = (SPI_HandleTypeDef *)info->trdHandle;

        //WARN：目前只考虑了8bit数据宽度，待优化
    halRet =  HAL_SPI_Transmit(handle, regAddr, regLen, 1000); // 发送寄存器地址
    if(halRet == HAL_OK) 
    {
			if(buff && buffLen!=0)
        halRet = HAL_SPI_Transmit(handle, buff, buffLen, 1000);   // 发送数据
    }

    // CS 失能处理
    SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_LOW : SR_GPIO_HIGH);

    return (halRet == HAL_OK) ? SR_OK : SR_FAIL;
}

int BspSpiWriteRead(SR_DEVICE_T *dev,uint8_t *txBuf,uint8_t *rxBuf,uint16_t len,uint8_t csCtrl)
{
    BSP_SPI_INFO_T *info = (BSP_SPI_INFO_T *)dev->deviceData;
	SR_SPI_DEV_T *spiDev = (SR_SPI_DEV_T *)dev;

    // 检查有效性检查
    if(!dev || !info || !info->trdHandle) return SR_INVALID;

    // CS 使能处理
    if(csCtrl&SR_SPI_CS_SEL )
        SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_HIGH:SR_GPIO_LOW);

    // 调用原厂接口
    HAL_StatusTypeDef halRet;
	SPI_HandleTypeDef *handle = (SPI_HandleTypeDef *)info->trdHandle;
		
		if(txBuf && !rxBuf)
			halRet = HAL_SPI_Transmit(handle, txBuf, len, 1000);
		else if(!txBuf && rxBuf)
			halRet = HAL_SPI_Receive(handle, rxBuf, len, 1000); 
		else
			halRet =  HAL_SPI_TransmitReceive(handle,txBuf,rxBuf,len, 1000);    

    // CS 失能处理
    if(csCtrl&SR_SPI_CS_RLS )
        SR_HalGpioWrite(spiDev->csId, (spiDev->csPol) ? SR_GPIO_LOW : SR_GPIO_HIGH);

     return (halRet == HAL_OK) ? SR_OK : SR_FAIL;
}   


//根据从机支持速率换成spi预分频值
static uint32_t  _GetSpiClkPrescaler(SPI_TypeDef  *instance,uint32_t speed)
{
    
    uint32_t SPI_CLOCK,prescaler;

    /* Some series may only have APBPERIPH_BASE, but don't have HAL_RCC_GetPCLK2Freq */
    #if defined(APBPERIPH_BASE)
        SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
    #elif defined(APB1PERIPH_BASE) || defined(APB2PERIPH_BASE)
        /* The SPI clock for H7 cannot be configured with a peripheral bus clock, so it needs to be written separately */
    #if defined(SOC_SERIES_STM32H7)
        /* When the configuration is generated using CUBEMX, the configuration for the SPI clock is placed in the HAL_SPI_Init function.
        Therefore, it is necessary to initialize and configure the SPI clock to automatically configure the frequency division */
        HAL_SPI_Init(spi_handle);
        SPI_CLOCK = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
    #else
        if ((uint32_t)instance >= APB2PERIPH_BASE)
        {
            SPI_CLOCK = HAL_RCC_GetPCLK2Freq();
        }
        else
        {
            SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
        }
    #endif /* SOC_SERIES_STM32H7) */
    #endif /* APBPERIPH_BASE */

    if (speed >= SPI_CLOCK / 2)
    {
        prescaler = SPI_BAUDRATEPRESCALER_2;
    }
    else if (speed >= SPI_CLOCK / 4)
    {
        prescaler = SPI_BAUDRATEPRESCALER_4;
    }
    else if (speed >= SPI_CLOCK / 8)
    {
        prescaler = SPI_BAUDRATEPRESCALER_8;
    }
    else if (speed >= SPI_CLOCK / 16)
    {
        prescaler = SPI_BAUDRATEPRESCALER_16;
    }
    else if (speed >= SPI_CLOCK / 32)
    {
        prescaler = SPI_BAUDRATEPRESCALER_32;
    }
    else if (speed >= SPI_CLOCK / 64)
    {
        prescaler = SPI_BAUDRATEPRESCALER_64;
    }
    else if (speed >= SPI_CLOCK / 128)
    {
        prescaler = SPI_BAUDRATEPRESCALER_128;
    }
    else
    {
        /*  min prescaler 256 */
        prescaler = SPI_BAUDRATEPRESCALER_256;
    }

    return prescaler;
}


void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* SPI1 clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

#ifdef BSP_SPI1_PIN_SEL_B3_B4_B5
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

#else
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#endif
  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();

#ifdef BSP_SPI1_PIN_SEL_B3_B4_B5
    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
#else
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
#endif

  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
  }
}

#endif  //end of SR_USE_SPI
