/*****************************************************************************
* File Name          : ISO14443B_Category.c
* Author             : CrystalSu
* Version            : V1.0.0.0
* Date               : Feb 14, 2020
* Description        : 
*                         - ISO14443B_EMV_Load_Modulation
*                         - ISO14443B_Transparent_Configure_CRC
*                         - ISO14443B_Transparent_With_RxMultiple
******************************************************************************/   

#include "BC45_Board_Define.h"
#include "Common_Utility_Category.h"
#include "ISO14443B_Category.h"
#include "BC45_Chip_Function.h"
#include "Delay.h"
#include "ISO14443A_Category.h"
	/* Refer to following functions in ISO14443B_EMV_Load_Modulation();
		- ISO14443A_Config
		- ISO14443A_WakeUp
	*/

// Global variable 
tISO14443B_Property  ISO14443B_Property ;

/*******************************************************************************
* Function Name : ISO14443B_Command
* Description   : Perform 
*				  	- air interface commands following ISO14443B
*					- setting up ISO14443B configuration
*					- setting and getting RF communication speed
*			
* Input         : 	- Command : Commands associated to ISO14443B as shown in source below 
*					- Param	: Parameters associated to command as shown in source below (after CMD_TYPE)
*					- LenParam : Length of input parameters
* Output        : 
*					- Data_Resp	: Reponse from operation the command
*					- LenData_Resp : Length of output response
* Return        : 
*				   - Response : Result from operating the function
*				 	 	- _SUCCESS_ 
*						- NO_RESPONSE
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- INVALID_RESP
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_Command( uint8_t Command, uint8_t *Param, uint16_t LenParam, uint8_t *Data_Resp, uint16_t *LenData_Resp )
{
	//uint16_t  i ;
	uint8_t   Resp ;
	uint8_t   temp_Slot ;
	uint8_t   AFI, Num_Slots_N ; //, temp_UID[10] ;
	uint16_t  temp_LenHigher_Layer ;

	switch(Command)
	{
		case B_Config_ISO14443B :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + LRC									
								ISO14443B_Property.Speed = 0x00 ;
								Resp = ISO14443B_Config( 0x00 ) ;
								*(LenData_Resp) = 0 ; 
		break ;

		case B_Config_Speed_Reader :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + Speed_Sel + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + LRC									
								if ( LenParam >= 1 )
								{ 
									ISO14443B_Property.Speed = *( Param ) ;
									BC45_Speed_14443B( ISO14443B_Property.Speed ) ;
									Resp = _SUCCESS_ ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
								}
								*(LenData_Resp) = 0 ; 
		break ;

		case B_Get_Speed_Reader : // Speed at Reader
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + Speed + LRC									
								Resp = ISO14443B_Get_Speed_Reader( Data_Resp, LenData_Resp ) ;
		break ;

		case B_SOFEOF_Sel :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + AFI + Number_of_Slots + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 1 )
								{ 
									BC45_SOFEOF_Selection( *(Param) ) ;
									Resp = _SUCCESS_ ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
								}
								*(LenData_Resp) = 0 ; 
		break ;
		
		case B_Request :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + AFI + Number_of_Slots + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 2 )
								{ 
									AFI = *( Param ) ;
									Num_Slots_N = *( Param + 1 ) ;
									Resp = ISO14443B_Request( AFI, Num_Slots_N, &temp_Slot, Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;

		case B_WakeUp :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + AFI + Number_of_Slots + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 2 )
								{ 
									AFI = *( Param ) ;
									Num_Slots_N = *( Param + 1 ) ;
									Resp = ISO14443B_WakeUp( AFI, Num_Slots_N, &temp_Slot, Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;
		
		case B_ATTRIB :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + PUPI[0] + ... + PUPI[3] + Param[0] + ... + Param[3] + Higher_Layer[0] + ... + Higher_Layer[n-1] ( Optional ) + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 8 ) // PUPI( 4 Bytes ) + Param( 4 Bytes ) = 8 Bytes
								{ 
									temp_LenHigher_Layer = LenParam - 8 ;
									Resp = ISO14443B_ATTRIB( Param, ( Param + 4 ), ( Param + 8 ), temp_LenHigher_Layer, Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;

		case B_Halt :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + PUPI[0] + ... + PUPI[3] + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 4 ) // PUPI( 4 Bytes ) = 4 Bytes
								{ 
									Resp = ISO14443B_Halt( Param, Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;
                //--------------------------------------------------  Combo -------------------------------------------------------------------------------------	  
                case B_WakeUp_ATTRIB :
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + AFI + Param[1] + ... + Param[3] + + Higher_Layer[0] + ... + Higher_Layer[n-1] ( Optional )  + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
								if ( LenParam >= 5 )
								{ 
									AFI = *( Param ) ;
									temp_LenHigher_Layer = LenParam - 5 ;
									Resp = ISO14443B_WakeUp_ATTRIB ( AFI, (Param + 1) , (Param + 5) , temp_LenHigher_Layer , Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;
		               
                //--------------------------------------------------  EMV Cmd -------------------------------------------------------------------------------------	  
                case B_EMV_Load_Modulation : 
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + Reset_Field_En + Run_All_Step + CMD_Category + First_Step + No_Of_Step + LRC
								// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + + CMD_TYPE + FBP_CMD + Last_Step + FF FF + 01 + Len[1] + Resp_Index[1] + Data_Index[1][0 - Len[1]]
                                                                // + FF FF + 02 + Len[2] + Resp_Index[2] + Data_Index[2][0 - Len[2]] + ... 
								// ... + FF FF + Step_Index[N] + Len[N] + Resp_Index[N] + Data_Index[N][0 - Len[N]] +  LRC                  
								if ( LenParam >= 5 )
								{ 
									Resp = ISO14443B_EMV_Load_Modulation (*( Param ), *( Param + 1), *( Param + 2) , *( Param + 3) , *( Param + 4) , Data_Resp, LenData_Resp ) ;
								}
								else
								{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
								}
		break ;  
                

		case B_Transparent_With_CRC :
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD  + TimeOut + Data_Tx[0] + ... + Data_Tx[n + 1] + LRC
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
					if ( LenParam >= 2 ) 
					{ 
						Resp = Transparent_With_CRC( (Param + 1), (LenParam - 1), *(Param), Data_Resp, LenData_Resp ) ;
					}
					else
					{
						Resp = PARAMETER_NOT_CORRECT ;
						*(LenData_Resp) = 0 ; 
					}
					break ;

		case B_Transparent_Without_CRC :
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + TimeOut + Data_Tx[0] + ... + Data_Tx[n + 1] + LRC
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
					if ( LenParam >= 2 ) 
					{ 
						Resp = Transparent_Without_CRC( (Param + 1), (LenParam - 1), *(Param), Data_Resp, LenData_Resp ) ;
					}
					else
					{
						Resp = PARAMETER_NOT_CORRECT ;
						*(LenData_Resp) = 0 ; 
					}
					break ;

                
		case  B_Transparent_Config_CRC :                
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + CMD + TimeOut + TxCRCEn + RxCRCEn + Data_Tx[0] + ... + Data_Tx[n + 1] + LRC
					// SOP + LEN_H + LEN_L + SEQ_NUM + DEV_ID + CMD_TYPE + FBP_CMD + RESP + DATA[0] + ... + DATA[N-1] + LRC									
					if ( LenParam >= 4 ) 
					{ 
						Resp = Transparent_Configure_CRC( *(Param + 1), *(Param + 2), (Param + 3), (LenParam - 3), *(Param), Data_Resp, LenData_Resp ) ;
					}
					else
					{
						Resp = PARAMETER_NOT_CORRECT ;
						*(LenData_Resp) = 0 ; 
					}
                
					break;  

		case  B_Transparent_With_RxMultiple :                
					if ( LenParam >= 2 ) 
					{ 
								Resp = Transparent_With_RxMultiple( (Param + 1),  (LenParam - 1), *(Param), Data_Resp, LenData_Resp ) ;
					}
					else
					{
									Resp = PARAMETER_NOT_CORRECT ;
									*(LenData_Resp) = 0 ; 
					}
					break;  
                
		default :
					Resp = UNKNOWN_CMD ;
					*(LenData_Resp) = 0 ; 
		break ;
	}

	return Resp ;
}

/*******************************************************************************
* Function Name : ISO14443B_Config
* Description   : Configure Registers and RF-Communication speed for ISO14443B Operation
* Input         : 
*				  - Speed : Tx_Speed(4 bits) + RxSpeed(4 bits)	
*						High Nibble = Tx_Speed(Bit7:4)
*							- 0000b = 106 kbps
*							- 0001b = 212 kbps		
*							- 0010b = 424 kbps		
*							- 0011b = 848 kbps		
*							- Other = 106 kbps		
*						Low Nibble = Rx_Speed(Bit3:0)
*							- 0000b = 106 kbps
*							- 0001b = 212 kbps		
*							- 0010b = 424 kbps		
*							- 0011b = 848 kbps		
*							- Other = 106 kbps		
* Output        : None
* Return        : 
*				  - Response :
*				 		- _SUCCESS_ 
*******************************************************************************/
uint8_t ISO14443B_Config( uint8_t Speed ) 
{
	BC45_Config_14443B() ;
	BC45_Speed_14443B( Speed ) ;
	
	// ON Field
	BC45_ON_RF( BC45_BOARD_PROPERTY.Driver_Config_Type ) ;
	Delay_ms ( 5 ) ;
	
	return _SUCCESS_ ;
} 

