optical/EMBOS/Users/EmbFunc/security/installment.c
2025-09-04 09:45:08 +08:00

606 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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();
}
}
}