#include "gd32f30x.h"
#include "gd32_flash.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
/*
 *gd32f307RCT6的flash内存总共有256K的空间现在要对齐进行相应的分区
 *前30K空间用于BOOTLOADER区
 *后30K空间用于json字符串数据保存，其中前4字节保存数据长度
 *剩下空间用于正常程序
 */
#define FMC_READ(addrx) (*(volatile uint32_t *)(uint32_t)(addrx))
static void GD32_EraseFlash(uint16_t start, uint16_t num);
void GD32_WriteFlash(uint32_t saddr, uint32_t *wdata, uint32_t wnum);
/*-------------------------------------------------*/
/*函数名：保存数据到flash中                        */
/*参  数：params保存的字符串数据								   */
/*返回值：无 																			 */
/*前4个字节用于保存字符串长度后面全是字符串数据   TODO：最大长度的限制 	*/
/*-------------------------------------------------*/
int save_config_params(char *params)
{
	uint32_t paramsLen = strlen(params);
	volatile uint32_t flashDataLen = FMC_READ(FMC_WRITE_START_ADDR);
	vTaskDelay(100);	
	if (paramsLen % 4 != 0)
	{
		paramsLen = (paramsLen / 4 + 1) * 4;
	}

	if (flashDataLen != paramsLen)
	{
		GD32_EraseFlash(113,paramsLen/2048+1);
		GD32_WriteFlash(FMC_WRITE_START_ADDR, (uint32_t *)&paramsLen, 4);
		GD32_WriteFlash(FMC_WRITE_START_ADDR + 4, (uint32_t *)params, paramsLen);
		return 1;
	}
	for (int i = 1; i < paramsLen / 4; i++)
	{
		uint32_t flashWord = FMC_READ(FMC_WRITE_START_ADDR + i * 4);
		uint32_t paramsWord = *(uint32_t *)(params + (i - 1) * 4);
		vTaskDelay(100); // 解决flash速度缓慢判断错误问题
		if (flashWord != paramsWord)
		{
			GD32_EraseFlash(113,paramsLen/2048+1);
			GD32_WriteFlash(FMC_WRITE_START_ADDR + 4, (uint32_t *)params, paramsLen);
			return 1;
		}
	}
}
/*-------------------------------------------------*/
/*函数名：从flash中读出字符串数据                       */
/*参  数：params保存的字符串数据								   */
/*返回值：无 																			 */
/*前4个字节用于保存字符串长度后面全是字符串数据 	*/
/*-------------------------------------------------*/
int read_data_from_flash(void *buffer)
{
	uint32_t length = FMC_READ(FMC_WRITE_START_ADDR);
	vTaskDelay(100);
	if (length == 0xFFFFFFFF)
	{
		return -1;
	}
	for (uint32_t i = 0; i < length; i += 4)
	{
		*(uint32_t *)((uint8_t *)buffer + i) = FMC_READ(FMC_WRITE_START_ADDR + 4 + i);
		
	}
	return 0;
}

/*-------------------------------------------------*/
/*函数名：擦除FLASH                                */
/*参  数：start：擦除起始扇区   num：擦几个扇区    */
/*返回值：无                                       */
/*-------------------------------------------------*/
void GD32_EraseFlash(uint16_t start, uint16_t num)
{
	uint16_t i;

	fmc_unlock();
	for (i = 0; i < num; i++)
	{
		fmc_page_erase((0x08000000 + start * 2048) + (2048 * i));
	}
	fmc_lock();
}
/*---------------------------------------------------------------------*/
/*函数名：写入FLASH                                                    */
/*参  数：saddr：写入地址 wdata：写入数据指针  wnum：写入多少个字节    */
/*返回值：无                                                           */
/*---------------------------------------------------------------------*/
void GD32_WriteFlash(uint32_t saddr, uint32_t *wdata, uint32_t wnum)
{
	fmc_unlock();
	while (wnum > 0)
	{
		fmc_word_program(saddr, *wdata);
		wnum -= 4;
		saddr += 4;
		wdata++;
	}
	fmc_lock();
}

void gd32_flash_test()
{
	char *p = "hello,word,test/r/n";
	save_config_params(p);
	char *t=pvPortMalloc(100);
	read_data_from_flash(t);
}