/*******************************************************************************
* Function Name	: ISO14443B_Get_Speed_Reader
* Description 	: Return current RF-Speed setting
* Input         : None
* Output        : 
*				  - Speed : Tx_Speed(4 bits) + RxSpeed(4 bits)	
*						High Nibble = Tx_Speed(Bit7:4)
*							- 0000b = 106 kbps
*							- 0001b = 212 kbps		
*							- 0010b = 424 kbps		
*							- 0011b = 848 kbps		
*							- Other = 106 kbps		
*						Low Nibble = Rx_Speed(Bit3:0)
*							- 0000b = 106 kbps
*							- 0001b = 212 kbps		
*							- 0010b = 424 kbps		
*							- 0011b = 848 kbps		
*							- Other = 106 kbps		
*				: - LenSpeed : Length of output, always = 1
* Return        : 
*				  - Response :
*						- _SUCCESS_ 
*******************************************************************************/
uint8_t ISO14443B_Get_Speed_Reader( uint8_t *Speed, uint16_t *LenSpeed )
{	 
	*( Speed )    = ISO14443B_Property.Speed ;
	*( LenSpeed ) = 1 ;

	return _SUCCESS_ ;	
}

/*******************************************************************************
* Function Name	: ISO14443B_Request
* Description 	: Perform Request command in ISO14443B standard
* Input         : None
*				  - AFI : Application family identifier 
*				  - Num_Slots_N : Number of slots
*						- 0x00 : 2^0 = 1 Slots
*						- 0x01 : 2^1 = 2 Slots
*						- 0x02 : 2^2 = 4 Slots
*						- 0x03 : 2^3 = 8 Slots
*						- 0x04 : 2^4 = 16 Slots
*						- Other : 16 Slots
* Output		: 
*				  - Slot_Num : The number of First slot that card is found
*				  - Data_Resp : Response data
*						- if Response = _SUCCESS_
*							- 1st to Last byte : Response data from Request command
*						- if Response = FRAMING_ERR or COLLISION_ERR or PARITY_ERR or CRC_ERR or INVALID_RESP (RF_COMMU_ERR_CATEGORY)
*							- 1st to Last byte : Error data in BC45 FIFO (if it exists)
*						- Other (NO_RESPONSE, ASIC_EXE_TIMEOUT)
*							- No Response data  
*				  - LenData_Resp : Length of Response data
* Return        : 
*				  - Response
*						- _SUCCESS_ 		
*						- NO_RESPONSE   	
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- INVALID_RESP
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_Request( uint8_t AFI, uint8_t Num_Slots_N, uint8_t *Slot_Num, uint8_t *Data_Resp, uint16_t *LenData_Resp ) 
{
	uint16_t  i ;
	uint8_t   Resp ;
	uint8_t   Number_of_Slots ;
	uint8_t   Slot_Marker ;

	Number_of_Slots = 1 ;

	if( Num_Slots_N > 4 )
	{	
		Num_Slots_N = 4 ;	
	}
	
	for ( i = 0 ; i < Num_Slots_N ; i++ )
	{	
		Number_of_Slots = 2 * Number_of_Slots ;	
	}
	
	Data_TxRF[0] = 0x05 ; // Prefix byte APf
	Data_TxRF[1] = AFI ;  // AFI if = 0x00 all tag proccess the REQB/WUPB
	Data_TxRF[2] = ( 0x00 | Num_Slots_N ) ; // PARAM (bit4 select REQB(0) or WUPB(1) ,bit 1-3 (Number of slots))
		
	BC45_CRC_Setting( TxCRC_Enable, RxCRC_Enable ) ;

	Resp = BC45_Transceive( &Data_TxRF[0], 3, &Data_RxRF[0], &LenData_RxRF ) ;	

	Slot_Marker = 2 ;
	while ( ( Slot_Marker <= Number_of_Slots ) && ( Resp !=  _SUCCESS_ ) )
	{
		Data_TxRF[0] = ( ( (Slot_Marker - 1) << 4 ) | 0x05 ) ; // APn
		Resp = BC45_Transceive( &Data_TxRF[0], 1, &Data_RxRF[0], &LenData_RxRF ) ;	
		Slot_Marker ++ ;		
		Delay_ms(3); // (128*250)/fc = 2.35ms
	};

	if( Resp == _SUCCESS_ )
	{	
		if ( LenData_RxRF == LEN_ISO14443B_REQUEST_RF_RESP )
		{
			*( Slot_Num ) = Slot_Marker - 1 ;	
			*(LenData_Resp) = LenData_RxRF - 1 ;	
			for( i = 0 ; i < LenData_RxRF - 1  ; i++ )
			{
				*( Data_Resp + i ) = Data_RxRF[i + 1] ;		
			}
		}
		else
		{
			Resp = INVALID_RESP ;
			*( Slot_Num ) = Slot_Marker - 1 ;	
			*(LenData_Resp) = LenData_RxRF ;	
			for( i = 0 ; i < LenData_RxRF ; i++ )
			{
				*( Data_Resp + i ) = Data_RxRF[i] ;		
			}
		}
	}
	else // RF Error
	{
		*( Slot_Num ) = 0x00 ;		
		*(LenData_Resp) = LenData_RxRF ;	
		for( i = 0 ; i < LenData_RxRF ; i++ )
		{
			*( Data_Resp + i ) = Data_RxRF[i] ;		
		}
	}

	return Resp ;
} 

/*******************************************************************************
* Function Name	: ISO14443B_WakeUp
* Description 	: Perform Wakeup command in ISO14443B standard
* Input         : None
*				  - AFI : Application family identifier 
*				  - Num_Slots_N : Number of slots
*						- 0x00 : 2^0 = 1 Slot
*						- 0x01 : 2^1 = 2 Slots
*						- 0x02 : 2^2 = 4 Slots
*						- 0x03 : 2^3 = 8 Slots
*						- 0x04 : 2^4 = 16 Slots
*						- Other : 16 Slots
* Output		: 
*				  - Slot_Num : The number of First slot that card is found
*				  - Data_Resp : Response data
*						- if Response = _SUCCESS_
*							- 1st to Last byte : Response data from Wakeup command
*						- if Response = FRAMING_ERR or COLLISION_ERR or PARITY_ERR or CRC_ERR or INVALID_RESP (RF_COMMU_ERR_CATEGORY)
*							- 1st to Last byte : Error data in BC45 FIFO (if it exists)
*						- Other (NO_RESPONSE, ASIC_EXE_TIMEOUT)
*							- No Response data  
*				  - LenData_Resp : Length of Response data
* Return        : 
*				  - Response
*						- _SUCCESS_ 		
*						- NO_RESPONSE   	
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- INVALID_RESP
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_WakeUp( uint8_t AFI, uint8_t Num_Slots_N, uint8_t *Slot_Num, uint8_t *Data_Resp, uint16_t *LenData_Resp ) 
{
	uint16_t  i ;
	uint8_t   Resp ;
	uint8_t   Number_of_Slots ;
	uint8_t   Slot_Marker ;

	Number_of_Slots = 1 ;

	if( Num_Slots_N > 4 )
	{	
		Num_Slots_N = 4 ;	
	}
	
	for ( i = 0 ; i < Num_Slots_N ; i++ )
	{	
		Number_of_Slots = 2 * Number_of_Slots ;	
	}
	
	Data_TxRF[0] = 0x05 ; // Prefix byte APf
	Data_TxRF[1] = AFI ;  // AFI if = 0x00 all tag proccess the REQB/WUPB
	Data_TxRF[2] = ( 0x08 | Num_Slots_N ) ; // PARAM (bit4 select REQB(0) or WUPB(1) ,bit 1-3 (Number of slots))
		
	BC45_CRC_Setting( TxCRC_Enable, RxCRC_Enable ) ;

	Resp = BC45_Transceive( &Data_TxRF[0], 3, &Data_RxRF[0], &LenData_RxRF ) ;	

	Slot_Marker = 2 ;
	while ( ( Slot_Marker <= Number_of_Slots ) && ( Resp !=  _SUCCESS_ ) )
	{
		Data_TxRF[0] = ( ( (Slot_Marker - 1) << 4 ) | 0x05 ) ; // APn
		Resp = BC45_Transceive( &Data_TxRF[0], 1, &Data_RxRF[0], &LenData_RxRF ) ;	
		Slot_Marker ++ ;		
		Delay_ms(3); // (128*250)/fc = 2.35ms
	};

	if( Resp == _SUCCESS_ )
	{	
		if ( LenData_RxRF == LEN_ISO14443B_WAKEUP_RF_RESP )
		{
			*( Slot_Num ) = Slot_Marker - 1 ;	
			*(LenData_Resp) = LenData_RxRF - 1 ;	
			for( i = 0 ; i < LenData_RxRF - 1  ; i++ )
			{
				*( Data_Resp + i ) = Data_RxRF[i + 1] ;		
			}
		}
		else
		{
			Resp = INVALID_RESP ;
			*( Slot_Num ) = Slot_Marker - 1 ;	
			*(LenData_Resp) = LenData_RxRF ;	
			for( i = 0 ; i < LenData_RxRF ; i++ )
			{
				*( Data_Resp + i ) = Data_RxRF[i] ;		
			}
		}
	}
	else // RF Error
	{
		*( Slot_Num ) = 0x00 ;		
		*(LenData_Resp) = LenData_RxRF ;	
		for( i = 0 ; i < LenData_RxRF ; i++ )
		{
			*( Data_Resp + i ) = Data_RxRF[i] ;		
		}
	}

	return Resp ;
}

/*******************************************************************************
* Function Name	: ISO14443B_ATTRIB
* Description 	: Perform ATTRIB command in ISO14443B standard
* Input         : 
*				  - PUPI : Pseudo-Unique PICC Identifier (4 bytes)
*				  - Param : 4-bytes parameter following ISO14443B
*				  - Higher_Layer : Higher layer information following ISO14443B
* Output        : 
*				  - Data_Resp : Response data
*						- if Response = _SUCCESS_
*							- 1st to Last byte : Response data from ATTRIB command
*						- if Response = FRAMING_ERR or COLLISION_ERR or PARITY_ERR or CRC_ERR (RF_COMMU_ERR_CATEGORY)
*							- 1st to Last byte : Error data in BC45 FIFO (if it exists)
*						- Other (ASIC_EXE_TIMEOUT)
*							- No Response data  
*				  - LenData_Resp : Length of Response data
* Return        : 
*				  - Response
*						- _SUCCESS_ 		
*						- NO_RESPONSE   	
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_ATTRIB( uint8_t *PUPI, uint8_t *Param, uint8_t *Higher_Layer, uint16_t LenHigher_Layer, uint8_t *Data_Resp, uint16_t *LenData_Resp )
{	
	uint16_t  i ;
	uint8_t   Resp ;

	Data_TxRF[0] = 0x1D ; // ATTRIB cmd
	for ( i = 0 ; i < 4 ; i++ )
	{	// PUPI 4 Byte
		Data_TxRF[i + 1] = *( PUPI + i ) ;	
	}	

	for ( i = 0 ; i < 4 ; i++ )
	{	// Param 1-4
		Data_TxRF[i + 5] = *( Param + i ) ;	
	}	

	LenData_TxRF = 9 ; 

	for ( i = 0 ; i < LenHigher_Layer ; i++ )
	{	// Higher Layer
		Data_TxRF[LenData_TxRF++] = *( Higher_Layer + i ) ;	
	}	

	BC45_CRC_Setting( TxCRC_Enable, RxCRC_Enable ) ;

	Resp = BC45_Transceive( &Data_TxRF[0], LenData_TxRF, &Data_RxRF[0], &LenData_RxRF ) ;	

	*( LenData_Resp ) = LenData_RxRF ;
	for ( i = 0 ; i < LenData_RxRF ; i++ )
	{
		*( Data_Resp + i ) = Data_RxRF[i] ;
	}

	return Resp ;
}


/*******************************************************************************
* Function Name	: ISO14443B_Halt
* Description 	: Perform Halt command in ISO14443B standard
* Input         :
*				  - PUPI : Pseudo-Unique PICC Identifier (4 bytes)
* Output        : 
*				  - Data_Resp : Response data
*						- if Response = _SUCCESS_
*							- 1st to Last byte : Response data from Halt command
*						- if Response = FRAMING_ERR or COLLISION_ERR or PARITY_ERR or CRC_ERR (RF_COMMU_ERR_CATEGORY)
*							- 1st to Last byte : Error data in BC45 FIFO (if it exists)
*						- Other (ASIC_EXE_TIMEOUT)
*							- No Response data  
*				  - LenData_Resp : Length of Response data
* Return        : 
*				  - Response
*						- _SUCCESS_ 		
*						- NO_RESPONSE   	
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_Halt( uint8_t *PUPI, uint8_t *Data_Resp, uint16_t *LenData_Resp )
{	
	uint16_t  i ;
	uint8_t   Resp ;

	Data_TxRF[0] = 0x50 ; // HLTB Cmd	
	
	for ( i = 0 ; i < 4 ; i++ )
	{	// PUPI 4 Bytes
		Data_TxRF[i + 1] = *( PUPI + i ) ;	
	}	

	BC45_CRC_Setting( TxCRC_Enable, RxCRC_Enable ) ;

	Resp = BC45_Transceive( &Data_TxRF[0], 5, &Data_RxRF[0], &LenData_RxRF ) ;	

	*( LenData_Resp ) = LenData_RxRF ;
	for ( i = 0 ; i < LenData_RxRF ; i++ )
	{
		*( Data_Resp + i ) = Data_RxRF[i] ;
	}

	return Resp ;
}



/*******************************************************************************
* Function Name	: ISO14443B_WakeUp_ATTRIB
* Description 	: Perform Wakeup command and ATTRIB in ISO14443B standard with fixing parameter
*                                 - Num_Slot = 0x00
* Input         : None
*				  - AFI : Application family identifier 
*				  - Param : 4-bytes parameter following ISO14443B
*				  - Higher_Layer : Higher layer information following ISO14443B
* Output		: 
*				  - Data_Resp : Response data
*						- if Response = _SUCCESS_
*							- 1st to 11th byte : Response data from Wakeup command
*                                                       - 12th to Last byte : Response data from ATTRIB command
*						- if Response = FRAMING_ERR or COLLISION_ERR or PARITY_ERR or CRC_ERR or INVALID_RESP (RF_COMMU_ERR_CATEGORY)
*							- 1st byte         : Error index
*							- 2nd to Last byte : Error data in BC45 FIFO (if it exists)
*						- Other (NO_RESPONSE, ASIC_EXE_TIMEOUT)
*							- No Response data  
*				  - LenData_Resp : Length of Response data
* Return        : 
*				  - Response
*						- _SUCCESS_ 		
*						- NO_RESPONSE   	
*						- FRAMING_ERR
*						- COLLISION_ERR
*						- PARITY_ERR
*						- CRC_ERR
*						- INVALID_RESP
*						- ASIC_EXE_TIMEOUT  
*******************************************************************************/
uint8_t ISO14443B_WakeUp_ATTRIB ( uint8_t AFI, uint8_t *Param , uint8_t *Higher_Layer, uint16_t LenHigher_Layer , uint8_t *Data_Resp, uint16_t *LenData_Resp ) 
{
	uint8_t   i ;
	uint8_t   Resp ;
	uint8_t   Err_Index, Slot_Num_Temp ;
        uint8_t   temp_Data_Resp[32] ;
        uint16_t  temp_LenData_Resp;
	uint8_t   PUPI[4];

        Err_Index = 0 ;
               
        Resp = ISO14443B_WakeUp( AFI, 0x00, &Slot_Num_Temp , &temp_Data_Resp[0], &temp_LenData_Resp );

        if ( Resp == _SUCCESS_ )
        {
                Err_Index = 1 ;
                for ( i = 0 ; i < 4 ; i ++ )
                {
                    PUPI[i] = temp_Data_Resp[i];
                }
                
                Resp =  ISO14443B_ATTRIB( &PUPI[0] , Param, Higher_Layer, LenHigher_Layer, &Data_RxRF[0] , &LenData_RxRF ) ;
                if ( Resp != _SUCCESS_ )
                {
                    temp_LenData_Resp = 0  ;    
                }
                
                for ( i = 0 ; i < LenData_RxRF ; i ++ )
                {
                    temp_Data_Resp[temp_LenData_Resp + i] = Data_RxRF[i] ;
                }
                temp_LenData_Resp = LenData_RxRF + temp_LenData_Resp ;
                
        }
               
	
        if ( Resp == _SUCCESS_ ) // Return 
	{	
		 for ( i = 0 ; i < temp_LenData_Resp ; i ++ )
                 {
                        *( Data_Resp + i ) = temp_Data_Resp[i] ;
                 }
                 *( LenData_Resp ) = temp_LenData_Resp ;
	}
	else
	{
		*( Data_Resp ) = Err_Index ; // Err Location
		for ( i = 0 ; i < temp_LenData_Resp ; i++ )
		{
			*( Data_Resp + i + 1 ) = temp_Data_Resp[i] ;	
		}
		*( LenData_Resp ) = temp_LenData_Resp + 1 ; // Index + Err data in BC45 FIFO
	}
	
	return Resp ;
}

