#include <stdio.h>

#define CM_LIB_GLOBALES
#define EXTERNMACRO 2

#include "CM_LIB.h"
#include "CM_I2C.h"
#include "CM_I2C_L.h"
#include <string.h>
#include <stdio.h>

uint8_t ucData[16], ucCi[8], ucSk[8];
// Zone Data
uint8_t ucCM_UserZone;
uint8_t ucCM_AntiTearing;

// Chip state
uint8_t ucCM_Encrypt;
uint8_t ucCM_Authenticate;

// Global data
uint8_t ucCM_InsBuff[4];


uint8_t authenticationModeFlag = 0;
uint8_t passwordModeFlag = 0;
uint8_t encryptModeFlag = 0;

uint8_t errorGlobalFlag = 0;

//default : four user zone use Secret Seed G1 and password write/read 1(all use set 1)
		 
//Secret Seed : it's used by cm_ActiveSecurity
uint8_t ucG[8] = {0x22,0x23,0x34,0x45,0x56,0x67,0x78,0x89};
//passworkd for write : it's used by cm_VerifyPassword
uint8_t psword_w[3] = {0x22,0x34,0x56};
//passworkd for read : it's used by cm_VerifyPassword
uint8_t psword_r[3] = {0x88,0x9a,0xbc};
uint8_t psword_7[3] = {0xDD, 0x77, 0x99};

uint8_t cm_Auth_Encrp_Personal(uint8_t pswMode,uint8_t authMode)
{

	uint8_t ucReturn;
	uint8_t pwData[8] = {0};
	uint8_t seedData[8] = {0};
	
	uint8_t fab_id = 0x06;
	uint8_t cma_id = 0x04;
	uint8_t per_id = 0x00;	
	uint8_t fuseData;	
	int i;
	uint8_t configAll[240] = {0};

	printf("---> cm_Auth_Encrp_Personal start...\n");
	//read fuse
	cm_ReadFuse(&fuseData);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_ReadFuse is error\n");		
		errorGlobalFlag = 12;
	}
	if(fuseData == 0x00)
	{
		printf("FAB,CMA,PER------three fuse has burnned! Exit cm_Auth_Encrp_Personal!\n");
		return 0;
	}
	printf("---> fuseData %#x\n", fuseData);

	uint8_t pwwr7[3] = {0xDD, 0x42, 0x97};
	ucReturn = cm_VerifySecureCode(pwwr7);
	if (ucReturn != SUCCESS)
	{
		ucReturn = cm_VerifySecureCode(psword_7);
		if (ucReturn != SUCCESS)
		{
			printf("cm_VerifySecureCode 1 is error\n");		
			errorGlobalFlag = 15;

			/************ Read all configs *******************/
			memset(configAll, 0, 240);
			ucReturn = cm_ReadConfigZone(0x00,configAll,240);
			if (ucReturn != SUCCESS)
			{
				printf("cm_ReadConfigZone all is error\n");
				errorGlobalFlag = 13;
			}
			else
			{
				printf("======== Configure Memory =========");
				for(i=0;i<240;i++)
				{
					if(i%8 == 0) printf("\n%04x:  ", i);
					printf("%02X ", configAll[i]);
				}
				printf("\n");
			}
			return -1;
		}
		printf("---> used psword_7: %#x %#x %#x\n", psword_7[0], psword_7[1], psword_7[2]);
	}
	
	// ----------------------------------------------write card mfg code 0x50 30 30 31
	usleep(100);
	uint8_t cmc[4] = {0x50,0x30,0x30,0x31};

	ucReturn = cm_WriteConfigZone(0x0C, cmc, 4, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x0C is error\n");	
		errorGlobalFlag = 2;
		return -1;
	}

	// ----------------------------------------------Write Identification Number = 00000000012345
	usleep(100);
	uint8_t idnum[7] = {0x00,0x00,0x00,0x00,0x01,0x23,0x45};
	ucReturn = cm_WriteConfigZone(0x19, idnum, 7, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x19 is error\n");			
		errorGlobalFlag = 3;
		return -1;
	}
	
	
	
	// ----------------------------------------------Write Issuer Code = STATION 035
	usleep(100);
	uint8_t issue[16] = {0x53,0x54,0x41,0x54,0x49,0x4F,0x4E,0x20,0x30,0x33,0x35,0x00,0x00,0x00,0x00,0x00};
	ucReturn = cm_WriteConfigZone(0x40, issue, 16, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x40 is error\n");	
		
		errorGlobalFlag = 4;
		return -1;
	}
	
	//---------------------------------------------config all user zone use the same password/seed of the set 1 
	// ---------------------------------------------Write Control for user zone 0
	usleep(100);
	ucData[0] = ((pswMode & 0x03) << 6) | ((authMode & 0x3) << 4) | 0x07; // AR[0-3] = 0101 0111 ---->
							 //01 ----> after Authentication successful ,then write correct password
							 //01 ----> the read and write need to Authentication
							 //1  ----> the host access(read/write) user zone use encryption mode(set 0 lead to unlock config zone error,i dont know why?)
							 //111----> the default data
	ucData[1] = 0x51;//Authentication set 1, POM set 1, Key 1        //PR[0-3] = 0101 0001
					 //01 ----> the secret seed select set 1(secret seed zone)
					 //01 ----> the POK select set 1(secret seed zone)
					 //0001 ----> the password select set 1(password zone)
	ucReturn = cm_WriteConfigZone(0x20, ucData, 2, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x20 is error\n");	
		
		errorGlobalFlag = 5;
		return -1;
	}
	
	
	// ---------------------------------------------Write Control for user zone 1
	usleep(100);
	ucReturn = cm_WriteConfigZone(0x22, ucData, 2, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x22 is error\n");	
		
		errorGlobalFlag = 6;
		return -1;
	}
	
	// ---------------------------------------------Write Control for user zone 2
	usleep(100);
	ucReturn = cm_WriteConfigZone(0x24, ucData, 2, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x24 is error\n");	
		
		errorGlobalFlag = 7;
		return -1;
	}
	
	
	// ---------------------------------------------Write Control for user zone 3
	usleep(100);
	ucReturn = cm_WriteConfigZone(0x26, ucData, 2, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x26 is error\n");	
		
		errorGlobalFlag = 8;
		return -1;
	}
	

	//----------------------------------------------Set DCR to allow unlimited checksum reads
	usleep(100);
	ucData[0] = 0xff;//after finish personal chip , must recover to the default 
