RaspberryPi + PN532 NFC RFID module + Waveshare C プログラムを使って Mifare を読む

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


-----

「RaspberryPi + PN532 NFC RFID module + Waveshare Python プログラムを使って Mifare を読む」
https://qiita.com/nanbuwks/items/ccc5c89f8f22d7249d16

では Waveshare の PN532HAT 用ライブラリを、PN532 NFC RFID module で使ってみました。

Waveshare ライブラリは、 Arduino , Raspberry Pi , STM32 用に提供されています。Raspberry Pi 用には Python と C が用意され、先の記事は Python で試したものでした。

今回は C で試してみます。
# ライセンス

先に試した RaspberryPi 用の Python ライブラリは MIT ライセンスでしたが、その他のものは BSD ライセンスらしいです。

# 環境

- 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 3 でも同様に利用できることが確認できました。

# インストール

「RaspberryPi + PN532 NFC RFID module + Waveshare Python プログラムを使って Mifare を読む」
https://qiita.com/nanbuwks/items/ccc5c89f8f22d7249d16

の記事の通り行っています。ライブラリ自体はダウンロードして展開するだけですが、Raspberry Pi 上で C のライブラリを使うには WiringPi をインストールしておく必要がありました。以下の記事の通りインストールしています。

「WiringPi インストール方法」
https://qiita.com/nanbuwks/items/f70005772133bf54f4d3

この記事上の 「2.52のインストール」のとおり行いました。

waveshare/raspberrypi/c/examples 

には、以下のサンプルがあります。

```

-rw-r--r-- 1 pi pi  369 Jun 29  2019 Makefile
-rw-r--r-- 1 pi pi 1.9K Jul 10  2019 rpi_dump_mifare.c
-rw-r--r-- 1 pi pi 1.6K Jul 10  2019 rpi_dump_ntag2.c
-rw-r--r-- 1 pi pi 1.1K Jul 10  2019 rpi_get_uid.c
-rw-r--r-- 1 pi pi  954 Jul 10  2019 rpi_read_gpio.c
-rw-r--r-- 1 pi pi 2.7K Jul 10  2019 rpi_rw_mifare.c
-rw-r--r-- 1 pi pi 1.9K Jul 10  2019 rpi_rw_ntag2.c
-rw-r--r-- 1 pi pi 1.4K Jul 10  2019 rpi_write_gpio.c
```

make すると、

```

$ make
make: *** No rule to make target '../../pn532.c', needed by 'pn532.o'.  Stop.
```

Makefile が不適切らしいです。

```

CC = gcc
DLIBS = -lwiringPi
INC_DIR = ../../
SRCS = $(wildcard *.c)
all: $(SRCS:.c=.exe)
.PHONY: clean
%.exe: %.o pn532.o pn532_rpi.o
	$(CC) -Wall -o $@ $^ $(DLIBS)
%.o: %.c
	$(CC) -Wall -c $^ $(DLIBS) -I$(INC_DIR)
pn532.o pn532_rpi.o: $(INC_DIR)pn532.c $(INC_DIR)pn532_rpi.c
	$(CC) -Wall -c $(INC_DIR)pn532.c
	$(CC) -Wall -c $(INC_DIR)pn532_rpi.c
clean:
	rm *.o *.exe
```


となっているのを書き直します。

```

INC_DIR = ../../
```
↓

```

INC_DIR = ../
```

```

$ make
```

すると実行ファイルができました。

```

drwx------ 2 pi pi 4.0K Mar 24 14:39 .
drwx------ 3 pi pi 4.0K Mar 23 10:04 ..
-rw-r--r-- 1 pi pi  366 Mar 24 14:39 Makefile
-rw-r--r-- 1 pi pi 6.6K Mar 24 14:39 pn532.o
-rw-r--r-- 1 pi pi 7.2K Mar 24 14:39 pn532_rpi.o
-rw-r--r-- 1 pi pi 1.9K Jul 10  2019 rpi_dump_mifare.c
-rwxr-xr-x 1 pi pi  19K Mar 24 14:39 rpi_dump_mifare.exe
-rw-r--r-- 1 pi pi 1.6K Jul 10  2019 rpi_dump_ntag2.c
-rwxr-xr-x 1 pi pi  19K Mar 24 14:39 rpi_dump_ntag2.exe
-rwxr-xr-x 1 pi pi  19K Mar 22 09:15 rpi_get_uid
-rw-r--r-- 1 pi pi 1.1K Mar 22 09:11 rpi_get_uid.c
-rwxr-xr-x 1 pi pi  19K Mar 24 14:39 rpi_get_uid.exe
-rw-r--r-- 1 pi pi  954 Jul 10  2019 rpi_read_gpio.c
-rwxr-xr-x 1 pi pi  19K Mar 24 14:39 rpi_read_gpio.exe
-rw-r--r-- 1 pi pi 2.7K Mar 22 08:30 rpi_rw_mifare.c
-rwxr-xr-x 1 pi pi  23K Mar 24 14:39 rpi_rw_mifare.exe
-rw-r--r-- 1 pi pi 1.9K Jul 10  2019 rpi_rw_ntag2.c
-rwxr-xr-x 1 pi pi  23K Mar 24 14:39 rpi_rw_ntag2.exe
-rw-r--r-- 1 pi pi 1.4K Jul 10  2019 rpi_write_gpio.c
-rwxr-xr-x 1 pi pi  19K Mar 24 14:39 rpi_write_gpio.exe
```

