2012/06/30

LLCPに疲れ果てる

疲れた・・・。

LLCPって、所詮はプロトコル。
LLCPがああだこうだと唱えてもなんにもならず、実際に動かしてようやく意味があるものなのだ。

ようやく動かせるようになってきてnfcpyで動作確認をしているものの、「正解」がわからない。
まだ正解と言えるようなものがなくて、事実上の標準、を待っている状況なのかもしれない。
手元にそういうものを持っていないので、なんか疲れているのだ。

 

であれば、だ。
それが実現されているデバイスがほしくなるのは、必然だろう。
Android 4くらいのデバイスがそうなんだろうが・・・携帯電話はほしくない。
今の電話代と同じくらいの値段で使えるようになったら考えよう(1600円くらい)。

先日、Nexus 7だっけ、タブレット型のが発表されてて、値段もお手頃だった。
NFCも搭載しているので、これが電話でなければ有力だ。
電話でなければ、電話でなければ・・・。

LLCPはVersion 1.1にすべきか

ずっとLLCPの実装をしているが、私はVersion 1.0の実装をしてきた。
しかし、nfcpyが1.1だし、NFC Forumでも1.0はdeprecated(使われてない)になってる。

うーーーん、作ろうとしているものがdeprecatedな仕様に沿っていても、誰も嬉しくないよな。。。。。

 

あきらめて、1.1の実装をしようかと思う。
サービス検索関係の実装だけやれば、たぶんいいはず。

いいはずだけど、ちょっと精神的にダメージがあるねえ。


いや、待て。

Parameter ListでSN(Service Name)を渡す、という手があるんじゃないか?

・・・だめだった。
いやいや、まだ待て。
そもそも、SNEPでやりたいんなら、llcp-test-serverじゃなくて、snep-test-serverでやればいいんじゃないのか?

 

activated as p2p target in 424 kbps passive mode
llc cfg {'recv-lto': 2000, 'send-miu': 128, 'send-agf': True, 'send-lto': 1000, 'send-lsc': 2, 'recv-miu': 1024, 'send-wks': 17, 'rcvd-ver': (1, 0)}
LLCP Link established, I'm the DEP Target
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
snep server bound to port 4
snep server bound to port 16
RECV  1 ->  1 CONN MIU=128 RW=1 SN=urn:nfc:sn:snep
DLC (4,None) LISTEN enqueue CONNECT PDU
accepting CONNECT from SAP 1
DLC (4,None) LISTEN dequeue CC PDU
SEND  4 ->  1 CC   MIU=128 RW=2
new data link connection (4 <=== 1)
serving snep client on remote sap 1
RECV  1 ->  1 I    N(S)=0 N(R)=0 LEN=5 SDU=75656e6f00
enqueue
SEND  0 ->  0 SYMM
Exception in thread Thread-1:
・・・・

 

CCが返ってきた!
自作LLCPがI PDUでデータを送った!
しかし、SYMMを返したところでnfcpyが例外で落ちてしまった。
うーむ。

 

とりあえずわかったことは、

  • nfcpyはSNEPをサポートするけど、SAP=4という形ではCONNECTできないみたい
  • llcp-test-serverはSNEPが来るとNGだが、snep-test-serverはOK
  • RRじゃなくてSYMMを返してくる
  • なんか落ちた

だ。
あ、データ送信はSNEPでやったわけじゃないので、それで落ちたのかな。

まあ、もうちょっとだな。
でも、1.1への対応もやりたいですな。


もしかすると、snep-test-serverサンプルを使うと、SAP=4でもできるのでは?

と思ってやったが、うまくいかん。
うまくいかんのが、コマンド的にだめなのか、それ以外の要因なのかがわからない。

「それ以外」というのは、R/Wの位置関係だ。
うちでは、PaSoRi RC-S370とRC-S620/Sで動作させている。
nfcpyはPaSoRiで、自作LLCPはRC-S620/Sだ。
やっていてわかったのだが、両者の位置関係がかなり微妙で、通信をしていると切られてしまうのだ。

あとですな、snep-test-server実行して失敗で終わると、その次がR/Wのアプリケーションエラーになって動かせなくなるのだ。
たぶん、デバイスをリセットすれば直るんだろうけど、pn53xの上で動く前提になっているnfcpyでそれをやるのは難しそうだ。

[llcp]nfcpyを推測してみるも、謎が増えるばかり

なぜnfcpyのLLCPは、CONNECT PDU受信時のDSAPを1(SDP)限定にしているのか。
ちょっと推測してみよう。


【その前に解説】
最近のhiro99maは訳のわからないことばかり書いてあるわ、と思われそうなので、今さらだが簡単に用語の説明をします。
まあ、訳がわからないのは最近に限ったことではないですがね。。

 

LLCP
Logical Link Control Protocolの略。
NFC Forumにて、NFC端末同士の通信に使うプロトコルとして指定されている。

 

PDU
Protocol Data Unitの略。
LLCPで使用するデータの単位。
通信するのでお互いにデータを送受信するのだが、1回の送信で1つのPDUを送信する。
PDUにはタイプがあって、タイプごとに載っているデータも異なる。

 

CONNECT
PDUタイプの1つ。
接続要求をするときに送信する。

 

SAP
Service Access Pointの略。
PDUのパラメータになっている。
サービスってのはあちこちで使われている言葉だが、LLCPでは「やりたいこと」みたいな意味のようだ。
原文では「The capabilities and features provided to the adjacent upper layer」。
たとえば「SNEP」というさらに上位のプロトコルがあるのだが、それを使った通信をしたいときにはPDUのSAPにSNEPの値(文字列とかではなく、数値なのだ)を指定する。
NFC Forumでの値は、こちら

 

DSAP
Destination SAPの略。
自分をSource、相手をDestinationと呼んでいて、それぞれSSAP、DSAPという名前になる。
PDUにはSSAPとDSAPをパラメータとして与えるようになっている。


時代背景を見てみる。

nfcpyがLLCPを搭載して「NexusSと通信できた」と報告している。
このときは、Android 2.3と書いている。
Android 2.3に搭載しているのは、LLCP v1.0のはず。
なぜかというと、LLCP v1.1がリリースされたのは、2011年6月20日。この記事が2011年5月だから、少なくとも正式リリースはまだだ。

Android 2.3には、NDEF Pushというプロトコル[pdf]が搭載されている。
これは、LLCPの上位層で、SNEPよりも前にリリースされている(2011年2月22日)。

そう考えると、当時はLLCPで通信するものはNDEF Pushだけだったと考えられる。

 

このNDEF Pushだが、サーバの要件として「com.android.nppという名前でサービス検索できること」という項目がある。
サービスの検索は、Service Discovery Protocolというプロトコルがあり、これ自体が1つのサービスになっている。
つまり、SAPが割り当てられているということだ。

Service Discovery Protocol(SDP)のSAP値は、1。
だから、LLCP接続しに来る人はSAPが1のはず、という実装になってるんじゃないだろうか?


などと書いてみたが、nfcpyからAndroid Beamできるようなのだよ。

 

ありがたいことに、ここにnfcpyでSNEPしたときのログが載っていた。
相手は、Samsung Nexus (Android 4.0.3)らしい。
RemoteのService Listが「0000000000000001」になっている。
これだと、有効なSAPがデフォルトのしかない、ってことになるんだよなあ。

 

と思ってログを見直すと、nfcpyのLocal Service Listが「0000000000000011」だ。
あれ、SDPしかないじゃないの!
SNEPのビットが立ってないじゃないか!!
・・・でも、自作LLCPに送られてきた情報では、SNEPのビットが立ってる。
どういうことなのだ?

もしかして、SDPでSNEP検索できるのか?
でも、だからってDSAP==1のみってのはなぁ。。。

[llcp]nfcpy v.s. 自作LLCP (3)

目先を変えて、nfcpyをtargetにしてやってみよう。

 

$ python llcp-test-server.py --mode=target
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

libusb0-dll:err [_usb_reap_async] timeout error

・・・

activated as p2p target in 424 kbps passive mode
LLCP Link established, I'm the DEP Target
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000000011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
connectionless server bound to port 16
connectionless server recv queue size is 2
connectionmode server bound to port 17
connectionmode server recv window is 2
shutdown on link disruption
nfc.llcp.Error: [EPIPE] Broken pipe
remote side closed logical data link
close connless echo server socket
I was the Target

 

むむ、切断されてしまった。
自作側からCONNECTを送信したのだけど、CCが返ってこなかった。


デバッグログを付けて見てみよう。

$ python llcp-test-server.py --mode=target -d nfc.llcp
enable debug output for module 'nfc.llcp'
searching for a usable reader
searching for a usb bus reader
path match for 'usb' (or no path given)
trying usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
import nfc.dev.rcs956_usb
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

libusb0-dll:err [_usb_reap_async] timeout error

・・・

activated as p2p target in 424 kbps passive mode
llc cfg {'recv-lto': 2000, 'send-miu': 128, 'send-agf': True, 'send-lto': 500, 'send-lsc': 2, 'recv-miu': 128, 'send-wks': 17, 'rcvd-ver': (1, 0)}
LLCP Link established, I'm the DEP Target
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000000011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
connectionless server bound to port 16
connectionless server recv queue size is 2
connectionmode server bound to port 17
connectionmode server recv window is 2
RECV  4 ->  4 CONN MIU=128 RW=1
discard PDU  4 ->  4 CONN MIU=128 RW=1
SEND  0 ->  0 SYMM
libusb0-dll:err [_usb_reap_async] timeout error

send_response: IOError no response from pn53x
shutdown on link disruption
closing service access point 17
shutdown socket DLC 17 <-> None LISTEN RW(R)=None V(S)=0 V(SA)=0 RW(L)=2 V(R)=0 V(RA)=0
DLC (None,None) LISTEN close()
nfc.llcp.Error: [EPIPE] Broken pipe
closing service access point 16
DLC (None,None) SHUTDOWN close()
shutdown socket LDL 16 -> None
closing service access point 1
remote side closed logical data link
close connless echo server socket
closing service access point 0
llc run thread terminated
shutdown requested
shutdown requested
I was the Target

 

4ってのは、CONNECTのPTYPEが0x04だからだろう。。。いや、DMを受信したときも4っていってるので違うのか。
でもCONNって書いてるから、わかってるはず。
で、なんで「discard」なんだ?
破棄したってことよねぇ。
まさかそんなこととは思ってない自作の方は、CCが返ってこないので困っているのだ。

 

nfcpyのllcpで「discard」とログを出すのは、_dispatch()だけだ。
SYMMか、AGFか、CONNECTだったらさばいて、そうじゃなかったら「discard」なのだ。

あ、CONNECTの条件に「dsap==1」ってのがあるな。
私はSNEP想定でDSAPを4にしてるのだ。

 

うーん、うーん・・・・

[llcp]nfcpy v.s. 自作LLCP (2)

2回戦。
nfcpyサンプルのllcp-test-clientは、引数でテスト番号を指定して実施できるようだ。
やってみよう。

 

Usage: llcp-test-client.py [options]

Options:
  -h, --help       show this help message and exit
  -t N, --test=N   run test number <N>
  -q               be quiet, only print errors
  -d MODULE        print debug messages for MODULE
  -f LOGFILE       write log messages to LOGFILE
  --device=SPEC    use only device(s) according to SPEC:
                   usb[:vendor[:product]] (vendor and product in hex)
                   usb[:bus[:dev]] (bus and device number in decimal)
                   tty[:(usb|com)[:port]] (usb virtual or com port)
  --mode=MODE      restrict mode to 'target' or 'initiator'
  --cl-echo=SAP    connection-less echo server address
  --co-echo=SAP    connection-oriented echo server address
  --link-miu=MIU   set maximum information unit size to MIU
  --quirks=choice  quirks mode, choices are 'android'


$ python llcp-test-client.py -t1
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

activated a p2p target in 424 kbps active mode
LLCP Link established, I'm the DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
Test 1: link activation, symmetry and deactivation
PASS
shutdown on local request
libusb0-dll:err [_usb_reap_async] timeout error

I was the Initiator

 

PASSっていってるから、OKなのかな?

自作側は、SYMMをしばらくやりとりしたあと、Link Deactivationで切断してる。


$ python llcp-test-client.py -t2
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

activated a p2p target in 424 kbps active mode
LLCP Link established, I'm the DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
Test 2: connection-less information transfer
   socket recv buffer set to 10
libusb0-dll:err [_usb_reap_async] timeout error

shutdown on link disruption
FAIL: no connection-less echo server on peer device
I was the Initiator

Connectionlessのテストみたいだが、うちはClass 2のつもりなんだよ。

あ、GeneralBytesにOPT書いてないや。。。
書いてみたけど、あんまり関係なかった。


$ python llcp-test-client.py -t3
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0002--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

activated a p2p target in 424 kbps active mode
LLCP Link established, I'm the DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
Test 3: connection-oriented information transfer
   socket recv window set 2
libusb0-dll:err [_usb_reap_async] timeout error

shutdown on link disruption
aborted by user
I was the Initiator

