トップ 新規 編集 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

Javaの応用:Felicaカードリーダ

 標準ライブラリによって読み取る例

Java SDK 1.6以降に追加されたsmartcardioによって外部ライブラリを用いず、標準クラスライブラリのみによってFelicaカード等のIDmを読み取る例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package sample.nfc;

import javax.smartcardio.Card;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import javax.xml.bind.DatatypeConverter;

public class SmartCardReader implements Runnable {
    private CardTerminal terminal;
    private Card card;
    private static byte[] readUID = { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x04 };    //IDmを読むための?
    public SmartCardReader() {
        try {
            terminal = TerminalFactory.getDefault().terminals().list().get(0);    //一台目を決め打ち
        } catch (CardException e) {
            System.err.println("読み取り機を取得できませんでした");
            System.exit(-1);
        }
    }
    public String readIDm() throws CardException{
        try {
            card = terminal.connect("*");
            ResponseAPDU response = card.getBasicChannel().transmit(new CommandAPDU(readUID));
            return DatatypeConverter.printHexBinary(response.getData());    //byte[]を文字列に変換
        } finally {
            card.disconnect(false);    //例外が発生してもとりあえず接続を切る
        }
    }
    @Override
    public void run() {
        //カードが置かれて、取られるまでの一連をひとまとめにしているが、感度により、一つのカードについて短期間に連続して起こる可能性があることを想定すべき
        while(true) {
            try {
                terminal.waitForCardPresent(0);
                System.out.println(readIDm());
                terminal.waitForCardAbsent(0);
            } catch (CardException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        //無限ループスレッドでカードが置かれた時にIDmを表示するアプリケーション
        Thread thread = new Thread(new SmartCardReader());
        thread.start();
    }
}

 Felicaカードリーダ


Felicaクラス

  • felicalib.dllのラッパー(wrapper)クラス。
  • 下の例に必要な部分のみしか実装していない。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package felica;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public class Felica {
    final public static short WILDCARD = (short) 0xFFFF;        // ワイルドカード
    final public static short SUICA = 0x03;
    public interface FelicaLib extends Library {
        FelicaLib INSTANCE = (FelicaLib) Native.loadLibrary("felicalib",
                FelicaLib.class);
        Pointer pasori_open(String dummy);
        int pasori_init(Pointer pasoriHandle);
        void pasori_close(Pointer pasoriHandle);
        Pointer felica_polling(Pointer pasoriHandle, short systemCode, byte rfu, byte time_slot);
        void felica_free(Pointer felicaHandle);
        void felica_getidm(Pointer felicaHandle, byte[] data);
        void felica_getpmm(Pointer felicaHandle, byte[] data);
        int felica_read_without_encryption02(Pointer felicaHandle, int serviceCode, int mode, byte addr, byte[] data);
    }
    @SuppressWarnings("serial")
    public class FelicaException extends Exception{
        public FelicaException(String string) {
            super(string);
        }
    }
    Pointer pasoriHandle;
    Pointer felicaHandle;
    /**
     * コンストラクタ。ここでFelicaカードリーダへのハンドルを取得している
     * @throws FelicaException
     */
    public Felica() throws FelicaException {
        pasoriHandle = FelicaLib.INSTANCE.pasori_open(null);
        if(pasoriHandle==null) {
            throw new FelicaException("felicalib.dllを開けません");
        }
        if(FelicaLib.INSTANCE.pasori_init(pasoriHandle)!=0) {
            throw new FelicaException("PaSoRiに接続できません");
        }
    }
    /**
     * Felicaカードリーダに関する処理を終了するさいに呼ぶメソッド
     */
    public void close(){
        if(felicaHandle!=Pointer.NULL) {
            FelicaLib.INSTANCE.felica_free(felicaHandle);
        }
        if(pasoriHandle!=Pointer.NULL) {
            FelicaLib.INSTANCE.pasori_close(pasoriHandle);
        }
    }
    public void polling(short systemCode) throws FelicaException{
        FelicaLib.INSTANCE.felica_free(felicaHandle);
        felicaHandle = FelicaLib.INSTANCE.felica_polling(pasoriHandle, systemCode, (byte)0, (byte)0);
        if(felicaHandle==Pointer.NULL) {
            throw new FelicaException("カード読み取り失敗");
        }
    }
    public byte[] getIDm() throws FelicaException{
        if(felicaHandle==Pointer.NULL) {
            throw new FelicaException("no polling executed.");
        }
        byte[] buf = new byte[8];
        FelicaLib.INSTANCE.felica_getidm(felicaHandle, buf);
        return buf;
    }
    
    /**
     * FelicaカードのID番号を取得するメソッド
     * @param systemCode システムコード(例えばSuicaは0x03、ワイルドカードは0xFF)
     * @return カードのID番号?
     * @throws FelicaException
     */
    public String getID(short systemCode) throws FelicaException {
        FelicaLib.INSTANCE.felica_free(felicaHandle);
        felicaHandle = FelicaLib.INSTANCE.felica_polling(pasoriHandle, systemCode, (byte)0, (byte)0);
        if(felicaHandle==Pointer.NULL) {
            throw new FelicaException("カード読み取り失敗");
        }
        byte[] buf = new byte[8];
        FelicaLib.INSTANCE.felica_getidm(felicaHandle, buf);
        return String.format("%02X%02X%02X%02X%02X%02X%02X%02X", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
    }
    /**
     * メイン関数。これだけで読み取りテストを行うことができるように50秒間読み取りを試みる
     * @param args コマンドラインオプション
     * @throws FelicaException
     */
    public static void main(String[] args) throws FelicaException {
        Felica felica = new Felica();
        for(int i=0;i<10;i++) {
            try {
                System.out.println(i+":"+felica.getID((short)0xFF));
            } catch (FelicaException e) {    //読み取れなかったらそのまま
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        felica.close();
    }
}

FelicaIdReaderクラス

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package felica;

import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;

import felica.Felica.FelicaException;

@SuppressWarnings("serial")
public class FelicaIdReader extends JFrame {
    private Felica felica;
    private JLabel label = new JLabel("ID=????????????????");
    boolean active = true;

    public FelicaIdReader() {
        super("フェリカカードリーダ");
        try {
            felica = new Felica();
        } catch (FelicaException e) {
            System.err.println("フェリカカードリーダにアクセスできません");
            System.exit(-1);
        }
        // 終了時処理の追加
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                active = false;
                synchronized (felica) {
                    felica.close();
                }
                System.exit(0);
            }
        });
        add(label);
        pack();
        // IDが全部表示されないこともあるため、幅を変更する
        Dimension dim = getPreferredSize();
        if (dim.getWidth() < 200) {
            setPreferredSize(new Dimension(200, (int) dim.getHeight()));
            pack();
        }
        setVisible(true);
        // Felicaカードの読み取りループ
        String Id = null;
        while (active) {
            try {
                Id = felica.getID(Felica.WILDCARD);
            } catch (FelicaException e) {
                Id = null;
            }
            if (Id != null) {
                label.setText("id=" + Id);
            } else {
                label.setText("現在カードは置かれていません");
            }
            try {
                Thread.sleep(500); // 0.5秒おきに読み取り
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new FelicaIdReader();
    }
}

 参考文献

ライブラリ

ソフト

情報源

Java Native Access

Felica.java FelicaIdReader.java SmartCardReader.java chrome_material_200_percent.pak

最終更新時間:2016年07月21日 22時56分29秒