STM32F4读写AT88SC0104加密存储芯片驱动库

一、AT88SC系列加密芯片应用很广,接触式与非接触式IC都会使用这个芯片作为存储芯片,I2C接口,但与标准的I2C时序有点差别,最好是使用模拟时序驱动,加解密算法来自于ATmel官方对其进行了封装,at88sc_read_storage与at88sc_write_storage两个函数对于应用层来说很友好

/** 
* @file     at88sc.c 
* @brief    at88sc driver. 
* @details  Simulation time sequence, authentication read and write user zone and config zone. 
* @author   ken 
* @date     2018-11-15 
* @version  A001 
* @par Copyright (c):  
* @par History:          
*   version: ken, 2018-11-15, create\n 
*/  
#include "system.h"
#include "at88sc.h"
#include "dwt.h"
#include "string.h"
#include "main.h"
#include "smartcard.h"

#ifdef AT88SC_DEBUG
    #define	at88sc_log(...) do{if(DEBUG(DEBUG_ENABLE)){DBG_LOG("[AT88SC](%ld) ",__LINE__);DBG_LOG(__VA_ARGS__);}}while(0)
    #define at88sc_usr(...) do{if(DEBUG(DEBUG_ENABLE)){DBG_LOG("[AT88SC] ");DBG_USR(__VA_ARGS__);}}while(0)
    #define at88sc_err(...) do{if(DEBUG(DEBUG_ENABLE)){DBG_LOG("[AT88SC] ");DBG_ERR(__VA_ARGS__);}}while(0)
    #define at88sc_dump(...) if(DEBUG(DEBUG_ENABLE)){DBG_DUMP(__VA_ARGS__);}
#else
    #define at88sc_log(...)
    #define at88sc_usr(...)
    #define at88sc_err(...)
    #define at88sc_dump(...)
#endif

/**  at88sc gpio port  */  
GPIO_InitTypeDef AT88SC_GPIO;
/**  GPA units  */  
uint8_t GPA[20];
/**  config zone  */  
//AT88SC_CONFIG_ZONE_T at88sc_config_zone;

static const uint8_t block_admini[]={BLOCK0_ADMINI,BLOCK1_ADMINI,BLOCK2_ADMINI,BLOCK3_ADMINI,BLOCK4_ADMINI,BLOCK5_ADMINI,BLOCK6_ADMINI,
BLOCK7_ADMINI,BLOCK8_ADMINI,BLOCK9_ADMINI,BLOCK10_ADMINI,BLOCK11_ADMINI,BLOCK12_ADMINI,BLOCK13_ADMINI,BLOCK14_ADMINI,BLOCK15_ADMINI};

/**  at88sc status  */  
AT88SC_STA_T st88sc_sta;

/**  GC_TABLE  */  
unsigned char const GC0[]={0x63,0x6A,0x56,0x56,0xD8,0x60,0x2F,0x25};//GC0
unsigned char const GC1[]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//GC1
unsigned char const GC2[]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//GC2
unsigned char const GC3[]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//GC3

