#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

#define DEV_PATH "/dev/nfc_dev"
#define BUF_SIZE 256

static void print_timestamp(void)
{
    struct timespec ts;
    struct tm tm;
    clock_gettime(CLOCK_REALTIME, &ts);
    localtime_r(&ts.tv_sec, &tm);
    printf("[%02d:%02d:%02d.%03ld] ",
           tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec / 1000000);
}

int main(int argc, char *argv[])
{
    const char *dev = (argc > 1) ? argv[1] : DEV_PATH;
    int fd = open(dev, O_RDONLY);
    if (fd < 0) {
        fprintf(stderr, "open %s failed: %s\n", dev, strerror(errno));
        return 1;
    }

    printf("NFC test started on %s, waiting for card...\n", dev);

    unsigned char buf[BUF_SIZE];
    while (1) {
        ssize_t n = read(fd, buf, sizeof(buf));
        if (n < 0) {
            fprintf(stderr, "read error: %s\n", strerror(errno));
            usleep(200000);
            continue;
        }
        if (n < 4) {
            printf("short read: %zd bytes\n", n);
            continue;
        }

        unsigned char datatype = buf[0];
        unsigned char status   = buf[1];
        int dataLen = ((int)buf[2] << 8) | buf[3];
        if (n < 4 + dataLen)
            dataLen = (int)(n - 4);

        unsigned char *data = &buf[4];

        print_timestamp();
        switch (datatype) {
        case 1:
            if (dataLen >= 2)
                printf("ATQA  (type=1 status=%d len=%d): %02X %02X\n",
                       status, dataLen, data[0], data[1]);
            else
                printf("ATQA  (type=1 status=%d len=%d)\n", status, dataLen);
            break;
        case 2:
            if (dataLen >= 1)
                printf("SAK   (type=2 status=%d len=%d): %02X\n",
                       status, dataLen, data[0]);
            else
                printf("SAK   (type=2 status=%d len=%d)\n", status, dataLen);
            break;
        case 0:
            printf("UID   (type=0 status=%d len=%d): ", status, dataLen);
            for (int i = 0; i < dataLen; i++) {
                if (i > 0) printf(" ");
                printf("%02X", data[i]);
            }
            printf("\n");
            break;
        default:
            printf("UNKNOWN (type=%d status=%d len=%d): ", datatype, status, dataLen);
            for (int i = 0; i < dataLen; i++) {
                if (i > 0) printf(" ");
                printf("%02X", data[i]);
            }
            printf("\n");
            break;
        }
    }

    close(fd);
    return 0;
}
