2015年12月11日金曜日

SDK for NFC を使って Pasori でカード情報を読み込んでみた

概要

Pasori は Sony が提供する Ferica 用の IC カードリーダでよく目にするやつだと Edy のチャージなどに使います
SDK for NFC というこれまた Sony が提供する SDK がありこれを使うと Pasori を使っていろいろな IC カードの情報を読み込んだり書き込んだりすることができます
今回は SDK を使った簡単なサンプルを作成してみました

環境

  • Windows7 64bit
  • Felica RC-S320
  • Microsoft Visual Studio Express 2015 Community 14.0.24720.00 Update 1
  • SDK for NFC 2.0.3

Visual Studio のインストール

詳細はこちらを御覧ください
SDK for NFC に含まれる nfc 用のライブラリを使うのですが、これが .lib ファイルという形式で提供されているため Visual Studio が必要になります
自分もよくわかっていないのですが、 .lib ファイルをリンカーとして登録して実行するには普通の gcc が実行できる環境だけではダメなようです

SDK for NFC のダウンロードとインストール

ダウンロードは以下のリンクからできます
http://www.sony.co.jp/Products/felica/business/products/ICS-D004_002_003.html

sdk4nfc_starter203J.zip をダウンロードしたら解凍して、Cドライブ直下に保存します

C:\sdk4nfc_starter203J

あとは Pasori 用のドライバをインストールしましょう
SDK 内に含まれている exe ファイルを実行すれば OK です
C:\sdk4nfc_starter203J\driver\NFCPortWithDriver.exe がそれになるのでを実行してドライバをインストールしてください
ドライバをインストールしたら一度再起動したほうが良いと思います

プロジェクトの作成と各種ライブラリの追加

Visual Studio を起動してプロジェクトを作成しましょう
作成するプロジェクトの種類は「Visual C++ -> Windows -> 全般 -> 空のプロジェクト」で OK です

プロジェクトを作成したインクルードパスとリンカーの設定をしましょう

インクルードパスの設定

プロジェクトのプロパティを開きます

C/C++ -> 全般 -> 追加のインクルードディレクトリ -> 編集

で追加ダイアログを開いて

新しい行 -> 参照ボタン

で以下のパスを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\include
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\include

追加できたら OK -> 適用しましょう

リンカーの設定

プロジェクトのプロパティを開きます

リンカー -> 入力 -> 追加の依存ライブラリ -> 編集

で追加のダイアログを開いて以下のライブラリを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\lib\x86\felica.lib
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\lib\x86\felica_nfc_library.lib

追加できたら OK -> 適用でプロパティを閉じましょう

ソースファイルの追加

ソースファイルをプロジェクトに追加します

プロジェクトを右クリック -> 追加 -> 新しい項目

で追加ダイアログを開いて

Visual C++ -> C++ ファイル (.cpp) -> 追加

でソースファイルを追加しましょう
デフォルトだと Source.cpp というファイルが追加されます

追加できたら早速サンプルコードを記載しましょう
コードの全容は以下の通りです

#include <cstdio>
#include <cstdlib>

#include "felica.h"

int main(void);
void error_routine(void);
void print_vector(char* title, unsigned char* vector, int length);