これは、自作側を途中で切断させた。
というのも、nfcpyが私の知らないPDUを送信したあと、ずっとSYMMをやりとりするだけになったからだ。

投げてきたPDUの番号は、0x09。
LLCP v1.0ではreservedなのだが、LLCP v1.1ではSNLになっている。
そう、Service Name Lookup、SDP関係のPDUだ。

いや、だからうちはv1.0だっていってるじゃないの!と思うけれども、どうしようもない。
そういえば、知らないPDUを受け取ったときはどうするんだろうね?

書いてあった。ignored by the receiverだと。
では、無視するようにしているから、まあ間違ってはいないのだな。

[D]06
[D]41
[D]08
[D]13
[D]fe
[D]75
[D]72
[D]6e
[D]3a
[D]6e
[D]66
[D]63
[D]3a
[D]73
[D]6e
[D]3a
[D]63
[D]6f
[D]2d
[D]65
[D]63
[D]68
[D]6f

urn:nfc.sn:co-echo

エコーするサービスってことなのかな。
検索すると、nfc-toolsに引っかかったので、そういうのがあるのかも。
NFC Forumのページにはなかった。

うーむ、この調子だとテストにならないなあ。

[llcp]nfcpy v.s. 自作LLCP (1)

くくく、ついにこのときが来たか。
自作のLLCPライブラリとnfcpyが闘うときがきた・・・。

ではなく、動作確認させていただくというところだ。
お手柔らかに。


先手、nfcpy

$ python llcp-test-server.py
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0001--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

libusb0-dll:err [_usb_reap_async] timeout error

 

クライアント待ちってところかな。
ってことは、こっちから送信だから、Initiatorとして動かすことになるのかな。

後手、自作LLCP。

$ ./tst

・・・InJumpForDEPでエラーになる。
携帯電話をかざすと、搬送波を出してるようだ。
うーん、Serverがポーリングしてクライアントを探すということかな。

改めて、Targetとして動かすと、ATR_REQを受け取り、GeneralBytesにLLCPのパラメータリストが載ってきているようだ。

424kbps
Active
Parameter List
VERSION : 11
agree : remote>local ==> local
Parameter List
MIUX
Parameter List
WKS : have SNEP
Parameter List
LTO : 500
Parameter List
OPT(LSC) : Class 1

自作のライブラリは、LLCP ver.1.0が使えればいいやってところ。
nfcpyはver1.1だが、これはOK。
MIUXは無視。
WKSにはSNEPが載っていたので、OK。
LTOも取得。
OPT・・・ここだ。

OPTは、オプション的なもので、v1.0ではLink Service Classesを渡せるようになっている。
この値は、こういう意味になっている。

  • Class 1 : Connectionless link service only
  • Class 2 : Connection-oriented link service only
  • Class 3 : 両方
  • unknown : まだ決めてない

私はSNEPしたいので、Connection-orientedが使えるClass 2 か Class 3だけを許容するようにしている。
しかし、nfcpyのllcp-test-serverはConnectionlessのみになっている。
だから、自作LLCPサーバは拒否して終了している。

うん、実装としては正しいんだけど、これでは動作確認できないじゃないか・・・。


じゃあ、仕方がないのでSNEPのサンプルを動かそう。

$ python snep-test-server.py
searching for a usable reader
searching for a usb bus reader
chipset is a PN533 version 1.48
using Sony RC-S370/P at usb:bus-0:\\.\libusb0-0001--0x054c-0x02e1
libusb0-dll:err [_usb_reap_async] timeout error

libusb0-dll:err [_usb_reap_async] timeout error

 

自作LLCPをTargetで動かして・・・。

424kbps
Active
Parameter List
VERSION : 11
agree : remote>local ==> local
Parameter List
MIUX
Parameter List
WKS : have SNEP
Parameter List
LTO : 1000
Parameter List
OPT(LSC) : Class 1

えー、これもClass 1なの??
解析の仕方間違えてるのかも。
GeneralBytesの生データを見てみよう。

[R]46
[R]66
[R]6d

これは、LLCPのMagic Number。


[R]01 VERSION
[R]01 LEN=1
[R]11 MAJOR=1 / MINOR=1

これは、VERSION。
v1.1。


[R]02 MIUX
[R]02 LEN=2
[R]03
[R]80

これはMIUX。
0x380。デフォルトの128byteとあわせて1KBよいですよ、と。


[R]03 WKS
[R]02 LEN=2
[R]00
[R]13

これはWKS。
SNEPとSDP。


[R]04 LTO
[R]01 LEN=1
[R]64

これはLTO。
1000ms。


[R]07 OPT
[R]01 LEN=1
[R]03 Class 3

そしてOPT。

・・・やっぱり解析実装ミスか(;_;)

恥ずかしいのだが、どうミスったか書いておこう。

誤:(*pBuf + xxx) & 0x03
正:*(pBuf + xxx) & 0x03

きー!


直すとちゃんと解析してくれた。やれやれ。

424kbps
Active
Parameter List
VERSION : 11
agree : remote>local ==> local
Parameter List
MIUX
Parameter List
WKS : have SNEP
Parameter List
LTO : 500
Parameter List
OPT(LSC) : Class 3

 

そして、nfcpyが反応した。

activated a p2p target in 424 kbps active mode
LLCP Link established, I'm the DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.0
  Link Timeout: 2000 ms
  Max Inf Unit: 128 octet
  Service List: 0000000000010001
snep server bound to port 4
snep server bound to port 16

うん、渡しているパラメータも正しそうだ。

 

このあと、SYMMをやりとりするだけになった。
第1回目は、まあ成功したと言ってよかろう。

nfcpyの使い方を忘れたので、復習

以前、nfcpyを動かした。
http://hiro99ma.blogspot.jp/2012/06/nfcpy.html
なのに、もう忘れた・・・。
  $ python HelloWorld
ってやったけど、そんなファイルはない、って怒られた。
こういうときは、復習だ。

とりあえず、nfcpyをダウンロードしたディレクトリでcygwinを開く。
$ python
>>>
OK。
>>> import nfc
OK。
>>> clf = nfc.ContactlessFrontend()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "nfc/clf.py", line 53, in __init__
    self.dev = dev.connect(path)
  File "nfc/dev/__init__.py", line 55, in connect
    import usb
ImportError: No such file or directory

エラー。
usbってのがない。
確かにここにはないのだけど、以前pyUSBってのはインストールしたのだよ。
ああ、cygwinのUSB周りを整理したときに、いろいろと削除しすぎたのがよくなかったみたいだ。
もう一度、pyUSBのインストール。
pyUSB0.4.3をダウンロードして、
  $ python setup.py install
コンパイルエラーが出たので、usb.hとlibusb.aをREADMEにある通りに配置。
そうすると、ビルド成功。インストールも成功。
>>> import usb
OK。
>>> clf = nfc.ContactlessFrontend()
No handlers could be found for logger "nfc.clf"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "nfc/clf.py", line 58, in __init__
    raise LookupError("couldn't find any usable nfc reader")
LookupError: couldn't find any usable nfc reader

エラー。
使うことができるR/Wがないよ、といわれた。
そういえば、PaSoRiは今WinUSBドライバで動かしているので、libusbドライバにせんといかんかった。
zadig.exeを使って、List All Devices→RC-S956選択→libusb-win32選択→Replace Driver、としてドライバ差し替え。
>>> clf = nfc.ContactlessFrontend()
OK。
>>> clf.close()
>>> exit()
として、プロンプト終了。
ひきつづき、サンプルを動かす。
$ cd examples
$ python HelloWorld
python: can't open file 'HelloWorld': [Errno 2] No such file or directory
あれ、こんな使い方じゃなかったっけ?
$ python helloworld.py
Please touch a tag to send a hello to the world
Remove this tag
No handlers could be found for logger "nfc.dev.pn53x_usb"
Now touch it again to receive a hello from the world
en: Hello World
de: Hallo Welt
fr: Bonjour tout le monde

あああ・・・。以前書いた記事が間違っていたのだ。修正しときました。

[llcp]シーケンス番号

コメントをもらいつつ、LLCPの実装が進んでいる。
今週は黙々とやっていたのだが、ああだこうだやりつつI PDUのところまでできたと思う。


I PDU (Informationの略)には、シーケンス番号がある。
ドキュメントでは、N(S)とN(R)と書いてある。
LLCの説明と同じなら、NはNowのNらしい。
これを取り扱うために、4つの状態変数を持つことになる(Connection-orientedの場合)。

  • V(S) : 送信状態変数
  • V(SA) : 送信ACK状態変数
  • V(R) : 受信状態変数
    V(RA) : 受信ACK状態変数

V(SA)は、最後に受信したN(R)を覚えておく。
V(RA)は、最後に送信したN(R)を覚えておく。

V(S)とV(R)の範囲は0~15。
V(S)は次に送信するI PDUのN(S)になる。I PDUを送信したらインクリメントする。
V(R)は次に受信するI PDUのN(S)の期待値で、V(R)==N(S)だったらインクリメントする。

 

自分をA、相手をBとし、自分が最初のI PDUを送信したとすると、こうなるはず。

A(VS=0, VR=0) → I(NS=0, RS=0) → B(VS=0, VR=0)
  A(VS=1, VR=0) : Iを送信したので、VSインクリメント
  B(VS=0, VR=1) : VR==NSだったので、VRインクリメント
A(VS=1, VR=0) ← I(NS=0, RS=1) ← B(VS=0, VR=1)
  A(VS=1, VR=1) : VR==NSだったので、VRインクリメント
  B(VS=1, VR=1) : Iを送信したので、VSインクリメント
A(VS=1, VR=1) → I(NS=1, RS=1) → B(VS=1, VR=1)
  A(VS=2, VR=1) : Iを送信したので、VSインクリメント
  B(VS=1, VR=2) : VR==NSだったので、VRインクリメント
A(VS=2, VR=1) ← I(NS=1, RS=2) ← B(VS=1, VR=2)
  A(VS=2, VR=2) : VR==NSだったので、VRインクリメント
  B(VS=2, VR=2) : Iを送信したので、VSインクリメント

これの繰り返し。15の次は0に戻る、というくらいか。

 

V(SA)とV(RA)はどこに出てくるのだろうか?
たぶん、FRMR PDUというエラー関係のPDU引数で使うように見える。
V(SA)は、自分がI PDUを送信するかどうかの判断でも使っているみたい。
まあ・・・後回しにしよう。


ずっとやっているけど、実装量はそんなに多くないのだ。
ログを出すための実装がけっこうある。
よくわからずにやっているためか、無駄な実装が多い気がする。
InitiatorとTargetで別の実装にしてしまったけど、ここを抽象化できれば一本化できるんじゃなかろうかね。

なんで別にしているかというと、Initiator系の場合は1コマンドで送信→受信だけど、Target系の場合は受信で1コマンド、送信で1コマンドとなっているため。
この見方は、R/Wから応答が返ってくるまでを1シーケンスとして実装しているからであって、普通に「応答が来るまで別のことをする」とやれば、抽象化とかなんとかいわずにできるのだ。

なんで応答が返ってくるまで1シーケンスにしてるかというと、InitiatorとしてR/Wを使っている分にはそっちの方が扱いやすいからだ。
送信と応答を別にするとなると、R/W制御を別のコンテキストにして、スレッドなり割込なりで回すようにせんといかん。
スレッドにするためにはOSの力を使わんといかんし、割込にするとPCでの実装がやりづらい。
抽象化するなら、この「非同期化」の部分だな。

メッセージループでぐるぐるとメッセージが来るまで待つようにしておけば、PCでもマイコンでも同じような実装ができそうだけど、ぐるぐる待つと電気喰うから割込が来るまで寝るようにして・・・とか考えるとめんどくさい。

でもまあ、そういうのをちゃんと設計できないと、ソフト専門とはいえ組込み屋さんとしてはいかんなぁ。

2012/06/24

「In」は「Initiator」の「In」

kappa
タイトルのイメージとしては「ウは宇宙船のウ」だが、関係はない。
そして絵は、タイトルとも内容ともまったく関係ない。

なんとなく、RC-S620/Sのコマンド名を眺めていた。
ターゲット関係の命令は「Tg」がついてるけど、それ以外ってルールがないよなぁ・・・
と思ったら、よく見るとInitiator系のコマンドには「In」ってついてるではないか。
英単語の「in」(~の中に)みたいなものだと思ってまったく気にしていなかったのだが、そうかそうか、そういうことなのか・・・。

以上、まったくどうでもいいお話でした。

どうでもいい話のついで、LLCPの進行状況を少し書いておこう。
遅いが、進んでいる。
さっきようやく、SYMMでやりとりするところができた。
まだCONNECTまで至っていないのだ。
まあ、SYMMとかのPDUって、R/Wへのコマンドではなくて単なるデータなので、自分で送信側と受信側を作っている限り、うまく動くのは当たり前だ。
DISCとDMは何となく作っているので、あとはCONNECT, CC, I, RRくらいを作れば、nfcpyのサンプルとやりとりするテストくらいはできるんじゃないかな、と思っている。
今週も早く帰ることができそうだったら進められるかもしれんが、月末だからなぁ。

