2013年7月5日金曜日

AARメッセージをゲットする

NFCの便利なところは何と言ってもタッチだけでいろんな動作をさせることができるところではないでしょうか。これの肝となるAndroidの機能が、タグディスパッチシステムというものになります。
Androidデバイスは画面がロック状態でなければ常にNFCタグを探しています。そして見つかるとすばやく中身を見てNDEFかどうか判断したりして、それからそれを必要とするアプリケーションへ通知します。この部分がタグディスパッチシステムになります。

で、どのアプリが必要としているかはアプリのマニフェストファイルに記述した内容で判断されます。
「こういうタグがきたら俺を呼んでくれ」的なことをアプリのマニフェストファイルに書いておくわけですね。

マニフェストに指定する場合、まずは大きな分類として「NDEF_DISCOVERD」、「TECH_DISCOVERD」、「TAG_DISCOVERD」の3種類の指定方法があります。タグがNDEFだった場合、まずはNDEF_DISCOVERDをくれと設定してあるアプリから検索され、見つかればそのアプリを起動します。複数あった場合は、例の選択画面が出てきます。それが無かった場合、今度はTECH_DISCOVERDをくれと設定してあるアプリを探します。それでも無い場合はTAG_DISCOVERDをくれのアプリを探します。

また、NDEF_DISCOVERDとTECH_DISCOVERDはさらに細かい設定ができます。NDEFの場合はスマートポスターがきたらとか、特定のメッセージに反応するように指定できます。TECH_DISCOVERDの方は、反応したいタグの種類(タイプAとかBとかFeliCaとか)を指定できます。

例えば、

<intent-filter>  
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimetype="text/plain" />
</intent-filter>

のように記述しておくと、テキストのNDEFが書かれているタグがきたら教えてくれるようになるわけですね。で、アプリ側ではonCreateあたりでgetIntentをすれば、NDEF_DISCOVERDの情報を含んだインテントがゲットできるわけです。

話は変わってNDEFなんですが、Android4.0からAAR(あんどろいど あぷりけーしょん れこーど)というのが追加されています。これはアプリケーションを一意に選択できるアプリのパッケージ名をデータとするレコードで、これがNDEFメッセージに含まれているとそのアプリケーションを起動してくれるという便利な機能です。さらには端末にそのアプリケーションがインストールされてない場合はGoogle Playの該当アプリのダウンロードページに飛ばしてくれるという至れり尽くせりの機能です。

ということでここからこれらの話がつながってくるんですが、AARを書き込んで起動してくれるようにしておいて、さらに起動時にゲットしたインテントからタグのUIDを取ろうとしたんですが、これがうまく行きませんでした。

起動してくれるんやからマニフェストの指定はいらんやろ~ということでまずは記述しなかったんですが、それだと起動時に取得できるインテントにタグ情報が含まれていませんでした。よってUIDの取得ができません。

じゃあTECH_DISCOVERDでも入れるか~ということで入れてもダメ。まあ、AARといってもNDEFですから、タグディスパッチシステムはNDEFとして認識してるはず、よっしゃもうこうなったらNDEF_DISCOVERD入れたろ~ということで入れてもダメ。
NDEF_DISCOVERDの詳細設定が必要なのか?でもAARって何?NFCフォーラムで規定されてるもんじゃないよね?アンドロイドってネーミングに入ってるし。
困ったときのNFC TagInfoということでAARを書き込んだタグを見てみると、


おー、えくすたーなる?そういえばそういうのあったな。ということでドキュメントを見ると、エクスターナルの場合は

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
        android:host="ext"
        android:pathPrefix="/example.com:externalType"/>
</intent-filter>

こんな風に指定せいと書いてありました。じゃあ、この「example.com:externalType」の部分を「android.com:pkg」にすればいいのかな?ということでこんな風に変更してみると。

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
        android:host="ext"
        android:pathPrefix="/android.com:pkg"/>
</intent-filter>

うまく行きましたー。ちゃんと1回の読み取りで、AARから起動→アプリでUIDを取得までできるようになりましたー。だから何とかやめてー。

2013年6月18日火曜日

インベントリのパラメータを試す1

