Kevin Townsend пре 7 година
родитељ
комит
ef8314484d
4 измењених фајлова са 298 додато и 77 уклоњено
  1. 120 71
      Adafruit_MFRC630.cpp
  2. 14 5
      Adafruit_MFRC630.h
  3. 1 1
      docs/Doxyfile
  4. 163 0
      examples/mifare1k_dump_spi/mifare1k_dump_spi.ino

+ 120 - 71
Adafruit_MFRC630.cpp

@@ -15,6 +15,7 @@
  ***************************************************************************/
 
 #include <Wire.h>
+#include <SPI.h>
 
 #include "Adafruit_MFRC630.h"
 
@@ -35,10 +36,19 @@ void Adafruit_MFRC630::write8(byte reg, byte value)
   TRACE_PRINT(" to 0x");
   TRACE_PRINTLN(reg, HEX);
 
-  _wire->beginTransmission(_i2c_addr);
-  _wire->write(reg);
-  _wire->write(value);
-  _wire->endTransmission();
+  if (_i2c_addr > 0) {
+    /* I2C */
+    _wire->beginTransmission(_i2c_addr);
+    _wire->write(reg);
+    _wire->write(value);
+    _wire->endTransmission();
+  } else {
+    /* SPI */
+    digitalWrite(_cs, LOW);
+    SPI.transfer((reg << 1) | 0x00);
+    SPI.transfer(value);
+    digitalWrite(_cs, HIGH);
+  }
 }
 
 /**************************************************************************/
@@ -46,10 +56,8 @@ void Adafruit_MFRC630::write8(byte reg, byte value)
     @brief  Write a buffer to the specified register
 */
 /**************************************************************************/
