PageRenderTime 112ms CodeModel.GetById 51ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 0ms

/PCSCMicro/Teridian/Device.cs

#
C# | 900 lines | 675 code | 47 blank | 178 comment | 149 complexity | b2275074198d7e22f82a9068b8f5cefb MD5 | raw file
  1/***************************************************************************
  2 * This code was adapted from TSPC_CCID.cs which was originally written by *
  3 * Teridian SemiConductor, Corp. It has been modified from its original    *
  4 * version to allow for use in the .NET Micro Framework. Additions have    *
  5 * been made to the original version to allow a broader use of the reader. *
  6 * LAST MODIFIED: 2010 April 23                                            *
  7 * Copyright (C) 2009 Gemalto                                              *
  8 ***************************************************************************/
  9/***************************************************************************
 10 *  Device.cs is part of the PC/SC Micro API for the .NET Micro            *
 11 *  Framework.                                                             *
 12 *                                                                         *
 13 *  The PC/SC Micro API for the .NET Micro Framework is free software:     *
 14 *  you can redistribute it and/or modify it under the terms of the GNU    *
 15 *  General Public License as published by the Free Software Foundation,   *
 16 *  either version 2 of the License, or (at your option) any later version.*
 17 *                                                                         *
 18 *  The PC/SC Micro API for the .NET Micro Framework is distributed in     *
 19 *  the hope that it will be useful, but WITHOUT ANY WARRANTY; without even*
 20 *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    *
 21 *  PURPOSE.  See the GNU General Public License for more details.         *
 22 *                                                                         *
 23 *  You should have received a copy of the GNU General Public License      *
 24 *  along with the PC/SC Micro API for the .NET Micro Framework. If not,   *
 25 *  see <http://www.gnu.org/licenses/>.                                    *
 26 ***************************************************************************/
 27using System;
 28using Microsoft.SPOT;
 29using Microsoft.SPOT.Hardware;
 30
 31namespace PCSCMicro
 32{
 33    internal class Device : Reader
 34    {
 35        #region Definition of constants and global variables
 36
 37        // Collecting Data TimeOut Design Setting
 38        int TestTimeOut = 15 * 60;       // Timeout for APDU calculated to second
 39        int InitializationTimeOut = 10;  // Apply to non-APDU and non-EMV testing command, in second
 40        int TimeOutUnitInMiliSec = 500;  // This TimeOut is independent with the ones in Min and Sec
 41
 42        // Hard-coded configuration constants
 43        string ACK = "C0AAC0";
 44        string NACK = "C055C0";
 45        string PowerOnReader = "C0110000041E05FFFFC0";      //9600 with 30 seconds timeout
 46        string PowerOnSC = "C03362";
 47        string PowerOffSC = "C03363";
 48        string CheckStatus = "C03365";
 49        string SetParametersCommand = "C03361";
 50        string APDUCommand = "C0336F";
 51        
 52        // Dynamic Strings used for commands
 53        string Config_Init;
 54        string SlotID = "00";
 55
 56        // Slip character definition
 57        const byte END = 0xC0;
 58        const byte ESC = 0xDB;
 59        const byte ESC_END = 0xDC;
 60        const byte ESC_ESC = 0xDD;
 61        byte[] ESC_END_ARR = new byte[] { ESC, ESC_END };
 62        byte[] ESC_ESC_ARR = new byte[] { ESC, ESC_ESC };
 63
 64        // Keep track of slot status
 65        const int ACTIVATED = 0;
 66        const int PRESENT = 1;
 67        const int NOCARD = 2;
 68        const int ERROR = 3;
 69        int SlotStatus = NOCARD;
 70
 71        // Maximum number of log lines
 72        const int MaxBytes = 4096;
 73
 74        // Flags used for running processes
 75        bool IsSerialPortOn = false;
 76        bool APDUCommandComplete = true;
 77        bool ActivatingSmartCard = false;
 78        bool CardActivated = false;
 79        bool ResettingCard = false;
 80
 81        // Retry counter for Serial Port Communication
 82        int NumberOfRetries;
 83
 84        // Serial Port
 85        string port = "COM1";
 86        int baudrate = 9600;
 87        System.IO.Ports.SerialPort ComPort = new System.IO.Ports.SerialPort(System.IO.Ports.Serial.COM1);
 88
 89        // Packet parser
 90        PacketParser Packet = new PacketParser();
 91
 92        // PPS Strings
 93        string Protocol = "00";//Protocol to be set by user later
 94        string FiDi = "11";//FiDi to be set by user later
 95
 96        // Card characteristics
 97        ReaderError error = ReaderError.NONE;
 98        string atr = null;
 99
100        #endregion
101
102        /*****************************************************************************/
103        /*                                                                           */
104        /*      Serial Port Communication: Initialize, Send and Receive Data         */
105        /*                                                                           */
106        /*****************************************************************************/
107
108        #region Serial Port Interface
109
110        // Initialize Serial Port 
111        void InitializeComPort(int baudrate, System.IO.Ports.Handshake handShake)
112        {
113            if (!ComPort.IsOpen)
114            {
115                // Set COM port properties
116                ComPort.BaudRate = baudrate;
117                ComPort.Parity = System.IO.Ports.Parity.None;
118                ComPort.StopBits = System.IO.Ports.StopBits.One;
119                ComPort.DataBits = 8;
120                ComPort.Handshake = handShake;
121                ComPort.ReadTimeout = 5000;
122                ComPort.Open();
123            }
124        }
125
126        // Computer CRC of the sending string
127        // CRC is computed using the following formula 
128        // over the CMD and Information fields:
129        // F(x) = 1 + x^2 + x^15 + x^16
130        ushort ComputeCRC(byte[] bArr, int offset, int bytecount)
131        {
132            ushort CRC = 0;
133            byte d;
134            int count = 0;
135            while (count++ < bytecount)
136            {
137                d = bArr[count + offset - 1];
138                for (int i = 8; i > 0; i--)
139                {
140                    if (((CRC ^ d) & 1) > 0)
141                        CRC = (ushort)((CRC >> 1) ^ 0xA001);
142                    else
143                        CRC >>= 1;
144                    d >>= 1;
145                }
146            }
147            // LittleEndian
148            CRC = (ushort)(~CRC);
149            return CRC;
150        }
151
152        // Check whether byte at bytecount is inside the packet
153        bool IsInsidePacket(byte[] byteArray, int length)
154        {
155            // () is used for current byte
156            // (C0)AAC0 or (C0)55C0
157            if ((length < byteArray.Length - 2) && (byteArray[length] == 0xC0) && (byteArray[length + 2] == 0xC0))
158            {
159                return false;
160            }
161            // C0AA(C0) or C055(C0)
162            if ((length > 1) && (byteArray[length] == 0xC0) && (byteArray[length - 2] == 0xC0))
163            {
164                return false;
165            }
166            // C0(AA)C0 or C0(55)C0
167            if ((length > 0) && (byteArray[length - 1] == 0xC0) && (byteArray[length + 1] == 0xC0))
168            {
169                return false;
170            }
171            return true;
172        }
173
174        // Check if the packet received is complete
175        bool IsComplete(byte[] byteArray, int length)
176        {
177            // Definition: Complete = ACK + C0 + (Data) + CRC1 + CRC2 + C0 = 3 + 1 + (Data) + 1 + 1 + 1 > 7 bytes
178            // or a NACK response (no wait for a NACK)
179            if (((length > 7) && (byteArray[length - 1] == 0xC0)) ||
180                (HexStringDecoder.ByteArrayToString(byteArray, length) == NACK))
181                return true;
182            return false;
183       }
184
185        // Send an array of bytes to the serial port
186        void SendReceive(string Message, ref string Response, int InputTimeOutInSec)
187        {
188            int RetryNACK = NumberOfRetries;
189        SendLabel:   // Used when receiving a NACK response, comand sending must be resent
190            /*-----------------------------------*/
191            /*     Send data to the Serial Port  */
192            /*-----------------------------------*/
193
194            #region Send data to the Serial Port
195            //Convert Hex String to Byte Array
196            byte[] myBuffer = new byte[Message.Length / 2]; // reserve 2 byte for CRC
197            myBuffer = HexStringDecoder.StringToByteArray(Message);
198            if ((Message != ACK) && (Message != NACK))
199            {
200                // CRC Calculation
201                ushort CRC = ComputeCRC(myBuffer, 1, myBuffer.Length - 4);
202                myBuffer[myBuffer.Length - 2] = (byte)(CRC & 0x00FF);
203                myBuffer[myBuffer.Length - 3] = (byte)(CRC >> 8);
204            }
205            // Update Message to include Error detection bits
206            Message = HexStringDecoder.ByteArrayToString(myBuffer, myBuffer.Length);
207            ComPort.DiscardInBuffer();
208            ComPort.DiscardOutBuffer();
209            // Send single byte in the byte array so it can be parsed
210            // Check to include escape characters
211            for (int i = 0; i < myBuffer.Length; i++)
212            {
213                if ((myBuffer[i] == 0xC0) && (i != 0) && (i != myBuffer.Length - 1))
214                {
215                    ComPort.Write(ESC_END_ARR, 0, 2);
216                }
217                else if ((myBuffer[i] == 0xDB) && (i != 0) && (i != myBuffer.Length - 1))
218                {
219                    ComPort.Write(ESC_ESC_ARR, 0, 2);
220                }
221                else
222                {
223                    ComPort.Write(myBuffer, i, 1);
224                }
225            }
226            #endregion
227
228            /*-----------------------------------*/
229            /* Receive data from the Serial Port */
230            /*-----------------------------------*/
231
232            #region Receive data from the Serial Port
233            // Initialize receive related variables
234            int TimeOutCycleCountDown = (InputTimeOutInSec * 1000 / TimeOutUnitInMiliSec);
235            bool TimeOut = false;
236            int bytecount = 0;
237            byte[] byteArrayBuffer = new byte[MaxBytes];
238            byte[] byteArrayReturn = new byte[MaxBytes];
239            // Reset the data string received and the byte received
240            Response = "";
241            // Unnecessary to collect data if it's an ACK or NACK
242            if ((Message == ACK) || (Message == NACK))
243                return;
244            // Do the loop if there's no timeout or the timeout cycle still exists
245            while ((!TimeOut) && (TimeOutCycleCountDown > 0) && (bytecount < MaxBytes))
246            {
247                // Attempt to read from COM port
248                if (1 == ComPort.Read(byteArrayBuffer, bytecount, 1))
249                {
250                    bytecount++;
251                }
252                else
253                {
254                    // If no response, set error and return
255                    error = ReaderError.NO_RESPONSE;
256                    return;
257                }
258                // Check if end of packet has been received
259                if (IsComplete(byteArrayBuffer, bytecount))
260                {
261                    TimeOut = true;
262                }
263            }
264            // Copy data response and dectect ESC characters
265            int j = 0;
266            for (int i = 0; i < bytecount; i++)
267            {
268                if (IsInsidePacket(byteArrayBuffer, i))
269                {
270                    if (byteArrayBuffer[i] == ESC)
271                    {
272                        switch (byteArrayBuffer[i + 1])
273                        {
274                            case ESC_END: // DBDC = C0
275                                byteArrayReturn[j++] = 0xC0;
276                                i += 2;
277                                break;
278                            case ESC_ESC: // DBDD = DB
279                                byteArrayReturn[j++] = 0xDB;
280                                i += 2;
281                                break;
282                            default:
283                                break;
284                        }
285                    }
286                }
287                byteArrayReturn[j++] = byteArrayBuffer[i];
288            }
289            Response = HexStringDecoder.ByteArrayToString(byteArrayReturn, j);
290            #endregion
291
292            /*-----------------------------------*
293             *        Handling NACK reponse      *
294             *-----------------------------------*/
295
296            #region Handling NACK reponse
297            // Prepare to resend the command
298            if ((Response != null) && (Response.Length >= NACK.Length) &&
299                (Response.Substring(0, NACK.Length) == NACK) && (RetryNACK-- > 0))
300            {
301                // Terminate all the running command after a number of retries when receiving NACK response
302                if (RetryNACK == 0)
303                {
304                    goto SendLabel;
305                }
306            }
307            #endregion
308        }
309        
310        #endregion
311
312        /*****************************************************************************/
313        /*                                                                           */
314        /*          Smart Card and Reader Communication                              */
315        /*                                                                           */
316        /*****************************************************************************/
317
318        #region Smart Card
319
320        // Validate responses
321        void ResponseValidation(PacketParser packet)
322        {
323            string Response = null;
324            // Infinite Loop detection 
325            if ((packet.ErrorCode == PacketParser.ErrorType.Timeout)
326                || (packet.ErrorCode == PacketParser.ErrorType.NoResponse)
327                || (packet.ErrorCode == PacketParser.ErrorType.NACK))
328            {
329                error = ReaderError.NO_RESPONSE;
330            }
331            // Other error detection
332            else if (packet.ErrorCode != PacketParser.ErrorType.None)
333            {
334                error = ReaderError.UNKNOWN_ERROR;
335                SendReceive(ACK, ref Response, TestTimeOut);
336            }
337            // Correct data response
338            else
339            {
340                error = ReaderError.NONE;
341                SendReceive(ACK, ref Response, TestTimeOut);
342            }
343        }
344
345        // Connect reader
346        internal override bool ConnectReader()
347        {
348            error = ReaderError.NONE;
349            string Response = null;
350            // Set port properties
351            port = "COM1";
352            baudrate = 9600;
353            // If reader is already on, no need to turn on again
354            if (IsSerialPortOn)
355            {
356                error = ReaderError.ALREADY_CONNECTED;
357                return true;
358            }
359            try
360            {
361                // Open COM port
362                InitializeComPort(baudrate, System.IO.Ports.Handshake.None);
363                Config_Init = PowerOnReader;
364                // Collect number of Retries if NACK receive
365                NumberOfRetries = (int)Convert.ToByte(Config_Init.Substring(12, 2));
366                // Send connect command to reader
367                SendReceive(Config_Init, ref Response, InitializationTimeOut);
368                // Make sure board connected
369                Packet.GetPacket(Response);
370                ResponseValidation((PacketParser)Packet);
371                if (Packet.ErrorCode == PacketParser.ErrorType.None)
372                {
373                    IsSerialPortOn = true;
374                    return true;
375                }
376                else
377                {
378                    IsSerialPortOn = false;
379                    error = ReaderError.PORT_CONNECTION_FAILED;
380                    if (ComPort.IsOpen)
381                    {
382                        ComPort.Close();
383                    }
384                    return false;
385                }
386            }
387            catch
388            {
389                if (ComPort.IsOpen)
390                {
391                    ComPort.Close();
392                }
393                error = ReaderError.PORT_CONNECTION_FAILED;
394                return false;
395            }
396        }
397
398        // Disconnect reader
399        internal override bool DisconnectReader()
400        {
401            error = ReaderError.NONE;
402            // Cannot disconnect reader if sending APDU
403            if ((!APDUCommandComplete))
404            {
405                error = ReaderError.TEST_RUNNING;
406                return false;
407            }
408            // Reader is already off
409            else if (!IsSerialPortOn)
410            {
411                error = ReaderError.READER_OFF;
412                return true;
413            }
414            // Close Port, reset port and board flags
415            ComPort.Close();
416            IsSerialPortOn = false;
417            return true;
418        }
419
420        // Reset reader
421        internal override bool ResetReader()
422        {
423            error = ReaderError.NONE;
424            // Disconnect then connect reader
425            if (IsSerialPortOn)
426            {
427                if (DisconnectReader())
428                {
429                    return false;
430                }
431            }
432            return ConnectReader();
433        }
434
435        // Update status
436        bool UpdateStatus()
437        {
438            error = ReaderError.NONE;
439            // Cannot update status of reader is off
440            if (!IsSerialPortOn)
441            {
442                error = ReaderError.READER_OFF;
443                return false;
444            }
445            // Cannot update status if APDU is being sent
446            if ((!APDUCommandComplete))
447            {
448                error = ReaderError.TEST_RUNNING;
449                return false;
450            }
451            // Cannot update status if activating smart card
452            else if (ActivatingSmartCard)
453            {
454                error = ReaderError.ACTIVATING_CARD;
455                return false;
456            }
457            // Create status command string
458            string StatusCmdStr = CheckStatus + SlotID + "FFFFCO";
459            try
460            {
461                // Reset activated flag in case card is no longer activated
462                CardActivated = false;
463                // Send command to reader
464                string Response = null;
465                SendReceive(StatusCmdStr, ref Response, InitializationTimeOut);
466                // Parse Response
467                Packet.GetPacket(Response);
468                ResponseValidation(Packet);
469                // If error, card is in error mode
470                if (Packet.ErrorCode != PacketParser.ErrorType.None)
471                {
472                    SlotStatus = ERROR;
473                    error = ReaderError.UNKNOWN_ERROR;
474                }
475                else
476                {
477                    // Decode card's response
478                    switch (HexStringDecoder.StringToByteArray(Response)[4 + 3]) // first 3 bytes are ACK or NACK characters
479                    {
480                        case NOCARD:
481                            atr = null;
482                            SlotStatus = NOCARD;
483                            break;
484                        case PRESENT:
485                            atr = null;
486                            SlotStatus = PRESENT;
487                            break;
488                        case ACTIVATED:
489                            SlotStatus = ACTIVATED;
490                            CardActivated = true;
491                            break;
492                        default:
493                            atr = null;
494                            SlotStatus = ERROR;
495                            return false;
496                    }
497                }
498                return true;
499            }
500            catch
501            {
502                SlotStatus = ERROR;
503                error = ReaderError.UNKNOWN_ERROR;
504                return false;
505            }
506        }
507
508        // Send User SlotStatus after status update
509        internal override int GetStatus()
510        {
511            UpdateStatus();
512            return SlotStatus;
513       }
514
515        // Activate card
516        internal override bool ActivateCard()
517        {
518            error = ReaderError.NONE;
519            // Cannot activate card if reader is off
520            if (!IsSerialPortOn)
521            {
522                error = ReaderError.READER_OFF;
523                return false;
524            }
525            // If resetting card, the following will have already been checked
526            if (!ResettingCard)
527            {
528                // Cannot activate card if sending APDU
529                if ((!APDUCommandComplete))
530                {
531                    error = ReaderError.TEST_RUNNING;
532                    return false;
533                }
534                UpdateStatus();
535                // No need to activate already activated card
536                if (SlotStatus == ACTIVATED || (ActivatingSmartCard))
537                {
538                    error = ReaderError.ACTIVATING_CARD;
539                    return true;
540                }
541                // Cannot activate card if there is no card
542                else if (SlotStatus != PRESENT)
543                {
544                    error = ReaderError.NO_CARD_INSERTED;
545                    return false;
546                }
547            }
548            // Set activation command string
549            string Response = null;
550            string testMode = "0103"; // sets to ISO mode ("01") and power at 5V ("03")
551            string ActivationCmdStr = PowerOnSC + SlotID + testMode + "FFFFC0";
552            try
553            {
554                // Set activation flag
555                ActivatingSmartCard = true;
556                // Send command to reader
557                SendReceive(ActivationCmdStr, ref Response, InitializationTimeOut);
558                // Parse response
559                Packet.GetPacket(Response);
560                ResponseValidation(Packet);
561                // If no response, deactivate
562                if (Packet.ErrorCode == PacketParser.ErrorType.NoResponse
563                    || Packet.ErrorCode == PacketParser.ErrorType.NACK)
564                {
565                    string DeactivationCmdStr = PowerOffSC + SlotID + "FFFFC0";
566                    SendReceive(DeactivationCmdStr, ref Response, InitializationTimeOut);
567                    Packet.GetPacket(Response);
568                    ResponseValidation(Packet);
569                    SlotStatus = ERROR;
570                    error = ReaderError.NO_RESPONSE;
571                    ActivatingSmartCard = false;
572                    return false;
573                }
574                // Any other error, set status as error
575                else if (Packet.ErrorCode != PacketParser.ErrorType.None)
576                {
577                    SlotStatus = ERROR;
578                    error = ReaderError.UNKNOWN_ERROR;
579                    ActivatingSmartCard = false;
580                    return false;
581                }
582                // No error means card is activated
583                else
584                {
585                    SlotStatus = ACTIVATED;
586                    atr = Response.Substring(14, Response.Length - 6 - 14);
587                }
588                // Update activation flags
589                ActivatingSmartCard = false;
590                CardActivated = true;
591                return true;
592            }
593            catch
594            {
595                SlotStatus = ERROR;
596                error = ReaderError.UNKNOWN_ERROR;
597                return false;
598            }
599        }
600
601        // Send PPS
602        bool SendPPS()
603        {
604            error = ReaderError.NONE;
605            // Cannot send PPS if reader is off
606            if (!IsSerialPortOn)
607            {
608                error = ReaderError.READER_OFF;
609                return false;
610            }
611            // Cannot send PPS if APDU is being sent
612            if ((!APDUCommandComplete))
613            {
614                error = ReaderError.TEST_RUNNING;
615                return false;
616            }
617            // Cannot send PPS if activating smart card
618            else if (ActivatingSmartCard)
619            {
620                error = ReaderError.ACTIVATING_CARD;
621                return false;
622            }
623            UpdateStatus();
624            // Cannot send PPS if card is deactivated
625            if (SlotStatus != ACTIVATED)
626            {
627                error = ReaderError.CARD_DEACTIVATED;
628                return false;
629            }
630            // Error checking for protocol
631            else if ((!Protocol.Equals("00")) && (!Protocol.Equals("01")))
632            {
633                error = ReaderError.BAD_PROTOCOL;
634                return false;
635            }
636            // Set command string for PPS
637            string SetParametersCmdStr = SetParametersCommand + SlotID + Protocol + FiDi + "0000FFFFC0";
638            try
639            {
640                // Send PPS to card
641                string Response = null;
642                SendReceive(SetParametersCmdStr, ref Response, InitializationTimeOut);
643                // Parse Response
644                Packet.GetPacket(Response);
645                ResponseValidation(Packet);
646                return true;
647            }
648            catch
649            {
650                error = ReaderError.UNKNOWN_ERROR;
651                return false;
652            }
653        }
654
655        // Send PPS with user defined parameters
656        internal override bool SendPPS(byte protocol)
657        {
658            error = ReaderError.NONE;
659            if(protocol != 1 && protocol != 0)
660            {
661                error = ReaderError.BAD_PROTOCOL;
662                return false;
663            }
664            Protocol = HexStringDecoder.ByteToHex(protocol);
665            return SendPPS();
666        }
667
668        // Deactivate card
669        internal override bool DeactivateCard()
670        {
671            error = ReaderError.NONE;
672            // Cannot deactivate card if reader is off
673            if (!IsSerialPortOn)
674            {
675                error = ReaderError.READER_OFF;
676                return false;
677            }
678            // If resetting card, the following has already been done
679            if (!ResettingCard)
680            {
681                // Cannot deactivate if currently activating
682                if (ActivatingSmartCard)
683                {
684                    error = ReaderError.ACTIVATING_CARD;
685                    return false;
686                }
687                // Cannot deactivate if APDU is being sent
688                else if ((!APDUCommandComplete))
689                {
690                    error = ReaderError.TEST_RUNNING;
691                    return false;
692                }
693                UpdateStatus();
694                // No need to deactivate if card is already deactivated
695                if (SlotStatus == PRESENT)
696                {
697                    error = ReaderError.CARD_DEACTIVATED;
698                    return true;
699                }
700                // Cannot deactivate if there is no card
701                else if (SlotStatus != ACTIVATED)
702                {
703                    error = ReaderError.NO_CARD_INSERTED;
704                    return false;
705                }
706            }
707            // Create deactivation command string
708            string DeactivationCmdStr = PowerOffSC + SlotID + "FFFFC0";
709            try
710            {
711                // Set deactivating flag
712                ActivatingSmartCard = true;
713                // Send command to reader
714                string Response = null;
715                SendReceive(DeactivationCmdStr, ref Response, InitializationTimeOut);
716                // Parse response
717                Packet.GetPacket(Response);
718                ResponseValidation(Packet);
719                // If error, assume card was not deactivated
720                if (Packet.ErrorCode != PacketParser.ErrorType.None)
721                {
722                    SlotStatus = ERROR;
723                    atr = null;
724                    error = ReaderError.UNKNOWN_ERROR;
725                    ActivatingSmartCard = false;
726                    return false;
727                }
728                else
729                {
730                    SlotStatus = PRESENT;
731                    atr = null;
732                }
733                // Reset flags
734                ActivatingSmartCard = false;
735                CardActivated = false;
736                return true;
737            }
738            catch
739            {
740                SlotStatus = ERROR;
741                error = ReaderError.UNKNOWN_ERROR;
742                return false;
743            }
744        }
745
746        // Reset card
747        internal override bool ResetCard()
748        {
749            error = ReaderError.NONE;
750            // Reader must be on to reset card
751            if (!IsSerialPortOn)
752            {
753                error = ReaderError.READER_OFF;
754                return false;
755            }
756            // Cannot reset card while sending APDU
757            else if ((!APDUCommandComplete))
758            {
759                error = ReaderError.TEST_RUNNING;
760                return false;
761            }
762            // Cannot reset card if activiating card
763            else if (ActivatingSmartCard)
764            {
765                error = ReaderError.ACTIVATING_CARD;
766                return true;
767            }
768            UpdateStatus();
769            // Cannot reset card if not there
770            if (SlotStatus == NOCARD)
771            {
772                error = ReaderError.NO_CARD_INSERTED;
773                return false;
774            }
775            // Set reset flag
776            ResettingCard = true;
777            // Deactivate card if necessary, then reactivate
778            if (CardActivated)
779            {
780                DeactivateCard();
781            }
782            bool ret = ActivateCard();
783            ResettingCard = false;
784            return ret;
785        }
786
787        // Checks to see if reader is Connected or not
788        internal override bool IsReaderActive()
789        {
790            error = ReaderError.NONE;
791            return IsSerialPortOn;
792        }
793
794        // Executes a Command given as a parameter
795        internal override string ExecuteCommand(string commandCode, string data)
796        {
797            error = ReaderError.NONE;
798            // Cannot send command if reader is off
799            if (!IsSerialPortOn)
800            {
801                error = ReaderError.READER_OFF;
802                return null;
803            }
804            // Cannot send command if APDU is being sent
805            if ((!APDUCommandComplete))
806            {
807                error = ReaderError.TEST_RUNNING;
808                return null;
809            }
810            // Cannot send command if activiating card
811            else if (ActivatingSmartCard)
812            {
813                error = ReaderError.ACTIVATING_CARD;
814                return null;
815            }
816            // Create command string
817            string CmdStr = "C0" + commandCode + SlotID + data + "FFFFC0";
818            try
819            {
820                // Send command to reader
821                string Response = null;
822                SendReceive(CmdStr, ref Response, InitializationTimeOut);
823                // Parse response
824                Packet.GetPacket(Response);
825                ResponseValidation(Packet);
826                Response = Packet.ResMsg;
827               return Response;
828            }
829            catch
830            {
831                error = ReaderError.UNKNOWN_ERROR;
832                return null;
833            }
834        }
835
836        // Get current error
837        internal override ReaderError Error
838        {
839            get
840            {
841                return error;
842            }
843        }
844
845        // Get ATR
846        internal override string ATR
847        {
848            get
849            {
850                return atr;
851            }
852        }
853
854        // Send APDU to smart card
855        internal override string SendAPDU(string apduText)
856        {
857            error = ReaderError.NONE;
858            // Cannot send APDU if serial port is off
859            if (!IsSerialPortOn)
860            {
861                error = ReaderError.READER_OFF;
862                return null;
863            }
864            // Cannot send APDU if another APDU is being sent
865            else if ((!APDUCommandComplete))
866            {
867                error = ReaderError.TEST_RUNNING;
868                return null;
869            }
870            // Cannot send APDU if activating smart card
871            else if (ActivatingSmartCard)
872            {
873                error = ReaderError.ACTIVATING_CARD;
874                return null;
875            }
876            UpdateStatus();
877            // Cannot send APDU if card is deactivated
878            if (SlotStatus != ACTIVATED)
879            {
880                error = ReaderError.CARD_DEACTIVATED;
881                return null;
882            }
883            // Start Sending Procedure
884            APDUCommandComplete = false;
885            string Response = null;
886            string APDUCmdStr = APDUCommand + SlotID + apduText + "FFFFC0"; ;
887            // Send APDU string
888            SendReceive(APDUCmdStr, ref Response, TestTimeOut);
889            // Parse Response string
890            Packet.GetPacket(Response);
891            ResponseValidation(Packet);
892            Response = Packet.resp;
893            APDUCommandComplete = true;
894            return Response;
895
896        }
897        #endregion
898
899    }
900}