
#include "installment.h"
#include "password.h"
#include "fram.h"
#include "paras.h"
#include "cpuid.h"
#include "shell.h"
#include "trigger.h"

/*



*/
//-------------------------------------------------------------------------------

u32 GetRTCSecond(void)
{
//	RTC_GetCounter
//	LL_RTC_TIME_GetSecond
	return 0;
}

//-------------------------------------------------------------------------------
#define	INS_SIZE	64

typedef struct
{
	// 0
	u8 curmc;				// 当前机型,CUR_MACHINE
	u16 mctype;				// 机器类型,MC_TYPE

	u8 clientId;			// 客户代码
	u32 cpuId;

	// 8
	u8 lastpswd[24];		// 旧密码

	// 32
	s32 workableTimer;		// 可工作时间计数器，剩余时间计数（分钟为单位）
	u32 rtcSecondTimer;		// 实时时钟计数
	// 40
	u8 rev[INS_SIZE - 4 - 40];
	u32 encount;			// 写入有效计数器
} __attribute__ ((packed)) Installment;


#define	UNLOCK_COUNTER_MIN	(S32_MAX - S16_MAX - U16_MAX)	// 全解计数（大于此数均为全解）
#define	UNLOCK_COUNTER_MAX	(S32_MAX)

#define	UNLOCK_COUNTER		(UNLOCK_COUNTER_MIN+S16_MAX + (S16_MAX)/2)			// 默认全解计数


//-------------------------------------------------------------------------------
Installment g_installment;
int g_instsel = -1;


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

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

void ResetInstall(void);


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

