#include "driver.h"
#include <linux/types.h>
#include <stdio.h>
#include <string.h>
#include "com_gpio.h"
#include "hal_interface_api.h"
#include "linux/fcntl.h"
#include "time.h"
#include <unistd.h>

#define DEV_NAME	"/dev/spi"
/*
bus: 1,2,3,4,5,6
*/
int stm32_spi_master_write(uint8_t spi, uint8_t *pBuf, uint32_t size)
{
	int fd;
	int ret;
	uint8_t dev_name[10] = {0};
	spi_arg_t spi_arg;
	// GPIO_TypeDef *NSS_PORT = NULL;
	// uint16_t	NSS_PIN = 0;

	switch(spi)
	{
	case 1:
		break;
	case 2:
		// NSS_PORT = GPIOI;
		// NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		// NSS_PORT = GPIOF;
		// NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", dev_name);
	}

	// //NSS low
	// stm32_gpio_write(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
	// usleep(1000);
	
	spi_arg.Size = size;
	memcpy(spi_arg.buf, pBuf, size);
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	if(ret == -1)
	{
		printf("Write spi failed!\n");
	}

	// //NSS high
	// stm32_gpio_write(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);

	close(fd);
	return 0;
}

int stm32_spi_master_read(uint8_t spi, uint8_t *pBuf, uint32_t size)
{
	int fd;
	int ret;
	uint8_t dev_name[10] = {0};
	spi_arg_t spi_arg;
	// GPIO_TypeDef *NSS_PORT = NULL;
	// uint16_t	NSS_PIN = 0;

	switch(spi)
	{
	case 1:
		break;
	case 2:
		// NSS_PORT = GPIOI;
		// NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		// NSS_PORT = GPIOF;
		// NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", DEV_NAME);
	}
	
	spi_arg.Size = size;
	ret = ioctl(fd, SPI_MASTER_RECEIVE, &spi_arg);
	if(ret == -1)
	{
		printf("Read spi failed!\n");
	}
	memcpy(pBuf, spi_arg.buf, size);

	close(fd);

	return 0;
}

int stm32_spi_master_write_read(uint8_t spi, uint8_t *txBuf, uint32_t txSize, uint8_t *rxBuf, uint32_t rxSize)
{
	int fd;
	int ret;
	uint8_t dev_name[10] = {0};
	spi_arg_t spi_arg;
	// GPIO_TypeDef *NSS_PORT = NULL;
	// uint16_t	NSS_PIN = 0;

	switch(spi)
	{
	case 1:
		break;
	case 2:
		// NSS_PORT = GPIOI;
		// NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		// NSS_PORT = GPIOF;
		// NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", DEV_NAME);
	}

	//Tx
	if(txSize > 0)
	{
		spi_arg.Size = txSize;
		memcpy(spi_arg.buf, txBuf, txSize);
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		if(ret == -1)
		{
			printf("Read spi failed!\n");
		}
	}

	//Rx
	if(rxSize > 0)
	{
		spi_arg.Size = rxSize;
		memset(spi_arg.buf, 0, rxSize);
		ret = ioctl(fd, SPI_MASTER_RECEIVE, &spi_arg);
		if(ret == -1)
		{
			printf("Read spi failed!\n");
		}
		memcpy(rxBuf, spi_arg.buf, rxSize);
	}

	close(fd);

	return 0;
}

/*
timeout: ms
*/
static int sf_wait_spi_ready(int fd, uint32_t timeout)
{ 
	spi_arg_t spi_arg;
	int ret = 0;
	uint32_t timeCnt = 0;
	
	spi_arg.Size = 1;
	spi_arg.buf[0] = 0x05;
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	if(ret == -1)
	{
		printf("SPI Read status1 failed!\n");
		return -1;
	}
	
	timeCnt = 0;
	do{
		timeCnt++;
		spi_arg.Size = 1;
		ret = ioctl(fd, SPI_MASTER_RECEIVE, &spi_arg);
		if(ret == -1)
		{
			printf("SPI Read status1 failed!\n");
		}

		if(spi_arg.buf[0]&0x01)
			usleep(10);
		else
			break;
	}while(timeCnt < timeout*100);

	//NSS high
	//stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);
}
/*
	flash: 	fw flash, spi5
	cmd:	erase 4 KB
*/
int sf_sector_erase(uint8_t spi, uint32_t offset)
{
	int fd;
	int ret;
	uint8_t dev_name[10] = {0};
	spi_arg_t spi_arg;
	uint32_t erase_addr = 0;
	uint8_t		status1_reg;
	uint32_t	timeout = 0;
	GPIO_TypeDef *NSS_PORT = NULL;
	uint16_t	NSS_PIN = 0;


	//erase_addr is the start address of one sector.
	erase_addr = (offset/4096)*4096;
	//printf("---> sf_sector_erase %#x\n", erase_addr);

	switch(spi)
	{
	case 1:
		break;
	case 2:
		NSS_PORT = GPIOI;
		NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		NSS_PORT = GPIOF;
		NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", dev_name);
	}

	//Write Enable
	spi_arg.Size = 1;
	spi_arg.buf[0] = 0x06;
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
	if(ret == -1)
	{
		printf("SPI Write Enable failed!\n");
		return -1;
	}

	//Sector Erase
	spi_arg.Size = 4;
	spi_arg.buf[0] = 0x20;
	spi_arg.buf[1] = (erase_addr>>16)&0xff;
	spi_arg.buf[2] = (erase_addr>>8)&0xff;
	spi_arg.buf[3] = erase_addr&0xff;
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
	if(ret == -1)
	{
		printf("SPI sector erase failed!\n");
		return -1;
	}
	

	usleep(3000);	//3ms
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	sf_wait_spi_ready(fd, 400);	//400ms
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high

	close(fd);

	return 0;
}