//	ucData[0] = 0xbf;//set unlimited checksum reads, Unlimited Authentication Trials,Eight Trials Allowed during debug for avoid the chip lock dead (why config 0x8f is error)
	ucReturn = cm_WriteConfigZone(0x18, ucData, 1, FALSE);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_WriteConfigZone 0x18 is error\n");
	
		errorGlobalFlag = 9;
		return -1;
	}
	
	
	
	//---------------------------------------------- Write Ci1
	usleep(100);
	ucCi[0] = 0xFF;
	ucCi[1] = 0x01;
	ucCi[2] = 0x02;
	ucCi[3] = 0x03;
	ucCi[4] = 0x04;
	ucCi[5] = 0x05;
	ucCi[6] = 0x06;
	ucCi[7] = 0x07;
	ucReturn = cm_WriteConfigZone(0x60, ucCi, 8, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x60 is error\n");
		
		errorGlobalFlag = 10;
		return -1;
	}
	
	
	
	// ------------------------------------------------Write G1
	usleep(100);
	// user must set and remember this secret for Secret Seed,then must be same whih cm_Auth_Encrp_rw before access to user zone for write or read .
	seedData[0] = ucG[0];
	seedData[1] = ucG[1];
	seedData[2] = ucG[2];
	seedData[3] = ucG[3];
	seedData[4] = ucG[4];
	seedData[5] = ucG[5];
	seedData[6] = ucG[6];
	seedData[7] = ucG[7];
	ucReturn = cm_WriteConfigZone(0x98, seedData, 8, FALSE);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_WriteConfigZone 0x98 is error\n");
		
		errorGlobalFlag = 11;
		return -1;
	}
	
	
	
	//--------------------------------------------- Write PSW1 (both Write and Read)
	usleep(100);
	// user must set and remember this secret for password for write/read.then must be same whih cm_Auth_Encrp_rw before access to user zone for write or read .
	pwData[0] = 0xFF;
	pwData[1] = psword_w[0];
	pwData[2] = psword_w[1];
	pwData[3] = psword_w[2];
	pwData[4] = 0xFF;
	pwData[5] = psword_r[0];
	pwData[6] = psword_r[1];
	pwData[7] = psword_r[2];
	ucReturn = cm_WriteConfigZone(0xB8, pwData, 8, FALSE);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_WriteConfigZone 0xB8 is error\n");
		
		errorGlobalFlag = 12;
		return -1;
	}

	//--------------------------------------------- Write PSW7 (only Write)
	usleep(100);
	pwData[0] = 0xFF;
	pwData[1] = psword_7[0];
	pwData[2] = psword_7[1];
	pwData[3] = psword_7[2];
	ucReturn = cm_WriteConfigZone(0xE8, pwData, 4, FALSE);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_WriteConfigZone 0xE8 is error\n");
		
		errorGlobalFlag = 13;
		return -1;
	}
	
