#include "spiflash.h"
#include "rtthread.h"
#include "DebugCmd.h"
#include "Public.h"

//#define	FLASH_TEST

#ifdef FLASH_TEST
uint8_t flashtestbuff[SPIFLASH_SIZE];
#endif

static uint8_t SpiFlashReadByte(void)
{
	return Spi1SendReceive(0);
}

static void SpiFlashSendByte(uint8_t sData)
{
	Spi1SendReceive(sData);
}

static void SpiFlashWriteEnable(void)
{
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_WREN);
	SpiFlashSetNss();
}

static void SpiFlashWaitForWriteEnd(void)
{
	uint8_t flashstatus = 0;
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_RDSR);
	do{
		flashstatus = SpiFlashReadByte();
		FeedDog();
	}
	while ((flashstatus & SPIFLASH_WIP_FLAG) == SPIFLASH_WIP_FLAG); 
	SpiFlashSetNss();
}

//扇区擦除
void SpiFlashEraseSector(uint32_t SectorAddr)
{
#ifdef FLASH_TEST
	memset(&flashtestbuff[SectorAddr], 0xff, 4096);
#else	
	SpiFlashWriteEnable();
	SpiFlashWaitForWriteEnd();
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_SE);
	SpiFlashSendByte((SectorAddr >> 16) & 0x00FF);
	SpiFlashSendByte((SectorAddr >> 8) & 0x00FF);
	SpiFlashSendByte(SectorAddr & 0x00FF);
	SpiFlashSetNss();
	SpiFlashWaitForWriteEnd();
#endif
}

//整片擦除
void SpiFlashEraseChip(void)
{
	SpiFlashWriteEnable();
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_BE);
	SpiFlashSetNss();
	SpiFlashWaitForWriteEnd();
}

//写数据
void SpiFlashWriteData(uint8_t* wData, uint32_t wAddr, uint16_t wLen)
{
#ifdef FLASH_TEST
	memcpy(&flashtestbuff[wAddr], wData, wLen);
#else
	SpiFlashWriteEnable();
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_WRITE);
	SpiFlashSendByte((wAddr >> 16) & 0x00FF);
	SpiFlashSendByte((wAddr >> 8) & 0x00FF);
	SpiFlashSendByte(wAddr & 0x00FF);
	for(int i = 0; i < wLen; i++) {
		SpiFlashSendByte(wData[i]);
	}
	SpiFlashSetNss();
	SpiFlashWaitForWriteEnd();
#endif	
}

void SpiFlashWriteAnyLengthData(uint8_t* wData, uint32_t wAddr, uint16_t wLen)
{
	uint16_t PageCnt;	//需要写入页数
	uint16_t FirstPageWriteSize;	//在起始地址不为页起始地址的情况下，先写入当前页剩余空间
	uint16_t LastPageWriteSize;	//最后一页写入长度
	uint32_t AddrOffset = 0;
	uint32_t WriteAddr;
	LogHeader LogH;
	WriteAddr = wAddr;
	
	//写入的长度超出最大空间，从起始开始写起
	if((WriteAddr + wLen) > SPIFLASH_SIZE) {
		LogH = (LogHeader)wData;
		WriteAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
		LogH->LogEndAddr = WriteAddr + wLen;
	}
	
	uint16_t FirstPageRemainSpace = SPIFLASH_PAGESIZE - (WriteAddr % SPIFLASH_PAGESIZE);
	
//	//判断是否跨扇区，跨扇区需要先擦除下一扇区
	CheckDelSecter(wAddr, wLen);
	
	if(wLen < FirstPageRemainSpace) {
		FirstPageWriteSize = wLen;		//计算首页写入长度
		PageCnt = 0;
		LastPageWriteSize = 0;
	} 
	else {
//		FirstPageWriteSize = FirstPageRemainSpace % SPIFLASH_PAGESIZE;
//		PageCnt = (wLen - (FirstPageWriteSize % SPIFLASH_PAGESIZE)) / SPIFLASH_PAGESIZE;		//计算需要写入多少整页
//		LastPageWriteSize = (wLen - (FirstPageWriteSize % SPIFLASH_PAGESIZE)) % SPIFLASH_PAGESIZE;	//计算剩余需要写入的长度
		FirstPageWriteSize = FirstPageRemainSpace;
		PageCnt = (wLen - FirstPageWriteSize) / SPIFLASH_PAGESIZE;		//计算需要写入多少整页
		LastPageWriteSize = (wLen - FirstPageWriteSize) % SPIFLASH_PAGESIZE;	//计算剩余需要写入的长度
	}
	
	if(FirstPageWriteSize > 0) {	
		SpiFlashWriteData(&wData[AddrOffset], WriteAddr, FirstPageWriteSize);
		AddrOffset += FirstPageWriteSize;
		WriteAddr += FirstPageWriteSize;
	}
	for(int i = 0; i < PageCnt; i++) {	
		SpiFlashWriteData(&wData[AddrOffset], WriteAddr, SPIFLASH_PAGESIZE);
		AddrOffset += SPIFLASH_PAGESIZE;
		WriteAddr += SPIFLASH_PAGESIZE;
	}
	if(LastPageWriteSize > 0) {		
		SpiFlashWriteData(&wData[AddrOffset], WriteAddr, LastPageWriteSize);
	}
}

