2018-04-08 16:51:19 +08:00
/**************************************************************************************************
*
* @ project Proxmark 3
* @ file smartcard . c
* @ author Chris Nocker < nocker02 @ gmail . com >
* @ created 03 / 04 / 2018
* @ brief Implements communication with a smart card .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "smartcard.h"
//#define SMART_CARD_DEBUG_ENABLED
# ifndef SMART_CARD_DEBUG_ENABLED
# endif // SMART_CARD_DEBUG_ENABLED
// -- Defines ---------------------------------------------------------------------------------- //
# define SMART_CARD_RST_PIN AT91C_PIO_PA1
# define SMART_CARD_IO_PIN AT91C_PIO_PA5
# define SMART_CARD_CLK_PIN AT91C_PIO_PA7
# define SMART_CARD_RST_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_RST_PIN
# define SMART_CARD_RST_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_RST_PIN
# define SMART_CARD_RST_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_RST_PIN
# define SMART_CARD_IO_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_IO_PIN
# define SMART_CARD_IO_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_IO_PIN
# define SMART_CARD_IO_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_IO_PIN
# define SMART_CARD_CLK_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_CLK_PIN
# define SMART_CARD_CLK_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_CLK_PIN
# define SMART_CARD_CLK_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_CLK_PIN
# define SMART_CARD_IO_OUPUT_MODE AT91C_BASE_PIOA->PIO_OER = SMART_CARD_IO_PIN
# define SMART_CARD_IO_RECEPTION_MODE AT91C_BASE_PIOA->PIO_ODR = SMART_CARD_IO_PIN
# define SMART_CARD_RECEIVE_BUFFER_SIZE (10)
# define SMART_CARD_TRANSMIT_BUFFER_SIZE (10)
2018-04-17 01:58:49 +08:00
# define SMART_CARD_CLOCK AT91C_BASE_PWMC_CH1
2018-04-08 16:51:19 +08:00
// true = the distance between a and b is greater than c
# define RANGE(a,b,c) ((MAX(a,b))-(MIN(a,b))>(c))
// -- Private Variables ------------------------------------------------------------------------ //
static bool triggerDeactivation ;
static bool communicationsEstablished ;
static uint16_t receiveBuffer [ SMART_CARD_RECEIVE_BUFFER_SIZE ] ; // Raw received bytes that need their parity checked before using them
static uint8_t receiveGetPtr ;
static uint8_t receivePutPtr ;
static uint8_t transmitBuffer [ SMART_CARD_TRANSMIT_BUFFER_SIZE ] ;
static uint8_t transmitGetPtr ;
static uint8_t transmitPutPtr ;
static bool generateClk ;
static bool receptionMode ;
static bool transmitMode ;
/**
* @ brief Get a transmit byte
* @ description Get a byte from the transmit buffer
* @ param receivedByte Pointer to return the byte from the buffer to the caller
* @ return bool true = A byte was removed from the buffer and returned to the caller
* false = No byte available
*/
static bool SMART_CARD_GetTransmitByte ( uint8_t * receivedByte ) {
bool result = false ;
uint8_t tempGetPtr = transmitGetPtr ;
// Move the temp put pointer to the next index
if ( + + tempGetPtr > = SMART_CARD_RECEIVE_BUFFER_SIZE ) {
tempGetPtr = 0 ;
}
// If the get pointer does not match the put pointer then there is data to be taken from the buffer
if ( transmitGetPtr ! = transmitPutPtr ) {
* receivedByte = transmitBuffer [ transmitGetPtr ] ;
transmitGetPtr = tempGetPtr ;
result = true ;
}
return result ;
}
/**
* @ brief Put transmit byte
* @ description Store a byte in the transmit buffer
* @ param transmitByte The byte to try and put in the buffer
* @ return bool true = Operation was performed successfully
* false = No room in buffer : - (
*/
static bool SMART_CARD_PutTransmitByte ( uint8_t transmitByte ) {
bool result = false ;
uint8_t tempPutPtr = transmitPutPtr ;
// Move the temp put pointer to the next index
if ( + + tempPutPtr > = SMART_CARD_RECEIVE_BUFFER_SIZE ) {
tempPutPtr = 0 ;
}
// If the new put pointer does not match the get pointer then it is safe to save this byte
if ( tempPutPtr ! = transmitGetPtr ) {
transmitBuffer [ transmitPutPtr ] = transmitByte ;
transmitPutPtr = tempPutPtr ;
result = true ;
}
return result ;
}
/**
* @ brief Get received byte
* @ description Get a byte from the receive buffer
* @ param receivedByte Pointer to return the byte from the buffer to the caller
* @ return bool true = A byte was removed from the buffer and returned to the caller
* false = No byte available
*/
static bool SMART_CARD_GetRecievedByte ( uint16_t * receivedByte ) {
bool result = false ;
uint8_t tempGetPtr = receiveGetPtr ;
// Move the temp put pointer to the next index
if ( + + tempGetPtr > = SMART_CARD_RECEIVE_BUFFER_SIZE ) {
tempGetPtr = 0 ;
}
// If the get pointer does not match the put pointer then there is data to be taken from the buffer
if ( receiveGetPtr ! = receivePutPtr ) {
* receivedByte = receiveBuffer [ receiveGetPtr ] ;
receiveGetPtr = tempGetPtr ;
result = true ;
}
return result ;
}
/**
* @ brief Put received byte
* @ description Store a verified , received byte in the receive buffer
* @ param receivedByte The byte to try and put in the buffer
* @ return bool true = Operation was performed successfully
* false = No room in buffer : - (
*/
static bool SMART_CARD_PutRecievedByte ( uint16_t receivedByte ) {
bool result = false ;
uint8_t tempPutPtr = receivePutPtr ;
// Move the temp put pointer to the next index
if ( + + tempPutPtr > = SMART_CARD_RECEIVE_BUFFER_SIZE ) {
tempPutPtr = 0 ;
}
// If the new put pointer does not match the get pointer then it is safe to save this byte
if ( tempPutPtr ! = receiveGetPtr ) {
receiveBuffer [ receivePutPtr ] = receivedByte ;
receivePutPtr = tempPutPtr ;
result = true ;
}
return result ;
}
/**
* @ brief Calculate byte parity
* @ description Calculate the parity of a byte
* @ param dataByte Byte to calculate the parity of
* @ return bool true = Parity of the byte is high
* false = Parity of the byte is low
*/
static bool SMART_CARD_CalculateByteParity ( uint8_t dataByte ) {
bool result ;
uint8_t i , parity ;
// Accumulate the parity
for ( i = 0 , parity = 0 ; i < 8 ; i + + ) {
if ( dataByte & ( 1 < < i ) ) {
parity + + ;
}
}
// The high (1) bits of the byte plus the parity bit must be even for the byte to be considered as good
result = ( parity % 2 ) ? true : false ;
return result ;
}
/**
* @ brief Verify received byte parity
* @ description Calculate the parity of a received sampled byte and compare it to the parity in the received sampled byte
* @ param receivedSampledByte Byte to verify the parity of
* @ return bool true = Parity of the received byte is good
* false = Parity of the received byte is bad ( reject )
*/
static bool SMART_CARD_VerifyReceivedByteParity ( uint16_t receivedSampledByte ) {
bool result ;
uint8_t dataByte = ( uint8_t ) ( receivedSampledByte > > 1 ) ;
// Check if the calculated parity is the same as the parity in the received sampled byte
if ( SMART_CARD_CalculateByteParity ( dataByte ) = = ( receivedSampledByte & 1 ) )
result = true ;
else
result = false ;
return result ;
}
/**
* @ brief Maintain the smart card connection
* @ description Send and receive commands
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
static bool SMART_CARD_MaintainConnection ( void ) {
// TODO: This functions implementation is not yet complete
bool result = true ;
uint16_t rxByte ;
uint8_t verifiedRxByte ;
// See if there has been a new byte sampled
if ( SMART_CARD_GetRecievedByte ( & rxByte ) ) {
// Check that the parity is correct
if ( SMART_CARD_VerifyReceivedByteParity ( rxByte ) ) {
verifiedRxByte = rxByte > > 1 ;
// TODO: Dummy code that is to remove compiler warnings during development
if ( verifiedRxByte ) {
SMART_CARD_PutTransmitByte ( verifiedRxByte ) ;
}
}
}
return result ;
}
/**
* @ brief Disable the clock
* @ description
* @ param void
* @ return void
*/
static void SMART_CARD_DisableClock ( void ) {
// Disable TC2
2018-04-17 01:58:49 +08:00
//AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_PWMC - > PWMC_DIS = PWM_CHANNEL ( 1 ) ;
2018-04-08 16:51:19 +08:00
generateClk = false ;
}
/**
* @ brief Enable the clock
* @ description
* @ param void
* @ return void
*/
static void SMART_CARD_EnableClock ( void ) {
// Enable and reset TC2
2018-04-17 01:58:49 +08:00
//AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_PWMC - > PWMC_ENA = PWM_CHANNEL ( 1 ) ;
2018-04-08 16:51:19 +08:00
generateClk = true ;
}
/**
* @ brief Perform deactivation
* @ description Control the signals to the smart card to perform a deactivation operation
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
static void SMART_CARD_PerformDeactivation ( void ) {
/*
* 1. Reset L
* 2. CLK L
* 3. I / O L
* 4. VCC L ( NOTE : This may require a circuit change ! ! ! )
*/
SMART_CARD_RST_LO ;
SMART_CARD_IO_LO ;
SMART_CARD_DisableClock ( ) ;
}
/**
* @ brief Negotiate parameters
* @ description
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
//static bool SMART_CARD_NegotiateProtocolParameters( void ) {
// TODO: This functions implementation is not yet complete
// bool result = false;
//
// // Check if the card is in a specific mode
// if ( 0xFF )
// {
// // Have to use this mode
// }
// else
// {
// // Negotiate
// }
//
// return result;
//}
/**
* @ brief Class selection
* @ description Class selection
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
static bool SMART_CARD_ClassSelection ( uint8_t class , uint8_t * answer , uint8_t length ) {
bool result = false ;
// Check that an answer was received
if ( answer [ 0 ] ) {
// Check that the answer was valid
if ( answer [ 1 ] ) {
// See if the card indicated a class
if ( answer [ 2 ] ) {
// Check that we are happy with the class (i.e. this is the 3V one that we supplied)
if ( answer [ 2 ] = = 2 ) {
result = true ;
} else {
// We cannot work with this class
triggerDeactivation = true ;
}
} else {
// Card did not indicate class, just accept this answer
result = true ;
}
} else {
// Error handling
}
} else {
// Card did not answer
triggerDeactivation = true ;
}
return result ;
}
/**
* @ brief Process the reset answer
* @ description
* @ param answer
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
2018-04-21 02:07:41 +08:00
static bool SMART_CARD_ProcessResetAnswer ( uint8_t * answer , uint8_t length ) {
2018-04-08 16:51:19 +08:00
// TODO: This functions implementation is not yet complete
bool result = false ;
uint8_t class ;
for ( class = 0 ; class < 3 ; class + + ) {
// We can only do one class as we cannot adjust the VCC voltage
if ( SMART_CARD_ClassSelection ( class , answer , length ) ) {
result = true ;
break ;
} else {
if ( triggerDeactivation ) {
triggerDeactivation = false ;
SMART_CARD_PerformDeactivation ( ) ;
}
}
}
return result ;
}
/**
* @ brief Perform warm reset
* @ description Can be performed at any time ( not sure we ' ll use this one ? ? ? )
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
//static bool SMART_CARD_PerformWarmReset( void ) {
// TODO: This functions implementation is not yet complete
// bool result = false;
// /*
// * 1. the interface device initiates a warm reset (at time Tc) by putting RST to state L for at least 400 clock cycles (delay te) while VCC remains powered and CLK provided
// * 2. The card shall set I/O to state H within 200 clock cycles (delay td) after state L is applied to RST
// * 3. RST is put to state H
// * 4. The answer on I/O shall begin between 400 and 40 000 clock cycles (delay tf) after the rising edge of the signal on RST
// * 5. If the answer does not begin within 40 000 clock cycles with RST at state H, the interface device shall perform a deactivation
// */
//
// return result;
//}
/**
* @ brief Perform cold reset
* @ description We are outputting the CLK to the smart card . Wait for the initial reset answer
* @ param void
* @ return bool true = Operation was performed successfully
* false = An error occurred
*/
static bool SMART_CARD_PerformColdReset ( void ) {
// TODO: This functions implementation is not yet complete
bool result = false ;
/*
* 1. The card shall set I / O to state H within 200 clock cycles
* The cold reset results from maintaining RST at state L for at least 400 clock cycles ( delay tb ) after the clock signal is applied to CLK
* 2. The interface device shall ignore the state on I / O while RST is at state L
* 3. RST is put to state H
* 4. The answer on I / O shall begin between 400 and 40 000 clock cycles ( delay tc ) after the rising edge of the signal on RST
* 5. If the answer does not begin within 40 000 clock cycles with RST at state H , the interface device shall perform a deactivation
*/
return result ;
}
/**
* @ brief Activate the smart card interface
* @ description Control the interface signals to perform an activation on the smart card
* @ param void
* @ return void
*/
static void SMART_CARD_ActivateInterface ( void ) {
/*
* 1. RST shall be put to state L
* 2. VCC shall be powered
* 3. I / O in the interface device shall be put in reception mode
* 4. CLK shall be provided with a clock signal ( 1 MHz to 5 MHz )
*/
SMART_CARD_RST_LO ;
SMART_CARD_IO_RECEPTION_MODE ;
SMART_CARD_EnableClock ( ) ;
}
/**
* @ brief Establish communications
* @ description Activate the smart card , perform a cold reset & process the reset answer
* @ param void
* @ return bool true = Operation was performed successfully and communications have been established
* false = An error occurred
*/
static bool SMART_CARD_EstablishCommunications ( void ) {
// TODO: This functions implementation is not yet complete
bool result = false ;
2018-04-25 07:33:25 +08:00
uint8_t answer [ 100 ] ;
2018-04-08 16:51:19 +08:00
// Activate the interface
SMART_CARD_ActivateInterface ( ) ;
// Perform a cold reset
result = SMART_CARD_PerformColdReset ( ) ;
// Process the "answer" if it was received
if ( result ) {
2018-04-21 02:07:41 +08:00
result = SMART_CARD_ProcessResetAnswer ( answer , 100 ) ;
2018-04-08 16:51:19 +08:00
// Check if the "answer" was acceptable
if ( ! result ) {
// Delay for 20ms
WaitMS ( 20 ) ;
}
}
2018-04-21 02:07:41 +08:00
2018-04-08 16:51:19 +08:00
return result ;
}
/**
* @ brief Configure timer
* @ description Configure the timer to generate an interrupt every 500 ns . This is 2 MHz . From this we will
* generate the 1 MHz clock signal and sample the I / O line every 2 interrupt triggers
* @ param void
* @ return void
*/
static void SMART_CARD_ConfigureClock ( void ) {
2018-04-17 01:58:49 +08:00
/*
2018-04-08 16:51:19 +08:00
AT91C_BASE_PMC - > PMC_PCER | = ( 1 < < AT91C_ID_TC2 ) ; // Enable Clock TC2
AT91C_BASE_TCB - > TCB_BMR & = AT91C_TCB_TC2XC2S ; // Clear the external clock selection
AT91C_BASE_TCB - > TCB_BMR | = AT91C_TCB_TC2XC2S_NONE ; // XC2 Clock = None
// Configure TC2 to count up to RC, then reset and generate an interrupt
AT91C_BASE_TC2 - > TC_CCR = AT91C_TC_CLKDIS ; // Disable TC2
AT91C_BASE_TC2 - > TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC2 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCTRG ; // Capture Mode, reset the TC2 counter when RC is reached
AT91C_BASE_TC2 - > TC_RC = 12 ; // RC Compare value = 24MHz / 2MHz = 12
AT91C_BASE_TC2 - > TC_IER = AT91C_TC_CPCS ; // Generate an interrupt when the RC value is reached
2018-04-17 01:58:49 +08:00
*/
// enable PWM Clock
AT91C_BASE_PMC - > PMC_PCER | = ( 1 < < AT91C_ID_PWMC ) ;
// Enable channel1 as SMART CARD real-time clock
AT91C_BASE_PWMC - > PWMC_ENA = PWM_CHANNEL ( 1 ) ;
// 48 MHz / 16 gives 3MHz
SMART_CARD_CLOCK - > PWMC_CMR = PWM_CH_MODE_PRESCALER ( 3 ) ; // Channel Mode Register
SMART_CARD_CLOCK - > PWMC_CDTYR = 0 ; // Channel Duty Cycle Register
SMART_CARD_CLOCK - > PWMC_CPRDR = 0xffff ; // Channel Period Register
AT91C_BASE_PWMC - > PWMC_IER = 1 < < 1 ;
// AT91C_BASE_PWMC->PWMC_IDR; // disable interrupt
2018-04-08 16:51:19 +08:00
}
// -- Public Functions ------------------------------------------------------------------------- //
/**
* @ brief CLK interrupt handler
*
* @ description Implements a bit banged CLK signal to the smart card . Also outputs data on the I / O line on rising
* CLK edges when transmiting and samples the I / O line on falling CLK edges when receiving
* @ param void
* @ return void
*/
void SMART_CARD_ClockInterruptHandler ( void ) {
static uint8_t clkCount ;
static uint8_t previousSampleRxClkCount ;
static uint8_t previousSampleTxClkCount ;
static uint16_t sampledRxData ; // The bits of the Rx byte are accumulated here
static uint8_t sampleBitIndex ; // Used during both Tx and Rx as the comms are half duplex
static uint8_t transmitByte ;
bool sampleBit = SMART_CARD_IO_STATE ; // Read the state of the I/O signal in case we are going to use it
// Clear the interrupt
// TODO: This functions implementation is not yet complete... just need to handle the interrupt
// Check if we are meant to be generating the CLK signal
if ( generateClk )
{
// On the even clock counts we will toggle the CLK signal
if ( clkCount + + % 2 )
{
// Read the current state of the CLK signal, if it is High then set it Low and if it is Low set it High
if ( SMART_CARD_CLK_STATE )
{
// Generate a falling edge
SMART_CARD_CLK_LO ;
// ******************************************************************* //
// On the falling edge of the CLK signal we sample from the I/O signal //
// ******************************************************************* //
// See if we are receiving
if ( receptionMode )
{
// See if we are already looking for the start of a new byte OR
// It has been a while since we last captured a byte (this provides resynchronising)
if ( ( sampleBitIndex = = 0 ) | | ( RANGE ( clkCount , previousSampleRxClkCount , 5 ) ) )
{
sampleBitIndex = 0 ;
previousSampleRxClkCount = clkCount ;
// The start bit must be low
if ( sampleBit = = 0 )
{
// Set the bit index to indicate that we've detected a start bit
sampleBitIndex = 1 ;
// Initialise the sample data byte where the received bits will be put
sampledRxData = 0 ;
}
}
// Otherwise see if we are in the process of collecting bits of a sample byte
else if ( ( sampleBitIndex ) & & ( sampleBitIndex < = 10 ) )
{
// Shift the bits of the sampled byte up by 1 to make room for this new bit
sampledRxData = sampledRxData < < 1 ;
// Or in the new sample bit
sampledRxData | = sampleBit < < sampleBitIndex ;
// Check if we've received the start bit, 8 bits of the byte and the parity bit
if ( sampleBitIndex = = 10 )
{
// Transfer the sampled data into the receive buffer so that it can be processed
if ( ! SMART_CARD_PutRecievedByte ( sampledRxData ) )
{
// An error has occured as there was no space to save this byte!
}
}
// Increment index and wait for next bit
sampleBitIndex + + ;
// Update the Rx CLK count so we know how long to wait
previousSampleRxClkCount = clkCount ;
}
}
}
// CLK is Low so set it High
else
{
// Generate a rising edge
SMART_CARD_CLK_HI ;
// ***************************************************************************************** //
// On the rising edge of the CLK signal we output the next bit of the byte to the I/O signal //
// ***************************************************************************************** //
// See if we are transmitting
if ( transmitMode )
{
// See if we are already looking for new byte to transmit OR
// It has been a while since we last sent a byte (this allows for the "pause" time)
if ( ( sampleBitIndex = = 0 ) | | ( RANGE ( clkCount , previousSampleTxClkCount , 7 ) ) )
{
sampleBitIndex = 0 ;
previousSampleTxClkCount = clkCount ;
// See if there is a byte to transmit
if ( SMART_CARD_GetTransmitByte ( & transmitByte ) )
{
// The start bit must be low
SMART_CARD_IO_LO ;
// Set the bit index to indicate that we've started transmitting
sampleBitIndex = 1 ;
}
}
// We are in the process of collecting bits of a sample byte
else if ( ( sampleBitIndex ) & & ( sampleBitIndex < = 11 ) )
{
// Check if we've output the start bit and the 8 bits of the byte and the parity bit
if ( sampleBitIndex = = 11 )
{
// There is nothing left to output, set the I/O signal high during the "pause" time
SMART_CARD_IO_HI ;
}
// Check if we've output the start bit and the 8 bits of the byte
else if ( sampleBitIndex = = 10 )
{
// Calculate the parity bit and output it appropriately
if ( SMART_CARD_CalculateByteParity ( transmitByte ) )
{
SMART_CARD_IO_HI ;
}
else
{
SMART_CARD_IO_LO ;
}
}
// Otherwise we are still outputting the bits of the byte
else
{
// Set the state of the I/O signal according to the bits of the transmit byte
if ( transmitByte & ( 1 < < ( sampleBitIndex - 1 ) ) )
{
SMART_CARD_IO_HI ;
}
else
{
SMART_CARD_IO_LO ;
}
}
// Increment index for when the next bit is output
sampleBitIndex + + ;
}
}
}
}
}
}
/**
* @ brief Service the smart card interface
* @ description Check if a transaction needs to occur
* @ param void
* @ return bool true = The smart card was service successfully
* false = An error occurred
*/
void SMART_CARD_ServiceSmartCard ( void ) {
if ( ! communicationsEstablished ) {
// Attempt to establish communications if they are not currently working
communicationsEstablished = SMART_CARD_EstablishCommunications ( ) ;
} else {
// Communications are working, processs any commands/responses
// If a fatal error occurs we will need to re-establish communications
communicationsEstablished = SMART_CARD_MaintainConnection ( ) ;
}
}
void SmartCard_setup ( void ) {
// Enable the pins to be controlled
AT91C_BASE_PIOA - > PIO_PER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN ;
// Configure the pins to be outputs
AT91C_BASE_PIOA - > PIO_OER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN ;
// Configure the IO pin for multi-drive mode (is this right?)
AT91C_BASE_PIOA - > PIO_MDER = SMART_CARD_IO_PIN ;
AT91C_BASE_PIOA - > PIO_PPUER = SMART_CARD_IO_PIN ;
// Configure a timer to generate an interrupt for the clock signal and sampling of the I/O line
SMART_CARD_ConfigureClock ( ) ;
}
void SmartCard_stop ( void ) {
2018-04-17 01:58:49 +08:00
//StopTicks();
2018-04-08 16:51:19 +08:00
if ( MF_DBGLEVEL > 3 ) Dbprintf ( " Smart Card Stop " ) ;
LED_A_OFF ( ) ;
}
bool SmartCard_init ( void ) {
2018-04-17 01:58:49 +08:00
//StartTicks();
2018-04-08 16:51:19 +08:00
2018-04-17 02:19:44 +08:00
//LED_A_ON();
2018-04-08 16:51:19 +08:00
SmartCard_setup ( ) ;
if ( MF_DBGLEVEL > 3 ) Dbprintf ( " Smart Card Init OK " ) ;
return true ;
}
void SmartCard_print_status ( void ) {
DbpString ( " Smart card module (ISO 7816) " ) ;
if ( ! SmartCard_init ( ) ) {
DbpString ( " init....................FAIL " ) ;
return ;
}
DbpString ( " init....................OK " ) ;
SmartCard_stop ( ) ;
}