/*
	flash: 	fw flash, spi5
	cmd:	erase whole chip
*/
int sf_chip_erase(uint8_t spi)
{
	int fd;
	int ret;
	uint8_t dev_name[10] = {0};
	spi_arg_t spi_arg;
	uint8_t		status1_reg;
	uint32_t	timeout = 0;
	GPIO_TypeDef *NSS_PORT = NULL;
	uint16_t	NSS_PIN = 0;

	switch(spi)
	{
	case 1:
		break;
	case 2:
		NSS_PORT = GPIOI;
		NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		NSS_PORT = GPIOF;
		NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", dev_name);
	}

	//Write Enable
	spi_arg.Size = 1;
	spi_arg.buf[0] = 0x06;
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
	if(ret == -1)
	{
		printf("SPI Write Enable failed!\n");
		return -1;
	}

	//chip Erase
	spi_arg.Size = 1;
	spi_arg.buf[0] = 0x60;
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
	if(ret == -1)
	{
		printf("SPI sector erase failed!\n");
		return -1;
	}
	

	sleep(10);	//10s
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	sf_wait_spi_ready(fd, 100000);	//100s
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high

	close(fd);

	return 0;
}

int sf_get_id(uint8_t spi, uint8_t *id)
{
	int fd;
	spi_arg_t args;
	uint8_t dev_name[10] = {0};
	int i;
	GPIO_TypeDef *NSS_PORT = NULL;
	uint16_t	NSS_PIN = 0;

	switch(spi)
	{
	case 1:
		break;
	case 2:
		NSS_PORT = GPIOI;
		NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		NSS_PORT = GPIOF;
		NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd < 0)
		printf("open failed\n");
	

	memset(args.buf, 0, 100);
	args.buf[0] = 0x9f;
	args.Size = 1;
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
	ioctl(fd, SPI_MASTER_TRANSFER, &args);
	args.Size = 3;
	ioctl(fd, SPI_MASTER_RECEIVE, &args);
	stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high
	memcpy(id, args.buf, args.Size);
	//printf("get id: %#x %#x %#x\n", id[0], id[1], id[2]);
	
			
	close(fd);
}

/*
	spi: 1,2,3,4,5,6
	PageSize = 256 bytes.
	Address must be the start of one page.
*/
int sf_write(uint8_t spi, uint32_t offset, uint8_t *buf, uint32_t size)
{
	int fd;
	int ret;
	spi_arg_t spi_arg;
	uint8_t 	dev_name[10] = {0};
	uint8_t		status1_reg;
	uint32_t	timeout = 0;
	uint32_t	remain = 0, writeLen = 0;
	uint32_t 	writeAddr = 0;
	GPIO_TypeDef *NSS_PORT = NULL;
	uint16_t	NSS_PIN = 0;


	//erase_addr is the start address of one sector.
	if(offset&0xff)
	{
		printf("The Address %#x is not a pages start!\n", offset);
		return -1;
	}

	//printf("---> sf_write %#x\n", offset);

	switch(spi)
	{
	case 1:
		break;
	case 2:
		NSS_PORT = GPIOI;
		NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		NSS_PORT = GPIOF;
		NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", dev_name);
	}

	
	
	//usleep(1000);
	
	remain = size;
	writeLen = 0;
	writeAddr = offset;
	while(remain > 256)
	{
		
		//Write Enable
		spi_arg.Size = 1;
		spi_arg.buf[0] = 0x06;
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
		if(ret == -1)
		{
			printf("SPI Write Enable failed!\n");
			return -1;
		}
		//Page Write
		spi_arg.Size = 260;
		spi_arg.buf[0] = 0x02;	//page write
		spi_arg.buf[1] = (writeAddr>>16)&0xff;
		spi_arg.buf[2] = (writeAddr>>8)&0xff;
		spi_arg.buf[3] = writeAddr&0xff;
		memcpy(&spi_arg.buf[4], &buf[writeLen], 256);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high
		if(ret == -1)
		{
			printf("SPI Read status1 failed!\n");
			return -1;
		}
		//wait page write finish
		usleep(700);	//700us
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		if(0 != sf_wait_spi_ready(fd, 3))	//3ms
			printf("Warnning page write timeout!\n");
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high

		remain -= 256;
		writeLen += 256;
		writeAddr += 256;
	}

	if(remain > 0)
	{
		//Write Enable
		spi_arg.Size = 1;
		spi_arg.buf[0] = 0x06;
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);	//NSS high
		if(ret == -1)
		{
			printf("SPI Write Enable failed!\n");
			return -1;
		}
		//page write
		spi_arg.Size = remain + 4;
		spi_arg.buf[0] = 0x02;	//page write
		spi_arg.buf[1] = (writeAddr>>16)&0xff;
		spi_arg.buf[2] = (writeAddr>>8)&0xff;
		spi_arg.buf[3] = writeAddr&0xff;
		memcpy(&spi_arg.buf[4], &buf[writeLen], remain);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high
		if(ret == -1)
		{
			printf("SPI Read status1 failed!\n");
			return -1;
		}
		//wait page write finish
		usleep(700);	//700us
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		if(0 != sf_wait_spi_ready(fd, 3))	//3ms
			printf("Warnning page write timeout!\n");
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high

		
		writeLen += remain;
		writeAddr += remain;
		remain -= remain;
	}
	
	close(fd);

	return 0;
}


