pn532tool.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * ____ _________ _ _
  3. * _ __ _ __ | ___|___ /___ \| |_ ___ ___ | |
  4. * | '_ \| '_ \|___ \ |_ \ __) | __/ _ \ / _ \| |
  5. * | |_) | | | |___) |__) / __/| || (_) | (_) | |
  6. * | .__/|_| |_|____/____/_____|\__\___/ \___/|_|
  7. * |_|
  8. * by hakanai
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <termios.h>
  30. #include <stdint.h>
  31. #include <time.h>
  32. #include <stdbool.h>
  33. #define TOOL_VER "v0.0.1"
  34. /*#define DEFAULT_PORT "/tmp/sss"*/
  35. #define DEFAULT_PORT "/dev/ttyUSB0"
  36. #define PN532_DIAGNOSE_CMD 0x04
  37. #define PN532_VERSION_CMD 0x02
  38. #ifndef ESP_OK
  39. #define ESP_OK 0
  40. #define ESP_FAIL -1
  41. #endif
  42. static const char *TAG = "PN532-DRV";
  43. static bool _print_hex;
  44. #ifndef ESP_LOGE
  45. #define ESP_LOGE(t, ...) do { \
  46. fprintf(stderr, "[%s] ", t); \
  47. fprintf(stderr, __VA_ARGS__ ); \
  48. fprintf(stderr, "\n"); \
  49. } while(0)
  50. #endif
  51. enum pn532_init_state_enum {
  52. PN532_STATE_READ_RFSTATUS = 0,
  53. PN532_STATE_READ_VERSION,
  54. PN532_STATE_GET_STATUS,
  55. PN532_STATE_SET_SCANNING,
  56. PN532_STATE_COMPLETE
  57. };
  58. // {{{ set_port_opt()
  59. static void set_portopt(int fd) {
  60. struct termios options;
  61. /* tcgetattr(fd, &options);*/
  62. memset(&options, 0, sizeof(struct termios));
  63. cfsetispeed(&options, B115200);
  64. cfsetospeed(&options, B115200);
  65. /* Set 8 bit */
  66. options.c_cflag &= ~CSIZE;
  67. options.c_cflag |= CS8;
  68. options.c_cflag |= (CLOCAL | CREAD);
  69. /* Set 1 stop */
  70. options.c_cflag &= ~CSTOPB;
  71. options.c_cflag &= ~CRTSCTS;
  72. /* Set no parity */
  73. options.c_cflag &= ~(PARENB | PARODD);
  74. options.c_iflag &= ~INPCK;
  75. options.c_iflag &= ~IGNBRK;
  76. /* Raw input */
  77. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  78. /* Software flow control is disabled */
  79. options.c_iflag &= ~(IXON | IXOFF | IXANY);
  80. /* Raw ouput */
  81. options.c_oflag &=~ OPOST;
  82. /* Unused because we use open with the NDELAY option */
  83. options.c_cc[VMIN] = 0;
  84. options.c_cc[VTIME] = 0;
  85. if (tcsetattr(fd, TCSANOW, &options) != 0) {
  86. /* printf("Unable to set port options\n");*/
  87. /* exit(1);*/
  88. }
  89. }
  90. // }}}
  91. static void printbuf(uint8_t *buffer, uint16_t len) {
  92. for(uint16_t i = 0; i < len; i++){
  93. printf("%.2x ", buffer[i]);
  94. }
  95. }
  96. #define pprint(a, b, c) if (_print_hex) { printf("%s: ", a); printbuf(b, c); puts(""); }
  97. #define MAXBUFSIZ 256
  98. static int send_packet(int fd, const uint8_t *buffer, uint16_t len) {
  99. uint8_t cmd[MAXBUFSIZ] = { 0 };
  100. uint8_t sum = 0xd4;
  101. int i;
  102. if (len > MAXBUFSIZ || len < 1) {
  103. ESP_LOGE(TAG, "data size is wrong %d", len);
  104. return ESP_FAIL;
  105. }
  106. /* Make header */
  107. for (i = 0; i < 9; i++)
  108. cmd[i] = 0xff;
  109. /* Padding */
  110. cmd[i++] = 0x00;
  111. cmd[i++] = 0xff;
  112. /* Set length */
  113. cmd[i++] = len + 1;
  114. cmd[i++] = -(len + 1);
  115. /* Set target id */
  116. cmd[i++] = 0xd4;
  117. for (int j = 0; j < len; j++) {
  118. cmd[i++] = buffer[j];
  119. sum += buffer[j];
  120. }
  121. cmd[i++] = -(sum);
  122. cmd[i++] = 0xd4;
  123. if (write(fd, cmd, i) < i)
  124. return ESP_FAIL;
  125. pprint("send", cmd, i);
  126. return ESP_OK;
  127. }
  128. static int read_buffer(int fd, uint8_t *buffer, int len) {
  129. int rlen = 0;
  130. while ((rlen = read(fd, buffer, len)) < 1)
  131. usleep(10);
  132. return rlen;
  133. }
  134. static int recv_packet(int fd, uint8_t *buffer) {
  135. int len, j, i;
  136. const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0, 0, 0, 0xFF};
  137. uint8_t dlen[2];
  138. uint8_t sum;
  139. len = read_buffer(fd, buffer, MAXBUFSIZ);
  140. pprint("recv", buffer, len);
  141. i = sizeof(PN532_ACK);
  142. if (memcmp(buffer, PN532_ACK, i)) {
  143. /* ESP_LOGE(TAG, "Invalid frame");*/
  144. return ESP_FAIL;
  145. }
  146. dlen[0] = buffer[i++];
  147. dlen[1] = buffer[i++];
  148. if (len < 2 || (uint8_t)(dlen[0] + dlen[1]) != 0) {
  149. /* ESP_LOGE(TAG, "Incorrect length");*/
  150. return ESP_FAIL;
  151. }
  152. if (buffer[i++] != 0xd5) {
  153. /* ESP_LOGE(TAG, "Hostcheck failed");*/
  154. return ESP_FAIL;
  155. }
  156. dlen[0] -= 2;
  157. sum = 0xd5 + buffer[i++];
  158. for (j = 0; j < dlen[0]; j++) {
  159. sum += buffer[i + j];
  160. }
  161. if (((uint8_t)(sum + buffer[len - 2])) != 0 || buffer[len - 1] != 0) {
  162. /* ESP_LOGE(TAG, "Checksum error %d %d %d", buffer[len-1], sum, (uint8_t)(sum + buffer[len-1]));*/
  163. return ESP_FAIL;
  164. }
  165. for (j = 0; j < dlen[0]; j++) {
  166. buffer[j] = buffer[i++];
  167. }
  168. return dlen[0];
  169. }
  170. static int read_status(int fd) {
  171. const uint8_t cmd[2] = { 0x58, 0x00 };
  172. uint8_t buffer[MAXBUFSIZ] = { 0 };
  173. const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
  174. const uint8_t ack_len = sizeof(PN532_ACK);
  175. if (send_packet(fd, cmd, 2) != ESP_OK) {
  176. return ESP_FAIL;
  177. }
  178. if (read_buffer(fd, buffer, MAXBUFSIZ) != ack_len) {
  179. return ESP_FAIL;
  180. }
  181. if (memcmp(buffer, PN532_ACK, ack_len)) {
  182. return ESP_FAIL;
  183. }
  184. pprint("[ack]", buffer, ack_len);
  185. return ESP_OK;
  186. }
  187. static int read_diagnose(int fd) {
  188. const uint8_t cmd[1] = { PN532_DIAGNOSE_CMD };
  189. uint8_t buffer[MAXBUFSIZ] = { 0 };
  190. int rlen;
  191. if (send_packet(fd, cmd, 1) != ESP_OK) {
  192. return ESP_FAIL;
  193. }
  194. if ((rlen = recv_packet(fd, buffer)) < 1) {
  195. return ESP_FAIL;
  196. }
  197. return ESP_OK;
  198. }
  199. static int read_version(int fd) {
  200. const uint8_t cmd[1] = { PN532_VERSION_CMD };
  201. uint8_t buffer[MAXBUFSIZ] = { 0 };
  202. int rlen;
  203. if (send_packet(fd, cmd, 1) != ESP_OK) {
  204. return ESP_FAIL;
  205. }
  206. if ((rlen = recv_packet(fd, buffer)) < 3) {
  207. return ESP_FAIL;
  208. }
  209. printf("PN532 ver %d.%d, features: %d\n",
  210. buffer[1], buffer[2], buffer[3]);
  211. return ESP_OK;
  212. }
  213. static int set_scanning(int fd) {
  214. const uint8_t cmd[5] = { 0x32, 0x05, 0xff, 0x01, 0x10 };
  215. uint8_t buffer[MAXBUFSIZ] = { 0 };
  216. int rlen;
  217. if (send_packet(fd, cmd, 5) != ESP_OK) {
  218. return ESP_FAIL;
  219. }
  220. if ((rlen = recv_packet(fd, buffer)) != 0) {
  221. return ESP_FAIL;
  222. }
  223. printf("PN532 mode set\n");
  224. return ESP_OK;
  225. }
  226. static void pn532_init(int fd) {
  227. static int test_state;
  228. while (test_state != PN532_STATE_COMPLETE) {
  229. switch (test_state) {
  230. case PN532_STATE_READ_RFSTATUS:
  231. if (read_status(fd) == ESP_OK)
  232. test_state = PN532_STATE_READ_VERSION;
  233. break;
  234. case PN532_STATE_READ_VERSION:
  235. if (read_version(fd) == ESP_OK)
  236. test_state = PN532_STATE_GET_STATUS;
  237. break;
  238. case PN532_STATE_GET_STATUS:
  239. if (read_diagnose(fd) == ESP_OK)
  240. test_state = PN532_STATE_SET_SCANNING;
  241. break;
  242. case PN532_STATE_SET_SCANNING:
  243. if (set_scanning(fd) == ESP_OK)
  244. test_state = PN532_STATE_COMPLETE;
  245. break;
  246. }
  247. }
  248. }
  249. static int read_passive(int fd) {
  250. const uint8_t cmd[3] = { 0x4a, 0x02, 0x00 };
  251. uint8_t buffer[MAXBUFSIZ] = { 0 };
  252. int rlen;
  253. if (send_packet(fd, cmd, 3) != ESP_OK) {
  254. return ESP_FAIL;
  255. }
  256. if ((rlen = recv_packet(fd, buffer)) < 1) {
  257. return ESP_FAIL;
  258. }
  259. if (buffer[0] == 0x00) { // (No card) skip
  260. return ESP_FAIL;
  261. }
  262. printf("Read (%d) bytes:", rlen);
  263. printbuf(buffer, rlen);
  264. puts("");
  265. return ESP_OK;
  266. }
  267. static void usage(char *app) {
  268. printf("Usage: %s [options]\n\n", app);
  269. printf(" -p[port]\t\ttty port (default: /dev/ttyUSB0)\n");
  270. printf(" -x\t\t\tprint hex (debug)\n");
  271. printf("\n");
  272. printf("pn532tool %s by @hakanai\n", TOOL_VER);
  273. exit(1);
  274. }
  275. int main(int ac, char **av) {
  276. char *port = DEFAULT_PORT;
  277. int fd;
  278. int c;
  279. while ((c = getopt(ac, av, "p:xhv")) != -1) {
  280. switch (c) {
  281. case 'p':
  282. port = strdup(optarg);
  283. break;
  284. case 'x':
  285. _print_hex = true;
  286. break;
  287. default:
  288. usage(av[0]);
  289. }
  290. }
  291. fd = open(port, O_RDWR | O_SYNC | O_NOCTTY);
  292. if (fd == -1) {
  293. perror(port);
  294. exit(2);
  295. }
  296. set_portopt(fd);
  297. pn532_init(fd);
  298. while (1) {
  299. if (read_passive(fd) == ESP_OK)
  300. usleep(100 * 1000);
  301. usleep(100 * 1000);
  302. }
  303. close(fd);
  304. return 0;
  305. }