after very useful tips from user vlp, I have finally been able to connect to an AT24C16 I2C card with my ACR39 card reader through the java smartcard API (original thread).
Since the free memory card I want to read is not a smart card, I need to use pseudo APDU commands to talk to the card via Card.transmitControlCommand
. The card reader came with a great documentation that contains all the commands I need (basically I just need to read the data on the card).
While everything seems to work fine, I don't get any response from the card or from the reader (when querying the firmware).
I have this:
package com.Smaca;
import java.util.List;
import javax.smartcardio.*;
public class SReader {
public static void readCard() {
TerminalFactory factory = TerminalFactory.getDefault();
// GET_READER_INFORMATION
// I believe this is the correct command - the manual specifies 11h as the last byte
// I tried both
byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0xB};
//byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0x11};
//SELECT_CARD_TYPE
byte[] SELECT_CARD_TYPE = new byte[] { (byte)0xFF, (byte)0xA4, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x01 };
//SELECT_PAGE_SIZE
byte[] SELECT_PAGE_SIZE = new byte[] { (byte)0xFF, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x04 };
//READ_MEMORY_CARD
byte[] READ = new byte[] { (byte)0xFF, (byte)0xB0, (byte)0xFF, (byte)0x00, (byte)0xFF };
int SCARD_CTL_CODE = 3500;
try {
List terminals = factory.terminals().list();
CardTerminal ter = (CardTerminal)terminals.get(0);
ter.waitForCardPresent(3000000);
if(ter.isCardPresent())
{
System.out.println("Card present");
Card ca = ter.connect("direct");
System.out.println(ca);
byte[] response_info = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), GET_R_INFO);
System.out.println("Reader info: "+ bytesToHex(response_info));
byte[] response = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_CARD_TYPE);
System.out.println("Select card: "+bytesToHex(response));
byte[] response_ps = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_PAGE_SIZE);
System.out.println("Select page size: "+ bytesToHex(response_ps));
byte[] response_read = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), READ);
System.out.println("Data read: "+ bytesToHex(response_read));
}
System.out.println( "is Card Present: " + ((CardTerminal)terminals.get(0)).isCardPresent());
} catch (CardException e) {
e.printStackTrace();
}
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte hashByte : bytes) {
int intVal = 0xff & hashByte;
if (intVal < 0x10) {
sb.append('0');
}
sb.append(Integer.toHexString(intVal));
}
return sb.toString();
}
public static final int SCARD_CTL_CODE(int command)
{
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
if (isWindows) {
return 0x00310000 | (command << 2);
} else {
return 0x42000000 | command;
}
}
public static void main(String[] args) {
readCard();
}
}
And this is the output:
Card present
PC/SC card in ACS ACR39U ICC Reader, protocol Unknown protocol 4, state OK
Reader info:
Select card:
Select page size:
Data read:
is Card Present: true
Can anyone see what I'm doing wrong? At the very least the GET_READER_INFORMATION command should work?!
UPDATE:
I think I know what the problem is. I only transmitted the raw data of the commands but they need to be transmitted as payload of the PC_to_RDR_XfrBlock
command (Chapter 7.1.4.).
I'm still having problems formatting the command, though. If anyone has any idea how to do that, please let me know. A concrete example would be great.
Thanks! Tom