#if 1
	usleep(1000);
	ucReturn = cm_BurnFuse(fab_id);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_BurnFuse fab_id is error\n");
		
		errorGlobalFlag = 12;
	}
	
	usleep(1000);
	ucReturn = cm_BurnFuse(cma_id);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_BurnFuse cma_id is error\n");
		
		errorGlobalFlag = 12;
	}
	
	usleep(1000);
	ucReturn = cm_BurnFuse(per_id);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_BurnFuse per_id is error\n");
		
		errorGlobalFlag = 12;
	}
#endif	

	usleep(1000);
	//read fuse
	cm_ReadFuse(&fuseData);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_ReadFuse is error\n");		
		errorGlobalFlag = 12;
	}
	if(fuseData == 0x00)
	{
		printf("FAB,CMA,PER------three fuse are burnned successful\n");
	}


	
	/************ Read all configs *******************/
	memset(configAll, 0, 240);
	ucReturn = cm_ReadConfigZone(0x00,configAll,240);
	if (ucReturn != SUCCESS)
	{
		printf("cm_ReadConfigZone all is error\n");
		errorGlobalFlag = 13;
	}
	else
	{
		printf("======== Configure Memory =========");
		for(i=0;i<240;i++)
		{
			if(i%8 == 0) printf("\n%04x:  ", i);
			printf("%02X ", configAll[i]);
		}
		printf("\n");
	}

	if(errorGlobalFlag != 0)
		return FAILED;
	
	printf("---> cm_Auth_Encrp_Personal successful!\n");
	return SUCCESS;		
}

/*
*FUNC: To init the chip of AT88SCxxx
*
*PARAM:
*		authMode : 
*							3 : close Authentication mode;
*							2 : write Authentication mode;
*							1 : normal Authentication mode;
*							0 : dual access mode;
*
*		pswMode : 
*							3 : close password mode;
*							2 : write password mode;
*							0/1 : read and write password mode;
*
*		encryptFlag :
*							TRUE  : enable encrypt mode
*							FALSE : disable encrypt mode
 *
 */
