1. Imagawayaki

    Posted

    Imagawayaki
Changes in title
+PythonでSuicaの残高を取得する(libpafe使用)
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,180 @@
+# PythonでSuicaの残高を取得する(libpafe使用)
+
+* 手元に中古で買ったFelicaリーダのRC-S320があったので,Pythonを使って動かせないか試してみた.
+* ちょっとした備忘録的なメモです.
+* そのうちRaspberry piとかで何かと組み合わせてみる予定.
+
+## 動作環境
+* OS: LMDE 2 Betsy
+* FeliCaリーダ: Sony RC-S320
+* Pythonのバージョン: 2.7.9
+
+## ライブラリ
+* [nfcpy](http://nfcpy.readthedocs.io/en/latest/index.html)の存在を知ったが,RC-S320には対応していない.
+* [libpafe](https://github.com/rfujita/libpafe)が対応していた.
+ * C言語のライブラリとして使える.
+ * Ruby上なら[libpafe-ruby](http://hito.music.coocan.jp/pasori/libpafe-ruby.html)が使える.
+
+## 環境設定
+1. libusbのインストール
+ * `$ sudo apt-get install libusb-dev`
+2. GitHubからlibpafeをcloneする
+ * `$ git clone https://github.com/rfujita/libpafe.git`
+3. コンパイル&インストール
+
+ ```
+ $ cd libpafe
+ $ ./configure
+ $ make
+ $ sudo make install
+ ```
+4. 動作確認
+
+ ```
+ $ cd libpafe
+ $ ./tests/pasori_test
+ PaSoRi (RC-S320)
+ firmware version 1.40
+ Echo test... success
+ EPROM test... success
+ RAM test... success
+ CPU test... success
+ Polling test... success
+ ```
+
+5. udevの設定
+ * 60-libpafe.rulesを作成
+ `$ sudo vi /lib/udev/rules.d/60-libpafe.rules`
+ * 以下の内容を記述
+
+ ```60-libpafe.rules
+ 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"
+ ```
+ * `$ sudo udevadm control --reload-rules`を実行
+ * `$ sudo reboot`で再起動する.
+
+
+## ICカードのIDmを取得する
+* ひとまずICカードのIDmを取得してみる.
+ [raspberrypiでFeliCaのIDmを読み取る(pasori RC-S320版)](http://qiita.com/t114/items/819a9cdfe90ea98dd4d3)
+
+ [Raspberry Pi + libpafe + Python + ctypesで、FeliCaのIDmを読む](http://thinkami.hatenablog.com/entry/2015/06/16/212600)
+(ほぼこちらに載せられていたものを参考にしています)
+
+```python:read_idm.py
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+from ctypes import *
+
+# libpafe.hの77行目で定義
+FELICA_POLLING_ANY = 0xffff
+
+if __name__ == '__main__':
+
+ libpafe = cdll.LoadLibrary("/usr/local/lib/libpafe.so")
+
+ libpafe.pasori_open.restype = c_void_p
+ pasori = libpafe.pasori_open()
+
+ libpafe.pasori_init(pasori)
+
+ libpafe.felica_polling.restype = c_void_p
+ felica = libpafe.felica_polling(pasori, FELICA_POLLING_ANY, 0, 0)
+
+ idm = c_ulonglong()
+ libpafe.felica_get_idm.restype = c_void_p
+ libpafe.felica_get_idm(felica, byref(idm))
+
+ # IDmは16進表記
+ print("IDm:", "%016X" % idm.value)
+
+ # READMEより、felica_polling()使用後はfree()を使う
+ # なお、freeは自動的にライブラリに入っているもよう
+ libpafe.free(felica)
+
+ libpafe.pasori_close(pasori)
+```
+
+* libpafeはC言語用のライブラリだが,Pythonのctypesを使うことでC言語の関数がPython上で使えるようになる.
+ * felica_get_idmを使う.
+ * `int felica_get_idm(felica *f, uint8 *idm);`
+ * f : felica_pollingで取得したfelica型のポインタ
+ * idm : IDmを格納するためのポインタ
+
+## Suicaの残高を取得する
+* Suicaの残高を表示するのはどうやるか?
+ * ICカード内の情報を取ってきて,その中から残高の情報を拾ってくる必要がある
+ * Suicaのデータ構造まとめ: [suica - FeliCa Library Wiki - FeliCa Library - OSDN](https://ja.osdn.net/projects/felicalib/wiki/suica)
+ * 10-11のあたりのデータを取ってくれば良さそう.
+
+* libpafeのfelica_readという関数で諸々の情報を取ってくることができるので,それを使う.
+参考: [続けるブログ: ラズベリーパイがICカードの残高をしゃべるよ](http://continue-to-challenge.blogspot.jp/2014/11/ic.html)
+ * ↑こちらはC言語で書かれているため,ctypesを使ってPython上でfelica_readを呼び出せるように書き換える
+ * 引数が構造体のポインタを示していたりするので,あらかじめ定義して調整する
+
+```python:read_balance.py
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+from ctypes import *
+
+# libpafe.hの77行目で定義
+FELICA_POLLING_ANY = 0xffff
+
+# 構造体の代わりとなるクラスの定義
+class felica_block_info(Structure):
+ _fields_ = [
+ ("service", c_uint16),
+ ("mode", c_uint8),
+ ("block", c_uint16)
+ ]
+
+if __name__ == '__main__':
+
+ libpafe = cdll.LoadLibrary("/usr/local/lib/libpafe.so")
+
+ libpafe.pasori_open.restype = c_void_p
+ pasori = libpafe.pasori_open()
+
+ libpafe.pasori_init(pasori)
+
+ libpafe.felica_polling.restype = c_void_p
+ felica = libpafe.felica_polling(pasori, FELICA_POLLING_ANY, 0, 0)
+
+ # Cのint型配列の定義(長さ16)
+ int_array16 = c_uint8 * 16
+
+ # 応答データ
+ data = int_array16()
+ # サービスコードのリスト
+ info = felica_block_info(c_uint16(0x090f), c_uint8(0), c_uint16(0))
+ for i in range(0, 32):
+ c_i = c_int(i)
+ libpafe.felica_read(felica, byref(c_i), byref(info), byref(data))
+ if (data[1] > 0) or (data[2] > 0):
+ print("残高:", data[11] * 256 + data[10], "円")
+ break
+
+ libpafe.free(felica)
+
+ libpafe.pasori_close(pasori)
+
+```
+
+* 同じ構造になっているからか,ICOCAとtoicaでもちゃんと使えた.
+
+## 参考
+* [raspberrypiでFeliCaのIDmを読み取る(pasori RC-S320版)](http://qiita.com/t114/items/819a9cdfe90ea98dd4d3)
+* [Raspberry Pi + libpafe + Python + ctypesで、FeliCaのIDmを読む](http://thinkami.hatenablog.com/entry/2015/06/16/212600)
+* [suica - FeliCa Library Wiki - FeliCa Library - OSDN](https://ja.osdn.net/projects/felicalib/wiki/suica)
+* [ラズベリーパイがICカードの残高をしゃべるよ](http://continue-to-challenge.blogspot.jp/2014/11/ic.html)
+* [ctypes 〜pythonでCをイジる(Macで)〜 - カールヌードル](http://curlnoodle.hatenablog.com/entry/2013/12/30/221858)