PageRenderTime 64ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

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