diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6a2774 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.*.swp +session +tags diff --git a/README b/README index 1c10404..d5c056a 100644 --- a/README +++ b/README @@ -1,8 +1,49 @@ === Brmdoor control software === -brmd/ - integration hub that collects data from various sources and provides unified reporting on IRC and web etc. +brmd/ - integration hub that collects data from various sources and provides +unified reporting on IRC and web etc. brmdoor/ - Arduino software Project webpage: http://brmlab.cz/project/brmdoor + +Note for PN532 version: if you want brmdoor to add card UID after "CARD" +message (not just nick), set printFullUID to true in brmdoor/brmdoor.ino. + + +==== Adding new UIDs to the database ==== + +There are two lists - the new proper and the old deperecated with truncated UIDs. +When adding, the new list is better place. + +The new proper list is searched for UIDs first. + +===== Using the new proper list - recommended ===== + +Edit the cardids_proper.h file and add your UID and nick to a new line, which +will become part of the ACLproper array. E.g. to add UID 04c24ce9ad2780 that is +7 bytes long and adding nick "voyeur1", add line: + + { 7, {0x04, 0xc2 0x4c, 0xe9, 0xad, 0x27, 0x80}, "voyeur1" }, + + +===== Using the old broken truncated list - not recommended ===== + +Edit the cardids.h file. If the new card UID is 4 bytes long, e.g. 35b018d4, +compute BCC, which is xor of these four bytes (0x49 in this case). Then add + + { {0x00, 0x00, 0x35, 0xb0, 0x18, 0xd4, 0x49}, "mifare_classic_1" }, + +The first two bytes are magic bytes that originate in the old reader, just use +two zero bytes as above. The last byte is BCC we computed before. But you can +use zero, the software doesn't need it. + +If the card UID is longer than 4 bytes (7 or 10 bytes), e.g. 04c24ce9ad2780, +discard last four bytes of the UID and prepend 0x88. Use this "newly" created +UID as if the card had only 4 byte UID, just like above. + + { {0x00, 0x00, 0x88, 0x04, 0xc2, 0x4c, 0x02}, "truncated_voyeur1" }, + +The old reader didn't support ISO14443 SELECT cascade 2 and 3. Hence the broken +UIDs. diff --git a/brmd/brmd.pl b/brmd/brmd.pl index 8e1caca..20d9e4d 100755 --- a/brmd/brmd.pl +++ b/brmd/brmd.pl @@ -11,7 +11,7 @@ use Image::Magick; our @channels = ("#brmlab", "#brmstatus"); our $streamurl = "http://brmlab.cz/stream"; -our $devdoor = $ARGV[0]; $devdoor ||= "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A700e1qB-if00-port0"; +our $devdoor = $ARGV[0]; $devdoor ||= "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A70078Q1-if00-port0"; our $devasign = $ARGV[1]; $devasign ||= "/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0"; our ($status, $streaming, $dooropen, $topic) = (0, 0, 0, 'BRMLAB OPEN'); our ($laststchange, $lastunlock) = (time, 0); diff --git a/brmdoor/.gitignore b/brmdoor/.gitignore index e430f5a..21ade5e 100644 --- a/brmdoor/.gitignore +++ b/brmdoor/.gitignore @@ -1 +1,2 @@ cardids.h +cardids_proper.h diff --git a/brmdoor/AdafruitPN532/Adafruit_PN532.cpp b/brmdoor/AdafruitPN532/Adafruit_PN532.cpp new file mode 100644 index 0000000..9528447 --- /dev/null +++ b/brmdoor/AdafruitPN532/Adafruit_PN532.cpp @@ -0,0 +1,1036 @@ +/**************************************************************************/ +/*! + @file Adafruit_PN532.cpp + @author Adafruit Industries + @license BSD (see license.txt) + + SPI Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver + + This is a library for the Adafruit PN532 NFC/RFID breakout boards + This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + + Check out the links above for our tutorials and wiring diagrams + These chips use SPI to communicate, 4 required to interface + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + + @section HISTORY + + v1.4 - Added setPassiveActivationRetries() + + v1.2 - Added writeGPIO() + - Added readGPIO() + + v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes + - Added the following helper functions for text display + static void PrintHex(const byte * data, const uint32_t numBytes) + static void PrintHexChar(const byte * pbtData, const uint32_t numBytes) + - Added the following Mifare Classic functions: + bool mifareclassic_IsFirstBlock (uint32_t uiBlock) + bool mifareclassic_IsTrailerBlock (uint32_t uiBlock) + uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData) + uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data) + uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data) + - Added the following Mifare Ultalight functions: + uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer) +*/ +/**************************************************************************/ +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +//#define PN532DEBUG + +#include "Adafruit_PN532.h" + +byte pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00}; +byte pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03}; + +// Uncomment these lines to enable debug output for PN532(SPI) and/or MIFARE related code +// #define PN532DEBUG +// #define MIFAREDEBUG + +#define PN532_PACKBUFFSIZ 64 +byte pn532_packetbuffer[PN532_PACKBUFFSIZ]; + +/**************************************************************************/ +/*! + @brief Instantiates a new PN532 class + + @param clk SPI clock pin (SCK) + @param miso SPI MISO pin + @param mosi SPI MOSI pin + @param ss SPI chip select pin (CS/SSEL) +*/ +/**************************************************************************/ +Adafruit_PN532::Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t ss) { + _clk = clk; + _miso = miso; + _mosi = mosi; + _ss = ss; + + pinMode(_ss, OUTPUT); + pinMode(_clk, OUTPUT); + pinMode(_mosi, OUTPUT); + pinMode(_miso, INPUT); +} + +/**************************************************************************/ +/*! + @brief Setups the HW +*/ +/**************************************************************************/ +void Adafruit_PN532::begin() { + digitalWrite(_ss, LOW); + + delay(1000); + + // not exactly sure why but we have to send a dummy command to get synced up + pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; + sendCommandCheckAck(pn532_packetbuffer, 1); + + // ignore response! +} + +/**************************************************************************/ +/*! + @brief Prints a hexadecimal value in plain characters + + @param data Pointer to the byte data + @param numBytes Data length in bytes +*/ +/**************************************************************************/ +void Adafruit_PN532::PrintHex(const byte * data, const uint32_t numBytes) +{ + uint32_t szPos; + for (szPos=0; szPos < numBytes; szPos++) + { + Serial.print("0x"); + // Append leading 0 for small values + if (data[szPos] <= 0xF) + Serial.print("0"); + Serial.print(data[szPos], HEX); + if ((numBytes > 1) && (szPos != numBytes - 1)) + { + Serial.print(" "); + } + } + Serial.println(""); +} + +/**************************************************************************/ +/*! + @brief Prints a hexadecimal value in plain characters, along with + the char equivalents in the following format + + 00 00 00 00 00 00 ...... + + @param data Pointer to the byte data + @param numBytes Data length in bytes +*/ +/**************************************************************************/ +void Adafruit_PN532::PrintHexChar(const byte * data, const uint32_t numBytes) +{ + uint32_t szPos; + for (szPos=0; szPos < numBytes; szPos++) + { + // Append leading 0 for small values + if (data[szPos] <= 0xF) + Serial.print("0"); + Serial.print(data[szPos], HEX); + if ((numBytes > 1) && (szPos != numBytes - 1)) + { + Serial.print(" "); + } + } + Serial.print(" "); + for (szPos=0; szPos < numBytes; szPos++) + { + if (data[szPos] <= 0x1F) + Serial.print("."); + else + Serial.print(data[szPos]); + } + Serial.println(""); +} + +/**************************************************************************/ +/*! + @brief Checks the firmware version of the PN5xx chip + + @returns The chip's firmware version and ID +*/ +/**************************************************************************/ +uint32_t Adafruit_PN532::getFirmwareVersion(void) { + uint32_t response; + + pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; + + if (! sendCommandCheckAck(pn532_packetbuffer, 1)) + return 0; + + // read data packet + readspidata(pn532_packetbuffer, 12); + + // check some basic stuff + if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) { + return 0; + } + + response = pn532_packetbuffer[6]; + response <<= 8; + response |= pn532_packetbuffer[7]; + response <<= 8; + response |= pn532_packetbuffer[8]; + response <<= 8; + response |= pn532_packetbuffer[9]; + + return response; +} + + +/**************************************************************************/ +/*! + @brief Sends a command and waits a specified period for the ACK + + @param cmd Pointer to the command buffer + @param cmdlen The size of the command in bytes + @param timeout timeout before giving up + + @returns 1 if everything is OK, 0 if timeout occured before an + ACK was recieved +*/ +/**************************************************************************/ +// default timeout of one second +boolean Adafruit_PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) { + uint16_t timer = 0; + + // write the command + spiwritecommand(cmd, cmdlen); + + // Wait for chip to say its ready! + while (readspistatus() != PN532_SPI_READY) { + if (timeout != 0) { + timer+=10; + if (timer > timeout) + return false; + } + delay(10); + } + + // read acknowledgement + if (!spi_readack()) { + return false; + } + + timer = 0; + // Wait for chip to say its ready! + while (readspistatus() != PN532_SPI_READY) { + if (timeout != 0) { + timer+=10; + if (timer > timeout) + return false; + } + delay(10); + } + + return true; // ack'd command +} + +/**************************************************************************/ +/*! + Writes an 8-bit value that sets the state of the PN532's GPIO pins + + @warning This function is provided exclusively for board testing and + is dangerous since it will throw an error if any pin other + than the ones marked "Can be used as GPIO" are modified! All + pins that can not be used as GPIO should ALWAYS be left high + (value = 1) or the system will become unstable and a HW reset + will be required to recover the PN532. + + pinState[0] = P30 Can be used as GPIO + pinState[1] = P31 Can be used as GPIO + pinState[2] = P32 *** RESERVED (Must be 1!) *** + pinState[3] = P33 Can be used as GPIO + pinState[4] = P34 *** RESERVED (Must be 1!) *** + pinState[5] = P35 Can be used as GPIO + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +boolean Adafruit_PN532::writeGPIO(uint8_t pinstate) { + uint8_t errorbit; + + // Make sure pinstate does not try to toggle P32 or P34 + pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34); + + // Fill command buffer + pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO; + pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins + pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI) + + #ifdef PN532DEBUG + Serial.print("Writing P3 GPIO: "); Serial.println(pn532_packetbuffer[1], HEX); + #endif + + // Send the WRITEGPIO command (0x0E) + if (! sendCommandCheckAck(pn532_packetbuffer, 3)) + return 0x0; + + // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM 00) + readspidata(pn532_packetbuffer, 8); + + #ifdef PN532DEBUG + Serial.print("Received: "); + PrintHex(pn532_packetbuffer, 8); + Serial.println(""); + #endif + + return (pn532_packetbuffer[5] == 0x0F); +} + +/**************************************************************************/ +/*! + Reads the state of the PN532's GPIO pins + + @returns An 8-bit value containing the pin state where: + + pinState[0] = P30 + pinState[1] = P31 + pinState[2] = P32 + pinState[3] = P33 + pinState[4] = P34 + pinState[5] = P35 +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::readGPIO(void) { + pn532_packetbuffer[0] = PN532_COMMAND_READGPIO; + + // Send the READGPIO command (0x0C) + if (! sendCommandCheckAck(pn532_packetbuffer, 1)) + return 0x0; + + // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1 DATACHECKSUM 00) + readspidata(pn532_packetbuffer, 11); + + /* READGPIO response should be in the following format: + + byte Description + ------------- ------------------------------------------ + b0..5 Frame header and preamble + b6 P3 GPIO Pins + b7 P7 GPIO Pins (not used ... taken by SPI) + b8 Interface Mode Pins (not used ... bus select pins) + b9..10 checksum */ + + #ifdef PN532DEBUG + Serial.print("Received: "); + PrintHex(pn532_packetbuffer, 11); + Serial.println(""); + Serial.print("P3 GPIO: 0x"); Serial.println(pn532_packetbuffer[6], HEX); + Serial.print("P7 GPIO: 0x"); Serial.println(pn532_packetbuffer[7], HEX); + Serial.print("IO GPIO: 0x"); Serial.println(pn532_packetbuffer[8], HEX); + // Note: You can use the IO GPIO value to detect the serial bus being used + switch(pn532_packetbuffer[8]) + { + case 0x00: // Using UART + Serial.println("Using UART (IO = 0x00)"); + break; + case 0x01: // Using I2C + Serial.println("Using I2C (IO = 0x01)"); + break; + case 0x02: // Using SPI + Serial.println("Using SPI (IO = 0x02)"); + break; + } + #endif + + return pn532_packetbuffer[6]; +} + +/**************************************************************************/ +/*! + @brief Configures the SAM (Secure Access Module) +*/ +/**************************************************************************/ +boolean Adafruit_PN532::SAMConfig(void) { + pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; + pn532_packetbuffer[1] = 0x01; // normal mode; + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second + pn532_packetbuffer[3] = 0x01; // use IRQ pin! + + if (! sendCommandCheckAck(pn532_packetbuffer, 4)) + return false; + + // read data packet + readspidata(pn532_packetbuffer, 8); + + return (pn532_packetbuffer[5] == 0x15); +} + +/**************************************************************************/ +/*! + Sets the MxRtyPassiveActivation byte of the RFConfiguration register + + @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout + after mxRetries + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +boolean Adafruit_PN532::setPassiveActivationRetries(uint8_t maxRetries) { + pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; + pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries) + pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF) + pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01) + pn532_packetbuffer[4] = maxRetries; + +#ifdef MIFAREDEBUG + Serial.print("Setting MxRtyPassiveActivation to "); Serial.print(maxRetries, DEC); Serial.println(" "); +#endif + + if (! sendCommandCheckAck(pn532_packetbuffer, 5)) + return 0x0; // no ACK + + return 1; +} + +/***** ISO14443A Commands ******/ + +/**************************************************************************/ +/*! + Waits for an ISO14443A target to enter the field + + @param cardBaudRate Baud rate of the card + @param uid Pointer to the array that will be populated + with the card's UID (up to 7 bytes) + @param uidLength Pointer to the variable that will hold the + length of the card's UID. + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +boolean Adafruit_PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength) { + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) + pn532_packetbuffer[2] = cardbaudrate; + + if (! sendCommandCheckAck(pn532_packetbuffer, 3)) + return 0x0; // no cards read + + // read data packet + readspidata(pn532_packetbuffer, 20); + // check some basic stuff + + /* ISO14443A card response should be in the following format: + + byte Description + ------------- ------------------------------------------ + b0..6 Frame header and preamble + b7 Tags Found + b8 Tag Number (only one used in this example) + b9..10 SENS_RES + b11 SEL_RES + b12 NFCID Length + b13..NFCIDLen NFCID */ + +#ifdef MIFAREDEBUG + Serial.print("Found "); Serial.print(pn532_packetbuffer[7], DEC); Serial.println(" tags"); +#endif + if (pn532_packetbuffer[7] != 1) + return 0; + + uint16_t sens_res = pn532_packetbuffer[9]; + sens_res <<= 8; + sens_res |= pn532_packetbuffer[10]; +#ifdef MIFAREDEBUG + Serial.print("ATQA: 0x"); Serial.println(sens_res, HEX); + Serial.print("SAK: 0x"); Serial.println(pn532_packetbuffer[11], HEX); +#endif + + /* Card appears to be Mifare Classic */ + *uidLength = pn532_packetbuffer[12]; +#ifdef MIFAREDEBUG + Serial.print("UID:"); +#endif + for (uint8_t i=0; i < pn532_packetbuffer[12]; i++) + { + uid[i] = pn532_packetbuffer[13+i]; +#ifdef MIFAREDEBUG + Serial.print(" 0x");Serial.print(uid[i], HEX); +#endif + } +#ifdef MIFAREDEBUG + Serial.println(); +#endif + + return 1; +} + + +/***** Mifare Classic Functions ******/ + +/**************************************************************************/ +/*! + Indicates whether the specified block number is the first block + in the sector (block 0 relative to the current sector) +*/ +/**************************************************************************/ +bool Adafruit_PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock) +{ + // Test if we are in the small or big sectors + if (uiBlock < 128) + return ((uiBlock) % 4 == 0); + else + return ((uiBlock) % 16 == 0); +} + +/**************************************************************************/ +/*! + Indicates whether the specified block number is the sector trailer +*/ +/**************************************************************************/ +bool Adafruit_PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock) +{ + // Test if we are in the small or big sectors + if (uiBlock < 128) + return ((uiBlock + 1) % 4 == 0); + else + return ((uiBlock + 1) % 16 == 0); +} + +/**************************************************************************/ +/*! + Tries to authenticate a block of memory on a MIFARE card using the + INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual + for more information on sending MIFARE and other commands. + + @param uid Pointer to a byte array containing the card UID + @param uidLen The length (in bytes) of the card's UID (Should + be 4 for MIFARE Classic) + @param blockNumber The block number to authenticate. (0..63 for + 1KB cards, and 0..255 for 4KB cards). + @param keyNumber Which key type to use during authentication + (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B) + @param keyData Pointer to a byte array containing the 6 byte + key value + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData) +{ + uint8_t len; + uint8_t i; + + // Hang on to the key and uid data + memcpy (_key, keyData, 6); + memcpy (_uid, uid, uidLen); + _uidLen = uidLen; + + #ifdef MIFAREDEBUG + Serial.print("Trying to authenticate card "); + Adafruit_PN532::PrintHex(_uid, _uidLen); + Serial.print("Using authentication KEY ");Serial.print(keyNumber ? 'B' : 'A');Serial.print(": "); + Adafruit_PN532::PrintHex(_key, 6); + #endif + + // Prepare the authentication command // + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ + pn532_packetbuffer[1] = 1; /* Max card numbers */ + pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; + pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ + memcpy (pn532_packetbuffer+4, _key, 6); + for (i = 0; i < _uidLen; i++) + { + pn532_packetbuffer[10+i] = _uid[i]; /* 4 byte card ID */ + } + + if (! sendCommandCheckAck(pn532_packetbuffer, 10+_uidLen)) + return 0; + + // Read the response packet + readspidata(pn532_packetbuffer, 12); + // check if the response is valid and we are authenticated??? + // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 + // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good + if (pn532_packetbuffer[7] != 0x00) + { + #ifdef PN532DEBUG + Serial.print("Authentification failed: "); + Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 12); + #endif + return 0; + } + + return 1; +} + +/**************************************************************************/ +/*! + Tries to read an entire 16-byte data block at the specified block + address. + + @param blockNumber The block number to authenticate. (0..63 for + 1KB cards, and 0..255 for 4KB cards). + @param data Pointer to the byte array that will hold the + retrieved data (if any) + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data) +{ + #ifdef MIFAREDEBUG + Serial.print("Trying to read 16 bytes from block ");Serial.println(blockNumber); + #endif + + /* Prepare the command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + + /* Send the command */ + if (! sendCommandCheckAck(pn532_packetbuffer, 4)) + { + #ifdef MIFAREDEBUG + Serial.println("Failed to receive ACK for read command"); + #endif + return 0; + } + + /* Read the response packet */ + readspidata(pn532_packetbuffer, 26); + + /* If byte 8 isn't 0x00 we probably have an error */ + if (pn532_packetbuffer[7] != 0x00) + { + //#ifdef MIFAREDEBUG + Serial.println("Unexpected response"); + Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26); + //#endif + return 0; + } + + /* Copy the 16 data bytes to the output buffer */ + /* Block content starts at byte 9 of a valid response */ + memcpy (data, pn532_packetbuffer+8, 16); + + /* Display data for debug if requested */ + #ifdef MIFAREDEBUG + Serial.print("Block "); + Serial.println(blockNumber); + Adafruit_PN532::PrintHexChar(data, 16); + #endif + + return 1; +} + +/**************************************************************************/ +/*! + Tries to write an entire 16-byte data block at the specified block + address. + + @param blockNumber The block number to authenticate. (0..63 for + 1KB cards, and 0..255 for 4KB cards). + @param data The byte array that contains the data to write. + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data) +{ + #ifdef MIFAREDEBUG + Serial.print("Trying to write 16 bytes to block ");Serial.println(blockNumber); + #endif + + /* Prepare the first command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + memcpy (pn532_packetbuffer+4, data, 16); /* Data Payload */ + + /* Send the command */ + if (! sendCommandCheckAck(pn532_packetbuffer, 20)) + { + #ifdef MIFAREDEBUG + Serial.println("Failed to receive ACK for write command"); + #endif + return 0; + } + delay(10); + + /* Read the response packet */ + readspidata(pn532_packetbuffer, 26); + + return 1; +} + +/**************************************************************************/ +/*! + Formats a Mifare Classic card to store NDEF Records + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareclassic_FormatNDEF (void) +{ + uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; + uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; + uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + // Write block 1 and 2 to the card + if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1))) + return 0; + if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2))) + return 0; + // Write key A and access rights card + if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3))) + return 0; + + // Seems that everything was OK (?!) + return 1; +} + +/**************************************************************************/ +/*! + Writes an NDEF URI Record to the specified sector (1..15) + + Note that this function assumes that the Mifare Classic card is + already formatted to work as an "NFC Forum Tag" and uses a MAD1 + file system. You can use the NXP TagWriter app on Android to + properly format cards for this. + + @param sectorNumber The sector that the URI record should be written + to (can be 1..15 for a 1K card) + @param uriIdentifier The uri identifier code (0 = none, 0x01 = + "http://www.", etc.) + @param url The uri text to write (max 38 characters). + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url) +{ + // Figure out how long the string is + uint8_t len = strlen(url); + + // Make sure we're within a 1K limit for the sector number + if ((sectorNumber < 1) || (sectorNumber > 15)) + return 0; + + // Make sure the URI payload is between 1 and 38 chars + if ((len < 1) || (len > 38)) + return 0; + + // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message) + uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len+5, 0xD1, 0x01, len+1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + if (len <= 6) + { + // Unlikely we'll get a url this short, but why not ... + memcpy (sectorbuffer1+9, url, len); + sectorbuffer1[len+9] = 0xFE; + } + else if (len == 7) + { + // 0xFE needs to be wrapped around to next block + memcpy (sectorbuffer1+9, url, len); + sectorbuffer2[0] = 0xFE; + } + else if ((len > 7) || (len <= 22)) + { + // Url fits in two blocks + memcpy (sectorbuffer1+9, url, 7); + memcpy (sectorbuffer2, url+7, len-7); + sectorbuffer2[len-7] = 0xFE; + } + else if (len == 23) + { + // 0xFE needs to be wrapped around to final block + memcpy (sectorbuffer1+9, url, 7); + memcpy (sectorbuffer2, url+7, len-7); + sectorbuffer3[0] = 0xFE; + } + else + { + // Url fits in three blocks + memcpy (sectorbuffer1+9, url, 7); + memcpy (sectorbuffer2, url+7, 16); + memcpy (sectorbuffer3, url+23, len-24); + sectorbuffer3[len-22] = 0xFE; + } + + // Now write all three blocks back to the card + if (!(mifareclassic_WriteDataBlock (sectorNumber*4, sectorbuffer1))) + return 0; + if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+1, sectorbuffer2))) + return 0; + if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+2, sectorbuffer3))) + return 0; + if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+3, sectorbuffer4))) + return 0; + + // Seems that everything was OK (?!) + return 1; +} + +/***** Mifare Ultralight Functions ******/ + +/**************************************************************************/ +/*! + Tries to read an entire 4-byte page at the specified address. + + @param page The page number (0..63 in most cases) + @param buffer Pointer to the byte array that will hold the + retrieved data (if any) +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::mifareultralight_ReadPage (uint8_t page, uint8_t * buffer) +{ + if (page >= 64) + { + #ifdef MIFAREDEBUG + Serial.println("Page value out of range"); + #endif + return 0; + } + + #ifdef MIFAREDEBUG + Serial.print("Reading page ");Serial.println(page); + #endif + + /* Prepare the command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ + pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */ + + /* Send the command */ + if (! sendCommandCheckAck(pn532_packetbuffer, 4)) + { + #ifdef MIFAREDEBUG + Serial.println("Failed to receive ACK for write command"); + #endif + return 0; + } + + /* Read the response packet */ + readspidata(pn532_packetbuffer, 26); + #ifdef MIFAREDEBUG + Serial.println("Received: "); + Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26); + #endif + + /* If byte 8 isn't 0x00 we probably have an error */ + if (pn532_packetbuffer[7] == 0x00) + { + /* Copy the 4 data bytes to the output buffer */ + /* Block content starts at byte 9 of a valid response */ + /* Note that the command actually reads 16 byte or 4 */ + /* pages at a time ... we simply discard the last 12 */ + /* bytes */ + memcpy (buffer, pn532_packetbuffer+8, 4); + } + else + { + #ifdef MIFAREDEBUG + Serial.println("Unexpected response reading block: "); + Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26); + #endif + return 0; + } + + /* Display data for debug if requested */ + #ifdef MIFAREDEBUG + Serial.print("Page ");Serial.print(page);Serial.println(":"); + Adafruit_PN532::PrintHexChar(buffer, 4); + #endif + + // Return OK signal + return 1; +} + + + +/************** high level SPI */ + + +/**************************************************************************/ +/*! + @brief Tries to read the SPI ACK signal +*/ +/**************************************************************************/ +boolean Adafruit_PN532::spi_readack() { + uint8_t ackbuff[6]; + + readspidata(ackbuff, 6); + + return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6)); +} + +/************** mid level SPI */ + +/**************************************************************************/ +/*! + @brief Reads the SPI status register (to know if the PN532 is ready) +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::readspistatus(void) { + digitalWrite(_ss, LOW); + delay(2); + spiwrite(PN532_SPI_STATREAD); + // read byte + uint8_t x = spiread(); + + digitalWrite(_ss, HIGH); + return x; +} + +/**************************************************************************/ +/*! + @brief Reads n bytes of data from the PN532 via SPI + + @param buff Pointer to the buffer where data will be written + @param n Number of bytes to be read +*/ +/**************************************************************************/ +void Adafruit_PN532::readspidata(uint8_t* buff, uint8_t n) { + digitalWrite(_ss, LOW); + delay(2); + spiwrite(PN532_SPI_DATAREAD); + +#ifdef PN532DEBUG + Serial.print("Reading: "); +#endif + for (uint8_t i=0; i https://www.adafruit.com/products/364 + + Check out the links above for our tutorials and wiring diagrams + These chips use SPI to communicate, 4 required to interface + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + @section HISTORY + + v1.1 - Added full command list + - Added 'verbose' mode flag to constructor to toggle debug output + - Changed readPassiveTargetID() to return variable length values + +*/ +/**************************************************************************/ + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#define PN532_PREAMBLE (0x00) +#define PN532_STARTCODE1 (0x00) +#define PN532_STARTCODE2 (0xFF) +#define PN532_POSTAMBLE (0x00) + +#define PN532_HOSTTOPN532 (0xD4) + +// PN532 Commands +#define PN532_COMMAND_DIAGNOSE (0x00) +#define PN532_COMMAND_GETFIRMWAREVERSION (0x02) +#define PN532_COMMAND_GETGENERALSTATUS (0x04) +#define PN532_COMMAND_READREGISTER (0x06) +#define PN532_COMMAND_WRITEREGISTER (0x08) +#define PN532_COMMAND_READGPIO (0x0C) +#define PN532_COMMAND_WRITEGPIO (0x0E) +#define PN532_COMMAND_SETSERIALBAUDRATE (0x10) +#define PN532_COMMAND_SETPARAMETERS (0x12) +#define PN532_COMMAND_SAMCONFIGURATION (0x14) +#define PN532_COMMAND_POWERDOWN (0x16) +#define PN532_COMMAND_RFCONFIGURATION (0x32) +#define PN532_COMMAND_RFREGULATIONTEST (0x58) +#define PN532_COMMAND_INJUMPFORDEP (0x56) +#define PN532_COMMAND_INJUMPFORPSL (0x46) +#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A) +#define PN532_COMMAND_INATR (0x50) +#define PN532_COMMAND_INPSL (0x4E) +#define PN532_COMMAND_INDATAEXCHANGE (0x40) +#define PN532_COMMAND_INCOMMUNICATETHRU (0x42) +#define PN532_COMMAND_INDESELECT (0x44) +#define PN532_COMMAND_INRELEASE (0x52) +#define PN532_COMMAND_INSELECT (0x54) +#define PN532_COMMAND_INAUTOPOLL (0x60) +#define PN532_COMMAND_TGINITASTARGET (0x8C) +#define PN532_COMMAND_TGSETGENERALBYTES (0x92) +#define PN532_COMMAND_TGGETDATA (0x86) +#define PN532_COMMAND_TGSETDATA (0x8E) +#define PN532_COMMAND_TGSETMETADATA (0x94) +#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88) +#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90) +#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A) + +#define PN532_WAKEUP (0x55) + +#define PN532_SPI_STATREAD (0x02) +#define PN532_SPI_DATAWRITE (0x01) +#define PN532_SPI_DATAREAD (0x03) +#define PN532_SPI_READY (0x01) + +#define PN532_MIFARE_ISO14443A (0x00) + +// Mifare Commands +#define MIFARE_CMD_AUTH_A (0x60) +#define MIFARE_CMD_AUTH_B (0x61) +#define MIFARE_CMD_READ (0x30) +#define MIFARE_CMD_WRITE (0xA0) +#define MIFARE_CMD_TRANSFER (0xB0) +#define MIFARE_CMD_DECREMENT (0xC0) +#define MIFARE_CMD_INCREMENT (0xC1) +#define MIFARE_CMD_STORE (0xC2) + +// Prefixes for NDEF Records (to identify record type) +#define NDEF_URIPREFIX_NONE (0x00) +#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01) +#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02) +#define NDEF_URIPREFIX_HTTP (0x03) +#define NDEF_URIPREFIX_HTTPS (0x04) +#define NDEF_URIPREFIX_TEL (0x05) +#define NDEF_URIPREFIX_MAILTO (0x06) +#define NDEF_URIPREFIX_FTP_ANONAT (0x07) +#define NDEF_URIPREFIX_FTP_FTPDOT (0x08) +#define NDEF_URIPREFIX_FTPS (0x09) +#define NDEF_URIPREFIX_SFTP (0x0A) +#define NDEF_URIPREFIX_SMB (0x0B) +#define NDEF_URIPREFIX_NFS (0x0C) +#define NDEF_URIPREFIX_FTP (0x0D) +#define NDEF_URIPREFIX_DAV (0x0E) +#define NDEF_URIPREFIX_NEWS (0x0F) +#define NDEF_URIPREFIX_TELNET (0x10) +#define NDEF_URIPREFIX_IMAP (0x11) +#define NDEF_URIPREFIX_RTSP (0x12) +#define NDEF_URIPREFIX_URN (0x13) +#define NDEF_URIPREFIX_POP (0x14) +#define NDEF_URIPREFIX_SIP (0x15) +#define NDEF_URIPREFIX_SIPS (0x16) +#define NDEF_URIPREFIX_TFTP (0x17) +#define NDEF_URIPREFIX_BTSPP (0x18) +#define NDEF_URIPREFIX_BTL2CAP (0x19) +#define NDEF_URIPREFIX_BTGOEP (0x1A) +#define NDEF_URIPREFIX_TCPOBEX (0x1B) +#define NDEF_URIPREFIX_IRDAOBEX (0x1C) +#define NDEF_URIPREFIX_FILE (0x1D) +#define NDEF_URIPREFIX_URN_EPC_ID (0x1E) +#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F) +#define NDEF_URIPREFIX_URN_EPC_PAT (0x20) +#define NDEF_URIPREFIX_URN_EPC_RAW (0x21) +#define NDEF_URIPREFIX_URN_EPC (0x22) +#define NDEF_URIPREFIX_URN_NFC (0x23) + +#define PN532_GPIO_VALIDATIONBIT (0x80) +#define PN532_GPIO_P30 (0) +#define PN532_GPIO_P31 (1) +#define PN532_GPIO_P32 (2) +#define PN532_GPIO_P33 (3) +#define PN532_GPIO_P34 (4) +#define PN532_GPIO_P35 (5) + +class Adafruit_PN532{ + public: + Adafruit_PN532(uint8_t cs, uint8_t clk, uint8_t mosi, uint8_t miso); + void begin(void); + + // Generic PN532 functions + boolean SAMConfig(void); + uint32_t getFirmwareVersion(void); + boolean sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000); + boolean writeGPIO(uint8_t pinstate); + uint8_t readGPIO(void); + boolean setPassiveActivationRetries(uint8_t maxRetries); + + // ISO14443A functions + boolean readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength); + + // Mifare Classic functions + bool mifareclassic_IsFirstBlock (uint32_t uiBlock); + bool mifareclassic_IsTrailerBlock (uint32_t uiBlock); + uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData); + uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data); + uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data); + uint8_t mifareclassic_FormatNDEF (void); + uint8_t mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url); + + // Mifare Ultralight functions + uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer); + + // Help functions to display formatted text + static void PrintHex(const byte * data, const uint32_t numBytes); + static void PrintHexChar(const byte * pbtData, const uint32_t numBytes); + + private: + uint8_t _ss, _clk, _mosi, _miso; + uint8_t _uid[7]; // ISO14443A uid + uint8_t _uidLen; // uid len + uint8_t _key[6]; // Mifare Classic key + + boolean spi_readack(); + uint8_t readspistatus(void); + void readspidata(uint8_t* buff, uint8_t n); + void spiwritecommand(uint8_t* cmd, uint8_t cmdlen); + void spiwrite(uint8_t c); + uint8_t spiread(void); +}; diff --git a/brmdoor/AdafruitPN532/examples/iso14443a_uid/iso14443a_uid.pde b/brmdoor/AdafruitPN532/examples/iso14443a_uid/iso14443a_uid.pde new file mode 100644 index 0000000..4fa39cd --- /dev/null +++ b/brmdoor/AdafruitPN532/examples/iso14443a_uid/iso14443a_uid.pde @@ -0,0 +1,83 @@ +/**************************************************************************/ +/*! + @file iso14443a_uid.pde + @author Adafruit Industries + @license BSD (see license.txt) + + This example will attempt to connect to an ISO14443A + card or tag and retrieve some basic information about it + that can be used to determine what type of card it is. + + Note that you need the baud rate to be 115200 because we need to print + out the data and read from the card at the same time! + +This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards +This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + +Check out the links above for our tutorials and wiring diagrams +These chips use SPI to communicate, 4 required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +*/ +/**************************************************************************/ + +#include + +#define SCK (2) +#define MOSI (3) +#define SS (4) +#define MISO (5) + +Adafruit_PN532 nfc(SCK, MISO, MOSI, SS); + +void setup(void) { + Serial.begin(115200); + Serial.println("Hello!"); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an ISO14443A card"); +} + + +void loop(void) { + boolean success; + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) + + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found + // 'uid' will be populated with the UID, and uidLength will indicate + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength); + + if (success) { + Serial.println("Found a card!"); + Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); + Serial.print("UID Value: "); + for (uint8_t i=0; i < uidLength; i++) + { + Serial.print(" 0x");Serial.print(uid[i], HEX); + } + Serial.println(""); + // Wait 1 second before continuing + delay(1000); + } +} diff --git a/brmdoor/AdafruitPN532/examples/mifareclassic_formatndef/mifareclassic_formatndef.pde b/brmdoor/AdafruitPN532/examples/mifareclassic_formatndef/mifareclassic_formatndef.pde new file mode 100644 index 0000000..f0ec9ec --- /dev/null +++ b/brmdoor/AdafruitPN532/examples/mifareclassic_formatndef/mifareclassic_formatndef.pde @@ -0,0 +1,164 @@ +/**************************************************************************/ +/*! + @file mifareclassic_formatndef.pde + @author Adafruit Industries + @license BSD (see license.txt) + + This example attempts to format a Mifare Classic + card for NDEF Records and writes an NDEF URI Record + + Note that you need the baud rate to be 115200 because we need to print + out the data and read from the card at the same time! + +This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards +This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + +Check out the links above for our tutorials and wiring diagrams +These chips use SPI to communicate, 4 required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! +*/ +/**************************************************************************/ + +#include + +#define SCK (2) +#define MOSI (3) +#define SS (4) +#define MISO (5) + +Adafruit_PN532 nfc(SCK, MISO, MOSI, SS); + +const char * url = "adafruit.com"; + +void setup(void) { + Serial.begin(115200); + Serial.println("Looking for PN532..."); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println(""); + Serial.println("PLEASE NOTE: Formatting your card for NDEF records will change the"); + Serial.println("authentication keys and you will no longer be able to read the"); + Serial.println("card as a normal Mifare card without resetting all keys. Try to keep"); + Serial.println("seperate cards for NDEF and non-NDEF purposes."); + Serial.println(""); + Serial.println("Place your Mifare Classic card on the reader to format with NDEF"); + Serial.println("and press any key to continue ..."); + // Wait for user input before proceeding + Serial.flush(); + while (!Serial.available()); + Serial.flush(); +} + +void loop(void) { + uint8_t success; // Flag to check if there was an error with the PN532 + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) + bool authenticated = false; // Flag to indicate if the sector is authenticated + + // Use the default key + uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + // Wait for an ISO14443A type card (Mifare, etc.). When one is found + // 'uid' will be populated with the UID, and uidLength will indicate + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); + + if (success) + { + // Display some basic information about the card + Serial.println("Found an ISO14443A card"); + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); + Serial.print(" UID Value: "); + nfc.PrintHex(uid, uidLength); + Serial.println(""); + + // Make sure this is a Mifare Classic card + if (uidLength != 4) + { + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); + return; + } + + // We probably have a Mifare Classic card ... + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); + + // Try to format the card for NDEF data + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 0, 0, keya); + if (!success) + { + Serial.println("Unable to authenticate block 0 to enable card formatting!"); + return; + } + success = nfc.mifareclassic_FormatNDEF(); + if (!success) + { + Serial.println("Unable to format the card for NDEF"); + return; + } + + Serial.println("Card has been formatted for NDEF data using MAD1"); + + // Try to authenticate block 4 (first block of sector 1) using our key + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keya); + + // Make sure the authentification process didn't fail + if (!success) + { + Serial.println("Authentication failed."); + return; + } + + // Try to write a URL + Serial.println("Writing URI to sector 1 as an NDEF Message"); + + // Authenticated seems to have worked + // Try to write an NDEF record to sector 1 + // Use 0x01 for the URI Identifier Code to prepend "http://www." + // to the url (and save some space). For information on URI ID Codes + // see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef + if (strlen(url) > 38) + { + // The length is also checked in the WriteNDEFURI function, but lets + // warn users here just in case they change the value and it's bigger + // than it should be + Serial.println("URI is too long ... must be less than 38 characters long"); + return; + } + + // URI is within size limits ... write it to the card and report success/failure + success = nfc.mifareclassic_WriteNDEFURI(1, NDEF_URIPREFIX_HTTP_WWWDOT, url); + if (success) + { + Serial.println("NDEF URI Record written to sector 1"); + } + else + { + Serial.println("NDEF Record creation failed! :("); + } + } + + // Wait a bit before trying again + Serial.println("\n\nDone!"); + Serial.flush(); + while (!Serial.available()); + Serial.flush(); +} diff --git a/brmdoor/AdafruitPN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde b/brmdoor/AdafruitPN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde new file mode 100644 index 0000000..5390c70 --- /dev/null +++ b/brmdoor/AdafruitPN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde @@ -0,0 +1,165 @@ +/**************************************************************************/ +/*! + @file mifareclassic_memdump.pde + @author Adafruit Industries + @license BSD (see license.txt) + + This example attempts to dump the contents of a Mifare Classic 1K card + + Note that you need the baud rate to be 115200 because we need to print + out the data and read from the card at the same time! + +This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards +This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + +Check out the links above for our tutorials and wiring diagrams +These chips use SPI to communicate, 4 required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +*/ +/**************************************************************************/ + +#include + +#define SCK (2) +#define MOSI (3) +#define SS (4) +#define MISO (5) + +Adafruit_PN532 nfc(SCK, MISO, MOSI, SS); + +void setup(void) { + // has to be fast to dump the entire memory contents! + Serial.begin(115200); + Serial.println("Looking for PN532..."); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an ISO14443A Card ..."); +} + + +void loop(void) { + uint8_t success; // Flag to check if there was an error with the PN532 + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) + uint8_t currentblock; // Counter to keep track of which block we're on + bool authenticated = false; // Flag to indicate if the sector is authenticated + uint8_t data[16]; // Array to store block data during reads + + // Use the default KEYA: FF FF FF FF FF FF + uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + uint8_t keyb[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + // uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 }; + // uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }; + + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found + // 'uid' will be populated with the UID, and uidLength will indicate + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); + + if (success) { + // Display some basic information about the card + Serial.println("Found an ISO14443A card"); + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); + Serial.print(" UID Value: "); + nfc.PrintHex(uid, uidLength); + Serial.println(""); + + if (uidLength == 4) + { + // We probably have a Mifare Classic card ... + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); + + // Now we try to go through all 16 sector (each having 4 blocks) + // authenticating each sector, and then dumping the blocks + for (currentblock = 0; currentblock < 64; currentblock++) + { + // Check if this is a new block so that we can reauthenticate + if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false; + + // If the sector hasn't been authenticated, do so first + if (!authenticated) + { + // Starting of a new sector ... try to to authenticate + Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------"); + if (currentblock == 0) + { + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 0, keya); + } + else + { + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 0, keyb); + } + if (success) + { + authenticated = true; + } + else + { + Serial.println("Authentication error"); + } + } + // If we're still not authenticated just skip the block + if (!authenticated) + { + Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate"); + } + else + { + // Authenticated ... we should be able to read the block now + // Dump the data into the 'data' array + success = nfc.mifareclassic_ReadDataBlock(currentblock, data); + if (success) + { + // Read successful + Serial.print("Block ");Serial.print(currentblock, DEC); + if (currentblock < 10) + { + Serial.print(" "); + } + else + { + Serial.print(" "); + } + // Dump the raw data + nfc.PrintHexChar(data, 16); + } + else + { + // Oops ... something happened + Serial.print("Block ");Serial.print(currentblock, DEC); + Serial.println(" unable to read this block"); + } + } + } + } + else + { + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); + } + } + // Wait a bit before trying again + Serial.println("\n\nSend a character to run the mem dumper again!"); + Serial.flush(); + while (!Serial.available()); + Serial.flush(); +} + diff --git a/brmdoor/AdafruitPN532/examples/readMifare/readMifare.pde b/brmdoor/AdafruitPN532/examples/readMifare/readMifare.pde new file mode 100644 index 0000000..720816b --- /dev/null +++ b/brmdoor/AdafruitPN532/examples/readMifare/readMifare.pde @@ -0,0 +1,162 @@ +/**************************************************************************/ +/*! + @file readMifare.pde + @author Adafruit Industries + @license BSD (see license.txt) + + This example will wait for any ISO14443A card or tag, and + depending on the size of the UID will attempt to read from it. + + If the card has a 4-byte UID it is probably a Mifare + Classic card, and the following steps are taken: + + - Authenticate block 4 (the first block of Sector 1) using + the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF + - If authentication succeeds, we can then read any of the + 4 blocks in that sector (though only block 4 is read here) + + If the card has a 7-byte UID it is probably a Mifare + Ultralight card, and the 4 byte pages can be read directly. + Page 4 is read by default since this is the first 'general- + purpose' page on the tags. + + +This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards +This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + +Check out the links above for our tutorials and wiring diagrams +These chips use SPI to communicate, 4 required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +*/ +/**************************************************************************/ + +#include + +#define SCK (2) +#define MOSI (3) +#define SS (4) +#define MISO (5) + +Adafruit_PN532 nfc(SCK, MISO, MOSI, SS); + +void setup(void) { + Serial.begin(9600); + Serial.println("Hello!"); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an ISO14443A Card ..."); +} + + +void loop(void) { + uint8_t success; + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) + + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found + // 'uid' will be populated with the UID, and uidLength will indicate + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); + + if (success) { + // Display some basic information about the card + Serial.println("Found an ISO14443A card"); + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); + Serial.print(" UID Value: "); + nfc.PrintHex(uid, uidLength); + Serial.println(""); + + if (uidLength == 4) + { + // We probably have a Mifare Classic card ... + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); + + // Now we need to try to authenticate it for read/write access + // Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + Serial.println("Trying to authenticate block 4 with default KEYA value"); + uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + // Start with block 4 (the first block of sector 1) since sector 0 + // contains the manufacturer data and it's probably better just + // to leave it alone unless you know what you're doing + success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya); + + if (success) + { + Serial.println("Sector 1 (Blocks 4..7) has been authenticated"); + uint8_t data[16]; + + // If you want to write something to block 4 to test with, uncomment + // the following line and this text should be read back in a minute + // data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0}; + // success = nfc.mifareclassic_WriteDataBlock (4, data); + + // Try to read the contents of block 4 + success = nfc.mifareclassic_ReadDataBlock(4, data); + + if (success) + { + // Data seems to have been read ... spit it out + Serial.println("Reading Block 4:"); + nfc.PrintHexChar(data, 16); + Serial.println(""); + + // Wait a bit before reading the card again + delay(1000); + } + else + { + Serial.println("Ooops ... unable to read the requested block. Try another key?"); + } + } + else + { + Serial.println("Ooops ... authentication failed: Try another key?"); + } + } + + if (uidLength == 7) + { + // We probably have a Mifare Ultralight card ... + Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)"); + + // Try to read the first general-purpose user page (#4) + Serial.println("Reading page 4"); + uint8_t data[32]; + success = nfc.mifareultralight_ReadPage (4, data); + if (success) + { + // Data seems to have been read ... spit it out + nfc.PrintHexChar(data, 4); + Serial.println(""); + + // Wait a bit before reading the card again + delay(1000); + } + else + { + Serial.println("Ooops ... unable to read the requested page!?"); + } + } + } +} + diff --git a/brmdoor/AdafruitPN532/examples/readMifareClassic/readMifareClassic.pde b/brmdoor/AdafruitPN532/examples/readMifareClassic/readMifareClassic.pde new file mode 100644 index 0000000..391cfcf --- /dev/null +++ b/brmdoor/AdafruitPN532/examples/readMifareClassic/readMifareClassic.pde @@ -0,0 +1,100 @@ +/**************************************************************************/ +/*! + @file readMifareClassic.pde + @author Adafruit Industries + @license BSD (see license.txt) + + This example will wait for any ISO14443A card or tag, and + depending on the size of the UID will attempt to read from it. + + If the card has a 4-byte UID it is probably a Mifare + Classic card, and the following steps are taken: + + Reads the 4 byte (32 bit) ID of a MiFare Classic card. + Since the classic cards have only 32 bit identifiers you can stick + them in a single variable and use that to compare card ID's as a + number. This doesn't work for ultralight cards that have longer 7 + byte IDs! + + Note that you need the baud rate to be 115200 because we need to + print out the data and read from the card at the same time! + +This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards +This library works with the Adafruit NFC breakout + ----> https://www.adafruit.com/products/364 + +Check out the links above for our tutorials and wiring diagrams +These chips use SPI to communicate, 4 required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! +*/ +/**************************************************************************/ + +#include + +#define SCK (2) +#define MOSI (3) +#define SS (4) +#define MISO (5) + +Adafruit_PN532 nfc(SCK, MISO, MOSI, SS); + +void setup(void) { + Serial.begin(115200); + Serial.println("Hello!"); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an ISO14443A Card ..."); +} + + +void loop(void) { + uint8_t success; + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) + + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found + // 'uid' will be populated with the UID, and uidLength will indicate + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); + + if (success) { + // Display some basic information about the card + Serial.println("Found an ISO14443A card"); + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); + Serial.print(" UID Value: "); + nfc.PrintHex(uid, uidLength); + + if (uidLength == 4) + { + // We probably have a Mifare Classic card ... + uint32_t cardid = uid[0]; + cardid <<= 8; + cardid |= uid[1]; + cardid <<= 8; + cardid |= uid[2]; + cardid <<= 8; + cardid |= uid[3]; + Serial.print("Seems to be a Mifare Classic card #"); + Serial.println(cardid); + } + Serial.println(""); + } +} + diff --git a/brmdoor/Makefile b/brmdoor/Makefile index a4439cd..453e1dd 100644 --- a/brmdoor/Makefile +++ b/brmdoor/Makefile @@ -5,6 +5,6 @@ ARDUINO_PORT = /dev/ttyUSB0 TARGET = brmdoor -ARDUINO_LIBS = SoftwareSerial +ARDUINO_LIBS = SoftwareSerial AdafruitPN532 include /usr/share/arduino/Arduino.mk diff --git a/brmdoor/brmdoor.ino b/brmdoor/brmdoor.ino index 0195886..f792907 100644 --- a/brmdoor/brmdoor.ino +++ b/brmdoor/brmdoor.ino @@ -3,6 +3,8 @@ #define MUSIC 1 #include +#include + // pins const int magnetPin = 10; const int soundPin = 9; /* piezo in series with 100R */ @@ -14,24 +16,101 @@ const int doorLock = 4; const int rfidRx = 3; const int rfidTx = 2; +// Pins where Adafruit PN532 shield is connected. +// Note that these are the analog pins used in digital mode - no other pins +// were available. +const int PN532_SCK = A3; +const int PN532_MOSI = A2; +const int PN532_SS = A1; +const int PN532_MISO = A0; + +// Set to true if you want to have correct UID printed in hex after CARD +// message into UART (case when card is known). +bool printFullUID = true; + +// If set to true, will add string "proper" after the CARD message to signify +// that the UID was found in the proper ACL list. +bool printProper = true; + +// Max retries to read card before timeout, 200 is around 1 second, 0xFF means +// wait forever (constitutes blocking read). +uint8_t pn532MaxRetries = 200; +bool pn532Working; //whether we have connected and working chip + int statusState = 0, statusStateOverride = 0; int videoState = 0, videoStateOverride = 0; -// cardId is the same as you can see in CARD telnet message -struct ACLdata { - byte cardId[7]; - char *nick; -} ACL[] = { -// the following include file contains lines like -// { {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE}, "username" }, +/*! + * The cardId is the same as you can see in CARD telnet message + * + * It's called broken, because we had broken reader that couldn't read 7-byte IDs. + * I.e. the old reader could only use SELECT cascade 1, which begins with 0x88 + * cascading tag, thus we have only 3 bytes from 7-byte UIDs. + * + * So if we get a 7-byte ID, we must do "retarded search" for the 3-byte part. + * If an ID in this struct contains 0x88 as third byte (index 2), it means it's + * a card with 7 or 10 byte UID and begins with a cascading tag 0x88. + * + * Currently the bytes seem to be: + * + * case of 4-byte UID: 0x00, 0x00, UID1, UID2, UID3, UID4, BCC + * case of 7-byte UID: 0xFF, 0x00, 0x88, UID1, UID2, UID3, BCC + * case of 10-byte UID: ??? I don't think I actually saw a real card with + * 10-byte UID, but it's in the NXP specs + * + */ +typedef struct ACLdataBroken { + byte cardId[7]; + const char *nick; +} ACLRecordBroken; + +/*! + * List of ACLs included from a static array, see ACLRecordBroken for details. + */ +ACLRecordBroken ACL[] = { +/* The following include file contains lines like + * { {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE}, "username" }, + */ #include "cardids.h" }; +/*! Structure for correct card UIDs */ +typedef struct ACLdataProper { + uint8_t uidLength; + uint8_t uid[10]; + const char *nick; +} ACLRecordProper; + +/*! + * List of ACLs with proper full card's UID, included from another file. + * + * Keep the last element of array having uidLength of 0 last, it's a + * terminator (so that we don't have to do sizeof arithmetic and guesstimating + * whether aliasing will break it or not). + */ +ACLRecordProper ACLproper[] = { +/* The following include file contains lines like + * { 4, {0x35, 0xb0, 0x18, 0xd4}, "mifare_1" }, + * { 7, {0x04, 0xc2 0x4c, 0xe9, 0xad, 0x27, 0x80}, "ultralight_c" }, + * + * Format of each array item is { UID_length, { UID_bytes }, nickname } + */ +#include "cardids_proper.h" + { 0, {0x00}, "terminator, don't delete this element!" } +}; + +// Let's hope aliasing won't break this. +// OMG why not some proper structures? +#define ACL_COUNT (sizeof(ACL)/sizeof(ACLRecordBroken)) + +// ISO14443 cascading tag +#define CASCADING_TAG 0x88 + // comSerial for communication with the host #define comSerial Serial -// rfidSerial for communication with the RFID reader -SoftwareSerial rfidSerial(rfidTx, rfidRx); +// PN532 chip instance +Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS); #if MUSIC @@ -101,64 +180,163 @@ void openDoorForTime(int ms) digitalWrite(doorLock, LOW); } -void readCard() +/*! + * Will search for given card UID in the borken ACL list with truncated UIDs. + * + * @param uid UID of the card read + * @param length length of the UID in bytes + * @param acls list of ACLs in the old b0rken form + * @param count of ACLs in the above array + * @returns index into acls if found or -1 if not found + */ +int retardedACLSearch(const uint8_t *uid, uint8_t length, const struct ACLdataBroken *acls, int aclCount) +{ + int idx = -1; + + for(int i=0; i= 0) { + proper = true; + } else { + // search for card UID in b0rken ACL database + aclIdx = retardedACLSearch(uid, uidLength, ACL, ACL_COUNT); + } + + if (aclIdx < 0) { + // unknown card ID + comSerial.write("CARD UNKNOWN "); + serialWriteUIDHex(uid, uidLength); + comSerial.write("\n"); + playMelodyNak(); + delay(750); + return false; + } + + // OK we got some known card, print its nick from respective ACL array + comSerial.write("CARD "); + comSerial.write(proper ? ACLproper[aclIdx].nick : ACL[aclIdx].nick); + + if (printFullUID) { + comSerial.write(" "); + serialWriteUIDHex(uid, uidLength); + } + + // for debugging purposes - to know that we got the UID from proper ACL list + if (printProper && proper) { + comSerial.write(" proper"); + } + + comSerial.write("\n"); + + openDoorForTime(5000); + + return true; +} + +/*! Set status led according to status, delat a bit. */ +void statusUpdate() { - byte RequestCardStatus[] = { 0xAA, 0x00, 0x03, 0x25, 0x26, 0x00, 0x00, 0xBB }; - byte NoCardResponse[] = { 0xAA, 0x00, 0x02, 0x01, 0x83, 0x80, 0xBB }; - byte buf[16]; - int i; - rfidSerial.listen(); - // write query to serial - for (i = 0; i < 8; i++) - rfidSerial.write((uint8_t)RequestCardStatus[i]); - // wait for the result, while reblinking delay(100); digitalWrite(statusLed, statusState); delay(150); - - // read input from serial into the buffer - i = 0; - while (rfidSerial.available() > 0) { - if (i < sizeof(buf)) { - buf[i] = rfidSerial.read(); - } - ++i; - } - // no card is detected - if (!memcmp(buf, NoCardResponse, 7)) { - comSerial.write("NOCARD\n"); - } - - // card detected - message has form AA0006xxxxxxxxxxxxxxBB where xxx... is the card ID - if (buf[0] == 0xAA && buf[1] == 0x00 && buf[2] == 0x06 && buf[10] == 0xBB) { - bool known = false; - // go through ACL - for (int i = 0; i < sizeof(ACL)/sizeof(ACL[0]); ++i) { - // if there is a match - print known card ... - if (!memcmp(ACL[i].cardId, buf+3, 7)) { - known = true; - comSerial.write("CARD "); - comSerial.write(ACL[i].nick); - comSerial.write("\n"); - // ... and open door for 5s - openDoorForTime(5000); - break; - } - } - // card was not found in the ACL - if (!known) { - comSerial.write("CARD UNKNOWN "); - for (int i = 0; i < 7; ++i) { - if (buf[i+3] <= 0xF) comSerial.write("0"); - comSerial.print(buf[i+3], HEX); - } - comSerial.write("\n"); - playMelodyNak(); - } - } else { - // make cycle interval 1s - delay(750); - } } void readSerial() @@ -187,7 +365,17 @@ void setup() pinMode(videoBtn, INPUT); digitalWrite(videoBtn, HIGH); comSerial.begin(9600); - rfidSerial.begin(9600); + + nfc.begin(); + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + comSerial.write("CARD READER BROKEN\n"); + pn532Working = false; + } else { + nfc.SAMConfig(); + nfc.setPassiveActivationRetries(pn532MaxRetries); + pn532Working = true; + } } void loop() @@ -204,11 +392,16 @@ void loop() int doorOpen = digitalRead(magnetPin); - digitalWrite(statusLed, !statusState); // will be turned back in readCard() + digitalWrite(statusLed, !statusState); digitalWrite(videoLed, videoState); + comSerial.print(statusState, DEC); comSerial.write(" "); comSerial.print(videoState, DEC); comSerial.write(" "); comSerial.print(doorOpen, DEC); comSerial.write(" "); - readCard(); + + statusUpdate(); + + readCardPN532(); readSerial(); } + diff --git a/brmdoor/cardids.h.sample b/brmdoor/cardids.h.sample new file mode 100644 index 0000000..4d1ca52 --- /dev/null +++ b/brmdoor/cardids.h.sample @@ -0,0 +1,5 @@ + { {0x00, 0x00, 0xDE, 0xEC, 0xE6, 0x3E, 0xEA}, "holland_chipkaart" }, + { {0xFF, 0x00, 0x88, 0x04, 0x63, 0x19, 0xF6}, "desfire_3" }, //0x04, 0x63, 0x19, 0x82, 0xcc, 0x22, 0x80 + { {0x00, 0x00, 0x35, 0xb0, 0x18, 0xd4, 0x49}, "mifare_1" }, + { {0xFF, 0x00, 0x88, 0x04, 0xc2, 0x4c, 0x02}, "ultralight" } //04c24ce9ad2780 + diff --git a/brmdoor/cardids_proper.h.sample b/brmdoor/cardids_proper.h.sample new file mode 100644 index 0000000..3b9b54c --- /dev/null +++ b/brmdoor/cardids_proper.h.sample @@ -0,0 +1,5 @@ + // Format of each array item is { UID_length, { UID_bytes }, nickname } + // See definition of struct ACLdataProper in brmdoor.ino + { 4, {0x35, 0xb0, 0x18, 0xd4}, "mifare_1_proper" }, + { 7, {0x04, 0xc2, 0x4c, 0xe9, 0xad, 0x27, 0x80}, "ultralight_proper" }, //04c24ce9ad2780 +