uint8_t cm_Auth_Encrp_Init(uint8_t authMode,uint8_t pswMode,uint8_t encryptFlag)
{     
	uint8_t ucReturn;
	uint8_t fuseData;
	int i;
	uint8_t ucData[4] = {0};
	uint8_t configAll[240] = {0};
#if 0
	//init I2C pin
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_5;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	stm32_gpio_init(GPIOE, &GPIO_InitStruct);
#endif
	if(pswMode == 0x0 || pswMode == 0x1)
		passwordModeFlag = 1;
	else if(pswMode == 0x2)
		passwordModeFlag = 2;
	else
		passwordModeFlag = 0;
	
	if(authMode == 0)
		authenticationModeFlag = 0;
	else if(authMode == 1)
		authenticationModeFlag = 1;
	else if(authMode == 2)
		authenticationModeFlag = 2;
	else if(authMode == 3)
		authenticationModeFlag = 3;
	
	if(encryptFlag == TRUE)
		encryptModeFlag = 1;
	else
		encryptModeFlag = 0;
	
	cm_PowerOn(); 				
			
	/**************** Check AT88SC0104C Present******************/
	ucData[0] = 0x5A;
	ucData[1] = 0xA5;
	ucReturn = cm_WriteConfigZone(0x0A, ucData, 2, FALSE);
	if (ucReturn != SUCCESS)
	{
		printf("cm_WriteConfigZone 0x0a is error\n");
		errorGlobalFlag = 1;
	}
	
	usleep(100);	//这个延时很重要，AT88SC0104C处理数据相当的慢。
	// Read back data
	ucData[0] = 0x00;
	ucData[1] = 0x00;
	ucReturn = cm_ReadConfigZone(0x0A, ucData, 2);
	if (ucReturn != SUCCESS) 
	{
		printf("cm_ReadConfigZone 0x0a is error\n");		
		errorGlobalFlag = 1;
	}
	if ((ucData[0]!= 0x5A) || (ucData[1]!= 0xA5) )
	{
		printf("read back data is not same\n");
		errorGlobalFlag = 1;
	}
	
	if(errorGlobalFlag != 0)
	{
		printf("there is a error and the flag = %d,the poweroff\n",errorGlobalFlag);
			
		cm_PowerOff();
		
		return FAILED;
	}

	return ucReturn;
}
 
/*
 *cm_WR: 
 *				0 : read
 *				1 : write
 *userZone: 
 *				select need to access the index of user zone in range of 0-3
 *startInZone:
 *				the start location in user zone for user operation of write/read,and the default data is 0
 *pData:
 *				the data buffer for store the write/read data
 *dataLen:
 *				the byte number of write/read
 *
*/
uint8_t cm_Auth_Encrp_rw(uint8_t cm_WR,uint8_t userZone,uint8_t startInZone,uint8_t *pData,uint8_t dataLen)
{  		
	uint8_t ucReturn;
	int i;
	uint8_t userZoneTemp = userZone & 0x03;
 
	uint8_t seedSet = 1;//which set of Secret Seed
	uint8_t pwset = 1;//which set of password for write/read
	
	//if(authenticationModeFlag == 0 || authenticationModeFlag == 1 || authenticationModeFlag == 2 || authenticationModeFlag == 3)//all to authenticate
	{
		if(encryptModeFlag == 1)
		{
			ucReturn = cm_ActiveSecurity(seedSet, ucG, NULL, TRUE);
		}
		else
		{
			ucReturn = cm_ActiveSecurity(seedSet, ucG, NULL, FALSE);
		}
	}
	
	if (ucReturn != SUCCESS) 
	{
		printf("cm_ActiveSecurity is error\n");		
		return FAILED;
	}

	ucReturn = cm_SetUserZone(userZoneTemp, FALSE);
	
	if (ucReturn != SUCCESS) 
	{
		printf("cm_SetUserZone is error\n");		
		return FAILED;
	}
	
	if(passwordModeFlag == 3)
	{
		if(cm_WR==0)
		{
			// Read back data
			for (i = 0; i < dataLen; ++i) 
				pData[i] = 0x00;  //clear pData
			ucReturn = cm_ReadSmallZone(startInZone, pData, dataLen);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_ReadSmallZone is error\n");
				
				return FAILED;
			}
		}
		else
		{
			// Write data to user zone
			ucReturn = cm_WriteSmallZone(startInZone, pData, dataLen);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_WriteSmallZone is error\n");
				
				return FAILED;
			}
			// Send checksum
			ucReturn = cm_SendChecksum(NULL);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_SendChecksum is error\n");
				
				return FAILED;
			}
		}
	}
	else  //(passwordModeFlag == 1 || passwordModeFlag == 2)
	{  
			ucCM_Authenticate = TRUE;
		
			if(cm_WR==0)
			{
				// Read back data, firstly verify the read password
				ucReturn=cm_VerifyPassword(psword_r,pwset,CM_PWREAD);					
				if (ucReturn != SUCCESS) 
				{
					printf("cm_VerifyPassword is error\n");
					
					return FAILED;
				}
				
				for (i = 0; i < dataLen; ++i) 
					pData[i] = 0x00;  //clear pData
				
				ucReturn = cm_ReadSmallZone(startInZone, pData, dataLen);
				if (ucReturn != SUCCESS) 
				{
					printf("cm_ReadSmallZone is error\n");
					
					return FAILED;
				}
			
				ucReturn =cm_ReadChecksum(NULL);
				if (ucReturn != SUCCESS) 
				{
					printf("cm_ReadChecksum is error\n");
					
					return FAILED;
				}
			}
		else
		{
			// Write data to user zone,firstly verify the write password
			ucReturn=cm_VerifyPassword(psword_w,pwset,CM_PWWRITE);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_VerifyPassword is error\n");
				
				return FAILED;
			}
			
			ucReturn = cm_WriteSmallZone(startInZone, pData, dataLen);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_WriteSmallZone is error\n");
				
				return FAILED;
			}
			
			// Send checksum
			ucReturn = cm_SendChecksum(NULL);
			if (ucReturn != SUCCESS) 
			{
				printf("cm_SendChecksum is error\n");
				
				return FAILED;
			}
		 }
	}
		
	ucReturn = cm_DeactiveSecurity();

	if (ucReturn != SUCCESS) 
	{
		printf("cm_DeactiveSecurity is error\n");
		
		return FAILED;
	}
	
  return SUCCESS;
}



uint8_t cm_Auth_Encrp_Read(uint8_t userZone,uint8_t startInZone,uint8_t* readData,uint8_t readLen)
{
	uint8_t returnData = 0;
	
	returnData = cm_Auth_Encrp_rw(0,userZone,startInZone,readData,readLen);
	
	if(returnData != SUCCESS)
		return FAILED;
	else
		return SUCCESS;
}


uint8_t cm_Auth_Encrp_Write(uint8_t userZone,uint8_t startInZone,uint8_t* writeData,uint8_t writeLen)
{
	uint8_t returnData = 0;
	
	returnData = cm_Auth_Encrp_rw(1,userZone,startInZone,writeData,writeLen);
	
	if(returnData != SUCCESS)
		return FAILED;
	else
		return SUCCESS;
}



uint8_t test_cryptomem(void)
{
	uint8_t readData[16] = {0};
	uint8_t readLen = 16;
	uint8_t writeData[16] = {0};
	uint8_t writeLen = 16;
	uint8_t i;
	uint8_t returnData;
	
	uint8_t userZone = 1;//user need to access the index of user zone
	uint8_t startInZone = 0;//the start location of x user zone for write/read

	// returnData = cm_Auth_Encrp_Init(1,1,TRUE); 
	// if(returnData != SUCCESS)
	// {
	// 	printf("cm_Auth_Encrp_Init is error\n");
		
	// 	return FAILED;
	// }

//	printf("Write: \n");
	for(i=0;i<writeLen;i++) 
	{
		writeData[i] = '6' + i;
//		printf("%#x ", writeData[i]);
	}
//	printf("\n");
	
	returnData = cm_Auth_Encrp_Write(userZone,startInZone,writeData,writeLen); 
	if(returnData != SUCCESS)
	{
		printf("cm_Auth_Encrp_Read is error\n");
		
		return FAILED;
	}
	
	usleep(100);
	returnData = cm_Auth_Encrp_Read(userZone,startInZone,readData,readLen); 
	if(returnData != SUCCESS)
	{
		printf("cm_Auth_Encrp_Read is error\n");		
		return FAILED;
	}

	printf("Crypto Check ok!\n");
	return SUCCESS;
}









