/*
 *  htk_spi.c
 *
 *  Created on: Feb 07, 2020
 *      Author: CrystalSu
 */

#include "ht32.h"
#include "htk_spi.h"
#include "gpio.h"
#include "systick_for_timeout.h"

typedef struct
{
	HT_SPI_TypeDef *spi;
	HT_GPIO_TypeDef *ncs_port;
	uint16_t ncs_pin;
}htk_SPI_TypeDef;

uint8_t txBuffer[65];
uint8_t rxBuffer[65];
static htk_SPI_TypeDef htk_spi_struct;

/**
  * @brief  Initial SPI for using with CLI.
  * @param  SPI: A HT_SPI_TypeDef structure that contains
  * 			  the configuration information for the specified
  * 			  SPI module.
  * @param	*NCS_Port: Pointer points to HT_GPIO_TypeDef structure that
  * 				contains configuration information for the specified
  * 				GPIO of SPI NCS port.
  * @param	NCS_Pin: SPI NCS pin which is used to select any chip.
  * @retval None
  */
void htk_SPI_Init(HT_SPI_TypeDef *SPI, HT_GPIO_TypeDef *NCS_Port, uint16_t NCS_Pin)
{
	htk_spi_struct.spi = SPI;
	htk_spi_struct.ncs_port = NCS_Port;
	htk_spi_struct.ncs_pin = NCS_Pin;
}


/**
  * @brief  Transmit and Receive an amount of data in non-blocking mode.
  * @param  hspi: pointer to a HT_SPI_TypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pTxData: pointer to transmission data buffer
  * @param  pRxData: pointer to reception data buffer
  * @param  Size: amount of data to be sent and received
  * @retval StatusTypeDef
  */