-void Adafruit_MFRC630::writeBuffer(byte reg, byte len, uint8_t *buffer)
+void Adafruit_MFRC630::writeBuffer(byte reg, uint16_t len, uint8_t *buffer)
 {
-  uint8_t i;
-
   TRACE_TIMESTAMP();
   TRACE_PRINT("Writing ");
   TRACE_PRINT(len);
@@ -57,16 +65,27 @@ void Adafruit_MFRC630::writeBuffer(byte reg, byte len, uint8_t *buffer)
   TRACE_PRINTLN(reg, HEX);
 
   TRACE_TIMESTAMP();
-  _wire->beginTransmission(_i2c_addr);
-  _wire->write(reg);
-  for (i = 0; i < len; i++)
-  {
-    _wire->write(buffer[i]);
-    TRACE_PRINT("0x");
-    TRACE_PRINT(buffer[i], HEX);
-    TRACE_PRINT(" ");
+  if (_i2c_addr > 0) {
+      /* I2C */
+      _wire->beginTransmission(_i2c_addr);
+      _wire->write(reg);
+      for (uint16_t i = 0; i < len; i++)
+      {
+        _wire->write(buffer[i]);
+        TRACE_PRINT("0x");
+        TRACE_PRINT(buffer[i], HEX);
+        TRACE_PRINT(" ");
+      }
+      _wire->endTransmission();
+  } else {
+      /* SPI */
+      digitalWrite(_cs, LOW);
+      SPI.transfer((reg << 1) | 0x00);
+      for (uint8_t i = 0; i < len; i++){
+          SPI.transfer(buffer[i]);
+      }
+      digitalWrite(_cs, HIGH);
   }
-  _wire->endTransmission();
   TRACE_PRINTLN("");
 }
 
@@ -77,60 +96,50 @@ void Adafruit_MFRC630::writeBuffer(byte reg, byte len, uint8_t *buffer)
 /**************************************************************************/
 byte Adafruit_MFRC630::read8(byte reg)
 {
-  uint8_t value;
-
-  readBuffer(reg, 1, &value);
-
-  return value;
-}
-
-/**************************************************************************/
-/*!
-    @brief  Read 'len' bytes from the specified register
-*/
-/**************************************************************************/
-byte Adafruit_MFRC630::readBuffer(byte reg, byte len, uint8_t *buffer)
-{
-  uint8_t i;
-
-  TRACE_TIMESTAMP();
-  TRACE_PRINT("Requesting ");
-  TRACE_PRINT(len);
-  TRACE_PRINT(" byte(s) from 0x");
-  TRACE_PRINTLN(reg, HEX);
-
-  #ifdef __SAM3X8E__
-    /* http://forum.arduino.cc/index.php?topic=385377.msg2947227#msg2947227 */
-    _wire->requestFrom(_i2c_addr, len, reg, 1, true);
-  #else
-    _wire->beginTransmission(_i2c_addr);
-    _wire->write(reg);
-    _wire->endTransmission();
-    _wire->requestFrom(_i2c_addr, (byte)len);
-  #endif
-
-  /* Dump the response into the supplied buffer */
-  for (i=0; i<len; i++)
-  {
-    buffer[i] = _wire->read();
-  }
+    uint8_t resp = 0;
+
+    TRACE_TIMESTAMP();
+    TRACE_PRINT("Requesting ");
+    TRACE_PRINT(len);
+    TRACE_PRINT(" byte(s) from 0x");
+    TRACE_PRINTLN(reg, HEX);
+
+    if (_i2c_addr > 0) {
+        /* I2C */
+        #ifdef __SAM3X8E__
+          /* http://forum.arduino.cc/index.php?topic=385377.msg2947227#msg2947227 */
+          _wire->requestFrom(_i2c_addr, 1, reg, 1, true);
+        #else
+          _wire->beginTransmission(_i2c_addr);
+          _wire->write(reg);
+          _wire->endTransmission();
+          _wire->requestFrom(_i2c_addr, 1);
+        #endif
+
+        /* Dump the response into the supplied buffer */
+        resp = _wire->read();
+    } else {
+        /* SPI */
+        uint8_t tx[2] = {(reg << 1) | 0x01 };
+        uint8_t rx[2] = { 0 };
+        digitalWrite(_cs, LOW);
+        rx[0] = SPI.transfer(tx[0]);
+        rx[1] = SPI.transfer(tx[1]);
+        digitalWrite(_cs, HIGH);
+        resp = rx[1];
+    }
 
-  TRACE_TIMESTAMP();
-  TRACE_PRINT("Response (len=");
-  TRACE_PRINT(len);
-  TRACE_PRINT("):");
-  for (i=0; i<len; i++)
-  {
+    TRACE_TIMESTAMP();
+    TRACE_PRINT("Response = ");
     TRACE_PRINT(" 0x");
-    if (buffer[i] <= 0xF)
+    if (resp <= 0xF)
     {
-      TRACE_PRINT("0");
+        TRACE_PRINT("0");
     }
-    TRACE_PRINT(buffer[i], HEX);
-  }
-  TRACE_PRINTLN("");
+    TRACE_PRINT(resp, HEX);
+    TRACE_PRINTLN("");
 
-  return len;
+    return resp;
 }
 
 /***************************************************************************
@@ -140,6 +149,7 @@ byte Adafruit_MFRC630::readBuffer(byte reg, byte len, uint8_t *buffer)
  /**************************************************************************/
  /*!
      @brief  Instantiates a new instance of the Adafruit_MFRC630 class
+             using the default I2C bus.
  */
  /**************************************************************************/
  Adafruit_MFRC630::Adafruit_MFRC630(int8_t pdown_pin, uint8_t i2c_addr)
@@ -152,14 +162,19 @@ byte Adafruit_MFRC630::readBuffer(byte reg, byte len, uint8_t *buffer)
 
    /* Set the I2C bus instance */
    _wire = &Wire;
+
+   /* Disable SPI access. */
+   _cs = -1;
  }
 
 /**************************************************************************/
 /*!
     @brief  Instantiates a new instance of the Adafruit_MFRC630 class
+            using the specified I2C bus.
 */
 /**************************************************************************/
