#include "bsp_spi_soft.h"
#include "elog.h"
// #include "delay.h"

#define DELAY_TIME 1 // 10微秒

void SPI_Init(const SPI_SOFT_TypeDef *pSoftSPI)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	__HAL_RCC_GPIOF_CLK_ENABLE(); // 使能GPIO F 时钟

	// //CS引脚初始化
	GPIO_InitStructure.Pin = pSoftSPI->cs_pin;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(pSoftSPI->cs_port, &GPIO_InitStructure);

	// SCK和MOSI引脚初始化
	GPIO_InitStructure.Pin = pSoftSPI->sclk_pin;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(pSoftSPI->sclk_port, &GPIO_InitStructure);

	// MISO引脚初始化
	GPIO_InitStructure.Pin = pSoftSPI->miso_pin;
	// GPIO_InitStructure.Mode = GPIO_Mode_IPU ;               //浮空输入
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT; // 浮空输入
	GPIO_InitStructure.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(pSoftSPI->miso_pin, &GPIO_InitStructure);

	// MOSI引脚初始化
	GPIO_InitStructure.Pin = pSoftSPI->mosi_pin;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(pSoftSPI->mosi_port, &GPIO_InitStructure);

	//  初始化  0   0
	HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_SET); // 极性0 初始化需要拉高
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_SET);
	// HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_SET);
}

/**
 * @brief Set SDIO as the input mode
 */
void SDO_IN(const SPI_SOFT_TypeDef *pSoftSPI)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = pSoftSPI->miso_pin;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(pSoftSPI->miso_pin, &GPIO_InitStruct);
}
/**
 * @brief Set SDIO as the output mode
 */
void SDO_OUT(const SPI_SOFT_TypeDef *pSoftSPI)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.Pin = pSoftSPI->miso_pin;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(pSoftSPI->miso_pin, &GPIO_InitStruct);
}
/**
 * @brief Send one byte by SPI bus
 * @def  先拉低，然后发送，在拉高有个跳变沿（从机检测到跳变），然后可以进入接收
 * @param u8_writedata
 */
void SPI_Write_OneByte(const SPI_SOFT_TypeDef *pSoftSPI, uint8_t u8_writedata)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET); // SCK Low
 		__NOP();
		if (u8_writedata & 0x80)
			// SDI_H;
			HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_SET);
		else
			// SDI_L;
			HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_RESET);
		// SCLK_H;
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_SET);
		__NOP();
		u8_writedata <<= 1;
		// SCLK_L;
		// HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET);
	}
}
/**
 * @brief Read one byte by SPI bus
 *
 * @return temp
 */
uint8_t SPI_Read_OneByte(const SPI_SOFT_TypeDef *pSoftSPI)
{
	uint8_t i;
	uint8_t temp = 0;
	for (i = 0; i < 8; i++)
	{
		temp <<= 1;
		// SCLK_H;
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_SET);  // SCK  High
 		__NOP();
		// if (SDO_R)
		if (HAL_GPIO_ReadPin(pSoftSPI->miso_port, pSoftSPI->miso_pin) == GPIO_PIN_SET)  // miso read
			temp |= 0x01;
		// SCLK_L;
 		__NOP();
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET);  
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_SET);  // SCK  High
	}
	return temp;
}

// 同步传输数据，比如在时钟的上升沿是写数据，那么在时钟的下降沿就是读数据
uint8_t SPI_ReadWriteByte(const SPI_SOFT_TypeDef *pSoftSPI, uint8_t TxData)
{
	int i = 0;
	uint8_t RxData = 0;

	HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET); // sclk low
	for (i = 7; i >= 0; i--)
	{
		// W25QXX_SCK_L();     // 时钟拉低 ，发送1bit
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET); // SCK Low
 		__NOP();
		// 数据发送
		if (TxData & (1 << i))
		{
			HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_SET); // MOSI H
		}
		else
		{
			HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_RESET); // MOSI L
		}
 		__NOP(); 

		// W25QXX_SCK_H();   // 拉高时钟读 1bit
		HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_SET);
 		__NOP();

		// 数据接收
		RxData <<= 1;
		if (HAL_GPIO_ReadPin(pSoftSPI->miso_port, pSoftSPI->miso_pin) == GPIO_PIN_SET)
			RxData |= 0x01;

 		__NOP();
	}

	HAL_GPIO_WritePin(pSoftSPI->sclk_port, pSoftSPI->sclk_pin, GPIO_PIN_RESET); // SCK LOw
	return RxData;
}