あ、最近たまに絵を入れるようになったのは、このサイトがあまりにも殺風景だからです。
それなら関係ある絵を入れればいいのだけど、まあ許してやってください。

[llcp]CONNECT前にSYMMで待つのは普通なのか?

SYMMがCONNECT前に挟まる理由は何となくわかった。
では、その動作はLLCP仕様としてどうなんだろうか?

これについては、何とも言えない。
「そうだ」とも書いてないし「やってはいけない」とも書いていない。
いや、Normal OperationになったらPDUのやりとりができる、と書いてあるので、やってはいけないということはなさそうだ。

 

問うのであれば、Connection-orientedの場合、Connection Establishmentを済ますのが先かどうか、くらいか。
Establishmentを先に済ませてしまうと、たぶんSYMMではなくRRをやりとりして待つことになると思う。
RRは引数の面倒を見ないといけないから、SYMMで待つ方が楽と言えばらくだ(大して変わらんと思うが)。

 

そんなわけで、CONNECT~DMはデータを送信する期間だけで、送るものが決まるまではCONNECTせずにSYMMで待つ、というスタイルがよさそうな気がしてきた。

長いものに巻かれたわけじゃないんだ、といいたいだけである。

[llcp]データを送信したい側がCONNECTを送信するのだろう

LLCPのシーケンスがわからんごとなってきたが、なぜここまでシーケンスの資料がないのだろうか?

思い当たったのは、LLC副層だ。
LLCPで検索していると、IEEE 802.2という規格が引っかかっていた。
あまり気にしていなかったのだが、「基礎から学ぶWindowsネットワーク LLCプロトコル」を見ると、LLCPでよく使われる「SAP」とか「N(S)」なんかが出てきている。

うーん、説明が少ないのは、既存のIEEE 802.2と一緒だから省略したということだろうか。


LLCについては、以下のページが詳しくわかりやすかった。

Network Analysis
http://www.cam.hi-ho.ne.jp/puffin/compendium/J_L1-LLC.html

 

ConnectionlessとかConnection-orientedなんかも同じだ。
Type IとかType IIとかは、Link Service ClassesのClass 1, Class 2と対応しそう。
NRMやABMなんて用語も説明があんまりなかったのだが、LLCから来ているのだろう。

 

読んだが・・・LLCPのConnection-orientedとの関連づけができんかった。
802.2には、LLCPの「CONNECT」に相当するものがよくわからない。
Normal Operation開始時には「5.8 Symmetry Procedure」の初期化をするようになっているが、これがABMになるという意味で、802.2の「SABME」になるのだろうか。

うーーん・・・


そういえば、NPPも同じような実装になっていたなあ、と検索してみると興味深い話があった。
https://launchpad.net/nfcpy/+announcement/8271
nfcpyだ。
読んだ感じからすると、nfcpyがサーバ動作をしているとき、symmetry packetを交換しないとうまくいかなかった、ということのようだ。
symmetry packetは、SYMM PDUのことだろうか。

 

http://www.libnfc.org/community/topic/401/p2p-communication-between-android-phone-and-nfc-reader/
こっちは、libnfcのフォーラム。
ターゲットになってNexus Sと通信しているログが出ている。
GeneralBytesを送信後、TgGetDataするとCONNECT PDUを受け取っているようだ。
この話は、コメントをいただいた件と一致している。
送信するNDEFメッセージがないときはSYMM PDUを送る、という文のあとで、送信するNDEFメッセージができるとCONNECT PDUを送る、とある。

そうか、そういうことなのか!


私はてっきり、CONNECTしたあとでSYMMを交換し合うフェーズになると思っていたのだが、Android端末を向かい合わせた時点で送るものがあろうとなかろうと「5.6.3 Connection Establishment」の手前まで実行し、送るものが出てくるまではSYMMをやりとりして待つ、ということなのだ。
送信するデータができれば自分からCONNECT PDUを投げるし、先に相手からCONNECTが来たらデータ受信側になる、と。

nstは送りたいNDEFメッセージを最初から持っているので、相手からCONNECTが来ると「私は送るものがあるんだから拒否」ということでDMを投げるのだろう。

つまり、開始まではこういうシーケンスになるということだと思う。

データ送受信開始まで

まだ間違ってるところはあるかもしれんが、この数日悩んでいたことに理屈が付いて、すっきりだ。

[snep]SNEPはclient/server構造

いただいたコメントを見つつ考えていた。

Android端末に対してInitiatorとして働きかけた場合の動作。Targetとして動くときの動作。
どちらについても、なぜかAndroid端末は同じような動きをしているように見える。

ということは、その上位層であるSNEPが関係しているのではなかろうか。


SNEPは、client/server構造である。
つまり、SNEPサーバがSNEPクライアントを待ち受け、要求が来たらそれに応えるという形と考えてよいだろう。

私はAndroidのソースを読んで、AndroidがInitiatorとなって周りに問いかけ、それに応答したTargetがSNEP接続して送信してくる、という構造なのだろうと思っていた。
しかし、周りがInitiatorとなってAndroid端末に話しかけるというパターンも可能であることをコメントで知った。

 

ならば、Androidは両刀遣いということか?
いや、変な意味ではなく、InitiatorとしてもTargetとしても動作するけど、何かの決めごとによってSNEP serverかSNEP clientになるということになっているのでは、という意味だ。
SNEP serverになる方は、CONNECT権を相手に渡したいのでSYMMする、というストーリーだ。


さらにコメントをいただいて考えていたのだが、考慮が足りていないところがあった。

 

(コメントより)
先の例のAndroidBeamなんかだと端末同士くっつけただけでBeam準備動作に入りますので、この時どちらがInitiatorになるかはタイミング次第だったりするような気がします。

 

私はずっと、SNEPサーバがInitiatorで、SNEPクライアントがTarget、という考え方をしていた。
福岡NFC勉強会で、オシロを使った搬送波の動きを見て、何となくその仮定が違っているのではないかという気がしていた。

 

(コメントより)
両刀といいますか、P2Pなんで基本どっちがどっちになるか分からないのでどっちも実装されてるのではないでしょーか。

なんとなくわかっていたつもりだったのだが、この「どっちがどっちになるかわからない」はInitiator/Targetの関係で、SNEP client/serverの関係はまた別ということまでは考えが及んでいなかった。

つまり、こう言い換えることができるのではないか。

  • データを送信したい側がInitiatorになるとは全然限らない。タイミング次第。
  • データを送信したい側はSNEP clientで、受信する側はSNEP server。
  • Androidでは動的にSNEP client/serverが切り替わり、「現在は送りたいデータがない」端末がSNEP serverになり、「現在送りたいデータがある」端末がSNEP clientになる。

こう考えると、nstの動きも理解できる。
nstは「常にTarget」で「常にSNEP client」の動作になる。
よって、相手は「常にInitiator」で「常にSNEP server」の動作になる。

Targetかつclientのnstに対して、Android端末は必ずATR_REQを投げることになる。
ATR_RESを返すnst。
それを受け取ったAndroid端末。しかし送るデータがないことを理解しているので、SYMMで接続権を相手に渡す。
SYMMをもらったnstは、喜々としてCONNECTを送信する、というストーリーだ。


しかし、まだ疑問は残る。

CONNECTで接続を確立したあとでSYMMを投げてもいいんじゃないのか、という点だ。
これについての規定があるなら、LLCPではなくてSNEPだろうな、と思う。

2012/06/23

[llcp]衝撃! AndroidもCONNECTを返す!?

なんとなく安っぽい週刊誌の見出しみたいになってしまった。
しかし、それほど衝撃だったのだ。
やってる人は違いますわ。

LLCPのCONNECTがよくわからんという記事に対してコメントをいただいて、「AndroidもCONNECTを返す」ということを知った私。

えぇぇぇっ。

私は飲んでいた酒を、ビールから焼酎に切り替えた。

[llcp]CONNECTで行き詰まる

息詰まる展開!だったらいいのだが、行き詰まっている・・・。
いつものことながら、NFCのLLCPについてだ。

 

LLCPのLink Activationが終わると、通信を始めることができる。
Normal Operation、という状態だ。
そのとき、UDP/IPみたいなConnectionless Transport Modeか、TCP/IPみたいなConnection-oriented Transport Modeかによって、シーケンスが変わってくる。

私はSNEPしたいので、Connection-oriented。
最初に使うPDUは、「5.6.3 Connection Establishment」によるとCONNECTだ。
さて、ここで問題だ。
誰がCONNECT PDUを送信するのか?

 

LLCPの開始は、InitiatorがATR_REQを投げ、TargetがATR_RESを返す。
この段階でLink Activationが終わると思うので、ボールはInitiatorが持っている。
だから、CONNECTはInitiatorが投げるのだろう。

だろうと思っていたのだ。
しかしnstの実装を見てみると、CONNECTが来るとLinkを切断しようとしているのだ。
InitiatorからはSYMMを送ってくるので、それに対してnstがCONNECTを投げるようになっている。
なんだ、この自信ありげなCONNECT排除の実装は!

ここまで実装されていると、仕様として何か記載があるんじゃないかと思う。
思うのだけど・・・見つけられない。
この数時間、仕様書をにらみつけているが、さっぱりわからん。
暴れてしまいそうだ。

 

SYMMが来たとしても、自分でCONNECTする、という実装ならわかるのだが、相手から来たCONNECTを断るというのは、何か確信があってのことに違いない。
こういうのを誰かに質問したくてGoogle検索から削除したのだけど・・・出てこんなぁ。

[llcp]WKS

最近、LLCPネタばかりだが、実装が終わるまでは続くので我慢してほしい。
私だって我慢してるんだ。

 

LLCPのWKSは、Well-known Serviceの略で、「自分はwell-knownなサービスのうち、これこれをサポートします」という意味で用いる。
2台の間で最初にリンクを張るときに、GeneralBytesに載せることになるだろう。
詳細は「4.4 LLC Parameter Format」と「4.5.3 Well-Known Service List, WKS」参照だ。

 

さて、LLCPの仕様書に書かれていないものがある(見つけられんかっただけ?)。
それは、Well-KnownなSAPの値だ。
nfc-smart-tagでは0x0013が指定されているけど、なんだろうと思ったのだ。

この値は、ここにある。
http://www.nfc-forum.org/specs/nfc_forum_assigned_numbers_register

Android NPPは、Service Discovery Protocolに対応しないといかんので、bit 1がON。
SNEPも対応するので、bit4がON。
そしてSAP0はLLCPで必須なので、bit0がON。
あわせて、0x0013というわけだ。

 

細かいことを言うようだが、SDPはLLCP 1.1と書いてある。
一応、LLCP 1.0にもSDPという単語は出てくるのだが、SDPが何をどうするかは書かれていない。書かれたのがLLCP 1.1からだと思う。
nstではVERSIONを1.0として返しているので、ここんところがちょっと気になるところではある。
しかし、Android NPPの仕様書が出たのはLLCP 1.1が出るよりも前だったと思うので、ルールだけ決めたのかな?

[felicalite]MAC生成の結果確認方法

MACって、ここ10年くらい食べてないなあ、のMACではない。

 

FeliCa Liteカードは、認証コマンドを持っていない。
その代わりに、MACレジスタというものを持っている。

機能は、1回のRead w/o Encriptionによって読み出したブロックのデータから値を計算するというものだ。
Read w/o Encription実行時には初期化されるので、注意が必要だ。
一般的な使い方としては、Read w/o Encriptionに読み出しブロックを指定するが、その最後にMACブロックにする、というものだ(Liteは同時に4ブロックまで指定できる)。

このMACブロックの値を、読み出した人が自分でも計算してみて、同じ値になったら「自分が発行したカードだ」と認識する、という片側認証するようになっているのだ。


よって、MACの計算アルゴリズムは公開されている。
いるのだが、なんだか難しい。。。
なんだかというか、私はけっこう時間がかかった。
それに、読み出した値と計算値が一致したとしても、それが偶然うまくいっているだけなのかどうかがよくわからなかった。

結局どうやって確認したかというと、ユーザーズマニュアル「6.4.8. MAC生成試験」というカードの動作確認項目があるので、これを試して一致したらOK、ということにした。
(実は、未だに計算には自信がない・・・)


私がAndroid向けに書いたのは、こんなコードだ。
Android向けといっても、携帯電話向けじゃない。
それに、私はJavaでのコーディングをほとんどしたことがないので、動けばいいや、といって作ったものなので、未だにきれいな実装方法がわかってない。

作ったのは昨年なので、確か動いていたはず…という記憶しかない。
間違ってたら、ごめんなさい、だ。

/**
* MAC計算
*
* @param mac MAC計算結果(先頭から8byte書く)。エラーになっても書き換える可能性あり。
* @param ck カード鍵(16byte)
* @param id ID(16byte)
* @param rc ランダムチャレンジブロック(16byte)
*
* @return true MAC計算成功
*/
private static boolean calcMac(byte[] mac, byte[] ck, byte[] id, byte[] rc) {
byte[] sk = new byte[16];
IvParameterSpec ips = null;

// 秘密鍵を準備
byte[] key = new byte[24];
for(int i=0; i<8; i++) {
key[i] = key[16+i] = ck[7-i];
key[8+i] = ck[15-i];
}

byte[] rc1 = new byte[8];
byte[] rc2 = new byte[8];
byte[] id1 = new byte[8];
byte[] id2 = new byte[8];
for(int i=0; i<8; i++) {
rc1[i] = rc[7-i];
rc2[i] = rc[15-i];
id1[i] = id[7-i];
id2[i] = id[15-i];
}

// RC[1]==(CK)==>SK[1]
ips = new IvParameterSpec(new byte[8]); //zero
int ret = enc83(sk, 0, key, rc1, 0, ips); //RC1-->SK1
if(ret != 8) {
Log.e(TAG, "calcMac: proc1");
return false;
}

// SK[1] =(iv)> RC[2] =(CK)=> SK[2]
ips = new IvParameterSpec(sk, 0, 8); //SK1
ret = enc83(sk, 8, key, rc2, 0, ips); //RC2-->SK2
if(ret != 8) {
Log.e(TAG, "calcMac: proc2");
return false;
}

/////////////////////////////////////////////////////////
for(int i=0; i<8; i++) {
key[i] = key[16+i] = sk[i];
key[8+i] = sk[8+i];
}

// RC[1] =(iv)=> ID[1] =(SK)=> tmp
ips = new IvParameterSpec(rc1, 0, 8); //RC1
ret = enc83(mac, 0, key, id1, 0, ips); //ID1-->tmp
if(ret != 8) {
Log.e(TAG, "calcMac: proc3");
return false;
}

// tmp =(iv)=> ID[2] =(SK)=> tmp
ips = new IvParameterSpec(mac); //tmp
ret = enc83(mac, 0, key, id2, 0, ips); //ID1-->tmp
if(ret != 8) {
Log.e(TAG, "calcMac: proc4");
return false;
}

for(int i=0; i<4; i++) {
byte swp = mac[i];
mac[i] = mac[7-i];
mac[7-i] = swp;
}

return true;
}


/**
* Triple-DES暗号化
*
* @param outBuf 暗号化出力バッファ(8byte以上)
* @param outOffset 暗号化出力バッファへの書き込み開始位置(ここから8byte書く)
* @param key 秘密鍵(24byte [0-7]KEY1, [8-15]KEY2, [16-23]KEY1)
* @param inBuf 平文バッファ(8byte以上)
* @param inOffset 平文バッファの読み込み開始位置(ここから8byte読む)
* @param ips 初期ベクタ(8byte)
*
* @return true 暗号化成功
*/
private static int enc83(byte[] outBuf, int outOffset, byte[] key, byte[] inBuf, int inOffset, IvParameterSpec ips) {
int sz = 0;
try {
// 秘密鍵を準備
SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
DESedeKeySpec dk = new DESedeKeySpec(key);
SecretKey sk = kf.generateSecret(dk);
dk = null;
kf = null;

// 暗号
Cipher c = Cipher.getInstance("DESede/CBC/NoPadding");
c.init(Cipher.ENCRYPT_MODE, sk, ips);
sz = c.doFinal(inBuf, inOffset, 8, outBuf, outOffset);

} catch (Exception e) {
Log.e(TAG, "enc83 exception");
}

return sz;
}

2012/06/21

[nfc]カードのサイズ

サイズというか、容量ですかね。

どこかで、NDEFフォーマット前にカードの容量はわからんかね、というようなことが書かれていた。

 

記憶を頼りに書くが、カード自体にはカードサイズを取得するコマンドはない。
FeliCa Standardにはあったと思うが、プロプライエタリなコマンドだ。

なので、けっこうめんどくさい。

 

さらに憶測になるが、まあいいや。

Type 2 Tag、つまりMIFARE UltralightやMIFARE Ultralight Cは64byteタイプがメジャーだ(と思う)けど、それ以外のサイズもある。
Ultralightとかだと、ポーリングに相当するコマンドを投げると、SAKというデータが返ってくる。
これを見て、まず大きく種別を把握することになる。

http://www.nxp.com/documents/application_note/130830.pdf

これの7ページあたりを見るとよかろう。
昔、記事に書いたような気もするが、記憶がないので書いてないかも。

 

これがわかったとしても、カードの種類くらいしかわからない。
MIFARE Classicは1Kと4Kの区別が付くのだけど、それ以外は特にないのだ。
むー。

ではどうやるかというと、実際に読むコマンドを投げる!だ。
読むときにはメモリアドレスみたいなものを指定するので、指定したアドレスに対して応答が返ってこなければ、そのアドレスはない、みたいな判別方法になる。

・・・だったと思う。
これも記事に書いたことがあるような気がする。
検索ページから削ってしまったのが悔やまれるのは、こういうときだ。

あった。libnfcの人がそういってたんだった。
http://hiro99ma.blogspot.jp/2012/02/mifareultralight-c.html

 

FeliCa LiteとLite-Sも同じようになるんじゃないかな。
まあ、あれはシステムブロック数が違うだけで、ユーザメモリは同じだったはず。

2012/06/20

そもそもnstってなにをするんだろう

LLCPの実装サンプルとして見ていたnfc-smart-tag。
よく考えると、SecureURLなるものをやりとりするための端末だったはずだ。
しかし、SecureURLもよくわからんし、そもそも何するんだろうというところをわかっていない。

今日は早く帰ってきたので、その辺を見てみよう。


http://code.google.com/p/nfc-smart-tag/wiki/NfcSmartTag

まずは、ここから読み始めるといいらしい。

「digitally signed one-time URL」デジタル署名されたワンタイムURL、これをSecureURLを呼んでいるようだ。
このSecureURLをNFC搭載モバイルデバイスへ送ることができる端末、それがnfc-smart-tagなのだ。

NFCプロトコルは以下に対応しているとのこと。

  • Android BEAM (SNEP over LLCP)
  • Android NPP (NDEF Push Protocol)
  • Tag Emulation
  • FeliCa Push

 

今までNFCプロトコルについて書いたことがなかったので、簡単に書いておこう。
「私の認識では」の一文を先に書いておこう。

 

・Android BEAM
・Android NPP

どちらもAndroidのデータ方式だが、ここではBEAMの方がSNEPを、NPPの方はNPPを使うように書かれている。
私の認識では、NPPだけ搭載しているのがAndroid4.0より前の機種。
4.0以降はSNEPを搭載していて、なんか来たらSNEPで様子を見て、違ったらNPPでやってみる、という手順で動いてると思っている。
「じゃあNPPだけ搭載すればいいやん」となりそうだが、NPPはAndroid独自規格なのに対して、SNEPはNFC Forum規格なので、いずれはNPPは消えるんじゃないかなと思ってる。

・Tag Emulation

Tagのふりをすること。
NFC Forumでは「Card Emulation」と呼んでいる、あれ。
ソースを読む限り、Type 3 Tagのエミュレーションみたい。
NFC Forumとしてはエミュレーションがoptional。
RC-S620/SでType 3 Tag以外のエミュレーションができるのかは不明(できんと思う)。

・FeliCa Push

いわゆる「三者間通信」。
Faver1.5時代から搭載されているアドホック通信機能。
アドホック、というとわかりにくいが、データを送りつける機能だと思っている。
FALPではデータ交換が可能になるが、Pushはデータを送るだけだ。


送信されたSecureURLは、オンラインアプリからオフラインアプリまで可能にする。
・・・訳が怪しい。
「physical location」とあるから、物理的な場所と関連したSecureURL、ということか。
例が書いてあるので、読むとわかるかも。

  • タッチによるチェックイン
  • クーポン
  • specialなofferにアクセス
  • NFCタッチによる購入アクションへの承認

わかるような、わからんような・・・。

送られてきたURLはワンタイムであることが保証されるので、漏れたりしても大丈夫、ということなのかな。
パスワード、いや、パスワード以上の情報を持つことになるのかな。
にもかかわらず、端末操作を特にがんばらなくてもいい、というのがよいのかも。

 

サーバ、みたいな横文字が入ると私には訳がわからなくなってくるのだが、もう少しだけ見ておこう。


http://code.google.com/p/nfc-smart-tag/wiki/SecureUrl

これがSecureURLのページらしい。

SecureURLを作るのに、情報としては

  • 64bitのstation ID(station、というのはnfc-smart-tag本体のこと)
  • 32bitのカウント値
  • (オプション)モバイル端末の64bit NFCID

がいるらしい。
おもしろいのは、NFCIDがオプション扱いということだ。
それ以外の情報も付加して、さらにセキュアに(なのかユニークになのか)できるようだ。

 

ここから先に、実際の実装方法が書いてあるが・・・もうよかろう。
あんまりサービス関係に興味がないので、ここまでだ。

あとは得意な人に任せよう・・・。

2012/06/19

[nst]ここらへんは仕様にあわせた方がいいかなぁ

nfc-smart-tag、フルネームで書くのもめんどうになってきたので、nstで許しておくれ。

ソースを読んでいて、ここはちょっとなあ、と思ったところを忘れんように挙げておこう。

 

  • NFCID2が8byteともランダム生成。先頭2byteは仕様にあわせるべし。
    Androidとかって、IDm見てたんじゃないっけ。
  • ATR_RESのTOとLLCPのLTOの値関係。
    LTO > RWTって仕様だから、RFConfigurationで小さくせんといかんかな。


いまのとこ、こんなもの。
また何かあれば追記しよう・・・ってほど、自分がわかってるかどうかわからんがね。

2012/06/17

[llcp]モードでいきなりつまずく

LLCPを実装しようか、とインターフェースを書き始めて、いきなりつまずいた。

通信方式として、Active communication modeとPassive communication modeがある。
通信速度として、106kbps, 212kbps, 424kbpsがある。
さて、どの組み合わせでやればいいんだろう?

 

NFC Forumとしては、Device Requirements[zip]でこう書いている。

  • 3.2 NFC Forum Brand Promise for NFC Forum Peer Mode
    • 物理層:NFC-A, NFC-F
    • デジタル層:NFC-A, NFC-F
    • Initiator/Target:NFC-DEP
    • LLCP
    • Service Discovery Protocol
    • SNEP
    • NDEF

通信速度はNFC-A, NFC-Fの定義だろうし、Digital ProtocolドキュメントではActive Communication modeはこのバージョン(1.0)では取り扱わない(not described)とかサポートしないとかいってる。

 

でもねぇ・・・nfc-smart-tagのソースを見る限りでは、106kbpsのActive communication modeでLLCPしようとしてるのよねぇ。
まあ、nfc-smart-tagはSecure URLを渡すための端末なので、LLCPは手段の1つでしかないので、私が変にお手本として期待しすぎているだけってのはわかっているのだ。
わかってるんだけどねぇ。。。

ここまでにつくったnfc-smart-tag資料

ちょろっと作ったので、サーバに置いておく。
なんで2つのファイルがあるかというと、astah* communityはデータのコピーができないため・・・。

いつもPDFにしてるけど、めんどくさいからこのままでいいや。
astah* のビューアソフトはないので、中身を見たい方はダウンロードしてインストールしてくだされ。

https://sites.google.com/site/hiro99ma/home/files/other/nfc-smart-tag.asta?attredirects=0&d=1

https://sites.google.com/site/hiro99ma/home/files/other/nfc-smart-tag_RF%E9%83%A8.asta?attredirects=0&d=1

NFC-DEPのきれいな終わらせ方がわからん

NFC-DEPの開始とデータ交換はわかったが、終わり方がわからん。

ISO/IEC 18092に従えば、RLS_REQを投げるとよさそうだ。
PN533ではInReleaseというコマンドがあるのだけど、RC-S620/Sではよくわからない。

 

ほっとくと、タイムアウトエラーで終わる。
通信相手がいなくなることは十分あり得るから、タイムアウトエラーの考慮は必要なのだけど、成功してもタイムアウトエラーになるのは気持ちが悪い。

だけど、対処のしようもないしなあ。。。
nfc-smart-tagのソースを見ると、LLCPのI PDUを投げて、その応答が0x81だったら成功、としている。
SNEPは1要求1応答だし、nfc-smart-tagは1回だけI PDUを投げるようにできているから、そうなってるんだろう。
まあ、それはそれでいいのかな。


よく見ると、nfc-smart-tagは、InitiatorからRLS_REQを受け取ると、ちゃんとRLS_RESを返すように実装している。
ってことは、Initiatorも同じ要領でRLS_REQを送信すればいいってことか。
なんでもかんでもR/Wに頼ろうとした私が甘かったか。。。

 

と思って実装したけど、なかなかうまくいかん。
nfc-smart-tagは、TgInitTargetの戻りでRLS_REQチェックをしているだけだ。
ドキュメントも、TgGetDEPDataで返すのはDEP_REQだけになっている。
RLS_REQはTargetでは途中で受け取ったことを戻り値Statusでしか判断できないと考えてよいのだろう。