/*******************************************************************************
* Function Name	: ISO14443B_EMV_Load_Modulation
* Description 	: 
* Input         : 
*				  - Reset_Field_En : Enable Field Reset before starting sequence command
*				  - Run_All_Step   : 1 - Run All command following Number of Steps
*                                                  : 0 - Run until Error occur
*                                 - CMD_Category   : CMD Sequence
*                                             00   : 1 - WUPB // 2 - WUPA // 3 - WUPB // 4 - ATTRIB // 
*                                                  : 5 - PPSE  // 6 - LOOPBACKWUPB // 7 - Reset Field  
*                                                  : > 7 - Repitative WUPB 
*                                             01   : 1 - WUPB // 2 - WUPA // 3 - WUPB // 4 - ATTRIB // 
*                                                  : 5 - APDU_1  // 6 - APDU_2    // 7 - Reset Field  
*                                                  : > 7 - Repitative WUPB 
*				  - First_Step     : defines the first command to be executed
*				  - No_Of_Step     : Number of Steps , defines the number of command to be executed
* Output        : 
*				  - All Transaction result are output , Each transcation is separted by FFh FFh
*                                 - The argument following FFh FFh : Index + Len_Index + Resp_Index + Resp_Data[0] + ... + Resp_Data[n]  
*                                 - Each Resp_Index has the same meaning as typical transaction
* Return        : 
*				  - Last Step that Executed
*						
*******************************************************************************/

