【问题标题】:How do I read passive NFC/RFID units with PN532?如何使用 PN532 读取无源 NFC/RFID 单元?
【发布时间】:2017-04-22 18:59:32
【问题描述】:

我从 eBay 买了一个红色的“ELECHOUSE V3”小工具包,里面有一张白卡和一个蓝色的钥匙扣转发器,我写了一个 C 程序来创建和解码数据包,我可以向它发送命令,它会响应AC数据包,我可以读取版本和状态。我没有使用任何 RFID 库,我只是使用纯 C 并制作我自己的简单库,因为我想理解它,我想为真正想理解它的人发布一个简单的单文件演示,而不仅仅是使用一些arduino lib或其他什么。所以这就是我没有问的所有问题。

所以这是我要问的问题:

要发送哪些命令来扫描是否存在无源(非供电)转发器?我不确定它们是什么类型,但它们是随套件一起提供的,可能是 ISO 14443 / 14443A。

实际上,我在三星 Galaxy S4 上尝试了这些标签,它说它们是 ISO 14443-3A NXP MIFARE Classic 1K - 不支持。但它仍然显示它们的序列号。

扫描所有支持的卡类型的确切命令是什么?

要发送命令,我使用如下函数: sendcmd("0x4A 0x01 0x00"); (0xD4的TFI自动添加到命令中,preamble/len/lcs/checksums全部计算处理。)

我确实收到了我的命令的 ACKS,但不知道要发送哪些命令来扫描卡片或读取卡片。

如果我可以让 PN532 将卡扫描数据返回给我,我应该能够使用 PN532 数据表对其进行解析。

非常感谢,

杰西