ではInitiator側はどうしたらいいんだ・・・。
まねして、CommunicateThruEXでRLS_REQを返すと、Target側がRLS_RESを返してきた!
そうか、TgInitTargetのときはどうしようもないけど、それ以外の場合はR/WがRLS_RESをさばいてくれるのだな。

 

RLS_REQを投げると、TargetはTgSetDEPDataから抜けてくれるのだが、RFなしっぽいエラーになっている。
期待するのはReleaseされたときのエラーコードなんだけど、これはしょうがないのか、単に実装をどっか間違ってるだけなのか。。
Targetが返すデータがないのでTgSetDEPDataを投げたタイミングでRLS_REQを送信しているつもりなのだが、なんかうまくいってないのかもね。

 

NFC-DEPは動かせていると思っていたけど、ちゃんとやるといろいろ出てくるものだなぁ。
とりあえずこの問題は置いておいて、LLCPに進んでみましょうかね。

2012/06/16

[無駄話]LEAP Motionというセンサ

急に、Kinectって面白そうだな、と思った。
私は唐突だ。
SDKもありそうなので調べてみたが・・・
MicrosoftのはWindows 7以降だったので、うちのXPでは使えない。
オープンなSDKもあるけど、センサみたいなものって開発元から資料が出ていたほうがよさそうに思う。

そんなことを思いながら調べていると、LEAP Motionというものがあった。
そういえば、twitterでそんな単語が出ていたような気がする。
(twitterに出てくるような話題は私に関係なさそうと思って放置してるのだ)
http://www.leapmotion.com/
70ドルってことは・・・1万円しないってことですな(いまは)。
なんだかよくわからないけど、けっこう細かいところまで検知するみたい。
まあ、検知しすぎなのは大変かもしれないけど、電池で動くんでなければソフトではじけばよいだろうしね。

私がしばしばやっているのはNFCくらいしかないのだが、NFCはそれ単体では何もできん。
なんというか、インターネットっていうのが情報をやりとりする、というだけで、それだけでは何もないのと同じだ。
やりとりをするための両端に機材がいるし、それを取り扱う人がいるし、ストレージとかなんだとかかんだとか、いろいろいる。
インターネットがあればなんでもできる、みたいにいっているけど、それはインターネットを取り扱う機器と、それを取り巻く環境ができているからだと思うのだ。
同じようにNFCも、NFCチップだけあればいいかというと、そうではない。
それにアクセスする装置もいるし、アクセスしたことを通知する機能もいるし、いろいろあるのだ。
私はインターネットを使ったシステムが苦手なので、なるべく使わないで済むようなつくりにしたいと思っている。
実家にブロードバンドのネットがつながれば意識が変わってくると思うが、その気配もないのでしばらくはこのままだ(WiMAXがんばれー)。

いかん、話が逸れた。
結局のところ、ホスト動作をするのは人間で、それ以外はすべてセンサという扱いでもいいのかもしれん。
ソフト屋さんとしては、人間(=ホスト)との接点はスイッチとかセンサとかのデバイスしかない。

NFCのカードというのは、メモリを持ったスイッチのような役割ができる。
なにかアイデアを考えようとしても「NFCじゃなくてもいいやん」ということに落ち着きがちだけど、力業とかではなく、何か視点を変えることで「ああ、そういうこともできるやん」というものがありそうな感じがある。
そういうところが、一部の人を引きつけてるんじゃないかな、と勝手に思っている。
あとは、その一部が"錬金術"みたいな妄想でないことを期待するところだ。

[rcs620s]TgInitTargetの6パターンを試す

RC-S620/Sのコマンドリファレンスマニュアルによると、ターゲットになるコマンドTgInitTargetで動作が可能なのは、以下の6パターンと書かれている。

  • Passive communication mode ISO/IEC 18092 106kbps - DEP
  • Passive communication mode ISO/IEC 18092 212kbps - DEP
  • Passive communication mode ISO/IEC 18092 424kbps - DEP
  • Active communication mode ISO/IEC 18092 106kbps - DEP
  • Active communication mode ISO/IEC 18092 212kbps - DEP
  • Active communication mode ISO/IEC 18092 424kbps - DEP

まだDEPの実装は終わってないが、動作確認だけすることにした。

 

結果として、全部動作することが確認できた。
って、ハードの単体テストかよ。。。
いやいや、各動作でのログを残しておきたかったのだ。
NFCのデバッグをするとき、ログしか追えるものがないからだ。

 

つまずいたのが1箇所。
106kbpsのPassiveが、最初はうまくできなかったのだ。
コマンドリファレンスマニュアルをよく読むと、「9 留意事項」にいろいろと重要なことが書かれていた。
いや、書かれていたのは知っていたのだが、気にしてなかったのだ。

  1. まず、ターゲットになる前に、通信性能向上のための呪文を唱える。
  2. そのあとでTgInitTargetコマンドを発行して、イニシエータを待つ。
  3. イニシエータがATR_REQを投げると、TgInitTargetから戻ってくる。
  4. このとき、通信速度とActive/Passiveが渡されるので確認
    • 106kbpsなら、通信性能向上解除の呪文を唱える
    • 106kbps Passiveなら、さらに呪文を唱える

この4番をやってなかったのだ。
理由は、めんどくさいから。。
だって、これをやるためには、

  • fAutomaticATR_RES=0にする→SetParametersコマンドの処理がいる
  • 呪文の処理がいる→WriteParameterコマンドの処理がいる
  • ATR_RESを手動で返す→TgSetGeneralBytesコマンドの処理がいる

と、3つも増えるのだ。
ああ、しゃーらしい!

 

けど、全部やると、ちゃんと動いた。
やらんと動かんから書いてあるのだから、ドキュメントはちゃんと読め、と思った。

libusbx

私は、USB機器を操作したいとき、PCだとlibusbを使っている。
libusb-1.0だ。
これで作っておくと、WindowsでもLinuxでもOS Xでも動くという、便利な代物だ。
(もちろん、それぞれの環境にインストールなんかはいるけど)

 

久々にパソr・・・USB機器を操作しようと実行したら、なんだかよくわからない実行時warningが出てきた。
うーん、同じソースで動いていたのに・・・。

よくわからないときは、とりあえず最新バージョンにしてやってみよう、とネットを見ると、libusbxなるプロジェクトができていることを知った。
「今後のWindows版はlibusbxでやる」みたいなことが書いてあったが、libusbxもマルチプラットフォームのようなので、心配はいらんようだ。

 

ライブラリが変わると、実装を変更したりするのがめんどうなのだが、libusb-1.0からlibusbxに変更するのは、includeパスくらいだけだった。
私はcygwin環境を使っているのだが、こんな置き方をした。

  • /usr/local/binにdllをコピー
  • /usr/local/libに.aとdll.aをコピー
  • /usr/local/includeにlibusbx-1.0/libusb-1.0.hをコピー
  • .bashrcに「LIBRARY_PATH=/usr/local/lib」を追加

最後のは、LD_LIBRARY_PATHに/usr/local/libがあったけどlibusb-1.0のリンクが通らないので、やってみたらなった。
cygwinはLD_LIBRARY_PATHじゃなくてLIBRARY_PATHだとか、なんだとかかんだとかいろいろ出てきたけど、動けばよかろうなのだ。

置き換えたら、warningは出なくなった。
あまり納得はいってないが、動けばよかろうなのだ。

[rcs620s]106kbpsコマンドではターゲットが戻ってこない?

NFC-DEPのため、RC-S620/Sコマンドリファレンスマニュアルを読みながら試作中。

TgInitTargetの戻り値確認をしている。
対抗機がないので、PaSoRiで以前SDK for NFC Starter Kitで作ったソフトでデータ読み取りを実行させている。
NFC-DEPのInitiatorがいればいいんだけど、手元にないしね・・・

 

やってて気付いたのだが、212kbps/424kbpsのReadコマンドはTgInitTargetから戻ってくるのだが、106kbpsのReadコマンドは戻ってこないのだ。

UIDやSAKが取得できているので、SENS_REQは済んでるはず。
ISO/IEC 18092を読むと、ATR_REQ/RESの前に「SDD」がある。
SDDは「Single Device Detection」の略で、たぶんカード(PICC)を1枚だけ検出するための処理を指しているのだろう。
SDDのあと、ATR_REQを要求してこなければ、これはプロプライエタリなコマンドということで独自処理をして終わるようなシーケンスになっている。

ということは、106kbpsのときにターゲットが戻ってこないのではなく、212kbps/424kbpsのときにはターゲットが戻るようにRC-S620/Sが処理をしている、と考えてよいのかな。
単に106kbpsの処理がうまくできてないだけかもしれんがね。

 

RC-S620/Sコマンドリファレンスマニュアル Version 2.0の図8-3ではATR_REQかTarget ID取得コマンドの2択になっているけど、通常のコマンドが来ることも想定しないといかんようだ。
そして、ATR_REQと通常コマンドの場合には、TgInitTargetから戻ってくる、と。

戻ったあとでどう比較するかというと、データを見るしかなさそうだ。
nfc-smart-tagでも、戻ってきたコマンドがATR_REQかどうかを確認してから処理を進めているので、考え方は間違っていないようだ。

[llcp]MIUのデフォルト値は128byte

LLCPの資料をまだ読んでいる。
長いことやっているのに、まだわかってないのが哀しい・・・。

しかし、最近ようやくNFC-DEPの実装に着手するなど、まったく止まっているわけではないのだ。


そのNFC-DEP。
上位層にLLCPを載せる前提で実装しようとしている。
というのも、長いデータ長の扱いが面倒だからだ。
R/Wコマンド→エアプロトコル、という段階でパケットが複数に分かれる場合、R/WがMIフラグを管理してくれるようだ。
しかし、R/Wコマンドを複数回呼び出してパケットが複数になる場合、当然ならがMIフラグを上位層が管理しなくてはならない。
めんどくさい。。。。

 

どこかで複数データ分割は対応しないといけないけど、それはLLCP層でやってしまい、NFC-DEPではそれを省こうと考えているのだ。
それができるのは、LLCPの1パケット(1 PDU)がNFC-DEPのR/Wコマンドに渡すことができるデータ長以下に抑えることができる場合だけだ。
さて、どうだろう。


LLCPでは、1回の送受信で扱うPDUのサイズを「MIU (Max Information Unit)」という値で管理している。
デフォルトは、128byte。
これを拡張することもできる(MIUX)が、しないこともできる。
だから、128byte。

NFC-DEP関連のR/Wコマンドで扱えるデータ長は、252byte。
MIUデフォルト値=128byte < 252byte。
よってNFC-DEPでパケット分割をサポートしなくてもなんとかなる。

Q.E.D.


そういえば、nfc-smart-tagではどうなってたんだっけ?
うまいこと分割してるのかな?

そう思ってソースを見る。

nfc-smart-tagはターゲット専用なので、TgInitTargetのGeneral Bytesを見る。
なぜなら、LLCPはここでPAX PDUのデータを載せることになっているからだ。

firmware/nfc/llcp.c L.32に定義がある。
コメントを読む限り、VERSION、WKS、Timeoutの3種類だけで、MIUXは送っていない。
つまり、1回のPDUは最大128byteということになる。
では、128byte以上のデータをどこかで分割しているのか?

その答は、firmware/target.cにあった。
L.283のspバッファ定義。
これが128byteになっている。
コメントにも「タグデータは80byte以下がいいな~」といってるので、間違いなかろう。
nfc-smart-tagは1回のI PDUで送るようにできている。

 

うーむ、割り切ってるなあ。
とはいえ、SmartPosterなのでブックマーク代わりのテキストが入ったとしても、URLがそんなに長くなることはないと思う。
URLとしてはよくあるだろうけど、わざわざNFCで送りたいものがそんなに長たらしくなくてもよさそうだ。
組込機器ってのは、こうじゃないとね。

RC-S956のモード遷移

最近のPaSoRiやRC-S620/Sでは、RC-S956というチップが使われている。
これは、モバイルではなく、R/W用のFeliCaチップだ。
FeliCaチップと書いたが、FeliCa専用というわけではなく、NFC-AもNFC-Bも対応している。
なので、正確にはNFC用R/Wチップ、となるか。

 

RC-S620/Sのコマンドリファレンスには、RC-S956内部で持つ「モード」のことがしばしば記載されている。
文章で書いてあるとなんだかわかりにくかったので、図にした。

RC-S956のモード

astah* communityだと、図がでかい・・・。

無料で使えるからいいのはいいのだけど、無料版だといろいろと制限がある。
有料版だと、フォントなんかも指定できるのだがね。

 

試しに、Diaを使ってみた。

RC-S956モード

うーん・・・・・・・・・・・・・・・。

メモに日本語が入力できなかったので、ちょっとなあ(Windows版だけ?)。

2012/06/15

アンテナに引っ掛けるのは搬送波じゃなくてもいい

以前、こんな記事を書いた。
周波数とアンテナの長さ
http://hiro99ma.blogspot.jp/2012/05/blog-post_21.html

関東のNFC勉強会が気になったので、調べた記事だ。
このとき私は、搬送波が13.56MHzだから、ダイポールアンテナとかだったら5.53メートルくらいの長さがいるだろう、と書いた。

しかし、勉強会の結果を見ていると、あんまり長くてもだめ、みたいなことが書かれていた。
ええっ、そうなの??
なんで???

そして今日、社長のコメントを読み、あることに気付いた。
もしかすると、誘導しているのは13.56MHzじゃなくて、106kbpsとか212kbpsの方かも。

λ=v/f=(3.0x10^8) / (212x10^3) = 300000/212 = 1415.94[m]。

長くなっとるやーん。
分母に周波数が来るんだから、周波数が高くならないと短くならんわな。

[pn533]InJumpForDEP

NXPのPN533ユーザーズマニュアル[pdf]をときどき読んでいる。
英語だけど、NFC R/Wの雰囲気を味わう分には、そんなに読まなくても何とかなる。

 

個人的にNFC-DEPのInitiator側処理を調べているので、それに関するコマンドを見てみよう。
まあ、私の調べていることはいつも個人的なものしかないのだがね・・。


InJumpForDEP。
これが、ターゲットをactive communication modeかpassive communication modeとして起こすコマンドらしい。

「If a target is in the field, it will then be ready for DEP exchange.」と書いてある。
力強い限りだ。

 

このコマンド、R/Wコマンドとしてはパラメータが多い。
Targetになるコマンドも多いのだが、これもなかなかだ。
必須は、3つ。

  • Active communication modeかPassive communication modeか
  • Baud Rate (106kbps / 212kbps / 424kbps)
  • オプションパラメータの有無

オプションが最大3つあるので、全部で6パラメータまであることになる。
コマンドの詳細は、ドキュメントを見ればわかるので割愛。


そのレスポンスが次のページに載っているが、これを見て何か気付かないだろうか?
そう、TgInitTargetコマンドのパラメータに似ているのだ。
ある人はこういうかもしれない、「ATR_REQ / ATR_RESに似ている」と。

 

ここまで材料が揃うと、このコマンドのやることが何となくわかってくる。

このコマンドは、Pollingをするだろう。
NFC-Bに対してはわからないけど、AとFのどちらかにはしそうだ。
どっちにするかは、Baud Rate設定で決まるだろうし、オプションパラメータ「PassiveInitiatorData」も関係するだろう。
Targetの捕捉はどうしても必要なのだ。

その応答を見てから、ATR_REQを送信するのだろう。
なぜなら、NFCID3iというオプションパラメータが212kbps/424kbps passiveでは使われず、POL_RESから取得したNFCID2tを使うと書いているからだ。
POL_RESは、NFC-FのPollingコマンドのこと。
NFC-Fの場合はNFCID3の10byte中、8byteはNFCID2(IDm)を使うことになっているので、自然な仕様だと思う。

Initiatorは要求をかける側なので、Targetが応答を返してきてから考えても遅くない。
だからTargetのようにGeneralBytesを別で渡すようなしくみはない。

 

というところだろう。

これとセットで使うのが、InDataExchangeだが、全部書くと面白くないだろうから、おしまい。

2012/06/13

[無駄話]サポート範囲

仕事の休み時間、なんとなく日本で使うことができるNFCのモバイル決済カードについての話になった(nimocaとかSUGOCAとかの話ってだけだが)。

カードをかざすと、乗ることができる。
そう、残金がなかったとしても。
そのときにお金を持ってなかったら、どうなるんだ?という話だ。
どうするんだろうね?

今日は、ちょうど2つくらいNFCサービスについての記事紹介があったので、読んでいた。

米国で普及しないグーグル版「おサイフケータイ」、その理由と背景を探る
http://gendai.ismedia.jp/articles/-/32729

ロンドン地下鉄がNFCでの乗車券サービスを始められない理由
http://ascii.jp/elem/000/000/701/701654/

どちらも目新しい話ではないが、気にする人が出てきたというのはいいことだろう。
縮退鍵などがなんで出てくるのかってのを検索してみるとわかるかもしれんな。
私はこの辺の記事が面白いと思った。
まあ、私は決済方面は興味がないのだがね。。技術としては面白いのだ。
http://techon.nikkeibp.co.jp/article/FEATURE/20091113/177603/

NFC-DEPをちゃんと実装してみようと思うが、めんどうになる

なんとなくめんどうなので避けていたが、そろそろNFC-DEPをちゃんと実装してみよう。
独り言だと思って聞き流しておくれ。

まず、どれに向けて実装するか。
私の場合、使える主なプラットフォームはこれらだ。
  • Windows XP 32bit
  • Linux 64bit (xubuntu)
  • Windows XP + cygwin
  • BeagleBoard
  • CQ出版社の付録基板
NFC-DEPの手先(?)となるのは、うちではNFC R/Wしかいない。
  • PaSoRi RC-S370 (黒パソリ)
  • RC-S620/S
PaSoRiはUSBだが、特にドライバがなくても慣れればアクセスできる。
AndroidのUSB Host機能からも使えたし、もちろんWindowsやLinuxからもできた。試してないけど、LPC2388もできそうな感触だ。
RC-S620/Sはいろいろできていいのだけど、UARTだからなんとなくめんどくさく感じてしまう。
個人的には、SPIくらいが好きなのだが、次製品はI2Cになるらしい。よく知らんが、ArduinoとかってI2Cポートがあるのかいな(ソフトI2Cか?)。
きっとR/WがI2Cスレーブになるだろうから、ホスト側がマスタになればいいんだけど、ACKがしばらく返ってこないようなコマンドはどう動くんだろう? ACKビットをホールドしたままにするのかいな。
まあ、ここはそこまで悩まなくてもいいだろう。


NFC-DEPに関して、R/Wの動作はできているので、インターフェースに落とすだけだ。
だけなのだが、そこが決め切らんところなのだ。

今のところ、NFC-DEPを使うのはNFC-AかNFC-F。
ここで、大きく選択が分かれる。
  • 106kbps通信
  • 212kbps通信
  • 424kbps通信
また、通信の関係もある。
  • Active communication mode
  • Passive communication mode
Initiatorの無線にTargetが載っかるPassiveモードか、お互いが無線を出し合うActiveモードか。
決める主導権は、Initiatorにある。
TargetはInitiatorを待ち、お互いの求めるものが一致すればNFC-DEPを始められるし、一致しなければTargetが無視するだけである。
この部分、アプリに全部お任せして、ミドル部分はいわれた通りに動くだけ、というのもいいだろう。
しかし、ただでさえわかりにくいDEPの部分をユーザに開放してしまうと、うまくつながらないということになるのは想像に難くない。
ある程度、使い道を限定した方がやりやすくなるんじゃないだろうか?

そこまで考えて、はたと手が止まった。
私はNFCのデータ交換の現実について詳しくない、という事実に気付いたのだ。
どうしたもんかねぇ。

InCommunicateThruはOKなのか

最近、NFCの基礎勉強をしていないので、Interface 2012年4月号を読んでいる。

今朝はなんとなく、8章を読んでいた。
「FeliCaリーダを使った電子マネー表示システムの制作」というものだ。
RX62NというRenesasのチップを搭載した付属ボードが昨年の付録にあったのだが、それにRC-S620/Sを載せて動かすという企画である。

 

最初に書いておくが、通信もののデータはビッグエンディアンが多い。
NBO(Network Byte Order)という書き方をしている場合もあるが、ビットの並びもバイトの並びもビッグエンディアンになっているものが多いように思う。
NFCもだいたいそうなのだが、FeliCaパケットの中にはときどきリトルエンディアンを含んだものがある(ブロックリストくらいか?)。

8章ではいくつかパケットの説明が書かれているのだが、システムコードはビッグエンディアンなので注意してほしい。
共通領域のシステムコードは0xfe00だし、サイバネは0x0003だ。

システムコードは、ISO/IEC 18092にはブロードキャスト(FFFF)しかないのでわからないけど・・・そういうものなのだ。
出所の資料くらいすぐ見つかるだろうと読んでいたのだが、なかなか出てこないのでびっくりした。
NFC ForumのType 3 Tagドキュメントに「リトルエンディアン」と出てくるのが、一番はっきりした記載のように思う。


そういう些末なことよりも、InCommunicateThruがさらっと出てきているところに驚きがあった。
CommunicateThruEXでよさそうなところに、あえてInCommunicateThruを持ってくるとは。
渋いな。

これがOKなら、InDataExchangeもいいかもな(なにが?)。

I2C

Sonyさんが開発中のNFC通信モジュールは、I2Cインターフェースらしい。

http://techon.nikkeibp.co.jp/article/NEWS/20120611/222331/

 

あいつーしー、と私は発音する(もちろんEEPROMは、いーつーぴー)。
英語っぽく発音するなら、あいすくぇあしー、だろうか。
元はフィリプス社のインターフェースだったけど、人口に膾炙したというか、よく使われている。

通信線は、2本。
GND抜かして、とかではなく、2本だ。
基本的には基板上の機器間を接続するから、GNDは共通になってることは多いかもしれんがね。

1本が信号線で、もう1本がクロック。
日本語の仕様書[pdf]があるので、そっちを読んでおくれ(なんとなく読みづらいが)。

 

仕事で、ちょっと使ったことがある。
ちょっとというか、ちょっと使いたいだけだったのにえらくはまったというか。
FTDIのチップを使って、PCからつなぎたかったのだ。
あまり時間もかけていられなかったのだが、不満足な出来だったのが心残りだ。

はまったのは、線が2本しかないので、どっちのデバイスが悪さをしているのかわからなかったところだった。
FTDIチップとデバイスA、FTDIチップとデバイスB、という組み合わせを試したけどどっちも同じような動作だったから、FTDIかなぁ、と勝手に思っている。
汚名をそそぐでも、判決を下すでもどっちでもいいけど、はっきりさせたいところだ。

 

個人的には、SPIみたいに分かれてる方が好き。デバッグしやすいし。

2012/06/09

[llcp]また私は読み違えたのか?

SNEPのドキュメントをざっと眺めたので、nfc-smart-tagのソースを追っていった。

今さらわかったのだが、

  • 相手がISO/IEC 18092 Active communication modeなら、SNEPでNDEFを返す
  • 相手がISO/IEC 18092 212/424kbps Passive communication modeなら、カードエミュレーションしてRead w/o Encryptionの応答としてNDEFを返す

となってた。

うーん、NFC ForumのDigital Protocolには「Active communicationはサポートしない」とあったので、その流れで適当に読んでいたのだが、読み違えていたようだ。

nfcpyを動かす

Windows XP環境でnfcpyを動かした。
既にいろいろインストールされている環境なので、他にもいるものがあるかもしれんが、まあ記録として書いておこう。
ドキュメントを読みながらやっているので、そう変わらんかも。

いるもの

  • cygwin (Windows環境でもできるらしいが、わからんかった)
  • libusb-win32
  • pyUSB

インストール

  1. cygwinをインストール。pythonもインストール。3.x系はだめらしい。
  2. libusb-win32は1.2.6.0を使った。libusb.aを/usr/lib/に、lusb0_usb.hを/usr/include/にコピー。
  3. pyUSBは0.4.3を使った。1.x系はだめらしい。ちなみにcygwinを使ったのは、これのインストール時にvcvarsall.batをうまく解決できなかったため。Windows SDKみたいなのがいると思う。
  4. nfcpyをbzrで持ってくる。

チュートリアル

ドキュメント参照。
書かれていない基本的なことを書こう。
まず、pythonを手入力コードで動かすには「python」って打つ。
そうすると「>>>」というコマンドプロンプトになるので、打っていく。
「import xxx」というのは、たぶんディレクトリ構成そのままだろうと思う。
チュートリアルで「import nfc」とあるが、これはnfcpyをダウンロードした中にある「nfc」というディレクトリ内にあるライブラリを読み込む、みたいなことをするみたい。
チュートリアルの「HelloWorld」を動かすには、
$ python HelloWorld
$ python helloworld.py
などとする。
このHelloWorldサンプルは、カードを一度かざし、もう一度かざし直すと何かして終わるようになっている。
気になったので、FeliCaランチャーで使ったカードをかざすと、項目として「NFCタグ(テキスト)」が出てきた。
クリックすると、ブラウザが起動して「Hello World」と出てきた。
へー。
そ、それだけじゃなかった。
read_ndef.pyというサンプルがあったので見てみると、言語ごと(ここではen, de, frの3つ)が書き込まれていた。
やるな、サンプルのくせに・・・。
いやあ、便利だわぁ。
SNEPサンプルもあるので、実装したら試せそうだ。

libusbの方も説明した方がよいかも。
libusb-win32を解凍すると、binディレクトリの中にinf-wizard.exeがある。これを実行して、PaSoRiなんかをうまいことlibusbで使えるようにしてやらないといかん。
また、binの下の方にtestlibusb-win.exeがあるので、試しておいた方がよい。
これでPaSoRiが見えなかったら、nfcpyも使えないはず。
私はzadigでlibusbが使えるものだと思っていたのだが、そうではないようだった。
(zadigは、ドライバの種類を選択できるのだった。libusbドライバを選べばよいのかも。)
inf-wizardでlibusbから使えるようにすると、今度はFeliCaランチャーみたいなアプリから使えなくなる。
そのときはデバイスマネージャからPaSoRiを探し出し、ドライバの更新をすると戻る。

