Comment envoyer une commande brute à un tag ?
Par la classe ou le protocole qui correspond à la couche radio du tag : NfcA, NfcV ou IsoDep sur Android, NFCMiFareTag, NFCISO15693Tag ou NFCISO7816Tag dans une session de tag iOS. Le code construit les octets de la commande, la plateforme ajoute l'encadrement, et la réponse revient en octets que seul le code peut juger. Web NFC n'en envoie aucune.
Choisir le canal selon la couche radio
Sur Android, les classes de technologie qui envoient les octets tels quels exposent toutes transceive(). NfcA atteint les tags NFC-A, dont tous les tags de type 2 ; NfcV atteint les tags ISO/IEC 15693 ; IsoDep porte les APDU vers les tags et les cartes ISO/IEC 14443-4. MifareUltralight.transceive() revient, selon sa référence, à se connecter par NfcA et à appeler sa méthode.
Sur iOS, une commande brute demande une session de tag, une session NDEF ne remettant aucun canal de commande, comme l'explique la page des sessions. Le tag détecté arrive sous l'un des protocoles que Core NFC définit : NFCMiFareTag, dont sendMiFareCommand sert les tags MIFARE Ultralight, Plus et DESFire mais pas le protocole Crypto1 de MIFARE Classic ; NFCISO15693Tag, avec une méthode par commande standard ; NFCISO7816Tag, dont sendCommand(apdu:) envoie les APDU ; et NFCFeliCaTag pour FeliCa.
Une page web n'a aucun canal. Web NFC s'arrête au NDEF délibérément, comme le décrit la page de l'écriture en Web NFC, donc un projet qui a besoin de commandes brutes a besoin d'une application.
Ce que contiennent vos octets
La plateforme encadre ce que le code envoie, et chaque référence dit où cet encadrement s'arrête. NfcA.transceive() prend des octets complets et ajoute le CRC lui-même : la référence de NfcA demande aux applications de ne pas l'ajouter, et écarte les commandes qui servent à l'interrogation. NfcV.transceive() attend l'octet de drapeaux, le code de la commande et ses paramètres, et ajoute le CRC lui aussi. IsoDep.transceive() prend l'APDU seul, sans indicateur de trame, et découpe lui-même celui qui est long.
Core NFC ne place pas la limite au même endroit. La référence de sendMiFareCommand demande à l'application de calculer les deux octets de CRC d'une commande de la famille MIFARE Ultralight et de les ajouter, l'inverse de la règle d'Android, si bien qu'une commande recopiée d'un code Android arrive sans eux. Les méthodes ISO 15693 construisent toute la requête et l'adressent par défaut à l'identifiant du tag.
Quelle que soit la plateforme, une commande qu'aucun type de tag ne définit appartient à une puce. Son code et ses paramètres viennent de la fiche technique de cette puce, que ce site laisse aux fiches de puces de wakdev.com.
Lire la réponse
Un appel qui revient a délivré des octets, et c'est tout ce que la plateforme a vérifié. Que le tag ait accepté la commande est écrit à l'intérieur de ces octets, dans un format qui appartient au protocole.
Un tag ISO 15693 ouvre sa réponse par un octet de drapeaux dont le bit de poids faible signale une erreur, suivi d'un code d'erreur, selon les définitions de la pile NFC libre d'Android. Core NFC transforme une telle réponse en erreur dont les informations portent NFCISO15693TagResponseErrorKey, avec le code de la norme.
Un APDU finit par deux octets de statut, 90 00 quand la commande a abouti. La référence de sendCommand les rend comme sw1 et sw2, toujours valides, et garde son erreur pour les problèmes de communication : une carte qui refuse une commande répond normalement, le refus étant dans les octets de statut. La page des APDU liste les valeurs courantes.
Deux sortes d'échec
Un échec de transport veut dire qu'aucune réponse exploitable n'est arrivée. Sur Android, l'appel lève TagLostException quand le tag a quitté le champ et IOException pour les autres échecs. Sur iOS, les codes d'erreur comprennent readerTransceiveErrorTagConnectionLost, readerTransceiveErrorPacketTooLong pour une commande plus longue que ce que le tag accepte, et readerTransceiveErrorTagResponseError quand le tag a répondu par une erreur.
Une écriture qui finit sur un échec de transport a une issue inconnue. La commande a pu atteindre le tag avant que sa réponse ne se perde : relisez donc la mémoire avant de renvoyer quoi que ce soit, et écrivez dans un ordre qui ne laisse jamais un message à moitié valide, le sujet de la page des écritures interrompues.
Des limites s'appliquent avant tout cela. Combien d'octets un appel peut porter, et combien de temps il attend, changent d'un téléphone Android à l'autre, comme l'explique la page des limites du contrôleur : une commande qui marche sur le téléphone d'essai peut échouer sur un autre avant même d'atteindre le tag.
Questions fréquentes
Une page web peut-elle envoyer une commande brute à un tag ?
Non. Web NFC lit et écrit du NDEF seulement, donc les commandes brutes demandent une application Android ou iOS.
Mon code doit-il ajouter le CRC ?
Pas sur Android, où NfcA et NfcV l'ajoutent. La référence d'Apple le demande pour les commandes de la famille MIFARE Ultralight envoyées avec sendMiFareCommand.
Pourquoi une commande revient-elle sans rien avoir fait ?
La plateforme signale une réponse délivrée, pas une commande acceptée. Lisez le drapeau d'erreur d'une réponse ISO 15693, ou les octets de statut d'un APDU, avant de croire au résultat.
D'où viennent les commandes d'une puce particulière ?
De la fiche technique de cette puce. Cette rubrique couvre les commandes que définissent les types de tags du NFC Forum, et les fiches de puces de wakdev.com couvrent le reste.