
#define	_IN_STAPP_C
#include "stapp.h"

#if	(APP_SAVE_TO != APP_SAVE_NONE)

#include "crc32.h"
#include "cpuid.h"
#include "stiap.h"

#include "stflash.h"

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





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

// 升级程序文件管理

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

typedef struct
{
	char xorbuf[8];
	u8 xchgbuf[8];
	u32 datalen;
	u32 bincrc;
	u32 rnpucrc;
	u32 hddatcrc;
	u8 rev[1024-8-8-8-8];
}GNPUHead;

GNPUHead g_gnpuHead =
{
#if (CUR_UPFL == GAUF_PMB1)       // 绘图仪主板
    {
        'G', 'O', 'A', 'P', 'M', 'B', 'O', 'S',
    },
    {
        4, 6, 7, 2, 3, 5, 8, 1,
    },
#elif (CUR_UPFL == GAUF_EMB1)       // 绣花机/布线机主板
    {
        'G', 'O', 'A', 'E', 'M', 'B', 'O', 'S',
    },
    {
        1, 3, 5, 2, 4, 8, 6, 7,
    },
#elif (CUR_UPFL == GAUF_EHA1)       // 平绣机头板
    {
        'G', 'O', 'A', 'E', 'H', 'A', 'O', 'S',
    },
    {
        5, 1, 3, 2, 7, 4, 8, 6,
    },
#elif (CUR_UPFL == GAUF_EHB1)       // 布线机机头板
    {
        'G', 'O', 'A', 'E', 'H', 'B', 'O', 'S',
    },
    {
        1, 5, 2, 4, 3, 7, 6, 8,
    },
#elif (CUR_UPFL == GAUF_EMCLA1)		// 平绣换色板
    {
        'G', 'O', 'A', 'E', 'C', 'L', 'A', '1',
    },
    {
        6, 1, 7, 4, 2, 5, 3, 8,
    },
#elif (CUR_UPFL == GAUF_EXTIO)		// 扩展IO板卡
#else
	{
		'R', 'P', 'U', 'P', 'D', 'A', 'T', 'E',
	},
	{
		1, 2, 3, 4, 5, 6, 7, 8,
	},
#endif
	0, 0, 0, 0, 
	{
		0,
	},
};

// 解码RNPU数据
int DecodeData(u8 * pBuf, int len)
{
	int i, j, k, num1;
	u8 tpbuf[8], opbuf[8];
	u8 temp, mod;

	if (pBuf == NULL || len == 0)
	{
		return -1;
	}

	for (i = 0; i < len && ((len - i) >= 8); i += 8)
	{
		// 每8个字节一组数据，如果不足8字节的数据，不做处理。
		memcpy(tpbuf, &(pBuf[i]), 8);

		// 根据交换表交换8个字节的顺序。
		memcpy(opbuf, tpbuf, 8);
		for (j = 0; j < 8; j++)
		{
			tpbuf[g_gnpuHead.xchgbuf[j]-1] = opbuf[j];
		}

		// 计算数组中数据位1的个数
		num1 = 0;
		for (j = 0; j < 8; j++)
		{
			mod = 0x01;
			for (k = 0; k < 8; k++)
			{
				if ((tpbuf[j] & mod) != 0)
				{
					num1++;
				}
				mod *= 2;
			}
		}

		// 根据个数的做循环移位操作（奇数右移，偶数左移）。
		if ((num1 & 0x01) != 0)		// 奇数
		{
			// 循环右移
			for (j = 0; j < num1; j++)
			{
				mod = tpbuf[7];
				for (k = 0; k < 8; k++)
				{
					temp = tpbuf[k];
					tpbuf[k] >>= 1;			// 右移
					if ((mod & 0x01) != 0)
					{
						tpbuf[k] |= 0x80;
					}
					mod = temp;
				}
			}
		}
		else						// 偶数
		{
			// 循环左移
			for (j = 0; j < num1; j++)
			{
				mod = tpbuf[0];
				for (k = 7; k >= 0; k--)
				{
					temp = tpbuf[k];
					tpbuf[k] <<= 1;			// 左移
					if ((mod & 0x80) != 0)
					{
						tpbuf[k] |= 0x01;
					}
					mod = temp;
				}
			}
		}

		// 数组数据和加密字符串做异或运算
		for (j = 0; j < 8; j++)
		{
			tpbuf[j] ^= g_gnpuHead.xorbuf[j];
		}

		// 得到最终的解密数组
		memcpy(&(pBuf[i]), tpbuf, 8);
	}

	return 0;
}

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