LLCPのInitiatorはコストが高めか

nfc-smart-tagのLLCP実装量を見て「こんなに少なくていいのか」と思ったが、それなりに割り切った実装であることがわかってきた。
この「割り切った」は別に悪い意味ではなく、機能を満たすために必要な量だけ実装しているという意味である。

 

NFC ForumのLLCPドキュメントは仕様書なので、なんでも対応できるように書いてある。
それをそのまま実装すると、かなり実装コストが高めになりそうだ。
だから、端折って「割り切った」実装にしたくなる。

したくなるのだが、どこまで端折っていいかのガイドラインがないので、NFC Forumの互換性テストなんかを実施しない限りは、各社が好き勝手な実装をして、お互いがP2Pなのに通信できない、ということになってしまう。

 

私としては、LLCPのサブセット規格がほしいところだ。
つまり「LLCPサブセット対応端末」みたいな位置づけを用意し、LLCPの中でもこれとこれには対応していて、これこれには対応していません、というようにLLCPの中身を分割してしまうのだ。
そしてPAXなんかで最初にやりとりするとき「おまえは、規格のどれに対応してますか?」「はい、私はこれこれに対応してます」みたいな通信をして、必要最小限の機能搭載だけで済ませられるようになるのだ。

そうなると、実装する量も減らせるので、実装コストも本体コストも下げることができるのになあ。
実装量が増えるとテスト量も増えて、大変なのだよ。

[無駄話]SNEP対応製品を探すも、挫折する

先日、このサイトをGoogle検索からはずすようにしたが、理由はいろいろとある。
NFCについて検索でひっかかるのに自分のサイトが多い、という理由は、まあそうだ。
なぜそれが嫌かというと、
  • 私は憶測で書いたり、調べもせずに書くことがあるので、それを信用されると困る
  • 自分の知りたいNFC関連のことが出てこないので、腹が立つ。
前者は「じゃあ、ちゃんと調べてから書けばいいやん」っていわれそうだが、私は憶測が当たっているかどうか、というのを楽しむタイプなのだ。
そういうときには「調べてないけど」とか「たぶん」とか口を濁しながらも書いているつもり。
全部が全部、検索から外さなくてもよかったかなー、とは思うが、まあいいや。姉妹サイト立てたし。
後者の方が深刻で、自分のサイトばかりが出てくると、「他の人は興味がないのでは・・・」とやる気が下がってしまう。
検索して他の人が出てくると「ああよかった」と思うのは、主体性がない人間だからだろうか・・・。
まあ、迷っても仕方ないので、やりたいことをやろう。

私は携帯電話はほとんど使わないので、「NFCが使える携帯電話を買おう!」などと思うことはない。
ただ、最近調べているLLCP/SNEP。これはNFC端末同士の通信なので、NFCが付いている人しかできない。
うちにはPaSoRiもRC-S620/Sもあるから、道具はそろっている。
そろっているのだが、使い方がわかっていない。
まず、使い方を見て、慣れたいのだ。
だからSNEP対応製品をネットで探すのだが、自分のサイトに阻まれ腹が立つ、というのは先ほど書いた。
あらためて検索すると、Android端末以外でもSNEPが使えそうなものはあった。

BlackBerry Bold990 / Curve 9360
携帯電話ではあるが、BlackBerryだ。
SNEP responderって書いてあるから、ターゲットになって待ち受けるのかな?
記事になっているサンプルがそうなのか、BlackBerry自体がそうなのかまでは読んでない。
Javaのライブラリ
これは、先日のNFC World記事。
搭載製品じゃないけどね。

あれ・・・見つけられない・・・。
キーワードが悪いのか?
でも、DEPとかじゃさらに見つからないだろうし・・・。
しかし、収穫もあった。
SNEP Server/Clientみたいな表現があったので、SNEPもある程度見ながらLLCPを見ていく方が良さそうだということに気づいたのだ。

2012/06/07

[llcp]Link Activationの復習

ようやく平常運転だ。

nfc-smart-tagのソースを読んでからLLCP v1.1のドキュメントを読むと、意味がよくわかる。
個人的には忸怩たるものがあるのだが・・・LLCPのドキュメントを読んでも具体的な動きがわからなかったので、屈服せざるを得まい。

それに、私がやりたいのはInitiator側なのだ。
だからTarget側であるnfc-smart-tagの動きを知っておくことは大切なのだ。
うんうん、そういうことにしておこう。

 

では、過去を振り返りながらLLCPのLink Activationを復習しよう。


LLCPは、NFC Forumが想定しているP2Pの下層プロトコルだ。
最下層は、NFC-DEP。
NFC-DEP、LLCP、SNEPという3層構成になっている。

少し前まではSNEPがなく、LLCPで通路だけができていたところだった。
通路だけあって、そこに何を通すかが決まっていなかった。
一番最初に通った大物は、AndroidのNPP(NDEF Push Protocol)だろう。
Android4.0からは、SNEPとNPPが搭載されていて、まずはSNEPでアクセスし、だめだったらNPPを使う、というソースになっていた。

 

LLCPはNFCながらも、UDPみたいなコネクションレスの通信と、TCPみたいなコネクション指向の通信が定義されている。
Androidのlibnfc-nxpや、NfcServiceの下層にはどっちも入っているのだけど、NfcService事態にはコネクション指向の通信しか含まれていなかったように思う(NativeNfcManager止まり)。

 

NFC-DEPは、リーダライタに直接コマンドを出して行うような、低レベルの通信だ。
「低レベル」というと程度が低いとかそんなことを思ってしまいそうだが、英語だと「low-level」ということで下位層を指す。
もちろん、最下層はRF(Radio Frequency。高周波とか無線とか)だがね。


LLCPは、おおきく3状態ある。

  1. Link Activation
  2. Normal Operation
  3. Link Deactivation

Link Activationで2台の端末を接続し、データをやりとりしている間はNormal Operation、終わったらLink Deactivationというわけだ。

LLCP v1.0からv1.1にあがるとき、SDP(Service Discovery Protocol)が追加されたのだけど、nfc-smart-tagでは使ってなさそうだった。
なので、私もそこは見ないことにする。


最初は、Link Activation。

お互いがサポートしているLLCPのバージョンや、やりとりできるパケットサイズなんかを確認するところだ。

LLCPでは、LLCPのパケットをPDU(Protocol Data Unit)という単位でやりとりする。
PDUには名前が付いていて、たとえばLink Activationのやりとりで使うのはPAX PDU(PArameter eXchange)という。

 

いうのだが、ここに罠が(おおげさ)!

LLCPを始める前に、まずNFC-DEPを始めないといかんのだが、そのときにATR_REQ / ATR_RES (ATtRibute REQuest / RESponse)というRFプロトコルを使う。
このプロトコルには、汎用として使えるGeneral Bytesという部分がある。プロトコルの一番最後になっていて、50byteくらいは好きに使っていいようになっているのだ。
LLCPではこの領域を使うようになっている(LLCPドキュメント6.2.3.1など)。

General Bytesに、キーワード「Ffm」に続けてLink Activationで使うデータを載せることになっているのだ。
LLCPで通信しよう、と思ったときには既に行動は終わっているのだ。

2012/06/06

DEPでの鍵は、ありうるのか?

鍵といえば、電気錠。
電気錠といえば、前回の福岡NFC勉強会。
そして、@mkogaxさんの公演と続く。


海外では、MIFAREのUID4→7byte ということがあったので流行ってないかもしれないが、日本だとFeliCa→認証しっかり→鍵にもOK、というのもありそうだ。

 

鍵としてNFCを利用するのであれば、私は次のいずれかを満たす必要があると思っている。

  1. 鍵は106kbpsで、7byte/10byte UIDを使用する
  2. 鍵は212k/424kbpsで、縮退鍵を使用する

 

1は、MIFARE系だ。慣れてない人が「NFC」と呼んでいるやつだ。
MIFARE系(NFC-A)は、UIDがsingle(4byte)、double(7byte)、triple(10byte)がある。
カスケードってのもあるようだが、それはよくわからん。システムコードごとにIDmがあるようなかんじだろうか。

 

2は、FeliCa Standardだ。
今のところの運用案としては、FeliCa LiteかStandardかの2択しかない。
Standardは高機能だが高い、Liteは低機能だが安い。
その間に入りそうなのがLite-Sなのだが、それはまだない。

私はStandardカードを買ったことはないのだが、錠がちゃんと縮退鍵を使ってアクセスするのであれば安全だろう。


「鍵が他の人から開けられるかどうかの試作なんて、ふとどきな」と思う人もいるかもしれんが、ちょっと待ってくれ、だ。

サムターンとかいろいろと鍵を物理的に開ける技など、今までにいくつも出てきて、それによって鍵は頑丈になってきたではないか。
それを「NFC使ってやってるので大丈夫」なんて、情報の力に頼るってのはおかしかろう。

忍者が「山」「川」とかで相手を見方かどうか見分けてるシーンがあるけど、あれはそれ以前にいくつものセキュリティを乗り越えさせ、最後を簡略な認証(と見せかけた、奥深い認証)でセキュリティを確保しているのだ。
まあ、それでも破られることはあるのだが。

最近は、セキュリティの基本を忘れているような気がしてならん。


さて、あまり興味がないカード側のことは、いいとしよう。
私は、一対一の通信、P2Pに興味がある。

P2Pは、両方ともカードではないことになる。
それ故、セキュリティについては防御しやすいとも言えるし、漏れやすいとも言える。
どちらが強いのだろうか?

気になるが、試せる環境にないなあ。
しかし、今後のことを考えると、この分野は非常に大切だ。
すなわち、DEPとセキュリティ、だ。

 

重要さについて考える非常に怖いので、今日はやめておこう。

[llcp]PAXの謎

謎、と書いた方が気分が盛り上がるだけだ。
単に私の読み不足だけなんだがね。


nfc-smart-tagのLLCPシーケンスを見ていると、いきなりCONNECTから始まっている。
うーん、Link ActivationのPAXがないけど、いいんだろうか・・・。

それに昨日気づき、朝からLLCP1.1を読んでいた(バージョン書かないとね)。
すると、p.44に書いてあるようだった。

 

まず、読むべきは6.2.1だろう。
私は先にNFC-DEPのドキュメントを読んでいたが、これを先に読んでいると気が楽だったかもしれない。

そして今回の謎は、6.2.3.1に記載されていた。
ATR_REQのGeneral BytesにPAX PDUで送る内容を書いておくことにより、PAX PDUは使わなくなる(SHALL NOT)のだ。
SHALL NOTなので、PAX PDUは使ってはいけない、くらいの強さなのだ。

 

nfc-smart-tagではLLCP initiatorとのやりとりを想定しており、PAXは使ってはいけないため、シーケンスからもPAX PDUがないのは正しいということになる。

Q.E.D


まあ、これで証明終わりにしてしまってもいいかもしれんが、気になることはある。

じゃあ、なんでPAX PDUなんてあるの?だ。
General Bytesにキーワードがなかった場合に使うのか、と思ったが「left to implementation」と書いてあるので、処理を終わるのだろう。

 

PAXは、PArameter eXchange、の略だ。
なので、パラメータ交換するためにあると考えると、別にシーケンスの最初だけ必要ってわけでもないか。

そう思うことにしておこう。


私は5章のシーケンスまでしか引いておらず、6章はNFC-DEPのことだろうからと、あまり気にしていなかったのだ。
まさか、Link Activationが絡んでいようとは!

NFC関係ではまった伏線では2番目のレベルであろう。
なお今のところ1番の伏線は、FeliCa Liteの片側認証演算だ。

2012/06/05

[nfc]InJumpForDEPじゃないとだめだった

CommunicateThruEXでATR_REQを送ってやればNFC-DEPを開始できるのでは、と思っていたのだが、そうもいかなかった。

PN533のドキュメントを読む限りでは、InJumpForDEPしないとDEPになることに気付かないようなのだ。

うーむ。

2012/06/03

[nfc]nfc-smart-tagが対応するタイプ

NFC-DEPの資料を作り終わったので、LLCPに着手。
まあ、今週はもう作業できそうな余裕はないがね。

LLCPなので、とりあえずnfc-smart-tagがどうやろうとしているのか見てみた。
まねはしないけど、どう扱っているのかは気になるところ。

Targetになって、LLCPを開始するところの判定を見ていったのだが、対応しているのが

  • ISO/IEC 18092 Active communication mode
  • ISO/IEC 18092 212/424kbps Passive communication mode

の2つみたい。

NFC ForumとしてはPassive communication modeしかサポートしてないって書いてた。
じゃあ、106kbps Passive communication modeは捨てたってことかしら。
うーむ。

ただ、LLCPはActiveもPassiveも気にしないだろうから、どうでもいいのかもしれん。
あるいは「NFC Forumなんか知ったことか!」なのかもしれん。
実はAndroid BeamがActive communication modeなのかもしれん。
ISO-DEPでやりたいのだ、という意思表明かもしれん。