UHF帯のRFIDタグを読み取りする場合、リーダでインベントリというのを行います。インベントリを行うと、たくさんタグがあってもアンチコリジョンとかうまくやってくれて、こんなタグがあったよーというのを通知してくれます。そのインベントリですが、動作を設定するパラメータがわんさかあります。
今回はその中で Session というのを試してみます。

Gen2のタグには、インベントリ済みフラグというのが内蔵されています。リーダの読み取り範囲にたくさんタグがある場合、すべてのタグが同じように返答していたらこれはなかなかすべてを聞き分けるのは難しいです。そこで、自分はもうインベントリされたよというフラグをタグが持っていて、インベントリ済みの場合はもう黙っておくということになっています。そうすることでインベントリが済んでいないタグだけが返答するようになります。

で、このフラグなんですが、インベントリされたらフラグを ON にするんですが、こんどは OFF にするタイミングはどうするのさ?という問題が出てきます。リーダから「ほうらお前らインベントリフラグを OFF にするんだ」的なコマンドを出すのが1つのやり方です。それだけだとずっと ON の状態のままのタグも出てきてしまいますので、一定時間過ぎたら OFF にするという仕組みにもなっています。で、一定時間って何よ。どんだけよ。という話になるんですが、これが Session の設定になります。

SessionにはS0、S1、S2、S3と4種類あって、S0は速攻で OFF にします。正確にはリーダからの電波が途切れてチップへの給電が無くなったら OFF になります。S1は 500msくらい ON の状態を保持します。S2とS3は違いがよくわからないんですが、どちらも5秒ほど ON の状態を保持します。

S0だと、すぐにフラグがリセットされるのでタグがやいのやいの反応し、タグがたくさんある場合に混線が生じます。S2とかにすると急におとなしくなって、短時間に何度も読み取りしようとすると反応しない場合があるわけです。

試してみましょう。いつものMorphicです。


設定の右下に「Session」がありますねー。
まずは0でタグの読み取りをします。
タグは適当に15個ほど置きました。


読み取りを開始するとピーピーピーピーひっきりなしに音がしています。
しばらく読み取ってから統計を見てみると、


平均して53個/秒で読み取りしたようです。
では Session を3にしてもう一回読み取ります。
今度は何回かピーといった後、全然音がしなくなりました。読み取ってない(タグが黙ってる)ようです。
しばらく読み取ってから統計を見てみると、


平均で2個/秒になってしまいました。
というわけで Session の効果はかなり違いが出るようです。
大量にタグがあって、1回読めばもういいや―的な場合は3、タグは少量で高速で読み取りたい場合は0に設定するのがいいようです。

2013年6月17日月曜日

NTAG210のUIDミラーを試してみる

NTAGの新しいシリーズにNTAG210とNTAG212がありますが今回NTAG210を入手しましたので早速試してみました。新シリーズでは新しくUIDミラーという機能が搭載されています。タグのUIDをNDEFメッセージの任意の場所にミラーできるという機能です。

NTAG210とNTAG212ですが仕様書を見るとサイズの違いだけのようです。NTAG210は80byte、NTAG212は164byteです。自由に書込みできる容量だけみると、NTAG210はMifareUltralightと同じ48byte、NTAG212はNTAG203より少し少ない128byteになっています。

こちらがNTAG210のBullsEyeです。


中身を見てみます。


Page3の1バイト目が 0xE1 になってますのでNDEFフォーマットされています。データは 0x03 0x00 0xFE で空のNDEFが確かに入っていますね。
まずここにタグのUIDをパラメータとするURLを書きます。


書きました。UIDの部分は 00 00 00 00 00 00 00 にしています。
ここでタグに細工をするとこのUIDの部分にタグ自身のUIDがコピーされるようになります。
正確には上書きされるのではなくて、タグ読み込み時に置き換えられるようです。
細工はNTAG210の場合Page16に行います。Page16の構造は仕様書によりますと、

  Page 16   MIRROR_BYTE  RFUI  MIRROR_PAGE  AUTH0

となっています。MIRROR_BYTEとMIRROR_PAGEで、何ページの何バイト目にミラーするかを指定します。ですので、UIDをミラーしたい開始のページ(4~15)とバイト(0~3)を書き込むわけです。
MIRROR_PAGEには開始ページをそのまま書けばいいですが、MIRROR_BYTEの方は特殊で上位3ビット目と4ビット目の2ビットを使って0~3を指定するようです。