int main(void)
{
    if (!initialize_library()) {
        fprintf(stderr, "Can't initialize library.\n");
        return EXIT_FAILURE;
    }
    printf("Complete initialize_library\r\n");

    if (!open_reader_writer_auto()) {
        fprintf(stderr, "Can't open reader writer.\n");
        return EXIT_FAILURE;
    }
    printf("Complete open_reader_writer_auto\r\n");

    structure_polling polling;
    unsigned char system_code[2] = { 0xFF, 0xFF };
    polling.system_code = system_code;
    polling.time_slot = 0x00;

    unsigned char number_of_cards = 0;

    structure_card_information card_information;
    unsigned char card_idm[8];
    unsigned char card_pmm[8];
    card_information.card_idm = card_idm;
    card_information.card_pmm = card_pmm;

    unsigned long timeout;
    get_polling_timeout(&timeout);
    printf("timeout: %lu\r\n", timeout);
    timeout = 2000;
    set_polling_timeout(timeout);

    if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
        fprintf(stderr, "Can't find FeliCa.\n");
        return EXIT_FAILURE;
    }

    fprintf(stdout, "number of cards: %d\n", number_of_cards);

    print_vector("card IDm:", card_idm, sizeof(card_idm));
    print_vector("card PMm:", card_pmm, sizeof(card_pmm));

    if (!close_reader_writer()) {
        fprintf(stderr, "Can't close reader writer.\n");
        return EXIT_FAILURE;
    }

    if (!dispose_library()) {
        fprintf(stderr, "Can't dispose library.\n");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

void error_routine(void) {
    enumernation_felica_error_type felica_error_type;
    enumernation_rw_error_type rw_error_type;
    get_last_error_types(&felica_error_type, &rw_error_type);
    printf("felica_error_type: %d\n", felica_error_type);
    printf("rw_error_type: %d\n", rw_error_type);

    close_reader_writer();
    dispose_library();
}

void print_vector(char* title, unsigned char* vector, int length) {
    if (title != NULL) {
        fprintf(stdout, "%s ", title);
    }

    int i;
    for (i = 0; i < length - 1; i++) {
        fprintf(stdout, "%02x ", vector[i]);
    }
    fprintf(stdout, "%02x", vector[length - 1]);
    fprintf(stdout, "\n");
}

SDK に含まれているサンプルのソースコードをほぼ流用しています
C:\sdk4nfc_starter203J\sample\FeliCa_Library\sample_06.cpp

サンプルコードの説明

以下ポイントを説明していきます

main メソッドの一番初めで NFC ライブラリの初期化をしています

if (!initialize_library()) {
    fprintf(stderr, "Can't initialize library.\n");
    return EXIT_FAILURE;
}

初期化が完了したら接続されている Pasori をオープンします
なので、これを実行するときに Pasori がパソコンに接続されて、正常に動作する状態になっている必要があります

if (!open_reader_writer_auto()) {
    fprintf(stderr, "Can't open reader writer.\n");
    return EXIT_FAILURE;
}

もし、Pasori が接続されていなかったりドライバインストールされていなくてうまく動作しない場合はここでエラーになります

カードのスキャンをスタートする前に Pasori がスキャンする時間を設定してます

unsigned long timeout;
get_polling_timeout(&timeout);
printf("timeout: %lu\r\n", timeout);
timeout = 2000;
set_polling_timeout(timeout);

デフォルトだと 100 ms しかスキャンしないので、カードを乗せた状態で実行しないと検知してくれません
なので、今回は少しスキャンに余裕を持たせて 2 秒間スキャンするようにしました

このあとでスキャンを開始します

if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
    fprintf(stderr, "Can't find FeliCa.\n");
    return EXIT_FAILURE;
}

スキャンに成功してカードの情報が取得できると引数として渡している card_information に値が設定されます

それをその後で参照します

print_vector("card IDm:", card_idm, sizeof(card_idm));
print_vector("card PMm:", card_pmm, sizeof(card_pmm));

最後に処理が完了したので終了処理をしています

if (!close_reader_writer()) {
    fprintf(stderr, "Can't close reader writer.\n");
    return EXIT_FAILURE;
}

if (!dispose_library()) {
    fprintf(stderr, "Can't dispose library.\n");
    return EXIT_FAILURE;
}

このあたりでコールしている関数の詳細は SDK に付属の pdf を参照するといいと思います
C:\Users\username\Downloads\sdk4nfc_starter203J\sdk4nfc_starter203J\doc\FeliCa_Library\M735_FeliCaLibrary_StarterKit_1.3j.pdf

ビルドして実際に試してみる

ソースを記載したビルドしましょう
プロジェクトを選択した状態で

ビルド -> ソリューションのビルド

でビルドが成功すれば OK です
失敗する場合はインクルードパストリンカーの設定を再度見なおしてください
今回の場合だと大抵はライブラリの読み込みに失敗してビルドが失敗します

コマンドプロンプトを開いて実際に実行してみましょう
実行するまでに Pasori を PC に接続してください

C:\Users\username\Documents\Visual Studio 2015\Projects\Project2\Debug>Project2.exe

で Pasori のスキャンがはじまります
今回はスキャンが 2 秒なのであらかじめ IC カードを置いておくといいと思います
スキャンに成功するとカードの IDm という識別番号が表示されると思います

自分は Pasumo がうまくスキャンできて IDm が取得できることは確認しました

最後に

今回スキャンして IDm を表示するとこまでやってみました
Pasumo の場合は乗車履歴とかも書き込まれているようで、それも取得できるみたいなので、次はそこまでやってみたいです
あとは、読み込みだけじゃなくて IC カードへの書き込みもやってみたいなと思います

ライブラリにはもう一つ lite 版というのがあり、関数とかの先頭に「felica_」がついた版があります
自分は初め lite 版を使っていたのですが、どうしても「 felicalib_nfc_open」で Pasori をオープンするところでこけてしまい、lite 版をあきらめました
これは予想ですが、Pasori のバージョンが RC-S320 というだいぶ古いバージョンを使っていたので失敗したのかもしれません
S370 や S380 という比較的新しいバージョンの Pasori を使えば lite 版でも動作するかもしれません

0 件のコメント:

コメントを投稿