// 初始化
int InitInstallment(void)
{
	int rslt;
	u32 cpuid;
	Installment tmpinstall1, tmpinstall2;
	rslt = 0;

	if (g_instsel >= 0)
	{
		return 0;
	}

	cpuid = 0;
	{
		CpuId id;
		GetCpuID(&id);
		cpuid += id.dword.dword1;
		cpuid += id.dword.dword2;
		cpuid += id.dword.dword3;
		cpuid += id.dword.dword4;
	}

	memset(&g_installment, 0, sizeof(Installment));

	// 确定哪个是有效的
	ReadFramData(ENC_ADDR, (u8*)&tmpinstall1, sizeof(Installment));
	ReadFramData(ENC_ADDR+INS_SIZE, (u8*)&tmpinstall2, sizeof(Installment));

	if (1	&&
		tmpinstall1.curmc == CUR_MACHINE		&&
		tmpinstall1.mctype == MC_TYPE			&&
		tmpinstall1.clientId == CUR_CLINET	&&
		tmpinstall1.cpuId == cpuid			&&
		1	)
	{
		if (1	&&
			tmpinstall2.curmc == CUR_MACHINE		&&
			tmpinstall2.mctype == MC_TYPE			&&
			tmpinstall2.clientId == CUR_CLINET	&&
			tmpinstall2.cpuId == cpuid			&&
			1	)
		{
			if (tmpinstall2.encount > tmpinstall1.encount)
			{
				g_instsel = 1;
			}
			else
			{
				g_instsel = 0;
			}
		}
		else
		{
			g_instsel = 0;
			// 将有效的写入无效的缓冲区
			WriteFramData(ENC_ADDR+INS_SIZE, (u8*)&tmpinstall1, sizeof(Installment));
		}
	}
	else
	{
		if (1	&&
			tmpinstall2.curmc == CUR_MACHINE		&&
			tmpinstall2.mctype == MC_TYPE			&&
			tmpinstall2.clientId == CUR_CLINET	&&
			tmpinstall2.cpuId == cpuid			&&
			1	)
		{
			g_instsel = 1;

			// 将有效的写入无效的缓冲区
			WriteFramData(ENC_ADDR, (u8*)&tmpinstall2, sizeof(Installment));
		}
		else
		{
			// 两个都无效
		}
	}

	if (g_instsel < 0)
	{
		ResetInstall();
	}

	// 重新读入
	if (g_instsel == 0)
	{
		printf("load enc 0\r\n");
		ReadFramData(ENC_ADDR, (u8*)&g_installment, sizeof(Installment));
	}
	else if (g_instsel == 1)
	{
		printf("load enc 1\r\n");
		ReadFramData(ENC_ADDR+INS_SIZE, (u8*)&g_installment, sizeof(Installment));
	}
	else
	{
		printf("load enc error\r\n");
	}

	if (0	||
		g_installment.curmc != CUR_MACHINE		||
		g_installment.mctype != MC_TYPE			||
		g_installment.clientId != CUR_CLINET	||
		g_installment.cpuId != cpuid			||
		0	)
	{
		printf("reload enc error\r\n");
		ResetInstall();
	}
	else
	{
		// 解码验证
		int rslt = -1;
		PswdCtrl pswdctrl;
		rslt = DecodePswdString(&pswdctrl, (char*)(g_installment.lastpswd), g_installment.clientId);	// 解码
		if (rslt < 0)
		{
			printf("DecodePswdString error, reset ResetInstall\r\n");
			// 保存的密码不正确, 或者是没有设置过密码
			ResetInstall();
		}
		else
		{
			if (pswdctrl.clientId == g_installment.clientId &&
				pswdctrl.cpuId == g_installment.cpuId &&
				1	)
			{
				s32 thishours = pswdctrl.thishours;

				if (thishours >= UNLOCK_MIN && thishours <= UNLOCK_MAX)
				{
					// 全解
					g_installment.workableTimer = UNLOCK_COUNTER;		// 设置为最大计数
				}
				else if (thishours < 0)
				{
					thishours *= -1;
					if (thishours >= LOCK_MIN && thishours <= LOCK_MAX)
					{
						g_installment.workableTimer = 0;	// 全部锁定
					}
				}
			}
			else
			{
				printf("clientId or cpuId not equ, reset ResetInstall\r\n");
				ResetInstall();
			}
		}
	}

	// 改变关电过程中的时间
	if (g_installment.workableTimer < UNLOCK_COUNTER_MIN)		// 有使用限制情况下
	{
		u32 temp;
		temp = GetRTCSecond();		// 读取现在RTC的值
		if (temp >= g_installment.rtcSecondTimer)
		{
			temp -= g_installment.rtcSecondTimer;

			printf("rtc record, close time=%u sec\r\n", temp);

			temp /= 60;		// 关机分钟数
			temp++;			// 至少减去1分钟

			g_installment.workableTimer -= temp;

			if (g_installment.workableTimer < 0)
			{
				g_installment.workableTimer = 0;
			}

			if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN)
			{
				g_installment.workableTimer = UNLOCK_COUNTER_MIN-1;
			}

			rslt = temp - 1;
		}
		else
		{
			printf("rtc reset\r\n");
			// 可能是电池掉电, rtc 复位
		}
	}

	g_installment.rtcSecondTimer = GetRTCSecond();	// 读取现在RTC的值，重新记录

	AddShellCmd("INS", "Install function", TestInstall);
	return rslt;
}


void ResetInstall()
{
	Installment tmpinstall;

	u32 cpuid;
	cpuid = 0;
	{
		CpuId id;
		GetCpuID(&id);
		cpuid += id.dword.dword1;
		cpuid += id.dword.dword2;
		cpuid += id.dword.dword3;
		cpuid += id.dword.dword4;
	}

	// 初始化两个缓冲区
	memset(&tmpinstall, 0, sizeof(Installment));

	tmpinstall.curmc = CUR_MACHINE;
	tmpinstall.mctype = MC_TYPE;
	tmpinstall.clientId = CUR_CLINET;
	tmpinstall.cpuId = cpuid;
	tmpinstall.encount = 100;
	tmpinstall.workableTimer = 0;		// 允许工作时间为0
	tmpinstall.rtcSecondTimer = GetRTCSecond();	// 读取现在RTC的值

	WriteFramData(ENC_ADDR, (u8*)&tmpinstall, sizeof(Installment));
	WriteFramData(ENC_ADDR+INS_SIZE, (u8*)&tmpinstall, sizeof(Installment));
	g_instsel = 0;
	printf("ResetInstall\r\n");
}