typedef struct
{
	int enFlag;
	int saveOffset;
	int isrnpufile;
	u32 bincrc;
	u32 rnpucrc;
	int rsvCounter;

}SaveAppCtrl;

SaveAppCtrl g_saveAppCtrl;

void InitSaveApp(void)
{
	g_gnpuHead.datalen = 0;
	g_gnpuHead.bincrc = 0;
	g_gnpuHead.rnpucrc = 0;
	g_gnpuHead.hddatcrc = 0;

	g_saveAppCtrl.saveOffset = 0;
	g_saveAppCtrl.isrnpufile = 0;

	g_saveAppCtrl.bincrc = CRC32_INIT;
	g_saveAppCtrl.rnpucrc = CRC32_INIT;
	g_saveAppCtrl.rsvCounter = 0;

	IAPCleanUpdateArea();			// 清空NORflash文件区域
}

// 保存一段数据到app区域
int SaveAppData(int idx, u8 * pBuf, int len, u32 ofst)
{
	u32 addr, wtlen;
	int i, thislen;
	//printf("SaveAppData idx=%d, len=%d, ofst=0x%x\r\n", idx, len, ofst);

	if (idx < 0 ||
		pBuf == NULL ||
		(len != SUPPORT_LEN_1 && len != SUPPORT_LEN_2) ||
		0	)
	{
		printf("SaveAppData para err\r\n");
		return -1;
	}

	// 文件头
	if (ofst == 0 && idx == 0 && g_saveAppCtrl.saveOffset < sizeof(g_gnpuHead))
	{
		if (ofst == 0 && idx == 0)
		{
			printf("process file head\r\n");

			if (memcmp(pBuf, g_gnpuHead.xorbuf, 8) == 0 &&
				memcmp(&(pBuf[8]), g_gnpuHead.xchgbuf, 8) == 0 &&
				1	)
			{
				u32 hdcrc, hddatsize;
				g_saveAppCtrl.isrnpufile = 1;
				// 填充校验
				g_saveAppCtrl.bincrc = CRC32_INIT;
				g_saveAppCtrl.rnpucrc = CRC32_INIT;

				g_gnpuHead.datalen = *((u32*)&(pBuf[16]));
				g_gnpuHead.bincrc = *((u32*)&(pBuf[20]));
				g_gnpuHead.rnpucrc = *((u32*)&(pBuf[24]));
				g_gnpuHead.hddatcrc = *((u32*)&(pBuf[28]));

				hddatsize = sizeof(g_gnpuHead) - sizeof(g_gnpuHead.rev) - 4;
				hdcrc = CalcCrc32((u8*)(&g_gnpuHead), hddatsize);

				if (hdcrc == g_gnpuHead.hddatcrc)
				{
					g_saveAppCtrl.rsvCounter = g_gnpuHead.datalen;
					return 0;
				}
				else
				{
					printf("file head crc error\r\n");
					return -2;
				}
			}
			else
			{
				printf("bin file not support\r\n");				// 作为bin文件升级，不安全
				return -1;
			}
		}
		else
		{
			printf("file not correct\r\n");
			return 0;
		}
	}
	else
	{
	}

#if (APP_SAVE_TO == APP_SAVE_NORFLASH)
	addr = NOR_APP_ADDR;
#elif (APP_SAVE_TO == APP_SAVE_EXRAM)
	addr = EXRAM_APP_ADDR;
#elif (APP_SAVE_TO == APP_SAVE_INFLASH)
	addr = APP_ADDR_BEG;
#else
	addr = 0;
#endif

	addr += ofst;
	addr += ((idx-1)*len);		// 写入地址务必使用idx*len;	否则在丢包,或者处理补发数据包时地址会产生偏差
	wtlen = len;

	g_saveAppCtrl.saveOffset += len;

	if (g_saveAppCtrl.isrnpufile != 0)
	{
		if (g_saveAppCtrl.rsvCounter > len)
		{
			thislen = len;
			g_saveAppCtrl.rsvCounter -= len;
		}
		else
		{
			thislen = g_saveAppCtrl.rsvCounter;
			g_saveAppCtrl.rsvCounter = 0;
		}
		for (i = 0; i < thislen; i++)
		{
			g_saveAppCtrl.rnpucrc = AddCrc32(g_saveAppCtrl.rnpucrc, pBuf[i]);
		}

		DecodeData(pBuf, thislen);		// 解码

		for (i = 0; i < thislen; i++)
		{
			g_saveAppCtrl.bincrc = AddCrc32(g_saveAppCtrl.bincrc, pBuf[i]);
		}

		for (i = thislen; i < len; i++)
		{
			pBuf[i] = 0xff;
		}
	}
	else
	{
		thislen = len;
	}

#if (APP_SAVE_TO == APP_SAVE_NORFLASH)
	printf("save to norflash, addr=0x%lx, wtlen=%d\r\n", addr, wtlen);
	DatFlashWrData(addr, pBuf, wtlen);
#elif (APP_SAVE_TO == APP_SAVE_EXRAM)
	printf("save to exram, addr=0x%lx, wtlen=%d\r\n", addr, wtlen);
	memcpy((void*)addr, (void*)pBuf, wtlen);
#elif (APP_SAVE_TO == APP_SAVE_INFLASH)
	printf("save to in flash addr=0x%lx, wtlen=%d\r\n", addr, wtlen);
	STMFlashWrite(addr, (u16*)pBuf, wtlen/2, 1);
#else
	printf("not support addr=0x%lx, wtlen=%d\r\n", addr, wtlen);
#endif
	return thislen;
}

