有两种方法可以通过Java Smartcard IO API与此阅读器进行交互:
第一种是打开常规APDU传输通道(从PC/SC的角度来看,这映射到T = 0或T = 1协议).你可以使用
Card card = getCard("*");
但是,这将要求读者报告卡的存在.否则你无法以这种方式打开连接.
然后,您可以将APDU命令发送到卡(在基本通道或逻辑通道上),您可以在基本通道上向阅读器发送特殊命令.这些特殊命令将其类字节设置为0xFF,以指示该命令旨在由读取器解释(而不是转发到卡).因此,这不适用于以0xE0开头的"外设控制"命令.
必须使用带有控制代码的控制命令将这些"外围设备控制"命令发送到阅读器SCARD_CTL_CODE(3500)
.与打开卡的连接一样,getCard("*")
如果读卡器上有卡,则可以使用.但是,如果您希望能够将这些命令发送到阅读器,即使没有卡,也必须以"直接"模式打开连接:
Card card = getCard("DIRECT");
然后,您可以使用该方法发送控制命令card.transmitControlCommand()
.此方法将控制代码作为第一个参数,将命令(作为字节数组)作为第二个参数.在基本通道或任何逻辑通道上交换命令channel.transmit()
通常不能在"直接"模式下工作(因此错误代码为0x16).
控制代码计算为
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; } }
请注意Windows和其他平台之间的区别.
例如,要发送蜂鸣器控制命令,您将使用
byte[] command = new byte[] { (byte)0xE0, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x01, (byte)0x0A }; byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
最后,请注意,通过PC/SC发送IOCTL控制代码需要特殊的驱动程序支持.具体来说,Microsoft提供的标准CCID驱动程序默认情况下不支持发送转义命令(请参阅USB CCID类驱动程序详细信息).此驱动程序仅在通过注册表值"EscapeCommandEnable"启用它们后才支持转义命令.0x1
您在问题中显示的错误是这个缺少对escape命令的支持的典型结果.
要可靠地支持阅读器的所有功能(包括转义命令),您需要在其网站上使用ACS提供的"PC/SC驱动程序"包.