int SetInstallMent(char * pPswdStr)
{
	int rslt = -1;
	PswdCtrl pswdctrl;

	ChangeToUper(pPswdStr);		// 转换为大写

	do
	{
		if (g_instsel >= 0)
		{
			rslt = DecodePswdString(&pswdctrl, pPswdStr, g_installment.clientId);	// 解码
			if (rslt >= 0)
			{
				// 6. 验证客户识别码和主板识别码是否符合当前设备。
				if (pswdctrl.clientId == g_installment.clientId &&
					pswdctrl.cpuId == g_installment.cpuId &&
					1	)
				{
					PswdCtrl oldctrl;

					if (g_installment.lastpswd[0] != 0)		// 非第一次设置
					{
						rslt = DecodePswdString(&oldctrl, (char*)(g_installment.lastpswd), g_installment.clientId);	// 解码上次密码
						if (rslt < 0)
						{
							break;
						}
					}
					else
					{
						if (pswdctrl.totaltime >= 0 && pswdctrl.totaltime < TIME_MUTI)
						{
							oldctrl.nexttotaltime = pswdctrl.totaltime;
						}
						else
						{
							rslt = -1;		// 设置不成功
							break;
						}
					}

					// 7.验证上次加密累计时间是否和板卡保存的一致（按小时数验证）。
					if (pswdctrl.totaltime == oldctrl.nexttotaltime)
					{
						// 8.将新的改变时间加到当前计数时间，并写入计数区域。
						s32 thishours = pswdctrl.thishours;

						if (thishours >= NORMAL_MIN && thishours <= NORMAL_MAX)		// 本次是增加时间或新设置加密
						{
							if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN || 	// 上次是全解
								g_installment.workableTimer < 0				)			// 上次是锁定
							{
								g_installment.workableTimer = thishours*60;		// 重置为加密状态
							}
							else
							{
								g_installment.workableTimer += thishours*60;	// 增加时间
								if (g_installment.workableTimer < 0)
								{
									g_installment.workableTimer = 0;
								}
								if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN)
								{
									g_installment.workableTimer = UNLOCK_COUNTER_MIN-1;
								}
							}
						}
						else if (thishours >= UNLOCK_MIN && thishours <= UNLOCK_MAX)	// 本次是全解
						{
							// 全解
							g_installment.workableTimer = UNLOCK_COUNTER;		// 设置为最大计数
						}
						else if (thishours < 0)		// 本次是锁定或减少时间
						{
							thishours *= -1;
							if (thishours >= NORMAL_MIN && thishours <= NORMAL_MAX)	// 正常减少时间
							{
								if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN) 	// 上次是全解
								{
									g_installment.workableTimer = 0;	// 全部锁定
								}
								else
								{
									g_installment.workableTimer -= thishours*60;			// 减少使用时间
									if (g_installment.workableTimer < 0)
									{
										g_installment.workableTimer = 0;
									}
									if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN)
									{
										g_installment.workableTimer = UNLOCK_COUNTER_MIN-1;
									}
								}
							}
							else if (thishours >= LOCK_MIN && thishours <= LOCK_MAX)
							{
								g_installment.workableTimer = 0;	// 全部锁定
							}
							else
							{
								rslt = -1;		// 设置不成功
								break;
							}
						}
						else
						{
							rslt = -1;			// 设置不成功
							break;
						}

						// 9.保存密码串到记录区域。
						memcpy(g_installment.lastpswd, pPswdStr, PSWDSTR_LEN);
						g_installment.lastpswd[PSWDSTR_LEN] = 0;
						RefWorkableTimer(0);
						rslt = 0;
						break;
					}
					else
					{
						rslt = -1;
						break;
					}
				}
				else
				{
					rslt = -1;
					break;
				}
			}
		}
	}while(0);


	return rslt;
}

