PageRenderTime 62ms CodeModel.GetById 26ms app.highlight 28ms RepoModel.GetById 2ms app.codeStats 0ms

/PCSCMicro/GemCore/Device.cs

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