実行ファイルが .exe となっているのが気持ち悪いですが、実行してみます。

```

$ ./rpi_rw_mifare.exe
Hello!
Failed to detect the PN532
```

と出たので、 rpi_rw_mifare.c を書き換えます。

```

    //PN532_SPI_Init(&pn532);
    PN532_I2C_Init(&pn532);
    //PN532_UART_Init(&pn532);
```
となっているのを、UARTに変更しました。

```

    //PN532_SPI_Init(&pn532);
    //PN532_I2C_Init(&pn532);
    PN532_UART_Init(&pn532);
```

UARTのポートは ../pn532_raspi.c で指定されています。

```

    fd = serialOpen("/dev/ttyS0", 115200);

```
となっているので RaspberryPi3より前のモデルを使っている場合は
/dev/ttyAMA0 に変更します。

再度make してから、実行します。


```

$ ./rpi_rw_mifare.exe
Hello!
Found PN532 with firmware version: 1.6
Waiting for RFID/NFC card...
...................................
```



```

Found card with UID: f3 3c 53 1c 
Write block 6 successfully
```

書き込めたみたいです。

# プログラム作ってみる

rpi_rw_mifare.c を書き換えて、特定のセクターをキー付きで読むプログラムを作ってみます。

```

/**
  * This example shows connecting to the PN532 and writing an Mifare Classic
  * type RFID tag
  */
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include "pn532.h"
#include "pn532_rpi.h"

int main(int argc, char** argv) {
    uint8_t buff[255];
    uint8_t uid[MIFARE_UID_MAX_LENGTH];
    uint8_t key_a[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    uint32_t pn532_error = PN532_ERROR_NONE;
    int32_t uid_len = 0;
//    printf("Hello!\n");
    PN532 pn532;
    //PN532_SPI_Init(&pn532);
    //PN532_I2C_Init(&pn532);
    PN532_UART_Init(&pn532);
    if (PN532_GetFirmwareVersion(&pn532, buff) == PN532_STATUS_OK) {
      printf("Found PN532 with firmware version: %d.%d\n", buff[1], buff[2]);
    } else {
        return -1;
    }
    PN532_SamConfiguration(&pn532);
    printf("Waiting for RFID/NFC card...\n");
    while (1)
    {

        // Check if a card is available to read
        uid_len = PN532_ReadPassiveTarget(&pn532, uid, PN532_MIFARE_ISO14443A, 1000);
        if (uid_len == PN532_STATUS_ERROR) {
            printf(".");
            fflush(stdout);
        } else {
            printf("Found card with UID: "); 
            for (uint8_t i = 0; i < uid_len; i++) {
                printf("%02x ", uid[i]);
            }
            printf("\n");
            break;
        }
    }
    //  read block #5 
    uint8_t block_number = 5;
    uint8_t DATA[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    pn532_error = PN532_MifareClassicAuthenticateBlock(&pn532, uid, uid_len,
            block_number, MIFARE_CMD_AUTH_A, key_a);
    if (pn532_error) {
        printf("Error: 0x%02x\n", pn532_error);
        return -1;
    }
    pn532_error = PN532_MifareClassicReadBlock(&pn532, DATA, block_number);
    if (pn532_error) {
        printf("Error: 0x%02x\n", pn532_error);
        return -1;
    }
    DATA[10]=0;
    printf("data= ");
    for (uint8_t i = 0; i < sizeof(DATA); i++) {
            printf("%02X ", DATA[i]);
    }
    printf("\n");
    // printf("%s\n", DATA);
}


```


コンパイルは手作業でやってみました。

```

$ cc read5withkey.c ../pn532.c ../pn532_rpi.c -I../ -lwiringPi -o read5withkey 
```

実行してみます

```
 $ ./read5withkey
Found PN532 with firmware version: 1.6
Waiting for RFID/NFC card...
....Found card with UID: 53 e6 64 1c 
data= 00 01 02 03 04 05 06 07 08 00 00 00 00 00 00 00 
```

# 感想

今回、 Python と C で使ってみましたが低レイヤのプログラムはやはりCが直感的に書けた感があります。