RC-S320とLinuxでFelicaのIDmを読み出す
SONY純正のFelica reader/writerのPasoriの中でもかなり初期のモデルにあたるRC-S320を入手していました。取り急ぎ使用する必要性も無かったので長いこと放置してるうちに、対応するWindows版ソフトウェア(NFCポートソフトウェア Version 5.4.8.6)は提供終了になっていました。
ソニー株式会社 | FeliCa | 個人のお客様 | サポート・ダウンロード | 基本ソフトウェア | NFCポートソフトウェア Version 5.4.8.6
そんなわけで、Linuxでの使用を試みました(本投稿に記載の情報は2023年6月時点のものです)。使用するための準備から、C言語による自作プログラムでのID読み出しまでを記載します。
USB接続
とりあえず、何も考えずにUSBポートにRC-S320を挿してみたところ、dmesgに以下の出力が確認できました。
[ 22.919334] usb 1-2: new low-speed USB device number 5 using xhci_hcd [ 23.073295] usb 1-2: New USB device found, idVendor=054c, idProduct=01bb, bcdDevice= 1.28 [ 23.073301] usb 1-2: New USB device strings: Mfr=0, Product=0, SerialNumber=0
単に接続されただけで、特にドライバモジュールが読まれているような挙動は確認できません。
lsusbでこのデバイス(idVendor=054c, idProduct=01bb)の詳細を確認してみると以下の通りでした。
$ lsusb -v -d 054c:01bb Bus 001 Device 005: ID 054c:01bb Sony Corp. FeliCa S320 [PaSoRi] Couldn't open device, some information will be missing Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x054c Sony Corp. idProduct 0x01bb FeliCa S320 [PaSoRi] bcdDevice 1.28 iManufacturer 0 iProduct 0 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0019 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 10
特に興味深い情報は無さそうですが、バスパワーでも最大100mAしか消費しないことが判りますので、RaspberryPiなど電力供給能力が心もとない機器と組み合わせても不安は少なそうです。
ここまでで、ハードウェアとしては認識されていることが確認できていますが、当然ながらソフトウェアが無ければPasoriを使ってFelicaにアクセスすることはできません。調べてみるとlibpafeというライブラリを使うとRC-S320をLinuxで使うことが出来そうです。
libpafeインストール
libpafeは下記リポジトリで公開されています。
github.com
最終更新が12年前の2011年で止まっていますので、そのまま動くのか不安がありましたが、最低限の知識があれば今でも使用可能です。
READMEにインストール手順が載っていますので、(基本的には)ほぼその通り作業しました。
# download source code $ git clone https://github.com/rfujita/libpafe # configure $ cd libpafe $ ./configure # make (multi-thread) $ make -j4 # install (require sudo) $ sudo make install
最後のmake install中に、以下の出力が含まれています。このmakeスクリプトでは/usr/local/libに出来上がったlibpafeのバイナリをデプロイしてくれるのですが、ここに置いたライブラリをリンクするには、例示されてるような手段でライブラリのパスを指定してあげる必要があるよと言ってるようです(後述)。
Libraries have been installed in:
/usr/local/libIf you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
udev設定
READMEの指示通り、/etc/udev/pasori.rulesを以下の内容で作成します(要sudo)。
ACTION!="add", GOTO="pasori_rules_end" SUBSYSTEM=="usb_device", GOTO="pasori_rules_start" SUBSYSTEM!="usb", GOTO="pasori_rules_end" LABEL="pasori_rules_start" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="01bb", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev" LABEL="pasori_rules_end"
※RC-S320で使用するだけならidProduct=02e1の行(恐らくRC-S330)は無くても問題無いはずです。
同様にREADMEの指示のように/etc/udev/rules.dにシンボリックリンクを貼った後に設定を反映します(要sudo)。
cd /etc/udev/rules.d sudo ln -s ../pasori.rules 010_pasori.rules sudo udevadm control --reload-rules
※RC-S320を既にUSBポートに接続している場合は一旦抜いて接続し直しましょう。reload-rulesしても接続し直すまでは反映されません。
動作確認
libpafe/testsに2つサンプルプログラム(pasori_testとfelica_dump)が有るので実行してみましょう。
pasori_testはここまでの手順に問題が無ければ以下のような出力が得られるはずです。
$ ./pasori_test PaSoRi (RC-S320) firmware version 1.40 Echo test... success EPROM test... success RAM test... success CPU test... success Polling test... success
もし、
$ ./pasori_test error
となった場合はsudoして実行してみてください。sudoでsuccess表示に変わった場合、udev周りの設定をどこか間違えていますので確認してください。
felica_dumpはタイムアウトでエラーにならないように予めPasoriにSuicaやおサイフケータイのようなFelicaを載せた状態で実行しましょう。すると以下のような出力が得られます。
$ ./felica_dump # lpdump : Fri Jun 16 19:52:58 2023 # --- IDm info (FeliCa) --- # Manufacture Date = 2015/7/30 # SN = **** # Manufacture Code = 0101 # Equip. Code = 0108 system num 3 # FELICA SYSTEM_CODE = 0003 # card IDm = **************** # card PMm = **************** # area num = 8 # service num = 50 ~以下略。一部の値は*で投稿用にマスクしています。~
ここまでで無事にPasoriでFelicaにアクセスできていることが確認できました。
次は自作プログラムでFelicaのIDを読み出してみましょう。
IDmを読み出す
前提として個々のFelica毎に異なる8byteのIDがIDmと呼ばれています。この値は製造時に設定され変更することができないユニークな値です。このため、IDmとユーザーを予め紐づけておくことで、例えば出欠確認のようなアプリケーションができます。というわけで、野良FelicaアプリではIDmの読み出しが主な目的となることが多いようです。
ここではIDmを読み出して表示するだけの簡単なプログラムをCで書いてみましょう。libpafeのREADMEに関数リファレンスが載ってますので、IDmを読み出す関数はfelica_get_idm()であることが判ります。これを叩くための最小限のコードの実装例は以下のようになります。やってることはPasoriを開いて初期化した後、ポーリングしてFelica情報を得てIDmを取り出して表示、最後に後始末といった感じです。
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "libpafe.h" int main(void){ int ret_code = EXIT_SUCCESS; pasori *psr; felica *flc; uint8_t *idm; // Memmory allocation for IDm idm = (uint8_t*) malloc(FELICA_IDM_LENGTH); if(idm == NULL){ fprintf(stderr, "Memory allocation error\n"); return EXIT_FAILURE; } // Open pasori psr = pasori_open(); if(psr == NULL){ fprintf(stderr, "Failed to open pasori\n"); return EXIT_FAILURE; } // Initialize pasori if(pasori_init(psr) != 0){ fprintf(stderr, "Failed to initialize pasori\n"); ret_code = EXIT_FAILURE; } else{ // Polling flc = felica_polling(psr, FELICA_POLLING_ANY, 0, 0); if(flc == NULL){ fprintf(stderr, "Failed to polling\n"); ret_code = EXIT_FAILURE; } else{ // Get IDm if(felica_get_idm(flc, idm) != 0){ fprintf(stderr, "Failed to get IDm\n"); ret_code = EXIT_FAILURE; } else{ fprintf(stdout, "IDm: "); for(int i=0; i<FELICA_IDM_LENGTH; i++){ fprintf(stdout, "%02X", *(idm+i)); } fprintf(stdout, "\n"); } } } // Free the memory free(idm); if(flc != NULL) free(flc); // Close pasori pasori_close(psr); return ret_code; }
このソースコードをreadIDm.cとしてコンパイルを試みると、恐らくlibpafe.hが見つからないとエラーが発生するはずです。
libpafeをmake installしたときのmakeスクリプトを見るとヘッダファイルは/usr/local/include/libpafe/にデプロイされていますので、以下のように明示的に指定してコンパイルしてみましょう。
gcc ./readIDm.c -I/usr/local/include/libpafe/ -lpafe -Wall -o readIDm
今度はコンパイルできたと思いますが、実行してみるとライブラリが見つからないとエラーが発生するはずです。libpafeをmake installしたときに現れたメッセージに書かれていたように、ライブラリのパスを明示する必要がありますので、以下のように指定してコンパイル(リンク)しなおしてみましょう。
gcc ./readIDm.c -I/usr/local/include/libpafe/ -Wl,-rpath /usr/local/lib -lpafe -Wall -o readIDm
これで出来たバイナリをPasoriにFelicaを載せて実行してみると16桁(8byteの16進数表現)のIDmが標準出力に出力されるはずです。そしてその値はlibpafeに同梱のサンプルプログラムのfelica_dumpの出力に含まれる最初のIDmの値と同一となっていればlibpafeを使用した自作プログラムで正常にIDmが読み出せていると判断できます。
libpafeを使用すれば、このような100行にも満たない比較的小さなコードで容易にIDmを読み出すことができると解りました。*1
以上。