/*
	spi: 1,2,3,4,5
	PageSize = 256 bytes.
	Address must be the start of one page.
*/
int sf_read(uint8_t spi, uint32_t offset, uint8_t *buf, uint32_t size)
{
	int fd;
	int ret;
	spi_arg_t spi_arg;
	uint8_t 	dev_name[10] = {0};
	uint8_t		status1_reg;
	uint32_t	timeout = 0;
	uint32_t	remain = 0, readLen = 0;
	uint32_t 	readAddr;
	GPIO_TypeDef *NSS_PORT = NULL;
	uint16_t	NSS_PIN = 0;


	//erase_addr is the start address of one sector.
	if(offset&0xff)
	{
		printf("The Address %#x is not a pages start!\n", offset);
		return -1;
	}
	//printf("---> sf_read %#x\n", offset);

	switch(spi)
	{
	case 1:
		break;
	case 2:
		NSS_PORT = GPIOI;
		NSS_PIN = GPIO_PIN_0;
		break;
	case 3:
		break;
	case 4:
		break;
	case 5:
		NSS_PORT = GPIOF;
		NSS_PIN = GPIO_PIN_6;
		break;	
	case 6:
		break;
	default:
		printf("Invalid bus number %d\n", spi);
		return -1;
	}

	sprintf(dev_name, "%s%d", DEV_NAME, spi);
	fd = open(dev_name, O_RDWR);
	if(fd == -1)
	{
		printf("Open %s failed!\n", dev_name);
	}
		
	remain = size;
	readLen = 0;
	readAddr = offset;
	while(remain > 256)
	{
		
		spi_arg.Size = 5;
		spi_arg.buf[0] = 0x0B;	//fast read
		spi_arg.buf[1] = (readAddr>>16)&0xff;
		spi_arg.buf[2] = (readAddr>>8)&0xff;
		spi_arg.buf[3] = readAddr&0xff;
		spi_arg.buf[4] = 0;	//dummy
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		if(ret == -1)
		{
			printf("SPI Fast Read command failed!\n");
			return -1;
		}
		spi_arg.Size = 256;
		ret = ioctl(fd, SPI_MASTER_RECEIVE, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high
		if(ret == -1)
		{
			printf("SPI fast Read failed!\n");
			return -1;
		}
		
		memcpy(&buf[readLen], spi_arg.buf, 256);

		remain -= 256;
		readLen += 256;
		readAddr += 256;
	}

	if(remain > 0)
	{
		
		spi_arg.Size = 5;
		spi_arg.buf[0] = 0x0B;	//fast read
		spi_arg.buf[1] = (readAddr>>16)&0xff;
		spi_arg.buf[2] = (readAddr>>8)&0xff;
		spi_arg.buf[3] = readAddr&0xff;
		spi_arg.buf[4] = 0;	//dummy
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_RESET);	//NSS low
		ret = ioctl(fd, SPI_MASTER_TRANSFER, &spi_arg);
		if(ret == -1)
		{
			printf("SPI Fast Read command failed!\n");
			return -1;
		}
		spi_arg.Size = remain;
		ret = ioctl(fd, SPI_MASTER_RECEIVE, &spi_arg);
		stm32_gpio_write(NSS_PORT, NSS_PIN, GPIO_PIN_SET);		//NSS high
		if(ret == -1)
		{
			printf("SPI fast Read failed!\n");
			return -1;
		}
		

		memcpy(&buf[readLen], spi_arg.buf, remain);

		readLen += remain;
		readAddr += remain;
		remain -= remain;
	}
	
	close(fd);

	return 0;
}