
#define	_IN_NORPARAS_C
#include "norparas.h"


#if (MAX_PARA_BLOCK > 0)
#include "norflash.h"
#include "inout.h"
#include "shell.h"
#include "delay.h"

//----------------------------------------------------

#define NORPARA_BEG_ADDR			(SNF_PARAS_BEGIN)			// 参数块起始地址,每个参数块占一个扇区,最大共16个参数块

#define	NP_BLOCK_BYTES				SNF_BYTES_PER_PAGE			// 每个参数页大小(一页)
#define NP_SAVE_BYTES_PER_BLOCK		SNF_BYTES_PER_SEC			// 每个参数块大小(一个扇区)
#define NP_SAVE_BLOCKS_PER_SEC		16							// 每个参数块页数,第一页存储参数页有效标志,实际共15个页用于存储参数


#define	GET_NORPARA_BLOCK_ADDR(bidx)	(NORPARA_BEG_ADDR+(bidx)*NP_SAVE_BYTES_PER_BLOCK)	// 获取参数块起始地址

//----------------------------------------------------

typedef struct
{
	int paraEn;								// 参数块有效标志
	NorParaBlock norParaBlock;				// 参数块数据
	s32 * pParaList;						// 参数列表(包含参数类型,最小最大值和默认值)
	char * pParasName;						// 参数名称列表

	// 存储
	u32 pageFlag[NP_SAVE_BLOCKS_PER_SEC];	// 参数页标志

}NorParaBlockCtrl;

NorParaBlockCtrl g_norParaBlockList[MAX_PARA_BLOCK];

//----------------------------------------------------

const char * SHOWP_STR	=
	"\t" " 显示或加载参数 " "\r\n"
	"\t" " p1   p2" "\r\n"
	"\t" " 0    0	显示全部参数 " "\r\n"
	"\t" " b001 0	显示参数块b " "\r\n"
	"\t" " b002 0	参数块b加载默认参数 " "\r\n"
	"\t" " b003 0	参数块b重新加载参数 " "\r\n"
;

void ShowPara(char * para1, char * para2);

const char * SETP_STR =
		"\t" "设置参数 " "\r\n"
		"\t" " p1    p2" "\r\n"
		"\t" " b00x  val	设置参数块b, 参数ID x, 参数值 val " "\r\n"
		"\t" " 10b000 0		保存参数块b " "\r\n"
;

void SetPara(char * para1, char * para2);
//----------------------------------------------------

void InitNorParas(void)
{
	static int g_inited = 0;

	if (g_inited == 0)
	{
		g_inited = 1;
		InitNorSpi();			// 初始化 nor flash 访问 SPI
		SNFlashInit(SetNorSpiNssOn, SetNorSpiNssOff, NorSpiReadByte, NorSpiWriteByte);	// 初始化nor flash 并注册读写函数

		// 参数块初始化
		for(int i = 0; i < MAX_PARA_BLOCK; i++)
		{
			memset(&g_norParaBlockList[i], 0, sizeof(NorParaBlockCtrl));
			LoadNorParas(i);
		}
		AddShellCmd("SHOWPARA", SHOWP_STR, ShowPara);
		AddShellCmd("SETPARA", SETP_STR, SetPara);
	}
}

// 获取参数块有效标志
int GetNorParaEn(int bIdx)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}

	return g_norParaBlockList[bIdx].paraEn;
}

// 加载参数页有效标志
int LoadParaPageFlag(int bIdx)
{
	NorParaBlockCtrl * pCtrl;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}
	pCtrl = &g_norParaBlockList[bIdx];

	return DatFlashRdData(GET_NORPARA_BLOCK_ADDR(bIdx), (u8 *)(&pCtrl->pageFlag[0]), NP_SAVE_BLOCKS_PER_SEC*sizeof(u32));
}

// 保存参数页有效标志
int SaveParaPageFlag(int bIdx)
{
	NorParaBlockCtrl * pCtrl;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}
	pCtrl = &g_norParaBlockList[bIdx];

	return DatFlashWrData(GET_NORPARA_BLOCK_ADDR(bIdx), (u8 *)(&pCtrl->pageFlag[0]), NP_SAVE_BLOCKS_PER_SEC*sizeof(u32));
}