void SpiFlashReadAnyLengthData(uint8_t* rData, uint32_t rAddr, uint16_t rLen)
{
#ifdef FLASH_TEST
	memcpy(rData, &flashtestbuff[rAddr], rLen);
#else	
	SpiFlashClrNss();
	SpiFlashSendByte(SPIFLASH_CMD_READ);
	SpiFlashSendByte((rAddr >> 16) & 0x00FF);
	SpiFlashSendByte((rAddr >> 8) & 0x00FF);
	SpiFlashSendByte(rAddr & 0x00FF);
	for(int i = 0; i < rLen; i++) {
		rData[i] = SpiFlashReadByte();
	}
	SpiFlashSetNss();
#endif	
}

uint32_t SpiFlashReadId(void)
{
	uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
	SpiFlashClrNss();
	SpiFlashSendByte(0x9F);
	Temp0 = SpiFlashReadByte();
	Temp1 = SpiFlashReadByte();
	Temp2 = SpiFlashReadByte();
	SpiFlashSetNss();
	Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
	return Temp;
}

typedef struct {
	uint16_t Flag;
	uint16_t LoopSavFlag;					//循环存储标志
	uint32_t LogCnt;							//日志最大数量
	uint32_t FirstLogStartAddr;		//第一个数据的起始地址
	uint32_t LastLogEndAddr;			//最后一个数据的结束地址
}LogNumSav_t;

static LogNumSav_t LogNumArray[256];
static __IO uint32_t gLogCnt = 0;
static __IO uint32_t FirstLogStartAddr = 0;			//第一个日志起始地址
static __IO uint32_t LastLogEndAddr = 0;				//最后一个日志结束地址
static __IO uint16_t LoopSavFlag = 0;						//循环存储标志
static uint16_t LogNumIdx;

uint16_t ReadLoopSavFlag(void)
{
	return LoopSavFlag;
}

void SetLoopSavFlag(uint16_t LoopFlag)
{
	LoopSavFlag = LoopFlag;
}

uint32_t ReadLogNum(void)
{
	return gLogCnt;
}

void SetLogNum(uint32_t LogCnt)
{
	gLogCnt = LogCnt;
}

uint32_t ReadFirstLogStartAddr(void)
{
	return FirstLogStartAddr;
}

void SetFirstLogStartAddr(uint32_t FLStartAddr)
{
	FirstLogStartAddr = FLStartAddr;
}


uint32_t ReadLastLogEndAddr(void)
{
	return LastLogEndAddr;
}

void SetLastLogEndAddr(uint32_t LLEndAddr)
{
	LastLogEndAddr = LLEndAddr;
}

void LogInit(void)
{
	LogNumIdx = 0xffff;
	SpiFlashReadId();
	SpiFlashReadAnyLengthData((uint8_t *)&LogNumArray, LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumArray));	
	for(int i = 0; i < 256; i++) {
		if(LogNumArray[i].Flag != LOG_INFO_SAV_FLAG) {
			LogNumIdx = i;
			break;
		}
	}
	if(LogNumIdx == 0xffff) {			//256条记录满，读最后一条记录
		LogNumIdx = 0;
		SetLogNum(LogNumArray[255].LogCnt);
		SetLoopSavFlag(LogNumArray[255].LoopSavFlag);
		SetFirstLogStartAddr(LogNumArray[255].FirstLogStartAddr);
		SetLastLogEndAddr(LogNumArray[255].LastLogEndAddr);
		return;
	}
	if(LogNumIdx == 0) {			//没有记录
		LogNumIdx = 0;
		SetLogNum(0);
		SetLoopSavFlag(0);
		SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		return;
	}
	SetLogNum(LogNumArray[LogNumIdx-1].LogCnt);
	SetLoopSavFlag(LogNumArray[LogNumIdx-1].LoopSavFlag);
	SetFirstLogStartAddr(LogNumArray[LogNumIdx-1].FirstLogStartAddr);
	SetLastLogEndAddr(LogNumArray[LogNumIdx-1].LastLogEndAddr);
}

