SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

無料のSDK for NFC Starter Kitを使ってFeliCa ICカードを読み書きするプログラムを開発する


FeliCaコマンドの発行

 後回しにしたfelicalib_nfc_thru関数について説明します。

 「SDK for NFC」の「NFCアクセスライブラリ」は、その名のとおりNFCに対応しています。つまり「FeliCa Standard」や「FeliCa Lite-S」だけでなく、「Type A (MIFARE)」や「Type B」もサポートしています。

 しかし、ポートのオープンやアクセス権の取得などの関数は共通化されているものの、いざ実際にカードの読み書きを行おうとすると、カードの規格ごとに異なるコマンド(バイナリデータ)を自分で組み立て、felicalib_nfc_thru関数の引数としてドライバに渡さなければなりません。

 FeliCa Lite-Sのコマンドの詳細は、「FeliCa Lite-Sユーザーズマニュアル」に記述があります[6]。

 コマンドには「Polling」「Write Without Encryption」「Read Without Encryption」があり、これらを使ってカードの読み書きを行うことができます。今回はS_PAD3ブロックを読み書きしてみましょう。

Pollingコマンド

 Pollingは、カードを捕捉するためのコマンドです。

 先に呼び出したfelicalib_nfc_poll_and_start_dev_accessと同等であり、省略しても動作するようですが、念のため発行しておきます。

 Pollingコマンドの構成は、次のとおりです。

Pollingコマンドパケットデータ
パラメータ名 サイズ データ 備考
コマンドコード 1 0x00 -
システムコード 2 - システムコードの指定
リクエストコード 1 - リクエストデータの指定
タイムスロット 1 - 応答可能な最大スロット数の指定
  • 「コマンドコード」は、「0x00」固定です。
  • 「システムコード」には、FeliCa Lite-S用のシステムコード「0x88B4」をビッグエンディアンで指定します。つまり、「0x88」「0xB4」になります。
  • 「リクエストコード」には、特に情報を要求しない場合、「0x00」を指定します。
  • 「タイムスロット」には、複数枚のカードを考慮しない場合、「0x00」を指定します。

 「コマンドコード」の前1バイトには、自分自身を含むデータ長をセットする必要があります。

 こうして組み立てたコマンドを、felicalib_nfc_thru関数を通して発行します。ベタ書きすると、次のようになります。

unsigned char pCom[] =
{
    0x06,       // データ長
    0x00,       // コマンドコード
    0x88, 0xB4, // システムコード
    0x00,       // リクエストコード
    0x00        // タイムスロット
};
unsigned char pRes[512];

unsigned short usComLen = 6;
unsigned short usResLen = sizeof(pRes);

bSuccess = felicalib_nfc_thru(pCom, usComLen, pRes, &usResLen);
if (! bSuccess)
{
    // エラー処理...
}

 コマンドの発行に成功すると、処理結果がレスポンスとして第3引数に格納されます。

Pollingレスポンスパケットデータ
パラメータ名 サイズ データ 備考
レスポンスコード 1 0x01 -
IDm 8 - 対象システムのIDm
PMm 8 - -
リクエストデータ 0 or 2 - リクエストコードで情報を要求した場合のみ

 「レスポンスコード」の前に、自分自身を含むデータ長が1バイト付加されるので注意してください。今回はリクエストデータを要求しなかったため、データ長は1+1+8+8=18になります。

 3バイト目から始まる「IDm」の領域には、捕捉したカードのIDmが格納されているはずです。

Write Without Encryptionコマンド

 カードへの書き込みには、「Write Without Encryption」コマンドを使います。

Write Without Encryptionコマンドパケットデータ
パラメータ名 サイズ データ 備考
コマンドコード 1 0x08 -
IDm 8 - -
サービス数 1 m m=1
サービスコードリスト 2m - リトルエンディアン
ブロック数 1 n n=1または2
ブロックリスト N - 2n≦N≦3n
ブロックデータ 16n - -
  • 「コマンドコード」は、「0x08」固定です。
  • 「IDm」には、先ほどPollingコマンドで取得した、カードのIDmを指定します。
  • 「サービス数」には、「0x01」を指定します。
  • 「サービスコードリスト」には、「0x0009」をリトルエンディアンで指定します。つまり、「0x09」「0x00」となります。サービスコード0x0009は、読み書き可能なブロックへのアクセスを意味します。
  • 「ブロック数」には、1つのブロックにのみアクセスする場合、「0x01」を指定します。
  • 「ブロックリスト」には、アクセスしたいブロックを指定します。S_PAD3ブロック、つまりブロック番号0x03にアクセスする場合は、「0x00」「0x03」「0x00」を指定してください。真ん中の「0x03」が、ブロック0x03を意味します。
  • 「ブロックデータ」には、カードに書き込むデータ羅列します。1ブロック分のデータを書き込む場合は、16バイトのデータを羅列することになります。

 なお、「コマンドコード」の前1バイトに、自分自身を含むデータ長をセットする必要があります。

 以上の書き込みコマンドをベタ書きすると、次のようになります。

unsigned char pCom[] = {
    0x21,                                           // データ長
    0x08,                                           // コマンドコード
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IDm
    0x01,                                           // サービス数
    0x09, 0x00,                                     // サービスコード
    0x01,                                           // ブロック数
    0x00, 0x03, 0x00,                               // ブロック
    'c',  'o',  'd',  'e',  'z',  'i',  'n',  'e',  // 任意のデータ
    '.',  'j',  'p',  0x00, 0x00, 0x00, 0x00, 0x00  // 任意のデータ
};

unsigned char pRes[512];

unsigned short usComLen = 0x21;
unsigned short usResLen = sizeof(pRes);

// 配列 unsigned char pIDm[8] に、
// 目的のシステムの IDm が格納されているものとする
memcpy_s(&pCom[2], sizeof(pCom) - 2, pIDm, 8);

bSuccess = felicalib_nfc_thru(pCom, usComLen, pRes, &usResLen);
if (! bSuccess)
{
    // エラー処理...
}

 書き込みは必ず16バイト単位で行われます。そのため、1バイトだけ書き変えたい場合も、当該ブロックのデータ16バイト分を読み取り、目的の1バイトを変更した後、16バイト分まとめて書き戻さなければなりません。

 コマンドの発行に成功すると、実行結果がレスポンスとして第3引数に格納されます。

Write Without Encryptionレスポンスパケットデータ
パラメータ名 サイズ データ 備考
レスポンスコード 1 0x09 -
IDm 8 - -
ステータスフラグ1 1 - 書き込み成功時は0x00
ステータスフラグ2 1 - -

 「レスポンスコード」の前に、自分自身を含むデータ長が1バイト付加されます。このコマンドの場合、データ長は12になります。

 「ステータスフラグ1」には、書き込みの成否が格納されます。成功時は「0x00」、失敗時はそれ以外の値になります。

次のページ
おわりに

修正履歴

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

小國 健(オグニ ツヨシ)

岩国市生まれ。都内在住。(株)NTTデータ勤務。金融系システムの企画・開発を担当。写真は0歳当時の自分。デバッガの解説「WinDbg. From A to Z!」もよろしくお願いします。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7402 2013/10/16 11:39

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー