当前位置:   article > 正文

linux下RFID卡(门禁卡,Mifare卡)的编程_nack (0x04 or 0x05) from mifare card is received

nack (0x04 or 0x05) from mifare card is received
    我使用的是串口读卡器,RFID卡是philips的Mifare-M1卡。操作读卡器,就是操作串口设备。串口设备的基础只是,请参考 https://www.ibm.com/developerworks/cn/linux/l-serials/ ,此文讲得很详细。
    在嵌入式平台下,串口设置需要做得更全一些,以避免一些特殊字符问题。本文描述了一种用select进行非阻塞方式读取的方法,方便了应用程序进行整合。
1,打开串口
  1. int open_comm (const char* device) {
  2. if (device == NULL) return -1;
  3. int fd = open (device, O_RDWR|O_NOCTTY|O_NDELAY);
  4. return fd;
  5. }

2,设置串口
  1. static int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,
  2. B38400, B19200, B9600, B4800, B2400, B1200, B300, };
  3. static int name_arr[] = { 115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,
  4. 38400, 19200, 9600, 4800, 2400, 1200, 300, };
  5. int set_options (int fd, int speed, int databits, int stopbits, int parity) {
  6. struct termios options;
  7. int status = 0;
  8. if ((status = tcgetattr (fd, &options)) != 0) {
  9. ERROR ("fail: status=%d, %s", status, strerror (errno));
  10. return -1;
  11. }
  12. int bSpeed = -1;
  13. for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {
  14. if (speed == name_arr[i]) {
  15. bSpeed = speed_arr[i];
  16. break;
  17. }
  18. }
  19. if (bSpeed == -1) {
  20. ERROR ("wrong speed=%d", speed);
  21. return -1;
  22. }
  23. cfsetispeed (&options, bSpeed);
  24. cfsetospeed (&options, bSpeed);
  25. /*允许接收并且设置为本地模式*/
  26. options.c_cflag |= (CLOCAL|CREAD);
  27. /*设置数据位数*/
  28. options.c_cflag &= ~CSIZE;
  29. switch (databits)
  30. {
  31. case 7:
  32. options.c_cflag |= CS7;
  33. break;
  34. case 8:
  35. options.c_cflag |= CS8;
  36. break;
  37. default:
  38. ERROR ("Unsupported data size");
  39. return -1;
  40. }
  41. switch (parity)
  42. {
  43. case 'n':
  44. case 'N':
  45. options.c_cflag &= ~PARENB; /* Clear parity enable */
  46. options.c_iflag &= ~INPCK; /* Enable parity checking */
  47. break;
  48. case 'o':
  49. case 'O':
  50. options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
  51. options.c_iflag |= INPCK; /* Disnable parity checking */
  52. break;
  53. case 'e':
  54. case 'E':
  55. options.c_cflag |= PARENB; /* Enable parity */
  56. options.c_cflag &= ~PARODD; /* 转换为偶效验*/
  57. options.c_iflag |= INPCK; /* Disnable parity checking */
  58. break;
  59. case 'S':
  60. case 's': /*as no parity*/
  61. options.c_cflag &= ~PARENB;
  62. options.c_cflag &= ~CSTOPB;
  63. break;
  64. default:
  65. ERROR ("Unsupported parity");
  66. return -1;
  67. }
  68. /* 设置停止位*/
  69. switch (stopbits)
  70. {
  71. case 1:
  72. options.c_cflag &= ~CSTOPB;
  73. break;
  74. case 2:
  75. options.c_cflag |= CSTOPB;
  76. break;
  77. default:
  78. ERROR ("Unsupported stop bits");
  79. return -1;
  80. }
  81. /* Set input parity option */
  82. //if (parity != 'n')
  83. // options.c_iflag |= INPCK;
  84. options.c_cc[VINTR] = 0;
  85. options.c_cc[VQUIT] = 0;
  86. options.c_cc[VERASE] = 0;
  87. options.c_cc[VKILL] = 0;
  88. options.c_cc[VEOF] = 0;
  89. options.c_cc[VTIME] = 1;
  90. options.c_cc[VMIN] = 0;
  91. options.c_cc[VSWTC] = 0;
  92. options.c_cc[VSTART] = 0;
  93. options.c_cc[VSTOP] = 0;
  94. options.c_cc[VSUSP] = 0;
  95. options.c_cc[VEOL] = 0;
  96. options.c_cc[VREPRINT] = 0;
  97. options.c_cc[VDISCARD] = 0;
  98. options.c_cc[VWERASE] = 0;
  99. options.c_cc[VLNEXT] = 0;
  100. options.c_cc[VEOL2] = 0;
  101. //options.c_cc[VTIME] = 150; // 15 seconds
  102. //options.c_cc[VMIN] = 0;
  103. tcflush (fd,TCIFLUSH); /* Update the options and do it NOW */
  104. if ((status = tcsetattr (fd,TCSANOW,&options)) != 0) {
  105. ERROR ("fail: status=%d, %s", status, strerror (errno));
  106. return -1;
  107. }
  108. return 0;
  109. }