-Adafruit_MFRC630::Adafruit_MFRC630(TwoWire* wireBus, int8_t pdown_pin, uint8_t i2c_addr)
+Adafruit_MFRC630::Adafruit_MFRC630(TwoWire* wireBus, int8_t pdown_pin,
+    uint8_t i2c_addr)
 {
   /* Set the PDOWN pin */
   _pdown = pdown_pin;
@@ -169,6 +184,32 @@ Adafruit_MFRC630::Adafruit_MFRC630(TwoWire* wireBus, int8_t pdown_pin, uint8_t i
 
   /* Set the I2C bus instance */
   _wire = wireBus;
+
+  /* Disable SPI access. */
+  _cs = -1;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Instantiates a new instance of the Adafruit_MFRC630 class
+            using the HW SPI bus.
+*/
+/**************************************************************************/
+Adafruit_MFRC630::Adafruit_MFRC630(int8_t pdown_pin, int8_t cs, int8_t rsvd)
+{
+  /* Set the PDOWN pin */
+  _pdown = pdown_pin;
+
+  /* Set the CS/SSEL pin */
+  _cs = cs;
+  pinMode(_cs, OUTPUT);
+
+  /* Disable I2C access */
+  _wire = NULL;
+  _i2c_addr = 0;
+
+  /* Ignore rsvd for now */
+  (void)rsvd;
 }
 
 /***************************************************************************
@@ -187,10 +228,18 @@ bool Adafruit_MFRC630::begin()
   TRACE_PRINTLN("\tTrace output enabled: . [+ms] Message");
   DEBUG_PRINTLN("");
 
-  /* Enable I2C */
+  /* Enable I2C or SPI */
   DEBUG_TIMESTAMP();
-  DEBUG_PRINTLN("Initialising I2C");
-  _wire->begin();
+  if (_i2c_addr > 0) {
+      DEBUG_PRINTLN("Initialising I2C");
+      _wire->begin();
+  } else {
+      DEBUG_PRINTLN("Initialising SPI (Mode 0, MSB, DIV16)");
+      SPI.begin();
+      SPI.setDataMode(SPI_MODE0);
+      SPI.setBitOrder(MSBFIRST);
+      SPI.setClockDivider(SPI_CLOCK_DIV16);
+  }
 
   /* Reset the MFRC630 if possible */
   if (_pdown != -1)
@@ -1192,7 +1241,7 @@ uint16_t Adafruit_MFRC630::mifareWriteBlock(uint16_t blocknum, uint8_t *buf)
 
     DEBUG_TIMESTAMP();
     DEBUG_PRINT("Writing data to card @ 0x");
-    DEBUG_PRINTLN(pagenum);
+    DEBUG_PRINTLN(blocknum);
 
     /* Enable CRC for TX (RX off!). */
     DEBUG_TIMESTAMP();
@@ -1331,7 +1380,7 @@ uint16_t Adafruit_MFRC630::ntagWritePage(uint16_t pagenum, uint8_t *buf)
    * 'user memory' range (see docs/NTAG.md for further details).
    */
   if ((pagenum < 4) || (pagenum > 44)) {
-    DEBUG_TIMESTAMP(...);
+    DEBUG_TIMESTAMP();
     DEBUG_PRINT("Page number out of range for NTAG213: ");
     DEBUG_PRINTLN(pagenum);
     return 0;

+ 14 - 5
Adafruit_MFRC630.h

@@ -76,7 +76,7 @@ class Adafruit_MFRC630
 {
   public:
     /**
-     * Constructor
+     * Default I2C bus constructor
      *
      * @param pdown_pin     The power down pin number (required)/
      * @param i2c_addr      The I2C address to use (default value is empty)
@@ -84,7 +84,7 @@ class Adafruit_MFRC630
     Adafruit_MFRC630(int8_t pdown_pin = -1, uint8_t i2c_addr = MFRC630_I2C_ADDR);
 
     /**
-     * Constructor
+     * Custom I2C bus constructor
      *
      * @param wireBus       The I2C bus to use
      * @param pdown_pin     The power down pin number (required)/
@@ -92,6 +92,15 @@ class Adafruit_MFRC630
      */
     Adafruit_MFRC630(TwoWire* wireBus, int8_t pdown_pin = -1, uint8_t i2c_addr = MFRC630_I2C_ADDR);
 
+    /**
+     * HW SPI bus constructor
+     *
+     * @param pdown_pin     The power down pin number (required)/
+     * @param cs            The CS/Sel pin for HW SPI access.
+     * @param rsvd          Reserved, required to distiguish contructors. :(
+     */
+    Adafruit_MFRC630(int8_t pdown_pin, int8_t cs, int8_t rsvd);
+
     /**
      * Initialises the IC and performs some simple system checks.
      *
@@ -130,7 +139,7 @@ class Adafruit_MFRC630
     /**
      * Clears the contents of the FIFO buffer.
      */
-    void    clearFIFO(void);
+    void clearFIFO(void);
 
     /* Command wrappers */
     /**
@@ -273,11 +282,11 @@ class Adafruit_MFRC630
     int8_t _pdown;
     uint8_t _i2c_addr;
     TwoWire* _wire;
+    uint8_t _cs;
 
     void write8(byte reg, byte value);
-    void writeBuffer(byte reg, byte len, uint8_t *buffer);
+    void writeBuffer(byte reg, uint16_t len, uint8_t *buffer);
     byte read8(byte reg);
-    byte readBuffer(byte reg, byte len, uint8_t *buffer);
 
     void printHex(uint8_t *buf, size_t len);
     void printError(enum mfrc630errors err);

+ 1 - 1
docs/Doxyfile

@@ -1656,7 +1656,7 @@ EXTRA_SEARCH_MAPPINGS  =
 # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
 # The default value is: YES.
 
-GENERATE_LATEX         = NO
+GENERATE_LATEX         = YES
 
 # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
 # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of

+ 163 - 0
examples/mifare1k_dump_spi/mifare1k_dump_spi.ino

@@ -0,0 +1,163 @@
+#include <Wire.h>
+#include <Adafruit_MFRC630.h>
+
+/* Indicate the pin number where PDOWN is connected. */
+#define PDOWN_PIN         (A4)
+
+/* Indicate the CS/SSEL pin if using SPI. */
+#define SSEL_PIN          (A5)
+
+/* Use the default I2C address */
+// Adafruit_MFRC630 rfid = Adafruit_MFRC630(PDOWN_PIN);
+
+/* Use HW SPI */
+Adafruit_MFRC630 rfid = Adafruit_MFRC630(PDOWN_PIN, SSEL_PIN, 0);
+
+/* Prints out len bytes of hex data in table format. */
+static void print_buf_hex(uint8_t *buf, size_t len)
+{
+  for (uint8_t i = 0; i < len; i++)
+  {
+    Serial.print("0x");
+    if (buf[i] < 16)
+    {
+      Serial.print("0");
+    }
+    Serial.print(buf[i], HEX);
+    Serial.print(" ");
+  }
+  Serial.println(" ");
+}
+
+/* Dumps an entire sector (4*16-byte blocks) to the serial monitor. */
+void radio_mifare_dump_sector(uint8_t sector_num)
+{
+  uint8_t readbuf[16] = { 0 };
+  /* Try to read four blocks inside the sector. */
+  for (uint8_t b = 0; b < 4 ; b++) {
+    uint8_t len = 0;
+    len = rfid.mifareReadBlock(sector_num * 4 + b, readbuf);
+    if (len == 0) {
+      /* No data returned! */
+      Serial.print("What!?! No data returned for block ");
+      Serial.print(sector_num * 4 + b);
+      Serial.println("!");
+      #if MOJIC_TRICK
+      Serial.println("(ノ ゜Д゜)ノ ︵ ┻━┻");
+      #endif
+      return;
+    } else {
+      /* Display the block contents. */
+      Serial.print(sector_num * 4 + b); Serial.print(": ");
+      print_buf_hex(readbuf, len);
+    }
+  }
+}
+
+/*
+ * This more concise loop show the minimim requirements to dump the first 1K
+ * of memory from a Mifare Classic or Mifare Plus compatible card. No meaningful
+ * error-handling or debug output is present here, so this code is intended
+ * as a simple starting point for further work.
+ */
+bool radio_mifare1K_dump_minimal(void)
+{
+    bool rc;
+
+    /* Put the IC in a known-state. */
+    rfid.softReset();
+
+    /* Configure the radio for ISO14443A-106. */
+    rfid.configRadio(MFRC630_RADIOCFG_ISO1443A_106);
+
+    /* Request a tag (activates the near field, etc.). */
+    uint16_t atqa = rfid.iso14443aRequest();
+
+    /* Looks like we found a tag, move on to selection. */
+    if (atqa)
+    {
+        uint8_t uid[10] = { 0 };
+        uint8_t uidlen;
+        uint8_t sak;
+
+        /* Retrieve the UID and SAK values. */
+        uidlen = rfid.iso14443aSelect(uid, &sak);
+        Serial.print("Found a tag with UUID ");
+        for (uint8_t i = 0; i < uidlen; i++) {
+            Serial.print(uid[i], HEX);
+            Serial.print(" ");
+        }
+        Serial.println("");
+        if (uidlen == 4) {
+            /* Assume Mifare Classic/Plus and set the global/default key. */
+            rfid.mifareLoadKey(rfid.mifareKeyGlobal);
+            /* Try to authenticate sectors 0..15. */
+            for (uint8_t s = 0; s < 16; s++) {
+                /* Try to authenticate this sector. */
+                Serial.print("Sector "); Serial.println(s);
+                if(rfid.mifareAuth(MIFARE_CMD_AUTH_A, s*4, uid)) {
+                    /* We should be able to read the sector contents now. */
+                    radio_mifare_dump_sector(s);
+                } else {
+                    Serial.print("AUTH_A failed for sector ");
+                    Serial.println(s);
+                }
+            }
+            rc = true;
+        } else {
+            Serial.print("Unexpected UID length: "); Serial.println(uidlen);
+            rc = false;
+        }
+    } else {
+        rc = false;     /* No tag found, return false. */
+    }
+
+    return rc;
+}
+
+/**
+ *
+ */
+void setup() {
+  Serial.begin(115200);
+
+  while (!Serial) {
+    delay(1);
+  }
+
+  Serial.println("");
+  Serial.println("-------------------------------");
+  Serial.println("Adafruit MFRC630 Mifare 1K Test");
+  Serial.println("-------------------------------");
+
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  /* Try to initialize the IC */
+  if (!(rfid.begin())) {
+    Serial.println("Unable to initialize the MFRC630. Check wiring?");
+    while(1) {
+      digitalWrite(LED_BUILTIN, HIGH);
+      delay(50);
+      digitalWrite(LED_BUILTIN, LOW);
+      delay(50);
+    }
+  }
+
+  /*
+   * This will be INCREDIBLY chatty on the I2C bus, but can be used as a
+   * quick test to wait until a card enters the near field.
+   */
+  Serial.println("Waiting for an ISO14443-A compatible card ...");
+  while (!radio_mifare1K_dump_minimal())
+  {
+    delay(50);
+  }
+}
+
+void loop() {
+    /* Blinky! */
+  digitalWrite(LED_BUILTIN, HIGH);
+  delay(500);
+  digitalWrite(LED_BUILTIN, LOW);
+  delay(500);
+}