ではやってみましょう。先ほど書き込んだタグのデータを見てみると、


Page10の2バイト目から 0x30 (ASCIIで数字の0)が続いているので、ここにミラーすればいいようです。というわけで MIRROR_PAGE には 0x0A(Page10)、MIRROR_BYTE には2進数で 0001 0000(16進数で 0x10)を書込みます。
書き込んだあと、もう一度NDEF読み込みをしてみると、


ちゃんとUIDのところにタグのUIDが表示されています!便利ですねー。

ネットと連携させる場合、ほとんどの場合タグのUIDをパラメータとするURLを使用します。そうするとタグごとにエンコードする内容が異なることになります。しかしこの機能を利用すればエンコードする内容はすべてのタグで同じにできるわけですね。なるほど。

2013年6月6日木曜日

Galaxy Nexusの謎

NFCには3つのモード(リーダ/ライタモード・P2Pモード・カードエミュレーションモード)がありますが、カードエミュレーションモードが使用できる端末はあまりなくて、Galaxy Nexusもカードエミュレーションには対応していません。しかしカードエミュレーションに対応してないからといってUIDが無いわけでもありません。
MANICA EXCEL TOOLとACR122リーダを使用してGalaxy NexusをACRリーダにのせてみると、


ほら、IDが入ってきます。ですがACR122の方は激しくピコピコピーピーしています。そのままにしておくと、


あら、どんどん別のIDが入ってきます。何なんでしょうか、これは。

NFCIP-1という通信規格を見てみると、この答えがあるようです。
NFCIP-1ではNFCIDというものが出てきます。これは複数のタグが通信範囲に存在する場合、1枚をどのように特定するかといういわゆるアンチコリジョンを実現するためのIDになります。

で、このNFCIDですが、規格では基本的にランダムということになっています。
同じ通信範囲の特定の1つを選択できればよいわけですから、ランダムでもOKなんですね。
ただ、NTAGやFeliCaなどのチップの場合は独自に設定された自分のUID(IDm)をNFCIDとしているわけです。

具体的にどんな感じなんでしょうか。
NFCIDにはNFCID1、NFCID2、NFCID3の3つ(※NFCIP-1の場合)があるようです。

NFCID1
106kbpsの通信速度で、カスケードレベルというのがあって、レベル1の場合は4byte、レベル2は7byte、レベル3は10byteのNFCIDになります。4byte、7byteということで何となくわかるかと思いますがMIFAREですね。NFC-A相当ということになります。また、レベル1の場合で先頭が 0x08 の場合は残り3バイトはランダムという規定になっているようです。

NFCID2
212kbps、424kbpsの通信速度で、8byteのNFCIDになります。こちらはNFC-F相当です。FeliCaですね。先頭が 0x01 0xFE の場合は残り6バイトはランダムということになっているようです。

NFCID3
P2Pを行う場合に使用される10byteのNFCIDのようです。

では先ほどGalaxy Nexusから取得したUIDを見てみましょう。8byteですね。ということはNFCID2が来てるってことですかね。先頭が確かにすべて 0x01 0xFE になってますので後ろの6バイトはランダムって事なんですね!

なるほどー。UIDは固定って思っちゃってるんで違うIDがバラバラ飛んでくるとウッ?ってなっちゃいますよね。

でもちょっと待ってください。NFCID2がGalaxy Nexusから飛んで来てる?NFCID2?NFCID2ってNFC-Fじゃね?
え?何で?なかよしなの?複雑ですねー。 謎です。

2013年5月31日金曜日

PC/SCに潜む謎

WindowsでNFCなどのICカードを利用するのに便利なPC/SCというインターフェース仕様があります。

通常はリーダライタはそれぞれドライバがあってSDKが提供されたりしてそのリーダ用のプログラムを作成するわけなんですが、PC/SCに対応したリーダライタでPC/SCを利用してプログラミングしてしまえば、他のPC/SC対応リーダに変更してもそのまま使えちゃうわけですね。(まぁ、そんなにうまくはいかないんですが)

こういう共通インターフェース仕様っていうのはぶっ飛び系(なんで?こんだけのことするのに何でこんなにコードがいるわけ?など)が多いわけですが、このPC/SCも結構不思議ちゃんな部分があります。

実際に見てみましょう。ACSさんのACR122リーダを使用します。

PC/SCの実体というかAPIの呼び出し先はwinscard.dllというシステムファイルです。Windowsに含まれてますので、特に何かインストールしなくても普通に使えます。

で、だいたい次のようなAPIの呼び出しをして使います。

 SCardEstablishContext - まあ、これから使うよー的な。
     ↓
 SCardListReaders - これでWindowsが認識しているPC/SCに対応したリーダの一覧を取得します。
     ↓
 SCardGetStatusChange - リーダの状態の変化を察知します。カードが置かれたとかがわかります。
     ↓
 SCardConnect - カードが置かれてるようなら、これでカードと接続(おおげさな)します。
     ↓
 SCardTransmit - カードに対してコマンドを送信します。
     ↓
 SCardDisconnect - カードとの接続を切断(またおおげさな)します。
     ↓
 SCardReleaseContext - 終わったよー的な。

至って普通に見えますね。重要なのは SCardTransmit で、これでAPDU(Application Protocol Data Unit)という形式のバイナリデータを送ることでカードを操作します。たとえば「お前だれー」というときは

 FF CA 00 00 00 (16進数)

といったバイナリ列を送ればカードのIDを返してきます。APDUは定義されたものもあればメーカ独自のものもあります。
先ほどのIDの取得やタグの読み書きなどは定義されていますが、ACR122リーダではブザーを鳴らしたりLEDを点灯したりみたいなこともAPDUを送ることで可能です。

 FF 00 40 50 04 05 05 03 01

なんて送ると、赤のLEDが3回点滅してそれに合わせてピーピーピーと鳴ります。便利ですねー。これを使えばカードをかざしてお前のカード認証されてねーよみたいなときに警告としてピーピー言うこともできそうです。

ところが不都合が1つあります。先ほどのAPDUを送信するAPIなんですが、SCardTransmitなんです。そうです。S「Card」Transmitです。カードなんです。カードに送るんです。
まあ、カードに送るって言っても一旦はリーダに送るんだからいいんじゃね?とも思いますが、実際SCardTransmitの引数はこうなっています。

 SCardTransmit(カードハンドル, 送信パラメータ, 送信データ, 送信データの長さ, 受信パラメータ, 受信用バッファ, 受信用バッファの長さ)

いきなりカードハンドルというのがあります。これは SCardConnect の時に取得できるカードの識別子みたいなもんです。これがないと送信してくれません。0とかにしてもダメです。もちろん送信するときにはカードとリーダが通信できている状態にある必要があります。

要するに、カードが置いてないときにAPDUコマンドは送信できないのです。例えそのAPDUがリーダのブザーを鳴らすとかカードに全く関係のないコマンドであったとしてもです。えー!なんでー?謎。
(注:ACR122リーダではこれを回避?するため DirectTransmit というものがPC/SCとは別に用意されているようです)

※2014/07/04 追記 カードが無くてもコマンド送信は可能でした。お詫びいたします。詳細は新しいエントリー「PC/SCに潜む謎 その2」を参照ください。

2013年5月24日金曜日

WindowsとAndroidのおしゃべり


WindowsでNFCを使うときにはよくこのリーダを使います。


ACSさんのACR122リーダです。
4千円くらいで手頃ですし、PC/SCにも対応していて開発もやりやすいです。

使い方としては社員証のFeliCaなんかをユーザの識別用に使ったりとかします。
あとは大量のNFCタグをDBに登録しなきゃいけないようなときにMANICA EXCEL TOOLと繋いで
タグのIDを片っ端からエクセルに入れて登録したりします。
MANICA EXCEL TOOLではNDEFの書込みもできるようにしてますので、スマートポスターの作成とかもできます。

これだけだとつまんないので、ふとAndoridにBeam飛ばせないのかと思って調べたらありました。
https://code.google.com/p/ismb-snep-java/wiki/SNEP_From_ACR122_To_Phone

こちらはJavaで実装されてますが、まぁ何で実装しようがリーダの制御でBeamが飛ばせるという
ことはわかりました。