3,在一定超时时间内读取数据
  1. static int cmd_read_timeout (int fd, unsigned char* buf, int msec) {
  2. if (fd < 0 || buf == NULL) {
  3. ERROR ("fd = %d, buf=%p", fd, buf);
  4. return -1;
  5. }
  6. int maxfd = fd;
  7. fd_set fdread;
  8. FD_ZERO (&fdread);
  9. FD_SET (fd, &fdread);
  10. /* set a suitable timeout to play around with */
  11. struct timeval timeout;
  12. timeout.tv_sec = 0;
  13. timeout.tv_usec = msec*1000;
  14. int nread = 0;
  15. int rc = select (maxfd+1, &fdread, NULL, NULL, &timeout);
  16. switch (rc) {
  17. case -1:
  18. ERROR ("error: %s", strerror (errno));
  19. /* select error */
  20. nread = -1;
  21. break;
  22. case 0:
  23. //DEBUG ("timeout!");
  24. nread = -1;
  25. break;
  26. default:
  27. {
  28. /* readable sockets */
  29. if (FD_ISSET (fd, &fdread)) {
  30. nread = read (fd, buf, 512);
  31. //DEBUG ("read(%d):%s\n", nread, buf);
  32. if ((buf[1] + 2) == nread) {
  33. // checksum
  34. unsigned char checksum = 0;
  35. for (int i = 0; i < nread; i++) {
  36. checksum = checksum^buf[i];
  37. }
  38. if (checksum == 0) {
  39. // get right command.
  40. } else {
  41. nread = 0;
  42. }
  43. } else {
  44. // ERROR cmd lenght;
  45. DEBUG ("cmd length not right! got data len=%d, require=%d", nread, buf[1]+2);
  46. nread = 0;
  47. }
  48. } else {
  49. ERROR ("fd not set! maybe error!");
  50. nread = -1;
  51. }
  52. break;
  53. }
  54. }
  55. return nread;
  56. }



