Raspberry Pi で NFC

Raspberry Pi でNFCをやってみようと思い、ebayでモジュールを購入するも不良品か、使い方が悪いのか、うまく動かず。

そこでSONYの RC-S360 を購入~

(GPIOに刺さっているケーブルは今回関係ありません。)
(今はRC-S360手に入りにくい!? 同じように使えるかわからないけど、楽天Edyリーダーが中身はRC-S360という書き込みがレヴューにありますねぇ)

ちなみにやることはRaspberryPi特有な手順ではなく、Linuxなら同じようにできるようです。
まずは準備~(´∀`)
sudo apt-get install libusb-dev
sudo apt-get install libpcsclite-dev
wget http://libnfc.googlecode.com/files/libnfc-1.7.0-rc7.tar.gz
tar zxvf filename
cd libnfc-1.7.0-rc7
./configure --with-drivers=pn53x_usb
make
sudo make install
sudo ldconfig
makeは6分ほどで完了します。
今回はUSBのリーダーを使うので configure の引数でUSBのドライバだけ有効にしています。

さっそくサンプル実行するもエラー!( ̄~ ̄;)

最近のカーネルでは標準の?ドライバがロードされてしまうみたい。
lsmodすると確かにロードされている。
/etc/modprobe.d/raspi-blacklist.conf に以下の2行を追加してロードされないようにします。
blacklist pn533
blacklist nfc
でもって再起動

プログラムを動かして以下のようなエラーが出る場合はsudoを付けるといいです。
error   libnfc.driver.pn53x_usb Unable to set USB configuration (Operation not permitted)
nfc_test: ERROR: Unable to open NFC device.
が!
ここからが長かった...(;´д`)
NFCってタグがあって、リーダーがあってプログラムがあればすんなり動くものだと思っていたらそんなことなかった...

まずは libnfc がサポートしているリーダーを使わなければなりません。
これはあらかじめ調べて RC-S360 を購入したので問題なし。

はまったのはタグの方で、いろんな種類があって種類ごとにプログラム側で読み方を変えなくてはならないのです。
最初は MIFARE Standard (Classic) というタグ(カード)で試してたんだけど認証がうまくいかず、がんばっても無理でした。(;´д⊂)
で、Androidで手持ちのタグの情報をみていると1つだけ種類が違うのに気付きました。写真の左2つが MIFARE Standard (Classic) で一番右のが MIFARE UltraLight といタグになります。
このタグは アキバ大好き!祭り で購入した物です。
MIFARE UltraLight は認証処理が必要なく、単純に読み書きする処理だけでいいのです。



今までの苦労はなんだったんだ~ヽ( ̄皿 ̄)ノ  ってくらい MIFARE UltraLight のタグだとあっさり情報の読み取りに成功しました。
しかし、問題がもう一つあります。
このタグは1枚しか持ってないので何枚か購入しようと思ったのですが、どこにも売ってない感じです。通販で1カ所あったくらいかな。
で、Google先生に聞いてみると、今はUltraLightの容量を少し増やした NTAG203 が主流のようです。記録可能容量は144バイト。



これなら八重洲のNFCショップや秋葉原のショップ、Amazonなどで購入可能です。



ということで、このタグにAndroidタブレットでNDEFのPlainTextを書き込んで読み込んでみました。


4バイトずつ読み込み先アドレスを変えつつ36回読み込むと144バイト読めます。
それを文字列として結合し、最後の行で表示しています。
「Raspberry Pi Test2」と表示されているので、うまく読み込めてますね。
前後に変なデータが付いてますがこれはおそらくNDEFのヘッダーなどと思われます。

サンプルプログラムは折りたたんでおきます。




//
// g++ -o nfc_test nfc_test.cpp -lnfc
//
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <nfc/nfc.h>

static void print_hex(const uint8_t *pbtData, const size_t szBytes)
{
    size_t szPos;

    for (szPos = 0; szPos < szBytes; szPos++) {
        printf("%02x  ", pbtData[szPos]);
    }
    printf("\n");
}

void exit_proc(nfc_context *context, nfc_device *pnd)
{
    nfc_close(pnd);
    nfc_exit(context);
}

int main(int argc, const char *argv[])
{
    nfc_context *context;
    nfc_device *pnd;
    nfc_target nt;
    uint8_t Rx[264]; // Tag response
    size_t RxLen = sizeof(Rx);
    const char *acLibnfcVersion = nfc_version();

    nfc_init(&context);

    printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
    pnd = nfc_open(context, NULL);

    if (pnd == NULL) {
        warnx("ERROR: %s", "Unable to open NFC device.");
        return EXIT_FAILURE;
    }
    if (nfc_initiator_init(pnd) < 0) {
        nfc_perror(pnd, "nfc_initiator_init");
        exit_proc(context, pnd);
        return EXIT_FAILURE;
    }

    printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));

    nfc_modulation nmMifare;
    nmMifare.nmt = NMT_ISO14443A;
    nmMifare.nbr = NBR_106;

    if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) > 0) {
        printf("The following (NFC) ISO14443A tag was found:\n");
        printf("    ATQA (SENS_RES): ");
        print_hex(nt.nti.nai.abtAtqa, 2);
        printf("       UID (NFCID%c): ", (nt.nti.nai.abtUid[0] == 0x08 ? '3' : '1'));
        print_hex(nt.nti.nai.abtUid, nt.nti.nai.szUidLen);
        printf("      SAK (SEL_RES): ");
        print_hex(&nt.nti.nai.btSak, 1);
        if (nt.nti.nai.szAtsLen) {
            printf("          ATS (ATR): ");
            print_hex(nt.nti.nai.abtAts, nt.nti.nai.szAtsLen);
        }
    }

    int ret;
    uint8_t Command[] = { 0x30, 0x04 };
    char Data[200];
    Data[0] = 0;

    for (int i = 0; i < 36; i++) {
        if ((ret = nfc_initiator_transceive_bytes(pnd, Command, sizeof(Command), Rx, RxLen, 0)) < 0) {
            fprintf(stdout, "エラー %d\n", ret);
        }
        print_hex(Rx, 4);
        Rx[4] = 0;
        strcat(Data, (char*) Rx);

        Command[1]++;
    }
    puts((char*) Data);

    exit_proc(context, pnd);
    return EXIT_SUCCESS;
}




0 件のコメント:

コメントを投稿