void SPI_Read_Write_buf(const SPI_SOFT_TypeDef *pSoftSPI, uint8_t* txBuf,uint8_t* rxBuf,uint16_t len)
{
	int i = 0;
	uint8_t RxData = 0;

	for ( size_t i = 0; i < len; i++ )
	{
		if (i==0) {
			SPI_Write_OneByte(pSoftSPI, *txBuf);
			txBuf++;
		}
		else{
			*rxBuf = SPI_ReadWriteByte(pSoftSPI, *txBuf);
			txBuf++;
			rxBuf++;
		}
	}
	//  TODO TimeOut
	return  ;
}

/**
 * @brief 	Write a register
 *
 * @param  d: {D2, D1, D0}  addr uint32_T
 * @return SUCCESS
 */
uint8_t WriteReg(const SPI_SOFT_TypeDef *pSoftSPI, uint32_t d)
{
	uint8_t tx[3] = {(d >> 16) & 0xff, (d >> 8) & 0xff, d & 0xff};
	SDO_OUT(pSoftSPI);
	// CS_L;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_RESET);
	SPI_Write_OneByte(pSoftSPI, tx[0]);
	SPI_Write_OneByte(pSoftSPI, tx[1]);
	SPI_Write_OneByte(pSoftSPI, tx[2]);
	// CS_H;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_SET);
	// SDI_L;
	HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_RESET);
	return SUCCESS;
}

/**
 * @brief 	Read a register
 * @param  d: {D2, D1, D0}  addr uint32_t
 * @return data: The data be read in a register
 */
uint8_t ReadReg(const SPI_SOFT_TypeDef *pSoftSPI, uint32_t d)
{
	uint8_t tx[3] = {(d >> 16) & 0xff, (d >> 8) & 0xff, d & 0xff};
	uint8_t data;
	// tx[0] = tx[0] | RF_DATA_READ_BIT;
	SDO_OUT(pSoftSPI);
	// CS_L;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_RESET);
	SPI_Write_OneByte(pSoftSPI, tx[0]);
	SPI_Write_OneByte(pSoftSPI, tx[1]);

	data = SPI_Read_OneByte(pSoftSPI);
	// CS_H;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_SET);
	SDO_OUT(pSoftSPI);
	// SDI_L;
	HAL_GPIO_WritePin(pSoftSPI->mosi_port, pSoftSPI->mosi_pin, GPIO_PIN_RESET);

	log_i(" ReadReg ... %02X   ", data);
	return data;
}

// test  ok
uint32_t SPI_FLASH_ReadDeviceID(const SPI_SOFT_TypeDef *pSoftSPI)
{
	uint32_t Temp = 0;
	uint8_t readout = 0;
	// CS_L;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_RESET);

	log_i(" SPI_FLASH_ReadDeviceID ...  ");
	// 发送4字节指令
	//   readout = SPI_ReadWriteByte(pSoftSPI,0x9F);
	SPI_Write_OneByte(pSoftSPI, 0x9F);
	Temp |= (readout << 24);

	readout = SPI_ReadWriteByte(pSoftSPI, 0xFF);

	//   readout = SPI_ReadWriteByte(pSoftSPI,0xFF);
	Temp |= (readout << 16);
	readout = SPI_ReadWriteByte(pSoftSPI, 0xFF);
	//   readout = SPI_ReadWriteByte(pSoftSPI,0xFF);
	Temp |= (readout << 8);
	readout = SPI_ReadWriteByte(pSoftSPI, 0xFF);
	//   readout = SPI_ReadWriteByte(pSoftSPI,0xFF);
	Temp |= (readout);

	log_i("rrrr: 0x%08X\n", Temp); // 0X00EF4019
								   // CS_H;
	HAL_GPIO_WritePin(pSoftSPI->cs_port, pSoftSPI->cs_pin, GPIO_PIN_SET);

	return Temp;
}

