我正在尝试更改ACR1252U上的蜂鸣器持续时间。
API链接: http://www.acs.com.hk/download-manual/6402/API-ACR1252U-1.09.pdf
根据API文档,我需要'E0000028010A'命令来更改蜂鸣器状态,其中'0A'将持续时间标记为0A * 10ms(页44)。
使用以下Java代码:
public static void main(String[] args) {
try {
byte[] send = new byte[6];
send[0] = (byte) 0xE0; // Commandclass
send[1] = (byte) 0x00; // Protocoll
send[2] = (byte) 0x00; // Param 1
send[3] = (byte) 0x28; // Param 2: Buzzerstatus
send[4] = (byte) 0x01; // Change Flag
send[5] = (byte) 0x0A; // Duration: 0A*10ms => 100ms
Card card = getCard("DIRECT"); // Works!
CardChannel channel = card.getBasicChannel(); // Works!
CommandAPDU command = new CommandAPDU(send); // Works!
channel.transmit(command); // EXCEPTION!
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Card getCard(String target) throws Exception {
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
for (CardTerminal t : terminals) {
if (t.getName().equals("ACS ACR1252 Dual Reader PICC 0")) {
Card card = t.connect(target);
return card;
}
}
throw new Exception();
}
但这会导致以下stacktrace指示“未知错误0x16”:
javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x16
at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
at readerconfig.TagConfig.main(TagConfig.java:24)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x16
at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:188)
... 2 more
我花了好几个小时在这个方向寻找任何东西,但我找不到任何东西。我甚至尝试过另一个设备,它仍然会产生这个错误。
要么我完全失明了,要么我的电脑没有正确设置。我只能说,我已经使用这款阅读器成功地从NFC标签上书写和阅读。但我无法改变读者本身的配置。
修改
我还发现了另一种发送命令的方法:
byte[] send = new byte[5];
send[0] = (byte) 0xE0;
send[1] = (byte) 0x0;
send[2] = (byte) 0x0;
send[3] = (byte) 0x18; // Tries to read firmware version
send[4] = (byte) 0x0;
Card card = CardUtils.getCard("DIRECT"); // Works!
card.transmitControlCommand(3500, send);
但这会导致“未知错误0x1”:
javax.smartcardio.CardException: transmitControlCommand() failed
at sun.security.smartcardio.CardImpl.transmitControlCommand(CardImpl.java:236)
at readerconfig.ReaderConfig.main(ReaderConfig.java:28)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x1
at sun.security.smartcardio.PCSC.SCardControl(Native Method)
at sun.security.smartcardio.CardImpl.transmitControlCommand(CardImpl.java:232)
... 1 more
答案 0 :(得分:5)
有两种方法可以通过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 Class Driver Details)。此驱动程序仅在通过注册表值“EscapeCommandEnable”启用它们后才支持转义命令。您在问题中显示的错误0x1
是对转义命令缺失支持的典型结果。
要可靠地支持阅读器的所有功能(包括转义命令),您需要使用ACS on their website提供的“PC / SC驱动程序”包。
答案 1 :(得分:1)
尝试使用
card.transmitControlCommand(int controlCode, byte[] command)
而不是传输。根据第5.8节(您链接到的pdf的第41页) controlcode是3500,虽然我不清楚,如果是十六进制或int,所以如果你能够,则与SCARD_CTL_CODE比较。至少,我解释了这个文档。
通常你使用transmitControlCommand与读者交谈并发送与卡谈话。
修正了ControlCode中的拼写错误。感谢Torhan Bartel告诉我。