/PCSCMicro/GemCore/Device.cs
C# | 935 lines | 703 code | 50 blank | 182 comment | 149 complexity | 73dd2527d114430220270e5844741734 MD5 | raw file
Possible License(s): GPL-2.0
- /***************************************************************************
- * This code was adapted from TSPC_CCID.cs which was originally written by *
- * Teridian SemiConductor, Corp. It has been modified from its original *
- * version to allow for use in the .NET Micro Framework. It has also been *
- * adapted to allow for use with the GemCore Serial Lite Pro evaluation *
- * board. Additions have been made to the original version to allow for a *
- * broader use of the reader. *
- * LAST MODIFIED: 2010 April 23 *
- * Copyright (C) 2009 Gemalto *
- ***************************************************************************/
- /***************************************************************************
- * Device.cs is part of the PC/SC Micro API for the .NET Micro *
- * Framework. *
- * *
- * The PC/SC Micro API for the .NET Micro Framework is free software: *
- * you can redistribute it and/or modify it under the terms of the GNU *
- * General Public License as published by the Free Software Foundation, *
- * either version 2 of the License, or (at your option) any later version.*
- * *
- * The PC/SC Micro API for the .NET Micro Framework is distributed in *
- * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even*
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *
- * PURPOSE. See the GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with the PC/SC Micro API for the .NET Micro Framework. If not, *
- * see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
- using System;
- using Microsoft.SPOT;
- using Microsoft.SPOT.Hardware;
-
- namespace PCSCMicro
- {
- internal class Device : Reader
- {
- #region Definition of constants and global variables
-
- // Collecting Data TimeOut Design Setting
- int TestTimeOut = 15 * 60; // Timeout for APDU calculated to second
- int InitializationTimeOut = 10; // Apply to non-APDU and non-EMV testing command, in second
- int TimeOutUnitInMiliSec = 500; // This TimeOut is independent with the ones in Min and Sec
-
- // Hard-coded configuration constants
- const string ACK = "60";
- const string NACK = "E0";
- const string PowerOnSC = "0112FF";
- const string PowerOffSC = "0111FF";
- const string CheckStatus = "0117FF";
- const string SetParametersCommand = "0612";
- const string RestartReader = "040C000000FF";
-
- // Dynamic Strings used for commands
- string NAD = "42";
- string PCB = "00";
- string Config_Init;
-
- // Bit to keep track of sent parity
- bool pcb = false;
- const string onPCB = "40";
- const string offPCB = "00";
-
- // Keep track of slot status
- const int ACTIVATED = 0;
- const int PRESENT = 1;
- const int NOCARD = 2;
- const int ERROR = 3;
- int SlotStatus = NOCARD;
-
- // Maximum number of log lines
- const int MaxBytes = 4096;
-
- // Flags used for running processes
- bool IsSerialPortOn = false;
- bool APDUCommandComplete = true;
- bool ActivatingSmartCard = false;
- bool CardActivated = false;
- bool ResettingCard = false;
-
- // Retry counters for Serial Port Communication
- int NumberOfRetries;
- int NumberOfGemCoreRetries;
-
- // Serial Port
- int baudrate = 9600;
- System.IO.Ports.SerialPort ComPort = new System.IO.Ports.SerialPort(System.IO.Ports.Serial.COM1);
-
- // Packet parser
- PacketParser Packet = new PacketParser();
-
- // PPS Strings
- string Protocol = "00";//Protocol to be set by user later
- string FiDi = "11";//FiDi to be set by user later
- string PRT = "50"; // T = 0, EDC = LRC, I-Block Sent = 1, I-Block Received = 0
- string TC1 = "00";
- string TC2_TA3 = "10";
- string RFU_TB3 = "00";
-
- // Card characteristics
- ReaderError error = ReaderError.NONE;
- string atr = null;
-
- #endregion
-
- /*****************************************************************************/
- /* */
- /* Serial Port Communication: Initialize, Send and Receive Data */
- /* */
- /*****************************************************************************/
-
- #region Serial Port Interface
-
- // Initialize Serial Port
- void InitializeComPort(int baudrate, System.IO.Ports.Handshake handShake)
- {
- if (!ComPort.IsOpen)
- {
- // Set COM port properties
- ComPort.BaudRate = baudrate;
- ComPort.Parity = System.IO.Ports.Parity.None;
- ComPort.StopBits = System.IO.Ports.StopBits.One;
- ComPort.DataBits = 8;
- ComPort.Handshake = handShake;
- ComPort.ReadTimeout = 5000;
- ComPort.Open();
- }
- }
-
- // Compute the LRC of the sending string
- // LRC = result of XOR between ACK, length, and message characters
- byte ComputeLRC(byte[] bArr, int bytecount)
- {
- byte TRC = 0;
- int count = 0;
- while (count++ < bytecount)
- {
- TRC = (byte)(TRC ^ bArr[count - 1]);
- }
- return TRC;
- }
-
- // Check if the packet received is complete
- bool IsComplete(byte[] byteArray, int length)
- {
- if (length > 3)
- {
- byte len = byteArray[2];
- if (length == len + 4)
- {
- return true;
- }
- }
- return false;
- }
-
- // Send an array of bytes to the serial port
- void SendReceive(string Message, ref string Response, int InputTimeOutInSec)
- {
- int RetryNACK = NumberOfRetries;
- SendLabel: // Used when receiving a NACK response, comand sending must be resent
- /*-----------------------------------*/
- /* Send data to the Serial Port */
- /*-----------------------------------*/
-
- #region Send data to the Serial Port
- //Convert Hex String to Byte Array
- byte[] myBuffer = new byte[Message.Length / 2]; // reserve 2 byte for CRC
- myBuffer = HexStringDecoder.StringToByteArray(Message);
- if ((Message != ACK) && (Message != NACK))
- {
- // TRC Calculation
- byte TRC = ComputeLRC(myBuffer, myBuffer.Length - 1);
- myBuffer[myBuffer.Length - 1] = TRC;
- }
- // Update Message to include Error detection bits
- Message = HexStringDecoder.ByteArrayToString(myBuffer, myBuffer.Length);
- ComPort.DiscardInBuffer();
- ComPort.DiscardOutBuffer();
- // Send single byte in the byte array so it can be parsed
- for (int i = 0; i < myBuffer.Length; i++)
- {
- ComPort.Write(myBuffer, i, 1);
- }
- #endregion
-
- /*-----------------------------------*/
- /* Receive data from the Serial Port */
- /*-----------------------------------*/
-
- #region Receive data from the Serial Port
- // Initialize receive related variables
- int TimeOutCycleCountDown = (InputTimeOutInSec * 1000 / TimeOutUnitInMiliSec);
- bool TimeOut = false;
- int bytecount = 0;
- byte[] byteArrayBuffer = new byte[MaxBytes];
- byte[] byteArrayReturn = new byte[MaxBytes];
- // Reset the data string received and the byte received
- Response = "";
- // Unnecessary to collect data if it's an ACK or NACK
- if ((Message == ACK) || (Message == NACK))
- return;
- // Do the loop if there's no timeout or the timeout cycle still exists
- while ((!TimeOut) && (TimeOutCycleCountDown > 0) && (bytecount < MaxBytes))
- {
- // Attempt to read from COM port
- if (1 == ComPort.Read(byteArrayBuffer, bytecount, 1))
- {
- bytecount++;
- }
- else
- {
- // If restart command was sent, then timeout is expected
- if (Message.Length >= 4 + RestartReader.Length - 2
- && Message.Substring(4, RestartReader.Length - 2) == RestartReader.Substring(0, RestartReader.Length - 2))
- {
- break;
- }
- // Else set error and return
- error = ReaderError.NO_RESPONSE;
- return;
- }
- // Check if end of packet has been received
- if (IsComplete(byteArrayBuffer, bytecount))
- {
- TimeOut = true;
- }
- }
- // Copy data to Response
- byteArrayReturn = byteArrayBuffer;
- Response = HexStringDecoder.ByteArrayToString(byteArrayReturn, bytecount);
- #endregion
-
- /*-----------------------------------*
- * Handling NACK reponse *
- *-----------------------------------*/
-
- #region Handling NACK reponse
- // Prepare to resend the command
- if ((Response != null) && (Response.Length >= NACK.Length) &&
- (Response.Substring(0, NACK.Length) == NACK) && (RetryNACK-- > 0))
- {
- // Terminate all the running command after a number of retries when receiving NACK response
- if (RetryNACK == 0)
- {
- goto SendLabel;
- }
- }
- // Resend command because GemCore board has returned incorrect command form error
- // used when PCB is incorrect or for connect command
- else if ((Response != null) && (Response.Length >= 3)
- && (Response.Substring(0, 3).CompareTo("248") >= 0)
- && !Message.Substring(Message.Length - 2, 2).Equals("C0"))
- {
- Message = NAD + getPCB() + Message.Substring(4);
- NumberOfGemCoreRetries--;
- if (NumberOfGemCoreRetries > 0)
- {
- SendReceive(Message, ref Response, InputTimeOutInSec);
- }
- }
- else
- {
- NumberOfGemCoreRetries = 10;
- }
- #endregion
- }
-
- #endregion
-
- /*****************************************************************************/
- /* */
- /* Smart Card and Reader Communication */
- /* */
- /*****************************************************************************/
-
- #region Smart Card
-
- // Retrieves the correct PCB value
- string getPCB()
- {
- // Last one was "00", so now send "40"
- if (pcb)
- {
- PCB = onPCB;
- }
- // Last one was "40", so now send "00"
- else
- {
- PCB = offPCB;
- }
- pcb = !pcb;
- return PCB;
- }
-
- // Validate responses
- void ResponseValidation(PacketParser packet)
- {
- // Infinite Loop detection
- if ((packet.ErrorCode == PacketParser.ErrorType.Timeout)
- || (packet.ErrorCode == PacketParser.ErrorType.NoResponse)
- || (packet.ErrorCode == PacketParser.ErrorType.NACK))
- {
- error = ReaderError.NO_RESPONSE;
- }
- // Illegal response message detection
- else if (packet.ErrorCode == PacketParser.ErrorType.IllegalMessage)
- {
- error = ReaderError.BAD_MESSAGE;
- }
- // Illegal sent command detection
- else if (packet.ErrorCode == PacketParser.ErrorType.UnknownCommand
- || packet.ErrorCode == PacketParser.ErrorType.NumberArgs
- || packet.ErrorCode == PacketParser.ErrorType.BadCommandCode
- || packet.ErrorCode == PacketParser.ErrorType.NumberParams
- || packet.ErrorCode == PacketParser.ErrorType.CommandNotSupported)
- {
- error = ReaderError.BAD_COMMAND;
- }
- // Card malfunction detection
- else if (packet.ErrorCode == PacketParser.ErrorType.CardMissing
- || packet.ErrorCode == PacketParser.ErrorType.CardRemoved
- || packet.ErrorCode == PacketParser.ErrorType.CardMalfunction
- || packet.ErrorCode == PacketParser.ErrorType.PoweredDown
- || packet.ErrorCode == PacketParser.ErrorType.ShortCircuit)
- {
- error = ReaderError.NO_CARD_INSERTED;
- }
- // Other error detection
- else if (packet.ErrorCode != PacketParser.ErrorType.None)
- {
- error = ReaderError.UNKNOWN_ERROR;
- }
- // Correct data response
- else
- {
- error = ReaderError.NONE;
- }
- }
-
- // Connect reader
- internal override bool ConnectReader()
- {
- error = ReaderError.NONE;
- string Response = null;
- // Set port properties
- baudrate = 9600;
- // If reader is already on, no need to turn on again
- if (IsSerialPortOn)
- {
- error = ReaderError.ALREADY_CONNECTED;
- return true;
- }
- NumberOfGemCoreRetries = 10;
- try
- {
- // Open COM port
- InitializeComPort(baudrate, System.IO.Ports.Handshake.None);
- // Collect number of Retries if NACK receive
- NumberOfRetries = 5;
- // Send initialization command
- Config_Init = NAD + getPCB() + PowerOnSC;
- SendReceive(Config_Init, ref Response, InitializationTimeOut);
- Config_Init = NAD + getPCB() + PowerOffSC;
- SendReceive(Config_Init, ref Response, InitializationTimeOut);
- IsSerialPortOn = true;
- return true;
- }
- catch
- {
- if (ComPort.IsOpen)
- {
- ComPort.Close();
- }
- error = ReaderError.PORT_CONNECTION_FAILED;
- return false;
- }
- }
-
- // Disconnect reader
- internal override bool DisconnectReader()
- {
- error = ReaderError.NONE;
- // Cannot disconnect reader if sending APDU
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- // Reader is already off
- else if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return true;
- }
- // Close Port, reset port and board flags
- ComPort.Close();
- IsSerialPortOn = false;
- return true;
- }
-
- // Reset reader
- internal override bool ResetReader()
- {
- error = ReaderError.NONE;
- // Send Restart Command and connect reader
- string Response = null;
- Config_Init = NAD + getPCB() + RestartReader;
- SendReceive(Config_Init, ref Response, InitializationTimeOut);
- IsSerialPortOn = false;
- return ConnectReader();
- }
-
- // Update status
- void UpdateStatus()
- {
- error = ReaderError.NONE;
- // Cannot update status of reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return;
- }
- // Cannot update status if APDU is being sent
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return;
- }
- // Cannot update status if activating smart card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return;
- }
- // Create status command string
- string StatusCmdStr = NAD + getPCB() + CheckStatus;
- try
- {
- // Reset activated flag in case card is no longer activated
- CardActivated = false;
- // Send command to reader
- string Response = null;
- SendReceive(StatusCmdStr, ref Response, InitializationTimeOut);
- // Parse Response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- // If error, card is in error mode
- if (Packet.ErrorCode != PacketParser.ErrorType.None)
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- }
- else
- {
- // Decode card's response
- switch (int.Parse(Response.Substring(9, 1)))
- {
- case 0:
- atr = null;
- SlotStatus = NOCARD;
- break;
- case 4:
- atr = null;
- SlotStatus = PRESENT;
- break;
- case 6:
- SlotStatus = ACTIVATED;
- CardActivated = true;
- break;
- default:
- atr = null;
- SlotStatus = ERROR;
- return;
- }
- }
- return;
- }
- catch
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- return;
- }
- }
-
- // Send User SlotStatus if able to update
- internal override int GetStatus()
- {
- UpdateStatus();
- return SlotStatus;
- }
-
- // Activate card
- internal override bool ActivateCard()
- {
- error = ReaderError.NONE;
- // Cannot activate card if reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return false;
- }
- // If resetting card, the following will have already been checked
- if (!ResettingCard)
- {
- // Cannot activate card if sending APDU
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- // Cannot activate if already (de)activating
- if ((ActivatingSmartCard))
- {
- error = ReaderError.ACTIVATING_CARD;
- return false;
- }
- UpdateStatus();
- // No need to activate already activated card
- if (SlotStatus == ACTIVATED)
- {
- error = ReaderError.NONE;
- return true;
- }
- // Cannot activate card if there is no card
- else if (SlotStatus != PRESENT)
- {
- error = ReaderError.NO_CARD_INSERTED;
- return false;
- }
- }
- // Set activation command string
- string Response = null;
- string ActivationCmdStr = NAD + getPCB() + PowerOnSC;
- try
- {
- // Set activation flag
- ActivatingSmartCard = true;
- // Send command to reader
- SendReceive(ActivationCmdStr, ref Response, InitializationTimeOut);
- // Parse response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- // If no response, deactivate
- if (Packet.ErrorCode == PacketParser.ErrorType.NoResponse
- || Packet.ErrorCode == PacketParser.ErrorType.NACK)
- {
- string DeactivationCmdStr = NAD + getPCB() + PowerOffSC;
-
- SendReceive(DeactivationCmdStr, ref Response, InitializationTimeOut);
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
-
- SlotStatus = ERROR;
- error = ReaderError.NO_RESPONSE;
- ActivatingSmartCard = false;
- return false;
- }
- // If card malfunction, set error type appropriately
- else if (Packet.ErrorCode == PacketParser.ErrorType.CardMalfunction)
- {
- SlotStatus = ERROR;
- error = ReaderError.CARD_MALFUNCTION;
- ActivatingSmartCard = false;
- return false;
- }
- // Any other error, set status as error
- else if (Packet.ErrorCode != PacketParser.ErrorType.None)
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- ActivatingSmartCard = false;
- return false;
- }
- // No error means card is activated
- else
- {
- SlotStatus = ACTIVATED;
- atr = Response.Substring(8, Response.Length - 2 - 8);
- }
- // Update activation flags
- ActivatingSmartCard = false;
- CardActivated = true;
- return true;
- }
- catch
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- return false;
- }
- }
-
- // Send PPS
- bool SendPPS()
- {
- error = ReaderError.NONE;
- // Cannot send PPS if reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return false;
- }
- // Cannot send PPS if APDU is being sent
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- // Cannot send PPS if activating smart card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return false;
- }
- UpdateStatus();
- // Cannot send PPS if card is deactivated
- if (SlotStatus != ACTIVATED)
- {
- error = ReaderError.CARD_DEACTIVATED;
- return false;
- }
- // Error checking for protocol
- else if ((!Protocol.Equals("00")) && (!Protocol.Equals("01")))
- {
- error = ReaderError.BAD_PROTOCOL;
- return false;
- }
- // Set command string for PPS
- string SetParametersCmdStr = NAD + getPCB() + SetParametersCommand + PRT +
- FiDi + TC1 + TC2_TA3 + RFU_TB3 + "FF";
- try
- {
- // Send PPS to card
- string Response = null;
- SendReceive(SetParametersCmdStr, ref Response, InitializationTimeOut);
- // Parse Response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- return true;
- }
- catch
- {
- error = ReaderError.UNKNOWN_ERROR;
- return false;
- }
- }
-
- // Send PPS with user defined parameters
- internal override bool SendPPS(byte protocol)
- {
- error = ReaderError.NONE;
- // Set data from protocol
- byte prt = (byte)HexStringDecoder.HexStringToInt(PRT);
- Protocol = HexStringDecoder.ByteToHex(protocol);
- if (protocol == 1)
- {
- prt |= 8; // Set protocol bit to 1
- TC2_TA3 = "20"; // Set TA3 = IFSC to 32
- RFU_TB3 = "00"; // Set TB3 = BWI/CWI to 0/0
- }
- else if (protocol == 0)
- {
- prt &= 0xF7; // Set protocol bit to 0
- TC2_TA3 = "10"; // Set TC2 = WI to 16
- RFU_TB3 = "00"; // Set RFU to 0
- }
- else
- {
- error = ReaderError.BAD_PROTOCOL;
- return false;
- }
- // Set PRT based on current PCB value
- if (pcb)
- {
- prt &= 0xFD; // Set next PCB to "00"
- }
- else
- {
- prt |= 2; // Set next PCB to "40"
- }
- PRT = HexStringDecoder.ByteToHex(prt);
- // Send PPS with updated PRT
- return SendPPS();
- }
-
- // Deactivate card
- internal override bool DeactivateCard()
- {
- error = ReaderError.NONE;
- // Cannot deactivate card if reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return false;
- }
- // If resetting card, the following has already been done
- if (!ResettingCard)
- {
- // Cannot deactivate if currently activating
- if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return false;
- }
- // Cannot deactivate if APDU is being sent
- else if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- UpdateStatus();
- // No need to deactivate if card is already deactivated
- if (SlotStatus == PRESENT)
- {
- error = ReaderError.CARD_DEACTIVATED;
- return true;
- }
- // Cannot deactivate if there is no card
- else if (SlotStatus != ACTIVATED)
- {
- error = ReaderError.NO_CARD_INSERTED;
- return false;
- }
- }
- // Create deactivation command string
- string DeactivationCmdStr = NAD + getPCB() + PowerOffSC;
- try
- {
- // Set deactivating flag
- ActivatingSmartCard = true;
- // Send command to reader
- string Response = null;
- SendReceive(DeactivationCmdStr, ref Response, InitializationTimeOut);
- // Parse response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- // If error, assume card was not deactivated
- if (Packet.ErrorCode != PacketParser.ErrorType.None)
- {
- SlotStatus = ERROR;
- atr = null;
- error = ReaderError.UNKNOWN_ERROR;
- CardActivated = false;
- ActivatingSmartCard = false;
- return false;
- }
- else
- {
- SlotStatus = PRESENT;
- atr = null;
- }
- // Reset flags
- ActivatingSmartCard = false;
- CardActivated = false;
- return true;
- }
- catch
- {
- ActivatingSmartCard = false;
- CardActivated = false;
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- return false;
- }
- }
-
- // Reset card
- internal override bool ResetCard()
- {
- error = ReaderError.NONE;
- // Reader must be on to reset card
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return false;
- }
- // Cannot reset card while sending APDU
- else if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- // Cannot reset card if activiating card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return true;
- }
- UpdateStatus();
- // Cannot reset card if not there
- if (SlotStatus == NOCARD)
- {
- error = ReaderError.NO_CARD_INSERTED;
- return false;
- }
- // Set reset flag
- ResettingCard = true;
- // Deactivate card if necessary, then reactivate
- if (CardActivated)
- {
- DeactivateCard();
- }
- bool ret = ActivateCard();
- ResettingCard = false;
- return ret;
- }
-
- // Checks to see if reader is Connected or not
- internal override bool IsReaderActive()
- {
- error = ReaderError.NONE;
- return IsSerialPortOn;
- }
-
- // Executes a Command given as a parameter
- internal override string ExecuteCommand(string commandCode, string data)
- {
- error = ReaderError.NONE;
- // Cannot send command if reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return null;
- }
- // Cannot send command if APDU is being sent
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return null;
- }
- // Cannot send command if activiating card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return null;
- }
- // Create command string
- string CmdStr = NAD + getPCB()
- + HexStringDecoder.ByteToHex((byte)((commandCode.Length / 2) + (data.Length / 2)))
- + commandCode + data + "FF";
- try
- {
- // Send command to reader
- string Response = null;
- SendReceive(CmdStr, ref Response, InitializationTimeOut);
- // Parse response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- return Response;
- }
- catch
- {
- error = ReaderError.UNKNOWN_ERROR;
- return null;
- }
- }
-
- // Get current error
- internal override ReaderError Error
- {
- get
- {
- return error;
- }
- }
-
- // Get ATR
- internal override string ATR
- {
- get
- {
- return atr;
- }
- }
-
- // Send APDU to smart card
- internal override string SendAPDU(string apduText)
- {
- error = ReaderError.NONE;
- // Cannot send APDU if serial port is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return null;
- }
- // Cannot send APDU if another APDU is being sent
- else if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return null;
- }
- // Cannot send APDU if activating smart card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return null;
- }
- UpdateStatus();
- // Cannot send APDU if card is deactivated
- if (SlotStatus != ACTIVATED)
- {
- error = ReaderError.CARD_DEACTIVATED;
- return null;
- }
- // Start Sending Procedure
- APDUCommandComplete = false;
- string Response = null;
- string APDUCmdStr = NAD + getPCB() +
- HexStringDecoder.ByteToHex((byte)(apduText.Length / 2 + 1)) // Length
- + "15" + apduText + "FF";
- // Send APDU string
- try
- {
- SendReceive(APDUCmdStr, ref Response, TestTimeOut);
- // Parse Response string
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- Response = Packet.resp;
- APDUCommandComplete = true;
- return Response;
- }
- catch
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- return null;
- }
-
- }
- #endregion
-
-
- }
- }