/PCSCMicro/Teridian/Device.cs
C# | 900 lines | 675 code | 47 blank | 178 comment | 149 complexity | b2275074198d7e22f82a9068b8f5cefb 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. Additions have *
- * been made to the original version to allow 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
- string ACK = "C0AAC0";
- string NACK = "C055C0";
- string PowerOnReader = "C0110000041E05FFFFC0"; //9600 with 30 seconds timeout
- string PowerOnSC = "C03362";
- string PowerOffSC = "C03363";
- string CheckStatus = "C03365";
- string SetParametersCommand = "C03361";
- string APDUCommand = "C0336F";
-
- // Dynamic Strings used for commands
- string Config_Init;
- string SlotID = "00";
-
- // Slip character definition
- const byte END = 0xC0;
- const byte ESC = 0xDB;
- const byte ESC_END = 0xDC;
- const byte ESC_ESC = 0xDD;
- byte[] ESC_END_ARR = new byte[] { ESC, ESC_END };
- byte[] ESC_ESC_ARR = new byte[] { ESC, ESC_ESC };
-
- // 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 counter for Serial Port Communication
- int NumberOfRetries;
-
- // Serial Port
- string port = "COM1";
- 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
-
- // 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();
- }
- }
-
- // Computer CRC of the sending string
- // CRC is computed using the following formula
- // over the CMD and Information fields:
- // F(x) = 1 + x^2 + x^15 + x^16
- ushort ComputeCRC(byte[] bArr, int offset, int bytecount)
- {
- ushort CRC = 0;
- byte d;
- int count = 0;
- while (count++ < bytecount)
- {
- d = bArr[count + offset - 1];
- for (int i = 8; i > 0; i--)
- {
- if (((CRC ^ d) & 1) > 0)
- CRC = (ushort)((CRC >> 1) ^ 0xA001);
- else
- CRC >>= 1;
- d >>= 1;
- }
- }
- // LittleEndian
- CRC = (ushort)(~CRC);
- return CRC;
- }
-
- // Check whether byte at bytecount is inside the packet
- bool IsInsidePacket(byte[] byteArray, int length)
- {
- // () is used for current byte
- // (C0)AAC0 or (C0)55C0
- if ((length < byteArray.Length - 2) && (byteArray[length] == 0xC0) && (byteArray[length + 2] == 0xC0))
- {
- return false;
- }
- // C0AA(C0) or C055(C0)
- if ((length > 1) && (byteArray[length] == 0xC0) && (byteArray[length - 2] == 0xC0))
- {
- return false;
- }
- // C0(AA)C0 or C0(55)C0
- if ((length > 0) && (byteArray[length - 1] == 0xC0) && (byteArray[length + 1] == 0xC0))
- {
- return false;
- }
- return true;
- }
-
- // Check if the packet received is complete
- bool IsComplete(byte[] byteArray, int length)
- {
- // Definition: Complete = ACK + C0 + (Data) + CRC1 + CRC2 + C0 = 3 + 1 + (Data) + 1 + 1 + 1 > 7 bytes
- // or a NACK response (no wait for a NACK)
- if (((length > 7) && (byteArray[length - 1] == 0xC0)) ||
- (HexStringDecoder.ByteArrayToString(byteArray, length) == NACK))
- 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))
- {
- // CRC Calculation
- ushort CRC = ComputeCRC(myBuffer, 1, myBuffer.Length - 4);
- myBuffer[myBuffer.Length - 2] = (byte)(CRC & 0x00FF);
- myBuffer[myBuffer.Length - 3] = (byte)(CRC >> 8);
- }
- // 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
- // Check to include escape characters
- for (int i = 0; i < myBuffer.Length; i++)
- {
- if ((myBuffer[i] == 0xC0) && (i != 0) && (i != myBuffer.Length - 1))
- {
- ComPort.Write(ESC_END_ARR, 0, 2);
- }
- else if ((myBuffer[i] == 0xDB) && (i != 0) && (i != myBuffer.Length - 1))
- {
- ComPort.Write(ESC_ESC_ARR, 0, 2);
- }
- else
- {
- 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 no response, 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 response and dectect ESC characters
- int j = 0;
- for (int i = 0; i < bytecount; i++)
- {
- if (IsInsidePacket(byteArrayBuffer, i))
- {
- if (byteArrayBuffer[i] == ESC)
- {
- switch (byteArrayBuffer[i + 1])
- {
- case ESC_END: // DBDC = C0
- byteArrayReturn[j++] = 0xC0;
- i += 2;
- break;
- case ESC_ESC: // DBDD = DB
- byteArrayReturn[j++] = 0xDB;
- i += 2;
- break;
- default:
- break;
- }
- }
- }
- byteArrayReturn[j++] = byteArrayBuffer[i];
- }
- Response = HexStringDecoder.ByteArrayToString(byteArrayReturn, j);
- #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;
- }
- }
- #endregion
- }
-
- #endregion
-
- /*****************************************************************************/
- /* */
- /* Smart Card and Reader Communication */
- /* */
- /*****************************************************************************/
-
- #region Smart Card
-
- // Validate responses
- void ResponseValidation(PacketParser packet)
- {
- string Response = null;
- // Infinite Loop detection
- if ((packet.ErrorCode == PacketParser.ErrorType.Timeout)
- || (packet.ErrorCode == PacketParser.ErrorType.NoResponse)
- || (packet.ErrorCode == PacketParser.ErrorType.NACK))
- {
- error = ReaderError.NO_RESPONSE;
- }
- // Other error detection
- else if (packet.ErrorCode != PacketParser.ErrorType.None)
- {
- error = ReaderError.UNKNOWN_ERROR;
- SendReceive(ACK, ref Response, TestTimeOut);
- }
- // Correct data response
- else
- {
- error = ReaderError.NONE;
- SendReceive(ACK, ref Response, TestTimeOut);
- }
- }
-
- // Connect reader
- internal override bool ConnectReader()
- {
- error = ReaderError.NONE;
- string Response = null;
- // Set port properties
- port = "COM1";
- baudrate = 9600;
- // If reader is already on, no need to turn on again
- if (IsSerialPortOn)
- {
- error = ReaderError.ALREADY_CONNECTED;
- return true;
- }
- try
- {
- // Open COM port
- InitializeComPort(baudrate, System.IO.Ports.Handshake.None);
- Config_Init = PowerOnReader;
- // Collect number of Retries if NACK receive
- NumberOfRetries = (int)Convert.ToByte(Config_Init.Substring(12, 2));
- // Send connect command to reader
- SendReceive(Config_Init, ref Response, InitializationTimeOut);
- // Make sure board connected
- Packet.GetPacket(Response);
- ResponseValidation((PacketParser)Packet);
- if (Packet.ErrorCode == PacketParser.ErrorType.None)
- {
- IsSerialPortOn = true;
- return true;
- }
- else
- {
- IsSerialPortOn = false;
- error = ReaderError.PORT_CONNECTION_FAILED;
- if (ComPort.IsOpen)
- {
- ComPort.Close();
- }
- return false;
- }
- }
- 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;
- // Disconnect then connect reader
- if (IsSerialPortOn)
- {
- if (DisconnectReader())
- {
- return false;
- }
- }
- return ConnectReader();
- }
-
- // Update status
- bool UpdateStatus()
- {
- error = ReaderError.NONE;
- // Cannot update status of reader is off
- if (!IsSerialPortOn)
- {
- error = ReaderError.READER_OFF;
- return false;
- }
- // Cannot update status if APDU is being sent
- if ((!APDUCommandComplete))
- {
- error = ReaderError.TEST_RUNNING;
- return false;
- }
- // Cannot update status if activating smart card
- else if (ActivatingSmartCard)
- {
- error = ReaderError.ACTIVATING_CARD;
- return false;
- }
- // Create status command string
- string StatusCmdStr = CheckStatus + SlotID + "FFFFCO";
- 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 (HexStringDecoder.StringToByteArray(Response)[4 + 3]) // first 3 bytes are ACK or NACK characters
- {
- case NOCARD:
- atr = null;
- SlotStatus = NOCARD;
- break;
- case PRESENT:
- atr = null;
- SlotStatus = PRESENT;
- break;
- case ACTIVATED:
- SlotStatus = ACTIVATED;
- CardActivated = true;
- break;
- default:
- atr = null;
- SlotStatus = ERROR;
- return false;
- }
- }
- return true;
- }
- catch
- {
- SlotStatus = ERROR;
- error = ReaderError.UNKNOWN_ERROR;
- return false;
- }
- }
-
- // Send User SlotStatus after status 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;
- }
- UpdateStatus();
- // No need to activate already activated card
- if (SlotStatus == ACTIVATED || (ActivatingSmartCard))
- {
- error = ReaderError.ACTIVATING_CARD;
- 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 testMode = "0103"; // sets to ISO mode ("01") and power at 5V ("03")
- string ActivationCmdStr = PowerOnSC + SlotID + testMode + "FFFFC0";
- 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 = PowerOffSC + SlotID + "FFFFC0";
- SendReceive(DeactivationCmdStr, ref Response, InitializationTimeOut);
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- SlotStatus = ERROR;
- error = ReaderError.NO_RESPONSE;
- 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(14, Response.Length - 6 - 14);
- }
- // 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 = SetParametersCommand + SlotID + Protocol + FiDi + "0000FFFFC0";
- 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;
- if(protocol != 1 && protocol != 0)
- {
- error = ReaderError.BAD_PROTOCOL;
- return false;
- }
- Protocol = HexStringDecoder.ByteToHex(protocol);
- 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 = PowerOffSC + SlotID + "FFFFC0";
- 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;
- ActivatingSmartCard = false;
- return false;
- }
- else
- {
- SlotStatus = PRESENT;
- atr = null;
- }
- // Reset flags
- ActivatingSmartCard = false;
- CardActivated = false;
- return true;
- }
- catch
- {
- 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 = "C0" + commandCode + SlotID + data + "FFFFC0";
- try
- {
- // Send command to reader
- string Response = null;
- SendReceive(CmdStr, ref Response, InitializationTimeOut);
- // Parse response
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- Response = Packet.ResMsg;
- 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 = APDUCommand + SlotID + apduText + "FFFFC0"; ;
- // Send APDU string
- SendReceive(APDUCmdStr, ref Response, TestTimeOut);
- // Parse Response string
- Packet.GetPacket(Response);
- ResponseValidation(Packet);
- Response = Packet.resp;
- APDUCommandComplete = true;
- return Response;
-
- }
- #endregion
-
- }
- }