2017-01-25 4 views
2

J'essaie de modifier la durée du buzzer sur l'ACR1252U.Erreur inconnue 0x16 sur l'accès du lecteur de carte à puce

Lien vers API: http://www.acs.com.hk/download-manual/6402/API-ACR1252U-1.09.pdf

Selon la documentation de l'API j'ai besoin commande 'E0000028010A' pour changer le statut de l'avertisseur sonore, selon laquelle '0A' marque la durée que 0A * 10ms (Page 44).

Après le code Java est utilisé:

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(); 
} 

Mais il en résulte la stacktrace suivante indiquant la "erreur 0x16 unkown":

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 

J'ai passé des heures à chercher quoi que ce soit dans ce direction cependant je ne pouvais rien trouver. J'ai même essayé un autre appareil, qui a encore généré cette erreur.

Soit je suis complètement devenu aveugle ou quelque chose n'est pas configuré correctement avec mon ordinateur. Tout ce que je peux dire, c'est que j'ai déjà écrit et lu avec succès des étiquettes NFC en utilisant ce lecteur. Mais je ne peux tout simplement pas changer la config du lecteur lui-même.

EDIT:

J'ai aussi trouvé cette alternative pour envoyer la commande:

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); 

Mais cela se traduit par la "erreur inconnue 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 
+1

https://bugs.openjdk.java.net/browse/JDK-6359908? –

+0

Essayez d'utiliser d'abord la commande E1, pour lire le contrôle du buzzer. Si cela fonctionne, une étape sera franchie: la communication a été établie. – Aubin

+0

Même erreur ... @RC. Im en utilisant T = 0. –

Répondre

3

Il existe deux façons d'interagir avec ce lecteur sur l'API Java Smartcard IO:

  1. Le premier est d'ouvrir un canal de transmission de APDU régulière (d'un point de vue PC/SC cela correspond à T = 0 ou T = 1 protocole). Vous pouvez le faire en utilisant

    Card card = getCard("*"); 
    

    Cependant, cela nécessitera que le lecteur signale la présence d'une carte. Sinon, vous ne pouvez pas ouvrir une connexion de cette façon.

    Vous pouvez ensuite transmettre des commandes APDU à la carte (sur le canal de base ou un canal logique) et vous pouvez envoyer des commandes spéciales au lecteur sur le canal de base. Ces commandes spéciales ont leur octet de classe défini sur 0xFF pour indiquer que la commande est destinée à être interprétée par le lecteur (au lieu d'être transmise à la carte).Donc, ceci n'est pas applicable pour les commandes de "contrôle des périphériques" qui commencent par 0xE0. Ces commandes de «contrôle des périphériques» doivent être envoyées au lecteur à l'aide de commandes de contrôle avec le code de contrôle SCARD_CTL_CODE(3500). Comme avec l'ouverture d'une connexion à la carte, vous pouvez utiliser getCard("*") s'il y a une carte présente sur le lecteur. Toutefois, si vous voulez être en mesure d'envoyer ces commandes au lecteur, même s'il n'y a pas présente de carte, vous devez ouvrir une connexion en mode « direct »:

    Card card = getCard("DIRECT"); 
    

    Vous pouvez ensuite envoyer des commandes de contrôle à l'aide du méthode card.transmitControlCommand(). Cette méthode prend le code de contrôle comme premier argument et la commande (comme byte array) comme second argument. L'échange de commandes sur le canal de base ou sur tout canal logique utilisant channel.transmit() ne fonctionnera généralement pas en mode "direct" (d'où le code d'erreur 0x16).

    Le code de contrôle est calculé comme

    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; 
        } 
    } 
    

    Notez la différence entre Windows et d'autres plates-formes.

    Par exemple, pour envoyer la commande de contrôle de l'avertisseur sonore, utilisez

    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); 
    

    Enfin, sachez que l'envoi des codes de contrôle IOCTL sur PC/SC nécessite le support de pilote spécial. Plus précisément, le pilote CCID standard fourni par Microsoft ne prend pas en charge l'envoi de commandes d'échappement par défaut (voir USB CCID Class Driver Details). Ce pilote prend en charge les commandes d'échappement uniquement après leur activation via la valeur de Registre "EscapeCommandEnable". L'erreur 0x1 que vous avez montrée dans votre question est un résultat typique de ce support manquant pour les commandes d'échappement.

    Pour prendre en charge de façon fiable toutes les fonctions du lecteur (y compris les commandes d'échappement), vous devez utiliser le package "Pilotes PC/SC" fourni par ACS on their website.

0

Essayez d'utiliser

card.transmitControlCommand(int controlCode, byte[] command) 

au lieu de transmettre. Selon la section 5.8 (page 41 du pdf vous avez lié à) le code de contrôle est 3500, bien qu'il ne soit pas clair pour moi, si c'est un hex ou un int, ainsi comparez à SCARD_CTL_CODE, si vous pouvez. Au moins, j'interprète la documentation ceci.

Habituellement, vous utilisez transmitControlCommand pour parler au lecteur et transmettre pour parler à la carte.

Caractère fixe dans ControlCode. Bravo à Torhan Bartel pour m'avoir dit.

+0

Le code de contrôle est 3500, vous avez une faute de frappe là ... Malheureusement j'ai déjà essayé cela. Avec 3500 et 13568 (= 0x3500). Les deux renvoient l'erreur 0x1. –

+0

Aussi si vous vous connectez avec "*"? Meilleur pour essayer de lire la version du firmware d'abord –

+0

Aussi avec "*" ... Aucune des commandes fonctionnent:/ –