👋

I-O DataのNFCリーダライタ ぴタッチ(USB-NFC3)にMac上のUnityでNFCカードのUIDを読み取る

2023/08/18に公開

1. 概要

以下の記事の続き。接続するところまでできたので、カードの情報を読み取る。
https://zenn.dev/yuji_miyano/articles/f44261f2c578fd

2. 環境

3. 方法

3.1 タッチしたかどうかを判定する

以下を参考にした。
https://github.com/danm-de/pcsc-sharp#monitor-reader-events

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PCSC;
using PCSC.Monitoring;

public class SimpleRead : MonoBehaviour
{
    string readerName;
    ISCardMonitor monitor;

    void Start()
    {
        var contextFactory = ContextFactory.Instance;
        using (var context = contextFactory.Establish(SCardScope.System)) {
            Debug.Log("Currently connected readers: ");
            var readerNames = context.GetReaders();
            foreach (var readerName in readerNames) {
                Debug.Log("\t" + readerName);
            }
            readerName = readerNames[0];
        }

        var monitorFactory = MonitorFactory.Instance;
        monitor = monitorFactory.Create(SCardScope.System);

        // connect events here..
        monitor.StatusChanged += (sender, args) =>
            Debug.Log($"New state: {args.NewState}");

        monitor.Start(readerName);

    }
    
    void OnApplicationQuit()
    {
        monitor.Cancel();
        monitor.Dispose();
    }

実行するとこんな感じ。NFCカードを検出するとNew state: Present、カードが離れるとNew state: Emptyが表示される。

monitor.Cancel();monitor.Dispose();がないと終了後にフリーズすることがある気がする。

3.2 タッチされたカードの情報を取得する

以下の記事を参考にしました。
https://qiita.com/mindwood/items/103fc0fb52bca7773e47

上記の記事でもPCSC-Sharpのサンプルを参考にしてあったので、カードを検出した後の挙動は基本的にはこちらのサンプルをベースにしました。
https://github.com/danm-de/pcsc-sharp/blob/master/Examples/ISO7816-4/Transmit/Program.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PCSC;
using PCSC.Monitoring;
using PCSC.Iso7816;
using System;       // BitConverterを使う

public class ReadCardInfo : MonoBehaviour
{
    string readerName;
    ISCardMonitor monitor;

    void Start()
    {
        var contextFactory = ContextFactory.Instance;
        // using (var context = contextFactory.Establish(SCardScope.System)) {
        using (var context = contextFactory.Establish(SCardScope.System)) {
            Debug.Log("Currently connected readers: ");
            var readerNames = context.GetReaders();
            foreach (var readerName in readerNames) {
                Debug.Log("\t" + readerName);
            }
            readerName = readerNames[0];
        }

        var monitorFactory = MonitorFactory.Instance;
        // var monitor = monitorFactory.Create(SCardScope.System);
        monitor = monitorFactory.Create(SCardScope.System);

        // connect events here..
        monitor.StatusChanged += (sender, args) => {
            Debug.Log($"New state: {args.NewState}");
            if( args.NewState == SCRState.Present)
            {
                ReadData();
            }
        };

        monitor.Start(readerName);
    }

    // read data
    private void ReadData() {

        using (var context = ContextFactory.Instance.Establish(SCardScope.System)) {
            using (var rfidReader = context.ConnectReader(readerName, SCardShareMode.Shared, SCardProtocol.Any)) {
                var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.Protocol) {
                    CLA = 0xFF,
                    Instruction = InstructionCode.GetData,
                    P1 = 0x00,
                    P2 = 0x00,
                    Le = 0 // We don't know the ID tag size
                };

                using (rfidReader.Transaction(SCardReaderDisposition.Leave)) {
                    Console.WriteLine("Retrieving the UID .... ");

                    var sendPci = SCardPCI.GetPci(rfidReader.Protocol);
                    var receivePci = new SCardPCI(); // IO returned protocol control information.

                    var receiveBuffer = new byte[256];
                    var command = apdu.ToArray();

                    var bytesReceived = rfidReader.Transmit(
                        sendPci, // Protocol Control Information (T0, T1 or Raw)
                        command, // command APDU
                        command.Length,
                        receivePci, // returning Protocol Control Information
                        receiveBuffer,
                        receiveBuffer.Length); // data buffer

                    var responseApdu =
                        new ResponseApdu(receiveBuffer, bytesReceived, IsoCase.Case2Short, rfidReader.Protocol);
                    Debug.Log(string.Format("SW1: {0:X2}, SW2: {1:X2}\nUid: {2}",
                        responseApdu.SW1,
                        responseApdu.SW2,
                        responseApdu.HasData ? BitConverter.ToString(responseApdu.GetData()) : "No uid received"));
                }
            }
        }
    }

    void OnApplicationQuit()
    {
        monitor.Cancel();
        monitor.Dispose();
    }
}

全然理解していないが、とりあえずカードのUIDが読み取れた。

Discussion