/**  PASSWORD_TABLE  */  
unsigned char const PW_WRITE0[]={0x57,0x26,0xF1};//WRITE PASSWORD 0
unsigned char const PW_READ0[]= {0x57,0x26,0xF1};//READ  PASSWORD 0
unsigned char const PW_WRITE1[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 1
unsigned char const PW_READ1[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 1
unsigned char const PW_WRITE2[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 2
unsigned char const PW_READ2[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 2
unsigned char const PW_WRITE3[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 3
unsigned char const PW_READ3[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 3
unsigned char const PW_WRITE4[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 4
unsigned char const PW_READ4[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 4
unsigned char const PW_WRITE5[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 5
unsigned char const PW_READ5[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 5
unsigned char const PW_WRITE6[]={0xFF,0xFF,0xFF};//WRITE PASSWORD 6
unsigned char const PW_READ6[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 6
unsigned char const PW_WRITE7[]={0x05,0x05,0xC7};//WRITE PASSWORD 7
unsigned char const PW_READ7[]= {0xFF,0xFF,0xFF};//READ  PASSWORD 7


static void SMSTART(void);
static void SMSTOP(void);
static void IIC_Initial(void);
static void at88sc_ack_polling(void);
static void at88sc_gpa_clock(uint8_t Datain,uint8_t times);
static void at88sc_read(uint8_t *rd_ptr);
static void at88sc_write(uint8_t *wd_ptr);
static void at88sc_encrypto_data(uint8_t encryptodatanumber,uint8_t *ptr);
static void at88sc_send_checksum(void);
static uint8_t at88sc_mtz_test(void);

/** 
* test i2c communication normal with at88sc. 
* write 2 register and read comparison,if the chip config zone lock well return 0xfx. 
* @param[in]   none.
* @param[out]  noen.
* @retval  1 success, 0 failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_mtz_test(void){
	
	uint8_t send_buf[2];
	uint8_t recv_buf[2];
	send_buf[0]=0xa5;
	send_buf[1]=0x5a;
	at88sc_write_config_register(MTZ_R,send_buf);
	delay_ms(10);
	at88sc_read_config_register(MTZ_R,recv_buf);
	
	if (recv_buf[0]==0xa5 && recv_buf[1]==0x5a ){
		return 1;
	}
	else
		return 0;
}

/** 
* i2c communication initialize. 
* initialize the i2c gpio signal. 
* @param[in]   none.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
static void IIC_Initial(void){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	CM_CLK_OUT;
	CM_DATA_OUT;
	
	CM_DATA_HI;			
	delay_us(12);
 	CM_CLK_HI;
	delay_us(12);
	CM_CLK_LO;
	delay_us(12);
 	CM_CLK_HI;
	delay_us(12);
	CM_CLK_LO;
	delay_us(12);
 	CM_CLK_HI;
	delay_us(12);
	CM_CLK_LO;
	delay_us(12);
 	CM_CLK_HI;
	delay_us(12);
	CM_CLK_LO;
	delay_us(12);
 	CM_CLK_HI;
	delay_us(12);
	CM_CLK_LO;
	delay_us(12);// 5 CLK
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}

/** 
* generate i2c start signal. 
* generate i2c start signal. 
* @param[in]   none.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
static void SMSTART(void){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	CM_DATA_OUT;
 	CM_CLK_LO;
	delay_us(8);
	 CM_DATA_HI;
	delay_us(8);
	CM_CLK_HI;
	delay_us(8);
 	CM_DATA_LO;
	delay_us(8);
 	CM_CLK_LO;
	delay_us(8);
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}

/** 
* generate i2c stop signal. 
* generate i2c stop signal. 
* @param[in]   none.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
static void SMSTOP(void){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	CM_DATA_OUT;  	
	CM_DATA_LO;
	delay_us(8);
  	CM_CLK_HI;
	delay_us(8);
  	CM_DATA_HI;
	delay_us(8);
  	CM_CLK_LO;
	delay_us(8);
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}

/** 
* poll i2c ack signal. 
* poll i2c ack signal. 
* @param[in]   none.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_ack_polling(void){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	uint8_t  AckPolling_return;
	uint8_t  temp, bitcounter;
	uint8_t  bytecounter;

	SMSTART();
	temp=0xb6;
	bytecounter=0xff;			//note:if CPU clk fast,inc bytecounter.
	AckPolling_return=0;

	do{	
		CM_DATA_OUT;
		delay_us(8);
		for(bitcounter=0;bitcounter<8;bitcounter++){
			
			if (temp&0x80){
				CM_DATA_HI;
			}
			else{
				CM_DATA_LO;
			}
			delay_us(8);
			CM_CLK_HI;
			delay_us(8);
			CM_CLK_LO;
			delay_us(8);
			temp=temp<<1;
		}
		
		bytecounter--;
				
		CM_DATA_IN;
		delay_us(8);
		
		CM_CLK_HI;
		delay_us(8);
		
		if(!(CM_DATA_RD)){
			CM_CLK_LO;
			delay_us(8);
			AckPolling_return=1;
		}
		else{
			CM_CLK_LO;
			AckPolling_return=0;
			SMSTART();
			temp=0xb6;
		}

		if(AckPolling_return==1){
			break;
		}

	}while(bytecounter>0);

	SMSTOP();
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}
  
/** 
* read data from at88sc. 
* protocol:cmd addr1 addr2 len data*N. 
* @param[in]   rd_ptr:read pointer, define command protocol.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
static void at88sc_read(uint8_t  *rd_ptr){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	uint8_t bitcounter;
	uint8_t temp;
	uint8_t cmd_send_counter;
	uint8_t bytecounter;
	temp=rd_ptr[0];
	bytecounter=0;
	cmd_send_counter=0;
	uint8_t recv_len = rd_ptr[3];
	
	SMSTART();

	do{
		CM_DATA_OUT;
		delay_us(8);
		for(bitcounter=0;bitcounter<8;bitcounter++){
			
			if (temp&0x80){
				CM_DATA_HI;
			}
			else{
				CM_DATA_LO;
			}
			delay_us(8);
			CM_CLK_HI;
			delay_us(8);
			CM_CLK_LO;
			delay_us(8);
			temp=temp<<1;
		}
		
		CM_DATA_HI;
		delay_us(8);

		CM_DATA_IN;
		delay_us(8);
		
		CM_CLK_HI;
		delay_us(8);

		if(!(CM_DATA_RD)){
			CM_CLK_LO;
			delay_us(8);
			bytecounter++;
			temp=rd_ptr[bytecounter];
		}
		else{
			CM_CLK_LO;
			SMSTART();
			temp=rd_ptr[0];
			bytecounter=0;
			cmd_send_counter++;
		}

		if(cmd_send_counter>8){
			bytecounter=4;
			goto read_out;
		}

	}while(bytecounter<4);
	
	for(bytecounter=0;bytecounter<recv_len;bytecounter++){
		
		CM_DATA_IN;
		delay_us(8);
		for(bitcounter=0;bitcounter<8;bitcounter++){
			
			CM_CLK_HI;
			delay_us(8);

			if (CM_DATA_RD){
				temp=temp|0x01;
			}
			else{
				temp=(temp&0xfe);
			}

			if(bitcounter<7){
				temp=temp<<1;
			}
			else{
				delay_us(4);
			}

			CM_CLK_LO;
			delay_us(8);
		}

		CM_DATA_OUT;
		delay_us(8);
		CM_DATA_LO;
		delay_us(8);
		CM_CLK_HI;
		delay_us(8);
		CM_CLK_LO;
		delay_us(8);
     	rd_ptr[bytecounter+4]=temp;
	}

read_out:
	SMSTOP();
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}

/** 
* write data to at88sc. 
* protocol:cmd addr1 addr2 len data*N. 
* @param[in]   wd_ptr:read pointer, define command protocol.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
static void at88sc_write(uint8_t *wd_ptr){
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__disable_irq();
	#endif
	
	uint8_t bitcounter;
	uint8_t temp;
	uint8_t bytecounter;
	uint8_t cmd_send_counter;
	temp=wd_ptr[0];
	bytecounter=0;
	cmd_send_counter=0;
	SMSTART();

	do{
		CM_DATA_OUT;
		delay_us(8);
		for(bitcounter=0;bitcounter<8;bitcounter++){
			
			if (temp&0x80){
				CM_DATA_HI;
			}
     		else{
				CM_DATA_LO;
			}

       		delay_us(8);
			CM_CLK_HI;
			delay_us(8);
			CM_CLK_LO;
			delay_us(8);
			temp=temp<<1;
		}
		
		CM_DATA_IN;
		delay_us(8);
  		CM_CLK_HI;
		delay_us(8);
		if(!(CM_DATA_RD)){
			
			CM_CLK_LO;
			delay_us(8);
			bytecounter++;
			temp=wd_ptr[bytecounter];
		}
  		else{
			CM_CLK_LO;
			SMSTART();
			temp=wd_ptr[0];
			bytecounter=0;
			cmd_send_counter++;
		}

  		if(cmd_send_counter>8){
			bytecounter=wd_ptr[3]+4;
		}
  	}while(bytecounter<wd_ptr[3]+4);

	SMSTOP();
	
	#ifdef AT88SC_DISABLE_INTERRUPT
	__enable_irq();
	#endif
}

/** 
* authentication arithmetic function. 
* Functions Brief:i don`t know. 
* @param[in]   i don`t know.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_gpa_clock(uint8_t Datain,uint8_t times){
	
	uint8_t t;
	uint8_t d;
	uint8_t din_gpa;
	uint8_t Ri;
	uint8_t R_Sum;
	uint8_t Si;
	uint8_t S_Sum;
	uint8_t Ti;
	uint8_t T_Sum;

	for(t=0x00;t<times;t++){
		
		din_gpa=Datain ^ GPA[0];
		Ri= din_gpa&0x1f;
		Si= ((din_gpa&0x0f)<<3)+((din_gpa&0xe0)>>5);
		Ti=(din_gpa&0xf8)>>3;
		
		//r parameter
		if(((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4))>31){
			R_Sum=((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4))-31;
		}
		else{
			R_Sum=((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4));
		}

		GPA[1]=GPA[2];
		GPA[2]=GPA[3];
		GPA[3]=GPA[4];
		GPA[4]=GPA[5]^Ri;
		GPA[5]=GPA[6];
		GPA[6]=GPA[7];
		GPA[7]=R_Sum;
		
		//s parameter
		if ((GPA[9]+((GPA[8]&0x3f)<<1)+((GPA[8]&0x40)>>6) )>127){
			S_Sum=( (GPA[9]) + ((GPA[8]&0x3f)<<1)+((GPA[8]&0x40)>>6) )-127;
		}
		else{
			S_Sum= (GPA[9]) + ((GPA[8]&0x3f)<<1)+((GPA[8]&0x40)>>6) ;
		}

		GPA[8]=GPA[9];
		GPA[9]=Si^GPA[10];
		GPA[10]=GPA[11];
		GPA[11]=GPA[12];
		GPA[12]=GPA[13];
		GPA[13]=GPA[14];
		GPA[14]=S_Sum;
		
		//t parameter
		if ((GPA[15]+GPA[17])> 31){
			T_Sum=GPA[15]+GPA[17]-31;
		}
		else{
			T_Sum=GPA[15]+GPA[17];
		}

		GPA[15]=GPA[16];
		GPA[16]=GPA[17];
		GPA[17]=GPA[18]^Ti;
		GPA[18]=GPA[19];
		GPA[19]=T_Sum;
		
		///Output
		if((GPA[14]&0x01)==0){
			d=((GPA[7]^GPA[3])&0x01);
		}
		else{
			d=((GPA[19]^GPA[16])&0x01);
		}

		if((GPA[14]&0x02)==0){
			d=d+((GPA[7]^GPA[3])&0x02);
		}
		else{
			d=d+((GPA[19]^GPA[16])&0x02);
		}

		if((GPA[14]&0x04)==0){
			d=d+((GPA[7]^GPA[3])&0x04);
		}
		else{
			d=d+((GPA[19]^GPA[16])&0x04);
		}

		if((GPA[14]&0x08)==0){
			d=d+((GPA[7]^GPA[3])&0x08);
		}
		else{
			d=d+((GPA[19]^GPA[16])&0x08);
		}

		GPA[0]= ( (((GPA[0])&0x0f)<<4) +d);
	}
}

/** 
* authentication the selected gc code. 
* authentication the selected gc code. 
* @param[in]   GC_select:gc code num.
* @param[out]  noen.
* @retval  return 0xff:success, other:failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_authentication(uint8_t GC_select){
	
	#ifdef AT88SC_NO_NEED_AUTHENTICATION
	return 0xff;
	#endif
	
	uint8_t SK[8];
	uint8_t Q_CH[0x14];
	uint8_t j;


	for(j=0;j<=19;j++){
		GPA[j]=0x00;
	}

	Q_CH[0]=0xb6;
	Q_CH[1]=0x00;
	Q_CH[2]=GC_select<<4;
	Q_CH[2]=Q_CH[2]+0x50;
	Q_CH[3]=0x08;
	at88sc_read(Q_CH);

	for(j=0;j<8;j++){
		Q_CH[j+12]=Q_CH[j+4];//CI
	}

	for(j=0;j<8;j++){
		Q_CH[j+4]=0xAA;      //$$can modify random number
	}

	for(j=0;j<4;j++){
		
	   at88sc_gpa_clock(Q_CH[12+2*j],0x03);
	   at88sc_gpa_clock(Q_CH[12+2*j+1],0x03);
	   at88sc_gpa_clock(Q_CH[4+j],0x01);
	}

	if ((GC_select&0x0f)==0x00)
		for(j=0;j<8;j++){
			Q_CH[12+j]=GC0[j];
		}
	else if ((GC_select&0x0f)==0x01)
		for(j=0;j<8;j++){
			Q_CH[12+j]=GC1[j];
		}
	else if ((GC_select&0x0f)==0x02)
		for(j=0;j<8;j++){
			Q_CH[12+j]=GC2[j];
		}
	else
		for(j=0;j<8;j++){
			Q_CH[12+j]=GC3[j];
		}

	for(j=0;j<4;j++){
		
	   at88sc_gpa_clock(Q_CH[12+2*j],0x03);
	   at88sc_gpa_clock(Q_CH[12+2*j+1],0x03);
	   at88sc_gpa_clock(Q_CH[8+j],0x01);
	}

	at88sc_gpa_clock(0x00,0x06);
	Q_CH[12]=GPA[0];
	
	for(j=1;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x07);
		Q_CH[12+j]=GPA[0];
	}

	Q_CH[0]=0xb8;//send ch
	Q_CH[2]=0x00;
	Q_CH[3]=0x10;
	Q_CH[1]=GC_select;
	at88sc_write(Q_CH);
	at88sc_ack_polling();

	//new ci
	Q_CH[12]=0xFF;
	for(j=1;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x02);
		Q_CH[12+j]=GPA[0];
	}
	//new sk
	for(j=0;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x02);
		SK[j]=GPA[0];
	}
	at88sc_gpa_clock(0x00,0x03);

	Q_CH[0]=0XB6;
	Q_CH[1]=0X00;
	Q_CH[2]=GC_select<<4;
	Q_CH[2]=Q_CH[2]+0x50;
	Q_CH[3]=0x08;
	at88sc_read(Q_CH);
	at88sc_ack_polling();
	if (Q_CH[4]!=0xff){
		goto Aut_Report;
	}

	for(j=0;j<8;j++){
		
		if(Q_CH[4+j]!= Q_CH[12+j]){
			goto Aut_Report;
		}
	}

	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(Q_CH[2],0x01);
	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(0x08,0x01);
	for(j=0;j<8;j++){
		
		at88sc_gpa_clock(Q_CH[4+j],0x01);
		at88sc_gpa_clock(0x00,0x05);
	}

	//crypto_Authentication
	for(j=0;j<=19;j++){
		GPA[j]=0x00;
	}

	for(j=0;j<8;j++){
		Q_CH[j+4]=0xAA;      //$$can modify random number
	}
	
	for(j=0;j<4;j++){
		
		at88sc_gpa_clock(Q_CH[12+2*j],0x03);
		at88sc_gpa_clock(Q_CH[12+2*j+1],0x03);
		at88sc_gpa_clock(Q_CH[4+j],0x01);
	}

	for(j=0;j<4;j++){
		
		at88sc_gpa_clock(SK[2*j],0x03);
		at88sc_gpa_clock(SK[2*j+1],0x03);
		at88sc_gpa_clock(Q_CH[8+j],0x01);
	}

	at88sc_gpa_clock(0x00,0x06);
	Q_CH[12]=GPA[0];
	for(j=1;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x07);
		Q_CH[12+j]=GPA[0];
	}

	Q_CH[0]=0xb8;
	Q_CH[1]=GC_select+0x10;
	Q_CH[2]=0x00;
	Q_CH[3]=0x10;
	at88sc_write(Q_CH);
	at88sc_ack_polling();

	//new ci
	Q_CH[12]=0xFF;
	for(j=1;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x02);
		Q_CH[12+j]=GPA[0];
	}
	//new sk
	for(j=0;j<8;j++){
		
		at88sc_gpa_clock(0x00,0x02);
		SK[j]=GPA[0];
	}
	at88sc_gpa_clock(0x00,0x03);

	Q_CH[0]=0XB6;
	Q_CH[1]=0X00;
	Q_CH[2]=GC_select<<4;
	Q_CH[2]=Q_CH[2]+0x50;
	Q_CH[3]=0x08;
	at88sc_read(Q_CH);
	at88sc_ack_polling();
	if (Q_CH[4]!=0xff){
		goto Aut_Report;
	}

	for(j=0;j<8;j++){
		if(Q_CH[4+j]!= Q_CH[12+j]){
			goto Aut_Report;
		}
	}

	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(Q_CH[2],0x01);
	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(0x08,0x01);
	for(j=0;j<8;j++){
		
		at88sc_gpa_clock(Q_CH[4+j],0x01);
		at88sc_gpa_clock(0x00,0x05);
	}

	Aut_Report:
	return Q_CH[4];
}

/** 
* verify the user zone write password. 
* verify the user zone write password. 
* @param[in]   pw_select:write code num.
* @param[out]  noen.
* @retval  return 0xff:success, other:failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_verify_write_password(uint8_t pw_select){
	
	
	#ifdef AT88SC_NO_NEED_PASSWORD
	return 0xff;
	#endif
	uint8_t j;
	uint8_t pw[7];

	if ((pw_select&0x0f)==0x00)
		for(j=0;j<3;j++){
			pw[4+j]=PW_WRITE0[j];
		}
	else if ((pw_select&0x0f)==0x01)
		for(j=0;j<3;j++){
			pw[4+j]=PW_WRITE1[j];
		}
	else if ((pw_select&0x0f)==0x02)
		for(j=0;j<3;j++){
			pw[4+j]=PW_WRITE2[j];
		}
	else if ((pw_select&0x0f)==0x03)
		for(j=0;j<3;j++){
			pw[4+j]=PW_WRITE3[j];
		}
	else if ((pw_select&0x0f)==0x04)
		for(j=0;j<3;j++){
			pw[4+j]=PW_WRITE4[j];
		}
	else if ((pw_select&0x0f)==0x05)
	   for(j=0;j<3;j++)
		  {pw[4+j]=PW_WRITE5[j];}
	else if ((pw_select&0x0f)==0x06)
	   for(j=0;j<3;j++)
		  {pw[4+j]=PW_WRITE6[j];}
	else
	   for(j=0;j<3;j++)
		  {pw[4+j]=PW_WRITE7[j];}

	for(j=0;j<3;j++){
		at88sc_gpa_clock(pw[4+j],0x05);
		pw[4+j]=GPA[0];
	}
	pw[0]=0xba;
	pw[1]=pw_select&0x0f;
	pw[2]=0x00;
	pw[3]=0x03;
	at88sc_write(pw);
	at88sc_ack_polling();

	pw[0]=0XB6;
	pw[1]=0X00;
	pw[2]=pw_select&0x0f;
	pw[2]=pw[2]*0x08;
	pw[2]=pw[2]+0xb0;
	pw[3]=0x01;
	at88sc_read(pw);
	at88sc_ack_polling();

	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(pw[2],0x01);
	at88sc_gpa_clock(0x00,0x05);
	at88sc_gpa_clock(0x01,0x01);
	pw[4]=pw[4]^GPA[0];
	at88sc_gpa_clock(pw[4],0x01);
	at88sc_gpa_clock(0x00,0x05);

	return pw[4];
}

/** 
* verify the user zone read password. 
* verify the user zone read password. 
* @param[in]   pw_select:read code num.
* @param[out]  noen.
* @retval  return 0xff:success, other:failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_verify_read_password(uint8_t pw_select){
	
	uint8_t j;
	uint8_t pw[7];
	if ((pw_select&0x0f)==0x00){
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ0[j];
		}
	}//{*(p+42+j)=PW_WRITE0[j];}}
	else if ((pw_select&0x0f)==0x01)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ1[j];
		}
	else if ((pw_select&0x0f)==0x02)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ2[j];
		}
	else if ((pw_select&0x0f)==0x03)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ3[j];
		}
	else if ((pw_select&0x0f)==0x04)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ4[j];
		}
	else if ((pw_select&0x0f)==0x05)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ5[j];
		}
	else if ((pw_select&0x0f)==0x06)
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ6[j];
		}
	else
		for(j=0;j<3;j++){
			pw[4+j]=PW_READ7[j];
		}

	for(j=0;j<3;j++){
		at88sc_gpa_clock(pw[4+j],0x05);//GPA[0]=pw[4+j];at88sc_gpa_clock(0x05);
		pw[4+j]=GPA[0];//*(p+42+j)=*(p+11);
	}
	pw[0]=0xba;//*(p+38)=0xba; //
	pw[1]=pw_select&0x0f;//*(p+39)=*(p+1)&0x0f;
	pw[1]=pw[1]+0x10;
	pw[2]=0x00;//*(p+40)=0x00;
	pw[3]=0x03;//*(p+41)=0x03;
	at88sc_write(pw);
	delay_ms(10);// delay_ms(1);delay_ms(1);

	pw[0]=0XB6;
	pw[1]=0X00;
	pw[2]=pw_select&0x0f;
	pw[2]=pw[2]*0x08;
	pw[2]=pw[2]+0xb4;
	pw[3]=0x01;
	at88sc_read(pw);

	at88sc_gpa_clock(0x00,0x05);//GPA[0]=0x00;at88sc_gpa_clock(5);
	at88sc_gpa_clock(pw[2],0x01);//GPA[0]=pw[2];at88sc_gpa_clock(1);
	at88sc_gpa_clock(0x00,0x05);//GPA[0]=0x00;at88sc_gpa_clock(5);
	at88sc_gpa_clock(0x01,0x01);//GPA[0]=0x01;at88sc_gpa_clock(1);

	pw[4]=pw[4]^GPA[0];
	at88sc_gpa_clock(pw[4],0x01);//GPA[0]=pw[4];at88sc_gpa_clock(1);
	at88sc_gpa_clock(0x00,0x05);//GPA[0]=0x00;at88sc_gpa_clock(5);

	return pw[4];
}

/** 
* select user zone by the parameter. 
* select user zone by the parameter. 
* @param[in]   zone:zone num.
* @param[out]  noen.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_select_user_zone(uint8_t zone){
	
	uint8_t zon[4];

	#if !defined(AT88SC_NO_NEED_AUTHENTICATION) && !defined(AT88SC_NO_NEED_PASSWORD)
	at88sc_gpa_clock(zone,0x01);
	#endif
	zon[0]=0xb4;
	zon[1]=0x03;
	zon[2]=zone;
	zon[3]=0x00;
	at88sc_write(zon);
	at88sc_ack_polling();
}

/** 
* read data from the user zone. 
* call this fuction before authentication & verify the password. 
* @param[in]   rd_high_addr:high 8 addr,rd_low_addr:low 8 addr,rd_number:read length, recv_ptr:reply data pointer.
* @param[out]  1:success,0:failed.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_read_user_zone(uint16_t addr,uint16_t rd_number,uint8_t *recv_ptr){
	
	if( rd_number<=READ_BUF_MAX_SIZE ){
		
		uint8_t j;
		uint8_t recv_buf[READ_BUF_MAX_SIZE+4];
		uint8_t rd_high_addr,rd_low_addr;
		
		rd_high_addr = addr>>8;
		rd_low_addr = addr&0xff;
		
		recv_buf[0]=0xb2;
		recv_buf[1]=rd_high_addr;
		recv_buf[2]=rd_low_addr;
		recv_buf[3]=rd_number;
		at88sc_read(recv_buf);
		at88sc_ack_polling();
		#if !defined(AT88SC_NO_NEED_AUTHENTICATION) && !defined(AT88SC_NO_NEED_PASSWORD)
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(rd_low_addr,0x01);
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(rd_number,0x01);
		for(j=0;j<rd_number;j++){
		
			recv_buf[4+j]=recv_buf[4+j]^GPA[0];
			at88sc_gpa_clock(recv_buf[4+j],0x01);
			at88sc_gpa_clock(0x00,0x05);
		}
		#endif
		memcpy(recv_ptr,&recv_buf[4],rd_number);
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* read data from the config zone. 
* read encryption data decode to original data. 
* @param[in]   rd_high_addr:high 8 addr,rd_low_addr:low 8 addr,rd_number:read length, recv_ptr:reply data pointer.
* @param[out]  1:success,0:failed.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_read_config_zone(unsigned char rd_high_addr,unsigned char rd_low_addr,unsigned char rd_number,uint8_t *recv_ptr){
	
	if( rd_number+4<=READ_BUF_MAX_SIZE ){
		
		unsigned char j;
		uint8_t send_buf[READ_BUF_MAX_SIZE];

		send_buf[0]=0xb6;
		send_buf[1]=rd_high_addr;
		send_buf[2]=rd_low_addr;
		send_buf[3]=rd_number;
		at88sc_read(send_buf);
		at88sc_ack_polling();

		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(rd_low_addr,0x01);
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(rd_number,0x01);

		for(j=0;j<rd_number;j++){
			
			if(rd_low_addr>=0xb0){
				send_buf[4+j]=send_buf[4+j]^GPA[0];}
			at88sc_gpa_clock(send_buf[4+j],0x01);
			at88sc_gpa_clock(0x00,0x05);
		}
		memcpy(recv_ptr,&send_buf[4],rd_number);
		
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* encryption to send at88sc. 
* encryption original data . 
* @param[in]   encryptodatanumber:data length,ptr:data pointer.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_encrypto_data(uint8_t encryptodatanumber,uint8_t *ptr){

	uint8_t j;
	uint8_t temp;
	for(j=0;j<encryptodatanumber;j++){
		
		at88sc_gpa_clock(0x00,0x05);
		temp=ptr[4+j];
		ptr[4+j]=ptr[4+j]^GPA[0];
		at88sc_gpa_clock(temp,0x01);
	}
}

/** 
* count protocol checksum. 
* count protocol checksum. 
* @param[in]   none.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_send_checksum(void){
	
	uint8_t dat6[6];

	dat6[0]=0xb4;
	dat6[1]=0x02;
	dat6[2]=0x00;
	dat6[3]=0x02;

	at88sc_gpa_clock(0x00,0x0f);
	dat6[4]=GPA[0];
	at88sc_gpa_clock(0x00,0x05);
	dat6[5]=GPA[0];

	at88sc_write(dat6);
}

/** 
* write data to user zone. 
* call this fuction before authentication & verify the password. 
* @param[in]   rd_high_addr:high 8 addr,rd_low_addr:low 8 addr,rd_number:read length, send_ptr:send data pointer.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_write_user_zone(uint16_t addr,uint8_t wr_number,uint8_t *send_ptr){
	
	if( wr_number<=WRITE_BUF_MAX_SIZE ){
		
		uint8_t send_buf[WRITE_BUF_MAX_SIZE+4];
		uint8_t wr_high_addr,wr_low_addr;
		
		wr_high_addr = addr>>8;
		wr_low_addr = addr&0xff;
		
		#if !defined(AT88SC_NO_NEED_AUTHENTICATION) && !defined(AT88SC_NO_NEED_PASSWORD)
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(wr_low_addr,0x01);
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(wr_number,0x01);
		#endif

		send_buf[0]=0xb0;
		send_buf[1]=wr_high_addr;
		send_buf[2]=wr_low_addr;
		send_buf[3]=wr_number;
		memcpy(&send_buf[4],send_ptr,wr_number);
		#if !defined(AT88SC_NO_NEED_AUTHENTICATION) && !defined(AT88SC_NO_NEED_PASSWORD)
		at88sc_encrypto_data(wr_number,send_buf);
		#endif
		at88sc_write(send_buf);
		delay_ms(5);
		at88sc_send_checksum();
		at88sc_ack_polling();
		
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* write data to config zone. 
* write data to config zone. 
* @param[in]   rd_high_addr:high 8 addr,rd_low_addr:low 8 addr,rd_number:read length, send_ptr:send data pointer.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_write_config_zone(uint8_t wr_high_addr,uint8_t wr_low_addr,uint8_t wr_number,uint8_t *send_ptr){
	
	if( wr_number+4 < WRITE_BUF_MAX_SIZE  ){
		
		uint8_t send_buf[WRITE_BUF_MAX_SIZE];
		uint8_t j;
		uint8_t temp;
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(wr_low_addr,0x01);
		at88sc_gpa_clock(0x00,0x05);
		at88sc_gpa_clock(wr_number,0x01);

		send_buf[0]=0xb4;
		send_buf[1]=wr_high_addr;
		send_buf[2]=wr_low_addr;
		send_buf[3]=wr_number;
		//at88sc_encrypto_data(wr_number);
		memcpy(&send_buf[4],send_ptr,wr_number);
		for(j=0;j<wr_number;j++){
			
			at88sc_gpa_clock(0x00,0x05);
			temp=send_buf[4+j];
			if(wr_low_addr>=0xb0){
				send_buf[4+j]=send_buf[4+j]^GPA[0];
			}
			at88sc_gpa_clock(temp,0x01);
		}

		at88sc_write(send_buf);
		delay_ms(5);
		at88sc_send_checksum();
		at88sc_ack_polling();
		
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* plaintext verify config zone sceure code. 
* for verify config passoword must after the chip reset,nor the case the verfiy well failed. 
* @param[in]   sc_first_byte:sc first byte,sc_second_byte:sc second byte,sc_third_byte: sc third byte.
* @param[out]  none.
* @retval  return 0xff:success, 0:failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_verify_sc_plaintext(uint8_t sc_first_byte,uint8_t sc_second_byte,uint8_t sc_third_byte){
	
	uint8_t scdata[7];
	scdata[0]=0xBA;
	scdata[1]=0x07;
	scdata[2]=0x00;
	scdata[3]=0x03;
	scdata[4]=sc_first_byte;
	scdata[5]=sc_second_byte;
	scdata[6]=sc_third_byte;
	at88sc_write(scdata);

	scdata[0]=0xb6;
	scdata[1]=0x00;
	scdata[2]=0xE8;
	scdata[3]=0x01;
	at88sc_read(scdata);
	return scdata[4];
}

/** 
* plaintext set user zone num. 
* plaintext set user zone num. 
* @param[in]   zonep:zone num.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
void at88sc_set_user_zone_plaintext(uint8_t zonep){
	
	uint8_t zon[4];
	zon[0]=0xb4;
	zon[1]=0x03;
	zon[2]=zonep;
	zon[3]=0x00;
	at88sc_write(zon);
}

/** 
* plaintext read data. 
* plaintext read data. 
* @param[in]   rd_cmd:command,A1:high 8byte,A2:low 8byte,N:length, recv_ptr:recvive pointer
* @param[out]  none.
* @retval  1:success 0:failed
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_read_paintext(uint8_t rd_cmd,uint8_t A1,uint8_t A2,uint8_t N, uint8_t *recv_ptr){
	
	if( N+4 < READ_BUF_MAX_SIZE  ){
		
		uint8_t send_buf[READ_BUF_MAX_SIZE];
		
		send_buf[0]=rd_cmd;//0xb2 or 0xb6
		send_buf[1]=A1;    //A1
		send_buf[2]=A2;    //A2
		send_buf[3]=N;     //N
		at88sc_read(send_buf);
		memcpy(recv_ptr,&send_buf[4],N);
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* plaintext write data. 
* plaintext write data. 
* @param[in]   rd_cmd:command,A1:high 8byte,A2:low 8byte,N:length, recv_ptr:send pointer
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint8_t at88sc_write_paintext(uint8_t wr_cmd,uint8_t A1,uint8_t A2,uint8_t N,uint8_t *send_ptr){
	
	if( N+4 < WRITE_BUF_MAX_SIZE  ){
		
		uint8_t send_buf[WRITE_BUF_MAX_SIZE];
		
		send_buf[0]=wr_cmd;//0xb0 or 0xb4
		send_buf[1]=A1;    //A1
		send_buf[2]=A2;    //A2
		send_buf[3]=N;     //N
		memcpy(&send_buf[4],send_ptr,N);
		at88sc_write(send_buf);
		
		return 1;
	}
	else{
		return 0;
	}
}

/** 
* at88sc write block. 
* send data support more than block size. 
* @param[in]   zone:block num,addr:user zone addr,len:read length,ptr:send data pointer.
* @param[out]  none.
* @retval  >0:send data length,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint16_t at88sc_write_user_block(uint8_t zone, uint16_t addr, uint16_t len, uint8_t *ptr){
	
	uint16_t 	send=0;
	uint16_t 	seg;
	uint8_t gc,pw;
	#if !defined(AT88SC_NO_NEED_AUTHENTICATION) && !defined(AT88SC_NO_NEED_PASSWORD)
	///<last use the block and this times use is the same, with no need for to do
	if( st88sc_sta.curr_use_block != zone ){
	
		gc = block_admini[zone]>>4;
		pw = block_admini[zone]&0x0f;
		
		if( at88sc_authentication(gc)!=0xff ){
			return 0;
		}
		else {
			if( at88sc_verify_write_password(pw)!=0xff  )
				return 0;
		}
		
		st88sc_sta.curr_use_block = zone;
	}
	#endif	
	if( addr+len <= AT88SC_BLOCK_SIZE ){
		
		at88sc_select_user_zone(zone);
		
		while( send<len ){
			
			if( len-send < WRITE_BUF_MAX_SIZE ){
				seg = (len-send);
			}
			else{
				seg = WRITE_BUF_MAX_SIZE;
			}
			
			if( addr/WRITE_BUF_MAX_SIZE != (addr+seg)/WRITE_BUF_MAX_SIZE )
				seg = WRITE_BUF_MAX_SIZE-addr%WRITE_BUF_MAX_SIZE;
			
			at88sc_write_user_zone(addr,seg,ptr);
			addr += seg;
			send += seg;
			ptr += seg;
			
			//for use in rtos, release system
			delay_ms(1);
		}
		return len;
	}
	else{
		return 0;
	}
}

/** 
* at88sc read block. 
* read data from the at88sc within a block. 
* @param[in]   zone:block num,addr:user zone addr,len:read length,ptr:save data pointer.
* @param[out]  none.
* @retval  >0:receive data length,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
uint16_t at88sc_read_user_block(uint8_t zone, uint16_t addr, uint16_t len, uint8_t *ptr){
	
	uint8_t gc,pw;
	uint16_t 	recv=0;
	uint16_t 	seg;
	///<last use the block and this times use is the same, with no need for to do
	if( st88sc_sta.curr_use_block != zone ){
	
		gc = block_admini[zone]>>4;
		pw = block_admini[zone]&0x0f;
		
		if( at88sc_authentication(gc)!=0xff ){
			return 0;
		}
		else {
			if( at88sc_verify_write_password(pw)!=0xff  )
				return 0;
		}
		
		st88sc_sta.curr_use_block = zone;
	}

	if( addr+len <= AT88SC_BLOCK_SIZE ){
		
		at88sc_select_user_zone(zone);
		while( recv<len ){
			
			if( len-recv < READ_BUF_MAX_SIZE ){
				seg = (len-recv);
			}
			else{
				seg = READ_BUF_MAX_SIZE;
			}
			
//			if( addr/READ_BUF_MAX_SIZE != (addr+seg)/READ_BUF_MAX_SIZE )
//				seg = READ_BUF_MAX_SIZE-addr%READ_BUF_MAX_SIZE;
			
			at88sc_read_user_zone(addr,seg,ptr);
			addr += seg;
			recv += seg;
			ptr += seg;
			
			//for use in rtos, release system
			delay_ms(1);
		}
		return len;
	}
	else{
		return 0;
	}
}

/** 
* read at88sc config register. 
* read config register into variate. 
* @param[in]   reg:contain address & read or write length,ptr:read data pointer.
* @param[out]  none.
* @retval  1:success,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-16 create
*/
uint8_t at88sc_read_config_register( uint16_t reg, uint8_t *ptr){
	
	uint8_t addr,len;
	addr = reg&0xff;
	len = reg>>8;	return at88sc_read_paintext(SYS_READ,0x00,addr,len,ptr); 
}

/** 
* write at88sc config register. 
* write config register from variate. 
* @param[in]   reg:contain address & read or write length,ptr:read data pointer.
* @param[out]  none.
* @retval  1:success,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-16 create
*/
uint8_t at88sc_write_config_register( uint16_t reg, uint8_t *ptr){
	
	uint8_t addr,len;
	addr = reg&0xff;
	len  = reg>>8;
	return at88sc_write_paintext(SYS_WRITE,0x00,addr,len,ptr); 
}

/** 
* write at88sc storage. 
* write at88sc all the block in continuous address,such as 0x0000-0x8000 for at88sc25616. 
* @param[in]   addr:write address,len:write length,ptr:write data pointer.
* @param[out]  none.
* @retval  >0:send data length,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-20 create
*/
uint16_t at88sc_write_storage(CARD_MANAGE_TypeDef *card_manage,  uint16_t addr, uint16_t len, uint8_t *ptr){
	
	uint16_t block_addr,write_len;
	uint16_t start_addr,count=0;
	uint8_t block_num;
	
	start_addr =  addr;
	
	if( addr+len <= AT88SC_STORAGE_SIZE ){
	
		while( count < len ){
			
			block_addr = start_addr%AT88SC_BLOCK_SIZE;
			block_num = start_addr/AT88SC_BLOCK_SIZE;
			
			write_len = AT88SC_BLOCK_SIZE-block_addr;
			
			if( write_len > (len-count) )
				write_len = len-count;
			
			at88sc_write_user_block(block_num, block_addr, write_len, ptr);
			
			count += write_len;
			start_addr += write_len;
			ptr += write_len;
			
		}
		
		return count;
	}
	else{
		return 0;
	}
}

/** 
* at88sc read storage. 
* read at88sc all the block in continuous address,such as 0x0000-0x8000 for at88sc25616. 
* @param[in]   addr:write address,len:write length,ptr:write data pointer.
* @param[out]  none.
* @retval  >0:receive data length,0: failed.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-20 create
*/
uint16_t at88sc_read_storage(CARD_MANAGE_TypeDef *card_manage, uint16_t addr, uint16_t len, uint8_t *ptr){
	
	uint16_t block_addr,write_len;
	uint16_t start_addr,count=0;
	uint8_t block_num;
	
	start_addr =  addr;
	
	if( addr+len <= AT88SC_STORAGE_SIZE ){
	
		while( count < len ){
			
			block_addr = start_addr%AT88SC_BLOCK_SIZE;
			block_num = start_addr/AT88SC_BLOCK_SIZE;
			
			write_len = AT88SC_BLOCK_SIZE-block_addr;
			
			if( write_len > (len-count) )
				write_len = len-count;
			
			at88sc_read_user_block(block_num, block_addr, write_len, ptr);
			
			count += write_len;
			start_addr += write_len;
			ptr += write_len;
			
		}
		
		return count;
	}
	else{
		return 0;
	}
}

/** 
* read at88sc fuse status. 
* read at88sc fuse status. 
* @param[in]   none.
* @param[out]  stata:return fuse state.
* @retval  none.
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-20 create
*/
void at88sc_read_fuse_state(uint8_t *state){
	
	uint8_t send_buf[READ_BUF_MAX_SIZE];
		
	send_buf[0]=SYS_READ;//0xb2 or 0xb6
	send_buf[1]=0x01;    //A1
	send_buf[2]=0x00;    //A2
	send_buf[3]=0x01;     //N
	at88sc_read(send_buf);
	
	*state = send_buf[4];
}


/** 
* at88sc initialize. 
* initialize i2c gpio, data struct. 
* @param[in]   none.
* @param[out]  none.
* @retval  none
* @par TAG 
*      reserved 
* @par other 
*      none 
* @par modify
*      ken 2018-11-15 create
*/
FUN_STATUS_T at88sc_init(void)
{
	AT88SC_GPIO_CLK_ENABLE();
	IIC_Initial();

	if(!at88sc_mtz_test()){      
	  
//		Error_Handler(SYSTEM_I2C_INIT_ERROR);
		return FUN_ERROR;
	}
	
	st88sc_sta.curr_use_block = 0xff;
	
	uint8_t state=0;
	static uint8_t vc_flag=0,wr_flag=0;
	uint8_t buf[128],temp[128];
	if( vc_flag )
		state = at88sc_verify_sc_plaintext(0x17,0xc3,0x3a);
//		state = at88sc_verify_sc_plaintext(0x05,0x05,0xc7);
	if( state>0 ){
		
		buf[0] = 0xaa;
		at88sc_write_config_register(DCR_R,buf);		///<ETA设为0 认证及密码校验不会错误计数
		
		at88sc_read_config_register(ATR_R,buf);
		at88sc_log("DCR_R %02X\r\n",buf[0]);
		
		buf[0] = 0xFF;
		at88sc_write_config_register(AR0_R,buf);
		at88sc_write_config_register(AR1_R,buf);
		at88sc_write_config_register(AR2_R,buf);
		at88sc_write_config_register(AR3_R,buf);
		at88sc_write_config_register(AR4_R,buf);
		at88sc_write_config_register(AR5_R,buf);
		at88sc_write_config_register(AR6_R,buf);
		at88sc_write_config_register(AR7_R,buf);
		
		at88sc_write_config_register(PACW0_R,buf);
		at88sc_write_config_register(PACW1_R,buf);
		at88sc_write_config_register(PACW2_R,buf);
		at88sc_write_config_register(PACW3_R,buf);
		at88sc_write_config_register(PACW4_R,buf);
		at88sc_write_config_register(PACW5_R,buf);
		at88sc_write_config_register(PACW6_R,buf);
		at88sc_write_config_register(PACW7_R,buf);
		
		buf[0] = 0x08;
		at88sc_write_config_register(PR0_R,buf);
		at88sc_write_config_register(PR1_R,buf);
		at88sc_write_config_register(PR2_R,buf);
		at88sc_write_config_register(PR3_R,buf);
		at88sc_write_config_register(PR4_R,buf);
		at88sc_write_config_register(PR5_R,buf);
		at88sc_write_config_register(PR6_R,buf);
		at88sc_write_config_register(PR7_R,buf);
		
		at88sc_write_config_register(SSG0_R,(uint8_t *)GC0);
		at88sc_write_config_register(SSG1_R,(uint8_t *)GC1);
		at88sc_write_config_register(SSG2_R,(uint8_t *)GC2);
		at88sc_write_config_register(SSG3_R,(uint8_t *)GC3);
		
		at88sc_write_config_register(W0_R,(uint8_t *)PW_WRITE0);
		at88sc_write_config_register(R0_R,(uint8_t *)PW_READ0);
		at88sc_write_config_register(W1_R,(uint8_t *)PW_WRITE1);
		at88sc_write_config_register(R1_R,(uint8_t *)PW_READ1);
		at88sc_write_config_register(W2_R,(uint8_t *)PW_WRITE2);
		at88sc_write_config_register(R2_R,(uint8_t *)PW_READ2);
		at88sc_write_config_register(W3_R,(uint8_t *)PW_WRITE3);
		at88sc_write_config_register(R3_R,(uint8_t *)PW_READ3);
		at88sc_write_config_register(W4_R,(uint8_t *)PW_WRITE4);
		at88sc_write_config_register(R4_R,(uint8_t *)PW_READ4);
		at88sc_write_config_register(W5_R,(uint8_t *)PW_WRITE5);
		at88sc_write_config_register(R5_R,(uint8_t *)PW_READ5);
		at88sc_write_config_register(W6_R,(uint8_t *)PW_WRITE6);
		at88sc_write_config_register(R6_R,(uint8_t *)PW_READ6);
//		at88sc_write_config_register(W7_R,(uint8_t *)PW_WRITE7);
		at88sc_write_config_register(R7_R,(uint8_t *)PW_READ7);
		
		at88sc_read_config_register(SSG0_R,buf);
		at88sc_log("SSG0 ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG1_R,buf);
		at88sc_log("SSG1 ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG2_R,buf);
		at88sc_log("SSG2 ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG3_R,buf);
		at88sc_log("SSG3 ");
		at88sc_dump(buf,8);
		
		at88sc_read_config_register(W0_R,buf);
		at88sc_log("W0 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R0_R,buf);
		at88sc_log("R0 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W1_R,buf);
		at88sc_log("W1 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R1_R,buf);
		at88sc_log("R1 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W2_R,buf);
		at88sc_log("W2 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R2_R,buf);
		at88sc_log("R2 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W3_R,buf);
		at88sc_log("W3 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R3_R,buf);
		at88sc_log("R3 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W4_R,buf);
		at88sc_log("W4 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R4_R,buf);
		at88sc_log("R4 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W5_R,buf);
		at88sc_log("W5 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R5_R,buf);
		at88sc_log("R5 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W6_R,buf);
		at88sc_log("W6 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R6_R,buf);
		at88sc_log("R6 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W7_R,buf);
		at88sc_log("W7 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(R7_R,buf);
		at88sc_log("R7 ");
		at88sc_dump(buf,3);
		
//		at88sc_read_config_register(SSG0_R,buf)
//		at88sc_log("SSG0 %02X\r\n",buf[0]);
//		at88sc_read_config_register(SSG1_R,buf);
//		at88sc_log("SSG1 %02X\r\n",buf[0]);
//		at88sc_read_config_register(SSG2_R,buf);
//		at88sc_log("SSG2 %02X\r\n",buf[0]);
//		at88sc_read_config_register(SSG3_R,buf);
//		at88sc_log("SSG3 %02X\r\n",buf[0]);
		
//		buf[0]=0xff;
//		at88sc_write_config_register(AR0_R,buf);
//		at88sc_write_config_register(AR1_R,buf);
//		at88sc_write_config_register(AR2_R,buf);
//		at88sc_write_config_register(AR3_R,buf);
		
		at88sc_log("printf AT88SC register\r\n");
		
		at88sc_read_config_register(DCR_R,buf);
		at88sc_log("DCR_R %02X\r\n",buf[0]);
		
		at88sc_read_config_register(SSG0_R,buf);
		at88sc_log("SSG0_R ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG1_R,buf);
		at88sc_log("SSG1_R ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG2_R,buf);
		at88sc_log("SSG2_R ");
		at88sc_dump(buf,8);
		at88sc_read_config_register(SSG3_R,buf);
		at88sc_log("SSG3_R ");
		at88sc_dump(buf,8);
		
		at88sc_read_config_register(AR0_R,buf);
		at88sc_log("AR0 %02X\r\n",buf[0]);
		at88sc_read_config_register(PR0_R,buf);
		at88sc_log("PR0 %02X\r\n",buf[0]);
		at88sc_read_config_register(AR1_R,buf);
		at88sc_log("AR1 %02X\r\n",buf[0]);
		at88sc_read_config_register(PR1_R,buf);
		at88sc_log("PR1 %02X\r\n",buf[0]);
		at88sc_read_config_register(AR2_R,buf);
		at88sc_log("AR2 %02X\r\n",buf[0]);
		at88sc_read_config_register(PR2_R,buf);
		at88sc_log("PR2 %02X\r\n",buf[0]);
		at88sc_read_config_register(AR3_R,buf);
		at88sc_log("AR3 %02X\r\n",buf[0]);
		at88sc_read_config_register(PR3_R,buf);
		at88sc_log("PR3 %02X\r\n",buf[0]);
		
		at88sc_read_config_register(PACW0_R,buf);
		at88sc_log("PACW0 %02X\r\n",buf[0]);
		at88sc_read_config_register(PACW1_R,buf);
		at88sc_log("PACW1 %02X\r\n",buf[0]);
		at88sc_read_config_register(PACW2_R,buf);
		at88sc_log("PACW2 %02X\r\n",buf[0]);
		at88sc_read_config_register(PACW3_R,buf);
		at88sc_log("PACW3 %02X\r\n",buf[0]);
		
		at88sc_read_config_register(W0_R,buf);
		at88sc_log("W0 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W1_R,buf);
		at88sc_log("W1 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W2_R,buf);
		at88sc_log("W2 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W3_R,buf);
		at88sc_log("W3 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W4_R,buf);
		at88sc_log("W4 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W5_R,buf);
		at88sc_log("W5 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W6_R,buf);
		at88sc_log("W6 ");
		at88sc_dump(buf,3);
		at88sc_read_config_register(W6_R,buf);
		at88sc_log("W7 ");
		at88sc_dump(buf,3);
		
		buf[0]=0xff;
		at88sc_write_config_register(AAC0_R,buf);
		at88sc_read_config_register(AAC0_R,buf);
		at88sc_log("AAC0 %02X\r\n",buf[0]);
		at88sc_read_config_register(AAC1_R,buf);
		at88sc_log("AAC1 %02X\r\n",buf[0]);
		at88sc_read_config_register(AAC2_R,buf);
		at88sc_log("AAC2 %02X\r\n",buf[0]);
		at88sc_read_config_register(AAC3_R,buf);
		at88sc_log("AAC3 %02X\r\n",buf[0]);
	}
	if( wr_flag ){
		for( uint16_t i=0; i<128; i++ )
			buf[i] = i;
		at88sc_write_storage(NULL,0, 128, buf);
		memset(buf,0,128);
		st88sc_sta.curr_use_block = 0xff;
		at88sc_read_storage(NULL,0, 128, buf);
		at88sc_log("read data ");
		at88sc_dump(&buf[0],32);
		at88sc_dump(&buf[32],32);
		at88sc_dump(&buf[64],32);
		at88sc_dump(&buf[96],32);
	}
	
	sys_status.have_sc_eeprom = 1;
	
	return FUN_OK;
//	while(1);
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵向深耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值