uint8_t ISO14443B_EMV_Load_Modulation ( uint8_t Reset_Field_En , uint8_t Run_All_Step , uint8_t CMD_Category ,  uint8_t First_Step,  uint8_t No_Of_Step, uint8_t *Data_Resp, uint16_t *LenData_Resp )
{
	uint16_t  i;
	uint8_t   Resp ;
	uint8_t   index;
	uint8_t   temp_Data_Resp[256] ;
	uint16_t  temp_LenData_Resp, LenData_Resp_LoopBack ;
        uint16_t  temp_Len_Old;
              
        if (Reset_Field_En == CHECK_ENABLE) 
        {   BC45_OFF_RF( BC45_BOARD_PROPERTY.Driver_Config_Type ) ;
            Delay_ms(2);
        }
        
        if (First_Step == 0 )
        { 
            First_Step = 1 ;
        }
        index = First_Step ;
        temp_Data_Resp[0]   = 0xFF; // Separate Charactor
        temp_Data_Resp[1]   = 0xFF; // Separate Charactor
        temp_Len_Old  = 2;
        
        Resp = ISO14443B_Config( 0x00 ) ;
        
        while ((index < First_Step + No_Of_Step) && ((Run_All_Step == 1) || (Resp == _SUCCESS_)))   
        {     
             if (index == 1) // WUPB
             {
                Resp = ISO14443B_WakeUp( 0, 0 , &Data_TxRF[0], &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ) ;
             }
             else if (index == 2) // WUPA 
             {
                Resp = ISO14443A_Config( 0x00 ) ; 
                Resp = ISO14443A_WakeUp( &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ) ;
             }
             else if (index == 3) // WUPB
             {
               Resp = ISO14443B_Config( 0x00 ) ; 
               Resp = ISO14443B_WakeUp( 0, 0 , &Data_TxRF[0], &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ) ;
             }
             else if (index == 4) // ATTRIB
             {  
                Data_TxRF[0] = 0x1D;
                for ( i = 0 ; i < 4 ;  i++)
                { 
                   Data_TxRF[1+i] = temp_Data_Resp [temp_Len_Old - temp_LenData_Resp - 2 + i ];
                }
                
                Data_TxRF[5] = 0x00;
                Data_TxRF[6] = 0x08;
                Data_TxRF[7] = 0x01;
                Data_TxRF[8] = 0x00; 
                
                Resp = Transparent_With_CRC( &Data_TxRF[0], 9, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 4 ms
                Delay_ms (2);
             }
             else if (index == 5) // PPSE
             {  
                if (CMD_Category == 0)
                {
                  Data_TxRF[0] = 0x02;
                   Data_TxRF[1] = 0x00; 
                   Data_TxRF[2] = 0xA4;
                   Data_TxRF[3] = 0x04;
                   Data_TxRF[4] = 0x00;
                   Data_TxRF[5] = 0x0E;
                   Data_TxRF[6] = 0x32;  // '2'
                   Data_TxRF[7] = 0x50;  // 'P'
                   Data_TxRF[8] = 0x41;  // 'A'
                   Data_TxRF[9] = 0x59;  // 'Y'
                   Data_TxRF[10] = 0x2E;  // '.'
                   Data_TxRF[11] = 0x53; // 'S'
                   Data_TxRF[12] = 0x59; // 'Y'
                   Data_TxRF[13] = 0x53; // 'S'
                   Data_TxRF[14] = 0x2E; // '.'
                   Data_TxRF[15] = 0x44; // 'D'
                   Data_TxRF[16] = 0x44; // 'D'
                   Data_TxRF[17] = 0x46; // 'F'
                   Data_TxRF[18] = 0x30; // '0'
                   Data_TxRF[19] = 0x31; // '1'
                   Data_TxRF[20] = 0x00;
                   Resp = Transparent_With_CRC( &Data_TxRF[0], 21, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 16 ms
                   LenData_Resp_LoopBack = temp_LenData_Resp;
                }
                else
                {
                   Data_TxRF[0] = 0x02;                  
                   Data_TxRF[1] = 0x00; 
                   Data_TxRF[2] = 0x00;
                   Data_TxRF[3] = 0xB0;
                   Data_TxRF[4] = 0x00;
                   Data_TxRF[5] = 0x00;
                   Data_TxRF[6] = 0x02;
                   Resp = Transparent_With_CRC( &Data_TxRF[0], 7, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 8 ms 
                }
                Delay_ms (2);
             }
             else if (index == 6) // LoopBack Command
             { 
                if (CMD_Category == 0)
                { 
                 /*
                  Data_TxRF[0] = 0x03;                  
                   Data_TxRF[1] = 0x00; 
                   Data_TxRF[2] = 0xA4;
                   Data_TxRF[3] = 0x04;
                   Data_TxRF[4] = 0x00;
                   Data_TxRF[5] = 0x0C;
                   Data_TxRF[6] = 0x01;  
                   Data_TxRF[7] = 0x02;  
                   Data_TxRF[8] = 0x03;  
                   Data_TxRF[9] = 0x04; 
                   Data_TxRF[10] = 0x05; 
                   Data_TxRF[11] = 0x06; 
                   Data_TxRF[12] = 0x07; 
                   Data_TxRF[13] = 0x08; 
                   Data_TxRF[14] = 0x09; 
                   Data_TxRF[15] = 0x0A; 
                   Data_TxRF[16] = 0x0B; 
                   Data_TxRF[17] = 0x0C; 
                   Data_TxRF[18] = 0x00; 
                   Resp = Transparent_With_CRC( &Data_TxRF[0], 19, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 8 ms
                 */
                  
                   
                   Data_TxRF[0] = 0x03;  
                   for (i = 1; i < (LenData_Resp_LoopBack) ; i++)
                   {  
                      Data_TxRF [i] = temp_Data_Resp[temp_Len_Old + i - temp_LenData_Resp - 2 ]; 
                   }
                   
                   if ( LenData_Resp_LoopBack < 3 )
                   {
                      LenData_Resp_LoopBack = 1 ;
                   }
                   else
                   {
                      LenData_Resp_LoopBack = LenData_Resp_LoopBack - 2 ;
                   }
                   
                   Resp = Transparent_With_CRC( &Data_TxRF[0], LenData_Resp_LoopBack , 4 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 8 ms
                   
                }
                else
                {
                   Data_TxRF[0] = 0x03;                  
                   Data_TxRF[1] = 0x00; 
                   Data_TxRF[2] = 0x00;
                   Data_TxRF[3] = 0xB0;
                   Data_TxRF[4] = 0x00;
                   Data_TxRF[5] = 0x00;
                   Data_TxRF[6] = 0x02;
                   Resp = Transparent_With_CRC( &Data_TxRF[0], 7, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 8 ms 
                   
                  /*
                   Data_TxRF[0] = 0x0B; 
                    Data_TxRF[1] = 0x00;
                    Data_TxRF[2] = 0x00;
                    Data_TxRF[3] = 0xB0;
                    Data_TxRF[4] = 0x00;
                    Data_TxRF[5] = 0x00;  
                    Data_TxRF[6] = 0x02; 
                   Resp = Transparent_With_CRC( &Data_TxRF[0], 7, 5 , &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ); // timeout 8 ms 
                  */
                }
             }

             else if (index == 7) // Reset Field
             {
                BC45_OFF_RF( BC45_BOARD_PROPERTY.Driver_Config_Type ) ;
                Delay_ms(2);
                 
                BC45_ON_RF( BC45_BOARD_PROPERTY.Driver_Config_Type ) ;
                Delay_ms(5);
                Resp = _SUCCESS_;
                temp_LenData_Resp = 0 ;
             }
             else 
             {  
                 BC45_Timer_Set_Resp_Waiting_Time( 2 ) ; // Timeout 2 ms;
                 Resp = ISO14443B_WakeUp( 0, 0 , &Data_TxRF[0], &temp_Data_Resp[temp_Len_Old + 3], &temp_LenData_Resp ) ;
             }
             
             temp_Data_Resp[temp_Len_Old]   = index;
             temp_Data_Resp[temp_Len_Old + 1]   = ((uint8_t)temp_LenData_Resp ) + 1 ;
             temp_Data_Resp[temp_Len_Old + 2]   = Resp;
             temp_Len_Old                   = temp_Len_Old + temp_LenData_Resp + 3 ;
             
             
             temp_Data_Resp[temp_Len_Old]   = 0xFF; // Separate Charactor
             temp_Data_Resp[temp_Len_Old+1] = 0xFF; // Separate Charactor
             temp_Len_Old                   = temp_Len_Old + 2;
            
             if (index == 2)  // WUPA
             {
                if (Resp != NO_RESPONSE)
                {
                  Resp = INVALID_RESP ; 
                }
                else
                {
                  Resp = _SUCCESS_ ; 
                }
             }
             index = index + 1; 
             
        }
                
        temp_LenData_Resp              = temp_Len_Old - 2 ;
       // if (Resp != _SUCCESS_)
        index = index - 1;
        
      
        for ( i = 0 ; i < temp_LenData_Resp ; i++ )
	{
	   *( Data_Resp + i) = temp_Data_Resp[i] ; 
	}
	*( LenData_Resp ) = temp_LenData_Resp ; // Len Respnose	

	return (index) ;
    
}

