├── .github ├── CONTRIBUTING.md └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── README.md ├── README.rst.ori ├── UNLICENSE ├── changes.txt ├── doc ├── PBOC2.0 │ ├── 第10部分(借记_贷记应用个人化指南).pdf │ ├── 第11部分(非接触式IC卡通讯规范).pdf │ ├── 第12部分(非接触式IC卡支付规范).pdf │ ├── 第13部分(基于借记_贷记应用的小额支付规范).pdf │ ├── 第1部分电子钱包电子存折应用卡片规范.pdf │ ├── 第2部分(电子钱包_电子存折应用规范).pdf │ ├── 第3部分(与应用无关的IC卡与终端接口规范).pdf │ ├── 第4部分(借记_贷记应用规范).pdf │ ├── 第5部分(借记_贷记应用卡片规范).pdf │ ├── 第6部分(借记_贷记应用终端规范).pdf │ ├── 第7部分(借记_贷记应用安全规范).pdf │ ├── 第8部分(与应用无关的非接触式规范).pdf │ └── 第9部分(电子钱包扩展应用指南).pdf ├── fritzing │ ├── Arduino-Uno-r3-with-RFID-RC522.fzz │ ├── Arduino-Uno-r3-with-RFID-RC522.png │ ├── RFID-RC522 - Pin Layout.png │ ├── RFID-RC522-v2.fzpz │ └── RFID-RC522-v2.png ├── rfidmifare.doc └── rfidmifare.pdf ├── examples ├── AccessControl │ └── AccessControl.ino ├── ChangeUID │ └── ChangeUID.ino ├── DumpInfo │ └── DumpInfo.ino ├── FixBrickedUID │ └── FixBrickedUID.ino ├── MifareClassicValueBlock │ └── MifareClassicValueBlock.ino ├── MinimalInterrupt │ └── MinimalInterrupt.ino ├── Ntag216_AUTH │ └── Ntag216_AUTH.ino ├── RFID-Cloner │ └── RFID-Cloner.ino ├── ReadAndWrite │ └── ReadAndWrite.ino ├── ReadNUID │ └── ReadNUID.ino ├── ReadUidMultiReader │ └── ReadUidMultiReader.ino ├── firmware_check │ └── firmware_check.ino ├── readPBOC │ ├── readPBOC.ino │ └── result.png ├── rfid_default_keys │ └── rfid_default_keys.ino ├── rfid_read_personal_data │ └── rfid_read_personal_data.ino └── rfid_write_personal_data │ └── rfid_write_personal_data.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── MFRC522.cpp ├── MFRC522.h ├── MFRC522Debug.cpp ├── MFRC522Debug.h ├── MFRC522Extended.cpp ├── MFRC522Extended.h ├── MFRC522Hack.cpp ├── MFRC522Hack.h ├── PBOC ├── PBOC.cpp ├── PBOC.h ├── utils.cpp └── utils.h ├── deprecated.h └── require_cpp11.h /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Code style 2 | ---------- 3 | 4 | 1. Please use ``fixed integers``, see `stdint.h`_. Why? This library is compatible to different boards which use different architectures (16bit vs 32bit). So unfixed ``int`` has different sizes on different environments and may cause unpredictable behaviour. 5 | 6 | 2. If possible: use advantages of `c++11`, e.g. `constexpr`. 7 | 8 | 3. Use tab in source files. Space in examples. 9 | 10 | 4. Add documentation to **every** new function or parameter. Add documentation to most steps in your source code. 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Step 1: Are you in the right place? 2 | GitHub issues only for **bugs** or **improvements** of the library. All other topics, e.g. hardware/programming, will be closed. 3 | 4 | For general support from the community, see [Arduino Forum](https://forum.arduino.cc/) or [StackOverflow](https://stackoverflow.com/questions/tagged/mifare). 5 | 6 | ### Step 2: Describe your environment 7 | 8 | * OS version: _____ 9 | * Arduino IDE version: _____ 10 | * MFRC522 Library version: _____ 11 | * Arduino device: _____ 12 | * MFRC522 device: _____ 13 | 14 | ### Step 3: Describe the problem 15 | 16 | #### Affected file(s) or example(s): 17 | 18 | * Filename 1 19 | * Filename 2 20 | 21 | #### Steps to reproduce: 22 | 23 | 1. _____ 24 | 2. _____ 25 | 3. _____ 26 | 27 | #### Observed Results: 28 | 29 | * What happened? This could be a description, log output, etc. 30 | 31 | #### Expected Results: 32 | 33 | * What did you expect to happen? 34 | 35 | #### Relevant Code: 36 | 37 | ```arduino 38 | // TODO(you): code here to reproduce the problem 39 | ``` 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MFRC522.zip 2 | 3 | # ignore IDE files 4 | .idea 5 | cmake 6 | CMakeLists.txt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | # Cache PlatformIO packages using Travis CI container-based infrastructure 6 | sudo: false 7 | cache: 8 | directories: 9 | - "~/.platformio" 10 | 11 | env: 12 | # add examples here and define which boards should be tested (only compile test) 13 | - PLATFORMIO_CI_SRC=examples/ChangeUID/ChangeUID.ino TESTBOARD=arduino_avr,arduino_arm,esp 14 | - PLATFORMIO_CI_SRC=examples/DumpInfo/DumpInfo.ino TESTBOARD=arduino_avr,arduino_arm,esp 15 | - PLATFORMIO_CI_SRC=examples/firmware_check/firmware_check.ino TESTBOARD=arduino_avr,arduino_arm,esp 16 | - PLATFORMIO_CI_SRC=examples/FixBrickedUID/FixBrickedUID.ino TESTBOARD=arduino_avr,arduino_arm,esp 17 | - PLATFORMIO_CI_SRC=examples/MifareClassicValueBlock/MifareClassicValueBlock.ino TESTBOARD=arduino_avr,arduino_arm,esp 18 | - PLATFORMIO_CI_SRC=examples/MinimalInterrupt/MinimalInterrupt.ino TESTBOARD=arduino_avr,arduino_arm,esp 19 | - PLATFORMIO_CI_SRC=examples/ReadAndWrite/ReadAndWrite.ino TESTBOARD=arduino_avr,arduino_arm,esp 20 | - PLATFORMIO_CI_SRC=examples/ReadUidMultiReader/ReadUidMultiReader.ino TESTBOARD=arduino_avr,arduino_arm,esp 21 | - PLATFORMIO_CI_SRC=examples/rfid_default_keys/rfid_default_keys.ino TESTBOARD=arduino_avr,arduino_arm,esp 22 | - PLATFORMIO_CI_SRC=examples/rfid_write_personal_data/rfid_write_personal_data.ino TESTBOARD=arduino_avr,arduino_arm,esp 23 | - PLATFORMIO_CI_SRC=examples/Ntag216_AUTH/Ntag216_AUTH.ino TESTBOARD=arduino_avr,arduino_arm,esp 24 | - PLATFORMIO_CI_SRC=examples/ReadNUID/ReadNUID.ino TESTBOARD=arduino_avr,arduino_arm,esp 25 | - PLATFORMIO_CI_SRC=examples/AccessControl/AccessControl.ino TESTBOARD=arduino_avr 26 | - PLATFORMIO_CI_SRC=examples/RFID-Cloner/RFID-Cloner.ino TESTBOARD=arduino_avr,arduino_arm,esp 27 | - PLATFORMIO_CI_SRC=examples/rfid_read_personal_data/rfid_read_personal_data.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 28 | 29 | install: 30 | - pip install -U platformio 31 | 32 | script: 33 | # short the string comparison 34 | - stringContain() { [ -z "${2##*$1*}" ]; } 35 | # selectable board tests @Rotzbua 36 | # prints only warnings and errors, to show all remove "1>/dev/null" 37 | - board="arduino_avr"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; ouput=$(platformio ci --lib=. --board=uno --board=megaatmega1280); echo "----"; echo "$ouput" | grep -E "^(Device|Data|Program|text|[0-9])"; else echo "skip board test of $board"; fi 38 | - board="arduino_arm"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; ouput=$(platformio ci --lib=. --board=due --board=zero); echo "----"; echo "$ouput" | grep -E "^(Device|Data|Program|text|[0-9])"; else echo "skip board test of $board"; fi 39 | - board="teensy"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; ouput=$(platformio ci --lib=. --board=teensy20 --board=teensy31); echo "----"; echo "$ouput" | grep -E "^(Device|Data|Program|text|[0-9])"; else echo "skip board test of $board"; fi 40 | - board="esp"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; ouput=$(platformio ci --lib=. --board=d1_mini); echo "----"; echo "$ouput" | grep -E "^(Device|Data|Program|text|[0-9])"; else echo "skip board test of $board"; fi 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PBOC-Arduino 2 | 3 | 这是一个基于MFRC522库的扩展,支持PBOC(中国人民银行金融IC卡)的协议,并提供读取卡片的样例。 4 | **欢迎大家给星~** 5 | ## 协议说明 6 | PBOC是中国人民银行根据EMV规范指定的中国金融IC卡的规范,具体协议均在[/doc/PBOC2.0](./doc/PBOC2.0)中。 7 | 协议在底层兼容iso-14443协议(具体见PBOC2.0第11部分),应用层兼容接触式IC卡的iso-7816传输协议。 8 | 9 | ## 内容简介 10 | * PBOC类 11 | * 在底层的ISO-14443协议上增加应用层的处理 12 | * 支持PBOC的Select、ReadRecord、GetData等命令 13 | * 支持ISO-7816格式的Respond 14 | * 支持解析各阶段的返回数据 15 | * utils 16 | * `byte addLen(byte len, byte* value, byte * buf, bool addzero = true); 17 | ` 18 | 将长度加入字节串前端构成tlv结构数据 19 | * `byte concatBytes(byte l1, byte l2, byte* s1, byte* s2, byte* s3); 20 | ` 21 | 连接两个字节串 22 | * `void dump_byte_array(byte *buffer, byte bufferSize); 23 | ` 24 | 以16进制输出字节串 25 | * `int printUntil(byte* data, byte end = 0x00);` 26 | `int printHalfBytes(byte* data, int begin, byte len);` 27 | 输出函数,按半字节输出直到某字符或固定长度,用来输出PBOC协议的某些信息 28 | * BytePool类,字节串内存池。所有字节串初始时建立好,通过release循环利用,极大节省空间。之所以不用动态内存是因为实测arduino对new等操作效果不好。 29 | * tlv结构体。构建tlv结构,注意的是为了节省空间,这里只记录指向tlv地址的指针,所以不能在使用结束之前释放原有内存块。 30 | * 修正了MFRC522Extended中对于"链接块"的处理的BUG。 31 | 32 | ## 使用说明 33 | 1. 下载库文件 34 | 2. 删除MFRC522库,以免产生冲突。为了兼容性本库保留MFRC522名字,之前程序大部分仍能照常运行,但是由于修复原来库中一些错误,略有冲突。 35 | 3. Ardinuo->项目->加载库->加载一个.ZIP库并选择该问文件夹 36 | 4. 使用示例中的readPBOC测试 37 | 38 | ## 运行截图 39 | ![](./examples/readPBOC/result.png) 40 | 本图中只有开户记录,没有交易记录。 41 | ## 致谢 42 | 感谢邬晓钧、赵有健老师的帮助,感谢360杨卿、简云定老师的讲解。 43 | -------------------------------------------------------------------------------- /README.rst.ori: -------------------------------------------------------------------------------- 1 | MFRC522 2 | ======= 3 | 4 | .. image:: https://travis-ci.org/miguelbalboa/rfid.svg?branch=master 5 | :target: https://travis-ci.org/miguelbalboa/rfid 6 | .. image:: https://img.shields.io/badge/C%2B%2B-11-brightgreen.svg 7 | :target: `compatible ide`_ 8 | .. image:: https://img.shields.io/github/release/miguelbalboa/rfid.svg?colorB=green 9 | :target: https://github.com/miguelbalboa/rfid/releases 10 | .. image:: https://img.shields.io/badge/ArduinoIDE-%3E%3D1.6.10-lightgrey.svg 11 | :target: `compatible ide`_ 12 | 13 | Arduino library for MFRC522 and other RFID RC522 based modules. 14 | 15 | Read and write different types of Radio-Frequency IDentification (RFID) cards 16 | on your Arduino using a RC522 based reader connected via the Serial Peripheral 17 | Interface (SPI) interface. 18 | 19 | 20 | .. _development: 21 | Development 22 | ---------- 23 | **The development by owner miguelbalboa has ended**. Further development will be done by community. This library is still maintained by miguelbalboa, so make pull request if you like some new features or fixes. Support/issues should be solved by community. 24 | 25 | 26 | .. _what works and not: 27 | What works and not? 28 | ---------- 29 | 30 | * **Works** 31 | 32 | #. Communication (Crypto1) with MIFARE Classic (1k, 4k, Mini). 33 | #. Communication (Crypto1) with MIFARE Classic compatible PICCs. 34 | #. Firmware self check of MFRC522. 35 | #. Set the UID, write to sector 0, and unbrick Chinese UID changeable MIFARE cards. 36 | 37 | * **Partial** 38 | 39 | #. Communication with MIFARE Ultralight. 40 | #. Other PICCs (Ntag216). 41 | #. More than 2 modules, require a multiplexer `#191 `_. 42 | 43 | * **Works not** 44 | 45 | #. MIFARE DESFire, MIFARE DESFire EV1/EV2, not supported by software. 46 | #. Communication with 3DES or AES, not supported by software. 47 | #. Peer-to-peer (ISO/IEC 18092), not `supported by hardware`_. 48 | #. Communication with smart phone, not `supported by hardware`_. 49 | #. Card emulation, not `supported by hardware`_. 50 | #. Use of IRQ pin. But there is a proof-of-concept example. 51 | #. With Arduino Yun see `#111 `_, not supported by software. 52 | #. With Intel Galileo (Gen2) see `#310 `__, not supported by software. 53 | #. Power reduction modes `#269 `_, not supported by software. 54 | #. I2C instead of SPI `#240 `_, not supported by software. 55 | #. UART instead of SPI `#281 `_, not supported by software. 56 | 57 | * **Need more?** 58 | 59 | #. If software: code it and make a pull request. 60 | #. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15). 61 | 62 | 63 | .. _compatible ide: 64 | Compatible IDE 65 | ---------- 66 | This library works with Arduino IDE 1.6, older versions are **not supported** and will cause compile errors. The built-in library manager is supported. 67 | 68 | If you use your own compiler, you have to enable ``c++11``-support. 69 | 70 | 71 | .. _compatible boards: 72 | Compatible boards 73 | ---------- 74 | 75 | **!!!Only for advanced user!!!** 76 | 77 | This library is compatible to Teensy and ESP8266, if you use board plugin of the Arduino IDE. Not all examples are available for every board. You also have to change pins, see `pin layout`_. 78 | 79 | Some user made some patches/suggestions/ports for other boards: 80 | 81 | * Linux: https://github.com/miguelbalboa/rfid/pull/216 82 | * chipKIT: https://github.com/miguelbalboa/rfid/pull/230 83 | * ESP8266 (native): https://github.com/miguelbalboa/rfid/pull/235 84 | * ESP8266 nonos sdk: https://github.com/mmmmar/esp8266-mfrc522 85 | * LPCOPen (in C): https://github.com/miguelbalboa/rfid/pull/258 86 | 87 | Note that the main target/support of library is still Arduino. 88 | 89 | .. _support issue: 90 | Support/issue 91 | ---------- 92 | 1. First checkout `what works and not`_ and `troubleshooting`_ . 93 | 94 | 2. It seems to be a hardware issue or you need support to program your project? 95 | Please ask in the official `Arduino forum`_, there you would get a much faster answer then on github. 96 | 97 | 3. It seems to be a software issue? 98 | Open an issue on github. 99 | 100 | 101 | .. _code style: 102 | Code style 103 | ---------- 104 | 105 | Please use ``fixed integers``, see `stdint.h`_. Why? This library is compatible to different boards which use different architectures (16bit vs 32bit). So unfixed ``int`` has different sizes on different environments and may cause unpredictable behaviour. 106 | 107 | 108 | .. _pin layout: 109 | Pin Layout 110 | ---------- 111 | 112 | The following table shows the typical pin layout used: 113 | 114 | +-----------+----------+---------------------------------------------------------------+--------------------------+ 115 | | | PCD | Arduino | Teensy | 116 | | +----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 117 | | | MFRC522 | Uno / 101 | Mega | Nano v3 |Leonardo / Micro | Pro Micro | 2.0 | ++ 2.0 | 3.1 | 118 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 119 | | Signal | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | 120 | +===========+==========+=============+=========+=========+=================+===========+========+========+========+ 121 | | RST/Reset | RST | 9 [1]_ | 5 [1]_ | D9 | RESET / ICSP-5 | RST | 7 | 4 | 9 | 122 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 123 | | SPI SS | SDA [3]_ | 10 [2]_ | 53 [2]_ | D10 | 10 | 10 | 0 | 20 | 10 | 124 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 125 | | SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 | 2 | 22 | 11 | 126 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 127 | | SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 | 3 | 23 | 12 | 128 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 129 | | SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 | 1 | 21 | 13 | 130 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 131 | 132 | .. [1] Configurable, typically defined as RST_PIN in sketch/program. 133 | .. [2] Configurable, typically defined as SS_PIN in sketch/program. 134 | .. [3] The SDA pin might be labeled SS on some/older MFRC522 boards. 135 | 136 | 137 | .. _hardware: 138 | Hardware 139 | -------- 140 | 141 | There are three hardware components involved: 142 | 143 | 1. **Micro Controller**: 144 | 145 | * An `Arduino`_ or compatible executing the Sketch using this library. 146 | 147 | * Prices vary from USD 7 for clones, to USD 75 for "starter kits" (which 148 | might be a good choice if this is your first exposure to Arduino; 149 | check if such kit already includes the Arduino, Reader, and some Tags). 150 | 151 | 2. **Proximity Coupling Device (PCD)**: 152 | 153 | * The PCD is the actual RFID **Reader** based on `NXP MFRC522`_ Contactless 154 | Reader Integrated Circuit). 155 | 156 | * Readers can be found on `eBay`_ for around USD 5: search for *"rc522"*. 157 | 158 | * You can also find them at several web stores, they are often included in 159 | *"starter kits"*; so check your favourite electronics provider as well. 160 | 161 | 3. **Proximity Integrated Circuit Card (PICC)**: 162 | 163 | * The PICC is the RFID **Card** or **Tag** using the `ISO/IEC 14443A`_ 164 | interface, for example Mifare or NTAG203. 165 | 166 | * One or two might be included with the Reader or *"starter kit"* already. 167 | 168 | 169 | .. _protocol: 170 | Protocols 171 | --------- 172 | 173 | 1. The micro controller and the reader use SPI for communication. 174 | 175 | * The protocol is described in the `NXP MFRC522`_ datasheet. 176 | 177 | * See the `Pin Layout`_ section for details on connecting the pins. 178 | 179 | 2. The reader and the tags communicate using a 13.56 MHz electromagnetic field. 180 | 181 | * The protocol is defined in ISO/IEC 14443-3:2011 Part 3 Type A. 182 | 183 | * Details are found in chapter 6 *"Type A – Initialization and anticollision"*. 184 | 185 | * See http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf for a free version 186 | of the final draft (which might be outdated in some areas). 187 | 188 | * The reader does not support ISO/IEC 14443-3 Type B. 189 | 190 | 191 | .. _security: 192 | Security 193 | ------- 194 | This library only supports crypto1-encrypted communication. Crypto1 has been known as `broken`_ for a few years, so it does NOT offer ANY security, it is virtually unencrypted communication. **Do not use it for any security related applications!** 195 | 196 | This library does not offer 3DES or AES authentication used by cards like the Mifare DESFire, it may be possible to be implemented because the datasheet says there is support. We hope for pull requests :). 197 | 198 | 199 | .. _troubleshooting: 200 | Troubleshooting 201 | ------- 202 | 203 | * **I don't get input from reader** or **WARNING: Communication failure, is the MFRC522 properly connected?** 204 | 205 | #. Check your connection, see `Pin Layout`_ . 206 | #. Check voltage. Most breakouts work with 3.3V. 207 | #. SPI only works with 3.3V, most breakouts seem 5V tollerant, but try a level shifter. 208 | #. SPI do not like long connections. Try shorter connections. 209 | #. SPI do not like prototyping boards. Maybe try a soldered connections. 210 | #. According to reports #101, #126 and #131, there may be a problem with the soldering on the MFRC522 breakout. You could fix this on your own. 211 | 212 | 213 | * **Sometimes I get timeouts** or **sometimes tag/card does not work.** 214 | 215 | #. Try other side of the antenna. 216 | #. Try to decrease distance between MFRC522. 217 | #. Increase antenna gain per firmware: ``mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);`` 218 | #. Use better power supply. 219 | #. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller. 220 | 221 | 222 | * **My tag/card doesn't work.** 223 | 224 | #. Distance between antenna and token too large (>1cm). 225 | #. You got the wrong type PICC. Is it really 13.56 MHz? Is it really a Mifare Type A? 226 | #. NFC tokens are not supported. Some may work. 227 | #. Animal RFID tags are not supported. They use a different frequency (125 kHz). 228 | #. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller. 229 | #. Newer versions of Mifare cards like DESFire/Ultralight maybe not work according to missing authentification, see `security`_ or different `protocol`_. 230 | #. Some boards bought from chinese manufactures do not use the best components and this can affect the detection of different types of tag/card. In some of these boards, the L1 and L2 inductors do not have a high enough current so the signal generated is not enough to get Ultralight C and NTAG203 tags to work, replacing those with same inductance (2.2uH) but higher operating current inductors should make things work smoothly. Also, in some of those boards the harmonic and matching circuit needs to be tuned, for this replace C4 and C5 with 33pf capacitors and you are all set. (Source: `Mikro Elektronika`_) 231 | 232 | * **My mobile phone doesn't recognize the MFRC522** or **my MFRC522 can't read data from other MFRC522** 233 | 234 | #. Card simmulation is not supported. 235 | #. Communication with mobile phones is not supported. 236 | #. Peer to peer communication is not supported. 237 | 238 | 239 | * **I need more features.** 240 | 241 | #. If software: code it and make a pull request. 242 | #. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15) 243 | 244 | 245 | .. _license: 246 | License 247 | ------- 248 | This is free and unencumbered software released into the public domain. 249 | 250 | Anyone is free to copy, modify, publish, use, compile, sell, or 251 | distribute this software, either in source code form or as a compiled 252 | binary, for any purpose, commercial or non-commercial, and by any 253 | means. 254 | 255 | In jurisdictions that recognize copyright laws, the author or authors 256 | of this software dedicate any and all copyright interest in the 257 | software to the public domain. We make this dedication for the benefit 258 | of the public at large and to the detriment of our heirs and 259 | successors. We intend this dedication to be an overt act of 260 | relinquishment in perpetuity of all present and future rights to this 261 | software under copyright law. 262 | 263 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 264 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 265 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 266 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 267 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 268 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 269 | OTHER DEALINGS IN THE SOFTWARE. 270 | 271 | For more information, please refer to https://unlicense.org/ 272 | 273 | 274 | History 275 | ------- 276 | 277 | The MFRC522 library was first created in Jan 2012 by Miguel Balboa (from 278 | http://circuitito.com) based on code by Dr. Leong (from http://B2CQSHOP.com) 279 | for *"Arduino RFID module Kit 13.56 Mhz with Tags SPI W and R By COOQRobot"*. 280 | 281 | It was translated into English and rewritten/refactored in the fall of 2013 282 | by Søren Thing Andersen (from http://access.thing.dk). 283 | 284 | It has been extended with functionality to alter sector 0 on Chinese UID changeable MIFARE card in Oct 2014 by Tom Clement (from http://tomclement.nl). 285 | 286 | 287 | .. _arduino: https://arduino.cc/ 288 | .. _ebay: https://www.ebay.com/ 289 | .. _iso/iec 14443a: https://en.wikipedia.org/wiki/ISO/IEC_14443 290 | .. _iso/iec 14443-3\:2011 part 3: 291 | .. _nxp mfrc522: https://www.nxp.com/documents/data_sheet/MFRC522.pdf 292 | .. _broken: https://eprint.iacr.org/2008/166 293 | .. _supported by hardware: https://web.archive.org/web/20151210045625/http://www.nxp.com/documents/leaflet/939775017564.pdf 294 | .. _Arduino forum: https://forum.arduino.cc 295 | .. _stdint.h: https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h 296 | .. _Mikro Elektronika: https://forum.mikroe.com/viewtopic.php?f=147&t=64203 297 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /changes.txt: -------------------------------------------------------------------------------- 1 | -- Add changes to unreleased tag until we make a release. 2 | 3 | unreleased 4 | - Removed: void PCD_Init(byte resetPowerDownPin); 5 | - Removed: MFRC522(byte resetPowerDownPin); 6 | - Changed default initialisation of SS pin with constants of arduino.h are not done anymore 7 | - Replaced UINT8_MAX by UNUSED_PIN 8 | - Replaced default value NULL for pointer with correct nullptr 9 | - 10 | 26 July 2017, v2.0.0 11 | - This is an extension version to read PBOC(中国人民银行金融卡标准) card. @Sleepychord 12 | 13 | 22 Mar 2017, v1.3.6 14 | - Added deprecate and compiler warnings @Rotzbua 15 | 16 | 8 Apr 2017, v1.3.5 17 | - Updated "AccessControl.ino", bugs fixed and alterate Wipe button polling method without using other library @beyondszine reviewed by @omersiar 18 | - Updated README notice about port for esp8266 @mmmmar 19 | 20 | 7 Apr 2017, v1.3.4 21 | - Added new example "rfid_read_personal_data.ino" @ryand1011 22 | - Updated example "rfid_write_personal_data.ino" code style to Arduino IDE @Rotzbua 23 | - Removed (temp.) Teensy from travis build script because fails @Rotzbua 24 | 25 | 26 Mar 2017, v1.3.3 26 | - Fixed bugs in MFRC522Extended, now should work with Desfire.h from JPG-Consulting @Rotzbua 27 | - Fixed UINT8_MAX error @Rotzbua 28 | 29 | 15 Mar 2017, v1.3.2 30 | - Added ESP8266 to library.properties 31 | 32 | 15 Mar 2017, v1.3.1 33 | - Fixed compiler warning in MFRC522Extended @Rotzbua 34 | - Removed unused function @Rotzbua 35 | 36 | 13 Mar 2017, v1.3.0 37 | - Warning: Source has moved to folder src! 38 | - Added addtional class to support ISO/IEC 14443-4 PICCs @JPG-Consulting 39 | - Added RATS (Request for Answer To Select) @JPG-Consulting 40 | - More information see https://github.com/miguelbalboa/rfid/pull/271 @JPG-Consulting 41 | 42 | 13 Mar 2017, v1.2.1 43 | - Removed need for reset pin #275 @tkoester 44 | - Added SPI speed option + Various minor changes #276 @tuyethoa08041997 45 | - Updated documentation, travis build script and small code change @Rotzbua 46 | 47 | 3 Jan 2017, v1.2.0 48 | - Warning: This version introduce usage of stdint.h, usage of not well defined int types are abandoned. 49 | Interface has changed: e.g. long -> int32_t 50 | @Rotzbua 51 | - Removed problematic example examples/servo_motor/servo_motor.ino @omersiar 52 | - Added examples/AccessControl/AccessControl.ino @omersiar 53 | - Fixed minor issues reported in #211 @omersiar 54 | - Added bad components hint to README @danielcbit 55 | - Fixed selftest @surr 56 | - Fixed auth problem with long UIDs @surr 57 | 58 | 26 Aug 2016, v1.1.9 59 | - Warning: Only Arduino IDE version 1.6 is supported, please update your IDE to 1.6 to use this Library. 60 | - Added ESP8266 platform support @Rotzbua 61 | - Changed README.rst content to show more info @Rotzbua 62 | - Minor Changes to examples/ReadUidMultiReader/ReadUidMultiReader.ino example @Rotzbua 63 | 64 | 11 Feb 2016, v1.1.8 65 | - Added examples/MinimalInterrupt/MinimalInterrupt.ino example, Interrupt example @lmmeng 66 | - Added .gitignore file allows the project to be more easily used as a subproject. @BenWiederhake 67 | - Added Added Teensy 2.0 & Tensy++ 2.0 pinouts to README.rst @jkutianski 68 | 69 | 16 Jan 2016, v1.1.7 70 | - README.rst Spelling and Grammar Tweak @cuthbertnibbles 71 | - Added examples/servo_motor/servo_motor.ino example, Arduino RFID Access Control with a Servo Motor @techied 72 | - Added examples/RFID-Cloner/RFID-Cloner.ino Copy from rfid cards with standard authentication @stefanblommaert 73 | - Fix compile error at examples/RFID-Cloner/RFID-Cloner.ino, using MFRC522:::PICC_Type, @Rotzbua 74 | 75 | 06 Jan 2016, v1.1.6 76 | - Fixed compilation error for examples/ReadNUID/ReadNUID.ino example. @Rotzbua 77 | 78 | 04 Jan 2016, v1.1.5 79 | - Use settings functions on SPI libraries, setSPIConfig was deleted, now the library use SPI.beginTransaction() and SPI.endTransaction() @sophiekovalevsky 80 | - Added examples/ReadNUID/ReadNUID.ino example, showing how to read new NUID from a PICC to serial. @sophiekovalevsky 81 | 82 | 03 Jan 2016, v1.1.4 83 | - Added Authentication with Ntag 213,215,216 returns the pACK MFRC522::PCD_NTAG216_AUTH @Gargantuanman 84 | - Starting to use versions http://semver.org/ 85 | - Continuous Integration @ivankravets 86 | - functions return MFRC522::StatusCode and MFRC522::PICC_Type instead of generic byte @rotzbua 87 | - removed int-values of MFRC522::StatusCode and MFRC522::PICC_Type @rotzbua 88 | 89 | 05 Dec 2015 90 | - recognize infineon cards correctly @mayatforest 91 | - added multi reader support, see example @lmmeng 92 | 93 | 10 Nov 2014 94 | - Updated the changelog. 95 | - Added makefile. 96 | 97 | 24 Oct 2014 98 | - Added PlatformIO-based manifest file. 99 | 100 | 17 Jul 2014 101 | - Written documentation for the library. 102 | - Added rfid_default_keys example. 103 | 104 | 11 Jun 2014 105 | - Updated example: ReadAndWrite. 106 | 107 | 14 Apr 2014 108 | - Updated examples: DumpInfo, MifareClassicValueBlock, and ReadAndWrite. 109 | 110 | 12 Feb 2014 111 | - Fixed resetPowerDownPin initial state. 112 | 113 | 29 Jan 2014 114 | - Fixed chipSelectPin initial state. 115 | 116 | 30 Nov 2013 117 | - Examples put in their own folders. 118 | - Updated the keywords.txt file. 119 | 120 | 12 Nov 2013 121 | - Updated examples: DumpInfo, MifareClassicValueBlock, and ReadAndWrite. 122 | 123 | 20 Oct 2013 124 | - All constants, functions and parameters are now commented in English. 125 | - Code refactored, most function names have changed. 126 | - Support ISO-14443-3 anti collission and 4/7/10 byte UIDs (cascade levels). 127 | - Added functions for MIFARE Classic Decrement/Increment/Restore/Transfer 128 | and MIFARE Ultralight Write. 129 | - New examples written. 130 | 131 | 19 Oct 2013 132 | - Renamed library from RFID to MFRC522 (RFID seemed to generic). 133 | - Register names changed to comply with datasheet. 134 | - Global defines moved into class. 135 | 136 | 24 Sep 2013 137 | - Turn off encryption when tag is halted. 138 | 139 | 27 Jan 2013 140 | - Added README and small TODO list. 141 | - Added example to show Serial on LCD display. 142 | 143 | 09 Sep 2012 144 | - Initial commit to GitHub. 145 | -------------------------------------------------------------------------------- /doc/PBOC2.0/第10部分(借记_贷记应用个人化指南).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第10部分(借记_贷记应用个人化指南).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第11部分(非接触式IC卡通讯规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第11部分(非接触式IC卡通讯规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第12部分(非接触式IC卡支付规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第12部分(非接触式IC卡支付规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第13部分(基于借记_贷记应用的小额支付规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第13部分(基于借记_贷记应用的小额支付规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第1部分电子钱包电子存折应用卡片规范.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第1部分电子钱包电子存折应用卡片规范.pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第2部分(电子钱包_电子存折应用规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第2部分(电子钱包_电子存折应用规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第3部分(与应用无关的IC卡与终端接口规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第3部分(与应用无关的IC卡与终端接口规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第4部分(借记_贷记应用规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第4部分(借记_贷记应用规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第5部分(借记_贷记应用卡片规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第5部分(借记_贷记应用卡片规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第6部分(借记_贷记应用终端规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第6部分(借记_贷记应用终端规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第7部分(借记_贷记应用安全规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第7部分(借记_贷记应用安全规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第8部分(与应用无关的非接触式规范).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第8部分(与应用无关的非接触式规范).pdf -------------------------------------------------------------------------------- /doc/PBOC2.0/第9部分(电子钱包扩展应用指南).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/PBOC2.0/第9部分(电子钱包扩展应用指南).pdf -------------------------------------------------------------------------------- /doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.fzz -------------------------------------------------------------------------------- /doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.png -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522 - Pin Layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/fritzing/RFID-RC522 - Pin Layout.png -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522-v2.fzpz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/fritzing/RFID-RC522-v2.fzpz -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/fritzing/RFID-RC522-v2.png -------------------------------------------------------------------------------- /doc/rfidmifare.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/rfidmifare.doc -------------------------------------------------------------------------------- /doc/rfidmifare.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/doc/rfidmifare.pdf -------------------------------------------------------------------------------- /examples/AccessControl/AccessControl.ino: -------------------------------------------------------------------------------- 1 | /* 2 | -------------------------------------------------------------------------------------------------------------------- 3 | Example sketch/program showing An Arduino Door Access Control featuring RFID, EEPROM, Relay 4 | -------------------------------------------------------------------------------------------------------------------- 5 | This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | 7 | This example showing a complete Door Access Control System 8 | 9 | Simple Work Flow (not limited to) : 10 | +---------+ 11 | +----------------------------------->READ TAGS+^------------------------------------------+ 12 | | +--------------------+ | 13 | | | | | 14 | | | | | 15 | | +----v-----+ +-----v----+ | 16 | | |MASTER TAG| |OTHER TAGS| | 17 | | +--+-------+ ++-------------+ | 18 | | | | | | 19 | | | | | | 20 | | +-----v---+ +----v----+ +----v------+ | 21 | | +------------+READ TAGS+---+ |KNOWN TAG| |UNKNOWN TAG| | 22 | | | +-+-------+ | +-----------+ +------------------+ | 23 | | | | | | | | 24 | | +----v-----+ +----v----+ +--v--------+ +-v----------+ +------v----+ | 25 | | |MASTER TAG| |KNOWN TAG| |UNKNOWN TAG| |GRANT ACCESS| |DENY ACCESS| | 26 | | +----------+ +---+-----+ +-----+-----+ +-----+------+ +-----+-----+ | 27 | | | | | | | 28 | | +----+ +----v------+ +--v---+ | +---------------> 29 | +-------+EXIT| |DELETE FROM| |ADD TO| | | 30 | +----+ | EEPROM | |EEPROM| | | 31 | +-----------+ +------+ +-------------------------------+ 32 | 33 | 34 | Use a Master Card which is act as Programmer then you can able to choose card holders who will granted access or not 35 | 36 | * **Easy User Interface** 37 | 38 | Just one RFID tag needed whether Delete or Add Tags. You can choose to use Leds for output or Serial LCD module to inform users. 39 | 40 | * **Stores Information on EEPROM** 41 | 42 | Information stored on non volatile Arduino's EEPROM memory to preserve Users' tag and Master Card. No Information lost 43 | if power lost. EEPROM has unlimited Read cycle but roughly 100,000 limited Write cycle. 44 | 45 | * **Security** 46 | To keep it simple we are going to use Tag's Unique IDs. It's simple and not hacker proof. 47 | 48 | @license Released into the public domain. 49 | 50 | Typical pin layout used: 51 | ----------------------------------------------------------------------------------------- 52 | MFRC522 Arduino Arduino Arduino Arduino Arduino 53 | Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 54 | Signal Pin Pin Pin Pin Pin Pin 55 | ----------------------------------------------------------------------------------------- 56 | RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 57 | SPI SS SDA(SS) 10 53 D10 10 10 58 | SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 59 | SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 60 | SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 61 | */ 62 | 63 | #include // We are going to read and write PICC's UIDs from/to EEPROM 64 | #include // RC522 Module uses SPI protocol 65 | #include // Library for Mifare RC522 Devices 66 | 67 | /* 68 | Instead of a Relay you may want to use a servo. Servos can lock and unlock door locks too 69 | Relay will be used by default 70 | */ 71 | 72 | // #include 73 | 74 | /* 75 | For visualizing whats going on hardware we need some leds and to control door lock a relay and a wipe button 76 | (or some other hardware) Used common anode led,digitalWriting HIGH turns OFF led Mind that if you are going 77 | to use common cathode led or just seperate leds, simply comment out #define COMMON_ANODE, 78 | */ 79 | 80 | #define COMMON_ANODE 81 | 82 | #ifdef COMMON_ANODE 83 | #define LED_ON LOW 84 | #define LED_OFF HIGH 85 | #else 86 | #define LED_ON HIGH 87 | #define LED_OFF LOW 88 | #endif 89 | 90 | constexpr uint8_t redLed = 7; // Set Led Pins 91 | constexpr uint8_t greenLed = 6; 92 | constexpr uint8_t blueLed = 5; 93 | 94 | constexpr uint8_t relay = 4; // Set Relay Pin 95 | constexpr uint8_t wipeB = 3; // Button pin for WipeMode 96 | 97 | boolean match = false; // initialize card match to false 98 | boolean programMode = false; // initialize programming mode to false 99 | boolean replaceMaster = false; 100 | 101 | uint8_t successRead; // Variable integer to keep if we have Successful Read from Reader 102 | 103 | byte storedCard[4]; // Stores an ID read from EEPROM 104 | byte readCard[4]; // Stores scanned ID read from RFID Module 105 | byte masterCard[4]; // Stores master card's ID read from EEPROM 106 | 107 | // Create MFRC522 instance. 108 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 109 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 110 | 111 | MFRC522 mfrc522(SS_PIN, RST_PIN); 112 | 113 | ///////////////////////////////////////// Setup /////////////////////////////////// 114 | void setup() { 115 | //Arduino Pin Configuration 116 | pinMode(redLed, OUTPUT); 117 | pinMode(greenLed, OUTPUT); 118 | pinMode(blueLed, OUTPUT); 119 | pinMode(wipeB, INPUT_PULLUP); // Enable pin's pull up resistor 120 | pinMode(relay, OUTPUT); 121 | //Be careful how relay circuit behave on while resetting or power-cycling your Arduino 122 | digitalWrite(relay, HIGH); // Make sure door is locked 123 | digitalWrite(redLed, LED_OFF); // Make sure led is off 124 | digitalWrite(greenLed, LED_OFF); // Make sure led is off 125 | digitalWrite(blueLed, LED_OFF); // Make sure led is off 126 | 127 | //Protocol Configuration 128 | Serial.begin(9600); // Initialize serial communications with PC 129 | SPI.begin(); // MFRC522 Hardware uses SPI protocol 130 | mfrc522.PCD_Init(); // Initialize MFRC522 Hardware 131 | 132 | //If you set Antenna Gain to Max it will increase reading distance 133 | //mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); 134 | 135 | Serial.println(F("Access Control Example v0.1")); // For debugging purposes 136 | ShowReaderDetails(); // Show details of PCD - MFRC522 Card Reader details 137 | 138 | //Wipe Code - If the Button (wipeB) Pressed while setup run (powered on) it wipes EEPROM 139 | if (digitalRead(wipeB) == LOW) { // when button pressed pin should get low, button connected to ground 140 | digitalWrite(redLed, LED_ON); // Red Led stays on to inform user we are going to wipe 141 | Serial.println(F("Wipe Button Pressed")); 142 | Serial.println(F("You have 10 seconds to Cancel")); 143 | Serial.println(F("This will be remove all records and cannot be undone")); 144 | bool buttonState = monitorWipeButton(10000); // Give user enough time to cancel operation 145 | if (buttonState == true && digitalRead(wipeB) == LOW) { // If button still be pressed, wipe EEPROM 146 | Serial.println(F("Starting Wiping EEPROM")); 147 | for (uint16_t x = 0; x < EEPROM.length(); x = x + 1) { //Loop end of EEPROM address 148 | if (EEPROM.read(x) == 0) { //If EEPROM address 0 149 | // do nothing, already clear, go to the next address in order to save time and reduce writes to EEPROM 150 | } 151 | else { 152 | EEPROM.write(x, 0); // if not write 0 to clear, it takes 3.3mS 153 | } 154 | } 155 | Serial.println(F("EEPROM Successfully Wiped")); 156 | digitalWrite(redLed, LED_OFF); // visualize a successful wipe 157 | delay(200); 158 | digitalWrite(redLed, LED_ON); 159 | delay(200); 160 | digitalWrite(redLed, LED_OFF); 161 | delay(200); 162 | digitalWrite(redLed, LED_ON); 163 | delay(200); 164 | digitalWrite(redLed, LED_OFF); 165 | } 166 | else { 167 | Serial.println(F("Wiping Cancelled")); // Show some feedback that the wipe button did not pressed for 15 seconds 168 | digitalWrite(redLed, LED_OFF); 169 | } 170 | } 171 | // Check if master card defined, if not let user choose a master card 172 | // This also useful to just redefine the Master Card 173 | // You can keep other EEPROM records just write other than 143 to EEPROM address 1 174 | // EEPROM address 1 should hold magical number which is '143' 175 | if (EEPROM.read(1) != 143) { 176 | Serial.println(F("No Master Card Defined")); 177 | Serial.println(F("Scan A PICC to Define as Master Card")); 178 | do { 179 | successRead = getID(); // sets successRead to 1 when we get read from reader otherwise 0 180 | digitalWrite(blueLed, LED_ON); // Visualize Master Card need to be defined 181 | delay(200); 182 | digitalWrite(blueLed, LED_OFF); 183 | delay(200); 184 | } 185 | while (!successRead); // Program will not go further while you not get a successful read 186 | for ( uint8_t j = 0; j < 4; j++ ) { // Loop 4 times 187 | EEPROM.write( 2 + j, readCard[j] ); // Write scanned PICC's UID to EEPROM, start from address 3 188 | } 189 | EEPROM.write(1, 143); // Write to EEPROM we defined Master Card. 190 | Serial.println(F("Master Card Defined")); 191 | } 192 | Serial.println(F("-------------------")); 193 | Serial.println(F("Master Card's UID")); 194 | for ( uint8_t i = 0; i < 4; i++ ) { // Read Master Card's UID from EEPROM 195 | masterCard[i] = EEPROM.read(2 + i); // Write it to masterCard 196 | Serial.print(masterCard[i], HEX); 197 | } 198 | Serial.println(""); 199 | Serial.println(F("-------------------")); 200 | Serial.println(F("Everything is ready")); 201 | Serial.println(F("Waiting PICCs to be scanned")); 202 | cycleLeds(); // Everything ready lets give user some feedback by cycling leds 203 | } 204 | 205 | 206 | ///////////////////////////////////////// Main Loop /////////////////////////////////// 207 | void loop () { 208 | do { 209 | successRead = getID(); // sets successRead to 1 when we get read from reader otherwise 0 210 | // When device is in use if wipe button pressed for 10 seconds initialize Master Card wiping 211 | if (digitalRead(wipeB) == LOW) { // Check if button is pressed 212 | // Visualize normal operation is iterrupted by pressing wipe button Red is like more Warning to user 213 | digitalWrite(redLed, LED_ON); // Make sure led is off 214 | digitalWrite(greenLed, LED_OFF); // Make sure led is off 215 | digitalWrite(blueLed, LED_OFF); // Make sure led is off 216 | // Give some feedback 217 | Serial.println(F("Wipe Button Pressed")); 218 | Serial.println(F("Master Card will be Erased! in 10 seconds")); 219 | bool buttonState = monitorWipeButton(10000); // Give user enough time to cancel operation 220 | if (buttonState == true && digitalRead(wipeB) == LOW) { // If button still be pressed, wipe EEPROM 221 | EEPROM.write(1, 0); // Reset Magic Number. 222 | Serial.println(F("Master Card Erased from device")); 223 | Serial.println(F("Please reset to re-program Master Card")); 224 | while (1); 225 | } 226 | Serial.println(F("Master Card Erase Cancelled")); 227 | } 228 | if (programMode) { 229 | cycleLeds(); // Program Mode cycles through Red Green Blue waiting to read a new card 230 | } 231 | else { 232 | normalModeOn(); // Normal mode, blue Power LED is on, all others are off 233 | } 234 | } 235 | while (!successRead); //the program will not go further while you are not getting a successful read 236 | if (programMode) { 237 | if ( isMaster(readCard) ) { //When in program mode check First If master card scanned again to exit program mode 238 | Serial.println(F("Master Card Scanned")); 239 | Serial.println(F("Exiting Program Mode")); 240 | Serial.println(F("-----------------------------")); 241 | programMode = false; 242 | return; 243 | } 244 | else { 245 | if ( findID(readCard) ) { // If scanned card is known delete it 246 | Serial.println(F("I know this PICC, removing...")); 247 | deleteID(readCard); 248 | Serial.println("-----------------------------"); 249 | Serial.println(F("Scan a PICC to ADD or REMOVE to EEPROM")); 250 | } 251 | else { // If scanned card is not known add it 252 | Serial.println(F("I do not know this PICC, adding...")); 253 | writeID(readCard); 254 | Serial.println(F("-----------------------------")); 255 | Serial.println(F("Scan a PICC to ADD or REMOVE to EEPROM")); 256 | } 257 | } 258 | } 259 | else { 260 | if ( isMaster(readCard)) { // If scanned card's ID matches Master Card's ID - enter program mode 261 | programMode = true; 262 | Serial.println(F("Hello Master - Entered Program Mode")); 263 | uint8_t count = EEPROM.read(0); // Read the first Byte of EEPROM that 264 | Serial.print(F("I have ")); // stores the number of ID's in EEPROM 265 | Serial.print(count); 266 | Serial.print(F(" record(s) on EEPROM")); 267 | Serial.println(""); 268 | Serial.println(F("Scan a PICC to ADD or REMOVE to EEPROM")); 269 | Serial.println(F("Scan Master Card again to Exit Program Mode")); 270 | Serial.println(F("-----------------------------")); 271 | } 272 | else { 273 | if ( findID(readCard) ) { // If not, see if the card is in the EEPROM 274 | Serial.println(F("Welcome, You shall pass")); 275 | granted(300); // Open the door lock for 300 ms 276 | } 277 | else { // If not, show that the ID was not valid 278 | Serial.println(F("You shall not pass")); 279 | denied(); 280 | } 281 | } 282 | } 283 | } 284 | 285 | ///////////////////////////////////////// Access Granted /////////////////////////////////// 286 | void granted ( uint16_t setDelay) { 287 | digitalWrite(blueLed, LED_OFF); // Turn off blue LED 288 | digitalWrite(redLed, LED_OFF); // Turn off red LED 289 | digitalWrite(greenLed, LED_ON); // Turn on green LED 290 | digitalWrite(relay, LOW); // Unlock door! 291 | delay(setDelay); // Hold door lock open for given seconds 292 | digitalWrite(relay, HIGH); // Relock door 293 | delay(1000); // Hold green LED on for a second 294 | } 295 | 296 | ///////////////////////////////////////// Access Denied /////////////////////////////////// 297 | void denied() { 298 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 299 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 300 | digitalWrite(redLed, LED_ON); // Turn on red LED 301 | delay(1000); 302 | } 303 | 304 | 305 | ///////////////////////////////////////// Get PICC's UID /////////////////////////////////// 306 | uint8_t getID() { 307 | // Getting ready for Reading PICCs 308 | if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue 309 | return 0; 310 | } 311 | if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue 312 | return 0; 313 | } 314 | // There are Mifare PICCs which have 4 byte or 7 byte UID care if you use 7 byte PICC 315 | // I think we should assume every PICC as they have 4 byte UID 316 | // Until we support 7 byte PICCs 317 | Serial.println(F("Scanned PICC's UID:")); 318 | for ( uint8_t i = 0; i < 4; i++) { // 319 | readCard[i] = mfrc522.uid.uidByte[i]; 320 | Serial.print(readCard[i], HEX); 321 | } 322 | Serial.println(""); 323 | mfrc522.PICC_HaltA(); // Stop reading 324 | return 1; 325 | } 326 | 327 | void ShowReaderDetails() { 328 | // Get the MFRC522 software version 329 | byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 330 | Serial.print(F("MFRC522 Software Version: 0x")); 331 | Serial.print(v, HEX); 332 | if (v == 0x91) 333 | Serial.print(F(" = v1.0")); 334 | else if (v == 0x92) 335 | Serial.print(F(" = v2.0")); 336 | else 337 | Serial.print(F(" (unknown),probably a chinese clone?")); 338 | Serial.println(""); 339 | // When 0x00 or 0xFF is returned, communication probably failed 340 | if ((v == 0x00) || (v == 0xFF)) { 341 | Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); 342 | Serial.println(F("SYSTEM HALTED: Check connections.")); 343 | // Visualize system is halted 344 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 345 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 346 | digitalWrite(redLed, LED_ON); // Turn on red LED 347 | while (true); // do not go further 348 | } 349 | } 350 | 351 | ///////////////////////////////////////// Cycle Leds (Program Mode) /////////////////////////////////// 352 | void cycleLeds() { 353 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 354 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 355 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 356 | delay(200); 357 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 358 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 359 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 360 | delay(200); 361 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 362 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 363 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 364 | delay(200); 365 | } 366 | 367 | //////////////////////////////////////// Normal Mode Led /////////////////////////////////// 368 | void normalModeOn () { 369 | digitalWrite(blueLed, LED_ON); // Blue LED ON and ready to read card 370 | digitalWrite(redLed, LED_OFF); // Make sure Red LED is off 371 | digitalWrite(greenLed, LED_OFF); // Make sure Green LED is off 372 | digitalWrite(relay, HIGH); // Make sure Door is Locked 373 | } 374 | 375 | //////////////////////////////////////// Read an ID from EEPROM ////////////////////////////// 376 | void readID( uint8_t number ) { 377 | uint8_t start = (number * 4 ) + 2; // Figure out starting position 378 | for ( uint8_t i = 0; i < 4; i++ ) { // Loop 4 times to get the 4 Bytes 379 | storedCard[i] = EEPROM.read(start + i); // Assign values read from EEPROM to array 380 | } 381 | } 382 | 383 | ///////////////////////////////////////// Add ID to EEPROM /////////////////////////////////// 384 | void writeID( byte a[] ) { 385 | if ( !findID( a ) ) { // Before we write to the EEPROM, check to see if we have seen this card before! 386 | uint8_t num = EEPROM.read(0); // Get the numer of used spaces, position 0 stores the number of ID cards 387 | uint8_t start = ( num * 4 ) + 6; // Figure out where the next slot starts 388 | num++; // Increment the counter by one 389 | EEPROM.write( 0, num ); // Write the new count to the counter 390 | for ( uint8_t j = 0; j < 4; j++ ) { // Loop 4 times 391 | EEPROM.write( start + j, a[j] ); // Write the array values to EEPROM in the right position 392 | } 393 | successWrite(); 394 | Serial.println(F("Succesfully added ID record to EEPROM")); 395 | } 396 | else { 397 | failedWrite(); 398 | Serial.println(F("Failed! There is something wrong with ID or bad EEPROM")); 399 | } 400 | } 401 | 402 | ///////////////////////////////////////// Remove ID from EEPROM /////////////////////////////////// 403 | void deleteID( byte a[] ) { 404 | if ( !findID( a ) ) { // Before we delete from the EEPROM, check to see if we have this card! 405 | failedWrite(); // If not 406 | Serial.println(F("Failed! There is something wrong with ID or bad EEPROM")); 407 | } 408 | else { 409 | uint8_t num = EEPROM.read(0); // Get the numer of used spaces, position 0 stores the number of ID cards 410 | uint8_t slot; // Figure out the slot number of the card 411 | uint8_t start; // = ( num * 4 ) + 6; // Figure out where the next slot starts 412 | uint8_t looping; // The number of times the loop repeats 413 | uint8_t j; 414 | uint8_t count = EEPROM.read(0); // Read the first Byte of EEPROM that stores number of cards 415 | slot = findIDSLOT( a ); // Figure out the slot number of the card to delete 416 | start = (slot * 4) + 2; 417 | looping = ((num - slot) * 4); 418 | num--; // Decrement the counter by one 419 | EEPROM.write( 0, num ); // Write the new count to the counter 420 | for ( j = 0; j < looping; j++ ) { // Loop the card shift times 421 | EEPROM.write( start + j, EEPROM.read(start + 4 + j)); // Shift the array values to 4 places earlier in the EEPROM 422 | } 423 | for ( uint8_t k = 0; k < 4; k++ ) { // Shifting loop 424 | EEPROM.write( start + j + k, 0); 425 | } 426 | successDelete(); 427 | Serial.println(F("Succesfully removed ID record from EEPROM")); 428 | } 429 | } 430 | 431 | ///////////////////////////////////////// Check Bytes /////////////////////////////////// 432 | boolean checkTwo ( byte a[], byte b[] ) { 433 | if ( a[0] != 0 ) // Make sure there is something in the array first 434 | match = true; // Assume they match at first 435 | for ( uint8_t k = 0; k < 4; k++ ) { // Loop 4 times 436 | if ( a[k] != b[k] ) // IF a != b then set match = false, one fails, all fail 437 | match = false; 438 | } 439 | if ( match ) { // Check to see if if match is still true 440 | return true; // Return true 441 | } 442 | else { 443 | return false; // Return false 444 | } 445 | } 446 | 447 | ///////////////////////////////////////// Find Slot /////////////////////////////////// 448 | uint8_t findIDSLOT( byte find[] ) { 449 | uint8_t count = EEPROM.read(0); // Read the first Byte of EEPROM that 450 | for ( uint8_t i = 1; i <= count; i++ ) { // Loop once for each EEPROM entry 451 | readID(i); // Read an ID from EEPROM, it is stored in storedCard[4] 452 | if ( checkTwo( find, storedCard ) ) { // Check to see if the storedCard read from EEPROM 453 | // is the same as the find[] ID card passed 454 | return i; // The slot number of the card 455 | break; // Stop looking we found it 456 | } 457 | } 458 | } 459 | 460 | ///////////////////////////////////////// Find ID From EEPROM /////////////////////////////////// 461 | boolean findID( byte find[] ) { 462 | uint8_t count = EEPROM.read(0); // Read the first Byte of EEPROM that 463 | for ( uint8_t i = 1; i <= count; i++ ) { // Loop once for each EEPROM entry 464 | readID(i); // Read an ID from EEPROM, it is stored in storedCard[4] 465 | if ( checkTwo( find, storedCard ) ) { // Check to see if the storedCard read from EEPROM 466 | return true; 467 | break; // Stop looking we found it 468 | } 469 | else { // If not, return false 470 | } 471 | } 472 | return false; 473 | } 474 | 475 | ///////////////////////////////////////// Write Success to EEPROM /////////////////////////////////// 476 | // Flashes the green LED 3 times to indicate a successful write to EEPROM 477 | void successWrite() { 478 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 479 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 480 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is on 481 | delay(200); 482 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 483 | delay(200); 484 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 485 | delay(200); 486 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 487 | delay(200); 488 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 489 | delay(200); 490 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 491 | delay(200); 492 | } 493 | 494 | ///////////////////////////////////////// Write Failed to EEPROM /////////////////////////////////// 495 | // Flashes the red LED 3 times to indicate a failed write to EEPROM 496 | void failedWrite() { 497 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 498 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 499 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 500 | delay(200); 501 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 502 | delay(200); 503 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 504 | delay(200); 505 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 506 | delay(200); 507 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 508 | delay(200); 509 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 510 | delay(200); 511 | } 512 | 513 | ///////////////////////////////////////// Success Remove UID From EEPROM /////////////////////////////////// 514 | // Flashes the blue LED 3 times to indicate a success delete to EEPROM 515 | void successDelete() { 516 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 517 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 518 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 519 | delay(200); 520 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 521 | delay(200); 522 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 523 | delay(200); 524 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 525 | delay(200); 526 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 527 | delay(200); 528 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 529 | delay(200); 530 | } 531 | 532 | ////////////////////// Check readCard IF is masterCard /////////////////////////////////// 533 | // Check to see if the ID passed is the master programing card 534 | boolean isMaster( byte test[] ) { 535 | if ( checkTwo( test, masterCard ) ) 536 | return true; 537 | else 538 | return false; 539 | } 540 | 541 | bool monitorWipeButton(uint32_t interval) { 542 | uint32_t now = (uint32_t)millis(); 543 | while ((uint32_t)millis() - now < interval) { 544 | // check on every half a second 545 | if (((uint32_t)millis() % 500) == 0) { 546 | if (digitalRead(wipeB) != LOW) 547 | return false; 548 | } 549 | } 550 | return true; 551 | } 552 | -------------------------------------------------------------------------------- /examples/ChangeUID/ChangeUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example to change UID of changeable MIFARE card. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This sample shows how to set the UID on a UID changeable MIFARE card. 8 | * NOTE: for more informations read the README.rst 9 | * 10 | * @author Tom Clement 11 | * @license Released into the public domain. 12 | * 13 | * Typical pin layout used: 14 | * ----------------------------------------------------------------------------------------- 15 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 16 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 17 | * Signal Pin Pin Pin Pin Pin Pin 18 | * ----------------------------------------------------------------------------------------- 19 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 20 | * SPI SS SDA(SS) 10 53 D10 10 10 21 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 22 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 23 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 31 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 32 | 33 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 34 | MFRC522Hack mfrc522Hack(&mfrc522); // Create MFRC522Hack instance. 35 | 36 | /* Set your new UID here! */ 37 | byte newUid[] = {0xDE, 0xAD, 0xBE, 0xEF}; 38 | 39 | MFRC522::MIFARE_Key key; 40 | 41 | void setup() { 42 | Serial.begin(9600); // Initialize serial communications with the PC 43 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 44 | SPI.begin(); // Init SPI bus 45 | mfrc522.PCD_Init(); // Init MFRC522 card 46 | Serial.println(F("Warning: this example overwrites the UID of your UID changeable card, use with care!")); 47 | 48 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 49 | for (byte i = 0; i < 6; i++) { 50 | key.keyByte[i] = 0xFF; 51 | } 52 | } 53 | 54 | // Setting the UID can be as simple as this: 55 | //void loop() { 56 | // byte newUid[] = NEW_UID; 57 | // if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { 58 | // Serial.println("Wrote new UID to card."); 59 | // } 60 | // delay(1000); 61 | //} 62 | 63 | // But of course this is a more proper approach 64 | void loop() { 65 | 66 | // Look for new cards, and select one if present 67 | if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { 68 | delay(50); 69 | return; 70 | } 71 | 72 | // Now a card is selected. The UID and SAK is in mfrc522.uid. 73 | 74 | // Dump UID 75 | Serial.print(F("Card UID:")); 76 | for (byte i = 0; i < mfrc522.uid.size; i++) { 77 | Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 78 | Serial.print(mfrc522.uid.uidByte[i], HEX); 79 | } 80 | Serial.println(); 81 | 82 | // Dump PICC type 83 | // MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 84 | // Serial.print(F("PICC type: ")); 85 | // Serial.print(mfrc522.PICC_GetTypeName(piccType)); 86 | // Serial.print(F(" (SAK ")); 87 | // Serial.print(mfrc522.uid.sak); 88 | // Serial.print(")\r\n"); 89 | // if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 90 | // && piccType != MFRC522::PICC_TYPE_MIFARE_1K 91 | // && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 92 | // Serial.println(F("This sample only works with MIFARE Classic cards.")); 93 | // return; 94 | // } 95 | 96 | // Set new UID 97 | if ( mfrc522Hack.MIFARE_SetUid(newUid, (byte)4, true) ) { 98 | Serial.println(F("Wrote new UID to card.")); 99 | } 100 | 101 | // Halt PICC and re-select it so DumpToSerial doesn't get confused 102 | mfrc522.PICC_HaltA(); 103 | if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { 104 | return; 105 | } 106 | 107 | // Dump the new memory contents 108 | Serial.println(F("New UID and contents:")); 109 | mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); 110 | 111 | delay(2000); 112 | } 113 | -------------------------------------------------------------------------------- /examples/DumpInfo/DumpInfo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program showing how to read data from a PICC to serial. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID 8 | * Reader on the Arduino SPI interface. 9 | * 10 | * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE 11 | * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When 12 | * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output 13 | * will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages 14 | * when removing the PICC from reading distance too early. 15 | * 16 | * If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading). 17 | * So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all 18 | * details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so 19 | * keep the PICCs at reading distance until complete. 20 | * 21 | * @license Released into the public domain. 22 | * 23 | * Typical pin layout used: 24 | * ----------------------------------------------------------------------------------------- 25 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 26 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 27 | * Signal Pin Pin Pin Pin Pin Pin 28 | * ----------------------------------------------------------------------------------------- 29 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 30 | * SPI SS SDA(SS) 10 53 D10 10 10 31 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 32 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 33 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 34 | */ 35 | 36 | #include 37 | #include 38 | 39 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 40 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 41 | 42 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 43 | 44 | void setup() { 45 | Serial.begin(9600); // Initialize serial communications with the PC 46 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 47 | SPI.begin(); // Init SPI bus 48 | mfrc522.PCD_Init(); // Init MFRC522 49 | mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details 50 | Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks...")); 51 | } 52 | 53 | void loop() { 54 | // Look for new cards 55 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 56 | return; 57 | } 58 | 59 | // Select one of the cards 60 | if ( ! mfrc522.PICC_ReadCardSerial()) { 61 | return; 62 | } 63 | 64 | // Dump debug info about the card; PICC_HaltA() is automatically called 65 | mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); 66 | } 67 | -------------------------------------------------------------------------------- /examples/FixBrickedUID/FixBrickedUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program to fix a broken UID changeable MIFARE cards. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This sample shows how to fix a broken UID changeable MIFARE cards that have a corrupted sector 0. 8 | * 9 | * @author Tom Clement 10 | * @license Released into the public domain. 11 | * 12 | * Typical pin layout used: 13 | * ----------------------------------------------------------------------------------------- 14 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 15 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 16 | * Signal Pin Pin Pin Pin Pin Pin 17 | * ----------------------------------------------------------------------------------------- 18 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 19 | * SPI SS SDA(SS) 10 53 D10 10 10 20 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 21 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 22 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 30 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 31 | 32 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 33 | MFRC522Hack mfrc522Hack(&mfrc522); // Create MFRC522Hack instance. 34 | 35 | MFRC522::MIFARE_Key key; 36 | 37 | void setup() { 38 | Serial.begin(9600); // Initialize serial communications with the PC 39 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 40 | SPI.begin(); // Init SPI bus 41 | mfrc522.PCD_Init(); // Init MFRC522 card 42 | Serial.println(F("Warning: this example clears your mifare UID, use with care!")); 43 | 44 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 45 | for (byte i = 0; i < 6; i++) { 46 | key.keyByte[i] = 0xFF; 47 | } 48 | } 49 | 50 | void loop() { 51 | if ( mfrc522Hack.MIFARE_UnbrickUidSector(false) ) { 52 | Serial.println(F("Cleared sector 0, set UID to 1234. Card should be responsive again now.")); 53 | } 54 | delay(1000); 55 | } 56 | -------------------------------------------------------------------------------- /examples/MifareClassicValueBlock/MifareClassicValueBlock.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to setup blocks on a MIFARE Classic PICC (= card/tag) 11 | * to be in "Value Block" mode: in this mode the operations Increment/Decrement, 12 | * Restore and Transfer can be used. 13 | * 14 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 15 | * 16 | * 17 | * Typical pin layout used: 18 | * ----------------------------------------------------------------------------------------- 19 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 20 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 21 | * Signal Pin Pin Pin Pin Pin Pin 22 | * ----------------------------------------------------------------------------------------- 23 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 24 | * SPI SS SDA(SS) 10 53 D10 10 10 25 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 26 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 27 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 28 | * 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 35 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 36 | 37 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 38 | 39 | MFRC522::MIFARE_Key key; 40 | 41 | /** 42 | * Initialize. 43 | */ 44 | void setup() { 45 | Serial.begin(9600); // Initialize serial communications with the PC 46 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 47 | SPI.begin(); // Init SPI bus 48 | mfrc522.PCD_Init(); // Init MFRC522 card 49 | 50 | // Prepare the key (used both as key A and as key B) 51 | // using FFFFFFFFFFFFh which is the default at chip delivery from the factory 52 | for (byte i = 0; i < 6; i++) { 53 | key.keyByte[i] = 0xFF; 54 | } 55 | 56 | Serial.println(F("Scan a MIFARE Classic PICC to demonstrate Value Block mode.")); 57 | Serial.print(F("Using key (for A and B):")); 58 | dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); 59 | Serial.println(); 60 | 61 | Serial.println(F("BEWARE: Data will be written to the PICC, in sector #1")); 62 | } 63 | 64 | /** 65 | * Main loop. 66 | */ 67 | void loop() { 68 | // Look for new cards 69 | if ( ! mfrc522.PICC_IsNewCardPresent()) 70 | return; 71 | 72 | // Select one of the cards 73 | if ( ! mfrc522.PICC_ReadCardSerial()) 74 | return; 75 | 76 | // Show some details of the PICC (that is: the tag/card) 77 | Serial.print(F("Card UID:")); 78 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 79 | Serial.println(); 80 | Serial.print(F("PICC type: ")); 81 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 82 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 83 | 84 | // Check for compatibility 85 | if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 86 | && piccType != MFRC522::PICC_TYPE_MIFARE_1K 87 | && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 88 | Serial.println(F("This sample only works with MIFARE Classic cards.")); 89 | return; 90 | } 91 | 92 | // In this sample we use the second sector, 93 | // that is: sector #1, covering block #4 up to and including block #7 94 | byte sector = 1; 95 | byte valueBlockA = 5; 96 | byte valueBlockB = 6; 97 | byte trailerBlock = 7; 98 | MFRC522::StatusCode status; 99 | byte buffer[18]; 100 | byte size = sizeof(buffer); 101 | int32_t value; 102 | 103 | // Authenticate using key A 104 | Serial.println(F("Authenticating using key A...")); 105 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 106 | if (status != MFRC522::STATUS_OK) { 107 | Serial.print(F("PCD_Authenticate() failed: ")); 108 | Serial.println(mfrc522.GetStatusCodeName(status)); 109 | return; 110 | } 111 | 112 | // Show the whole sector as it currently is 113 | Serial.println(F("Current data in sector:")); 114 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 115 | Serial.println(); 116 | 117 | // We need a sector trailer that defines blocks 5 and 6 as Value Blocks and enables key B 118 | // The last block in a sector (block #3 for Mifare Classic 1K) is the Sector Trailer. 119 | // See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7: 120 | // Bytes 0-5: Key A 121 | // Bytes 6-8: Access Bits 122 | // Bytes 9: User data 123 | // Bytes 10-15: Key B (or user data) 124 | byte trailerBuffer[] = { 125 | 255, 255, 255, 255, 255, 255, // Keep default key A 126 | 0, 0, 0, 127 | 0, 128 | 255, 255, 255, 255, 255, 255}; // Keep default key B 129 | // The access bits are stored in a peculiar fashion. 130 | // There are four groups: 131 | // g[0] Access bits for block 0 (for sectors 0-31) 132 | // or blocks 0-4 (for sectors 32-39) 133 | // g[1] Access bits for block 1 (for sectors 0-31) 134 | // or blocks 5-9 (for sectors 32-39) 135 | // g[2] Access bits for block 2 (for sectors 0-31) 136 | // or blocks 10-14 (for sectors 32-39) 137 | // g[3] Access bits for the Sector Trailer: block 3 (for sectors 0-31) 138 | // or block 15 (for sectors 32-39) 139 | // Each group has access bits [C1 C2 C3], in this code C1 is MSB and C3 is LSB. 140 | // Determine the bit pattern needed using MIFARE_SetAccessBits: 141 | // g0=0 access bits for block 0 (of this sector) using [0 0 0] = 000b = 0 142 | // which means key A|B have r/w for block 0 of this sector 143 | // which (in this example) translates to block #4 within sector #1; 144 | // this is the transport configuration (at factory delivery). 145 | // g1=6 access bits for block 1 (of this sector) using [1 1 0] = 110b = 6 146 | // which means block 1 (of this sector) is used as a value block, 147 | // which (in this example) translates to block #5 within sector #1; 148 | // where key A|B have r, key B has w, key B can increment, 149 | // and key A|B can decrement, transfer, and restore. 150 | // g2=6 same thing for block 2 (of this sector): set it to a value block; 151 | // which (in this example) translates to block #6 within sector #1; 152 | // g3=3 access bits for block 3 (of this sector): the Sector Trailer here; 153 | // using [0 1 1] = 011b = 3 which means only key B has r/w access 154 | // to the Sector Trailer (block 3 of this sector) from now on 155 | // which (in this example) translates to block #7 within sector #1; 156 | mfrc522.MIFARE_SetAccessBits(&trailerBuffer[6], 0, 6, 6, 3); 157 | 158 | // Read the sector trailer as it is currently stored on the PICC 159 | Serial.println(F("Reading sector trailer...")); 160 | status = mfrc522.MIFARE_Read(trailerBlock, buffer, &size); 161 | if (status != MFRC522::STATUS_OK) { 162 | Serial.print(F("MIFARE_Read() failed: ")); 163 | Serial.println(mfrc522.GetStatusCodeName(status)); 164 | return; 165 | } 166 | // Check if it matches the desired access pattern already; 167 | // because if it does, we don't need to write it again... 168 | if ( buffer[6] != trailerBuffer[6] 169 | || buffer[7] != trailerBuffer[7] 170 | || buffer[8] != trailerBuffer[8]) { 171 | // They don't match (yet), so write it to the PICC 172 | Serial.println(F("Writing new sector trailer...")); 173 | status = mfrc522.MIFARE_Write(trailerBlock, trailerBuffer, 16); 174 | if (status != MFRC522::STATUS_OK) { 175 | Serial.print(F("MIFARE_Write() failed: ")); 176 | Serial.println(mfrc522.GetStatusCodeName(status)); 177 | return; 178 | } 179 | } 180 | 181 | // Authenticate using key B 182 | Serial.println(F("Authenticating again using key B...")); 183 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); 184 | if (status != MFRC522::STATUS_OK) { 185 | Serial.print(F("PCD_Authenticate() failed: ")); 186 | Serial.println(mfrc522.GetStatusCodeName(status)); 187 | return; 188 | } 189 | 190 | // A value block has a 32 bit signed value stored three times 191 | // and an 8 bit address stored 4 times. Make sure that valueBlockA 192 | // and valueBlockB have that format (note that it will only format 193 | // the block when it doesn't comply to the expected format already). 194 | formatValueBlock(valueBlockA); 195 | formatValueBlock(valueBlockB); 196 | 197 | // Add 1 to the value of valueBlockA and store the result in valueBlockA. 198 | Serial.print("Adding 1 to value of block "); Serial.println(valueBlockA); 199 | status = mfrc522.MIFARE_Increment(valueBlockA, 1); 200 | if (status != MFRC522::STATUS_OK) { 201 | Serial.print(F("MIFARE_Increment() failed: ")); 202 | Serial.println(mfrc522.GetStatusCodeName(status)); 203 | return; 204 | } 205 | status = mfrc522.MIFARE_Transfer(valueBlockA); 206 | if (status != MFRC522::STATUS_OK) { 207 | Serial.print(F("MIFARE_Transfer() failed: ")); 208 | Serial.println(mfrc522.GetStatusCodeName(status)); 209 | return; 210 | } 211 | // Show the new value of valueBlockA 212 | status = mfrc522.MIFARE_GetValue(valueBlockA, &value); 213 | if (status != MFRC522::STATUS_OK) { 214 | Serial.print(F("mifare_GetValue() failed: ")); 215 | Serial.println(mfrc522.GetStatusCodeName(status)); 216 | return; 217 | } 218 | Serial.print("New value of value block "); Serial.print(valueBlockA); 219 | Serial.print(" = "); Serial.println(value); 220 | 221 | // Decrement 10 from the value of valueBlockB and store the result in valueBlockB. 222 | Serial.print("Subtracting 10 from value of block "); Serial.println(valueBlockB); 223 | status = mfrc522.MIFARE_Decrement(valueBlockB, 10); 224 | if (status != MFRC522::STATUS_OK) { 225 | Serial.print(F("MIFARE_Decrement() failed: ")); 226 | Serial.println(mfrc522.GetStatusCodeName(status)); 227 | return; 228 | } 229 | status = mfrc522.MIFARE_Transfer(valueBlockB); 230 | if (status != MFRC522::STATUS_OK) { 231 | Serial.print(F("MIFARE_Transfer() failed: ")); 232 | Serial.println(mfrc522.GetStatusCodeName(status)); 233 | return; 234 | } 235 | // Show the new value of valueBlockB 236 | status = mfrc522.MIFARE_GetValue(valueBlockB, &value); 237 | if (status != MFRC522::STATUS_OK) { 238 | Serial.print(F("mifare_GetValue() failed: ")); 239 | Serial.println(mfrc522.GetStatusCodeName(status)); 240 | return; 241 | } 242 | Serial.print(F("New value of value block ")); Serial.print(valueBlockB); 243 | Serial.print(F(" = ")); Serial.println(value); 244 | // Check some boundary... 245 | if (value <= -100) { 246 | Serial.println(F("Below -100, so resetting it to 255 = 0xFF just for fun...")); 247 | status = mfrc522.MIFARE_SetValue(valueBlockB, 255); 248 | if (status != MFRC522::STATUS_OK) { 249 | Serial.print(F("mifare_SetValue() failed: ")); 250 | Serial.println(mfrc522.GetStatusCodeName(status)); 251 | return; 252 | } 253 | } 254 | 255 | // Dump the sector data 256 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 257 | Serial.println(); 258 | 259 | // Halt PICC 260 | mfrc522.PICC_HaltA(); 261 | // Stop encryption on PCD 262 | mfrc522.PCD_StopCrypto1(); 263 | } 264 | 265 | /** 266 | * Helper routine to dump a byte array as hex values to Serial. 267 | */ 268 | void dump_byte_array(byte *buffer, byte bufferSize) { 269 | for (byte i = 0; i < bufferSize; i++) { 270 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 271 | Serial.print(buffer[i], HEX); 272 | } 273 | } 274 | 275 | /** 276 | * Ensure that a given block is formatted as a Value Block. 277 | */ 278 | void formatValueBlock(byte blockAddr) { 279 | byte buffer[18]; 280 | byte size = sizeof(buffer); 281 | MFRC522::StatusCode status; 282 | 283 | Serial.print(F("Reading block ")); Serial.println(blockAddr); 284 | status = mfrc522.MIFARE_Read(blockAddr, buffer, &size); 285 | if (status != MFRC522::STATUS_OK) { 286 | Serial.print(F("MIFARE_Read() failed: ")); 287 | Serial.println(mfrc522.GetStatusCodeName(status)); 288 | return; 289 | } 290 | 291 | if ( (buffer[0] == (byte)~buffer[4]) 292 | && (buffer[1] == (byte)~buffer[5]) 293 | && (buffer[2] == (byte)~buffer[6]) 294 | && (buffer[3] == (byte)~buffer[7]) 295 | 296 | && (buffer[0] == buffer[8]) 297 | && (buffer[1] == buffer[9]) 298 | && (buffer[2] == buffer[10]) 299 | && (buffer[3] == buffer[11]) 300 | 301 | && (buffer[12] == (byte)~buffer[13]) 302 | && (buffer[12] == buffer[14]) 303 | && (buffer[12] == (byte)~buffer[15])) { 304 | Serial.println(F("Block has correct Value Block format.")); 305 | } 306 | else { 307 | Serial.println(F("Formatting as Value Block...")); 308 | byte valueBlock[] = { 309 | 0, 0, 0, 0, 310 | 255, 255, 255, 255, 311 | 0, 0, 0, 0, 312 | blockAddr, ~blockAddr, blockAddr, ~blockAddr }; 313 | status = mfrc522.MIFARE_Write(blockAddr, valueBlock, 16); 314 | if (status != MFRC522::STATUS_OK) { 315 | Serial.print(F("MIFARE_Write() failed: ")); 316 | Serial.println(mfrc522.GetStatusCodeName(status)); 317 | } 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /examples/MinimalInterrupt/MinimalInterrupt.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * Minimal example how to use the interrupts to read the UID of a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 3 10 22 | * IRQ ? ? ? ? 2 10 23 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 24 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 25 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 26 | * 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 33 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 34 | constexpr uint8_t IRQ_PIN = 2; // Configurable, depends on hardware 35 | 36 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 37 | 38 | MFRC522::MIFARE_Key key; 39 | 40 | volatile boolean bNewInt = false; 41 | byte regVal = 0x7F; 42 | void activateRec(MFRC522 mfrc522); 43 | void clearInt(MFRC522 mfrc522); 44 | 45 | /** 46 | * Initialize. 47 | */ 48 | void setup() { 49 | Serial.begin(115200); // Initialize serial communications with the PC 50 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 51 | SPI.begin(); // Init SPI bus 52 | 53 | mfrc522.PCD_Init(); // Init MFRC522 card 54 | 55 | /* read and printout the MFRC522 version (valid values 0x91 & 0x92)*/ 56 | Serial.print(F("Ver: 0x")); 57 | byte readReg = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 58 | Serial.println(readReg, HEX); 59 | 60 | /* setup the IRQ pin*/ 61 | pinMode(IRQ_PIN, INPUT_PULLUP); 62 | 63 | /* 64 | * Allow the ... irq to be propagated to the IRQ pin 65 | * For test purposes propagate the IdleIrq and loAlert 66 | */ 67 | regVal = 0xA0; //rx irq 68 | mfrc522.PCD_WriteRegister(mfrc522.ComIEnReg, regVal); 69 | 70 | bNewInt = false; //interrupt flag 71 | 72 | /*Activate the interrupt*/ 73 | attachInterrupt(digitalPinToInterrupt(IRQ_PIN), readCard, FALLING); 74 | 75 | do { //clear a spourious interrupt at start 76 | ; 77 | } while (!bNewInt); 78 | bNewInt = false; 79 | 80 | Serial.println(F("End setup")); 81 | } 82 | 83 | /** 84 | * Main loop. 85 | */ 86 | void loop() { 87 | if (bNewInt) { //new read interrupt 88 | Serial.print(F("Interrupt. ")); 89 | mfrc522.PICC_ReadCardSerial(); //read the tag data 90 | // Show some details of the PICC (that is: the tag/card) 91 | Serial.print(F("Card UID:")); 92 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 93 | Serial.println(); 94 | 95 | clearInt(mfrc522); 96 | mfrc522.PICC_HaltA(); 97 | bNewInt = false; 98 | } 99 | 100 | // The receiving block needs regular retriggering (tell the tag it should transmit??) 101 | // (mfrc522.PCD_WriteRegister(mfrc522.FIFODataReg,mfrc522.PICC_CMD_REQA);) 102 | activateRec(mfrc522); 103 | delay(100); 104 | } //loop() 105 | 106 | /** 107 | * Helper routine to dump a byte array as hex values to Serial. 108 | */ 109 | void dump_byte_array(byte *buffer, byte bufferSize) { 110 | for (byte i = 0; i < bufferSize; i++) { 111 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 112 | Serial.print(buffer[i], HEX); 113 | } 114 | } 115 | /** 116 | * MFRC522 interrupt serving routine 117 | */ 118 | void readCard() { 119 | bNewInt = true; 120 | } 121 | 122 | /* 123 | * The function sending to the MFRC522 the needed commands to activate the reception 124 | */ 125 | void activateRec(MFRC522 mfrc522) { 126 | mfrc522.PCD_WriteRegister(mfrc522.FIFODataReg, mfrc522.PICC_CMD_REQA); 127 | mfrc522.PCD_WriteRegister(mfrc522.CommandReg, mfrc522.PCD_Transceive); 128 | mfrc522.PCD_WriteRegister(mfrc522.BitFramingReg, 0x87); 129 | } 130 | 131 | /* 132 | * The function to clear the pending interrupt bits after interrupt serving routine 133 | */ 134 | void clearInt(MFRC522 mfrc522) { 135 | mfrc522.PCD_WriteRegister(mfrc522.ComIrqReg, 0x7F); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /examples/Ntag216_AUTH/Ntag216_AUTH.ino: -------------------------------------------------------------------------------- 1 | //This example show how you can get Authenticated by the NTAG213,215,216 by default the tags are unprotected in order to protect them we need to write 4 different values: 2 | // Using mfrc522.MIFARE_Ultralight_Write(PageNum, Data, #Databytes)) 3 | //1.- we need to write the 32bit passWord to page 0xE5 !for ntag 213 and 215 page is different refer to nxp documentation! 4 | //2.- Now Write the 16 bits pACK to the page 0xE6 use the 2 high bytes like this: pACKH + pACKL + 00 + 00 after an authentication the tag will return this secret bytes 5 | //3.- Now we need to write the first page we want to protect this is a 1 byte data in page 0xE3 we need to write 00 + 00 + 00 + firstPage all pages after this one are write protected 6 | // Now WRITE protection is ACTIVATED so we need to get authenticated in order to write the last data 7 | //4.- Finally we need to write an access record in order to READ protect the card this step is optional only if you want to read protect also write 80 + 00 + 00 + 00 to 0xE4 8 | //After completeing all these steps you will nee to authentiate first in order to read or write ant page after the first page you selected to protect 9 | //To disengage proection just write the page (0xE3) to 00 + 00 + 00 + FF that going to remove all protection 10 | //Made by GARGANTUA from RoboCreators.com & paradoxalabs.com 11 | 12 | #include 13 | #include 14 | 15 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 16 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 17 | 18 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 19 | 20 | void setup() { 21 | Serial.begin(9600); // Initialize serial communications with the PC 22 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 23 | SPI.begin(); // Init SPI bus 24 | mfrc522.PCD_Init(); // Init MFRC522 25 | Serial.println(F("Scan PICC to see UID, type, and data blocks...")); 26 | } 27 | 28 | void loop() { 29 | // Look for new cards 30 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 31 | return; 32 | } 33 | 34 | // Select one of the cards 35 | if ( ! mfrc522.PICC_ReadCardSerial()) { 36 | return; 37 | } 38 | 39 | byte PSWBuff[] = {0xFF, 0xFF, 0xFF, 0xFF}; //32 bit PassWord default FFFFFFFF 40 | byte pACK[] = {0, 0}; //16 bit PassWord ACK returned by the NFCtag 41 | 42 | Serial.print("Auth: "); 43 | Serial.println(mfrc522.PCD_NTAG216_AUTH(&PSWBuff[0], pACK)); //Request Authentification if return STATUS_OK we are good 44 | 45 | //Print PassWordACK 46 | Serial.print(pACK[0], HEX); 47 | Serial.println(pACK[1], HEX); 48 | 49 | byte WBuff[] = {0x00, 0x00, 0x00, 0x04}; 50 | byte RBuff[18]; 51 | 52 | //Serial.print("CHG BLK: "); 53 | //Serial.println(mfrc522.MIFARE_Ultralight_Write(0xE3, WBuff, 4)); //How to write to a page 54 | 55 | mfrc522.PICC_DumpMifareUltralightToSerial(); //This is a modifier dunp just cghange the for cicle to < 232 instead of < 16 in order to see all the pages on NTAG216 56 | 57 | delay(3000); 58 | } -------------------------------------------------------------------------------- /examples/RFID-Cloner/RFID-Cloner.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy the RFID card data into variables and then 3 | * scan the second empty card to copy all the date 4 | * ---------------------------------------------------------------------------- 5 | * Example sketch/program which will try the most used default keys listed in 6 | * https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys to dump the 7 | * block 0 of a MIFARE RFID card using a RFID-RC522 reader. 8 | * 9 | * Typical pin layout used: 10 | * ----------------------------------------------------------------------------------------- 11 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 12 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 13 | * Signal Pin Pin Pin Pin Pin Pin 14 | * ----------------------------------------------------------------------------------------- 15 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 16 | * SPI SS SDA(SS) 10 53 D10 10 10 17 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 18 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 19 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 27 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 28 | 29 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 30 | 31 | byte buffer[18]; 32 | byte block; 33 | byte waarde[64][16]; 34 | MFRC522::StatusCode status; 35 | 36 | MFRC522::MIFARE_Key key; 37 | 38 | // Number of known default keys (hard-coded) 39 | // NOTE: Synchronize the NR_KNOWN_KEYS define with the defaultKeys[] array 40 | constexpr uint8_t NR_KNOWN_KEYS = 8; 41 | // Known keys, see: https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys 42 | byte knownKeys[NR_KNOWN_KEYS][MFRC522::MF_KEY_SIZE] = { 43 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // FF FF FF FF FF FF = factory default 44 | {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // A0 A1 A2 A3 A4 A5 45 | {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, // B0 B1 B2 B3 B4 B5 46 | {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, // 4D 3A 99 C3 51 DD 47 | {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, // 1A 98 2C 7E 45 9A 48 | {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // D3 F7 D3 F7 D3 F7 49 | {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, // AA BB CC DD EE FF 50 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 00 00 00 00 00 00 51 | }; 52 | 53 | char choice; 54 | /* 55 | * Initialize. 56 | */ 57 | void setup() { 58 | Serial.begin(9600); // Initialize serial communications with the PC 59 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 60 | SPI.begin(); // Init SPI bus 61 | mfrc522.PCD_Init(); // Init MFRC522 card 62 | Serial.println(F("Try the most used default keys to print block 0 to 63 of a MIFARE PICC.")); 63 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 64 | 65 | for (byte i = 0; i < 6; i++) { 66 | key.keyByte[i] = 0xFF; 67 | } 68 | } 69 | 70 | 71 | 72 | //Via seriele monitor de bytes uitlezen in hexadecimaal 73 | 74 | void dump_byte_array(byte *buffer, byte bufferSize) { 75 | for (byte i = 0; i < bufferSize; i++) { 76 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 77 | Serial.print(buffer[i], HEX); 78 | } 79 | } 80 | //Via seriele monitor de bytes uitlezen in ASCI 81 | 82 | void dump_byte_array1(byte *buffer, byte bufferSize) { 83 | for (byte i = 0; i < bufferSize; i++) { 84 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 85 | Serial.write(buffer[i]); 86 | } 87 | } 88 | 89 | /* 90 | * Try using the PICC (the tag/card) with the given key to access block 0 to 63. 91 | * On success, it will show the key details, and dump the block data on Serial. 92 | * 93 | * @return true when the given key worked, false otherwise. 94 | */ 95 | 96 | boolean try_key(MFRC522::MIFARE_Key *key) 97 | { 98 | boolean result = false; 99 | 100 | for(byte block = 0; block < 64; block++){ 101 | 102 | // Serial.println(F("Authenticating using key A...")); 103 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, key, &(mfrc522.uid)); 104 | if (status != MFRC522::STATUS_OK) { 105 | Serial.print(F("PCD_Authenticate() failed: ")); 106 | Serial.println(mfrc522.GetStatusCodeName(status)); 107 | return false; 108 | } 109 | 110 | // Read block 111 | byte byteCount = sizeof(buffer); 112 | status = mfrc522.MIFARE_Read(block, buffer, &byteCount); 113 | if (status != MFRC522::STATUS_OK) { 114 | Serial.print(F("MIFARE_Read() failed: ")); 115 | Serial.println(mfrc522.GetStatusCodeName(status)); 116 | } 117 | else { 118 | // Successful read 119 | result = true; 120 | Serial.print(F("Success with key:")); 121 | dump_byte_array((*key).keyByte, MFRC522::MF_KEY_SIZE); 122 | Serial.println(); 123 | 124 | // Dump block data 125 | Serial.print(F("Block ")); Serial.print(block); Serial.print(F(":")); 126 | dump_byte_array1(buffer, 16); //omzetten van hex naar ASCI 127 | Serial.println(); 128 | 129 | for (int p = 0; p < 16; p++) //De 16 bits uit de block uitlezen 130 | { 131 | waarde [block][p] = buffer[p]; 132 | Serial.print(waarde[block][p]); 133 | Serial.print(" "); 134 | } 135 | 136 | } 137 | } 138 | Serial.println(); 139 | 140 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 141 | 142 | mfrc522.PICC_HaltA(); // Halt PICC 143 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 144 | return result; 145 | 146 | start(); 147 | } 148 | 149 | /* 150 | * Main loop. 151 | */ 152 | void loop() { 153 | start(); 154 | 155 | } 156 | 157 | void start(){ 158 | choice = Serial.read(); 159 | 160 | if(choice == '1') 161 | { 162 | Serial.println("Read the card"); 163 | keuze1(); 164 | 165 | } 166 | else if(choice == '2') 167 | { 168 | Serial.println("See what is in the variables"); 169 | keuze2(); 170 | } 171 | else if(choice == '3') 172 | { 173 | Serial.println("Copying the data on to the new card"); 174 | keuze3(); 175 | } 176 | } 177 | 178 | void keuze2(){ //Test waardes in blokken 179 | 180 | for(block = 4; block <= 62; block++){ 181 | if(block == 7 || block == 11 || block == 15 || block == 19 || block == 23 || block == 27 || block == 31 || block == 35 || block == 39 || block == 43 || block == 47 || block == 51 || block == 55 || block == 59){ 182 | block ++; 183 | } 184 | 185 | Serial.print(F("Writing data into block ")); 186 | Serial.print(block); 187 | Serial.println("\n"); 188 | 189 | for(int j = 0; j < 16; j++){ 190 | Serial.print(waarde[block][j]); 191 | Serial.print(" "); 192 | } 193 | Serial.println("\n"); 194 | 195 | } 196 | 197 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 198 | start(); 199 | } 200 | 201 | void keuze3(){ //Copy the data in the new card 202 | Serial.println("Insert new card..."); 203 | // Look for new cards 204 | if ( ! mfrc522.PICC_IsNewCardPresent()) 205 | return; 206 | 207 | // Select one of the cards 208 | if ( ! mfrc522.PICC_ReadCardSerial()) 209 | return; 210 | 211 | // Show some details of the PICC (that is: the tag/card) 212 | Serial.print(F("Card UID:")); 213 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 214 | Serial.println(); 215 | Serial.print(F("PICC type: ")); 216 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 217 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 218 | 219 | // Try the known default keys 220 | /*MFRC522::MIFARE_Key key; 221 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 222 | // Copy the known key into the MIFARE_Key structure 223 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 224 | key.keyByte[i] = knownKeys[k][i]; 225 | } 226 | }*/ 227 | for (byte i = 0; i < 6; i++) { 228 | key.keyByte[i] = 0xFF; 229 | } 230 | 231 | for(int i = 4; i <= 62; i++){ //De blocken 4 tot 62 kopieren, behalve al deze onderstaande blocken (omdat deze de authenticatie blokken zijn) 232 | if(i == 7 || i == 11 || i == 15 || i == 19 || i == 23 || i == 27 || i == 31 || i == 35 || i == 39 || i == 43 || i == 47 || i == 51 || i == 55 || i == 59){ 233 | i++; 234 | } 235 | block = i; 236 | 237 | // Authenticate using key A 238 | Serial.println(F("Authenticating using key A...")); 239 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 240 | if (status != MFRC522::STATUS_OK) { 241 | Serial.print(F("PCD_Authenticate() failed: ")); 242 | Serial.println(mfrc522.GetStatusCodeName(status)); 243 | return; 244 | } 245 | 246 | // Authenticate using key B 247 | Serial.println(F("Authenticating again using key B...")); 248 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, block, &key, &(mfrc522.uid)); 249 | if (status != MFRC522::STATUS_OK) { 250 | Serial.print(F("PCD_Authenticate() failed: ")); 251 | Serial.println(mfrc522.GetStatusCodeName(status)); 252 | return; 253 | } 254 | 255 | // Write data to the block 256 | Serial.print(F("Writing data into block ")); 257 | Serial.print(block); 258 | Serial.println("\n"); 259 | 260 | dump_byte_array(waarde[block], 16); 261 | 262 | 263 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(block, waarde[block], 16); 264 | if (status != MFRC522::STATUS_OK) { 265 | Serial.print(F("MIFARE_Write() failed: ")); 266 | Serial.println(mfrc522.GetStatusCodeName(status)); 267 | } 268 | 269 | 270 | Serial.println("\n"); 271 | 272 | } 273 | mfrc522.PICC_HaltA(); // Halt PICC 274 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 275 | 276 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 277 | start(); 278 | } 279 | 280 | void keuze1(){ //Read card 281 | Serial.println("Insert card..."); 282 | // Look for new cards 283 | if ( ! mfrc522.PICC_IsNewCardPresent()) 284 | return; 285 | 286 | // Select one of the cards 287 | if ( ! mfrc522.PICC_ReadCardSerial()) 288 | return; 289 | 290 | // Show some details of the PICC (that is: the tag/card) 291 | Serial.print(F("Card UID:")); 292 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 293 | Serial.println(); 294 | Serial.print(F("PICC type: ")); 295 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 296 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 297 | 298 | // Try the known default keys 299 | MFRC522::MIFARE_Key key; 300 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 301 | // Copy the known key into the MIFARE_Key structure 302 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 303 | key.keyByte[i] = knownKeys[k][i]; 304 | } 305 | // Try the key 306 | if (try_key(&key)) { 307 | // Found and reported on the key and block, 308 | // no need to try other keys for this PICC 309 | break; 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /examples/ReadAndWrite/ReadAndWrite.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to read and write data blocks on a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 14 | * 15 | * 16 | * Typical pin layout used: 17 | * ----------------------------------------------------------------------------------------- 18 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 19 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 20 | * Signal Pin Pin Pin Pin Pin Pin 21 | * ----------------------------------------------------------------------------------------- 22 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 23 | * SPI SS SDA(SS) 10 53 D10 10 10 24 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 25 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 26 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 27 | * 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 34 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 35 | 36 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 37 | 38 | MFRC522::MIFARE_Key key; 39 | 40 | /** 41 | * Initialize. 42 | */ 43 | void setup() { 44 | Serial.begin(9600); // Initialize serial communications with the PC 45 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 46 | SPI.begin(); // Init SPI bus 47 | mfrc522.PCD_Init(); // Init MFRC522 card 48 | 49 | // Prepare the key (used both as key A and as key B) 50 | // using FFFFFFFFFFFFh which is the default at chip delivery from the factory 51 | for (byte i = 0; i < 6; i++) { 52 | key.keyByte[i] = 0xFF; 53 | } 54 | 55 | Serial.println(F("Scan a MIFARE Classic PICC to demonstrate read and write.")); 56 | Serial.print(F("Using key (for A and B):")); 57 | dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); 58 | Serial.println(); 59 | 60 | Serial.println(F("BEWARE: Data will be written to the PICC, in sector #1")); 61 | } 62 | 63 | /** 64 | * Main loop. 65 | */ 66 | void loop() { 67 | // Look for new cards 68 | if ( ! mfrc522.PICC_IsNewCardPresent()) 69 | return; 70 | 71 | // Select one of the cards 72 | if ( ! mfrc522.PICC_ReadCardSerial()) 73 | return; 74 | 75 | // Show some details of the PICC (that is: the tag/card) 76 | Serial.print(F("Card UID:")); 77 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 78 | Serial.println(); 79 | Serial.print(F("PICC type: ")); 80 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 81 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 82 | 83 | // Check for compatibility 84 | if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 85 | && piccType != MFRC522::PICC_TYPE_MIFARE_1K 86 | && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 87 | Serial.println(F("This sample only works with MIFARE Classic cards.")); 88 | return; 89 | } 90 | 91 | // In this sample we use the second sector, 92 | // that is: sector #1, covering block #4 up to and including block #7 93 | byte sector = 1; 94 | byte blockAddr = 4; 95 | byte dataBlock[] = { 96 | 0x01, 0x02, 0x03, 0x04, // 1, 2, 3, 4, 97 | 0x05, 0x06, 0x07, 0x08, // 5, 6, 7, 8, 98 | 0x08, 0x09, 0xff, 0x0b, // 9, 10, 255, 12, 99 | 0x0c, 0x0d, 0x0e, 0x0f // 13, 14, 15, 16 100 | }; 101 | byte trailerBlock = 7; 102 | MFRC522::StatusCode status; 103 | byte buffer[18]; 104 | byte size = sizeof(buffer); 105 | 106 | // Authenticate using key A 107 | Serial.println(F("Authenticating using key A...")); 108 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 109 | if (status != MFRC522::STATUS_OK) { 110 | Serial.print(F("PCD_Authenticate() failed: ")); 111 | Serial.println(mfrc522.GetStatusCodeName(status)); 112 | return; 113 | } 114 | 115 | // Show the whole sector as it currently is 116 | Serial.println(F("Current data in sector:")); 117 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 118 | Serial.println(); 119 | 120 | // Read data from the block 121 | Serial.print(F("Reading data from block ")); Serial.print(blockAddr); 122 | Serial.println(F(" ...")); 123 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size); 124 | if (status != MFRC522::STATUS_OK) { 125 | Serial.print(F("MIFARE_Read() failed: ")); 126 | Serial.println(mfrc522.GetStatusCodeName(status)); 127 | } 128 | Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":")); 129 | dump_byte_array(buffer, 16); Serial.println(); 130 | Serial.println(); 131 | 132 | // Authenticate using key B 133 | Serial.println(F("Authenticating again using key B...")); 134 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); 135 | if (status != MFRC522::STATUS_OK) { 136 | Serial.print(F("PCD_Authenticate() failed: ")); 137 | Serial.println(mfrc522.GetStatusCodeName(status)); 138 | return; 139 | } 140 | 141 | // Write data to the block 142 | Serial.print(F("Writing data into block ")); Serial.print(blockAddr); 143 | Serial.println(F(" ...")); 144 | dump_byte_array(dataBlock, 16); Serial.println(); 145 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16); 146 | if (status != MFRC522::STATUS_OK) { 147 | Serial.print(F("MIFARE_Write() failed: ")); 148 | Serial.println(mfrc522.GetStatusCodeName(status)); 149 | } 150 | Serial.println(); 151 | 152 | // Read data from the block (again, should now be what we have written) 153 | Serial.print(F("Reading data from block ")); Serial.print(blockAddr); 154 | Serial.println(F(" ...")); 155 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size); 156 | if (status != MFRC522::STATUS_OK) { 157 | Serial.print(F("MIFARE_Read() failed: ")); 158 | Serial.println(mfrc522.GetStatusCodeName(status)); 159 | } 160 | Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":")); 161 | dump_byte_array(buffer, 16); Serial.println(); 162 | 163 | // Check that data in block is what we have written 164 | // by counting the number of bytes that are equal 165 | Serial.println(F("Checking result...")); 166 | byte count = 0; 167 | for (byte i = 0; i < 16; i++) { 168 | // Compare buffer (= what we've read) with dataBlock (= what we've written) 169 | if (buffer[i] == dataBlock[i]) 170 | count++; 171 | } 172 | Serial.print(F("Number of bytes that match = ")); Serial.println(count); 173 | if (count == 16) { 174 | Serial.println(F("Success :-)")); 175 | } else { 176 | Serial.println(F("Failure, no match :-(")); 177 | Serial.println(F(" perhaps the write didn't work properly...")); 178 | } 179 | Serial.println(); 180 | 181 | // Dump the sector data 182 | Serial.println(F("Current data in sector:")); 183 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 184 | Serial.println(); 185 | 186 | // Halt PICC 187 | mfrc522.PICC_HaltA(); 188 | // Stop encryption on PCD 189 | mfrc522.PCD_StopCrypto1(); 190 | } 191 | 192 | /** 193 | * Helper routine to dump a byte array as hex values to Serial. 194 | */ 195 | void dump_byte_array(byte *buffer, byte bufferSize) { 196 | for (byte i = 0; i < bufferSize; i++) { 197 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 198 | Serial.print(buffer[i], HEX); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /examples/ReadNUID/ReadNUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program showing how to read new NUID from a PICC to serial. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * Example sketch/program showing how to the read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID 8 | * Reader on the Arduino SPI interface. 9 | * 10 | * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE 11 | * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When 12 | * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output 13 | * will show the type, and the NUID if a new card has been detected. Note: you may see "Timeout in communication" messages 14 | * when removing the PICC from reading distance too early. 15 | * 16 | * @license Released into the public domain. 17 | * 18 | * Typical pin layout used: 19 | * ----------------------------------------------------------------------------------------- 20 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 21 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 22 | * Signal Pin Pin Pin Pin Pin Pin 23 | * ----------------------------------------------------------------------------------------- 24 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 25 | * SPI SS SDA(SS) 10 53 D10 10 10 26 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 27 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 28 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 35 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 36 | 37 | MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class 38 | 39 | MFRC522::MIFARE_Key key; 40 | 41 | // Init array that will store new NUID 42 | byte nuidPICC[4]; 43 | 44 | void setup() { 45 | Serial.begin(9600); 46 | SPI.begin(); // Init SPI bus 47 | rfid.PCD_Init(); // Init MFRC522 48 | 49 | for (byte i = 0; i < 6; i++) { 50 | key.keyByte[i] = 0xFF; 51 | } 52 | 53 | Serial.println(F("This code scan the MIFARE Classsic NUID.")); 54 | Serial.print(F("Using the following key:")); 55 | printHex(key.keyByte, MFRC522::MF_KEY_SIZE); 56 | } 57 | 58 | void loop() { 59 | 60 | // Look for new cards 61 | if ( ! rfid.PICC_IsNewCardPresent()) 62 | return; 63 | 64 | // Verify if the NUID has been readed 65 | if ( ! rfid.PICC_ReadCardSerial()) 66 | return; 67 | 68 | Serial.print(F("PICC type: ")); 69 | MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak); 70 | Serial.println(rfid.PICC_GetTypeName(piccType)); 71 | 72 | // Check is the PICC of Classic MIFARE type 73 | if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && 74 | piccType != MFRC522::PICC_TYPE_MIFARE_1K && 75 | piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 76 | Serial.println(F("Your tag is not of type MIFARE Classic.")); 77 | return; 78 | } 79 | 80 | if (rfid.uid.uidByte[0] != nuidPICC[0] || 81 | rfid.uid.uidByte[1] != nuidPICC[1] || 82 | rfid.uid.uidByte[2] != nuidPICC[2] || 83 | rfid.uid.uidByte[3] != nuidPICC[3] ) { 84 | Serial.println(F("A new card has been detected.")); 85 | 86 | // Store NUID into nuidPICC array 87 | for (byte i = 0; i < 4; i++) { 88 | nuidPICC[i] = rfid.uid.uidByte[i]; 89 | } 90 | 91 | Serial.println(F("The NUID tag is:")); 92 | Serial.print(F("In hex: ")); 93 | printHex(rfid.uid.uidByte, rfid.uid.size); 94 | Serial.println(); 95 | Serial.print(F("In dec: ")); 96 | printDec(rfid.uid.uidByte, rfid.uid.size); 97 | Serial.println(); 98 | } 99 | else Serial.println(F("Card read previously.")); 100 | 101 | // Halt PICC 102 | rfid.PICC_HaltA(); 103 | 104 | // Stop encryption on PCD 105 | rfid.PCD_StopCrypto1(); 106 | } 107 | 108 | 109 | /** 110 | * Helper routine to dump a byte array as hex values to Serial. 111 | */ 112 | void printHex(byte *buffer, byte bufferSize) { 113 | for (byte i = 0; i < bufferSize; i++) { 114 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 115 | Serial.print(buffer[i], HEX); 116 | } 117 | } 118 | 119 | /** 120 | * Helper routine to dump a byte array as dec values to Serial. 121 | */ 122 | void printDec(byte *buffer, byte bufferSize) { 123 | for (byte i = 0; i < bufferSize; i++) { 124 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 125 | Serial.print(buffer[i], DEC); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /examples/ReadUidMultiReader/ReadUidMultiReader.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program showing how to read data from more than one PICC to serial. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * Example sketch/program showing how to read data from more than one PICC (that is: a RFID Tag or Card) using a 8 | * MFRC522 based RFID Reader on the Arduino SPI interface. 9 | * 10 | * Warning: This may not work! Multiple devices at one SPI are difficult and cause many trouble!! Engineering skill 11 | * and knowledge are required! 12 | * 13 | * @license Released into the public domain. 14 | * 15 | * Typical pin layout used: 16 | * ----------------------------------------------------------------------------------------- 17 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 18 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 19 | * Signal Pin Pin Pin Pin Pin Pin 20 | * ----------------------------------------------------------------------------------------- 21 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 22 | * SPI SS 1 SDA(SS) ** custom, take a unused pin, only HIGH/LOW required ** 23 | * SPI SS 2 SDA(SS) ** custom, take a unused pin, only HIGH/LOW required ** 24 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 25 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 26 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 27 | * 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 34 | constexpr uint8_t SS_1_PIN = 10; // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 2 35 | constexpr uint8_t SS_2_PIN = 8; // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 1 36 | 37 | constexpr uint8_t NR_OF_READERS = 2; 38 | 39 | byte ssPins[] = {SS_1_PIN, SS_2_PIN}; 40 | 41 | MFRC522 mfrc522[NR_OF_READERS]; // Create MFRC522 instance. 42 | 43 | /** 44 | * Initialize. 45 | */ 46 | void setup() { 47 | 48 | Serial.begin(9600); // Initialize serial communications with the PC 49 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 50 | 51 | SPI.begin(); // Init SPI bus 52 | 53 | for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { 54 | mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN); // Init each MFRC522 card 55 | Serial.print(F("Reader ")); 56 | Serial.print(reader); 57 | Serial.print(F(": ")); 58 | mfrc522[reader].PCD_DumpVersionToSerial(); 59 | } 60 | } 61 | 62 | /** 63 | * Main loop. 64 | */ 65 | void loop() { 66 | 67 | for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { 68 | // Look for new cards 69 | 70 | if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) { 71 | Serial.print(F("Reader ")); 72 | Serial.print(reader); 73 | // Show some details of the PICC (that is: the tag/card) 74 | Serial.print(F(": Card UID:")); 75 | dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size); 76 | Serial.println(); 77 | Serial.print(F("PICC type: ")); 78 | MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak); 79 | Serial.println(mfrc522[reader].PICC_GetTypeName(piccType)); 80 | 81 | // Halt PICC 82 | mfrc522[reader].PICC_HaltA(); 83 | // Stop encryption on PCD 84 | mfrc522[reader].PCD_StopCrypto1(); 85 | } //if (mfrc522[reader].PICC_IsNewC 86 | } //for(uint8_t reader 87 | } 88 | 89 | /** 90 | * Helper routine to dump a byte array as hex values to Serial. 91 | */ 92 | void dump_byte_array(byte *buffer, byte bufferSize) { 93 | for (byte i = 0; i < bufferSize; i++) { 94 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 95 | Serial.print(buffer[i], HEX); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/firmware_check/firmware_check.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program to test your firmware. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This example test the firmware of your MFRC522 reader module, only known version can be checked. If the test passed 8 | * it do not mean that your module is faultless! Some modules have bad or broken antennas or the PICC is broken. 9 | * NOTE: for more informations read the README.rst 10 | * 11 | * @author Rotzbua 12 | * @license Released into the public domain. 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 10 10 22 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 23 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 24 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 31 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 32 | 33 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 34 | 35 | /** 36 | * Check firmware only once at startup 37 | */ 38 | void setup() { 39 | Serial.begin(9600); // Initialize serial communications with the PC 40 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 41 | SPI.begin(); // Init SPI bus 42 | mfrc522.PCD_Init(); // Init MFRC522 module 43 | 44 | Serial.println(F("*****************************")); 45 | Serial.println(F("MFRC522 Digital self test")); 46 | Serial.println(F("*****************************")); 47 | mfrc522.PCD_DumpVersionToSerial(); // Show version of PCD - MFRC522 Card Reader 48 | Serial.println(F("-----------------------------")); 49 | Serial.println(F("Only known versions supported")); 50 | Serial.println(F("-----------------------------")); 51 | Serial.println(F("Performing test...")); 52 | bool result = mfrc522.PCD_PerformSelfTest(); // perform the test 53 | Serial.println(F("-----------------------------")); 54 | Serial.print(F("Result: ")); 55 | if (result) 56 | Serial.println(F("OK")); 57 | else 58 | Serial.println(F("DEFECT or UNKNOWN")); 59 | Serial.println(); 60 | } 61 | 62 | void loop() {} // nothing to do 63 | -------------------------------------------------------------------------------- /examples/readPBOC/readPBOC.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to read and write data blocks on a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 14 | * 15 | * 16 | * Typical pin layout used: 17 | * ----------------------------------------------------------------------------------------- 18 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 19 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 20 | * Signal Pin Pin Pin Pin Pin Pin 21 | * ----------------------------------------------------------------------------------------- 22 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 23 | * SPI SS SDA(SS) 10 53 D10 10 10 24 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 25 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 26 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 27 | * 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 36 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 37 | 38 | PBOC pboc(SS_PIN, RST_PIN); // Create MFRC522 instance. 39 | PBOC::ADFS adfs; 40 | PBOC::PSE_FCI fci; 41 | 42 | /** 43 | * Initialize. 44 | */ 45 | void setup() { 46 | Serial.begin(9600); // Initialize serial communications with the PC 47 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 48 | SPI.begin(); // Init SPI bus 49 | pboc.init(); 50 | } 51 | 52 | /** 53 | * Main loop. 54 | */ 55 | void loop(){ 56 | if(!pboc.active()) return; 57 | pboc.printUID(); 58 | pboc.tag.blockNumber = false; 59 | pboc.tag.ats.tc1.supportsCID = false; 60 | pboc.tag.ats.tc1.supportsNAD = false; 61 | // Serial.print(pboc.base.PCD_ReadRegister(pboc.base.TxModeReg), HEX); 62 | PBOC::Respond res = pboc.select(strlen(PBOC::PSE), PBOC::PSE); 63 | while(res.status != MFRC522::STATUS_OK){ 64 | Serial.print(F("Select Failed!")); 65 | Serial.println(MFRC522::GetStatusCodeName(res.status)); 66 | return ; 67 | } 68 | if(!fci.init(res.len, res.info)) return; 69 | //read record 70 | byte * buf1 = res.info; 71 | res = pboc.readRecord(fci.sfi, 0x01); 72 | pboc.pool.release(buf1);//release buf storing respond of select 73 | // Serial.print(F("ADFS:")); 74 | // dump_byte_array(res.info, res.len); 75 | if (!adfs.init(res.len, res.info)) return ; 76 | Serial.println(); 77 | Serial.print(F("AID:")); 78 | dump_byte_array((byte *)(adfs.l[0].aid.data()), (byte)(adfs.l[0].aid.len())); 79 | Serial.println(); 80 | Serial.print(F("LABEL:")); 81 | Serial.write(adfs.l[0].apn.data(), adfs.l[0].apn.len()); 82 | Serial.println(); 83 | buf1 = res.info; 84 | res = pboc.select(adfs.l[0].aid.len(), adfs.l[0].aid.data()); 85 | while(res.status != MFRC522::STATUS_OK){ 86 | Serial.print(F("Select APP Failed!")); 87 | Serial.println(MFRC522::GetStatusCodeName(res.status)); 88 | pboc.pool.release(buf1); 89 | return; 90 | } 91 | pboc.pool.release(buf1); 92 | // Serial.print(F("Received:")); 93 | // dump_byte_array(res.info, res.len); 94 | pboc.pool.release(res.info); 95 | Serial.println(); 96 | 97 | 98 | // byte gpo_data[] = {0x60, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, 99 | // 0x56,0x00,0x00,0x00,0x00,0x00,0x01,0x56,0x13,0x09,0x25,0x00,0x00,0x00,0x00,0x00}; 100 | // res = pboc.gpo(sizeof(gpo_data), gpo_data); 101 | 102 | byte meta_sfi_addr[] = {0x1, 0x1}; 103 | tlv meta_sfi(meta_sfi_addr); 104 | res = pboc.readRecord(meta_sfi, 0x1); 105 | // printStatus(res); 106 | Serial.print(F("银行卡号:")); 107 | int t = printUntil(res.info + 4, 0xD) + 1; 108 | Serial.println(); 109 | Serial.print(F("有效日期至:20")); 110 | t = printHalfBytes(res.info + 4, t, 2); 111 | Serial.print(F("年")); 112 | t = printHalfBytes(res.info + 4, t, 2); 113 | Serial.println(F("月")); 114 | pboc.pool.release(res.info); 115 | 116 | // res = pboc.readRecord(meta_sfi, 0x2); //可能有姓名等,不同银行差别较大 6A83说明无此记录 117 | // printStatus(res); 118 | // dump_byte_array(res.info, res.len); 119 | // pboc.pool.release(res.info); 120 | 121 | 122 | res = pboc.getData(0x9F, 0x79); 123 | // printStatus(res); 124 | Serial.print(F("金额:")); 125 | t = printHalfBytes(res.info + 3, 0, 10); 126 | Serial.print("."); 127 | t = printHalfBytes(res.info + 3, t, 2); 128 | Serial.println(F("元 ")); 129 | pboc.pool.release(res.info); 130 | 131 | res = pboc.getData(0x9F, 0x4F); 132 | // dump_byte_array(res.info, res.len);//按标准应该是9A 03 9F 21 03 9F 02 06 9F 03 06 9F 1A 02 5F 2A 02 9F 4E 14 9C 01 9F 36 02 133 | // "日期 时间 授权金额 其他金额 终端国家代码 货币类型 商户名称 交易类型 应用交易计数器" 134 | Serial.println(F("日期 时间 授权金额 商户名称"));//更准确应该按照上边读出来的 135 | pboc.pool.release(res.info); 136 | 137 | byte rec_sfi_addr[] = {0x1, 0xB}; 138 | for(byte i = 1;i <= 10;i++){ 139 | tlv rec_sfi(rec_sfi_addr); 140 | res = pboc.readRecord(rec_sfi, i); 141 | // printStatus(res); 142 | if(res.sw1 != 0x90 || res.sw2 != 0x00){ 143 | Serial.println("没有其他交易记录!"); 144 | pboc.pool.release(res.info); 145 | break; 146 | } 147 | // dump_byte_array(res.info, res.len); 148 | int t = 0; 149 | Serial.print("20"); 150 | t = printHalfBytes(res.info, t, 2); 151 | Serial.print(F("年")); 152 | t = printHalfBytes(res.info, t, 2); 153 | Serial.print(F("月")); 154 | t = printHalfBytes(res.info, t, 2); 155 | Serial.print("日 "); 156 | t = printHalfBytes(res.info, t, 2); 157 | Serial.print(":"); 158 | t = printHalfBytes(res.info, t, 2); 159 | Serial.print(":"); 160 | t = printHalfBytes(res.info, t, 2); 161 | Serial.print(" "); 162 | 163 | if(res.info[t/2 + 6 * 2 + 2 * 2 + 20] <= 0x1) Serial.print("-"); 164 | else if(res.info[t/2 + 6 * 2 + 2 * 2 + 20] == 0x21) Serial.print("+"); 165 | t = printHalfBytes(res.info, t, 10); 166 | Serial.print("."); 167 | t = printHalfBytes(res.info, t, 2); 168 | Serial.print(F("元 ")); 169 | 170 | t += (6 + 2 + 2) * 2; 171 | 172 | Serial.write(res.info + t / 2, 20); 173 | Serial.println(); 174 | pboc.pool.release(res.info); 175 | } 176 | pboc.halt(); 177 | Serial.println(); 178 | Serial.println(F("End a loop")); 179 | } 180 | void printStatus(PBOC::Respond& res){ 181 | Serial.print("Respond Status:"); 182 | Serial.print(MFRC522::GetStatusCodeName(res.status)); 183 | Serial.print(res.sw1 < 0x10 ? " 0" : " "); 184 | Serial.print(res.sw1, HEX); 185 | Serial.print(res.sw2 < 0x10 ? " 0" : " "); 186 | Serial.print(res.sw2, HEX); 187 | Serial.println(); 188 | } 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /examples/readPBOC/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sleepychord/pboc-arduino/ec10aac0556e197dd836b94142f71bf1ad99ab17/examples/readPBOC/result.png -------------------------------------------------------------------------------- /examples/rfid_default_keys/rfid_default_keys.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * Example sketch/program which will try the most used default keys listed in 11 | * https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys to dump the 12 | * block 0 of a MIFARE RFID card using a RFID-RC522 reader. 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 10 10 22 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 23 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 24 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 32 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 33 | 34 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 35 | 36 | // Number of known default keys (hard-coded) 37 | // NOTE: Synchronize the NR_KNOWN_KEYS define with the defaultKeys[] array 38 | constexpr uint8_t NR_KNOWN_KEYS = 8; 39 | // Known keys, see: https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys 40 | byte knownKeys[NR_KNOWN_KEYS][MFRC522::MF_KEY_SIZE] = { 41 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // FF FF FF FF FF FF = factory default 42 | {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // A0 A1 A2 A3 A4 A5 43 | {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, // B0 B1 B2 B3 B4 B5 44 | {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, // 4D 3A 99 C3 51 DD 45 | {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, // 1A 98 2C 7E 45 9A 46 | {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // D3 F7 D3 F7 D3 F7 47 | {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, // AA BB CC DD EE FF 48 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 00 00 00 00 00 00 49 | }; 50 | 51 | /* 52 | * Initialize. 53 | */ 54 | void setup() { 55 | Serial.begin(9600); // Initialize serial communications with the PC 56 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 57 | SPI.begin(); // Init SPI bus 58 | mfrc522.PCD_Init(); // Init MFRC522 card 59 | Serial.println(F("Try the most used default keys to print block 0 of a MIFARE PICC.")); 60 | } 61 | 62 | /* 63 | * Helper routine to dump a byte array as hex values to Serial. 64 | */ 65 | void dump_byte_array(byte *buffer, byte bufferSize) { 66 | for (byte i = 0; i < bufferSize; i++) { 67 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 68 | Serial.print(buffer[i], HEX); 69 | } 70 | } 71 | 72 | /* 73 | * Try using the PICC (the tag/card) with the given key to access block 0. 74 | * On success, it will show the key details, and dump the block data on Serial. 75 | * 76 | * @return true when the given key worked, false otherwise. 77 | */ 78 | boolean try_key(MFRC522::MIFARE_Key *key) 79 | { 80 | boolean result = false; 81 | byte buffer[18]; 82 | byte block = 0; 83 | MFRC522::StatusCode status; 84 | 85 | // http://arduino.stackexchange.com/a/14316 86 | if ( ! mfrc522.PICC_IsNewCardPresent()) 87 | return false; 88 | if ( ! mfrc522.PICC_ReadCardSerial()) 89 | return false; 90 | // Serial.println(F("Authenticating using key A...")); 91 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, key, &(mfrc522.uid)); 92 | if (status != MFRC522::STATUS_OK) { 93 | // Serial.print(F("PCD_Authenticate() failed: ")); 94 | // Serial.println(mfrc522.GetStatusCodeName(status)); 95 | return false; 96 | } 97 | 98 | // Read block 99 | byte byteCount = sizeof(buffer); 100 | status = mfrc522.MIFARE_Read(block, buffer, &byteCount); 101 | if (status != MFRC522::STATUS_OK) { 102 | // Serial.print(F("MIFARE_Read() failed: ")); 103 | // Serial.println(mfrc522.GetStatusCodeName(status)); 104 | } 105 | else { 106 | // Successful read 107 | result = true; 108 | Serial.print(F("Success with key:")); 109 | dump_byte_array((*key).keyByte, MFRC522::MF_KEY_SIZE); 110 | Serial.println(); 111 | // Dump block data 112 | Serial.print(F("Block ")); Serial.print(block); Serial.print(F(":")); 113 | dump_byte_array(buffer, 16); 114 | Serial.println(); 115 | } 116 | Serial.println(); 117 | 118 | mfrc522.PICC_HaltA(); // Halt PICC 119 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 120 | return result; 121 | } 122 | 123 | /* 124 | * Main loop. 125 | */ 126 | void loop() { 127 | // Look for new cards 128 | if ( ! mfrc522.PICC_IsNewCardPresent()) 129 | return; 130 | 131 | // Select one of the cards 132 | if ( ! mfrc522.PICC_ReadCardSerial()) 133 | return; 134 | 135 | // Show some details of the PICC (that is: the tag/card) 136 | Serial.print(F("Card UID:")); 137 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 138 | Serial.println(); 139 | Serial.print(F("PICC type: ")); 140 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 141 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 142 | 143 | // Try the known default keys 144 | MFRC522::MIFARE_Key key; 145 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 146 | // Copy the known key into the MIFARE_Key structure 147 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 148 | key.keyByte[i] = knownKeys[k][i]; 149 | } 150 | // Try the key 151 | if (try_key(&key)) { 152 | // Found and reported on the key and block, 153 | // no need to try other keys for this PICC 154 | break; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /examples/rfid_read_personal_data/rfid_read_personal_data.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Initial Author: ryand1011 (https://github.com/ryand1011) 3 | * 4 | * Reads data written by a program such as "rfid_write_personal_data.ino" 5 | * 6 | * See: https://github.com/miguelbalboa/rfid/tree/master/examples/rfid_write_personal_data 7 | * 8 | * Uses MIFARE RFID card using RFID-RC522 reader 9 | * Uses MFRC522 - Library 10 | * ----------------------------------------------------------------------------------------- 11 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 12 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 13 | * Signal Pin Pin Pin Pin Pin Pin 14 | * ----------------------------------------------------------------------------------------- 15 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 16 | * SPI SS SDA(SS) 10 53 D10 10 10 17 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 18 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 19 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 26 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 27 | 28 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 29 | 30 | //*****************************************************************************************// 31 | void setup() { 32 | Serial.begin(9600); // Initialize serial communications with the PC 33 | SPI.begin(); // Init SPI bus 34 | mfrc522.PCD_Init(); // Init MFRC522 card 35 | Serial.println(F("Read personal data on a MIFARE PICC:")); //shows in serial that it is ready to read 36 | } 37 | 38 | //*****************************************************************************************// 39 | void loop() { 40 | 41 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 42 | MFRC522::MIFARE_Key key; 43 | for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; 44 | 45 | //some variables we need 46 | byte block; 47 | byte len; 48 | MFRC522::StatusCode status; 49 | 50 | //------------------------------------------- 51 | 52 | // Look for new cards 53 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 54 | return; 55 | } 56 | 57 | // Select one of the cards 58 | if ( ! mfrc522.PICC_ReadCardSerial()) { 59 | return; 60 | } 61 | 62 | Serial.println(F("**Card Detected:**")); 63 | 64 | //------------------------------------------- 65 | 66 | mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card 67 | 68 | //mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); //uncomment this to see all blocks in hex 69 | 70 | //------------------------------------------- 71 | 72 | Serial.print(F("Name: ")); 73 | 74 | byte buffer1[18]; 75 | 76 | block = 4; 77 | len = 18; 78 | 79 | //------------------------------------------- GET FIRST NAME 80 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file 81 | if (status != MFRC522::STATUS_OK) { 82 | Serial.print(F("Authentication failed: ")); 83 | Serial.println(mfrc522.GetStatusCodeName(status)); 84 | return; 85 | } 86 | 87 | status = mfrc522.MIFARE_Read(block, buffer1, &len); 88 | if (status != MFRC522::STATUS_OK) { 89 | Serial.print(F("Reading failed: ")); 90 | Serial.println(mfrc522.GetStatusCodeName(status)); 91 | return; 92 | } 93 | 94 | //PRINT FIRST NAME 95 | for (uint8_t i = 0; i < 16; i++) 96 | { 97 | if (buffer1[i] != 32) 98 | { 99 | Serial.write(buffer1[i]); 100 | } 101 | } 102 | Serial.print(" "); 103 | 104 | //---------------------------------------- GET LAST NAME 105 | 106 | byte buffer2[18]; 107 | block = 1; 108 | 109 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834 110 | if (status != MFRC522::STATUS_OK) { 111 | Serial.print(F("Authentication failed: ")); 112 | Serial.println(mfrc522.GetStatusCodeName(status)); 113 | return; 114 | } 115 | 116 | status = mfrc522.MIFARE_Read(block, buffer2, &len); 117 | if (status != MFRC522::STATUS_OK) { 118 | Serial.print(F("Reading failed: ")); 119 | Serial.println(mfrc522.GetStatusCodeName(status)); 120 | return; 121 | } 122 | 123 | //PRINT LAST NAME 124 | for (uint8_t i = 0; i < 16; i++) { 125 | Serial.write(buffer2[i] ); 126 | } 127 | 128 | 129 | //---------------------------------------- 130 | 131 | Serial.println(F("\n**End Reading**\n")); 132 | 133 | delay(1000); //change value if you want to read cards faster 134 | 135 | mfrc522.PICC_HaltA(); 136 | mfrc522.PCD_StopCrypto1(); 137 | } 138 | //*****************************************************************************************// 139 | -------------------------------------------------------------------------------- /examples/rfid_write_personal_data/rfid_write_personal_data.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Write personal data of a MIFARE RFID card using a RFID-RC522 reader 3 | * Uses MFRC522 - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 4 | * ----------------------------------------------------------------------------------------- 5 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 6 | * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro 7 | * Signal Pin Pin Pin Pin Pin Pin 8 | * ----------------------------------------------------------------------------------------- 9 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 10 | * SPI SS SDA(SS) 10 53 D10 10 10 11 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 12 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 13 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 14 | * 15 | * Hardware required: 16 | * Arduino 17 | * PCD (Proximity Coupling Device): NXP MFRC522 Contactless Reader IC 18 | * PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. 19 | * The reader can be found on eBay for around 5 dollars. Search for "mf-rc522" on ebay.com. 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above 26 | constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above 27 | 28 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 29 | 30 | void setup() { 31 | Serial.begin(9600); // Initialize serial communications with the PC 32 | SPI.begin(); // Init SPI bus 33 | mfrc522.PCD_Init(); // Init MFRC522 card 34 | Serial.println(F("Write personal data on a MIFARE PICC ")); 35 | } 36 | 37 | void loop() { 38 | 39 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 40 | MFRC522::MIFARE_Key key; 41 | for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; 42 | 43 | // Look for new cards 44 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 45 | return; 46 | } 47 | 48 | // Select one of the cards 49 | if ( ! mfrc522.PICC_ReadCardSerial()) { 50 | return; 51 | } 52 | 53 | Serial.print(F("Card UID:")); //Dump UID 54 | for (byte i = 0; i < mfrc522.uid.size; i++) { 55 | Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 56 | Serial.print(mfrc522.uid.uidByte[i], HEX); 57 | } 58 | Serial.print(F(" PICC type: ")); // Dump PICC type 59 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 60 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 61 | 62 | byte buffer[34]; 63 | byte block; 64 | MFRC522::StatusCode status; 65 | byte len; 66 | 67 | Serial.setTimeout(20000L) ; // wait until 20 seconds for input from serial 68 | // Ask personal data: Family name 69 | Serial.println(F("Type Family name, ending with #")); 70 | len = Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial 71 | for (byte i = len; i < 30; i++) buffer[i] = ' '; // pad with spaces 72 | 73 | block = 1; 74 | //Serial.println(F("Authenticating using key A...")); 75 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 76 | if (status != MFRC522::STATUS_OK) { 77 | Serial.print(F("PCD_Authenticate() failed: ")); 78 | Serial.println(mfrc522.GetStatusCodeName(status)); 79 | return; 80 | } 81 | else Serial.println(F("PCD_Authenticate() success: ")); 82 | 83 | // Write block 84 | status = mfrc522.MIFARE_Write(block, buffer, 16); 85 | if (status != MFRC522::STATUS_OK) { 86 | Serial.print(F("MIFARE_Write() failed: ")); 87 | Serial.println(mfrc522.GetStatusCodeName(status)); 88 | return; 89 | } 90 | else Serial.println(F("MIFARE_Write() success: ")); 91 | 92 | block = 2; 93 | //Serial.println(F("Authenticating using key A...")); 94 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 95 | if (status != MFRC522::STATUS_OK) { 96 | Serial.print(F("PCD_Authenticate() failed: ")); 97 | Serial.println(mfrc522.GetStatusCodeName(status)); 98 | return; 99 | } 100 | 101 | // Write block 102 | status = mfrc522.MIFARE_Write(block, &buffer[16], 16); 103 | if (status != MFRC522::STATUS_OK) { 104 | Serial.print(F("MIFARE_Write() failed: ")); 105 | Serial.println(mfrc522.GetStatusCodeName(status)); 106 | return; 107 | } 108 | else Serial.println(F("MIFARE_Write() success: ")); 109 | 110 | // Ask personal data: First name 111 | Serial.println(F("Type First name, ending with #")); 112 | len = Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial 113 | for (byte i = len; i < 20; i++) buffer[i] = ' '; // pad with spaces 114 | 115 | block = 4; 116 | //Serial.println(F("Authenticating using key A...")); 117 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 118 | if (status != MFRC522::STATUS_OK) { 119 | Serial.print(F("PCD_Authenticate() failed: ")); 120 | Serial.println(mfrc522.GetStatusCodeName(status)); 121 | return; 122 | } 123 | 124 | // Write block 125 | status = mfrc522.MIFARE_Write(block, buffer, 16); 126 | if (status != MFRC522::STATUS_OK) { 127 | Serial.print(F("MIFARE_Write() failed: ")); 128 | Serial.println(mfrc522.GetStatusCodeName(status)); 129 | return; 130 | } 131 | else Serial.println(F("MIFARE_Write() success: ")); 132 | 133 | block = 5; 134 | //Serial.println(F("Authenticating using key A...")); 135 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 136 | if (status != MFRC522::STATUS_OK) { 137 | Serial.print(F("PCD_Authenticate() failed: ")); 138 | Serial.println(mfrc522.GetStatusCodeName(status)); 139 | return; 140 | } 141 | 142 | // Write block 143 | status = mfrc522.MIFARE_Write(block, &buffer[16], 16); 144 | if (status != MFRC522::STATUS_OK) { 145 | Serial.print(F("MIFARE_Write() failed: ")); 146 | Serial.println(mfrc522.GetStatusCodeName(status)); 147 | return; 148 | } 149 | else Serial.println(F("MIFARE_Write() success: ")); 150 | 151 | 152 | Serial.println(" "); 153 | mfrc522.PICC_HaltA(); // Halt PICC 154 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 155 | 156 | } -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for library MFRC522 3 | ####################################### 4 | 5 | ####################################### 6 | # KEYWORD1 Classes, datatypes, and C++ keywords 7 | ####################################### 8 | MFRC522 KEYWORD1 9 | MFRC522Extended KEYWORD1 10 | PCD_Register KEYWORD1 11 | PCD_Command KEYWORD1 12 | PCD_RxGain KEYWORD1 13 | PICC_Command KEYWORD1 14 | MIFARE_Misc KEYWORD1 15 | PICC_Type KEYWORD1 16 | StatusCode KEYWORD1 17 | TagBitRates KEYWORD1 18 | Uid KEYWORD1 19 | CardInfo KEYWORD1 20 | MIFARE_Key KEYWORD1 21 | PcbBlock KEYWORD1 22 | 23 | ####################################### 24 | # KEYWORD2 Methods and functions 25 | ####################################### 26 | 27 | # Basic interface functions for communicating with the MFRC522 28 | PCD_WriteRegister KEYWORD2 29 | PCD_WriteRegister KEYWORD2 30 | PCD_ReadRegister KEYWORD2 31 | PCD_ReadRegister KEYWORD2 32 | setBitMask KEYWORD2 33 | PCD_SetRegisterBitMask KEYWORD2 34 | PCD_ClearRegisterBitMask KEYWORD2 35 | PCD_CalculateCRC KEYWORD2 36 | 37 | # Functions for manipulating the MFRC522 38 | PCD_Init KEYWORD2 39 | PCD_Reset KEYWORD2 40 | PCD_AntennaOn KEYWORD2 41 | PCD_AntennaOff KEYWORD2 42 | PCD_GetAntennaGain KEYWORD2 43 | PCD_SetAntennaGain KEYWORD2 44 | PCD_PerformSelfTest KEYWORD2 45 | 46 | # Functions for communicating with PICCs 47 | PCD_TransceiveData KEYWORD2 48 | PCD_CommunicateWithPICC KEYWORD2 49 | PICC_RequestA KEYWORD2 50 | PICC_WakeupA KEYWORD2 51 | PICC_REQA_or_WUPA KEYWORD2 52 | PICC_Select KEYWORD2 53 | PICC_HaltA KEYWORD2 54 | PICC_RATS KEYWORD2 55 | PICC_PPS KEYWORD2 56 | 57 | # Functions for communicating with ISO/IEC 14433-4 cards 58 | TCL_Transceive KEYWORD2 59 | TCL_TransceiveRBlock KEYWORD2 60 | TCL_Deselect KEYWORD2 61 | 62 | # Functions for communicating with MIFARE PICCs 63 | PCD_Authenticate KEYWORD2 64 | PCD_StopCrypto1 KEYWORD2 65 | MIFARE_Read KEYWORD2 66 | MIFARE_Write KEYWORD2 67 | MIFARE_Increment KEYWORD2 68 | MIFARE_Ultralight_Write KEYWORD2 69 | MIFARE_GetValue KEYWORD2 70 | MIFARE_SetValue KEYWORD2 71 | PCD_NTAG216_AUTH KEYWORD2 72 | 73 | # Support functions 74 | PCD_MIFARE_Transceive KEYWORD2 75 | GetStatusCodeName KEYWORD2 76 | PICC_GetType KEYWORD2 77 | PICC_GetTypeName KEYWORD2 78 | 79 | # Support functions for debuging 80 | PCD_DumpVersionToSerial KEYWORD2 81 | PICC_DumpToSerial KEYWORD2 82 | PICC_DumpDetailsToSerial KEYWORD2 83 | PICC_DumpMifareClassicToSerial KEYWORD2 84 | PICC_DumpMifareClassicSectorToSerial KEYWORD2 85 | PICC_DumpMifareUltralightToSerial KEYWORD2 86 | PICC_DumpISO14443_4 KEYWORD2 87 | 88 | # Advanced functions for MIFARE 89 | MIFARE_SetAccessBits KEYWORD2 90 | MIFARE_OpenUidBackdoor KEYWORD2 91 | MIFARE_SetUid KEYWORD2 92 | MIFARE_UnbrickUidSector KEYWORD2 93 | 94 | # Convenience functions - does not add extra functionality 95 | PICC_IsNewCardPresent KEYWORD2 96 | PICC_ReadCardSerial KEYWORD2 97 | 98 | ####################################### 99 | # KEYWORD3 setup and loop functions, as well as the Serial keywords 100 | ####################################### 101 | 102 | ####################################### 103 | LITERAL1 Constants 104 | ####################################### 105 | CommandReg LITERAL1 106 | ComIEnReg LITERAL1 107 | DivIEnReg LITERAL1 108 | ComIrqReg LITERAL1 109 | DivIrqReg LITERAL1 110 | ErrorReg LITERAL1 111 | Status1Reg LITERAL1 112 | Status2Reg LITERAL1 113 | FIFODataReg LITERAL1 114 | FIFOLevelReg LITERAL1 115 | WaterLevelReg LITERAL1 116 | ControlReg LITERAL1 117 | BitFramingReg LITERAL1 118 | CollReg LITERAL1 119 | ModeReg LITERAL1 120 | TxModeReg LITERAL1 121 | RxModeReg LITERAL1 122 | TxControlReg LITERAL1 123 | TxASKReg LITERAL1 124 | TxSelReg LITERAL1 125 | RxSelReg LITERAL1 126 | RxThresholdReg LITERAL1 127 | DemodReg LITERAL1 128 | MfTxReg LITERAL1 129 | MfRxReg LITERAL1 130 | SerialSpeedReg LITERAL1 131 | CRCResultRegH LITERAL1 132 | CRCResultRegL LITERAL1 133 | ModWidthReg LITERAL1 134 | RFCfgReg LITERAL1 135 | GsNReg LITERAL1 136 | CWGsPReg LITERAL1 137 | ModGsPReg LITERAL1 138 | TModeReg LITERAL1 139 | TPrescalerReg LITERAL1 140 | TReloadRegH LITERAL1 141 | TReloadRegL LITERAL1 142 | TCounterValueRegH LITERAL1 143 | TCounterValueRegL LITERAL1 144 | TestSel1Reg LITERAL1 145 | TestSel2Reg LITERAL1 146 | TestPinEnReg LITERAL1 147 | TestPinValueReg LITERAL1 148 | TestBusReg LITERAL1 149 | AutoTestReg LITERAL1 150 | VersionReg LITERAL1 151 | AnalogTestReg LITERAL1 152 | TestDAC1Reg LITERAL1 153 | TestDAC2Reg LITERAL1 154 | TestADCReg LITERAL1 155 | PCD_Idle LITERAL1 156 | PCD_Mem LITERAL1 157 | PCD_GenerateRandomID LITERAL1 158 | PCD_CalcCRC LITERAL1 159 | PCD_Transmit LITERAL1 160 | PCD_NoCmdChange LITERAL1 161 | PCD_Receive LITERAL1 162 | PCD_Transceive LITERAL1 163 | PCD_MFAuthent LITERAL1 164 | PCD_SoftReset LITERAL1 165 | RxGain_18dB LITERAL1 166 | RxGain_23dB LITERAL1 167 | RxGain_18dB_2 LITERAL1 168 | RxGain_23dB_2 LITERAL1 169 | RxGain_33dB LITERAL1 170 | RxGain_38dB LITERAL1 171 | RxGain_43dB LITERAL1 172 | RxGain_48dB LITERAL1 173 | RxGain_min LITERAL1 174 | RxGain_avg LITERAL1 175 | RxGain_max LITERAL1 176 | PICC_CMD_REQA LITERAL1 177 | PICC_CMD_WUPA LITERAL1 178 | PICC_CMD_CT LITERAL1 179 | PICC_CMD_SEL_CL1 LITERAL1 180 | PICC_CMD_SEL_CL2 LITERAL1 181 | PICC_CMD_SEL_CL3 LITERAL1 182 | PICC_CMD_HLTA LITERAL1 183 | PICC_CMD_RATS LITERAL1 184 | PICC_CMD_MF_AUTH_KEY_A LITERAL1 185 | PICC_CMD_MF_AUTH_KEY_B LITERAL1 186 | PICC_CMD_MF_READ LITERAL1 187 | PICC_CMD_MF_WRITE LITERAL1 188 | PICC_CMD_MF_DECREMENT LITERAL1 189 | PICC_CMD_MF_INCREMENT LITERAL1 190 | PICC_CMD_MF_RESTORE LITERAL1 191 | PICC_CMD_MF_TRANSFER LITERAL1 192 | PICC_CMD_UL_WRITE LITERAL1 193 | MF_ACK LITERAL1 194 | MF_KEY_SIZE LITERAL1 195 | PICC_TYPE_UNKNOWN LITERAL1 196 | PICC_TYPE_ISO_14443_4 LITERAL1 197 | PICC_TYPE_ISO_18092 LITERAL1 198 | PICC_TYPE_MIFARE_MINI LITERAL1 199 | PICC_TYPE_MIFARE_1K LITERAL1 200 | PICC_TYPE_MIFARE_4K LITERAL1 201 | PICC_TYPE_MIFARE_UL LITERAL1 202 | PICC_TYPE_MIFARE_PLUS LITERAL1 203 | PICC_TYPE_MIFARE_DESFIRE LITERAL1 204 | PICC_TYPE_TNP3XXX LITERAL1 205 | PICC_TYPE_NOT_COMPLETE LITERAL1 206 | STATUS_OK LITERAL1 207 | STATUS_ERROR LITERAL1 208 | STATUS_COLLISION LITERAL1 209 | STATUS_TIMEOUT LITERAL1 210 | STATUS_NO_ROOM LITERAL1 211 | STATUS_INTERNAL_ERROR LITERAL1 212 | STATUS_INVALID LITERAL1 213 | STATUS_CRC_WRONG LITERAL1 214 | STATUS_MIFARE_NACK LITERAL1 215 | FIFO_SIZE LITERAL1 216 | BITRATE_106KBITS LITERAL1 217 | BITRATE_212KBITS LITERAL1 218 | BITRATE_424KBITS LITERAL1 219 | BITRATE_848KBITS LITERAL1 -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MFRC522", 3 | "keywords": "rfid, spi", 4 | "description": "Read/Write a RFID Card or Tag using the ISO/IEC 14443A/MIFARE interface. Support PBOC card.", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/Sleepychord/pboc-arduino.git" 9 | }, 10 | "version": "2.0.0", 11 | "exclude": "doc", 12 | "frameworks": "arduino", 13 | "platforms": ["atmelavr", "ststm32", "teensy", "espressif8266"] 14 | } 15 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MFRC522 2 | version=2.0.0 3 | author=GithubCommunity 4 | maintainer=Sleepychord 5 | sentence=Arduino RFID Library for MFRC522 (SPI) and PBOC 6 | paragraph=Read/Write a RFID Card or Tag using the ISO/IEC 14443A/MIFARE interface. Support PBOC card. 7 | category=Communication 8 | url=https://github.com/Sleepychord/pboc-arduino 9 | architectures=avr,STM32F1,teensy,esp8266 10 | -------------------------------------------------------------------------------- /src/MFRC522.h: -------------------------------------------------------------------------------- 1 | /** 2 | * MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 3 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 4 | * Created by Miguel Balboa (circuitito.com), Jan, 2012. 5 | * Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) 6 | * Extended by Tom Clement with functionality to write to sector 0 of UID changeable Mifare cards. 7 | * Released into the public domain. 8 | * 9 | * Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. 10 | * Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board. 11 | * 12 | * There are three hardware components involved: 13 | * 1) The micro controller: An Arduino 14 | * 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC 15 | * 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. 16 | * 17 | * The microcontroller and card reader uses SPI for communication. 18 | * The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf 19 | * 20 | * The card reader and the tags communicate using a 13.56MHz electromagnetic field. 21 | * The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision". 22 | * A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf 23 | * Details are found in chapter 6, Type A – Initialization and anticollision. 24 | * 25 | * If only the PICC UID is wanted, the above documents has all the needed information. 26 | * To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected. 27 | * The MIFARE Classic chips and protocol is described in the datasheets: 28 | * 1K: http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf 29 | * 4K: http://datasheet.octopart.com/MF1S7035DA4,118-NXP-Semiconductors-datasheet-11046188.pdf 30 | * Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf 31 | * The MIFARE Ultralight chip and protocol is described in the datasheets: 32 | * Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf 33 | * Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf 34 | * 35 | * MIFARE Classic 1K (MF1S503x): 36 | * Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. 37 | * The blocks are numbered 0-63. 38 | * Block 3 in each sector is the Sector Trailer. See http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf sections 8.6 and 8.7: 39 | * Bytes 0-5: Key A 40 | * Bytes 6-8: Access Bits 41 | * Bytes 9: User data 42 | * Bytes 10-15: Key B (or user data) 43 | * Block 0 is read-only manufacturer data. 44 | * To access a block, an authentication using a key from the block's sector must be performed first. 45 | * Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11). 46 | * All keys are set to FFFFFFFFFFFFh at chip delivery. 47 | * Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked. 48 | * To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns. 49 | * MIFARE Classic 4K (MF1S703x): 50 | * Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. 51 | * The blocks are numbered 0-255. 52 | * The last block in each sector is the Sector Trailer like above. 53 | * MIFARE Classic Mini (MF1 IC S20): 54 | * Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. 55 | * The blocks are numbered 0-19. 56 | * The last block in each sector is the Sector Trailer like above. 57 | * 58 | * MIFARE Ultralight (MF0ICU1): 59 | * Has 16 pages of 4 bytes = 64 bytes. 60 | * Pages 0 + 1 is used for the 7-byte UID. 61 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 62 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 63 | * Pages 4-15 are read/write unless blocked by the lock bytes in page 2. 64 | * MIFARE Ultralight C (MF0ICU2): 65 | * Has 48 pages of 4 bytes = 192 bytes. 66 | * Pages 0 + 1 is used for the 7-byte UID. 67 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 68 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 69 | * Pages 4-39 are read/write unless blocked by the lock bytes in page 2. 70 | * Page 40 Lock bytes 71 | * Page 41 16 bit one way counter 72 | * Pages 42-43 Authentication configuration 73 | * Pages 44-47 Authentication key 74 | */ 75 | #ifndef MFRC522_h 76 | #define MFRC522_h 77 | 78 | #include "require_cpp11.h" 79 | #include "deprecated.h" 80 | // Enable integer limits 81 | #define __STDC_LIMIT_MACROS 82 | #include 83 | #include 84 | #include 85 | 86 | // Firmware data for self-test 87 | // Reference values based on firmware version 88 | // Hint: if needed, you can remove unused self-test data to save flash memory 89 | // 90 | // Version 0.0 (0x90) 91 | // Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 self-test 92 | const byte MFRC522_firmware_referenceV0_0[] PROGMEM = { 93 | 0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19, 94 | 0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA, 95 | 0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50, 96 | 0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E, 97 | 0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78, 98 | 0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94, 99 | 0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF, 100 | 0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D 101 | }; 102 | // Version 1.0 (0x91) 103 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test 104 | const byte MFRC522_firmware_referenceV1_0[] PROGMEM = { 105 | 0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 106 | 0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73, 107 | 0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A, 108 | 0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E, 109 | 0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC, 110 | 0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41, 111 | 0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02, 112 | 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79 113 | }; 114 | // Version 2.0 (0x92) 115 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test 116 | const byte MFRC522_firmware_referenceV2_0[] PROGMEM = { 117 | 0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 118 | 0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE, 119 | 0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82, 120 | 0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49, 121 | 0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81, 122 | 0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9, 123 | 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 124 | 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F 125 | }; 126 | // Clone 127 | // Fudan Semiconductor FM17522 (0x88) 128 | const byte FM17522_firmware_reference[] PROGMEM = { 129 | 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 130 | 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 131 | 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, 132 | 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, 133 | 0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 134 | 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E, 135 | 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 136 | 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 137 | }; 138 | 139 | class MFRC522 { 140 | public: 141 | // Size of the MFRC522 FIFO 142 | static constexpr byte FIFO_SIZE = 64; // The FIFO is 64 bytes. 143 | // Default value for unused pin 144 | static constexpr uint8_t UNUSED_PIN = UINT8_MAX; 145 | 146 | // MFRC522 registers. Described in chapter 9 of the datasheet. 147 | // When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3) 148 | enum PCD_Register : byte { 149 | // Page 0: Command and status 150 | // 0x00 // reserved for future use 151 | CommandReg = 0x01 << 1, // starts and stops command execution 152 | ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits 153 | DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits 154 | ComIrqReg = 0x04 << 1, // interrupt request bits 155 | DivIrqReg = 0x05 << 1, // interrupt request bits 156 | ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed 157 | Status1Reg = 0x07 << 1, // communication status bits 158 | Status2Reg = 0x08 << 1, // receiver and transmitter status bits 159 | FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer 160 | FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer 161 | WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning 162 | ControlReg = 0x0C << 1, // miscellaneous control registers 163 | BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames 164 | CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface 165 | // 0x0F // reserved for future use 166 | 167 | // Page 1: Command 168 | // 0x10 // reserved for future use 169 | ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving 170 | TxModeReg = 0x12 << 1, // defines transmission data rate and framing 171 | RxModeReg = 0x13 << 1, // defines reception data rate and framing 172 | TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2 173 | TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation 174 | TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver 175 | RxSelReg = 0x17 << 1, // selects internal receiver settings 176 | RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder 177 | DemodReg = 0x19 << 1, // defines demodulator settings 178 | // 0x1A // reserved for future use 179 | // 0x1B // reserved for future use 180 | MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters 181 | MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters 182 | // 0x1E // reserved for future use 183 | SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface 184 | 185 | // Page 2: Configuration 186 | // 0x20 // reserved for future use 187 | CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation 188 | CRCResultRegL = 0x22 << 1, 189 | // 0x23 // reserved for future use 190 | ModWidthReg = 0x24 << 1, // controls the ModWidth setting? 191 | // 0x25 // reserved for future use 192 | RFCfgReg = 0x26 << 1, // configures the receiver gain 193 | GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation 194 | CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation 195 | ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation 196 | TModeReg = 0x2A << 1, // defines settings for the internal timer 197 | TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. 198 | TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value 199 | TReloadRegL = 0x2D << 1, 200 | TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value 201 | TCounterValueRegL = 0x2F << 1, 202 | 203 | // Page 3: Test Registers 204 | // 0x30 // reserved for future use 205 | TestSel1Reg = 0x31 << 1, // general test signal configuration 206 | TestSel2Reg = 0x32 << 1, // general test signal configuration 207 | TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7 208 | TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus 209 | TestBusReg = 0x35 << 1, // shows the status of the internal test bus 210 | AutoTestReg = 0x36 << 1, // controls the digital self-test 211 | VersionReg = 0x37 << 1, // shows the software version 212 | AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2 213 | TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1 214 | TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2 215 | TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels 216 | // 0x3C // reserved for production tests 217 | // 0x3D // reserved for production tests 218 | // 0x3E // reserved for production tests 219 | // 0x3F // reserved for production tests 220 | }; 221 | 222 | // MFRC522 commands. Described in chapter 10 of the datasheet. 223 | enum PCD_Command : byte { 224 | PCD_Idle = 0x00, // no action, cancels current command execution 225 | PCD_Mem = 0x01, // stores 25 bytes into the internal buffer 226 | PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number 227 | PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self-test 228 | PCD_Transmit = 0x04, // transmits data from the FIFO buffer 229 | PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit 230 | PCD_Receive = 0x08, // activates the receiver circuits 231 | PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission 232 | PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader 233 | PCD_SoftReset = 0x0F // resets the MFRC522 234 | }; 235 | 236 | // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). 237 | // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf 238 | enum PCD_RxGain : byte { 239 | RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum 240 | RxGain_23dB = 0x01 << 4, // 001b - 23 dB 241 | RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b 242 | RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b 243 | RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default 244 | RxGain_38dB = 0x05 << 4, // 101b - 38 dB 245 | RxGain_43dB = 0x06 << 4, // 110b - 43 dB 246 | RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum 247 | RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB 248 | RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB 249 | RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB 250 | }; 251 | 252 | // Commands sent to the PICC. 253 | enum PICC_Command : byte { 254 | // The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) 255 | PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. 256 | PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. 257 | PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. 258 | PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 259 | PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 260 | PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 261 | PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. 262 | PICC_CMD_RATS = 0xE0, // Request command for Answer To Reset. 263 | // The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) 264 | // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. 265 | // The read/write commands can also be used for MIFARE Ultralight. 266 | PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A 267 | PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B 268 | PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. 269 | PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. 270 | PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. 271 | PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. 272 | PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. 273 | PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. 274 | // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) 275 | // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. 276 | PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. 277 | }; 278 | 279 | // MIFARE constants that does not fit anywhere else 280 | enum MIFARE_Misc { 281 | MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. 282 | MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. 283 | }; 284 | 285 | // PICC types we can detect. Remember to update PICC_GetTypeName() if you add more. 286 | // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered 287 | enum PICC_Type : byte { 288 | PICC_TYPE_UNKNOWN , 289 | PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4 290 | PICC_TYPE_ISO_18092 , // PICC compliant with ISO/IEC 18092 (NFC) 291 | PICC_TYPE_MIFARE_MINI , // MIFARE Classic protocol, 320 bytes 292 | PICC_TYPE_MIFARE_1K , // MIFARE Classic protocol, 1KB 293 | PICC_TYPE_MIFARE_4K , // MIFARE Classic protocol, 4KB 294 | PICC_TYPE_MIFARE_UL , // MIFARE Ultralight or Ultralight C 295 | PICC_TYPE_MIFARE_PLUS , // MIFARE Plus 296 | PICC_TYPE_MIFARE_DESFIRE, // MIFARE DESFire 297 | PICC_TYPE_TNP3XXX , // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure 298 | PICC_TYPE_NOT_COMPLETE = 0xff // SAK indicates UID is not complete. 299 | }; 300 | 301 | // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. 302 | // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered 303 | enum StatusCode : byte { 304 | STATUS_OK , // Success 305 | STATUS_ERROR , // Error in communication 306 | STATUS_COLLISION , // Collission detected 307 | STATUS_TIMEOUT , // Timeout in communication. 308 | STATUS_NO_ROOM , // A buffer is not big enough. 309 | STATUS_INTERNAL_ERROR , // Internal error in the code. Should not happen ;-) 310 | STATUS_INVALID , // Invalid argument. 311 | STATUS_CRC_WRONG , // The CRC_A does not match 312 | STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. 313 | }; 314 | 315 | // A struct used for passing the UID of a PICC. 316 | typedef struct { 317 | byte size; // Number of bytes in the UID. 4, 7 or 10. 318 | byte uidByte[10]; 319 | byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. 320 | } Uid; 321 | 322 | // A struct used for passing a MIFARE Crypto1 key 323 | typedef struct { 324 | byte keyByte[MF_KEY_SIZE]; 325 | } MIFARE_Key; 326 | 327 | // Member variables 328 | Uid uid; // Used by PICC_ReadCardSerial(). 329 | 330 | ///////////////////////////////////////////////////////////////////////////////////// 331 | // Functions for setting up the Arduino 332 | ///////////////////////////////////////////////////////////////////////////////////// 333 | MFRC522(const byte chipSelectPin, const byte resetPowerDownPin, 334 | SPIClass *spiClass = &SPI, const SPISettings spiSettings = SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)) 335 | : _chipSelectPin(chipSelectPin), _resetPowerDownPin(resetPowerDownPin), 336 | _spiClass(spiClass), _spiSettings(spiSettings) {}; 337 | MFRC522() : MFRC522(UNUSED_PIN, UNUSED_PIN) {}; 338 | 339 | ///////////////////////////////////////////////////////////////////////////////////// 340 | // Basic interface functions for communicating with the MFRC522 341 | ///////////////////////////////////////////////////////////////////////////////////// 342 | void PCD_WriteRegister(PCD_Register reg, byte value); 343 | void PCD_WriteRegister(PCD_Register reg, byte count, byte *values); 344 | byte PCD_ReadRegister(PCD_Register reg); 345 | void PCD_ReadRegister(PCD_Register reg, byte count, byte *values, byte rxAlign = 0); 346 | void PCD_SetRegisterBitMask(PCD_Register reg, byte mask); 347 | void PCD_ClearRegisterBitMask(PCD_Register reg, byte mask); 348 | StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result); 349 | 350 | ///////////////////////////////////////////////////////////////////////////////////// 351 | // Functions for manipulating the MFRC522 352 | ///////////////////////////////////////////////////////////////////////////////////// 353 | void PCD_Init(); 354 | void PCD_Init(byte chipSelectPin, byte resetPowerDownPin); 355 | void PCD_Reset(); 356 | void PCD_AntennaOn(); 357 | void PCD_AntennaOff(); 358 | byte PCD_GetAntennaGain(); 359 | void PCD_SetAntennaGain(byte mask); 360 | bool PCD_PerformSelfTest(); 361 | 362 | ///////////////////////////////////////////////////////////////////////////////////// 363 | // Functions for communicating with PICCs 364 | ///////////////////////////////////////////////////////////////////////////////////// 365 | StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); 366 | StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = nullptr, byte *backLen = nullptr, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); 367 | StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize); 368 | StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize); 369 | StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize); 370 | virtual StatusCode PICC_Select(Uid *uid, byte validBits = 0); 371 | StatusCode PICC_HaltA(); 372 | 373 | ///////////////////////////////////////////////////////////////////////////////////// 374 | // Functions for communicating with MIFARE PICCs 375 | ///////////////////////////////////////////////////////////////////////////////////// 376 | StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); 377 | void PCD_StopCrypto1(); 378 | StatusCode MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize); 379 | StatusCode MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize); 380 | StatusCode MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize); 381 | StatusCode MIFARE_Decrement(byte blockAddr, int32_t delta); 382 | StatusCode MIFARE_Increment(byte blockAddr, int32_t delta); 383 | StatusCode MIFARE_Restore(byte blockAddr); 384 | StatusCode MIFARE_Transfer(byte blockAddr); 385 | StatusCode MIFARE_GetValue(byte blockAddr, int32_t *value); 386 | StatusCode MIFARE_SetValue(byte blockAddr, int32_t value); 387 | StatusCode PCD_NTAG216_AUTH(byte *passWord, byte pACK[]); 388 | 389 | ///////////////////////////////////////////////////////////////////////////////////// 390 | // Support functions 391 | ///////////////////////////////////////////////////////////////////////////////////// 392 | StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); 393 | static PICC_Type PICC_GetType(byte sak); 394 | 395 | // Support functions for debuging - proxy for MFRC522Debug to keep backwarts compatibility 396 | static const __FlashStringHelper *GetStatusCodeName(StatusCode code); 397 | static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); 398 | 399 | // Support functions for debuging 400 | void PCD_DumpVersionToSerial(); 401 | void PICC_DumpToSerial(Uid *uid); 402 | void PICC_DumpDetailsToSerial(Uid *uid); 403 | void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key); 404 | void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); 405 | void PICC_DumpMifareUltralightToSerial(); 406 | 407 | // Advanced functions for MIFARE 408 | void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); 409 | 410 | ///////////////////////////////////////////////////////////////////////////////////// 411 | // Convenience functions - does not add extra functionality 412 | ///////////////////////////////////////////////////////////////////////////////////// 413 | virtual bool PICC_IsNewCardPresent(); 414 | virtual bool PICC_ReadCardSerial(); 415 | 416 | protected: 417 | // Pins 418 | byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) 419 | byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 420 | 421 | // SPI communication 422 | SPIClass *_spiClass; // SPI class which abstracts hardware. 423 | const SPISettings _spiSettings; // SPI settings. 424 | 425 | // Functions for communicating with MIFARE PICCs 426 | StatusCode MIFARE_TwoStepHelper(byte command, byte blockAddr, int32_t data); 427 | }; 428 | 429 | #endif 430 | -------------------------------------------------------------------------------- /src/MFRC522Debug.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MFRC522Debug.h" 3 | 4 | /** 5 | * Returns a __FlashStringHelper pointer to the PICC type name. 6 | * 7 | * @return const __FlashStringHelper * 8 | */ 9 | const __FlashStringHelper *MFRC522Debug::PICC_GetTypeName(MFRC522::PICC_Type piccType ///< One of the PICC_Type enums. 10 | ) { 11 | switch (piccType) { 12 | case MFRC522::PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); 13 | case MFRC522::PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); 14 | case MFRC522::PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); 15 | case MFRC522::PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); 16 | case MFRC522::PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); 17 | case MFRC522::PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); 18 | case MFRC522::PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); 19 | case MFRC522::PICC_TYPE_MIFARE_DESFIRE: return F("MIFARE DESFire"); 20 | case MFRC522::PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); 21 | case MFRC522::PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); 22 | case MFRC522::PICC_TYPE_UNKNOWN: 23 | default: return F("Unknown type"); 24 | } 25 | } // End PICC_GetTypeName() 26 | 27 | /** 28 | * Returns a __FlashStringHelper pointer to a status code name. 29 | * 30 | * @return const __FlashStringHelper * 31 | */ 32 | const __FlashStringHelper *MFRC522Debug::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. 33 | ) { 34 | switch (code) { 35 | case MFRC522::STATUS_OK: return F("Success."); 36 | case MFRC522::STATUS_ERROR: return F("Error in communication."); 37 | case MFRC522::STATUS_COLLISION: return F("Collission detected."); 38 | case MFRC522::STATUS_TIMEOUT: return F("Timeout in communication."); 39 | case MFRC522::STATUS_NO_ROOM: return F("A buffer is not big enough."); 40 | case MFRC522::STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); 41 | case MFRC522::STATUS_INVALID: return F("Invalid argument."); 42 | case MFRC522::STATUS_CRC_WRONG: return F("The CRC_A does not match."); 43 | case MFRC522::STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); 44 | default: return F("Unknown error"); 45 | } 46 | } // End GetStatusCodeName() 47 | -------------------------------------------------------------------------------- /src/MFRC522Debug.h: -------------------------------------------------------------------------------- 1 | #include "MFRC522.h" 2 | 3 | #ifndef MFRC522Debug_h 4 | #define MFRC522Debug_h 5 | 6 | class MFRC522Debug { 7 | private: 8 | 9 | public: 10 | // Get human readable code and type 11 | static const __FlashStringHelper *PICC_GetTypeName(MFRC522::PICC_Type type); 12 | static const __FlashStringHelper *GetStatusCodeName(MFRC522::StatusCode code); 13 | }; 14 | #endif // MFRC522Debug_h 15 | -------------------------------------------------------------------------------- /src/MFRC522Extended.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Library extends MFRC522.h to support RATS for ISO-14443-4 PICC. 3 | * RATS - Request for Answer To Select. 4 | * @author JPG-Consulting 5 | */ 6 | #ifndef MFRC522Extended_h 7 | #define MFRC522Extended_h 8 | 9 | #include 10 | #include "MFRC522.h" 11 | 12 | class MFRC522Extended : public MFRC522 { 13 | 14 | public: 15 | // ISO/IEC 14443-4 bit rates 16 | enum TagBitRates : byte { 17 | BITRATE_106KBITS = 0x00, 18 | BITRATE_212KBITS = 0x01, 19 | BITRATE_424KBITS = 0x02, 20 | BITRATE_848KBITS = 0x03 21 | }; 22 | 23 | // Structure to store ISO/IEC 14443-4 ATS 24 | typedef struct { 25 | byte size; 26 | byte fsc; // Frame size for proximity card 27 | 28 | struct { 29 | bool transmitted; 30 | bool sameD; // Only the same D for both directions supported 31 | TagBitRates ds; // Send D 32 | TagBitRates dr; // Receive D 33 | } ta1; 34 | 35 | struct { 36 | bool transmitted; 37 | byte fwi; // Frame waiting time integer 38 | byte sfgi; // Start-up frame guard time integer 39 | } tb1; 40 | 41 | struct { 42 | bool transmitted; 43 | bool supportsCID; 44 | bool supportsNAD; 45 | } tc1; 46 | 47 | // Raw data from ATS 48 | byte data[FIFO_SIZE - 2]; // ATS cannot be bigger than FSD - 2 bytes (CRC), according to ISO 14443-4 5.2.2 49 | } Ats; 50 | 51 | // A struct used for passing the PICC information 52 | typedef struct { 53 | uint16_t atqa; 54 | Uid uid; 55 | Ats ats; 56 | 57 | // For Block PCB 58 | bool blockNumber; 59 | } TagInfo; 60 | 61 | // A struct used for passing PCB Block 62 | typedef struct { 63 | struct { 64 | byte pcb; 65 | byte cid; 66 | byte nad; 67 | } prologue; 68 | struct { 69 | byte size; 70 | byte *data; 71 | } inf; 72 | } PcbBlock; 73 | 74 | // Member variables 75 | TagInfo tag; 76 | 77 | ///////////////////////////////////////////////////////////////////////////////////// 78 | // Contructors 79 | ///////////////////////////////////////////////////////////////////////////////////// 80 | MFRC522Extended() : MFRC522() {}; 81 | MFRC522Extended(uint8_t ss, uint8_t rst) : MFRC522(ss, rst) {}; 82 | 83 | ///////////////////////////////////////////////////////////////////////////////////// 84 | // Functions for communicating with PICCs 85 | ///////////////////////////////////////////////////////////////////////////////////// 86 | StatusCode PICC_Select(Uid *uid, byte validBits = 0) override; // overrride 87 | StatusCode PICC_RequestATS(Ats *ats); 88 | StatusCode PICC_PPS(); // PPS command without bitrate parameter 89 | StatusCode PICC_PPS(TagBitRates sendBitRate, TagBitRates receiveBitRate); // Different D values 90 | 91 | ///////////////////////////////////////////////////////////////////////////////////// 92 | // Functions for communicating with ISO/IEC 14433-4 cards 93 | ///////////////////////////////////////////////////////////////////////////////////// 94 | StatusCode TCL_Transceive(PcbBlock *send, PcbBlock *back); 95 | StatusCode TCL_Transceive(TagInfo * tag, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL); 96 | StatusCode TCL_TransceiveRBlock(TagInfo *tag, bool ack, byte *backData = NULL, byte *backLen = NULL, byte* linked = nullptr); 97 | StatusCode TCL_Deselect(TagInfo *tag); 98 | 99 | ///////////////////////////////////////////////////////////////////////////////////// 100 | // Support functions 101 | ///////////////////////////////////////////////////////////////////////////////////// 102 | static PICC_Type PICC_GetType(TagInfo *tag); 103 | using MFRC522::PICC_GetType;// // make old PICC_GetType(byte sak) available, otherwise would be hidden by PICC_GetType(TagInfo *tag) 104 | 105 | // Support functions for debuging 106 | void PICC_DumpToSerial(TagInfo *tag); 107 | using MFRC522::PICC_DumpToSerial; // make old PICC_DumpToSerial(Uid *uid) available, otherwise would be hidden by PICC_DumpToSerial(TagInfo *tag) 108 | void PICC_DumpDetailsToSerial(TagInfo *tag); 109 | using MFRC522::PICC_DumpDetailsToSerial; // make old PICC_DumpDetailsToSerial(Uid *uid) available, otherwise would be hidden by PICC_DumpDetailsToSerial(TagInfo *tag) 110 | void PICC_DumpISO14443_4(TagInfo *tag); 111 | 112 | ///////////////////////////////////////////////////////////////////////////////////// 113 | // Convenience functions - does not add extra functionality 114 | ///////////////////////////////////////////////////////////////////////////////////// 115 | bool PICC_IsNewCardPresent() override; // overrride 116 | bool PICC_ReadCardSerial() override; // overrride 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/MFRC522Hack.cpp: -------------------------------------------------------------------------------- 1 | #include "MFRC522Hack.h" 2 | 3 | /** 4 | * Performs the "magic sequence" needed to get Chinese UID changeable 5 | * Mifare cards to allow writing to sector 0, where the card UID is stored. 6 | * 7 | * Note that you do not need to have selected the card through REQA or WUPA, 8 | * this sequence works immediately when the card is in the reader vicinity. 9 | * This means you can use this method even on "bricked" cards that your reader does 10 | * not recognise anymore (see MFRC522Hack::MIFARE_UnbrickUidSector). 11 | * 12 | * Of course with non-bricked devices, you're free to select them before calling this function. 13 | */ 14 | bool MFRC522Hack::MIFARE_OpenUidBackdoor(const bool logErrors) const { 15 | // Magic sequence: 16 | // > 50 00 57 CD (HALT + CRC) 17 | // > 40 (7 bits only) 18 | // < A (4 bits only) 19 | // > 43 20 | // < A (4 bits only) 21 | // Then you can write to sector 0 without authenticating 22 | 23 | _device->PICC_HaltA(); // 50 00 57 CD 24 | 25 | byte cmd = 0x40; 26 | byte validBits = 7; /* Our command is only 7 bits. After receiving card response, 27 | this will contain amount of valid response bits. */ 28 | byte response[32]; // Card's response is written here 29 | byte received; 30 | MFRC522::StatusCode status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0, 31 | false); // 40 32 | if (status != MFRC522::STATUS_OK) { 33 | if (logErrors) { 34 | Serial.println( 35 | F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); 36 | Serial.print(F("Error name: ")); 37 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 38 | } 39 | return false; 40 | } 41 | if (received != 1 || response[0] != 0x0A) { 42 | if (logErrors) { 43 | Serial.print(F("Got bad response on backdoor 0x40 command: ")); 44 | Serial.print(response[0], HEX); 45 | Serial.print(F(" (")); 46 | Serial.print(validBits); 47 | Serial.print(F(" valid bits)\r\n")); 48 | } 49 | return false; 50 | } 51 | 52 | cmd = 0x43; 53 | validBits = 8; 54 | status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0, false); // 43 55 | if (status != MFRC522::STATUS_OK) { 56 | if (logErrors) { 57 | Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); 58 | Serial.print(F("Error name: ")); 59 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 60 | } 61 | return false; 62 | } 63 | if (received != 1 || response[0] != 0x0A) { 64 | if (logErrors) { 65 | Serial.print(F("Got bad response on backdoor 0x43 command: ")); 66 | Serial.print(response[0], HEX); 67 | Serial.print(F(" (")); 68 | Serial.print(validBits); 69 | Serial.print(F(" valid bits)\r\n")); 70 | } 71 | return false; 72 | } 73 | 74 | // You can now write to sector 0 without authenticating! 75 | return true; 76 | } // End MIFARE_OpenUidBackdoor() 77 | 78 | /** 79 | * Reads entire block 0, including all manufacturer data, and overwrites 80 | * that block with the new UID, a freshly calculated BCC, and the original 81 | * manufacturer data. 82 | * 83 | * It assumes a default KEY A of 0xFFFFFFFFFFFF. 84 | * Make sure to have selected the card before this function is called. 85 | */ 86 | bool MFRC522Hack::MIFARE_SetUid(const byte *newUid, const byte uidSize, const bool logErrors) const { 87 | 88 | // UID + BCC byte can not be larger than 16 together 89 | if (!newUid || !uidSize || uidSize > 15) { 90 | if (logErrors) { 91 | Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); 92 | } 93 | return false; 94 | } 95 | 96 | // Authenticate for reading 97 | MFRC522::MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 98 | MFRC522::StatusCode status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid)); 99 | if (status != MFRC522::STATUS_OK) { 100 | 101 | if (status == MFRC522::STATUS_TIMEOUT) { 102 | // We get a read timeout if no card is selected yet, so let's select one 103 | 104 | // Wake the card up again if sleeping 105 | // byte atqa_answer[2]; 106 | // byte atqa_size = 2; 107 | // PICC_WakeupA(atqa_answer, &atqa_size); 108 | 109 | if (!_device->PICC_IsNewCardPresent() || !_device->PICC_ReadCardSerial()) { 110 | Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); 111 | return false; 112 | } 113 | 114 | status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid)); 115 | if (status != MFRC522::STATUS_OK) { 116 | // We tried, time to give up 117 | if (logErrors) { 118 | Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); 119 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 120 | } 121 | return false; 122 | } 123 | } else { 124 | if (logErrors) { 125 | Serial.print(F("PCD_Authenticate() failed: ")); 126 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 127 | } 128 | return false; 129 | } 130 | } 131 | 132 | // Read block 0 133 | byte block0_buffer[18]; 134 | byte byteCount = sizeof(block0_buffer); 135 | status = _device->MIFARE_Read((byte) 0, block0_buffer, &byteCount); 136 | if (status != MFRC522::STATUS_OK) { 137 | if (logErrors) { 138 | Serial.print(F("MIFARE_Read() failed: ")); 139 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 140 | Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); 141 | } 142 | return false; 143 | } 144 | 145 | // Write new UID to the data we just read, and calculate BCC byte 146 | byte bcc = 0; 147 | for (uint8_t i = 0; i < uidSize; i++) { 148 | block0_buffer[i] = newUid[i]; 149 | bcc ^= newUid[i]; 150 | } 151 | 152 | // Write BCC byte to buffer 153 | block0_buffer[uidSize] = bcc; 154 | 155 | // Stop encrypted traffic so we can send raw bytes 156 | _device->PCD_StopCrypto1(); 157 | 158 | // Activate UID backdoor 159 | if (!MIFARE_OpenUidBackdoor(logErrors)) { 160 | if (logErrors) { 161 | Serial.println(F("Activating the UID backdoor failed.")); 162 | } 163 | return false; 164 | } 165 | 166 | // Write modified block 0 back to card 167 | status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16); 168 | if (status != MFRC522::STATUS_OK) { 169 | if (logErrors) { 170 | Serial.print(F("MIFARE_Write() failed: ")); 171 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 172 | } 173 | return false; 174 | } 175 | 176 | // Wake the card up again 177 | byte atqa_answer[2]; 178 | byte atqa_size = 2; 179 | _device->PICC_WakeupA(atqa_answer, &atqa_size); 180 | 181 | return true; 182 | } 183 | 184 | /** 185 | * Resets entire sector 0 to zeroes, so the card can be read again by readers. 186 | */ 187 | bool MFRC522Hack::MIFARE_UnbrickUidSector(const bool logErrors) const { 188 | MIFARE_OpenUidBackdoor(logErrors); 189 | 190 | byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 191 | 0x00}; 192 | 193 | // Write modified block 0 back to card 194 | MFRC522::StatusCode status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16); 195 | if (status != MFRC522::STATUS_OK) { 196 | if (logErrors) { 197 | Serial.print(F("MIFARE_Write() failed: ")); 198 | Serial.println(MFRC522Debug::GetStatusCodeName(status)); 199 | } 200 | return false; 201 | } 202 | return true; 203 | } 204 | -------------------------------------------------------------------------------- /src/MFRC522Hack.h: -------------------------------------------------------------------------------- 1 | #ifndef MFRC522HACK_H 2 | #define MFRC522HACK_H 3 | 4 | #include 5 | #include "MFRC522.h" 6 | #include "MFRC522Debug.h" 7 | 8 | class MFRC522Hack { 9 | private: 10 | MFRC522 *const _device; 11 | public: 12 | MFRC522Hack(MFRC522 *const device) : _device(device) {}; 13 | 14 | bool MIFARE_OpenUidBackdoor(const bool logErrors) const; 15 | 16 | bool MIFARE_SetUid(const byte *newUid, const byte uidSize, const bool logErrors) const; 17 | 18 | bool MIFARE_UnbrickUidSector(const bool logErrors) const; 19 | }; 20 | 21 | 22 | #endif //MFRC522HACK_H 23 | -------------------------------------------------------------------------------- /src/PBOC/PBOC.cpp: -------------------------------------------------------------------------------- 1 | #include "PBOC.h" 2 | 3 | char PBOC::PSE[] ="1PAY.SYS.DDF01"; 4 | char PBOC::PPSE[] ="2PAY.SYS.DDF01"; 5 | 6 | PBOC::Respond PBOC::select(byte len, byte* data){ 7 | Respond ret; 8 | byte* buf1 = pool.getBytes(), *buf2 = pool.getBytes(); 9 | len = addLen(len, data, buf1); 10 | static const byte select_command[] = {0x00, 0xA4, 0x04, 0x00}; 11 | len = concatBytes(4, len, select_command, buf1, buf2); 12 | ret.len = pool.BUFLEN; 13 | ret.status = base.TCL_Transceive(&tag, buf2, len, buf1, &ret.len); 14 | if(ret.status == MFRC522::STATUS_OK){ 15 | ret.sw2 = buf1[--ret.len]; 16 | ret.sw1 = buf1[--ret.len]; 17 | ret.info = buf1; 18 | }else{ 19 | ret.info = NULL; 20 | ret.sw1 = ret.sw2 = ret.len = 0; 21 | pool.release(buf1); 22 | } 23 | pool.release(buf2); 24 | return ret; 25 | } 26 | bool PBOC::PSE_FCI::init(byte len, byte* data){ 27 | byte* x = data; 28 | if(*x == 0x6f){ 29 | fci = tlv(++x); 30 | x += 1; 31 | if(*x == 0x84){ 32 | df = tlv(++x); 33 | x += df.len() + 1; 34 | }else goto ParseError; 35 | if(*x == 0xa5){ 36 | fcip = tlv(++x); 37 | x += 1; 38 | if(*x == 0x88){ 39 | sfi = tlv(++x); 40 | x += sfi.len() + 1; 41 | }else goto ParseError; 42 | if(x < data + len && *x == 0x5f && *(x + 1) == 0x2d){ 43 | x += 2; 44 | lp = tlv(x); 45 | x += lp.len() + 1; 46 | } 47 | if(x < data + len && *x == 0x9f && *(x + 1) == 0x11){ 48 | x += 2; 49 | icti = tlv(x); 50 | x += icti.len() + 1; 51 | } 52 | }else goto ParseError; 53 | } else goto ParseError; 54 | if(x == data + len) return true; else {Serial.print('Parse finished at ');Serial.print(x - data);} 55 | ParseError: 56 | Serial.print('ParseError!'); 57 | return false; 58 | } 59 | 60 | PBOC::Respond PBOC::readRecord(tlv sfi, byte p1){ 61 | byte buf1[] = {0x00, 0xb2, p1, 0x04, 0x00}; 62 | byte* buf2 = pool.getBytes(); 63 | buf1[3] += (*sfi.data()) << 3; 64 | Respond ret; 65 | ret.len = pool.BUFLEN; 66 | // dump_byte_array(buf1, 5); 67 | ret.status = base.TCL_Transceive(&tag, buf1, 5, buf2, &ret.len); 68 | if(ret.status == MFRC522::STATUS_OK){ 69 | ret.sw2 = buf2[--ret.len]; 70 | ret.sw1 = buf2[--ret.len]; 71 | ret.info = buf2; 72 | }else{ 73 | ret.info = NULL; 74 | ret.sw1 = ret.sw2 = ret.len = 0; 75 | } 76 | return ret; 77 | } 78 | bool PBOC::ADFS::init(byte len, byte* data){ 79 | tot = 0; 80 | byte* x = data; 81 | if(*x == 0x70 && *(x + 1) + 2 == len){ 82 | x += 2; 83 | 84 | while(x < data + len){ 85 | if(*x != 0x61) break; 86 | if(tot == MAXADF) break; 87 | l[tot++].init(x); 88 | x += *(x + 1) + 2; 89 | } 90 | } 91 | if(x == data + len) return true; 92 | Serial.print(F("ParseError!")); 93 | return false; 94 | } 95 | 96 | void PBOC::ADF::init(byte* x){ 97 | if(*x == 0x61){ 98 | x += 2; 99 | if(*x == 0x4f){ 100 | aid.set(++x); 101 | x += aid.len() + 1; 102 | } 103 | if(*x == 0x50){ 104 | label.set(++x); 105 | x += label.len() + 1; 106 | } 107 | if(*x == 0x87){ 108 | api.set(++x); 109 | x += api.len() + 1; 110 | } 111 | if(*x == 0x9f && *(x + 1) == 0x12) 112 | { 113 | x += 2; 114 | apn.set(x); 115 | x += apn.len() + 1; 116 | } 117 | } 118 | } 119 | PBOC::Respond PBOC::gpo(byte len, byte* data) 120 | { 121 | static const byte gpo_command[] = {0x80, 0xA8, 0x00, 0x00}; 122 | byte * buf1 = pool.getBytes(), *buf2 = pool.getBytes(); 123 | len = addLen(len, data, buf1, false); 124 | byte tmpchar = 0x83; 125 | len = concatBytes(1, len, &tmpchar, buf1, buf2); 126 | len = addLen(len, buf2, buf1); 127 | len = concatBytes(4, len, gpo_command, buf1, buf2); 128 | Respond ret; 129 | ret.len = pool.BUFLEN; 130 | ret.status = base.TCL_Transceive(&tag, buf2, len, buf1, &ret.len); 131 | if(ret.status == MFRC522::STATUS_OK){ 132 | ret.sw2 = buf1[--ret.len]; 133 | ret.sw1 = buf1[--ret.len]; 134 | ret.info = buf1; 135 | }else{ 136 | ret.info = NULL; 137 | ret.sw1 = ret.sw2 = ret.len = 0; 138 | pool.release(buf1); 139 | } 140 | pool.release(buf2); 141 | return ret; 142 | } 143 | PBOC::Respond PBOC::getData(byte p1, byte p2){ 144 | byte gpo_command[] = {0x80, 0xCA, p1, p2, 0x00}; 145 | byte * buf1 = pool.getBytes(); 146 | Respond ret; 147 | ret.len = pool.BUFLEN; 148 | ret.status = base.TCL_Transceive(&tag, gpo_command, 5, buf1, &ret.len); 149 | if(ret.status == MFRC522::STATUS_OK){ 150 | ret.sw2 = buf1[--ret.len]; 151 | ret.sw1 = buf1[--ret.len]; 152 | ret.info = buf1; 153 | }else{ 154 | ret.info = NULL; 155 | ret.sw1 = ret.sw2 = ret.len = 0; 156 | pool.release(buf1); 157 | } 158 | return ret; 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/PBOC/PBOC.h: -------------------------------------------------------------------------------- 1 | #ifndef pboc_h 2 | #define pboc_h 3 | #include 4 | #include "../MFRC522Extended.h" 5 | #include "utils.h" 6 | 7 | class PBOC{ 8 | private: 9 | PBOC(){} 10 | public: 11 | static char PSE[]; 12 | static char PPSE[]; 13 | 14 | MFRC522Extended base; 15 | BytePool pool; 16 | MFRC522Extended::TagInfo tag; 17 | 18 | PBOC(uint8_t ss, uint8_t rst):base(ss, rst), pool(){} 19 | void init(){ 20 | base.PCD_Init(); 21 | tag.blockNumber = false; 22 | tag.ats.tc1.supportsCID = false; 23 | tag.ats.tc1.supportsNAD = false; 24 | } 25 | bool active(){ 26 | return base.PICC_IsNewCardPresent() && base.PICC_ReadCardSerial(); 27 | } 28 | void printUID(){ 29 | Serial.print(F("Card UID:")); 30 | dump_byte_array(base.uid.uidByte, base.uid.size); 31 | Serial.println(); 32 | } 33 | void halt(){ 34 | base.PICC_HaltA(); 35 | base.PCD_StopCrypto1(); 36 | } 37 | typedef struct { 38 | MFRC522::StatusCode status; 39 | byte sw1; 40 | byte sw2; 41 | byte* info; 42 | byte len; 43 | } Respond; 44 | 45 | Respond select(byte len, byte* data); 46 | struct PSE_FCI{ 47 | tlv fci, df;// Dedicated File Name 48 | tlv fcip;// FCI propritetary Template 49 | tlv sfi, lp, icti;//Short file identifier, language perference, issuer code table index 50 | bool init(byte len, byte* data); 51 | }; // File Control Information Template 52 | Respond readRecord(tlv sfi, byte p1); 53 | struct ADF{// Application Definition File 54 | tlv aid; // Application Identifier 55 | tlv label; //Application Label 56 | tlv api; // Application Priority Indicator 57 | tlv apn; // Application Priority Name; 58 | ADF(){} 59 | void init(byte* data); 60 | }; 61 | struct ADFS{ 62 | enum consts : byte { MAXADF = 3}; 63 | ADF l[MAXADF]; 64 | byte tot; 65 | bool init(byte len, byte* data); 66 | }; 67 | Respond gpo(byte len, byte* data); 68 | Respond getData(byte p1, byte p2); 69 | }; 70 | 71 | #endif -------------------------------------------------------------------------------- /src/PBOC/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | byte addLen(byte len, byte* value, byte * buf, bool addzero){ 3 | buf[0] = len; 4 | memcpy(buf + 1, value, len); 5 | if(addzero){ 6 | buf[len + 1] = 0; 7 | return len + 2; 8 | } 9 | return len + 1; 10 | } 11 | byte concatBytes(byte l1, byte l2, byte* s1, byte* s2, byte* s3){ 12 | if(s2 != s3){ 13 | memmove(s3, s1, l1); 14 | memcpy(s3 + l1, s2, l2); 15 | return l1 + l2; 16 | }else{ 17 | Serial.print(F("Overlap in concat!")); 18 | return 0; 19 | } 20 | } 21 | void dump_byte_array(byte *buffer, byte bufferSize) { 22 | for (byte i = 0; i < bufferSize; i++) { 23 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 24 | Serial.print(buffer[i], HEX); 25 | } 26 | } 27 | int printUntil(byte* data, byte end){ 28 | for(int i = 0;i < 256;i++){ 29 | byte h1 = data[i] >> 4; 30 | byte h2 = data[i] & 0xF; 31 | if(h1 == end) return i * 2; 32 | Serial.print(h1, HEX); 33 | if(h2 == end) return i * 2 + 1; 34 | Serial.print(h2, HEX); 35 | } 36 | } 37 | int printHalfBytes(byte* data, int begin, byte len) 38 | { 39 | for(int i = 0;i < len;i++){ 40 | byte h = 0; 41 | if(begin & 1) h = data[begin >> 1] & 0xF; 42 | else h = data[begin >> 1] >> 4; 43 | Serial.print(h, HEX); 44 | begin++; 45 | } 46 | return begin; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/PBOC/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef utils_h 2 | #define utils_h 3 | #include 4 | 5 | byte addLen(byte len, byte* value, byte * buf, bool addzero = true); 6 | byte concatBytes(byte l1, byte l2, byte* s1, byte* s2, byte* s3); 7 | void dump_byte_array(byte *buffer, byte bufferSize); 8 | int printUntil(byte* data, byte end = 0x00); 9 | int printHalfBytes(byte* data, int begin, byte len); 10 | class BytePool{ 11 | public: 12 | byte total; 13 | static const byte MAXPOOL = 5; 14 | static const byte BUFLEN = 128; 15 | byte* pool[MAXPOOL]; 16 | bool used[MAXPOOL]; 17 | byte defaultPool[BUFLEN * MAXPOOL]; 18 | BytePool():total(0){ 19 | memset(used, 0, sizeof(used)); 20 | total = MAXPOOL; 21 | for(byte i = 0;i < total;i++) 22 | pool[i] = defaultPool + i * BUFLEN; 23 | } 24 | byte* getBytes(){ 25 | for(int i = 0;i < total;i++) 26 | if(!used[i]){ 27 | used[i] = true; 28 | return pool[i]; 29 | } 30 | Serial.println("No buffer~~~"); 31 | return NULL; 32 | } 33 | byte release(byte * buf){ 34 | /* 35 | 0 : normal return 36 | 1 : used error 37 | 2 : do not managed by pool 38 | */ 39 | for(int i = 0;i < total;i++) 40 | if(pool[i] == buf){ 41 | if(!used[i]) return 1; 42 | used[i] = false; 43 | return 0; 44 | } 45 | return 2; 46 | } 47 | }; 48 | 49 | struct tlv{ 50 | byte * p; 51 | tlv(byte* _p):p(_p){} 52 | tlv():p(NULL){} 53 | void set(byte* _p){p = _p;} 54 | byte len(){ return p?*p:0; } 55 | byte* data(){ return p + 1; } 56 | }; 57 | #endif 58 | -------------------------------------------------------------------------------- /src/deprecated.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016 by Ludwig Grill (www.rotzbua.de) 3 | * Simple deprecated workaround for Arduino IDE 4 | * IDE 1.6.8 use gcc 4.8 which do not support c++14 [[deprecated]] 5 | * Later versions should support c++14, then use c++14 syntax 6 | */ 7 | #ifndef DEPRECATED_H 8 | #define DEPRECATED_H 9 | 10 | #ifdef __has_cpp_attribute 11 | #if __has_cpp_attribute(deprecated) 12 | #define DEPRECATED [[deprecated]] 13 | #define DEPRECATED_MSG(msg) [[deprecated(msg)]] 14 | #endif // __has_cpp_attribute(deprecated) 15 | #else 16 | #define DEPRECATED __attribute__((deprecated)) 17 | #define DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) 18 | #endif // __has_cpp_attribute 19 | 20 | #endif // DEPRECATED_H 21 | -------------------------------------------------------------------------------- /src/require_cpp11.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016 by Ludwig Grill (www.rotzbua.de) 3 | * Throws error if c++11 is not supported 4 | */ 5 | #ifndef REQUIRE_CPP11_H 6 | #define REQUIRE_CPP11_H 7 | 8 | #if __cplusplus < 201103L 9 | #error "This library needs at least a C++11 compliant compiler, maybe compiler argument for C++11 support is missing or if you use Arduino IDE upgrade to version >=1.6.6" 10 | #endif 11 | 12 | #endif // REQUIRE_CPP11_H 13 | --------------------------------------------------------------------------------