// 设置参数页有效标志
int SetParaPageFlagValue(int bIdx, int pIdx, int enFlag)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK || pIdx < 0 || pIdx >= NP_SAVE_BLOCKS_PER_SEC)
	{
		return -1;
	}

	if (enFlag == 0)
	{
		g_norParaBlockList[bIdx].pageFlag[pIdx] = 0;	// 失效,0xffffffff未使用页
	}
	else
	{
		g_norParaBlockList[bIdx].pageFlag[pIdx] = PARA_VALID+pIdx;	// 有效
	}

	return 0;
}

// 从参数页标志得到当前有效参数页
int GetSaveIdxFromPageFlag(int bIdx)
{
	int i;
	NorParaBlockCtrl * pCtrl;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}

	pCtrl = &g_norParaBlockList[bIdx];

	for(i = 1; i < NP_SAVE_BLOCKS_PER_SEC; i++)
	{
		if (pCtrl->pageFlag[i] == PARA_VALID+i)
		{
			return i;
		}
	}

	return -2;
}

// 得到下一个未使用页
int GetNextSaveIdxFromPageFlag(int bIdx)
{
	int i;
	NorParaBlockCtrl * pCtrl;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}

	pCtrl = &g_norParaBlockList[bIdx];

	for (i = 1; i < NP_SAVE_BLOCKS_PER_SEC; i++)
	{
		if (pCtrl->pageFlag[i] == 0xffffffff)
		{
			return i;
		}
	}

	return -2;
}

// 读取参数
// bIdx:参数块ID
// return: -1:参数加载错误,所有参数页都被废弃,未找到有效参数
//		    0:正确返回值
int LoadNorParas(int bIdx)
{
	u32 addr;			//
	NorParaBlockCtrl * pCtrl;
	int idx, rslt;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}

	pCtrl = &g_norParaBlockList[bIdx];

	memset(pCtrl, 0, sizeof(NorParaBlockCtrl));

	// 读入扇区存储参数有效标志
	rslt = LoadParaPageFlag(bIdx);
	if (rslt < 0)
	{
		return -1;
	}

	idx = GetSaveIdxFromPageFlag(bIdx);		// 得到当前有效参数页id

	if (idx < 0)
	{
		printf("load nor para error, code=%d\r\n", idx);
		return -1;
	}

	printf("load nor para block %d, page is %d\r\n", bIdx, idx);

	addr = GET_NORPARA_BLOCK_ADDR(bIdx) + (idx * NP_BLOCK_BYTES);
	DatFlashRdData(addr, (u8*)&pCtrl->norParaBlock, sizeof(NorParaBlock));

	g_norParaBlockList[bIdx].paraEn = PARA_VALID;						// 参数有效

	return 0;
}

// 保存参数
//bIdx 定义的参数块ID
int SaveNorParas(int bIdx)
{
	u32 addr;
	int cidx, nidx;

	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return -1;
	}

	cidx = GetSaveIdxFromPageFlag(bIdx);
	nidx = GetNextSaveIdxFromPageFlag(bIdx);
	if (cidx < 0)
	{
		cidx = 0;
	}

	if (nidx < 0)		// 超出扇区
	{
		printf("overflow, erase 4k\r\n");
		DatFlash4kErase(GET_NORPARA_BLOCK_ADDR(bIdx), 1);		// 擦除整个扇区
		LoadParaPageFlag(bIdx);
		cidx = 0;
		nidx = GetNextSaveIdxFromPageFlag(bIdx);
	}

	if (nidx < 0)		//
	{
		printf("SaveNorParas error\r\n");
		return -2;
	}

	// 将参数存储在之后的页中
	addr = GET_NORPARA_BLOCK_ADDR(bIdx) + ((nidx) * NP_BLOCK_BYTES);
	DatFlashWrDataWithErase(addr, (u8 *)&g_norParaBlockList[bIdx].norParaBlock, sizeof(NorParaBlock));

	SetParaPageFlagValue(bIdx, nidx, 1);	// 设置新参数存储页有效

	SetParaPageFlagValue(bIdx, cidx, 0);	// 废弃旧的参数存储页

	SaveParaPageFlag(bIdx);		// 保存参数页标志

	g_norParaBlockList[bIdx].paraEn = PARA_VALID;						// 参数有效

	printf("save nor para successful, page is %d \r\n", nidx);

	return 0;
}


// 获取并返回参数块
NorParaBlock * GetNorParaBlock(int bIdx)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK)
	{
		return NULL;
	}

	return &g_norParaBlockList[bIdx].norParaBlock;
}

