NFC IV – Les types de messages du NFC Forum
Ce billet sera l’occasion de rentrer dans les détails de plusieurs type de message Ndef définis par le NFC Forum. Nous verrons dans un premier temps, les différents Type Name Format (TNF) prévus par le consortium, puis je décrirai les types des messages NFC les plus courants, tels que l’Uri et le Text.
L’En-tête d’un message Ndef
Les premiers octets d’un message Ndef constituent son en-tête. Ils contiennent divers informations sur la nature du message. Pour être plus précis, un message Ndef peut contenir plusieurs enregistrements (Record) et ce sont ces Record Ndef qui contiennent un en-tête.
MB, ME et CR
Les 3 premiers bits permettent de situer le Record par rapport aux autres. Le premier, MB (pour Message Begin), permet d’indiquer si le Record est le premier du message, le second, ME (pour Message End), permet d’indiquer s’il est le dernier. Ainsi, un message qui contient un unique enregistrement commencera par 11.
Le troisième bit, CR (pour Chunk Record), permet d’indiquer que le payload est tronqué et partagé sur plusieurs enregistrements. Nous ne rentrerons pas dans les détails de ce mécanisme dans cet article mais précisons tout de même que tout les enregistrements doivent être dans le même message.
SR
Le quatrième bit, SR (pour Short Record), permet d’indiquer que l’enregistrement est de petite taille. Par conséquent, le champs Payload Length sera d’un octet (taille maximale du payload de 255 octets) contre 4 octets dans le cas contraire.
IL
Le cinquième bit, IL (pour ID Length field present), permet d’indiquer la présence d’un identifiant de Record. S’il vaut 1, alors les champs ID Length et ID seront présents (voir schéma récapitulatif).
TNF
Enfin, les 3 derniers bits de ce premier octet décrivent le TNF (Type Name Format) de l’enregistrement. Les différents TNF sont :
- 0x00 Vide : Enregistrement vide
- 0x01 Well-Known Type (WKT) : Type défini par le NFC Forum (voir plus loin)
- 0x02 Type MIME
- 0x03 Absolute Uri (voir plus loin le WKT Uri)
- 0x04 External (voir le second billet de cette série)
- 0x05 Type non connu
- 0x06 Type inchangé (utilisé pour les enregistrements tronqués)
- 0x07 réservé pour un usage futur
Type Length
Le deuxième octet de l’en-tête précise le taille du type. Le TNF indique une sorte de catégorie
de type, mais pas le type lui-même. Le type précis étant de taille variable (“image/jpeg”, “Sp”, …), ce champs permet d’indiquer le nombre d’octet qu’occupera le type dans l’en-tête.
Payload Length
Ce champs détaille la taille en octet du payload. En fonction de la valeur de SR, ce champs a une taille de 1 ou 4 octets.
ID Length
Ce champs, s’il est présent indique la taille en octet de l’identifiant de l’enregistrement.
Type et ID
L’en-tête se termine par successivement les champs Type et ID dont la taille et/ou la présence sont conditionnées par les champs précédents et représentant respectivement le type du payload et l’identifiant de l’enregistrement.
Les Well-Known Types
Je vais maintenant présenter 3 des WKT que sont Uri, Text et SmartPoster. Les deux premiers types, bien que pouvant laisser présager de leur simplicité, ont été spécifiés de manière à optimiser la taille du message, ce qui nécessite de les détailler.
URI
Le type URI permet comme son nom l’indique de stocker une URI (Uniform Resource Identifier). Un message URI utilise donc le TNF WKT (0x01) et son type de taille 1 octet est désigné par la lettre U majuscule (0x55). Mais l’intérêt du type URI réside dans le fait qu’on s’affranchit d’encoder le préfixe de l’URI dans le payload, ce qui peut faire économiser jusqu’à une dizaine d’octets.
Le premier octet du payload désigne donc le préfixe de l’URI. Voici une sélection des préfixes définis par le NFC Forum.
- 0x00 : pas de préfixe
- 0x01 : http://www.
- 0x02 : https://www.
- 0x03 : http://
- 0x04 : https://
- 0x05 : tel:
- 0x06 : mailto:
- 0x1D : file://
- 0x24…0xFF : réservés pour un usage futur
Ainsi, si on reprend l’exemple donné dans le premier billet
D1 01 10 55 03 62 6C 6F 67 2E 7A 65 6E 69 6B 61 2E 63 6F 6D
D1 : MB=1, ME=1, CR=0, SR=1, IL=0, TNF=001
01 : type sur 1 octet
10 : payload sur 16 octets
55 : type U (URI)
03 : préfixe http://
626C6F672E7A656E696B612E636F6D : blog.zenika.com
Il est également possible d’utiliser le TNF Absolute Uri (0x03) si on ne souhaite pas utiliser les préfixes.
Text
Le type Text permet de contenir du texte brut, mais en indiquant son encodage ainsi que sa langue. Un message Text utilise donc le TNF WKT (0x01) et son type de taille 1 octet est désigné par la lettre T majuscule (0x54). Le premier octet du payload d’un enregistrement Text indique l’encodage du texte et le nombre d’octets qui sont utilisés pour décrire la langue. Ainsi, le premier bit indique l’encodage UTF-8 s’il vaut 0 et UTF-16 s’il vaut 1. Le second bit n’est pas utilisé pour le moment et doit être positionné à 0. Les 6 bits suivants indique la taille en octets de la langue.
Les n octets qui suivent le premier indiquent donc la langue du texte, puis les octets suivants le texte.
Voici le message pour le texte “Hello World !” avec comme langue “en-US” et encodé en utf-8.
D1 01 13 54 // x x x T 05 65 6E 2D // x e n - 55 53 48 65 // U S H e 6C 6C 6F 20 // l l o 57 6F 72 6C // W o r l 64 20 21 00 // d ! x
et le texte “NFC” avec pour langue “fr” en utf-8
D1 01 06 54 // x x x T 02 66 72 4E // x f r N 46 43 00 00 // F C x x
SmartPoster
Le type SmartPoster est une sorte d’extension du type Uri. Il permet autour d’un enregistrement Uri, d’ajouter des informations supplémentaires. Ces informations supplémentaires peuvent être un titre (enregistrement Text), éventuellement dans plusieurs langues, une icône, la taille et le type de la ressource vers laquelle pointe l’Uri.
Un message SmartPoster est un enregistrement unique dont le type de taille 2 est désigné par les lettres Sp (0x53, 0x70); ce n’est pas un ensemble d’enregistrements. Par contre, son payload est constitué d’un enregistrement Uri et des différents enregistrements correspondant aux informations supplémentaires. L’Uri et ses ajouts sont ainsi encapsulés
dans le SmartPoster.
Voici pour exemple, un SmartPoster constitué de l’Url du blog et du titre Blog
en français (fr).
D1 02 1F 53 // x x x S 70 91 01 10 // p x x x 55 03 62 6C // U x b l 6F 67 2E 7A // o g . z 65 6E 69 6B // e n i k 61 2E 63 6F // a . c o 6D 51 01 07 // m x x x 54 02 66 72 // T x f r 42 6C 6F 67 // B l o g
Le 5 premiers octets nous indiquent qu’il s’agit d’un enregistrement unique (MB = 1 et ME = 1) de 31 octets (0x1F) dont le type est Sp
. Par contre le sixième octet (0x91) indique un premier enregistrement qui ne sera pas le dernier (MB = 1 et ME = 0). De même, le 26ème octet indique un enregistrement final (MB = 0 et ME = 1).
Et avec Android ?
Les WKT du NFC Forum permettent d’optimiser les messages Ndef, mais nécessitent de mettre les mains dans le cambouis
. Malheureusement, en l’état actuel des choses, l’API NFC d’Android ne nous sera pas d’un grand secours. La seule facilité offerte pour le moment permet de transformer une Uri
en NdfRecord
. Il n’y a rien pour le texte ou les SmartPoster et rien pour les opérations inverses.
Voici comment créer le SmartPoster de l’exemple précédent
NdefRecord uriRecord = NdefRecord.createUri("http://blog.zenika.com"); String title = "Blog"; byte[] textPayload = new byte[title.length() + 3]; textPayload[0] = 0x02; String lg = "fr"; System.arraycopy(lg.getBytes(), 0, textPayload, 1, lg.length()); System.arraycopy(title.getBytes(), 0, textPayload, 1 + lg.length(), title.length()); NdefRecord textRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], textPayload); NdefMessage payloadSp = new NdefMessage(new NdefRecord[] {uriRecord, textRecord}); NdefRecord spRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_SMART_POSTER, new byte[0], payloadSp.toByteArray()); NdefMessage spMsg = new NdefMessage(new NdefRecord[] {spRecord});