PN532 NFC RFID module のインターフェースを直接叩いて Felica 学生カードを読む

(Felica/Mifare/NFC チャレンジシリーズ) その他の記事はこちら 「Felica/Mifare/NFC でいろいろ実験」
https://qiita.com/nanbuwks/items/1f416d6e45a87250ee0a


----

「RaspberryPiでPN532 NFC RFID module で Felica 学生カードを読む」
https://qiita.com/nanbuwks/items/3858283873e968316a2d

では、FCF Student カードに入っている学生証の学籍番号を読んでみました。

しかしながらちょっとスッキリしないです。

```

    tag.dump() # why need?

```
を入れないと学籍番号をうまく読まなかったり、ライブラリで何のコマンドを PN532 に送信しているのかよくわからなかったりします。

さて、
「libnfc で pn53x-tamashell を使ってみる」
https://qiita.com/nanbuwks/items/d2c47f6b24ec07f48dee

において、PN532とローレベルのやり取りを行いました。これで PN532 や カードに渡すコマンドは把握できたので、直接 PN532 とやり取りするプログラムを作ってみました。


# 環境

- PN532 NFC RFID module
  - 電解コンデンサ追加加工済
  - cf., 「NFC モジュールの動作安定性を改善する」 
  - https://qiita.com/nanbuwks/items/a9217ba2e8f206b899b1
- Raspberry Pi Model B+ V1.2
  - Raspberry Pi OS Lite armhf-2020-12-04
- Python 3.7.3

通信インターフェースは シリアル接続を使い、以下の記事のように設定しています。

「Raspberry Pi で nfcpy + PN532 NFC RFID module」
https://qiita.com/nanbuwks/items/e14d8fdd6f863d5b68fe


# Pythonプログラム


```

import serial
import time


def makepredata(payload):
  predata=bytearray([0x00,0x00,0xFF])
  predata.append(len(payload))
  predata.append(256-(len(payload)))
  return(predata)
def makepostdata(payload):
  sum=0
  for i in range(len(payload)):
    sum=sum+payload[i]
  postdata=bytearray([256-(sum % 256)])
  postdata.append(0x00)
  return(postdata)

# ペイロードにプレデータ、ポストデータを追加しPN532へ送信する
def senddata(payload):
  predata=makepredata(payload)
  postdata=makepostdata(payload)
  alldata=predata+payload+postdata
  ser.write(alldata)

# PN532からの返事を受信する
def getreturn():
  result=bytearray([])
  while 1:
    time.sleep(0.01)
    result = result + ser.read_all()
    if len(result)<4:
         continue
    if ( 0x00==result[0] and 0xFF==result[1] and result[2]==256-result[3] ):
      if len(result)<result[2]+6:
         continue
    else:
      result=result[1:]
      continue
    break
#  print(result.hex())
  if  0xd5==result[4] and 0x00==result[-1] :
    # 返事のチェックサムを照合
    sum=0
    for i in result[4:-2]:
      sum=sum+i
    if (256-(sum%256))==result[-2]:
      return(result)
    else:
      return(bytearray([]))
  else:
    return(bytearray([]))


ser = serial.Serial("/dev/ttyAMA0", 115200)

# FeliCa Poll
payload=bytearray([0xD4])+bytearray([0x4A,0x01,0x01,0x00,0xFE,0x00,0x01,0x00])
senddata(payload)
#print("send:",senddata.hex())
result=getreturn()
#print(result.hex())
# get Idm
Idm=result[10:18]
print("Idm:",Idm.hex())

# FeliCa read
payload=bytearray([0xD4])+bytearray([0x40,0x01,0x14,0x06])+Idm+bytearray([0x01,0x8B,0x1A,0x03,0x80,0x00,0x80,0x02,0x80,0x03])
senddata(payload)
#print("send:",senddata.hex())
result=getreturn()
#print(result.hex())
print()
print("block 8000:",result[21:36].hex())
print("block 8002:",result[37:52].hex())
print("block 8003:",result[53:68].hex())
print()
print("block 8000:",bytes(result[21:36]))
print("block 8002:",bytes(result[37:52]))
print("block 8003:",bytes(result[53:68]))

ser.close()
                               

```

実行結果

```

Idm: 010106016702a515

block 8000: 313233343536373839303100003131
block 8002: 363031303039383736353433323130
block 8003: 303232303333313939393939393939

block 8000: b'12345678901\x00\x0011'
block 8002: b'601009876543210'
block 8003: b'022033199999999'
```
読めました

# 他の環境

今回は、Raspberry Pi とシリアル接続で行いました。
しかしながらPCやWindowsなどでも、ポート指定などの若干の変更で動くハズ。
また、SPI や I2C 対応も難しくないでしょう。