// 判断接收是否完成
// 返回接收到的数据量
int IsAppReceiveDone(void)
{
	return (int)g_gnpuHead.datalen - (int)g_saveAppCtrl.rsvCounter;
}

u32 GetAppSaveDataCrc(u32 addr, u32 size)
{
#define RD_DAT_BUF_LEN		(1024)		// 字节数

	// 从flash读出数据再次验证
	u32 crc;

#if (APP_SAVE_TO == APP_SAVE_EXRAM)
	u8 rdata[RD_DAT_BUF_LEN];
#else
	u8 volatile rdata[RD_DAT_BUF_LEN];
#endif

	int i, thislen, rsvlen;
	rsvlen = size;
	crc = CRC32_INIT;

	while(addr < APP_ADDR_BEG+size)
	{
		if (rsvlen > RD_DAT_BUF_LEN)
		{
			thislen = RD_DAT_BUF_LEN;
			rsvlen -= RD_DAT_BUF_LEN;
		}
		else
		{
			thislen = rsvlen;
			rsvlen = 0;
		}
#if (APP_SAVE_TO == APP_SAVE_NORFLASH)
		DatFlashRdData(addr, rdata, RD_DAT_BUF_LEN);		// 读取一个扇区
#elif (APP_SAVE_TO == APP_SAVE_EXRAM)
		memcpy(rdata, (void*)addr, RD_DAT_BUF_LEN);
#elif (APP_SAVE_TO == APP_SAVE_INFLASH)
		STMFlashRead(addr, (u16*)rdata, RD_DAT_BUF_LEN/2);
#else
#endif

		for (i = 0; i < thislen; i++)
		{
			crc = AddCrc32(crc, rdata[i]);
		}

		addr += RD_DAT_BUF_LEN;						// 地址增加
	}
	return crc;
}


int IsSaveDataCorrect(void)
{
	u32 crc, hddatsize;
	int rslt;

	if (g_saveAppCtrl.isrnpufile == 0)
	{
		printf("g_isrnpufile == 0\r\n");
		return 0;
	}

	hddatsize = sizeof(g_gnpuHead) - sizeof(g_gnpuHead.rev) - 4;	//
	crc = CalcCrc32((u8*)(&g_gnpuHead), hddatsize);

	rslt = -1;

	printf("check g_gnpuHead crc = 0x%lx \r\n",crc);
	printf("g_gnpuHead.hddatcrc = 0x%lx \r\n",g_gnpuHead.hddatcrc);
	printf("g_gnpuHead.bincrc = 0x%lx \r\n",g_gnpuHead.bincrc);
	printf("g_saveAppCtrl.bincrc = 0x%lx \r\n",g_saveAppCtrl.bincrc);
	printf("g_gnpuHead.rnpucrc = 0x%lx \r\n",g_gnpuHead.rnpucrc);
	printf("g_saveAppCtrl.rnpucrc = 0x%lx \r\n",g_saveAppCtrl.rnpucrc);
	printf("g_gnpuHead.datalen = 0x%lx \r\n",g_gnpuHead.datalen);
	printf("g_saveAppCtrl.rsvCounter = 0x%lx \r\n",g_saveAppCtrl.rsvCounter);

	if (g_gnpuHead.hddatcrc == crc &&
		g_gnpuHead.bincrc == g_saveAppCtrl.bincrc &&
		g_gnpuHead.rnpucrc == g_saveAppCtrl.rnpucrc &&
		1	)
	{
		crc = GetAppSaveDataCrc(APP_ADDR_BEG, g_gnpuHead.datalen);

		printf("calc crc = 0x%x, g_gnpuHead.bincrc = 0x%x\r\n", crc, g_gnpuHead.bincrc);

		if (g_gnpuHead.bincrc == crc)
		{
			rslt = 0;
		}
		else
		{
			printf("re calc file data crc error\r\n");
		}
	}
	else
	{
		printf("receive file crc error\r\n");
	}

	return rslt;
}


// 启动APP升级任务
void StartAppUpdate(int reboot)
{ 
	if (IsSaveDataCorrect() == 0)
	{
		u32 rdstart, wrstart, len, wtlen, check;

		rdstart = (APP_ADDR_BEG - APP_SAVE_BASE);
		wrstart = (STM32_APP_ADDR - STM32_FLASH_BASE);	// 文件起始地址
		len = g_gnpuHead.datalen;
		wtlen = (g_gnpuHead.datalen + STM32_FLASH_RW_SIZE - 1) / STM32_FLASH_RW_SIZE;
		wtlen *= STM32_FLASH_RW_SIZE;
		check = g_gnpuHead.bincrc;

		printf("StartAppUpdate rdstart = 0x%x, wrstart = 0x%x, len = %d, wtlen = %d, wcrc=0x%x\r\n", rdstart, wrstart, len, wtlen, check);

		IapWritePara(rdstart, wrstart, len, wtlen, check);

#if (1)		// 改为不再区分，都需要重启升级
		RestartMcu();		// 重启MCU
#else
		if (reboot != 0)
		{
			RestartMcu();		// 重启MCU
		}
		else
		{
			UpdateApp();		// 升级主控文件
			JumpToApp();		// 进入APP
		}
#endif
	}
	else
	{
		printf("IsSaveDataCorrect failed\r\n");
	}
}


#endif