【问题讨论】:

    标签: nfc rfid


    【解决方案1】:

    啊,好吧..在尝试了数据表中显示的所有相关内容但均未成功后,我将业余无线电打开到 13.56Mhz CW/LSB,没有任何声音可听..所以只是为了好玩,我尝试了 RFRegulationTest命令,这解锁了整个事情!似乎是一个测试命令,它打开发射器并让它保持开启,直到你发出另一个命令......但它会根据需要初始化一些东西!

    下面是使 NXP NP532 扫描卡所需的命令: (我使用的是 115200bps 的 RS232,但其他接口应该类似。)

    你发送给它:

    0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0xFF 0x03 0xFD 0xD4 0x58 0x00 0xD4
    

    你会得到一个 ACK​​ 并且发射器会启动: 0x00 0x00 0xFF 0x00 0xFF 0x00

    此时发射器将启动。也许让它做 100 毫秒或其他时间,然后你就可以开始扫描卡片了:

    0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0xFF 0x04 0xFC 0xD4 0x4A 0x02 0x00 0xE0
    

    然后芯片将打开无线电发射器并开始扫描卡,直到卡进入范围,然后它读取序列号,关闭发射器,并给你一个包含:

    0x4B、0x01/0x02(取决于检测到的是 1 还是 2 卡),然后是有关卡的各种信息,例如它的序列号。

    您还可以设置在给出 0x4A 0x02 0x00 命令时尝试的最大尝试次数,方法是将尝试次数设置为低于 0xFF 的数字,如下所示:

    sendcmd("0x32 0x05 0xFF 0x01 0x10")
    

    在这种情况下,当您发出读取命令 (0x4A 0x02 0x00) 时,它会尝试几分之一秒(0x10 次)然后放弃并发送包含以下内容的数据包:

    0x4B, 0x00 
    

    这意味着“找到的卡片:零。”

    有关所有详细信息,请参阅数据表,它确实告诉了您需要知道的一切,除了我在运行 rf 测试命令之前无法弄清楚如何启用发射器。

    无论如何,只要你愿意,只需每秒多次发送第二个命令,或者更慢,每次发送该命令时,它都会扫描并通知你范围内是否有卡片!

    或者,如果您将重试次数设置为 0xFF,那么它将一直尝试直到检测到卡,然后您只需在找到卡时重新发送 scan-for-card 命令。

    0xFF 的长字符串只是为了唤醒设备,因为它进入睡眠状态并错过了您发送的前几个字节。

    我给出的以一堆 0xFF 开头的发送内容的示例是整个完整的数据包,包括前导码、长度字段、校验和以及计算的所有内容。您可以直接发送它们以使其扫描卡片。

    初始射频测试命令和重试设置命令只需要在上电时运行一次,之后根据需要继续重新发送读取命令。

    我的 PN532 芯片将自身报告为版本:1.6

    这是我的小示例程序:

    (我从 SO 帖子中提取的 RS232 初始化部分 - 感谢编写该内容的人!)

    (适用于 Linux。使用 gcc nfc.c -o nfc.e 编译)

    (应该能够将其移植到任何平台,您只需要处理串行端口 - 其余的与平台无关。)

    (另请注意,这只是扫描卡并返回序列号/NFCID,并且仅适用于被动模式下 106kbps 的 Mifare、ISO/IEC14443-3 A 型卡。如果您想实际读取/写入内存卡片,您必须编写更多代码,但这至少演示了如何开始以及命令结构如何工作,并提供了一些方便的例程来发送和解码数据包。)

    #include <errno.h>
    #include <fcntl.h> 
    #include <string.h>
    #include <termios.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    int debug=0;
    int fd;
    void init_rs232(void);
    void sendpacket(unsigned char * payload, int len);
    void sendcmd(char * payload);
    int main(void)
    {
        printf("Welcome!\n");
        init_rs232();
        int waitfor;
    #define PACKET 1
    #define ACK 2
        sendcmd("0x58 0x00");waitfor=ACK; //RFRegulationTest -- This command is used for radio regulation test. 
        int cstate=0;   //Chat state, config state, whatever..
        int lc=0;
        while(1)
        {
            lc++;   //Send a scan command every second or so.
            if(lc>1000)
            {
                lc=0;
                sendcmd("0x4A 0x02 0x00");  //InListPassiveTarget -- The goal of this command is to detect as many targets (maximum MaxTg) as possible (max two) in passive mode.
            }
    
            if(cstate==1)   //ACK's set the bottom bit in state, allowing it to go onto the next state.
            {
                sendcmd("0x02");waitfor=PACKET; //Read the version out of the PN532 chip.
                cstate++;
            }
            if(cstate==3)   //ACK's set the bottom bit in state, allowing it to go onto the next state.
            {
                sendcmd("0x04");waitfor=PACKET; //Get current status.
                cstate++;
            }
            if(cstate==5)
            {
                waitfor=PACKET;
                sendcmd("0x32 0x05 0xFF 0x01 0x10");//Max retries - last byte is for passive: 0=1 try, 1=2 tries, 254=255 tries, 0xFF=infinite retries.
                //If last byte is 0xFF, then unit starts scanning for cards indefinitely. As soon as it detects a card, it stops scanning and returns info.
                //If last byte is less than 0xFF, it tries scans and as soon as it finds a card returns info on it and stops trying, but
                //if it never finds a card in the specified number of retries, it gives up and returns 0x4B, 0x00 (Cards found: Zero.)
                cstate++;
            }
    //Alternative way to send a new scan command each time the previous one gives up or finds a card:
    //      if(cstate==7)
    //      {
    //          waitfor=PACKET;
    //          sendcmd("0x4A 0x02 0x00");      //InListPassiveTarget
    //          cstate--;
    //      }
    
    
            static unsigned char buffin [1000024];
            static unsigned char buf[1],bufo[1];
            int n;
            static int bi=0;
            unsigned char len,lcs,tfi,dcs;
    
            bufo[0]=buf[0];
            n=read(fd,buf,sizeof(buf));
            if(n!=0)
            {
                if(n>0)
                {
                    if(bi<1000000)
                    {
                        static int state=0;
    
                        if(state==0)    //Waiting for preamble..
                        {
                            if((bufo[0]==0)&&(buf[0]==0xFF)){state=10;}
                        }
                        else if(state==10)  //Waiting for Len
                        {
                            len=buf[0];
                            state=20;
                        }
                        else if(state==20)  //Waiting for len checksum
                        {
                            if((len==0xFF)&&(buf[0]==0xFF)){printf("ERROR: BIG PACKET. Bye.\n");exit(-2);}
                            if((len==0x00)&&(buf[0]==0xFF)){state=21;}
                            else if((len==0xFF)&&(buf[0]==0x00)){state=21;}
                            else
                            {
                                lcs=buf[0]+len;
                                if(lcs){printf("ERROR: len checksum failed! 0x%02X\n",buf[0]);}
                                state=30;
                            }
                        }
                        else if(state==21)  //Waiting for the 0x00 after ack/nack..
                        {
                            state=0;
                            if(buf[0]==0x00)
                            {
                                if(bufo[0]==0xFF)
                                {
                                    if(debug){printf("ACK!\n");}
                                    if(waitfor==ACK){cstate=cstate|1;}
                                }
                                if(bufo[0]==0x00){printf("NACK!\n");}
    
                            }else{
                                printf("ERROR: Invalid length, or ack/nack missing postamble...\n");
                            }
                        }
                        else if(state==30)  //Waiting for tfi..
                        {
                            tfi=buf[0];
                            //printf("tfi=0x%02X\n",tfi);
                            dcs=tfi;
                            bi=0;
                            state=40;
                        }
                        else if(state==40)  //Saving bytes...
                        {
                            //printf("Saving payload byte 0x%02X\n",buf[0]);
                            buffin[bi++]=buf[0];
                            dcs=dcs+buf[0];
                            if(bi>=len){state=50;}
                        }
                        else if(state==50)  //Calculating the checksum..
                        {
                            state=0;
                            dcs=dcs+buf[0];
                            if(dcs)
                            {
                                printf("ERROR: Data Checksum Failed! (0x%02X)\n",dcs);
                            }else{
                                if(waitfor==PACKET){cstate=cstate|1;}
                                //printf("Good Packet: tfi=0x%02X, len=%d\n",tfi,len-1);
                                if(tfi==0xD5)
                                {
                                    if(buffin[0]==0x03){printf("PN532 Version: %d.%d, features:%d\n",buffin[2],buffin[3],buffin[4]);}
                                    if(buffin[0]==0x05)
                                    {
    
                                        printf("Status: Last Error:%d, Field:%d, Targets:%d, SAM Status:0x%02X\n",buffin[1],buffin[2],buffin[3],buffin[len-2]);
                                        static char bitrates[255][10]={"106kbps","212kbps","424kbps"};
                                        static char modtypes[255][100];
                                        strcpy(modtypes[0x00],"Mifare, ISO/IEC14443-3 Type A, ISO/IEC14443-3 Type B, ISO/IEC18092 passive 106 kbps");
                                        strcpy(modtypes[0x10],"FeliCa, ISO/IEC18092 passive 212/424 kbps");
                                        strcpy(modtypes[0x01],"ISO/IEC18092 Active mode");
                                        strcpy(modtypes[0x02],"Innovision Jewel tag");
                                        if(buffin[3]==1){printf("Target %d: rx bps:%s, tx bps:%s, modulation type: %s.\n",buffin[4],bitrates[buffin[5]],bitrates[buffin[6]],modtypes[buffin[7]]);}
                                        if(buffin[3]==2){printf("Target %d: rx bps:%s, tx bps:%s, modulation type: %s.\n",buffin[8],bitrates[buffin[9]],bitrates[buffin[10]],modtypes[buffin[11]]);}
                                    }
                                    if(buffin[0]==0x4B)
                                    {
                                        printf("FOUND %d CARDS!\n",buffin[1]);
                                        //ONLY VALID FOR Mifare/ ISO type A 106KBPS:
                                        int i,ii,iii;
                                        i=0;ii=2;
                                        while(i<buffin[1])
                                        {
                                            printf("Target # %d:", buffin[ii++]);
                                            printf("SENS_RES=0x%02X%02X, ",buffin[ii],buffin[ii+1]);ii++;ii++;
                                            printf("SEL_RES=0x%02X, ",buffin[ii++]);
                                            printf("NFCIDLength=%d, ",buffin[ii++]);
                                            printf("NFCID=");
                                            iii=0;
                                            while(iii<buffin[ii-1])
                                            {
                                                printf("%02X",buffin[ii+iii]);
                                                iii++;
                                                if(iii<buffin[ii-1]){printf(":");}
                                            }
                                            ii=ii+iii;
                                            printf("\n");
                                            i++;
                                        }
    
                                    }
                                    //Just a debugging thing for printing out the contents of valid packets.
                                    //int i=0;while(i<(len-1)){printf("0x%02X, ",buffin[i++]);}printf("\n");
                                }
                                else if(tfi==0x7F)
                                {
                                    printf("Received error packet 0x7F with zero size.\n");
                                }else{
                                    printf("ERROR: Got unknown %d byte packet with tfi=0x%02X!\n",len-1,tfi);
                                }
    
                            }
                        }
                        else
                        {
                            printf("Uhoh!\n");
                        }
                        //printf("Got byte 0x%02X, now state is %d\n",(unsigned char)buf[0],state);
    
                    }else{
                        printf("ERROR: bi=%d which is too big.. Starting over.\n",bi);
                        bi=0;
                    }
                }else{
                    printf("ERROR %d while reading serial port: %s\n",errno,strerror(errno));
                    exit(-1);
                }
            }
    
            usleep(1000);
    
        }
    
    
    
        return(0);
    }
    
    
    
    
    void init_rs232(void)
    {
        char *portname = "/dev/ttyUSB0";
        fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
        if (fd < 0)
        {
                printf("error %d opening %s: %s", errno, portname, strerror (errno));
            exit(-1);
        }
    
            struct termios tty;
            memset (&tty, 0, sizeof tty);
            if (tcgetattr (fd, &tty) != 0)
            {
                    printf("error %d from tcgetattr(%s)\n", errno,strerror(errno));
            exit(-1);
            }
    
            cfsetospeed (&tty, B115200);
            cfsetispeed (&tty, B115200);
    
            tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
            // disable IGNBRK for mismatched speed tests; otherwise receive break
            // as \000 chars
            tty.c_iflag &= ~IGNBRK;         // disable break processing
            tty.c_lflag = 0;                // no signaling chars, no echo,
                                            // no canonical processing
            tty.c_oflag = 0;                // no remapping, no delays
            tty.c_cc[VMIN]  = 0;            // read doesn't block
            tty.c_cc[VTIME] = 0;            // 0.5 seconds read timeout
    
            tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
    
            tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                            // enable reading
            tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
            tty.c_cflag |= 0;   //This was parity
            tty.c_cflag &= ~CSTOPB;
            tty.c_cflag &= ~CRTSCTS;
    
            if (tcsetattr (fd, TCSANOW, &tty) != 0)
            {
                    printf("error %d from tcsetattr(%s)\n", errno,strerror(errno));
            exit(-1);
            }
    }
    
    
    void sendpacket(unsigned char * payload, int len)
    {
        int tfi;
        static unsigned char buffer[66000];
        int i,bo;
        unsigned char lcs,dcs;
        tfi=0xD4;
        i=0;
        bo=0;
        while(i<=8){i++;buffer[bo++]=0xFF;} //Pre-padding.. 8-800 OK, 900 too much, 7 too little. Needs to be 0xFF I guess.. Probably wakes it up.
        buffer[bo++]=0x00;          //Preamble.
        buffer[bo++]=0xFF;              //Preamble.
        len++;
        lcs=-len;               //Length Checksum.. (yes...)
        buffer[bo++]=len;
        buffer[bo++]=lcs;
        buffer[bo++]=tfi;
        dcs=tfi;
        i=0;
        while((i<65900)&&(i<(len-1)))
        {
            buffer[bo]=payload[i];
            dcs=dcs+buffer[bo];
            bo++;
            i++;
        }
        dcs=(-dcs);
        buffer[bo++]=dcs;
        write(fd,buffer,bo);
        //printf("Sent %d bytes\n",bo);
        //printf("Whole packet: ");
        //i=0;
        //while(i<bo)
        //{
        //  printf("0x%02X ",buffer[i]);
        //  i++;
        //}
        //printf("\n");
    }
    void sendcmd(char * payload)    //Accepts space separated argument list like "0xFF 0x0A 255 'USERID' 0 0"
    {               //strings are quoted in half quotes. half quotes inside a string are escaped \\'
        int i,v;        //full quotes inside a string are escaped like \"
        static unsigned char buffer[1024];  //back slashes inside a string are escaped like \\\\  .
        static int bo;      //(The first escape or escape pair is for the C compiler, the second for this function:
        bo=0;           // The actual contents of the string are just \' and \\)
        i=0;            // Numeric formats supported are hex (0xNN), base ten (123), and octal (0377).
        if(debug){printf("sendcmd: ");}
        while(payload[i])
        {
            if((payload[i]!='\'')&&(payload[i]!=' '))
            {
                v=strtoul(&payload[i],NULL,0);
                buffer[bo++]=v;
                if(debug){printf("0x%02X, ",v);}
                while(payload[i]>' '){i++;}
            }
            else if(payload[i]=='\'')
            {
                i++;
                int keeprun;
                keeprun=1;
                while(keeprun)
                {
                    if(payload[i]=='\\')
                    {
                        i++;
                    }else{
                        if(payload[i]=='\''){keeprun=0;}
                    }
    
                    if((keeprun)&&(payload[i]))
                    {
                        buffer[bo++]=payload[i];
                        if(debug){printf("%c",payload[i]);}
    
                    }
                    i++;
                }
                if(debug){printf(", ");}
    
            }
            else
            {
                i++;
            }
        }
        if(debug){printf("\n");}
        sendpacket(buffer,bo);
    }
    

    【讨论】:

    • 感谢您提供此信息。这使我的卡工作。你能给我一个你找到这个命令的链接吗?以及这些位的确切含义。谢谢
    • 哇,那是 5 年前的样子,我不记得了,但谷歌搜索了一下,可能是这样的:nxp.com/docs/en/user-guide/141520.pdf——你可以搜索十六进制值(没有 0x,只是举个例子 D4 看看不同的代码是什么意思,或者只是通读文档,看起来它给出了一些例子。
    猜你喜欢
    • 2015-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多