void SavLogNum(uint32_t LogNum)
{
	LogNumSav_t CLogSav;
	
	if(LogNum == 0) {
		LogNumIdx = 0;
		SetLogNum(0);
		SetLoopSavFlag(0);
		SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
		return;
	}
	
	SetLogNum(LogNum);
	CLogSav.Flag = LOG_INFO_SAV_FLAG;
	CLogSav.LogCnt = LogNum;
	CLogSav.FirstLogStartAddr = ReadFirstLogStartAddr();
	CLogSav.LastLogEndAddr = ReadLastLogEndAddr();
	
	if(LogNumIdx == 256) {
		SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
		LogNumIdx = 0;
	}
	SpiFlashWriteData((uint8_t *)&CLogSav, LogNumIdx * sizeof(LogNumSav_t) + LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumSav_t));
	LogNumIdx++;
}

/*****************************************************************************************
* 函数名称: CheckDelSecter
* 功能描述: 检查需要删除的扇区，跨扇区删除下一扇区，如果到了删除最后一个扇区，循环到起始扇区
* 参    数: wAddr, 写入地址
						wLen, 写入长度
* 返 回 值: 返回写入起始地址
*****************************************************************************************/
uint8_t LogBuff[LOG_SAV_SIZE_MAX];
const uint8_t SavFlag[4] ={0xAA, 0x55, 0x55, 0xAA};
void CheckDelSecter(uint32_t wAddr, uint16_t wLen)
{
	uint32_t DelOffsetAddr, FindFirstLogAddr;				//存储起始地址
	uint32_t DelSectorNum = 0;
	uint32_t SurplusSpace = SPIFLASH_SECTORSIZE - (wAddr % SPIFLASH_SECTORSIZE);
	
	if((wAddr + wLen) > SPIFLASH_SIZE) {
		DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
		SetLastLogEndAddr(DelOffsetAddr + wLen);
		SetLoopSavFlag(1);
		SpiFlashEraseSector(DelOffsetAddr);
		FindFirstLogAddr = DelOffsetAddr + SPIFLASH_SECTORSIZE;
	}
	else {
		if(wLen < SurplusSpace) {	//长度没有超过扇区剩余容量
			SetLastLogEndAddr(wAddr + wLen);
			return;
		}
		DelOffsetAddr = (wAddr / SPIFLASH_SECTORSIZE + 1) * SPIFLASH_SECTORSIZE;
		DelSectorNum = (wLen - SurplusSpace) / SPIFLASH_SECTORSIZE + 1;
		SetLastLogEndAddr(wAddr + wLen);
		for(int i = 0; i < DelSectorNum; i++) {
			SpiFlashEraseSector(DelOffsetAddr);
			DelOffsetAddr += SPIFLASH_SECTORSIZE;
		}
		if(DelOffsetAddr == SPIFLASH_SIZE) {
			DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
		}
		FindFirstLogAddr = DelOffsetAddr;
	}
	
	if(!ReadLoopSavFlag())
		return;
	
	uint32_t ReadAddr = FindFirstLogAddr;
	while(1) {
		SpiFlashReadAnyLengthData(LogBuff, ReadAddr, LOG_SAV_SIZE_MAX);
		int i;
		for(i = 0; i <= LOG_SAV_SIZE_MAX - 4; i++) {
			if(memcmp(&LogBuff[i], SavFlag, 4) == 0) {
				SetFirstLogStartAddr(ReadAddr + i);
				return;;
			}
		}
		if(i == LOG_SAV_SIZE_MAX) {
			ReadAddr += LOG_SAV_SIZE_MAX;
			if(ReadAddr >= SPIFLASH_SIZE) {		//找不到下一条数据，重置flash
				Debug_Printf("Add LOG Error, Next Data No Find!\r\n");
				SetLogNum(0);
				SetLoopSavFlag(0);
				SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
				SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
				return;
			}
		}
	}
}