Android Beamといっても単にNDEFメッセージをSNEPというプロトコルで送信しているだけのようです。SNEPについてはこちらに資料がありました。
http://www.jortec.neec-fct.org/wp-content/uploads/2013/02/Simple_NDEF_Exchange_Protocol.pdf

 Version(1byte) | Request(1byte) | Length(4byte) | NDEF Data

これでいけそうです。しかしこれだけではなくて、SNEPデータをさらにLLCPというプロトコルに載せないとダメのようです。この部分がまたややこしくてInitiatorになったりTargetに接続したり(いわゆるビームが走るっていう部分ですね)とまぁいろいろあるんですが、先ほどのJavaのソースを参考に同じようにやればできそうなのでとりあえず実装してみました(多謝~)。
MANICA EXCEL TOOLを改造して、NDEF書込みの部分を書き込まずにSNEPで送信するように変更しました。

MANICA EXCEL TOOL(改造版)を起動してACRリーダの設定をします。


B列に送信したいURLを書きます。


で、Galaxy Nexusをリーダに置くと...


おー!URLが表示されました。
ってこれ何かに使えますかね?(笑)

2013年5月23日木曜日

EPCの謎に迫る2


Gen2のUHFパッシブタグのEPCの値は通常は96bit(12byte)なんですが変更も可能です。
EPCメモリバンクの構造は次のようになってます。

 CRC(チェックサム)2byte | PC(Protocol Control) 2byte | EPCの値 12byte(通常は)

EPCの値の前にPCという値があって、じつはこのPCの先頭5bitが後に続くEPCの値の長さになっています。正確にはワード単位の長さです。5bitなので、2進数で(00000)~(11111)までで10進数でいうと0~31までです。1ワードは2byte(16bit)ですから、0byte(0bit)~62byte(496bit)まで指定できることになります。

実際PCの部分をリーダで読むと、大概 30 00(16進数)になっています。リーダのアプリケーションによってはタグ読取時に表示するEPCの値がPCの部分からの表示になっているものもあり、「はじめの3000って何ね~」と言う人もかなりいます。3000は2進数にすると(0011 0000 0000 0000)で先頭5bitは(00110)で10進数で6になり、6ワード=12byteということで96bitになっているわけです。

496bitというと結構な量ですが本当にそんなに長くできるんでしょうか。AlienのHiggs3の仕様をみてみると、「96-EPC Bits, extensible to 480 Bits」って書いてありますので、480bitまでは拡張できるようです。

ということで実験です。
Morphicリーダに付属のアプリケーションではPCの書き換えまではできないので今回はNECのマルチリーダライタを使います。ソフトウェアは当社のMANICA EXCEL TOOL(改造版)です。この改造版はNECマルチリーダライタを使って「セルへ入力」をすると、セルへ現在のEPCの値を入力した後、右隣にあるセルの値をPC含めてEPCバンクに書込みをします。


NECマルチリーダライタです。950MHzの古いタイプです。


MANICA EXCEL TOOLを起動して、NECマルチリーダライタに設定します。

書き込みたい値をセルに入れておきます。480bit(60byte)なので、レングスは30ワードになり、PCの部分は(1111 0000 0000 0000)で、EPCの値は適当に16進数で 11 22 33 44 55 66 77 88 99 00 (これを6回繰り返し。計60byte)にします。ということでセルには


といれておきます。このセルの左のセルにフォーカスがある状態で


Higgs3のタグをリーダに乗せると(ピコッ)


セルに現在のEPCの値が入りました。

で、書き換えできたんでしょうか。Morphicで読んでみると


はみ出してて見えません(笑

実はMorphicもMANICA EXCEL TOOLに接続できます(便利ですね!)。


設定を追加して


Morphic側のMANICA EXCEL TOOLを起動し、読み込んでみると(ピッ)


確かに書込みできています!
こんなに長い値が書込みできるなんて、なんて開発者泣かせの迷惑便利なんでしょうか!
ちなみに496bitも試してみると何と書けました(笑)。仕様は480bitまでとなってるのであんまりやらない方がいいかもしれません。

拡張できることはわかりました。では縮小はどうでしょうか?


1ワード(2byte, 16bit)にしてみます。


できました。
ここで疑問が。いっそのこと0ワードってできるんでしょうか?

やってみます。


できました(笑)。ステルスタグとでも呼びますか。どうやって戻すんだろう(笑)