4,读取唯一的卡号和sector0上block1的数据。
  1. //============================================
  2. // Command List, preamble + length + command
  3. //============================================
  4. static const unsigned char SelectCard[]= {0xBA,0x02,0x01 };
  5. static const unsigned char LoginSector0[]= {0xBA,0x0A,0x02,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
  6. static const unsigned char LoginSector1[]= {0xBA,0x0A,0x02,0x01,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
  7. static const unsigned char ReadBlock1[]= {0xBA,0x03,0x03,0x01};
  8. 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};
  9. static const unsigned char ReadValue[]= {0xBA,0x03,0x05,0x05};
  10. static const unsigned char InitializeValue[]= {0xBA,0x07,0x06,0x04,0x00,0x00,0x00,0x01};
  11. static const unsigned char IncrementValue[]= {0xBA,0x07,0x08,0x04,0x00,0x00,0x00,0x20};
  12. static const unsigned char DecrementValue[]= {0xBA,0x07,0x09,0x04,0x03,0x00,0x00,0x00};
  13. static const unsigned char CopyValue[]= {0xBA,0x04,0x0A,0x04,0x05};
  14. static const unsigned char ReadULPage5[]= {0xBA,0x03,0x10,0x05};
  15. static const unsigned char WriteULPage5[]= {0xBA,0x07,0x11,0x05,0x11,0x22,0x33,0x44};
  16. static const unsigned char TurnOnRedLed[]= {0xBA,0x03,0x40,0x01};
  17. static const unsigned char TurnOffRedLed[]= {0xBA,0x03,0x40,0x00};
  18. static int wrap_data (unsigned char* dest, const unsigned char* src, int len) {
  19. if (dest == NULL || src == NULL || len == 0) return -1;
  20. memcpy (dest, src, len);
  21. unsigned char checksum = 0;
  22. for (int i = 0; i < len; i++) {
  23. checksum = checksum ^ src[i];
  24. }
  25. dest[len] = checksum;
  26. return 0;
  27. }
  28. int clear_comm (int fd) {
  29. tcflush(fd,TCIFLUSH);
  30. return 0;
  31. }
  32. int read_card_id_name (int fd, unsigned char* id, unsigned char* name) {
  33. if (id == NULL || name == NULL) return -1;
  34. unsigned char data_send[512] = {0};
  35. unsigned char data_recv[512] = {0};
  36. int nWrite = 0;
  37. int nRead = 0;
  38. tcflush(fd,TCIFLUSH);
  39. wrap_data (data_send, SelectCard, sizeof (SelectCard));
  40. nWrite = write (fd, data_send, sizeof (SelectCard) + 1);
  41. if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {
  42. return -1;
  43. }
  44. //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]);
  45. if ((data_recv[2] != 0x01) || (data_recv[3] != 0)) {
  46. return -1;
  47. }
  48. int retcode = 0;
  49. unsigned char card_type = data_recv[data_recv[1]];
  50. switch (card_type) {
  51. case 1:
  52. case 4:
  53. memcpy (id, &data_recv[4], 4);
  54. #if 1
  55. // verify password of sector0
  56. wrap_data (data_send, LoginSector0, sizeof (LoginSector0));
  57. nWrite = write (fd, data_send, sizeof (LoginSector0) + 1);
  58. if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {
  59. return -1;
  60. }
  61. if ((data_recv[2] != 0x02) || (data_recv[3] != 0x02)) {
  62. return -1;
  63. }
  64. // read data from block1
  65. wrap_data (data_send, ReadBlock1, sizeof (ReadBlock1));
  66. nWrite = write (fd, data_send, sizeof (ReadBlock1) + 1);
  67. if ((nRead = cmd_read_timeout (fd, data_recv, 300)) <= 0) {
  68. return -1;
  69. }
  70. if ((data_recv[2] != 0x03) || (data_recv[3] != 0)) {
  71. return -1;
  72. }
  73. memcpy (name, &data_recv[4], 16);
  74. #endif
  75. retcode = 0;
  76. break;
  77. case 3:
  78. memcpy (id, &data_recv[4], 7);
  79. retcode = -1;
  80. break;
  81. case 2:
  82. case 5:
  83. case 6:
  84. default:
  85. retcode = -1;
  86. break;
  87. }
  88. if (retcode != 0) {
  89. return retcode;
  90. }
  91. // Glare Red Led to indicate working ok
  92. wrap_data (data_send, TurnOnRedLed, sizeof (TurnOnRedLed));
  93. nWrite = write (fd, data_send, sizeof (TurnOnRedLed) + 1);
  94. nRead = cmd_read_timeout (fd, data_recv, 300);
  95. usleep (200*1000);
  96. wrap_data (data_send, TurnOffRedLed, sizeof (TurnOffRedLed));
  97. nWrite = write (fd, data_send, sizeof (TurnOffRedLed) + 1);
  98. nRead = cmd_read_timeout (fd, data_recv, 300);
  99. return 0;
  100. }

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

  1. int GlareLed (int fd) {
  2. int retcode = 0;
  3. unsigned char data_send[512] = {0};
  4. unsigned char data_recv[512] = {0};
  5. int nWrite = 0;
  6. int nRead = 0;
  7. // Glare Red Led to indicate working ok
  8. wrap_data (data_send, TurnOnRedLed, sizeof (TurnOnRedLed));
  9. nWrite = write (fd, data_send, sizeof (TurnOnRedLed) + 1);
  10. nRead = cmd_read_timeout (fd, data_recv, 300);
  11. DEBUG ("get %d bytes", nRead);
  12. usleep (200*1000);
  13. wrap_data (data_send, TurnOffRedLed, sizeof (TurnOffRedLed));
  14. nWrite = write (fd, data_send, sizeof (TurnOffRedLed) + 1);
  15. nRead = cmd_read_timeout (fd, data_recv, 300);
  16. DEBUG ("get %d bytes", nRead);
  17. return 0;
  18. }


6,主函数

  1. int main(int argc, char **argv)
  2. {
  3. const char *dev ="/dev/ttyUSB0";
  4. if (argc > 1) dev = argv[1];
  5. int fd = open (dev, O_RDWR|O_NOCTTY|O_NDELAY); //| O_NOCTTY | O_NDELAY
  6. if (fd < 0) {
  7. ERROR ("Can't Open Serial Port");
  8. return -1;
  9. }
  10. if (set_options (fd, B115200, 8, 1, 'N') != 0) {
  11. ERROR ("Set Parity Error");
  12. close (fd);
  13. return -1;
  14. }
  15. while (1) {
  16. unsigned char id[10];
  17. unsigned char name[20];
  18. int ret = read_card_id_name (fd, id, name);
  19. if (ret == 0) {
  20. printf ("%02x%02x%02x%02x\n ", id[0], id[1], id[2], id[3]);
  21. }
  22. //GlareLed (fd);
  23. //DEBUG ("");
  24. //string content = getdata (fd);
  25. //printf ("%s", content.c_str ());
  26. //write(fd, "AT1", 3);
  27. usleep (300*1000);
  28. }
  29. close(fd);
  30. return 0;
  31. }

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

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


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/772172
推荐阅读
相关标签
  

闽ICP备14008679号