Adafruit_MFRC630.cpp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. /*!
  2. * @file Adafruit_MFRC630.cpp
  3. *
  4. * @mainpage Adafruit MFRC630 Library
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * This is a library for the Adafruit MFRC630 Breakout
  9. *
  10. * Designed specifically to work with the Adafruit MFRC630 Breakout:
  11. * http://www.adafruit.com/products/xxx
  12. *
  13. * These boards use I2C to communicate, 2 pins are required to interface.
  14. *
  15. * Adafruit invests time and resources providing this open source code,
  16. * please support Adafruit andopen-source hardware by purchasing products
  17. * from Adafruit!
  18. *
  19. * @section author Author
  20. *
  21. * Written by Kevin Townsend for Adafruit Industries.
  22. *
  23. * @section license License
  24. *
  25. * BSD license, all text above must be included in any redistribution
  26. */
  27. #include "Adafruit_MFRC630.h"
  28. /***************************************************************************
  29. PRIVATE FUNCTIONS
  30. ***************************************************************************/
  31. static unsigned char rev8_lookup[16] = {0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
  32. 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf};
  33. /*!
  34. * @brief Uses the lookup table above to reverse a single byte.
  35. * @param n Input byte
  36. * @return uint8_t. A byte
  37. */
  38. uint8_t reverse8(uint8_t n) {
  39. return (rev8_lookup[n & 0b1111] << 4) | rev8_lookup[n >> 4];
  40. }
  41. /**************************************************************************/
  42. /*!
  43. @brief Write a byte to the specified register
  44. */
  45. /**************************************************************************/
  46. void Adafruit_MFRC630::write8(byte reg, byte value) {
  47. TRACE_TIMESTAMP();
  48. TRACE_PRINT(F("Writing 0x"));
  49. TRACE_PRINT(value, HEX);
  50. TRACE_PRINT(F(" to 0x"));
  51. TRACE_PRINTLN(reg, HEX);
  52. switch (_transport) {
  53. case MFRC630_TRANSPORT_I2C:
  54. /* I2C */
  55. _wire->beginTransmission(_i2c_addr);
  56. _wire->write(reg);
  57. _wire->write(value);
  58. _wire->endTransmission();
  59. break;
  60. case MFRC630_TRANSPORT_SPI:
  61. /* SPI */
  62. digitalWrite(_cs, LOW);
  63. SPI.transfer((reg << 1) | 0x00);
  64. SPI.transfer(value);
  65. digitalWrite(_cs, HIGH);
  66. break;
  67. case MFRC630_TRANSPORT_SERIAL:
  68. /* TODO: Adjust for 10-bit protocol! */
  69. _serial->write((reg << 1) | 0x00);
  70. _serial->write(value);
  71. break;
  72. }
  73. }
  74. /**************************************************************************/
  75. /*!
  76. @brief Write a buffer to the specified register
  77. */
  78. /**************************************************************************/
  79. void Adafruit_MFRC630::writeBuffer(byte reg, uint16_t len, uint8_t *buffer) {
  80. TRACE_TIMESTAMP();
  81. TRACE_PRINT(F("Writing "));
  82. TRACE_PRINT(len);
  83. TRACE_PRINT(F(" byte(s) to 0x"));
  84. TRACE_PRINTLN(reg, HEX);
  85. TRACE_TIMESTAMP();
  86. switch (_transport) {
  87. case MFRC630_TRANSPORT_I2C:
  88. /* I2C */
  89. _wire->beginTransmission(_i2c_addr);
  90. _wire->write(reg);
  91. for (uint16_t i = 0; i < len; i++) {
  92. _wire->write(buffer[i]);
  93. TRACE_PRINT(F("0x"));
  94. TRACE_PRINT(buffer[i], HEX);
  95. TRACE_PRINT(F(" "));
  96. }
  97. _wire->endTransmission();
  98. break;
  99. case MFRC630_TRANSPORT_SPI:
  100. /* SPI */
  101. digitalWrite(_cs, LOW);
  102. SPI.transfer((reg << 1) | 0x00);
  103. for (uint8_t i = 0; i < len; i++) {
  104. SPI.transfer(buffer[i]);
  105. TRACE_PRINT(F("0x"));
  106. TRACE_PRINT(buffer[i], HEX);
  107. TRACE_PRINT(F(" "));
  108. }
  109. digitalWrite(_cs, HIGH);
  110. break;
  111. case MFRC630_TRANSPORT_SERIAL:
  112. _serial->write((reg << 1) | 0x00);
  113. for (uint16_t i = 0; i < len; i++) {
  114. _serial->write(buffer[i]);
  115. TRACE_PRINT(F("0x"));
  116. TRACE_PRINT(buffer[i], HEX);
  117. TRACE_PRINT(F(" "));
  118. }
  119. break;
  120. }
  121. TRACE_PRINTLN("");
  122. }
  123. /**************************************************************************/
  124. /*!
  125. @brief Read a byte from the specified register
  126. */
  127. /**************************************************************************/
  128. byte Adafruit_MFRC630::read8(byte reg) {
  129. uint8_t resp = 0;
  130. uint8_t tx[2] = {0};
  131. uint8_t rx[2] = {0};
  132. uint8_t timeout = 0xFF;
  133. TRACE_TIMESTAMP();
  134. TRACE_PRINT(F("Requesting 1 byte from 0x"));
  135. TRACE_PRINTLN(reg, HEX);
  136. switch (_transport) {
  137. case MFRC630_TRANSPORT_I2C:
  138. /* I2C */
  139. #ifdef __SAM3X8E__
  140. /* http://forum.arduino.cc/index.php?topic=385377.msg2947227#msg2947227 */
  141. _wire->requestFrom(_i2c_addr, 1, reg, 1, true);
  142. #else
  143. _wire->beginTransmission(_i2c_addr);
  144. _wire->write(reg);
  145. _wire->endTransmission();
  146. _wire->requestFrom((uint8_t)_i2c_addr, (uint8_t)1);
  147. #endif
  148. /* Dump the response into the supplied buffer */
  149. resp = _wire->read();
  150. break;
  151. case MFRC630_TRANSPORT_SPI:
  152. /* SPI */
  153. digitalWrite(_cs, LOW);
  154. tx[0] = (reg << 1) | 0x01;
  155. tx[1] = 0;
  156. rx[0] = SPI.transfer(tx[0]);
  157. rx[1] = SPI.transfer(tx[1]);
  158. digitalWrite(_cs, HIGH);
  159. resp = rx[1];
  160. break;
  161. case MFRC630_TRANSPORT_SERIAL:
  162. tx[0] = (reg << 1) | 0x01;
  163. _serial->write(tx[0]);
  164. while (!_serial->available()) {
  165. delay(1);
  166. timeout--;
  167. if (timeout == 0) {
  168. return 0;
  169. }
  170. }
  171. resp = _serial->read();
  172. delay(1);
  173. /* Check for stray byte(s) */
  174. while (_serial->available()) {
  175. _serial->read();
  176. delay(1);
  177. }
  178. break;
  179. }
  180. TRACE_TIMESTAMP();
  181. TRACE_PRINT(F("Response = "));
  182. TRACE_PRINT(F(" 0x"));
  183. if (resp <= 0xF) {
  184. TRACE_PRINT(F("0"));
  185. }
  186. TRACE_PRINT(resp, HEX);
  187. TRACE_PRINTLN(F(""));
  188. return resp;
  189. }
  190. /***************************************************************************
  191. CONSTRUCTOR
  192. ***************************************************************************/
  193. /**************************************************************************/
  194. /*!
  195. @brief Instantiates a new instance of the Adafruit_MFRC630 class
  196. using the default I2C bus.
  197. */
  198. /**************************************************************************/
  199. Adafruit_MFRC630::Adafruit_MFRC630(uint8_t i2c_addr, int8_t pdown_pin) {
  200. /* Set the transport */
  201. _transport = MFRC630_TRANSPORT_I2C;
  202. /* Set the PDOWN pin */
  203. _pdown = pdown_pin;
  204. /* Set the I2C address */
  205. _i2c_addr = i2c_addr;
  206. /* Set the I2C bus instance */
  207. _wire = &Wire;
  208. /* Disable SPI access. */
  209. _cs = -1;
  210. /* Disable SW serial access */
  211. _serial = NULL;
  212. }
  213. /**************************************************************************/
  214. /*!
  215. @brief Instantiates a new instance of the Adafruit_MFRC630 class
  216. using the specified I2C bus.
  217. */
  218. /**************************************************************************/
  219. Adafruit_MFRC630::Adafruit_MFRC630(TwoWire *wireBus, uint8_t i2c_addr,
  220. int8_t pdown_pin) {
  221. /* Set the transport */
  222. _transport = MFRC630_TRANSPORT_I2C;
  223. /* Set the PDOWN pin */
  224. _pdown = pdown_pin;
  225. /* Set the I2C address */
  226. _i2c_addr = i2c_addr;
  227. /* Set the I2C bus instance */
  228. _wire = wireBus;
  229. /* Disable SPI access. */
  230. _cs = -1;
  231. /* Disable SW serial access */
  232. _serial = NULL;
  233. }
  234. /**************************************************************************/
  235. /*!
  236. @brief Instantiates a new instance of the Adafruit_MFRC630 class
  237. using the HW SPI bus.
  238. */
  239. /**************************************************************************/
  240. Adafruit_MFRC630::Adafruit_MFRC630(enum mfrc630_transport transport, int8_t cs,
  241. int8_t pdown_pin) {
  242. /* Set the transport */
  243. _transport = transport;
  244. /* Set the PDOWN pin */
  245. _pdown = pdown_pin;
  246. /* Set the CS/SSEL pin */
  247. _cs = cs;
  248. pinMode(_cs, OUTPUT);
  249. /* Disable I2C access */
  250. _wire = NULL;
  251. _i2c_addr = 0;
  252. /* Disable SW serial access */
  253. _serial = NULL;
  254. }
  255. /**************************************************************************/
  256. /*!
  257. @brief Instantiates a new instance of the Adafruit_MFRC630 class
  258. using the specified Serial block.
  259. */
  260. /**************************************************************************/
  261. Adafruit_MFRC630::Adafruit_MFRC630(Stream *serial, int8_t pdown_pin) {
  262. /* Set the transport */
  263. _transport = MFRC630_TRANSPORT_SERIAL;
  264. /* Set the PDOWN pin */
  265. _pdown = pdown_pin;
  266. /* Set the Serial instance */
  267. _serial = serial;
  268. /* Disable I2C access */
  269. _wire = NULL;
  270. _i2c_addr = 0;
  271. /* Disable SPI access. */
  272. _cs = -1;
  273. }
  274. /***************************************************************************
  275. PUBLIC FUNCTIONS
  276. ***************************************************************************/
  277. /**************************************************************************/
  278. /*!
  279. @brief Sets up the HW
  280. */
  281. /**************************************************************************/
  282. bool Adafruit_MFRC630::begin() {
  283. /* Display alert for DEBUG and TRACE output. */
  284. DEBUG_PRINTLN(F("\tDebug output enabled: D [+ms] Message"));
  285. TRACE_PRINTLN(F("\tTrace output enabled: . [+ms] Message"));
  286. DEBUG_PRINTLN(F(""));
  287. /* Enable I2C, SPI or SW serial */
  288. DEBUG_TIMESTAMP();
  289. switch (_transport) {
  290. case MFRC630_TRANSPORT_I2C:
  291. DEBUG_PRINTLN(F("Initialising I2C"));
  292. _wire->begin();
  293. break;
  294. case MFRC630_TRANSPORT_SPI:
  295. DEBUG_PRINTLN(F("Initialising SPI (Mode 0, MSB, DIV16)"));
  296. SPI.begin();
  297. SPI.setDataMode(SPI_MODE0);
  298. SPI.setBitOrder(MSBFIRST);
  299. #ifdef SPI_CLOCK_DIV16
  300. SPI.setClockDivider(SPI_CLOCK_DIV16);
  301. #endif
  302. break;
  303. case MFRC630_TRANSPORT_SERIAL:
  304. /* NOTE: 'Serial' has to be initialised in the calling sketch! */
  305. break;
  306. }
  307. /* Reset the MFRC630 if possible */
  308. if (_pdown != -1) {
  309. DEBUG_TIMESTAMP();
  310. DEBUG_PRINTLN(F("Resetting MFRC630"));
  311. pinMode(_pdown, OUTPUT);
  312. digitalWrite(_pdown, HIGH);
  313. digitalWrite(_pdown, LOW);
  314. digitalWrite(_pdown, HIGH);
  315. digitalWrite(_pdown, LOW);
  316. /* Typical 2.5ms startup delay */
  317. delay(5);
  318. }
  319. /* Check device ID for bus response */
  320. DEBUG_TIMESTAMP();
  321. DEBUG_PRINTLN(F("Checking transport layer"));
  322. /* Read the VERSION register */
  323. byte ver = read8(MFRC630_REG_VERSION);
  324. /* If ver == 0xFF or 0x0 likely a bus failure */
  325. if ((ver == 0xFF) || (ver == 0)) {
  326. DEBUG_TIMESTAMP();
  327. DEBUG_PRINTLN(F("Transport failure!"));
  328. return false;
  329. }
  330. /* If !1.8, there was a problem */
  331. if (ver != 0x18) {
  332. DEBUG_TIMESTAMP();
  333. DEBUG_PRINTLN(F("FAILED!"));
  334. return false;
  335. }
  336. DEBUG_TIMESTAMP();
  337. DEBUG_PRINT(F("IC Version = "));
  338. DEBUG_PRINT((ver & 0xF0) >> 4, HEX);
  339. DEBUG_PRINT(F("."));
  340. DEBUG_PRINTLN(ver & 0x0F, HEX);
  341. return true;
  342. }
  343. /**************************************************************************/
  344. /*!
  345. @brief Determines the number of bytes in the HW FIFO buffer (max 512)
  346. @returns The number of bytes available in the HW FIFO buffer
  347. */
  348. /**************************************************************************/
  349. int16_t Adafruit_MFRC630::readFIFOLen(void) {
  350. DEBUG_TIMESTAMP();
  351. DEBUG_PRINTLN(F("Checking FIFO length"));
  352. /* Give FIFO a chance to fill up. */
  353. /* TODO: Why do we need a delay between reads?!? */
  354. delay(10);
  355. /* Read the MFRC630_REG_FIFO_LENGTH register */
  356. /* In 512 byte mode, the upper two bits are stored in FIFO_CONTROL */
  357. byte hi = read8(MFRC630_REG_FIFO_CONTROL);
  358. byte lo = read8(MFRC630_REG_FIFO_LENGTH);
  359. /* Determine len based on FIFO size (255 byte or 512 byte mode) */
  360. int16_t l = (hi & 0x80) ? lo : (((hi & 0x3) << 8) | lo);
  361. DEBUG_TIMESTAMP();
  362. DEBUG_PRINT(F("FIFO contains "));
  363. DEBUG_PRINT(l);
  364. DEBUG_PRINTLN(F(" byte(s)"));
  365. return l;
  366. }
  367. /**************************************************************************/
  368. /*!
  369. @brief Read 'len' bytes from the HW FIFO buffer (max 512 bytes)
  370. @returns The number of bytes read from the FIFO, or -1 if an error occured.
  371. */
  372. /**************************************************************************/
  373. int16_t Adafruit_MFRC630::readFIFO(uint16_t len, uint8_t *buffer) {
  374. int16_t counter = 0;
  375. /* Check for 512 byte overflow */
  376. if (len > 512) {
  377. return -1;
  378. }
  379. DEBUG_TIMESTAMP();
  380. DEBUG_PRINT(F("Reading "));
  381. DEBUG_PRINT(len);
  382. DEBUG_PRINTLN(F(" byte(s) from FIFO"));
  383. /* Read len bytes from the FIFO */
  384. for (uint16_t i = 0; i < len; i++) {
  385. buffer[i] = read8(MFRC630_REG_FIFO_DATA);
  386. counter++;
  387. }
  388. return counter;
  389. }
  390. /**************************************************************************/
  391. /*!
  392. @brief Writes the specified number of bytes to the HW FIFO
  393. @returns The number of bytes written to the FIFO, -1 if an error occured.
  394. */
  395. /**************************************************************************/
  396. int16_t Adafruit_MFRC630::writeFIFO(uint16_t len, uint8_t *buffer) {
  397. int counter = 0;
  398. /* Check for 512 byte overflow */
  399. if (len > 512) {
  400. return -1;
  401. }
  402. DEBUG_TIMESTAMP();
  403. DEBUG_PRINT(F("Writing "));
  404. DEBUG_PRINT(len);
  405. DEBUG_PRINTLN(F(" byte(s) to FIFO"));
  406. /* Write len bytes to the FIFO */
  407. for (uint16_t i = 0; i < len; i++) {
  408. write8(MFRC630_REG_FIFO_DATA, buffer[i]);
  409. counter++;
  410. }
  411. return counter;
  412. }
  413. /**************************************************************************/
  414. /*!
  415. @brief Flushes the contents of the FIFo buffer
  416. */
  417. /**************************************************************************/
  418. void Adafruit_MFRC630::clearFIFO(void) {
  419. DEBUG_TIMESTAMP();
  420. DEBUG_PRINTLN(F("Clearing FIFO buffer "));
  421. uint8_t ctrl = read8(MFRC630_REG_FIFO_CONTROL);
  422. write8(MFRC630_REG_FIFO_CONTROL, ctrl | (1 << 4));
  423. }
  424. /**************************************************************************/
  425. /*!
  426. @brief Writes a parameter-less command to the internal state machine
  427. */
  428. /**************************************************************************/
  429. void Adafruit_MFRC630::writeCommand(byte command) {
  430. uint8_t buff[1] = {command};
  431. DEBUG_TIMESTAMP();
  432. DEBUG_PRINT(F("Sending CMD 0x"));
  433. DEBUG_PRINTLN(command, HEX);
  434. writeBuffer(MFRC630_REG_COMMAND, 1, buff);
  435. }
  436. /**************************************************************************/
  437. /*!
  438. @brief Writes a parameterised command to the internal state machine
  439. */
  440. /**************************************************************************/
  441. void Adafruit_MFRC630::writeCommand(byte command, uint8_t paramlen,
  442. uint8_t *params) {
  443. /* Arguments and/or data necessary to process a command are exchanged via
  444. the FIFO buffer:
  445. - Each command that needs a certain number of arguments will start
  446. processing only when it has received the correct number of arguments
  447. via the FIFO buffer.
  448. - The FIFO buffer is not cleared automatically at command start. It is
  449. recommended to write the command arguments and/or the data bytes into
  450. the FIFO buffer and start the command afterwards.
  451. - Each command may be stopped by the host by writing a new command code
  452. into the command register e.g.: the Idle-Command. */
  453. DEBUG_TIMESTAMP();
  454. DEBUG_PRINTLN(F("Sending Command"));
  455. /* Cancel any current command. */
  456. write8(MFRC630_REG_COMMAND, MFRC630_CMD_IDLE);
  457. /* Flush the FIFO */
  458. clearFIFO();
  459. /* Write data to the FIFO */
  460. writeFIFO(paramlen, params);
  461. /* Send the command */
  462. write8(MFRC630_REG_COMMAND, command);
  463. }
  464. /**************************************************************************/
  465. /*!
  466. @brief Gets the three bit COM status for the IC
  467. */
  468. /**************************************************************************/
  469. uint8_t Adafruit_MFRC630::getComStatus(void) {
  470. return (read8(MFRC630_REG_STATUS) & 0b111);
  471. }
  472. /**************************************************************************/
  473. /*!
  474. @brief Performs a soft reset of the IC
  475. */
  476. /**************************************************************************/
  477. void Adafruit_MFRC630::softReset(void) {
  478. writeCommand(MFRC630_CMD_SOFTRESET);
  479. delay(100);
  480. }
  481. /**************************************************************************/
  482. /*!
  483. @brief Prints out n bytes of hex data.
  484. */
  485. /**************************************************************************/
  486. void Adafruit_MFRC630::printHex(uint8_t *buf, size_t len) {
  487. if (len) {
  488. DEBUG_PRINT("[ ");
  489. }
  490. for (uint8_t i = 0; i < len; i++) {
  491. // DEBUG_PRINT("0x");
  492. if (buf[i] < 16) {
  493. DEBUG_PRINT(F("0"));
  494. }
  495. DEBUG_PRINT(buf[i], HEX);
  496. DEBUG_PRINT(F(" "));
  497. }
  498. if (len) {
  499. DEBUG_PRINT(F("]"));
  500. }
  501. }
  502. /**************************************************************************/
  503. /*!
  504. @brief Prints a human readable error code.
  505. */
  506. /**************************************************************************/
  507. void Adafruit_MFRC630::printError(enum mfrc630errors err) {
  508. ERROR_TIMESTAMP();
  509. ERROR_PRINT(F("ERROR! Danger, Will Robinson: "));
  510. switch (err) {
  511. case MFRC630_ERROR_INTEG:
  512. ERROR_PRINTLN(F("Data integrity!"));
  513. break;
  514. case MFRC630_ERROR_PROT:
  515. ERROR_PRINTLN(F("Protocol error!"));
  516. break;
  517. case MFRC630_ERROR_COLLDET:
  518. ERROR_PRINTLN(F("Collision detected!"));
  519. break;
  520. case MFRC630_ERROR_NODATA:
  521. ERROR_PRINTLN(F("No data!"));
  522. break;
  523. case MFRC630_ERROR_MINFRAME:
  524. ERROR_PRINTLN(F("Frame data too small!"));
  525. break;
  526. case MFRC630_ERROR_FIFOOVL:
  527. ERROR_PRINTLN(F("FIFO full!"));
  528. break;
  529. case MFRC630_ERROR_FIFOWR:
  530. ERROR_PRINTLN(F("Couldn't write to FIFO!"));
  531. break;
  532. case MFRC630_ERROR_EEPROM:
  533. ERROR_PRINTLN(F("EEPROM access!"));
  534. break;
  535. default:
  536. ERROR_PRINT(F("Unhandled error code: "));
  537. ERROR_PRINTLN(err, HEX);
  538. break;
  539. }
  540. /* Halt execution here if we're not in release mode! */
  541. #if MFRC630_VERBOSITY > MFRC630_VERBOSITY_RELEASE
  542. while (1) {
  543. delay(1);
  544. }
  545. #endif
  546. }
  547. /**************************************************************************/
  548. /*!
  549. @brief Configures the radio for the specified protocol
  550. */
  551. /**************************************************************************/
  552. bool Adafruit_MFRC630::configRadio(mfrc630radiocfg cfg) {
  553. DEBUG_TIMESTAMP();
  554. DEBUG_PRINT(F("Configuring the radio for "));
  555. switch (cfg) {
  556. case MFRC630_RADIOCFG_ISO1443A_106:
  557. DEBUG_PRINTLN(F("ISO1443A-106"));
  558. writeBuffer(MFRC630_REG_DRV_MOD, sizeof(antcfg_iso14443a_106),
  559. antcfg_iso14443a_106);
  560. DEBUG_TIMESTAMP();
  561. DEBUG_PRINTLN(F("Setting driver mode"));
  562. write8(MFRC630_REG_DRV_MOD, 0x8E); /* Driver mode register */
  563. DEBUG_TIMESTAMP();
  564. DEBUG_PRINTLN(F("Setting transmitter amplifier (residual carrier %)"));
  565. write8(MFRC630_REG_TX_AMP, 0x12); /* Transmiter amplifier register */
  566. DEBUG_TIMESTAMP();
  567. DEBUG_PRINTLN(F("Setting driver configuration"));
  568. write8(MFRC630_REG_DRV_CON, 0x39); /* Driver configuration register */
  569. DEBUG_TIMESTAMP();
  570. DEBUG_PRINTLN(F("Configuring transmitter (overshoot/TX load)"));
  571. write8(MFRC630_REG_TXL, 0x06); /* Transmitter register */
  572. break;
  573. default:
  574. DEBUG_PRINTLN(F("[UNKNOWN!]"));
  575. return false;
  576. break;
  577. }
  578. return true;
  579. }
  580. uint16_t Adafruit_MFRC630::iso14443aRequest(void) {
  581. return iso14443aCommand(ISO14443_CMD_REQA);
  582. }
  583. uint16_t Adafruit_MFRC630::iso14443aWakeup(void) {
  584. return iso14443aCommand(ISO14443_CMD_WUPA);
  585. }
  586. uint16_t Adafruit_MFRC630::iso14443aCommand(enum iso14443_cmd cmd) {
  587. uint16_t atqa = 0; /* Answer to request (2 bytes). */
  588. DEBUG_TIMESTAMP();
  589. DEBUG_PRINTLN(F("Checking for an ISO14443A tag"));
  590. /* Cancel any current command */
  591. writeCommand(MFRC630_CMD_IDLE);
  592. /* Flush the FIFO */
  593. clearFIFO();
  594. /*
  595. * Define the number of bits from the last byte should be sent. 000 means
  596. * that all bits of the last data byte are sent, 1..7 causes the specified
  597. * number of bits to be sent. Also set the DataEn bit to enable data xfer.
  598. */
  599. write8(MFRC630_REG_TX_DATA_NUM, 0x07 | (1 << 3));
  600. /* Disable CRC. */
  601. DEBUG_TIMESTAMP();
  602. DEBUG_PRINTLN(F("A. Disabling CRC checks."));
  603. write8(MFRC630_REG_TX_CRC_PRESET, 0x18);
  604. write8(MFRC630_REG_RX_CRC_CON, 0x18);
  605. /* Clear the receiver control register. */
  606. DEBUG_TIMESTAMP();
  607. DEBUG_PRINTLN(F("B. Clearing the receiver control register."));
  608. write8(MFRC630_REG_RX_BIT_CTRL, 0);
  609. /* Clear the interrupts. */
  610. DEBUG_TIMESTAMP();
  611. DEBUG_PRINTLN(F("C. Clearing and configuring interrupts."));
  612. write8(MFRC630_REG_IRQ0, 0b01111111);
  613. write8(MFRC630_REG_IRQ1, 0b00111111);
  614. /* Allow the receiver and Error IRQs to be propagated to the GlobalIRQ. */
  615. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_RXIRQ | MFRC630IRQ0_ERRIRQ);
  616. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  617. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  618. /* Configure the frame wait timeout using T0 (5ms max). */
  619. DEBUG_TIMESTAMP();
  620. DEBUG_PRINTLN(F("D. Configuring Timer0 @ 211.875kHz, post TX, 5ms timeout."));
  621. write8(MFRC630_REG_T0_CONTROL, 0b10001);
  622. write8(MFRC630_REG_T0_RELOAD_HI, 1100 >> 8);
  623. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  624. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 1100 >> 8);
  625. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  626. /* Send the ISO14443 command. */
  627. DEBUG_TIMESTAMP();
  628. DEBUG_PRINTLN(F("E. Sending ISO14443 command."));
  629. uint8_t send_req[] = {(uint8_t)cmd};
  630. writeCommand(MFRC630_CMD_TRANSCEIVE, 1, send_req);
  631. /* Wait here until we're done reading, get an error, or timeout. */
  632. /* TODO: Update to use timeout parameter! */
  633. DEBUG_TIMESTAMP();
  634. DEBUG_PRINTLN(F("F. Waiting for a response or timeout."));
  635. uint8_t irqval = 0;
  636. while (!(irqval & MFRC630IRQ1_TIMER0IRQ)) {
  637. irqval = read8(MFRC630_REG_IRQ1);
  638. /* Check for a global interrrupt, which can only be ERR or RX. */
  639. if (irqval & MFRC630IRQ1_GLOBALIRQ) {
  640. break;
  641. }
  642. }
  643. /* Cancel the current command (in case we timed out or error occurred). */
  644. writeCommand(MFRC630_CMD_IDLE);
  645. /* Check the RX IRQ, and exit appropriately if it has fired (error). */
  646. irqval = read8(MFRC630_REG_IRQ0);
  647. if ((!(irqval & MFRC630IRQ0_RXIRQ) || (irqval & MFRC630IRQ0_ERRIRQ))) {
  648. DEBUG_TIMESTAMP();
  649. DEBUG_PRINTLN(F("ERROR: No RX flag set, transceive failed or timed out."));
  650. /* Display the error message if ERROR IRQ is set. */
  651. if (irqval & MFRC630IRQ0_ERRIRQ) {
  652. uint8_t error = read8(MFRC630_REG_ERROR);
  653. /* Only display the error if it isn't a timeout. */
  654. if (error) {
  655. printError((enum mfrc630errors)error);
  656. }
  657. }
  658. return 0;
  659. }
  660. /* Read the response */
  661. uint16_t rxlen = readFIFOLen();
  662. DEBUG_TIMESTAMP();
  663. DEBUG_PRINTLN(F("G. Reading response from FIFO buffer."));
  664. if (rxlen == 2) {
  665. /*
  666. * If we have 2 bytes for the response, it's the ATQA.
  667. *
  668. * See ISO14443-3 6.3.2 for help in interpretting the ATQA value.
  669. *
  670. * "After a REQA Command is transmitted by the PCD, all
  671. * PICCs in the IDLE State shall respond synchronously with ATQA."
  672. *
  673. * 0x44 = 4 bit frame anticollision
  674. * UID size = double
  675. */
  676. readFIFO(rxlen, (uint8_t *)&atqa);
  677. DEBUG_TIMESTAMP();
  678. DEBUG_PRINT(F("Received response (ATQA): 0x"));
  679. DEBUG_PRINTLN(atqa, HEX);
  680. return atqa;
  681. }
  682. return 0;
  683. }
  684. /*
  685. * For high level details on the selection and anti-collision protocols see
  686. * "Chip Type Identification Procedure" in
  687. * https://www.nxp.com/docs/en/application-note/AN10833.pdf
  688. */
  689. uint8_t Adafruit_MFRC630::iso14443aSelect(uint8_t *uid, uint8_t *sak) {
  690. (void)sak;
  691. DEBUG_TIMESTAMP();
  692. DEBUG_PRINTLN(F("Selecting an ISO14443A tag"));
  693. /* Cancel any current command */
  694. writeCommand(MFRC630_CMD_IDLE);
  695. /* Flush the FIFO */
  696. clearFIFO();
  697. /* Allow the receiver and Error IRQs to be propagated to the GlobalIRQ. */
  698. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_RXIRQ | MFRC630IRQ0_ERRIRQ);
  699. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  700. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  701. /* Configure the frame wait timeout using T0 (5ms max). */
  702. /* 1 'tick' 4.72us, so 1100 = 5.2ms */
  703. DEBUG_TIMESTAMP();
  704. DEBUG_PRINTLN(F("A. Configuring Timer0 @ 211.875kHz, post TX, 5ms timeout."));
  705. write8(MFRC630_REG_T0_CONTROL, 0b10001);
  706. write8(MFRC630_REG_T0_RELOAD_HI, 1100 >> 8);
  707. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  708. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 1100 >> 8);
  709. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  710. /* Set the cascade level (collision detection loop) */
  711. DEBUG_TIMESTAMP();
  712. DEBUG_PRINTLN(F("B. Checking cascade level (collision detection)."));
  713. uint8_t cascadelvl;
  714. for (cascadelvl = 1; cascadelvl <= 3; cascadelvl++) {
  715. uint8_t cmd;
  716. uint8_t kbits = 0; /* Bits known in UID so far. */
  717. uint8_t send_req[7] = {0}; /* TX buffer */
  718. uint8_t *uid_this_level = &(send_req[2]); /* UID pointer */
  719. uint8_t message_length;
  720. DEBUG_TIMESTAMP();
  721. DEBUG_PRINT(F("Cascade level "));
  722. DEBUG_PRINTLN(cascadelvl);
  723. switch (cascadelvl) {
  724. case 1:
  725. cmd = ISO14443_CAS_LEVEL_1;
  726. break;
  727. case 2:
  728. cmd = ISO14443_CAS_LEVEL_2;
  729. break;
  730. case 3:
  731. cmd = ISO14443_CAS_LEVEL_3;
  732. break;
  733. }
  734. /* Disable CRC. */
  735. DEBUG_TIMESTAMP();
  736. DEBUG_PRINTLN(F("a. Disabling CRC checks."));
  737. write8(MFRC630_REG_TX_CRC_PRESET, 0x18);
  738. write8(MFRC630_REG_RX_CRC_CON, 0x18);
  739. /* As per ISO14443-3, limit coliision checks to 32 attempts. */
  740. uint8_t cnum;
  741. DEBUG_TIMESTAMP();
  742. DEBUG_PRINTLN(F("b. Collision detection (max 32 attempts)."));
  743. for (cnum = 0; cnum < 32; cnum++) {
  744. DEBUG_TIMESTAMP();
  745. DEBUG_PRINT(F("Attempt = "));
  746. DEBUG_PRINT(cnum);
  747. DEBUG_PRINT(F(", known bits = "));
  748. DEBUG_PRINT(kbits);
  749. DEBUG_PRINT(F(" "));
  750. printHex(uid_this_level, (kbits + 8 - 1) / 8);
  751. DEBUG_PRINTLN("");
  752. /* Clear the interrupts. */
  753. write8(MFRC630_REG_IRQ0, 0b01111111);
  754. write8(MFRC630_REG_IRQ1, 0b00111111);
  755. /* Send the current collision level command */
  756. send_req[0] = cmd;
  757. send_req[1] = 0x20 + kbits;
  758. /* Limit MFRC630_REG_TX_DATA_NUM to the correct number of bits. */
  759. write8(MFRC630_REG_TX_DATA_NUM, (kbits % 8) | (1 << 3));
  760. // ValuesAfterColl: If cleared, every received bit after a collision is
  761. // replaced by a zero. This function is needed for ISO/IEC14443
  762. // anticollision (0<<7). We want to shift the bits with RxAlign
  763. uint8_t rxalign = kbits % 8;
  764. write8(MFRC630_REG_RX_BIT_CTRL, (0 << 7) | (rxalign << 4));
  765. /* Determine the message length */
  766. if ((kbits % 8) == 0) {
  767. message_length = ((kbits / 8)) + 2;
  768. } else {
  769. message_length = ((kbits / 8) + 1) + 2;
  770. }
  771. /* Send the command. */
  772. writeCommand(MFRC630_CMD_TRANSCEIVE, message_length, send_req);
  773. /* Wait until the command execution is complete. */
  774. uint8_t irq1_value = 0;
  775. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  776. irq1_value = read8(MFRC630_REG_IRQ1);
  777. /* Check for a global interrrupt, which can only be ERR or RX. */
  778. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  779. break;
  780. }
  781. }
  782. /* Cancel any current command */
  783. writeCommand(MFRC630_CMD_IDLE);
  784. /* Parse results */
  785. uint8_t irq0_value = read8(MFRC630_REG_IRQ0);
  786. uint8_t error = read8(MFRC630_REG_ERROR);
  787. uint8_t coll = read8(MFRC630_REG_RX_COLL);
  788. uint8_t coll_p = 0;
  789. /* Check if an error occured */
  790. if (irq0_value & MFRC630IRQ0_ERRIRQ) {
  791. /* Display the error code in human-readable format. */
  792. printError((enum mfrc630errors)error);
  793. if (error & MFRC630_ERROR_COLLDET) {
  794. /* Collision error, check if the collision position is valid */
  795. if (coll & (1 << 7)) {
  796. /* Valid, so check the collision position (bottom 7 bits). */
  797. coll_p = coll & (~(1 << 7));
  798. DEBUG_TIMESTAMP();
  799. DEBUG_PRINT(F("Bit collision detected at bit "));
  800. DEBUG_PRINTLN(coll_p);
  801. uint8_t choice_pos = kbits + coll_p;
  802. uint8_t selection =
  803. (uid[((choice_pos + (cascadelvl - 1) * 3) / 8)] >>
  804. ((choice_pos) % 8)) &
  805. 1;
  806. uid_this_level[((choice_pos) / 8)] |= selection
  807. << ((choice_pos) % 8);
  808. kbits++;
  809. DEBUG_TIMESTAMP();
  810. DEBUG_PRINT(F("'uid_this_level' is now "));
  811. DEBUG_PRINT(kbits);
  812. DEBUG_PRINT(F(": "));
  813. printHex(uid_this_level, 10);
  814. DEBUG_PRINTLN(F(""));
  815. } else {
  816. /* Invalid collision position (bit 7 = 0) */
  817. DEBUG_TIMESTAMP();
  818. DEBUG_PRINTLN(F("Bit collision detected, but no valid position."));
  819. coll_p = 0x20 - kbits;
  820. } /* End: if (coll & (1 << 7)) */
  821. } else {
  822. DEBUG_TIMESTAMP();
  823. DEBUG_PRINTLN(F("Unhandled error."));
  824. coll_p = 0x20 - kbits;
  825. } /* End: if (error & MFRC630_ERROR_COLLDET) */
  826. } else if (irq0_value & MFRC630IRQ0_RXIRQ) {
  827. /* We have data and no collision, all is well in the world! */
  828. coll_p = 0x20 - kbits;
  829. DEBUG_TIMESTAMP();
  830. DEBUG_PRINTLN(F("Received data, no bit collision!"));
  831. } else {
  832. /* Probably no card */
  833. DEBUG_TIMESTAMP();
  834. DEBUG_PRINTLN(F("No error and no data = No card"));
  835. return 0;
  836. } /* End: if (irq0_value & (1 << 1)) */
  837. /* Read the UID so far */
  838. uint16_t rxlen = readFIFOLen();
  839. uint8_t buf[5]; /* UID = 4 bytes + BCC */
  840. readFIFO(rxlen < 5 ? rxlen : 5, buf);
  841. /*
  842. * Move current buffer contents into the UID placeholder, OR'ing the
  843. * results so that we don't lose the bit we set if you have a collision.
  844. */
  845. uint8_t rbx;
  846. for (rbx = 0; (rbx < rxlen); rbx++) {
  847. uid_this_level[(kbits / 8) + rbx] |= buf[rbx];
  848. }
  849. kbits += coll_p;
  850. if ((kbits >= 32)) {
  851. DEBUG_TIMESTAMP();
  852. DEBUG_PRINT(F("Leaving collision loop: uid "));
  853. DEBUG_PRINT(kbits);
  854. DEBUG_PRINTLN(F(" bits long"));
  855. DEBUG_TIMESTAMP();
  856. printHex(uid_this_level, kbits / 8);
  857. DEBUG_PRINTLN(F(""));
  858. break; /* Exit the collision loop */
  859. }
  860. } /* End: for (cnum = 0; cnum < 32; cnum++) */
  861. /* Check if the BCC matches ... */
  862. DEBUG_TIMESTAMP();
  863. DEBUG_PRINTLN(F("C. Checking BCC for data integrity."));
  864. uint8_t bcc_val = uid_this_level[4];
  865. uint8_t bcc_calc = uid_this_level[0] ^ uid_this_level[1] ^
  866. uid_this_level[2] ^ uid_this_level[3];
  867. if (bcc_val != bcc_calc) {
  868. DEBUG_PRINTLN(F("ERROR: BCC mistmatch!\n"));
  869. return 0;
  870. }
  871. /* Clear the interrupts. */
  872. DEBUG_TIMESTAMP();
  873. DEBUG_PRINTLN(F("D. Clearing and configuring interrupts."));
  874. write8(MFRC630_REG_IRQ0, 0b01111111);
  875. write8(MFRC630_REG_IRQ1, 0b00111111);
  876. send_req[0] = cmd;
  877. send_req[1] = 0x70;
  878. send_req[6] = bcc_calc;
  879. message_length = 7;
  880. /* Re-enable CRCs. */
  881. write8(MFRC630_REG_TX_CRC_PRESET, 0x18 | 1);
  882. write8(MFRC630_REG_RX_CRC_CON, 0x18 | 1);
  883. /* Reset the TX and RX registers (disable alignment, transmit full bytes) */
  884. write8(MFRC630_REG_TX_DATA_NUM, (kbits % 8) | (1 << 3));
  885. uint8_t rxalign = 0;
  886. write8(MFRC630_REG_RX_BIT_CTRL, (0 << 7) | (rxalign << 4));
  887. /* Send the command. */
  888. DEBUG_TIMESTAMP();
  889. DEBUG_PRINTLN(F("E. Sending collision command"));
  890. writeCommand(MFRC630_CMD_TRANSCEIVE, message_length, send_req);
  891. /* Wait until the command execution is complete. */
  892. uint8_t irq1_value = 0;
  893. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  894. irq1_value = read8(MFRC630_REG_IRQ1);
  895. /* Check for a global interrrupt, which can only be ERR or RX. */
  896. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  897. break;
  898. }
  899. }
  900. writeCommand(MFRC630_CMD_IDLE);
  901. /* Check the source of exiting the loop. */
  902. DEBUG_TIMESTAMP();
  903. DEBUG_PRINTLN(F("F. Command complete, verifying proper exit."));
  904. uint8_t irq0_value = read8(MFRC630_REG_IRQ0);
  905. /* Check the ERROR IRQ */
  906. if (irq0_value & MFRC630IRQ0_ERRIRQ) {
  907. /* Check what kind of error. */
  908. uint8_t error = read8(MFRC630_REG_ERROR);
  909. if (error & MFRC630_ERROR_COLLDET) {
  910. /* Collision detecttion. */
  911. printError(MFRC630_ERROR_COLLDET);
  912. return 0;
  913. }
  914. }
  915. /* Read SAK answer from fifo. */
  916. DEBUG_TIMESTAMP();
  917. DEBUG_PRINTLN(F("G. Checking SAK in response payload."));
  918. uint8_t sak_len = readFIFOLen();
  919. if (sak_len != 1) {
  920. DEBUG_TIMESTAMP();
  921. DEBUG_PRINTLN(F("ERROR: NO SAK in response!\n"));
  922. return 0;
  923. }
  924. uint8_t sak_value;
  925. readFIFO(sak_len, &sak_value);
  926. DEBUG_TIMESTAMP();
  927. DEBUG_PRINT(F("SAK answer: "));
  928. DEBUG_PRINTLN(sak_value);
  929. /* Check if there is more data to read. */
  930. if (sak_value & (1 << 2)) {
  931. /* UID not yet complete, continue to next cascade. */
  932. DEBUG_TIMESTAMP();
  933. DEBUG_PRINTLN(F("UID not complete ... looping to next cascade level."));
  934. uint8_t UIDn;
  935. for (UIDn = 0; UIDn < 3; UIDn++) {
  936. // uid_this_level[UIDn] = uid_this_level[UIDn + 1];
  937. uid[(cascadelvl - 1) * 3 + UIDn] = uid_this_level[UIDn + 1];
  938. }
  939. } else {
  940. DEBUG_TIMESTAMP();
  941. DEBUG_PRINTLN(F("DONE! UID fully parsed, exiting."));
  942. /* Done! */
  943. /* Add current bytes at this level to the UID. */
  944. uint8_t UIDn;
  945. for (UIDn = 0; UIDn < 4; UIDn++) {
  946. uid[(cascadelvl - 1) * 3 + UIDn] = uid_this_level[UIDn];
  947. }
  948. /* Finally, return the length of the UID that's now at the uid pointer. */
  949. return cascadelvl * 3 + 1;
  950. }
  951. DEBUG_TIMESTAMP();
  952. DEBUG_PRINTLN(F("Exiting cascade loop"));
  953. } /* End: for (cascadelvl = 1; cascadelvl <= 3; cascadelvl++) */
  954. /* Return 0 for UUID length if nothing was found. */
  955. return 0;
  956. }
  957. void Adafruit_MFRC630::mifareLoadKey(uint8_t *key) {
  958. DEBUG_TIMESTAMP();
  959. DEBUG_PRINTLN(F("Loading Mifare key into crypto unit."));
  960. writeCommand(MFRC630_CMD_IDLE);
  961. clearFIFO();
  962. writeFIFO(6, key);
  963. writeCommand(MFRC630_CMD_LOADKEY);
  964. }
  965. bool Adafruit_MFRC630::mifareAuth(uint8_t key_type, uint8_t blocknum,
  966. uint8_t *uid) {
  967. DEBUG_TIMESTAMP();
  968. DEBUG_PRINT(F("Authenticating Mifare block "));
  969. DEBUG_PRINTLN(blocknum);
  970. writeCommand(MFRC630_CMD_IDLE);
  971. clearFIFO();
  972. /* Allow the IDLE and Error IRQs to be propagated to the GlobalIRQ. */
  973. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_IDLEIRQ | MFRC630IRQ0_ERRIRQ);
  974. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  975. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  976. /* Configure the frame wait timeout using T0 (10ms max). */
  977. /* 1 'tick' 4.72us, so 2000 = ~10ms */
  978. DEBUG_TIMESTAMP();
  979. DEBUG_PRINTLN(F("Configuring Timer0 @ 211.875kHz, post TX, 10ms timeout."));
  980. write8(MFRC630_REG_T0_CONTROL, 0b10001);
  981. write8(MFRC630_REG_T0_RELOAD_HI, 2000 >> 8);
  982. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  983. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 2000 >> 8);
  984. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  985. /* Clear interrupts. */
  986. write8(MFRC630_REG_IRQ0, 0b01111111);
  987. write8(MFRC630_REG_IRQ1, 0b00111111);
  988. /* Start of AUTH procedure. */
  989. writeCommand(MFRC630_CMD_IDLE);
  990. clearFIFO();
  991. /*
  992. * MFAUTHENT command has the following parameters:
  993. * [0] Key type (0x60 = KEYA, 0x61 = KEYB)
  994. * [1] Block address
  995. * [2] UID byte 0
  996. * [3] UID byte 1
  997. * [4] UID byte 2
  998. * [5] UID byte 3
  999. *
  1000. * NOTE: When the MFAuthent command is active, any FIFO access is blocked!
  1001. */
  1002. uint8_t params[6] = {key_type, blocknum, uid[0], uid[1], uid[2], uid[3]};
  1003. writeFIFO(6, params);
  1004. writeCommand(MFRC630_CMD_MFAUTHENT);
  1005. /*
  1006. * This command terminates automatically when the MIFARE Classic card is
  1007. * authenticated and the bit MFCrypto1On is set to logic 1.
  1008. *
  1009. * This command does not terminate automatically when the card does not
  1010. * answer, therefore the timer should be initialized to automatic mode. In
  1011. * this case, beside the bit IdleIRQ the bit TimerIRQ can be used as
  1012. * termination criteria. During authentication processing the bits RxIRQ
  1013. * and TxIRQ are blocked. The Crypto1On shows if the authentication was
  1014. * successful. The Crypto1On is always valid.
  1015. *
  1016. * In case there is an error during authentication, the bit ProtocolErr in
  1017. * the Error register is set to logic 1 and the bit Crypto1On in register
  1018. * Status2Reg is set to logic 0.
  1019. */
  1020. /* Wait until the command execution is complete. */
  1021. uint8_t irq1_value = 0;
  1022. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  1023. irq1_value = read8(MFRC630_REG_IRQ1);
  1024. /* Check for a global interrrupt, which can only be ERR or RX. */
  1025. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  1026. break;
  1027. }
  1028. }
  1029. #if 0
  1030. uint8_t irq0_value = read8(MFRC630_REG_IRQ0);
  1031. uint8_t error = read8(MFRC630_REG_ERROR);
  1032. uint8_t status = read8(MFRC630_REG_STATUS);
  1033. Serial.print(F("ERROR : ")); Serial.println(error, HEX);
  1034. Serial.print(F("IRQ0 : ")); Serial.println(irq0_value, HEX);
  1035. Serial.print(F("IRQ1 : ")); Serial.println(irq1_value, HEX);
  1036. Serial.print(F("STATUS: ")); Serial.println(status, HEX);
  1037. #endif
  1038. /* Check the error flag (MFRC630_ERROR_PROT, etc.) */
  1039. uint8_t error = read8(MFRC630_REG_ERROR);
  1040. if (error) {
  1041. printError((enum mfrc630errors)error);
  1042. return false;
  1043. }
  1044. /* Check if we timed out or got a response. */
  1045. if (irq1_value & MFRC630IRQ1_TIMER0IRQ) {
  1046. /* Timed out, no auth! :( */
  1047. return false;
  1048. }
  1049. /* Check the status register for CRYPTO1 flag (Mifare AUTH). */
  1050. uint8_t status = read8(MFRC630_REG_STATUS);
  1051. return (status & MFRC630STATUS_CRYPTO1ON) ? true : false;
  1052. }
  1053. uint16_t Adafruit_MFRC630::mifareReadBlock(uint8_t blocknum, uint8_t *buf) {
  1054. clearFIFO();
  1055. /* Enable CRC. */
  1056. DEBUG_TIMESTAMP();
  1057. DEBUG_PRINTLN(F("A. Disabling CRC checks."));
  1058. write8(MFRC630_REG_TX_CRC_PRESET, 0x18 | 1);
  1059. write8(MFRC630_REG_RX_CRC_CON, 0x18 | 1);
  1060. /* Allow the IDLE and Error IRQs to be propagated to the GlobalIRQ. */
  1061. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_IDLEIRQ | MFRC630IRQ0_ERRIRQ);
  1062. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  1063. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  1064. /* Configure the frame wait timeout using T0 (10ms max). */
  1065. /* 1 'tick' 4.72us, so 2000 = ~10ms */
  1066. DEBUG_TIMESTAMP();
  1067. DEBUG_PRINTLN(F("Configuring Timer0 @ 211.875kHz, post TX, 10ms timeout."));
  1068. write8(MFRC630_REG_T0_CONTROL, 0b10001); /* Start at end of TX, 211kHz */
  1069. write8(MFRC630_REG_T0_RELOAD_HI, 0xFF);
  1070. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  1071. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 0xFF);
  1072. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  1073. /* Clear interrupts. */
  1074. write8(MFRC630_REG_IRQ0, 0b01111111);
  1075. write8(MFRC630_REG_IRQ1, 0b00111111);
  1076. /* Transceive the command. */
  1077. uint8_t req[2] = {MIFARE_CMD_READ, blocknum};
  1078. writeCommand(MFRC630_CMD_TRANSCEIVE, 2, req);
  1079. /* Wait until the command execution is complete. */
  1080. uint8_t irq1_value = 0;
  1081. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  1082. irq1_value = read8(MFRC630_REG_IRQ1);
  1083. /* Check for a global interrrupt, which can only be ERR or RX. */
  1084. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  1085. break;
  1086. }
  1087. }
  1088. writeCommand(MFRC630_CMD_IDLE);
  1089. /* Check if we timed out or got a response. */
  1090. if (irq1_value & MFRC630IRQ1_TIMER0IRQ) {
  1091. /* Timed out, no auth :( */
  1092. DEBUG_PRINTLN(F("TIMED OUT!"));
  1093. return 0;
  1094. }
  1095. /* Read the size and contents of the FIFO, and return the results. */
  1096. uint16_t buffer_length = readFIFOLen();
  1097. uint16_t rx_len = (buffer_length <= 16) ? buffer_length : 16;
  1098. readFIFO(rx_len, buf);
  1099. return rx_len;
  1100. }
  1101. uint16_t Adafruit_MFRC630::ntagReadPage(uint16_t pagenum, uint8_t *buf) {
  1102. clearFIFO();
  1103. /* Enable CRC. */
  1104. DEBUG_TIMESTAMP();
  1105. DEBUG_PRINTLN(F("A. Disabling CRC checks."));
  1106. write8(MFRC630_REG_TX_CRC_PRESET, 0x18 | 1);
  1107. write8(MFRC630_REG_RX_CRC_CON, 0x18 | 1);
  1108. /* Allow the IDLE and Error IRQs to be propagated to the GlobalIRQ. */
  1109. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_IDLEIRQ | MFRC630IRQ0_ERRIRQ);
  1110. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  1111. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  1112. /* Configure the frame wait timeout using T0 (10ms max). */
  1113. /* 1 'tick' 4.72us, so 2000 = ~10ms */
  1114. DEBUG_TIMESTAMP();
  1115. DEBUG_PRINTLN(F("Configuring Timer0 @ 211.875kHz, post TX, 10ms timeout."));
  1116. write8(MFRC630_REG_T0_CONTROL, 0b10001); /* Start at end of TX, 211kHz */
  1117. write8(MFRC630_REG_T0_RELOAD_HI, 0xFF);
  1118. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  1119. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 0xFF);
  1120. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  1121. /* Clear interrupts. */
  1122. write8(MFRC630_REG_IRQ0, 0b01111111);
  1123. write8(MFRC630_REG_IRQ1, 0b00111111);
  1124. /* Transceive the command. */
  1125. uint8_t req[2] = {(uint8_t)NTAG_CMD_READ, (uint8_t)pagenum};
  1126. writeCommand(MFRC630_CMD_TRANSCEIVE, 2, req);
  1127. /* Wait until the command execution is complete. */
  1128. uint8_t irq1_value = 0;
  1129. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  1130. irq1_value = read8(MFRC630_REG_IRQ1);
  1131. /* Check for a global interrrupt, which can only be ERR or RX. */
  1132. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  1133. break;
  1134. }
  1135. }
  1136. writeCommand(MFRC630_CMD_IDLE);
  1137. /* Check if we timed out or got a response. */
  1138. if (irq1_value & MFRC630IRQ1_TIMER0IRQ) {
  1139. /* Timed out, no auth :( */
  1140. DEBUG_PRINTLN(F("TIMED OUT!"));
  1141. return 0;
  1142. }
  1143. /* Read the size and contents of the FIFO, and return the results. */
  1144. uint16_t buffer_length = readFIFOLen();
  1145. uint16_t rx_len = (buffer_length <= 4) ? buffer_length : 4;
  1146. readFIFO(rx_len, buf);
  1147. return rx_len;
  1148. }
  1149. uint16_t Adafruit_MFRC630::mifareWriteBlock(uint16_t blocknum, uint8_t *buf) {
  1150. clearFIFO();
  1151. DEBUG_TIMESTAMP();
  1152. DEBUG_PRINT(F("Writing data to card @ 0x"));
  1153. DEBUG_PRINTLN(blocknum);
  1154. /* Enable CRC for TX (RX off!). */
  1155. DEBUG_TIMESTAMP();
  1156. DEBUG_PRINTLN(F("A. Disabling CRC checks."));
  1157. write8(MFRC630_REG_TX_CRC_PRESET, 0x18 | 1);
  1158. write8(MFRC630_REG_RX_CRC_CON, 0x18 | 0);
  1159. /* Allow the IDLE and Error IRQs to be propagated to the GlobalIRQ. */
  1160. write8(MFRC630_REG_IRQOEN, MFRC630IRQ0_IDLEIRQ | MFRC630IRQ0_ERRIRQ);
  1161. /* Allow Timer0 IRQ to be propagated to the GlobalIRQ. */
  1162. write8(MFRC630_REG_IRQ1EN, MFRC630IRQ1_TIMER0IRQ);
  1163. /* Configure the frame wait timeout using T0 (10ms max). */
  1164. /* 1 'tick' 4.72us, so 2000 = ~10ms */
  1165. DEBUG_TIMESTAMP();
  1166. DEBUG_PRINTLN(F("Configuring Timer0 @ 211.875kHz, post TX, 10ms timeout."));
  1167. write8(MFRC630_REG_T0_CONTROL, 0b10001); /* Start at end of TX, 211kHz */
  1168. write8(MFRC630_REG_T0_RELOAD_HI, 0xFF);
  1169. write8(MFRC630_REG_TO_RELOAD_LO, 0xFF);
  1170. write8(MFRC630_REG_T0_COUNTER_VAL_HI, 0xFF);
  1171. write8(MFRC630_REG_T0_COUNTER_VAL_LO, 0xFF);
  1172. /* Clear interrupts. */
  1173. write8(MFRC630_REG_IRQ0, 0b01111111);
  1174. write8(MFRC630_REG_IRQ1, 0b00111111);
  1175. /* Transceive the WRITE command. */
  1176. uint8_t req1[2] = {(uint8_t)MIFARE_CMD_WRITE, (uint8_t)blocknum};
  1177. writeCommand(MFRC630_CMD_TRANSCEIVE, sizeof(req1), req1);
  1178. /* Wait until the command execution is complete. */
  1179. uint8_t irq1_value = 0;
  1180. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  1181. irq1_value = read8(MFRC630_REG_IRQ1);
  1182. /* Check for a global interrrupt, which can only be ERR or RX. */
  1183. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  1184. break;
  1185. }
  1186. }
  1187. writeCommand(MFRC630_CMD_IDLE);
  1188. /* Check if we timed out or got a response. */
  1189. if (irq1_value & MFRC630IRQ1_TIMER0IRQ) {
  1190. /* Timed out, no auth :( */
  1191. DEBUG_PRINTLN(F("TIMED OUT!"));
  1192. return 0;
  1193. }
  1194. /* Check if an error occured */
  1195. uint8_t error = read8(MFRC630_REG_ERROR);
  1196. uint8_t irq0_value = read8(MFRC630_REG_IRQ0);
  1197. if (irq0_value & MFRC630IRQ0_ERRIRQ) {
  1198. printError((enum mfrc630errors)error);
  1199. return 0;
  1200. }
  1201. /* We should have a single ACK byte in buffer at this point. */
  1202. uint16_t buffer_length = readFIFOLen();
  1203. if (buffer_length != 1) {
  1204. DEBUG_TIMESTAMP();
  1205. DEBUG_PRINT(F("Unexpected response buffer len: "));
  1206. DEBUG_PRINTLN(buffer_length);
  1207. return 0;
  1208. }
  1209. uint8_t ack = 0;
  1210. readFIFO(1, &ack);
  1211. if (ack != 0x0A) {
  1212. /* Missing valid ACK response! */
  1213. DEBUG_TIMESTAMP();
  1214. DEBUG_PRINT(F("Invalid ACK response: "));
  1215. DEBUG_PRINTLN(ack, HEX);
  1216. return 0;
  1217. }
  1218. /* TODO: Verift values! */
  1219. /* Clear the interrupts. */
  1220. write8(MFRC630_REG_IRQ0, 0b01111111);
  1221. write8(MFRC630_REG_IRQ1, 0b00111111);
  1222. /* Transfer the page data. */
  1223. writeCommand(MFRC630_CMD_TRANSCEIVE, 16, buf);
  1224. /* Wait until the command execution is complete. */
  1225. irq1_value = 0;
  1226. while (!(irq1_value & MFRC630IRQ1_TIMER0IRQ)) {
  1227. irq1_value = read8(MFRC630_REG_IRQ1);
  1228. /* Check for a global interrrupt, which can only be ERR or RX. */
  1229. if (irq1_value & MFRC630IRQ1_GLOBALIRQ) {
  1230. break;
  1231. }
  1232. }
  1233. writeCommand(MFRC630_CMD_IDLE);
  1234. /* Check if we timed out or got a response. */
  1235. if (irq1_value & MFRC630IRQ1_TIMER0IRQ) {
  1236. /* Timed out, no auth :( */
  1237. DEBUG_PRINTLN(F("TIMED OUT!"));
  1238. return 0;
  1239. }
  1240. /* Check if an error occured */
  1241. error = read8(MFRC630_REG_ERROR);
  1242. irq0_value = read8(MFRC630_REG_IRQ0);
  1243. if (irq0_value & MFRC630IRQ0_ERRIRQ) {
  1244. printError((enum mfrc630errors)error);
  1245. return 0;
  1246. }
  1247. /* We should have a single ACK byte in buffer at this point. */
  1248. buffer_length = readFIFOLen();
  1249. if (buffer_length != 1) {
  1250. DEBUG_TIMESTAMP();
  1251. DEBUG_PRINT(F("Unexpected response buffer len: "));
  1252. DEBUG_PRINTLN(buffer_length);
  1253. return 0;
  1254. }
  1255. ack = 0;
  1256. readFIFO(1, &ack);
  1257. if (ack != 0x0A) {
  1258. /* Missing valid ACK response! */
  1259. DEBUG_TIMESTAMP();
  1260. DEBUG_PRINT(F("Invalid ACK response: "));
  1261. DEBUG_PRINTLN(ack, HEX);
  1262. return 0;
  1263. }
  1264. return 16;
  1265. }
  1266. uint16_t Adafruit_MFRC630::ntagWritePage(uint16_t pagenum, uint8_t *buf) {
  1267. /*
  1268. * For now, protect pages 0..3 and 40..44, and restrict writes to the safe
  1269. * 'user memory' range (see docs/NTAG.md for further details).
  1270. */
  1271. if ((pagenum < 4) || (pagenum > 44)) {
  1272. DEBUG_TIMESTAMP();
  1273. DEBUG_PRINT(F("Page number out of range for NTAG213: "));
  1274. DEBUG_PRINTLN(pagenum);
  1275. return 0;
  1276. }
  1277. /* Use the Mifare write, which is compatible with the NTAG cards. */
  1278. return mifareWriteBlock(pagenum, buf) == 16 ? 4 : 0;
  1279. }