linux下RFID卡(门禁卡,Mifare卡)的编程

来源:互联网 发布:java web war包下载 编辑:程序博客网 时间:2024/05/01 07:59
    我使用的是串口读卡器,RFID卡是philips的Mifare-M1卡。操作读卡器,就是操作串口设备。串口设备的基础只是,请参考 https://www.ibm.com/developerworks/cn/linux/l-serials/ ,此文讲得很详细。
    在嵌入式平台下,串口设置需要做得更全一些,以避免一些特殊字符问题。本文描述了一种用select进行非阻塞方式读取的方法,方便了应用程序进行整合。
1,打开串口
int open_comm (const char* device) {    if (device == NULL) return -1;    int fd = open (device, O_RDWR|O_NOCTTY|O_NDELAY);    return fd;}

2,设置串口
static int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,                          B38400, B19200, B9600, B4800, B2400, B1200, B300, };static int name_arr[] = { 115200, 38400,  19200,  9600,  4800,  2400,  1200,  300,                          38400,  19200,  9600, 4800, 2400, 1200,  300, };int set_options (int fd, int speed, int databits, int stopbits, int parity) {    struct termios options;    int status = 0;    if ((status = tcgetattr (fd, &options)) != 0) {        ERROR ("fail: status=%d, %s", status, strerror (errno));        return -1;    }    int bSpeed = -1;    for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {        if (speed == name_arr[i]) {            bSpeed = speed_arr[i];            break;        }    }    if (bSpeed == -1) {        ERROR ("wrong speed=%d", speed);        return -1;    }    cfsetispeed (&options, bSpeed);    cfsetospeed (&options, bSpeed);    /*允许接收并且设置为本地模式*/    options.c_cflag |= (CLOCAL|CREAD);    /*设置数据位数*/    options.c_cflag &= ~CSIZE;    switch (databits)    {    case 7:        options.c_cflag |= CS7;        break;    case 8:        options.c_cflag |= CS8;        break;    default:        ERROR ("Unsupported data size");        return -1;    }    switch (parity)    {    case 'n':    case 'N':        options.c_cflag &= ~PARENB;   /* Clear parity enable */        options.c_iflag &= ~INPCK;     /* Enable parity checking */        break;    case 'o':    case 'O':        options.c_cflag |= (PARODD | PARENB);  /* 设置为奇效验*/        options.c_iflag |= INPCK;             /* Disnable parity checking */        break;    case 'e':    case 'E':        options.c_cflag |= PARENB;     /* Enable parity */        options.c_cflag &= ~PARODD;   /* 转换为偶效验*/        options.c_iflag |= INPCK;       /* Disnable parity checking */        break;    case 'S':    case 's':  /*as no parity*/        options.c_cflag &= ~PARENB;        options.c_cflag &= ~CSTOPB;        break;    default:        ERROR ("Unsupported parity");        return -1;    }    /* 设置停止位*/    switch (stopbits)    {    case 1:        options.c_cflag &= ~CSTOPB;        break;    case 2:        options.c_cflag |= CSTOPB;        break;    default:        ERROR ("Unsupported stop bits");        return -1;    }    /* Set input parity option */    //if (parity != 'n')    //  options.c_iflag |= INPCK;    options.c_cc[VINTR] = 0;    options.c_cc[VQUIT] = 0;    options.c_cc[VERASE] = 0;    options.c_cc[VKILL] = 0;    options.c_cc[VEOF] = 0;    options.c_cc[VTIME] = 1;    options.c_cc[VMIN] = 0;    options.c_cc[VSWTC] = 0;    options.c_cc[VSTART] = 0;    options.c_cc[VSTOP] = 0;    options.c_cc[VSUSP] = 0;    options.c_cc[VEOL] = 0;    options.c_cc[VREPRINT] = 0;    options.c_cc[VDISCARD] = 0;    options.c_cc[VWERASE] = 0;    options.c_cc[VLNEXT] = 0;    options.c_cc[VEOL2] = 0;    //options.c_cc[VTIME] = 150; // 15 seconds    //options.c_cc[VMIN] = 0;    tcflush (fd,TCIFLUSH); /* Update the options and do it NOW */    if ((status = tcsetattr (fd,TCSANOW,&options)) != 0) {        ERROR ("fail: status=%d, %s", status, strerror (errno));        return -1;    }    return 0;}



3,在一定超时时间内读取数据
static int cmd_read_timeout (int fd, unsigned char* buf, int msec) {    if (fd < 0 || buf == NULL) {        ERROR ("fd = %d, buf=%p", fd, buf);        return -1;    }    int maxfd = fd;    fd_set fdread;    FD_ZERO (&fdread);    FD_SET (fd, &fdread);    /* set a suitable timeout to play around with */    struct timeval timeout;    timeout.tv_sec = 0;    timeout.tv_usec = msec*1000;    int nread = 0;    int rc = select (maxfd+1, &fdread, NULL, NULL, &timeout);    switch (rc) {    case -1:        ERROR ("error: %s", strerror (errno));        /* select error */        nread = -1;        break;    case 0:        //DEBUG ("timeout!");        nread = -1;        break;    default:    {        /* readable sockets */        if (FD_ISSET (fd, &fdread)) {            nread = read (fd, buf, 512);            //DEBUG ("read(%d):%s\n", nread, buf);            if ((buf[1] + 2) == nread) {                // checksum                unsigned char checksum = 0;                for (int i = 0; i < nread; i++) {                    checksum = checksum^buf[i];                }                if (checksum == 0) {                    // get right command.                } else {                    nread = 0;                }            } else {                // ERROR cmd lenght;                DEBUG ("cmd length not right! got data len=%d, require=%d", nread, buf[1]+2);                nread = 0;            }        } else {            ERROR ("fd not set! maybe error!");            nread = -1;        }        break;    }    }    return nread;}



4,读取唯一的卡号和sector0上block1的数据。
//============================================//  Command List, preamble + length + command//============================================static const unsigned char SelectCard[]=      {0xBA,0x02,0x01 };static const unsigned char LoginSector0[]=    {0xBA,0x0A,0x02,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};static const unsigned char LoginSector1[]=    {0xBA,0x0A,0x02,0x01,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};static const unsigned char ReadBlock1[]=      {0xBA,0x03,0x03,0x01};static const unsigned char WriteBlock1[]=     {0xBA,0x13,0x04,0x01,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};static const unsigned char ReadValue[]=       {0xBA,0x03,0x05,0x05};static const unsigned char InitializeValue[]=   {0xBA,0x07,0x06,0x04,0x00,0x00,0x00,0x01};static const unsigned char IncrementValue[]=  {0xBA,0x07,0x08,0x04,0x00,0x00,0x00,0x20};static const unsigned char DecrementValue[]=  {0xBA,0x07,0x09,0x04,0x03,0x00,0x00,0x00};static const unsigned char CopyValue[]=       {0xBA,0x04,0x0A,0x04,0x05};static const unsigned char ReadULPage5[]=     {0xBA,0x03,0x10,0x05};static const unsigned char WriteULPage5[]=    {0xBA,0x07,0x11,0x05,0x11,0x22,0x33,0x44};static const unsigned char TurnOnRedLed[]=    {0xBA,0x03,0x40,0x01};static const unsigned char TurnOffRedLed[]=   {0xBA,0x03,0x40,0x00};static int wrap_data (unsigned char* dest, const unsigned char* src, int len) {    if (dest == NULL || src == NULL || len == 0) return -1;    memcpy (dest, src, len);    unsigned char checksum = 0;    for (int i = 0; i < len; i++) {        checksum = checksum ^ src[i];    }    dest[len] = checksum;    return 0;}int clear_comm (int fd) {    tcflush(fd,TCIFLUSH);    return 0;}int read_card_id_name (int fd, unsigned char* id, unsigned char* name) {    if (id == NULL || name == NULL) return -1;    unsigned char data_send[512] = {0};    unsigned char data_recv[512] = {0};    int nWrite = 0;    int nRead = 0;    tcflush(fd,TCIFLUSH);    wrap_data (data_send, SelectCard, sizeof (SelectCard));    nWrite = write (fd, data_send, sizeof (SelectCard) + 1);    if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {        return -1;    }    //DEBUG ("(%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", nRead, data_recv[0], data_recv[1], data_recv[2], data_recv[3], data_recv[4], data_recv[5], data_recv[6], data_recv[7], data_recv[8], data_recv[9]);    if ((data_recv[2] != 0x01) || (data_recv[3] != 0)) {        return -1;    }    int retcode = 0;    unsigned char card_type = data_recv[data_recv[1]];    switch (card_type) {    case 1:    case 4:        memcpy (id, &data_recv[4], 4);#if 1        // verify password of sector0        wrap_data (data_send, LoginSector0, sizeof (LoginSector0));        nWrite = write (fd, data_send, sizeof (LoginSector0) + 1);        if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {            return -1;        }        if ((data_recv[2] != 0x02) || (data_recv[3] != 0x02)) {            return -1;        }        // read data from block1        wrap_data (data_send, ReadBlock1, sizeof (ReadBlock1));        nWrite = write (fd, data_send, sizeof (ReadBlock1) + 1);        if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {            return -1;        }        if ((data_recv[2] != 0x03) || (data_recv[3] != 0)) {            return -1;        }        memcpy (name, &data_recv[4], 16);#endif        retcode = 0;        break;    case 3:        memcpy (id, &data_recv[4], 7);        retcode = -1;        break;    case 2:    case 5:    case 6:    default:        retcode = -1;        break;    }    if (retcode != 0) {        return retcode;    }    // Glare Red Led to indicate working ok    wrap_data (data_send, TurnOnRedLed, sizeof (TurnOnRedLed));    nWrite = write (fd, data_send, sizeof (TurnOnRedLed) + 1);    nRead = cmd_read_timeout (fd, data_recv, 300);    usleep (200*1000);    wrap_data (data_send, TurnOffRedLed, sizeof (TurnOffRedLed));    nWrite = write (fd, data_send, sizeof (TurnOffRedLed) + 1);    nRead = cmd_read_timeout (fd, data_recv, 300);    return 0;}

5,闪烁红灯,提示操作成功。

int GlareLed (int fd) {    int retcode = 0;    unsigned char data_send[512] = {0};    unsigned char data_recv[512] = {0};    int nWrite = 0;    int nRead = 0;    // Glare Red Led to indicate working ok    wrap_data (data_send, TurnOnRedLed, sizeof (TurnOnRedLed));    nWrite = write (fd, data_send, sizeof (TurnOnRedLed) + 1);    nRead = cmd_read_timeout (fd, data_recv, 300);    DEBUG ("get %d bytes", nRead);    usleep (200*1000);    wrap_data (data_send, TurnOffRedLed, sizeof (TurnOffRedLed));    nWrite = write (fd, data_send, sizeof (TurnOffRedLed) + 1);    nRead = cmd_read_timeout (fd, data_recv, 300);    DEBUG ("get %d bytes", nRead);    return 0;}


6,主函数

int main(int argc, char **argv){    const char *dev ="/dev/ttyUSB0";    if (argc > 1) dev = argv[1];    int fd = open (dev, O_RDWR|O_NOCTTY|O_NDELAY);         //| O_NOCTTY | O_NDELAY    if (fd < 0) {        ERROR ("Can't Open Serial Port");        return -1;    }    if (set_options (fd, B115200, 8, 1, 'N') != 0) {        ERROR ("Set Parity Error");        close (fd);        return -1;    }    while (1) {        unsigned char id[10];        unsigned char name[20];        int ret = read_card_id_name (fd, id, name);        if (ret == 0) {            printf ("%02x%02x%02x%02x\n ", id[0], id[1], id[2], id[3]);        }        //GlareLed (fd);        //DEBUG ("");        //string content = getdata (fd);        //printf ("%s", content.c_str ());        //write(fd, "AT1", 3);        usleep (300*1000);    }    close(fd);    return 0;}

7,遇到问题
在开发过程中,发现在嵌入式环境中,接收的数据经常会莫名丢失,0x13,0x11经常会不见了,丢失的都是这两个数,后来加上如下这段就好了。
    options.c_cc[VINTR] = 0;    options.c_cc[VQUIT] = 0;    options.c_cc[VERASE] = 0;    options.c_cc[VKILL] = 0;    options.c_cc[VEOF] = 0;    options.c_cc[VTIME] = 1;    options.c_cc[VMIN] = 0;    options.c_cc[VSWTC] = 0;    options.c_cc[VSTART] = 0;    options.c_cc[VSTOP] = 0;    options.c_cc[VSUSP] = 0;    options.c_cc[VEOL] = 0;    options.c_cc[VREPRINT] = 0;    options.c_cc[VDISCARD] = 0;    options.c_cc[VWERASE] = 0;    options.c_cc[VLNEXT] = 0;    options.c_cc[VEOL2] = 0;

8,有问题可以联系 agooou@gmail.com


原创粉丝点击