uint8_t LogBuffTemp[LOG_SAV_SIZE_MAX];
void AddLog(uint8_t *wData, uint32_t wLen)
{
	//const uint8_t SavFlag[4] ={0xAA, 0x55, 0x55, 0xAA};
	uint32_t LogNum;
	uint32_t LogSize;
	//uint32_t FLStartAddr;
	uint32_t LLEndAddr;
//	uint32_t SectorN;
	LogHeader LogH;
	
	LogH = (LogHeader)LogBuffTemp;
	
	LogNum = ReadLogNum();
	if(LogNum == 0) {
		SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
		SpiFlashEraseSector(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
	}
	//FLStartAddr = ReadFirstLogStartAddr();
	LLEndAddr = ReadLastLogEndAddr();
	LogNum++;
	LogH->LogSavFlag = LOG_SAV_FLAG;
	LogH->LogIdx = LogNum;
	LogSize = wLen + sizeof(LogHeader_t);
	LogH->LogEndAddr = LLEndAddr + LogSize;
	LogH->TimeStamp = TimeTs();
	memcpy(&LogBuffTemp[sizeof(LogHeader_t)], wData, wLen);
	
	//判断是否跨扇区，跨扇区需要先擦除下一扇区
	CheckDelSecter(LLEndAddr, LogSize);
	if(LogH->LogEndAddr > SPIFLASH_SIZE) {
		LLEndAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
		LogH->LogEndAddr = ReadLastLogEndAddr();
	}
	SpiFlashWriteAnyLengthData(LogBuffTemp, LLEndAddr, LogSize);
		
	SavLogNum(LogNum);
	//Debug_Printf("Add LOG: %d,endaddr = %d\r\n", LogNum, ReadLastLogEndAddr());
}


/*****************************************************************************************
* 函数名称: ReadLog
* 功能描述: 读取日志
* 参    数: Header, 上一包日志头信息，连续读取时传入上一包数据信息，缩短日志遍历时间，
										Header->LogEndAddr为0读取第一包数据,LogIdx数据无效
						rData, 日志出口，需要释放
						LogIdx, 读取的日志的序号，为0读取Header->LogEndAddr对应日志
* 返 回 值: 返回数据长度
*****************************************************************************************/
int ReadLog(LogHeader Header, uint8_t **rData, uint32_t LogIdx)
{	
	uint32_t FSAddr;
	int LogLen = 0;
	//bool FirstIdx = false;
	
	if(Header == NULL)
		return 0;
	
	if(Header->LogEndAddr == 0) {
		Header->LogEndAddr = ReadFirstLogStartAddr();
		LogIdx = 0;
	}
	
	if(LogIdx == 1) {
		FSAddr = ReadFirstLogStartAddr();
	}
	else
		FSAddr = Header->LogEndAddr;
	
	while(1) {
		SpiFlashReadAnyLengthData((uint8_t *)Header, FSAddr, sizeof(LogHeader_t));
		if(Header->LogSavFlag != LOG_SAV_FLAG) {
			if((SPIFLASH_SIZE - FSAddr) < LOG_SAV_SIZE_MAX)	{	//判断是否到片尾
				FSAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTOR_NUM;
				continue;
			}
			else 
				return 0;
		}
		if(LogIdx == 0) {
			LogIdx = Header->LogIdx;
		}
		else if(Header->LogIdx != LogIdx) {
			FSAddr = Header->LogEndAddr;
			continue;
		}

		if(Header->LogIdx == LogIdx) {
			if(*rData == NULL)
				return sizeof(LogHeader_t);
				
			SpiFlashReadAnyLengthData(LogBuffTemp, FSAddr, Header->LogEndAddr - FSAddr);
			LogLen = Header->LogEndAddr - FSAddr - sizeof(LogHeader_t);
			void *pTemp  = rt_malloc(LogLen);
			if(pTemp == NULL)
				return 0;
			
			*rData =pTemp;
			memcpy(*rData, &LogBuffTemp[sizeof(LogHeader_t)], LogLen);
			break;
		}
	}
	return LogLen;
}


/*****************************************************************************************
* 函数名称: ReadPara
* 功能描述: 读取参数
* 参    数: Para, 网关参数
						ParaLen, 参数长度
* 返 回 值: 无
*****************************************************************************************/
int ReadPara(uint8_t *Para, uint32_t ParaLen)
{	
	SpiFlashReadAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen);		//读取片尾数据
	uint16_t Check = CRC_Modbus(0xA001, Para, ParaLen - 2);
	GWConfigPara CfgPara = (GWConfigPara)Para;
	if(CfgPara->crc16 != Check)
		return -1;
	return 0;
}

/*****************************************************************************************
* 函数名称: WritePara
* 功能描述: 写入参数
* 参    数: Para, 网关参数
						ParaLen, 参数长度
* 返 回 值: 无
*****************************************************************************************/
int WritePara(uint8_t *Para, uint32_t ParaLen)
{	
	SpiFlashEraseSector(GATEWEY_PARA_SAV_ADDR);
	
	uint16_t Check = CRC_Modbus(0xA001, Para, ParaLen - 2);
	GWConfigPara CfgPara = (GWConfigPara)Para;
	CfgPara->crc16 = Check;
	SpiFlashWriteAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen);		//读取片尾数据
	return 0;
}

/* USER CODE END */