StatusTypeDef SPI_TransmitReceive(HT_SPI_TypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
	StatusTypeDef errorcode = HAL_OK;
	uint32_t tickstart = Get_TickCount();
  while (Size--)
  {

		/* Loop while Tx buffer register is empty                                                                 */
		while (!SPI_GetFlagStatus(hspi, SPI_FLAG_TXBE))
		{
      if((Timeout != HAL_MAX_DELAY) && ((Get_TickCount()-tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
		}

		/* Send byte through the SPIx peripheral                                                                  */
		SPI_SendData(hspi, *pTxData);
		pTxData++;

		/* Loop while Rx is not empty                                                                             */
		while (!SPI_GetFlagStatus(hspi, SPI_FLAG_RXBNE))
		{
      if((Timeout != HAL_MAX_DELAY) && ((Get_TickCount()-tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
		}

		/* Return the byte read from the SPI                                                                      */
		*pRxData = SPI_ReceiveData(hspi);
		pRxData++;
  }
	error:
	
	return errorcode;
}


/**
  * @brief  SPI write single register of BC45.
  * @param  address: Register address of BC45 for write.
  * @param  data: Data to write.
  * @retval None
  */
void htk_SPI_writeSingleRegister(uint8_t address, uint8_t data)
{
  uint8_t tmpAddr = 0;
  uint8_t txBuffer[2];
  uint8_t rxBuffer[2];

  NCS_CLR(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);
  tmpAddr = (uint8_t)(address << 1) & 0x7E;
  txBuffer[0] = tmpAddr;
  txBuffer[1] = data;

  /* SPI transmit and receive */
  SPI_TransmitReceive(htk_spi_struct.spi, txBuffer, rxBuffer, 2, HAL_MAX_DELAY);

  NCS_SET(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);
	
	//htk_SPI_readSingleRegister(address, &data);
	//data = 0;
}


/**
  * @brief  SPI read single register of BC45.
  * @param  address: Register address of BC45 for read.
  * @param  data: Pointer to data buffer for storing
  * 			  output data from the register.
  * @retval None
  */
void htk_SPI_readSingleRegister(uint8_t address, uint8_t *data)
{
  uint8_t tmpAddr = 0;
  uint8_t txBuffer[2];
  uint8_t rxBuffer[2];

  NCS_CLR(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);
  tmpAddr = (((uint8_t)(address << 1) & 0x7E) | 0x80);
  txBuffer[0] = tmpAddr;
  txBuffer[1] = 0x00; // dummy data

  /* SPI transmit and receive data */
  SPI_TransmitReceive(htk_spi_struct.spi, txBuffer, rxBuffer, 2, HAL_MAX_DELAY);
  /* Keep the data to rxBuffer */
  *data = rxBuffer[1];

  NCS_SET(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);
}

/**
  * @brief  SPI write multiple data to single register of BC45.
  * @param  address: Register address of BC45 to write.
  * @param  data: Pointer to data input buffer for writing.
  * @param  len: Length of data input.
  * @retval None
  */
void htk_SPI_writeMultiData(uint8_t address, uint8_t *data, uint16_t inputLen)
{
  uint8_t dataOffset = 1;
  uint8_t srcOffset = 0;
  uint8_t tmpAddr = 0;
  uint8_t len;
  uint8_t countData;
  StatusTypeDef status;

  /*Check length data input*/
  if(inputLen <= 64)
  {
	  len = inputLen;
  }
  else
  {
	  len = 64;
  }

  /*Assign the address to write*/
  tmpAddr = (uint8_t)(address << 1) & 0x7E;
  txBuffer[0] = tmpAddr;

  NCS_CLR(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);

  /*Loop for writing the input data*/
  while(inputLen != 0)
  {
	  for(countData = 0; countData < len; countData++)
	  {
		  txBuffer[countData + dataOffset] = data[countData + srcOffset];
	  }

	  status = SPI_TransmitReceive(htk_spi_struct.spi,
			  	  	  	  	  	  	    txBuffer, rxBuffer,
										countData + dataOffset,
										500);
	  if(status == HAL_OK)
	  {
		  dataOffset = 0;
		  srcOffset += len;
		  inputLen = inputLen - len;
		  if(inputLen < 64)
		  {
			  len = inputLen;
		  }
	  }
	  else
	  {
		  //Go to Error Callback
	  }
  }

  NCS_SET(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);

}


/**
  * @brief  SPI read multiple data from single register of BC45.
  * @param  address: Register address of BC45 to read.
  * @param  data: Pointer to data output buffer for reading.
  * @param  len: Length of data output.
  * @retval None
  */
void htk_SPI_readMultiData(uint8_t address, uint8_t *data, uint16_t outputLen)
{
  uint8_t dataOffset = 0;
  uint8_t srcOffset = 1;
  uint8_t tmpAddr = 0;
  uint8_t len;
  uint8_t countData;
  StatusTypeDef status;

  /*Check length output data*/
  if(outputLen <= 64)
  {
	  len = outputLen;
  }
  else
  {
	  len = 64;
  }

  /*Assign the address to read*/
  tmpAddr = (address << 1);
  txBuffer[0] = tmpAddr | 0x80;

  NCS_CLR(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);

  /*Loop for reading the data*/
  while(outputLen != 0)
  {
	  for(countData = 0; countData < len; countData++)
	  {
		  txBuffer[countData + srcOffset] = tmpAddr;
	  }
	  if(len == outputLen)
	  {
		  txBuffer[len - 1 + srcOffset] = 0x00;
	  }

	  status = SPI_TransmitReceive(htk_spi_struct.spi,
	  			  	  	  	  	  	  	    txBuffer, rxBuffer,
											len + srcOffset,
	  										500);

	  for(countData = 0; countData < len; countData++)
	  {
		  data[countData + dataOffset] = rxBuffer[countData + srcOffset];
	  }

	  outputLen = outputLen - len;
	  if(outputLen < 64)
	  {
		  srcOffset = 0;
		  dataOffset += len;
		  len = outputLen;
	  }

  }

  NCS_SET(htk_spi_struct.ncs_port, htk_spi_struct.ncs_pin);

}