他に理由はあるのかもしれん。
わかるのは、NFCのRF層がどう動くのかはアプリの動きからじゃさっぱりわからんから、実際のところを知りたかったらソースファイルを読むしかない(自分のも相手のも)というところか。
まだまだ先は長いなあ。

Android Beamの送信側がInitiatorでも悪くない

以前、こんな記事を書いた。

Android Beamの送信側は、たぶんターゲットになる

 

これの真偽は確認していないが、こういうのもわかった。

Androidはポーリング周期後にカードエミュレーションするのか

 

カードエミュレーションするなら、Beamの送信側がInitiatorとなっても何とかなりそうだと思った。

いかん、過去の資料も訂正しないと・・・。

 

と思ったのだが、果たして真偽はどうなのだろうか?
もし、カードエミュレーション専用モードになっているのであれば、Beam送信側がInitiatorとしてDEPを仕掛けてきたとしても「カードコマンドじゃない」ということで破棄するだろう。

私の気持ちとしては、P2P通信のためにターゲットになるのと、カードエミュレーションするのはまったく別のルートにするだろう、というところ。
P2P通信にはホスト側の動作が欠かせないが、カードエミュレーションであれば通常はホストは関与せず、SmartMXなどのNFCアプリが勝手に処理するものだと思うからだ。
だって、お金関係の処理をするのにユーザに書き換えられるかもしれないアプリが使われているとしたら、不安でしょうがないじゃないか。。。

 

そんなわけで、InitiatorとなってBeam送信するということもできるのだろうけど、たぶんやらないだろうな、という推測でいよう。
私はAndroid関係者でもNFC関係者でもないので、勝手に推測するだけだ。

DEP initiator側の記載は、ない

朝っぱらから何を調べていることやら・・・。

ともかく、DEP調査の続きだ。


RC-S620/Sコマンドリファレンスマニュアル<簡易版>を読んでいたが、ようやく確信できた。
このドキュメントには、DEPのTarget側になるための記載はあるが、Initiator側になるための記載がない。
がーん。

 

NFCIP-1を読んで、そのままNFC-DEPを実装すればいいのだけど、けっこうめんどくさい。
そのめんどくさい部分を、RC-S956なんかがうまいこと吸収してくれている。
少なくとも、ドキュメントを読む限りではTargetについてはかなりやってくれる。

例えば、NFC-DEPを開始する際にはこんなやりとりをしなくてはならない。

  1. InitiatorがSDD
  2. TargetがSDDに応答
  3. InitiatorがATR_REQ送信(NFCID3はSDD応答の結果を使う)
  4. TargetがATR_RES返信(タイムアウト時間なんかを返す)
  5. 必要があればPSL_REQ / PSL_RES
  6. DEP_REQ / DEP_RESでやりとり
    ・DEPのPDU種別(INF, ACK, NACK, ATT, RTOX)によってパラメータが変わる
    ・シーケンス番号代わりにPNIを管理

あー、めんどくさい。
このめんどくさい処理の大半を、おそらくPCDチップはさばいてくれるのだ。
Targetがここまでやるのなら、Initiatorもやってくれように思う。

 

試しに、CommunicateThruEXでATR_REQパケットを投げたら、DEP待ちにしたTargetは反応した。
だから、素のエアプロトコルでやりとりすることは、少なくとも可能なのだ。
とはいえ・・・そこまでやるほどNFC好きじゃないのだ。


nfc-smart-tagではどうやってんのかな、と思ってソースを眺めたが、やはりTargetの部分しかなかった。
たしかに、ここの図を見ても、LLCPはTargetってことになっている。
うーん、秘密なのか-。

とはいえ、Targetがここまでやる、ということがわかったので、Initiatorも同等のことをやってくれるだろう、という期待はできる。
それに、DEPのInitiatorについては実験済みなので、できないことはないと思う。
あとは、気力だな。

2012/06/02

[dep]ATR_REQの仕様をよく読んでなかった

NFCIP-1, ISO/IEC 18092, ECMA-340, JIS-X5411, NFC Forum Digital Protocol、そのどれにもATR_REQのことが書かれている。

けっこう仕様を読んでいるつもりだったが、まだまだ読み足りないようだ。

 

ATR_REQのNFCID3i(iはInitiatorのi)だが、さらっとこう書かれていた。

In Passive communication mode at 212 and 424kbps, NFCID2t shall replace NFCID3i.


なんと!
つまり、Passiveの場合は最初にポーリングしてターゲットのNFCID2がわかるから、ATR_REQ時にはそれを使ってNFCID3にするんだそうな。

NFC ForumのDigital Protocolには、14.6.2.2にそれらしき記載がある。
ATR_REQの3~10byteがNFCID2と異なったら無視せよ、と書いてあるのだが、NFCID2の前に「its」とついていた。
この「its」は、TargetのNFCID2、という意味なのだろう。
だから、InitiatorはTargetのNFCID2をNFCID3として使わなくてはならない、ということか。

 

しかしそれには、もう少し追記してほしいところがある。
それは「In Passive communication mode」の部分。
Active communication modeだったらその限りではない、のような記載が・・・。

ああ・・・
p.147のNOTEにこんな記載が。

In this version of the document, the Active Communication mode is not supported, .....

NFC ForumのDigital Protocol ver.1.0では、Passive communication modeしかサポートしていないのか。
これは、文書の最初にある「1.1 Scope」に書いてあった。
伏線が張られていたのか・・・。

 

そんなわけで、仕様書を読み返すといろいろと発見があるので、ときどき読み返さねばならんと思った。
けっこうきついんだけどね・・・。

[dep]ATR_REQから見て行く

LLCP実装に手を染めよう。
手を染める、だと悪いことをするみたいだが、そんなことはないのだ。

持っているのが、PaSoRiとRC-S620/Sしかないので、基本的にRC-S956系のことしか考えずに書いていく。


参考資料

  • NFCIP-1に相当するもの(ISO/IEC 18092とかJIS-X5211とか)
    私は、ECMA-340のが見やすいと思う。
  • RC-S620/Sコマンドリファレンスマニュアル<簡易版> Version 2.0以降

なんでECMA-340にしたかというと、PDFの見出しが付いていて見やすいから。
ISO/IEC 18092やJIS-X5211も同じ章番号なので、気にしないでおくれ。

 

LLCPは、NFC-DEPを使う。
NFC-DEPは、ISO/IEC 18092で規定されているData Exchange Protocolである。
なので、そこから見て行くことになる。

 

RC-S620/Sコマンドリファレンスマニュアルの図8-3を見ると、DEPのトリガとなるのはATR_REQと書かれている。
つまり、InitiatorからATR_REQを送信しなくてはならないことになる。

これはECMA-340でいえば、Figure 24, 25の部分だろう。

Passive communication mode(InitiatorがRFを出し、Targetは出さない)の場合、InitiatorがSDD(Single Device Detection)でターゲットを1つだけ見つけ出し、ATR_REQを送信してATR_RESを受信。

Active communication mode(InitiatorとTargetが交互に入れ替わる)の場合、ATR_RESが取得できるまでATR_REQを送信している。

つまりATR_REQのタイミングでいえば、Passiveの場合はポーリングのようなSDDが挟まるが、Activeの場合はいきなりATR_REQが来ることになる。
それが図8-3で矢印が分かれている理由である。

 

ちなみに、Figure 13でATR_REQ送信かプロプライエタリコマンド処理するかの分岐は、SEL_RESを見て決めている。
NFCID1が完全で、Transport Protocolに対応しているかどうか(TPE)、になる。


こうやって細かく書くと非常に難しそうなのだが、実装してみるとそこまで大変なことにはならない。
これは、R/W側のチップが細かいエアプロトコルをうまいこと処理しているからだろうな。

[adk]しばらく中止

5月は、FeliCa PlugとUSBでほぼ終わったような気がする。

ADKは中途半端だが、しばらく中止しよう。
途中経過のソフトだけ置いておく。FeliCa Plug、関係なし・・・。

https://github.com/hirokuma/felica_plug_adk

 

文句を言わせてもらえるなら、なんでAndroidはAAPなんてプロトコルをわざわざ作り出したんかね。。。
VID/PIDって、製品の発行元なんかを意味するんだから、そんな途中で切り替えるなんて変なことをせんほうがいいと思うったい。
なしてかねぇ。。。

 

「世の中のルール何かしらねえ、俺がルールを作る」みたいなのだろうか。
まあ、嫌なら使うな、という意味かもしれないので、中止しようというわけだ。

[adk]最初からAccessory Modeだったらどうするんだろう?

Accessory Modeに対応したAndroid端末にADK端末を接続すると、Android端末はAccessory Modeになる。

Accessory Modeにする主導権は、ADK端末側にある。
AAP(Android Accessory Protocol)を使って、Android端末とやりとりする。

私は今回、ADK側をこう作った。

  1. GET_DESCRIPTORリクエストを出して、デバイスディスクリプタを取得(18byte)。
  2. デバイスディスクリプタの中にVIDとPIDがあるので、Accessory Modeになっているときの値かどうか比較。
  3. Accessory Modeの値だったら、正常ということで処理終わり。
  4. AAP:ACCESSORY_GET_PROTOCOLリクエストを出して、プロトコルバージョンを取得(2byte)。
  5. プロトコルバージョンが0だったり、2byte取得できなかったりしたら、Accessory Mode対応外ということで終了。
  6. AAP:ACCESSORY_SEND_STRINGリクエストを出して、文字列を送信。
    ・ACCESSORY_STRING_MANUFACTURER
    ・ACCESSORY_STRING_MODEL
    ・ACCESSORY_STRING_DESCRIPTION
    ・ACCESSORY_STRING_VERSION
    ・ACCESSORY_STRING_URI
    ・ACCESSORY_STRING_SERIAL
  7. AAP:ACCESSORY_STARTリクエストを出して、Android端末にAccessory Modeになってもらう。

まあ、Android Developerに書いてある通りだ。

 

LPC2388基板ではうまくいってないけど、PCからこの制御をすると、A500側に画面が出てきた。
ACCESSORY_STRING_DESCRIPTIONで指定したアプリがないので、ACCESSORY_STRING_URIに指定してあるサイトに飛びますか?みたいな画面だった。
「はい」にすると、単にブラウザが起動してサイトに飛んでいった。
もしかするとmailtoなんかもいけるかもしれんが、試してない。


気になったのは、既にAndroid端末がAccessory Modeになっていたときだ。
説明通りだと、ACCESSORY_STRING_URIみたいな文字列を送信するタイミングがない。
これは「最初からAccessory Modeになっている端末なんかない」ということなのだろうか。

A500では、USBケーブルを外したらVID/PIDが元に戻ったので、それがトリガとなってAccessory Modeから抜けているのだろう。
だから、Android端末側がそういう風に作ってあるのなら、Accessory Modeになりっぱなしってことはないんだろう。

 

BeagleBoardとかで実際に試してみればいいんだけど、めんどくさいからやらない。

「NFCアプリ」はNFC内にあったりもする

わかりにくいタイトルになってしまった。
ときどき「NFCアプリ」という言葉を見かける。
Androidで作られたアプリだったり、パソコンとかのアプリだったりする。
しかし、そうでないこともある。
セキュアエレメントみたいな、NFCをどう使うのか、ということを決める内部的なものも「NFCアプリ」と呼ぶことがある。

ということを、今週読んだ記事で思ったのだが、どの記事かは忘れてしまった。
SmartMXはセキュアマイコン(よく知らんが)とかを持っているので、それ用のソフトもNFCアプリになるかもしれんな。

[usb]SE0はSingle Ended Zeroの略だろう

Accessory Modeにならない件についていろいろ考え込んだが、Android DeveloperにあるArduinoのADKサンプルを見て調べるのが一番よいだろう、ということになった。

 

まず、VID/PIDを切り替えるところ。
これは、AndroidAccessory.cppのswitchDevice()でやっている。
最後にACCESSORY_STARTしたあと、USBタスクの状態がUSB_DETACHED_SUBSTATE_WAIT_FOR_DEVICEになるまで待っている。

状態がUSB_DETACHED_SUBSTATE_WAIT_FOR_DEVICEになるのは、USBタスクの状態がUSB_DETACHED_SUBSTATE_INITIALIZEになったあと。

ではUSB_DETACHED_SUBSTATE_INITIALIZEになるのはどういうときかというと、VBUSの状態がSE0になったときのようだ。

 

コメントには、SE0はdisconnected、となっているが、はてさて。
USB2.0の仕様書を読むと、Assert_Single_Ended_Zeroというポートがあった。
これのようだ。D+とD-がVOLよりも小さいという条件かな。
VBUSは電源と見てよさそうだから、電源供給が断たれた?
でも、ホストだよ??

 

まったく踏み込むつもりがないところに入り込んでしまった、居心地の悪さを感じる。。
私はソフト屋さんなので、ハードが関係しそうなところとは極力距離を置いているのだ。
置いているというか、置かれているというか。。