// 设置参数名称
void SetNorParaNameString(int bIdx, void * pName)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK	)
	{
		return;
	}

	g_norParaBlockList[bIdx].pParasName = pName;
}

// 设置参数列表(参数类型,最小最大值默认值)
void SetNorParaList(int bIdx, void * pPara)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK	)
	{
		return;
	}

	g_norParaBlockList[bIdx].pParaList = pPara;
}

// 加载默认参数
void LoadNorDefPara(int bIdx)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK || g_norParaBlockList[bIdx].pParaList == NULL)
	{
		return;
	}

	for(int i = 0; i < PARA_NUM_PER_BLK; i++)
	{
		int offset = i * 4 + 3;
		g_norParaBlockList[bIdx].norParaBlock.buff[i] = * ( g_norParaBlockList[bIdx].pParaList + offset );
	}
}


// 参数范围检测(检测参数块内的全部参数)
void CheckParaRange(int bIdx)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK || g_norParaBlockList[bIdx].pParaList == NULL)
	{
		return;
	}

	for(int i = 0; i < PARA_NUM_PER_BLK; i++)
	{
		int paratype, minOffset, maxOffset;		// 参数类型,最小最大值指针偏移量
		paratype = (i * 4);
		minOffset = (i * 4 + 1);
		maxOffset = (i * 4 + 2);
		if ((*(g_norParaBlockList[bIdx].pParaList + paratype)) == PTYPE_S)
		{
			if (g_norParaBlockList[bIdx].norParaBlock.buff[i] < (*(g_norParaBlockList[bIdx].pParaList + minOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[i] = (*( g_norParaBlockList[bIdx].pParaList + minOffset));
				printf("less than min, equal min, block %d, id is %d\r\n", bIdx, i+1);
			}
			else if (g_norParaBlockList[bIdx].norParaBlock.buff[i] > (*( g_norParaBlockList[bIdx].pParaList + maxOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[i] = (*( g_norParaBlockList[bIdx].pParaList + maxOffset));
				printf("more than max, equal max, block %d, id is %d\r\n", bIdx, i+1);
			}
		}
		else if ((*(g_norParaBlockList[bIdx].pParaList + paratype)) == PTYPE_U)
		{
			if ((u32)g_norParaBlockList[bIdx].norParaBlock.buff[i] < (u32)(*(g_norParaBlockList[bIdx].pParaList + minOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[i] = (*( g_norParaBlockList[bIdx].pParaList + minOffset));
				printf("less than min, equal min, block %d, id is %d\r\n", bIdx, i+1);
			}
			else if ((u32)g_norParaBlockList[bIdx].norParaBlock.buff[i] > (u32)(*( g_norParaBlockList[bIdx].pParaList + maxOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[i] = (*( g_norParaBlockList[bIdx].pParaList + maxOffset));
				printf("more than max, equal max, block %d, id is %d\r\n", bIdx, i+1);
			}
		}
	}
}


// 参数范围检测(检测参数块内的某个参数)
void CheckAParaRange(int bIdx, int id)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK || g_norParaBlockList[bIdx].pParaList == NULL)
	{
		return;
	}

	if (id >= 0 && id < PARA_NUM_PER_BLK)
	{
		int paratype, minOffset, maxOffset;		// 参数类型,最小最大值指针偏移量
		paratype = (id * 4);
		minOffset = (id * 4 + 1);
		maxOffset = (id * 4 + 2);
		if ((*(g_norParaBlockList[bIdx].pParaList + paratype)) == PTYPE_S)
		{
			if (g_norParaBlockList[bIdx].norParaBlock.buff[id] < (*( g_norParaBlockList[bIdx].pParaList + minOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[id] = (*( g_norParaBlockList[bIdx].pParaList + minOffset));
				printf("less than min, equal min\r\n");
			}
			else if (g_norParaBlockList[bIdx].norParaBlock.buff[id] > (*( g_norParaBlockList[bIdx].pParaList + maxOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[id] = (*( g_norParaBlockList[bIdx].pParaList + maxOffset));
				printf("more than max, equal max\r\n");
			}
		}
		else if ((*(g_norParaBlockList[bIdx].pParaList + paratype)) == PTYPE_U)
		{
			if ((u32)g_norParaBlockList[bIdx].norParaBlock.buff[id] < (u32)(*( g_norParaBlockList[bIdx].pParaList + minOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[id] = (*( g_norParaBlockList[bIdx].pParaList + minOffset));
				printf("less than min, equal min\r\n");
			}
			else if ((u32)g_norParaBlockList[bIdx].norParaBlock.buff[id] > (u32)(*( g_norParaBlockList[bIdx].pParaList + maxOffset)) )
			{
				g_norParaBlockList[bIdx].norParaBlock.buff[id] = (*( g_norParaBlockList[bIdx].pParaList + maxOffset));
				printf("more than max, equal max\r\n");
			}
		}
	}
}


// 获取一个参数
s32 GetANorPara(int bIdx, int id)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK	)
	{
		return -1;
	}

	if (GetNorParaEn(bIdx) == PARA_VALID)
	{
		int idx = id - 1;

		if (idx >= 0 && idx < PARA_NUM_PER_BLK)
		{
			return g_norParaBlockList[bIdx].norParaBlock.buff[idx];
		}
	}
	return 0;
}

// 设置一个参数
// 该函数不提供保存功能,需参数设置完成后手动保存
// 注:norflash不宜频繁写
void SetANorPara(int bIdx, int id, s32 val)
{
	if (bIdx < 0 || bIdx >= MAX_PARA_BLOCK	)
	{
		return;
	}

	char * pInfo = NULL;
	int idx = id - 1;

	if (idx >= 0 && idx < PARA_NUM_PER_BLK)
	{
		if ((*(g_norParaBlockList[bIdx].pParaList + idx*4)) == PTYPE_S)
		{
			s32 old;

			pInfo = (g_norParaBlockList[bIdx].pParasName+(idx)*PARA_STR_LEN);

			printf("set para block %d\r\n", bIdx+1);

			old = g_norParaBlockList[bIdx].norParaBlock.buff[idx];
			g_norParaBlockList[bIdx].norParaBlock.buff[idx] = val;

			CheckAParaRange(bIdx, idx);

			if (pInfo == NULL)
			{
				pInfo = "";
			}

			printf("%d. (%s) = %d, oldvalue=%d\r\n", (id), pInfo, val, old);
		}
		else
		{
			u32 old;

			pInfo = (g_norParaBlockList[bIdx].pParasName+(idx)*PARA_STR_LEN);

			printf("set para block %d\r\n", bIdx+1);

			old = (u32)g_norParaBlockList[bIdx].norParaBlock.buff[idx];
			g_norParaBlockList[bIdx].norParaBlock.buff[idx] = val;

			CheckAParaRange(bIdx, idx);

			if (pInfo == NULL)
			{
				pInfo = "";
			}

			printf("%d. (%s) = %d, oldvalue=%d\r\n", (id), pInfo, (u32)val, old);
		}
	}
}


/*
 * 		p1				p2
 * 		1001			val				// 设置参数块1,参数ID 1,参数值val
 * 		1002			val				// 设置参数块1,参数ID 2,参数值val
		......
 * 		2001			val				// 设置参数块2,参数ID 1,参数值val
 * 		2002			val				// 设置参数块2,参数ID 2,参数值val		//不提供保存功能
		......
 * 		101000							// 保存参数块1
 * 		102000							// 保存参数块2
 */

void SetPara(char * para1, char * para2)
{
	int p1, p2, p3;

	if (para1 == NULL || para2 == NULL)
	{
		return;
	}

	printf("para1=%s, para2=%s\r\n", para1, para2);

	p1 = 0;
	p2 = 0;
	if (strcmp(para1, "") != 0)
	{
		p1 = atoi(para1);
	}
	if (strcmp(para2, "") != 0)
	{
		p2 = atoi(para2);
	}
	if (p1 == p2)
	{
	}

	p3 = p1 / 1000;			// 参数块id
	p1 = p1 % 1000;			// 参数id
							// p2:参数值

	if (p3 > 0 && p3 <= MAX_PARA_BLOCK)
	{
		SetANorPara(p3-1, p1, p2);
	}
	else if (p3 > 100 && p3 <= 116)
	{
		p3 -= 101;
		printf("save block %d\r\n", p3+1);
		SaveNorParas(p3);
	}
}

/*
 * 		p1			p2
 * 								// 显示全部参数
 * 		1001					// 显示参数块1
 * 		2001					// 显示参数块2
 * 		1002					// 参数块1加载默认参数
 * 		2002					// 参数块2加载默认参数
 * 		1003					// 参数块1重新加载参数
 * 		2003					// 参数块2重新加载参数
 */
void ShowPara(char * para1, char * para2)
{
	int p1, p2, p3;

	if (para1 == NULL || para2 == NULL)
	{
		return;
	}

	printf("para1=%s, para2=%s\r\n", para1, para2);

	p1 = 0;
	p2 = 0;
	if (strcmp(para1, "") != 0)
	{
		p1 = atoi(para1);
	}
	if (strcmp(para2, "") != 0)
	{
		p2 = atoi(para2);
	}
	if (p1 == p2)
	{
	}
	p3 = p1 / 1000;			// 参数块id
	p1 = p1 % 1000;			// 功能码
							// p2: 参数ID

	if (p3 <= MAX_PARA_BLOCK)
	{
		switch(p1)
		{
			case 0:
			{
				// 显示全部块参数
				for (int j = 0; j < MAX_PARA_BLOCK; j++)
				{
					printf("\r\npara block %d:\r\n", j+1);

					if (g_norParaBlockList[j].pParasName == NULL)
					{
						continue;
					}

					for(int i = 0; i < PARA_NUM_PER_BLK; i++)
					{
						char * pStr;
						pStr = g_norParaBlockList[j].pParasName + (i*PARA_STR_LEN);
						if (pStr == NULL)
						{
							pStr = "";
						}

						if ( strcmp(pStr, "") != 0 )
						{
							if ((*(g_norParaBlockList[j].pParaList+i*4)) == PTYPE_S)
							{
								printf("%d. (%s) val=%d, min=%d, max=%d, def=%d\r\n", i+1, pStr,
										GetANorPara(j, i+1),
										*(g_norParaBlockList[j].pParaList+ i*4+1),
										*(g_norParaBlockList[j].pParaList+ i*4+2),
										*(g_norParaBlockList[j].pParaList+ i*4+3)   );
							}
							else
							{
								printf("%d. (%s) val=%d, min=%d, max=%d, def=%d\r\n", i+1, pStr,
										(u32)GetANorPara(j, i+1),
										(u32)(*(g_norParaBlockList[j].pParaList+ i*4+1)),
										(u32)(*(g_norParaBlockList[j].pParaList+ i*4+2)),
										(u32)(*(g_norParaBlockList[j].pParaList+ i*4+3))  );
							}
						}
						DelayMs(1);
					}
				}
				break;
			}
			case 1:
			{
				// 显示某个参数块
				printf("\r\npara block %d:\r\n", p3);

				if (g_norParaBlockList[p3-1].pParasName != NULL)
				{
					for(int i = 0; i < PARA_NUM_PER_BLK; i++)
					{
						char * pStr;
						pStr = g_norParaBlockList[p3-1].pParasName + (i*PARA_STR_LEN);
						if (pStr == NULL)
						{
							pStr = "";
						}

						if ( strcmp(pStr, "") != 0 )
						{
							if ((*(g_norParaBlockList[j].pParaList+i*4)) == PTYPE_S)
							{
								printf("%d. (%s) val=%d, min=%d, max=%d, def=%d\r\n", i+1, pStr,
										GetANorPara(p3-1, i+1),
										*(g_norParaBlockList[p3-1].pParaList+ i*4+1),
										*(g_norParaBlockList[p3-1].pParaList+ i*4+2),
										*(g_norParaBlockList[p3-1].pParaList+ i*4+3)   );
							}
							else
							{
								printf("%d. (%s) val=%d, min=%d, max=%d, def=%d\r\n", i+1, pStr,
										(u32)GetANorPara(p3-1, i+1),
										(u32)(*(g_norParaBlockList[p3-1].pParaList+ i*4+1)),
										(u32)(*(g_norParaBlockList[p3-1].pParaList+ i*4+2)),
										(u32)(*(g_norParaBlockList[p3-1].pParaList+ i*4+3))  );
							}
						}
						DelayMs(1);
					}
				}
				break;
			}
			case 2:
			{
				int bidx = p3 - 1;
				// 加载默认参数
				if (bidx >= 0)
				{
					printf("load def para block %d:\r\n", p3);
					LoadNorDefPara(bidx);
				}
				break;
			}
			case 3:
			{
				int bidx = p3 - 1;
				if (bidx >= 0)
				{
					printf("load para block %d:\r\n", p3);
					// 重新加载参数
					LoadNorParas(bidx);
				}
				break;
			}
			default:
				break;
		}
	}
}

#endif