// 得到剩余工作时长，单位为分钟
int GetWorkableTime(void)
{
	if (g_instsel >= 0)
	{
		return g_installment.workableTimer;
	}
	else
	{
		return 0;
	}
}


// 更新计数器，单位为分钟
int RefWorkableTimer(s32 val)
{
	if (g_instsel < 0)
	{
		g_installment.workableTimer = 0;
	}
	else
	{
		g_installment.rtcSecondTimer = GetRTCSecond();	// 每隔1分钟，记录rtc的计数值

		/*
		 * 20221024 ljs++
		 * 因界面计算错误,个别情况下所发送的关机时间错误
		 * 命令代码UCMD_SET_ELAPSED_TIME
		 * 例如,在全解的情况下发送关机时间5000小时,实际并没有关机,只是主控进行了重启
		 * 所造成的由无时间限制变成了有时间限制,甚至密码到期
		 * 为解决此问题,增加if条件判断
		 * 在全解的情况下,不更新计数器
		 */
		if (g_installment.workableTimer < UNLOCK_COUNTER_MIN)	// 非全解的情况下
		{
			g_installment.workableTimer += val;
		}

		if (g_installment.workableTimer < 0)
		{
			g_installment.workableTimer = 0;
		}
		else if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN)
		{
			g_installment.workableTimer = UNLOCK_COUNTER;
		}

		g_installment.encount++;
		if (g_instsel == 0)
		{
			WriteFramData(ENC_ADDR+INS_SIZE, (u8*)&g_installment, sizeof(Installment));
			g_instsel = 1;
		}
		else
		{
			WriteFramData(ENC_ADDR, (u8*)&g_installment, sizeof(Installment));
			g_instsel = 0;
		}
	}

#if (0)		// 调试输出
	{
		static u32 timer = 0;
		u32 gap = 0;
		u32 temp;
		temp = GetMsSoftTimer();
		if (timer == 0)
		{
			gap = 0;
		}
		else
		{
			gap = temp - timer;
		}

		timer = temp;

		printf("at %d, RefWorkableTimer, gap = %d, ",timer, gap);

		if (g_installment.workableTimer <= 0)
		{
			g_installment.workableTimer = 0;
			printf("limit use\r\n");		
		}
		else if (g_installment.workableTimer >= UNLOCK_COUNTER_MIN)
		{
			g_installment.workableTimer = UNLOCK_COUNTER;
			printf("no limit\r\n");
		}
		else
		{
			printf("change workabletimer to %d\r\n", g_installment.workableTimer);		
		}
	}
#endif

	return g_installment.workableTimer;
}

// 板卡ID信息
void GetBoardIdInfo(char * boardId)
{
	sprintf(boardId, "CPUID: %u", g_installment.cpuId);
}

// 加密字符串
void GetLastInstallment(char * installment)
{
	sprintf(installment, "LPSWD: %s", g_installment.lastpswd);
}

// 读取前一次密码
void GetLastpswd(u8 * lastpswd)
{
	memcpy(lastpswd, g_installment.lastpswd, 24);
}

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

	p1 = 0;
	p2 = 0;

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

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

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

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

	if (p1 == p2)
	{
	}

	//--------------------------------
	{
		if (p1 == 0)
		{
			char buff[32];
			GetBoardIdInfo(buff);		// 板卡ID信息
			printf("%s\r\n", buff);
			GetLastInstallment(buff);	// 加密字符串
			printf("%s\r\n", buff);

			printf("Workable = %d min\r\n", GetWorkableTime());
		}
		else if (p1 == 1)
		{
			SetInstallMent(para2);
		}
		else if (p1 == 2)
		{
			RefWorkableTimer(p2);
		}
		else if (p1 == 100)
		{
			ResetInstall();
		}
	}
}



