├── doc ├── PN5180-NFC.png ├── FritzingLayout.jpg └── PN5180 R1.1-170710_SCH.PDF ├── library.properties ├── library.json ├── Debug.h ├── PN5180FeliCa.h ├── README.md ├── PN5180ISO14443.h ├── Debug.cpp ├── keywords.txt ├── PN5180iClass.h ├── PN5180ISO15693.h ├── PN5180FeliCa.cpp ├── PN5180.h ├── examples ├── PN5180-FeliCa │ └── PN5180-FeliCa.ino └── PN5180-Library │ └── PN5180-Library.ino ├── PN5180ISO14443.cpp ├── PN5180iClass.cpp ├── PN5180.cpp ├── PN5180ISO15693.cpp └── LICENSE /doc/PN5180-NFC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATrappmann/PN5180-Library/HEAD/doc/PN5180-NFC.png -------------------------------------------------------------------------------- /doc/FritzingLayout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATrappmann/PN5180-Library/HEAD/doc/FritzingLayout.jpg -------------------------------------------------------------------------------- /doc/PN5180 R1.1-170710_SCH.PDF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATrappmann/PN5180-Library/HEAD/doc/PN5180 R1.1-170710_SCH.PDF -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=PN5180 Library 2 | version=1.8.1 3 | author=Andreas Trappmann 4 | maintainer=Andreas Trappmann 5 | sentence=NXP NFC PN5180 Library for Arduino 6 | paragraph=NXP NFC PN5180 Library 7 | category=Sensors 8 | url=https://github.com/ATrappmann/PN5180-Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PN5180-Library", 3 | "frameworks": "Arduino", 4 | "keywords": "NXP NFC PN5180", 5 | "description": "NXP NFC PN5180 Library for Arduino", 6 | "authors": 7 | [ 8 | { 9 | "name": "Andreas Trappmann", 10 | "email": "andreas.trappmann@t-online.de", 11 | "url": "https://github.com/ATrappmann/PN5180-Library", 12 | "maintainer": true 13 | } 14 | ], 15 | "repository": 16 | { 17 | "type": "git", 18 | "url": "https://github.com/ATrappmann/PN5180-Library" 19 | } 20 | } -------------------------------------------------------------------------------- /Debug.h: -------------------------------------------------------------------------------- 1 | // NAME: Debug.h 2 | // 3 | // DESC: Helper methods for debugging 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef DEBUG_H 20 | #define DEBUG_H 21 | 22 | #ifdef DEBUG 23 | #define PN5180DEBUG(msg) Serial.print(msg) 24 | #else 25 | #define PN5180DEBUG(msg) 26 | #endif 27 | 28 | #ifdef DEBUG 29 | extern char * formatHex(const uint8_t val); 30 | extern char * formatHex(const uint16_t val); 31 | extern char * formatHex(const uint32_t val); 32 | #endif 33 | 34 | #endif /* DEBUG_H */ 35 | -------------------------------------------------------------------------------- /PN5180FeliCa.h: -------------------------------------------------------------------------------- 1 | // NAME: PN5180FeliCa.h 2 | // 3 | // DESC: FeliCa protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2020 by CrazyRedMachine. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef PN5180FeliCa_H 20 | #define PN5180FeliCa_H 21 | 22 | #include "PN5180.h" 23 | 24 | class PN5180FeliCa : public PN5180 { 25 | 26 | public: 27 | PN5180FeliCa(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); 28 | 29 | public: 30 | uint8_t pol_req(uint8_t *buffer); 31 | /* 32 | * Helper functions 33 | */ 34 | public: 35 | bool setupRF(); 36 | uint8_t readCardSerial(uint8_t *buffer); 37 | bool isCardPresent(); 38 | }; 39 | 40 | #endif /* PN5180FeliCa_H */ 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PN5180-Library 2 | 3 | Arduino Uno / Arduino ESP-32 library for PN5180-NFC Module from NXP Semiconductors 4 | 5 | ![PN5180-NFC module](./doc/PN5180-NFC.png) 6 | ![PN5180 Schematics](./doc/FritzingLayout.jpg) 7 | 8 | Release Notes: 9 | 10 | Version 1.8.1 - 19.08.2021 11 | 12 | * Added changes from Nettermann90 13 | 14 | Version 1.7 - 12.07.2021 15 | 16 | * Migrated branch from Dirk Carstensen for ISO14443 tags to the library. 17 | * See https://github.com/tueddy/PN5180-Library/tree/ISO14443 18 | 19 | Version 1.6 - 13.03.2021 20 | 21 | * Added PN5180::writeEEPROM 22 | 23 | Version 1.5 - 29.01.2020 24 | 25 | * Fixed offset in readSingleBlock. Was off by 1. 26 | 27 | Version 1.4 - 13.11.2019 28 | 29 | * ICODE SLIX2 specific commands, see https://www.nxp.com/docs/en/data-sheet/SL2S2602.pdf 30 | * Example usage, currently outcommented 31 | 32 | Version 1.3 - 21.05.2019 33 | 34 | * Initialized Reset pin with HIGH 35 | * Made readBuffer static 36 | * Typo fixes 37 | * Data type corrections for length parameters 38 | 39 | Version 1.2 - 28.01.2019 40 | 41 | * Cleared Option bit in PN5180ISO15693::readSingleBlock and ::writeSingleBlock 42 | 43 | Version 1.1 - 26.10.2018 44 | 45 | * Cleanup, bug fixing, refactoring 46 | * Automatic check for Arduino vs. ESP-32 platform via compiler switches 47 | * Added open pull requests 48 | * Working on documentation 49 | 50 | Version 1.0.x - 21.09.2018 51 | 52 | * Initial versions 53 | -------------------------------------------------------------------------------- /PN5180ISO14443.h: -------------------------------------------------------------------------------- 1 | // NAME: PN5180ISO14443.h 2 | // 3 | // DESC: ISO14443 protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2019 by Dirk Carstensen. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef PN5180ISO14443_H 20 | #define PN5180ISO14443_H 21 | 22 | #include "PN5180.h" 23 | 24 | class PN5180ISO14443 : public PN5180 { 25 | 26 | public: 27 | PN5180ISO14443(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); 28 | 29 | private: 30 | uint16_t rxBytesReceived(); 31 | public: 32 | // Mifare TypeA 33 | uint8_t activateTypeA(uint8_t *buffer, uint8_t kind); 34 | bool mifareBlockRead(uint8_t blockno,uint8_t *buffer); 35 | uint8_t mifareBlockWrite16(uint8_t blockno, uint8_t *buffer); 36 | bool mifareHalt(); 37 | /* 38 | * Helper functions 39 | */ 40 | public: 41 | bool setupRF(); 42 | uint8_t readCardSerial(uint8_t *buffer); 43 | bool isCardPresent(); 44 | }; 45 | 46 | #endif /* PN5180ISO14443_H */ 47 | -------------------------------------------------------------------------------- /Debug.cpp: -------------------------------------------------------------------------------- 1 | // NAME: Debug.cpp 2 | // 3 | // DESC: Helper functions for debugging 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #include 20 | #include "Debug.h" 21 | 22 | #ifdef DEBUG 23 | 24 | static const char hexChar[] = "0123456789ABCDEF"; 25 | static char hexBuffer[9]; 26 | 27 | char * formatHex(const uint8_t val) { 28 | hexBuffer[0] = hexChar[val >> 4]; 29 | hexBuffer[1] = hexChar[val & 0x0f]; 30 | hexBuffer[2] = '\0'; 31 | return hexBuffer; 32 | } 33 | 34 | char * formatHex(const uint16_t val) { 35 | hexBuffer[0] = hexChar[(val >> 12) & 0x0f]; 36 | hexBuffer[1] = hexChar[(val >> 8) & 0x0f]; 37 | hexBuffer[2] = hexChar[(val >> 4) & 0x0f]; 38 | hexBuffer[3] = hexChar[val & 0x0f]; 39 | hexBuffer[4] = '\0'; 40 | return hexBuffer; 41 | } 42 | 43 | char * formatHex(uint32_t val) { 44 | for (int i=7; i>=0; i--) { 45 | hexBuffer[i] = hexChar[val & 0x0f]; 46 | val = val >> 4; 47 | } 48 | hexBuffer[8] = '\0'; 49 | return hexBuffer; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For PN5180-Library 3 | ####################################### 4 | # Class 5 | ####################################### 6 | 7 | PN5180 KEYWORD1 8 | PN5180ISO15693 KEYWORD1 9 | PN5180ISO14443 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions 13 | ####################################### 14 | 15 | writeRegister KEYWORD2 16 | writeRegisterWithOrMask KEYWORD2 17 | writeRegisterWithAndMask KEYWORD2 18 | readRegister KEYWORD2 19 | readEprom KEYWORD2 20 | sendData KEYWORD2 21 | readData KEYWORD2 22 | loadRFConfig KEYWORD2 23 | setRF_on KEYWORD2 24 | setRF_off KEYWORD2 25 | getIRQStatus KEYWORD2 26 | getTransceiveState KEYWORD2 27 | transceiveCommand KEYWORD2 28 | 29 | issueISO15693Command KEYWORD2 30 | getInventory KEYWORD2 31 | readSingleBlock KEYWORD2 32 | writeSingleBlock KEYWORD2 33 | getSystemInfo KEYWORD2 34 | setupRF KEYWORD2 35 | 36 | ####################################### 37 | # Constants 38 | ####################################### 39 | 40 | PN5180_NSS LITERAL1 41 | PN5180_BUSY LITERAL1 42 | PN5180_RST LITERAL1 43 | 44 | PN5180_SPI_SETTINGS LITERAL1 45 | 46 | PN5180TransceiveStat LITERAL1 47 | PN5180_TS_Idle LITERAL1 48 | PN5180_TS_WaitTransmit LITERAL1 49 | PN5180_TS_Transmitting LITERAL1 50 | PN5180_TS_WaitReceive LITERAL1 51 | PN5180_TS_WaitForData LITERAL1 52 | PN5180_TS_Receiving LITERAL1 53 | PN5180_TS_LoopBack LITERAL1 54 | PN5180_TS_RESERVED LITERAL1 55 | 56 | SYSTEM_CONFIG LITERAL1 57 | IRQ_ENABLE LITERAL1 58 | IRQ_STATUS LITERAL1 59 | IRQ_CLEAR LITERAL1 60 | TRANSCEIVE_CONTROL LITERAL1 61 | TIMER1_RELOAD LITERAL1 62 | TIMER1_CONFIG LITERAL1 63 | RX_WAIT_CONFIG LITERAL1 64 | CRC_RX_CONFIG LITERAL1 65 | RX_STATUS LITERAL1 66 | RF_STATUS LITERAL1 67 | SYSTEM_STATUS LITERAL1 68 | TEMP_CONTROL LITERAL1 69 | 70 | DIE_IDENTIFIER LITERAL1 71 | PRODUCT_VERSION LITERAL1 72 | FIRMWARE_VERSION LITERAL1 73 | EEPROM_VERSION LITERAL1 74 | IRQ_PIN_CONFIG LITERAL1 75 | -------------------------------------------------------------------------------- /PN5180iClass.h: -------------------------------------------------------------------------------- 1 | // NAME: PN5180iClass.h 2 | // 3 | // DESC: iClass protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef PN5180ICLASS_H 20 | #define PN5180ICLASS_H 21 | 22 | #include "PN5180.h" 23 | 24 | enum { 25 | ICLASS_CMD_HALT = 0x00, 26 | ICLASS_CMD_ACTALL = 0x0A, 27 | ICLASS_CMD_IDENTIFY = 0x0C, 28 | ICLASS_CMD_SELECT = 0x81, 29 | ICLASS_CMD_READCHECK = 0x88, 30 | ICLASS_CMD_CHECK = 0x05, 31 | ICLASS_CMD_READ = 0x0C, 32 | }; 33 | 34 | enum iClassErrorCode { 35 | EC_NO_CARD = -1, 36 | ICLASS_EC_OK = 0, 37 | ICLASS_EC_UNKNOWN_ERROR = 0xFE, 38 | }; 39 | 40 | class PN5180iClass : public PN5180 { 41 | 42 | public: 43 | PN5180iClass(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); 44 | 45 | private: 46 | iClassErrorCode issueiClassCommand(uint8_t *cmd, uint8_t cmdLen, uint8_t **resultPtr); 47 | public: 48 | iClassErrorCode ActivateAll(); 49 | iClassErrorCode Identify(uint8_t *csn); 50 | iClassErrorCode Select(uint8_t *csn); 51 | iClassErrorCode ReadCheck(uint8_t *ccnr); 52 | iClassErrorCode Check(uint8_t *mac); 53 | iClassErrorCode Read(uint8_t blockNum, uint8_t *blockData); 54 | iClassErrorCode Halt(); 55 | 56 | /* 57 | * Helper functions 58 | */ 59 | public: 60 | bool setupRF(); 61 | const __FlashStringHelper *strerror(iClassErrorCode errno); 62 | 63 | }; 64 | 65 | #endif /* PN5180ICLASS_H */ 66 | -------------------------------------------------------------------------------- /PN5180ISO15693.h: -------------------------------------------------------------------------------- 1 | // NAME: PN5180ISO15693.h 2 | // 3 | // DESC: ISO15693 protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef PN5180ISO15693_H 20 | #define PN5180ISO15693_H 21 | 22 | #include "PN5180.h" 23 | 24 | enum ISO15693ErrorCode { 25 | EC_NO_CARD = -1, 26 | ISO15693_EC_OK = 0, 27 | ISO15693_EC_NOT_SUPPORTED = 0x01, 28 | ISO15693_EC_NOT_RECOGNIZED = 0x02, 29 | ISO15693_EC_OPTION_NOT_SUPPORTED = 0x03, 30 | ISO15693_EC_UNKNOWN_ERROR = 0x0f, 31 | ISO15693_EC_BLOCK_NOT_AVAILABLE = 0x10, 32 | ISO15693_EC_BLOCK_ALREADY_LOCKED = 0x11, 33 | ISO15693_EC_BLOCK_IS_LOCKED = 0x12, 34 | ISO15693_EC_BLOCK_NOT_PROGRAMMED = 0x13, 35 | ISO15693_EC_BLOCK_NOT_LOCKED = 0x14, 36 | ISO15693_EC_CUSTOM_CMD_ERROR = 0xA0 37 | }; 38 | 39 | class PN5180ISO15693 : public PN5180 { 40 | 41 | public: 42 | PN5180ISO15693(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); 43 | 44 | private: 45 | ISO15693ErrorCode issueISO15693Command(uint8_t *cmd, uint8_t cmdLen, uint8_t **resultPtr); 46 | public: 47 | ISO15693ErrorCode getInventory(uint8_t *uid); 48 | 49 | ISO15693ErrorCode readSingleBlock(uint8_t *uid, uint8_t blockNo, uint8_t *blockData, uint8_t blockSize); 50 | ISO15693ErrorCode writeSingleBlock(uint8_t *uid, uint8_t blockNo, uint8_t *blockData, uint8_t blockSize); 51 | 52 | ISO15693ErrorCode getSystemInfo(uint8_t *uid, uint8_t *blockSize, uint8_t *numBlocks); 53 | 54 | // ICODE SLIX2 specific commands, see https://www.nxp.com/docs/en/data-sheet/SL2S2602.pdf 55 | ISO15693ErrorCode getRandomNumber(uint8_t *randomData); 56 | ISO15693ErrorCode setPassword(uint8_t *password, uint8_t *random); 57 | ISO15693ErrorCode writePassword(uint8_t *password, uint8_t *uid); 58 | ISO15693ErrorCode enablePrivacy(uint8_t *password, uint8_t *random); 59 | ISO15693ErrorCode unlockICODESLIX2(uint8_t *password); 60 | ISO15693ErrorCode lockICODESLIX2(uint8_t *password); 61 | ISO15693ErrorCode newpasswordICODESLIX2(uint8_t *newpassword, uint8_t *oldpassword, uint8_t *uid); 62 | /* 63 | * Helper functions 64 | */ 65 | public: 66 | bool setupRF(); 67 | const __FlashStringHelper *strerror(ISO15693ErrorCode errno); 68 | 69 | }; 70 | 71 | #endif /* PN5180ISO15693_H */ 72 | -------------------------------------------------------------------------------- /PN5180FeliCa.cpp: -------------------------------------------------------------------------------- 1 | // NAME: PN5180FeliCa.h 2 | // 3 | // DESC: FeliCa protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2020 by CrazyRedMachine. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | //#define DEBUG 1 20 | 21 | #include 22 | #include "PN5180FeliCa.h" 23 | #include 24 | #include "Debug.h" 25 | 26 | PN5180FeliCa::PN5180FeliCa(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) 27 | : PN5180(SSpin, BUSYpin, RSTpin) { 28 | } 29 | 30 | bool PN5180FeliCa::setupRF() { 31 | PN5180DEBUG(F("Loading RF-Configuration...\n")); 32 | if (loadRFConfig(0x09, 0x89)) { // FeliCa 424 parameters 33 | PN5180DEBUG(F("done.\n")); 34 | } 35 | else return false; 36 | 37 | PN5180DEBUG(F("Turning ON RF field...\n")); 38 | if (setRF_on()) { 39 | PN5180DEBUG(F("done.\n")); 40 | } 41 | else return false; 42 | 43 | return true; 44 | } 45 | 46 | /* 47 | * buffer : must be 20 byte array 48 | * buffer[0-1] is length and 01 49 | * buffer[2..9] is IDm 50 | * buffer[10..17] is PMm. 51 | * buffer[18..19] is POL_RES data 52 | * 53 | * return value: the uid length in bytes: 54 | * - zero if no tag was recognized 55 | * - 8 if a FeliCa tag was recognized 56 | */ 57 | uint8_t PN5180FeliCa::pol_req(uint8_t *buffer) { 58 | uint8_t cmd[6]; 59 | uint8_t uidLength = 0; 60 | // Load FeliCa 424 protocol 61 | if (!loadRFConfig(0x09, 0x89)) 62 | return 0; 63 | // OFF Crypto 64 | if (!writeRegisterWithAndMask(SYSTEM_CONFIG, 0xFFFFFFBF)) 65 | return 0; 66 | 67 | //send FeliCa request (every packet starts with length) 68 | cmd[0] = 0x06; //total length 69 | cmd[1] = 0x00; //POL_REQ command 70 | cmd[2] = 0xFF; // 71 | cmd[3] = 0xFF; // any target 72 | cmd[4] = 0x01; // System Code request 73 | cmd[5] = 0x00; // 1 timeslot only 74 | 75 | if (!sendData(cmd, 6, 0x00)) 76 | return 0; 77 | //wait a little to avoid bug with some cards 78 | delay(50); 79 | 80 | //response packet should be 0x14 (20 bytes total length), 0x01 Response Code, 8 IDm bytes, 8 PMm bytes, 2 Request Data bytes 81 | //READ 20 bytes reply 82 | uint8_t *internalBuffer = readData(20); 83 | if (!internalBuffer) 84 | return 0; 85 | for (int i=0; i<20; i++) { 86 | buffer[i] = internalBuffer[i]; 87 | } 88 | 89 | //check Response Code 90 | if ( buffer[1] != 0x01 ){ 91 | uidLength = 0; 92 | } else { 93 | uidLength = 8; 94 | } 95 | return uidLength; 96 | } 97 | 98 | uint8_t PN5180FeliCa::readCardSerial(uint8_t *buffer) { 99 | 100 | uint8_t response[20]; 101 | uint8_t uidLength; 102 | 103 | for (int i = 0; i < 20; i++) 104 | response[i] = 0; 105 | 106 | uidLength = pol_req(response); 107 | 108 | // no reply 109 | if (uidLength == 0) 110 | return 0; 111 | 112 | for (int i = 0; i < uidLength; i++) 113 | buffer[i] = response[i+2]; 114 | 115 | return uidLength; 116 | } 117 | 118 | bool PN5180FeliCa::isCardPresent() { 119 | uint8_t buffer[8]; 120 | return (readCardSerial(buffer) != 0); 121 | } 122 | -------------------------------------------------------------------------------- /PN5180.h: -------------------------------------------------------------------------------- 1 | // NAME: PN5180.h 2 | // 3 | // DESC: NFC Communication with NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | #ifndef PN5180_H 20 | #define PN5180_H 21 | 22 | #include 23 | 24 | // PN5180 Registers 25 | #define SYSTEM_CONFIG (0x00) 26 | #define IRQ_ENABLE (0x01) 27 | #define IRQ_STATUS (0x02) 28 | #define IRQ_CLEAR (0x03) 29 | #define TRANSCEIVE_CONTROL (0x04) 30 | #define TIMER1_RELOAD (0x0c) 31 | #define TIMER1_CONFIG (0x0f) 32 | #define RX_WAIT_CONFIG (0x11) 33 | #define CRC_RX_CONFIG (0x12) 34 | #define RX_STATUS (0x13) 35 | #define CRC_TX_CONFIG (0x19) 36 | #define RF_STATUS (0x1d) 37 | #define SYSTEM_STATUS (0x24) 38 | #define TEMP_CONTROL (0x25) 39 | 40 | // PN5180 EEPROM Addresses 41 | #define DIE_IDENTIFIER (0x00) 42 | #define PRODUCT_VERSION (0x10) 43 | #define FIRMWARE_VERSION (0x12) 44 | #define EEPROM_VERSION (0x14) 45 | #define IRQ_PIN_CONFIG (0x1A) 46 | 47 | enum PN5180TransceiveStat { 48 | PN5180_TS_Idle = 0, 49 | PN5180_TS_WaitTransmit = 1, 50 | PN5180_TS_Transmitting = 2, 51 | PN5180_TS_WaitReceive = 3, 52 | PN5180_TS_WaitForData = 4, 53 | PN5180_TS_Receiving = 5, 54 | PN5180_TS_LoopBack = 6, 55 | PN5180_TS_RESERVED = 7 56 | }; 57 | 58 | // PN5180 IRQ_STATUS 59 | #define RX_IRQ_STAT (1<<0) // End of RF rececption IRQ 60 | #define TX_IRQ_STAT (1<<1) // End of RF transmission IRQ 61 | #define IDLE_IRQ_STAT (1<<2) // IDLE IRQ 62 | #define RFOFF_DET_IRQ_STAT (1<<6) // RF Field OFF detection IRQ 63 | #define RFON_DET_IRQ_STAT (1<<7) // RF Field ON detection IRQ 64 | #define TX_RFOFF_IRQ_STAT (1<<8) // RF Field OFF in PCD IRQ 65 | #define TX_RFON_IRQ_STAT (1<<9) // RF Field ON in PCD IRQ 66 | #define RX_SOF_DET_IRQ_STAT (1<<14) // RF SOF Detection IRQ 67 | 68 | class PN5180 { 69 | private: 70 | uint8_t PN5180_NSS; // active low 71 | uint8_t PN5180_BUSY; 72 | uint8_t PN5180_RST; 73 | 74 | SPISettings PN5180_SPI_SETTINGS; 75 | static uint8_t readBuffer[508]; 76 | 77 | public: 78 | PN5180(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); 79 | 80 | void begin(); 81 | void end(); 82 | 83 | /* 84 | * PN5180 direct commands with host interface 85 | */ 86 | public: 87 | /* cmd 0x00 */ 88 | bool writeRegister(uint8_t reg, uint32_t value); 89 | /* cmd 0x01 */ 90 | bool writeRegisterWithOrMask(uint8_t addr, uint32_t mask); 91 | /* cmd 0x02 */ 92 | bool writeRegisterWithAndMask(uint8_t addr, uint32_t mask); 93 | 94 | /* cmd 0x04 */ 95 | bool readRegister(uint8_t reg, uint32_t *value); 96 | 97 | /* cmd 0x06 */ 98 | bool writeEEPROM(uint8_t addr, uint8_t *data, int len); 99 | 100 | /* cmd 0x07 */ 101 | bool readEEprom(uint8_t addr, uint8_t *buffer, int len); 102 | 103 | /* cmd 0x09 */ 104 | bool sendData(uint8_t *data, int len, uint8_t validBits = 0); 105 | /* cmd 0x0a */ 106 | uint8_t * readData(int len, uint8_t *buffer = NULL); 107 | 108 | /* cmd 0x11 */ 109 | bool loadRFConfig(uint8_t txConf, uint8_t rxConf); 110 | 111 | /* cmd 0x16 */ 112 | bool setRF_on(); 113 | /* cmd 0x17 */ 114 | bool setRF_off(); 115 | 116 | /* 117 | * Helper functions 118 | */ 119 | public: 120 | void reset(); 121 | 122 | uint32_t getIRQStatus(); 123 | bool clearIRQStatus(uint32_t irqMask); 124 | 125 | PN5180TransceiveStat getTransceiveState(); 126 | 127 | /* 128 | * Private methods, called within an SPI transaction 129 | */ 130 | private: 131 | bool transceiveCommand(uint8_t *sendBuffer, size_t sendBufferLen, uint8_t *recvBuffer = 0, size_t recvBufferLen = 0); 132 | 133 | }; 134 | 135 | #endif /* PN5180_H */ 136 | -------------------------------------------------------------------------------- /examples/PN5180-FeliCa/PN5180-FeliCa.ino: -------------------------------------------------------------------------------- 1 | // NAME: PN5180-FeliCa.ino 2 | // 3 | // DESC: Example usage of the PN5180 library for the PN5180-NFC Module 4 | // from NXP Semiconductors. 5 | // 6 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 7 | // Copyright (c) 2019 by Dirk Carstensen. 8 | // Copyright (c) 2020 by CrazyRedMachine. 9 | // 10 | // This file is part of the PN5180 library for the Arduino environment. 11 | // 12 | // This library is free software; you can redistribute it and/or 13 | // modify it under the terms of the GNU Lesser General Public 14 | // License as published by the Free Software Foundation; either 15 | // version 2.1 of the License, or (at your option) any later version. 16 | // 17 | // This library is distributed in the hope that it will be useful, 18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | // Lesser General Public License for more details. 21 | // 22 | // BEWARE: SPI with an Arduino to a PN5180 module has to be at a level of 3.3V 23 | // use of logic-level converters from 5V->3.3V is absolutly neccessary 24 | // on most Arduinos for all input pins of PN5180! 25 | // If used with an ESP-32, there is no need for a logic-level converter, since 26 | // it operates on 3.3V already. 27 | // 28 | // Arduino <-> Level Converter <-> PN5180 pin mapping: 29 | // 5V <--> 5V 30 | // 3.3V <--> 3.3V 31 | // GND <--> GND 32 | // 5V <-> HV 33 | // GND <-> GND (HV) 34 | // LV <-> 3.3V 35 | // GND (LV) <-> GND 36 | // SCLK,13 <-> HV1 - LV1 --> SCLK 37 | // MISO,12 <--- <-- MISO 38 | // MOSI,11 <-> HV3 - LV3 --> MOSI 39 | // SS,10 <-> HV4 - LV4 --> NSS (=Not SS -> active LOW) 40 | // BUSY,9 <--- BUSY 41 | // Reset,7 <-> HV2 - LV2 --> RST 42 | // 43 | // ESP-32 <--> PN5180 pin mapping: 44 | // 3.3V <--> 3.3V 45 | // GND <--> GND 46 | // SCLK, 18 --> SCLK 47 | // MISO, 19 <-- MISO 48 | // MOSI, 23 --> MOSI 49 | // SS, 16 --> NSS (=Not SS -> active LOW) 50 | // BUSY, 5 <-- BUSY 51 | // Reset, 17 --> RST 52 | // 53 | 54 | /* 55 | * Pins on ICODE2 Reader Writer: 56 | * 57 | * ICODE2 | PN5180 58 | * pin label | pin I/O name 59 | * 1 +5V 60 | * 2 +3,3V 61 | * 3 RST 10 I RESET_N (low active) 62 | * 4 NSS 1 I SPI NSS 63 | * 5 MOSI 3 I SPI MOSI 64 | * 6 MISO 5 O SPI MISO 65 | * 7 SCK 7 I SPI Clock 66 | * 8 BUSY 8 O Busy Signal 67 | * 9 GND 9 Supply VSS - Ground 68 | * 10 GPIO 38 O GPO1 - Control for external DC/DC 69 | * 11 IRQ 39 O IRQ 70 | * 12 AUX 40 O AUX1 - Analog/Digital test signal 71 | * 13 REQ 2? I/O AUX2 - Analog test bus or download 72 | * 73 | */ 74 | 75 | //#define WRITE_ENABLED 1 76 | 77 | #include 78 | #include 79 | 80 | #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_ARCH_SAM) 81 | 82 | #define PN5180_NSS 10 83 | #define PN5180_BUSY 9 84 | #define PN5180_RST 7 85 | 86 | #elif defined(ARDUINO_ARCH_ESP32) 87 | 88 | #define PN5180_NSS 16 // swapped with BUSY 89 | #define PN5180_BUSY 5 // swapped with NSS 90 | #define PN5180_RST 17 91 | 92 | #else 93 | #error Please define your pinout here! 94 | #endif 95 | 96 | PN5180FeliCa nfc(PN5180_NSS, PN5180_BUSY, PN5180_RST); 97 | 98 | void setup() { 99 | Serial.begin(115200); 100 | Serial.println(F("==================================")); 101 | Serial.println(F("Uploaded: " __DATE__ " " __TIME__)); 102 | Serial.println(F("PN5180 FeliCa Demo Sketch")); 103 | 104 | nfc.begin(); 105 | 106 | Serial.println(F("----------------------------------")); 107 | Serial.println(F("PN5180 Hard-Reset...")); 108 | nfc.reset(); 109 | 110 | Serial.println(F("----------------------------------")); 111 | Serial.println(F("Reading product version...")); 112 | uint8_t productVersion[2]; 113 | nfc.readEEprom(PRODUCT_VERSION, productVersion, sizeof(productVersion)); 114 | Serial.print(F("Product version=")); 115 | Serial.print(productVersion[1]); 116 | Serial.print("."); 117 | Serial.println(productVersion[0]); 118 | 119 | if (0xff == productVersion[1]) { // if product version 255, the initialization failed 120 | Serial.println(F("Initialization failed!?")); 121 | Serial.println(F("Press reset to restart...")); 122 | Serial.flush(); 123 | exit(-1); // halt 124 | } 125 | 126 | Serial.println(F("----------------------------------")); 127 | Serial.println(F("Reading firmware version...")); 128 | uint8_t firmwareVersion[2]; 129 | nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); 130 | Serial.print(F("Firmware version=")); 131 | Serial.print(firmwareVersion[1]); 132 | Serial.print("."); 133 | Serial.println(firmwareVersion[0]); 134 | 135 | Serial.println(F("----------------------------------")); 136 | Serial.println(F("Reading EEPROM version...")); 137 | uint8_t eepromVersion[2]; 138 | nfc.readEEprom(EEPROM_VERSION, eepromVersion, sizeof(eepromVersion)); 139 | Serial.print(F("EEPROM version=")); 140 | Serial.print(eepromVersion[1]); 141 | Serial.print("."); 142 | Serial.println(eepromVersion[0]); 143 | 144 | Serial.println(F("----------------------------------")); 145 | Serial.println(F("Enable RF field...")); 146 | nfc.setupRF(); 147 | } 148 | 149 | uint32_t loopCnt = 0; 150 | bool errorFlag = false; 151 | 152 | void loop() { 153 | Serial.println(F("----------------------------------")); 154 | Serial.print(F("Loop #")); 155 | Serial.println(loopCnt++); 156 | #if defined(ARDUINO_ARCH_ESP32) 157 | Serial.println("Free heap: " + String(ESP.getFreeHeap())); 158 | #endif 159 | uint8_t uid[20]; 160 | // check for FeliCa card 161 | nfc.reset(); 162 | nfc.setupRF(); 163 | uint8_t uidLength = nfc.readCardSerial(uid); 164 | if (uidLength > 0) { 165 | Serial.print(F("FeliCa card found, UID=")); 166 | for (int i=0; i 22 | #include "PN5180ISO14443.h" 23 | #include 24 | #include "Debug.h" 25 | 26 | PN5180ISO14443::PN5180ISO14443(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) 27 | : PN5180(SSpin, BUSYpin, RSTpin) { 28 | } 29 | 30 | bool PN5180ISO14443::setupRF() { 31 | PN5180DEBUG(F("Loading RF-Configuration...\n")); 32 | if (loadRFConfig(0x00, 0x80)) { // ISO14443 parameters 33 | PN5180DEBUG(F("done.\n")); 34 | } 35 | else return false; 36 | 37 | PN5180DEBUG(F("Turning ON RF field...\n")); 38 | if (setRF_on()) { 39 | PN5180DEBUG(F("done.\n")); 40 | } 41 | else return false; 42 | 43 | return true; 44 | } 45 | 46 | uint16_t PN5180ISO14443::rxBytesReceived() { 47 | uint32_t rxStatus; 48 | uint16_t len = 0; 49 | readRegister(RX_STATUS, &rxStatus); 50 | // Lower 9 bits has length 51 | len = (uint16_t)(rxStatus & 0x000001ff); 52 | return len; 53 | } 54 | /* 55 | * buffer : must be 10 byte array 56 | * buffer[0-1] is ATQA 57 | * buffer[2] is sak 58 | * buffer[3..6] is 4 byte UID 59 | * buffer[7..9] is remaining 3 bytes of UID for 7 Byte UID tags 60 | * kind : 0 we send REQA, 1 we send WUPA 61 | * 62 | * return value: the uid length: 63 | * - zero if no tag was recognized 64 | * - single Size UID (4 byte) 65 | * - double Size UID (7 byte) 66 | * - triple Size UID (10 byte) - not yet supported 67 | */ 68 | uint8_t PN5180ISO14443::activateTypeA(uint8_t *buffer, uint8_t kind) { 69 | uint8_t cmd[7]; 70 | uint8_t uidLength = 0; 71 | // Load standard TypeA protocol 72 | if (!loadRFConfig(0x0, 0x80)) 73 | return 0; 74 | 75 | // OFF Crypto 76 | if (!writeRegisterWithAndMask(SYSTEM_CONFIG, 0xFFFFFFBF)) 77 | return 0; 78 | // Clear RX CRC 79 | if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE)) 80 | return 0; 81 | // Clear TX CRC 82 | if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE)) 83 | return 0; 84 | //Send REQA/WUPA, 7 bits in last byte 85 | cmd[0] = (kind == 0) ? 0x26 : 0x52; 86 | if (!sendData(cmd, 1, 0x07)) 87 | return 0; 88 | // READ 2 bytes ATQA into buffer 89 | if (!readData(2, buffer)) 90 | return 0; 91 | //Send Anti collision 1, 8 bits in last byte 92 | cmd[0] = 0x93; 93 | cmd[1] = 0x20; 94 | if (!sendData(cmd, 2, 0x00)) 95 | return 0; 96 | //Read 5 bytes, we will store at offset 2 for later usage 97 | if (!readData(5, cmd+2)) 98 | return 0; 99 | //Enable RX CRC calculation 100 | if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01)) 101 | return 0; 102 | //Enable TX CRC calculation 103 | if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01)) 104 | return 0; 105 | //Send Select anti collision 1, the remaining bytes are already in offset 2 onwards 106 | cmd[0] = 0x93; 107 | cmd[1] = 0x70; 108 | if (!sendData(cmd, 7, 0x00)) 109 | return 0; 110 | //Read 1 byte SAK into buffer[2] 111 | if (!readData(1, buffer+2)) 112 | return 0; 113 | // Check if the tag is 4 Byte UID or 7 byte UID and requires anti collision 2 114 | // If Bit 3 is 0 it is 4 Byte UID 115 | if ((buffer[2] & 0x04) == 0) { 116 | // Take first 4 bytes of anti collision as UID store at offset 3 onwards. job done 117 | for (int i = 0; i < 4; i++) buffer[3+i] = cmd[2 + i]; 118 | uidLength = 4; 119 | } 120 | else { 121 | // Take First 3 bytes of UID, Ignore first byte 88(CT) 122 | if (cmd[2] != 0x88) 123 | return 0; 124 | for (int i = 0; i < 3; i++) buffer[3+i] = cmd[3 + i]; 125 | // Clear RX CRC 126 | if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE)) 127 | return 0; 128 | // Clear TX CRC 129 | if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE)) 130 | return 0; 131 | // Do anti collision 2 132 | cmd[0] = 0x95; 133 | cmd[1] = 0x20; 134 | if (!sendData(cmd, 2, 0x00)) 135 | return 0; 136 | //Read 5 bytes. we will store at offset 2 for later use 137 | if (!readData(5, cmd+2)) 138 | return 0; 139 | // first 4 bytes belongs to last 4 UID bytes, we keep it. 140 | for (int i = 0; i < 4; i++) { 141 | buffer[6 + i] = cmd[2+i]; 142 | } 143 | //Enable RX CRC calculation 144 | if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01)) 145 | return 0; 146 | //Enable TX CRC calculation 147 | if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01)) 148 | return 0; 149 | //Send Select anti collision 2 150 | cmd[0] = 0x95; 151 | cmd[1] = 0x70; 152 | if (!sendData(cmd, 7, 0x00)) 153 | return 0; 154 | //Read 1 byte SAK into buffer[2] 155 | if (!readData(1, buffer + 2)) 156 | return 0; 157 | uidLength = 7; 158 | } 159 | return uidLength; 160 | } 161 | 162 | bool PN5180ISO14443::mifareBlockRead(uint8_t blockno, uint8_t *buffer) { 163 | bool success = false; 164 | uint16_t len; 165 | uint8_t cmd[2]; 166 | // Send mifare command 30,blockno 167 | cmd[0] = 0x30; 168 | cmd[1] = blockno; 169 | if (!sendData(cmd, 2, 0x00)) 170 | return false; 171 | //Check if we have received any data from the tag 172 | delay(5); 173 | len = rxBytesReceived(); 174 | if (len == 16) { 175 | // READ 16 bytes into buffer 176 | if (readData(16, buffer)) 177 | success = true; 178 | } 179 | return success; 180 | } 181 | 182 | 183 | uint8_t PN5180ISO14443::mifareBlockWrite16(uint8_t blockno, uint8_t *buffer) { 184 | uint8_t cmd[1]; 185 | // Clear RX CRC 186 | writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE); 187 | 188 | // Mifare write part 1 189 | cmd[0] = 0xA0; 190 | cmd[1] = blockno; 191 | sendData(cmd, 2, 0x00); 192 | readData(1, cmd); 193 | 194 | // Mifare write part 2 195 | sendData(buffer,16, 0x00); 196 | delay(10); 197 | 198 | // Read ACK/NAK 199 | readData(1, cmd); 200 | 201 | //Enable RX CRC calculation 202 | writeRegisterWithOrMask(CRC_RX_CONFIG, 0x1); 203 | return cmd[0]; 204 | } 205 | 206 | bool PN5180ISO14443::mifareHalt() { 207 | uint8_t cmd[1]; 208 | //mifare Halt 209 | cmd[0] = 0x50; 210 | cmd[1] = 0x00; 211 | sendData(cmd, 2, 0x00); 212 | return true; 213 | } 214 | 215 | uint8_t PN5180ISO14443::readCardSerial(uint8_t *buffer) { 216 | 217 | uint8_t response[10]; 218 | uint8_t uidLength; 219 | // Always return 10 bytes 220 | // Offset 0..1 is ATQA 221 | // Offset 2 is SAK. 222 | // UID 4 bytes : offset 3 to 6 is UID, offset 7 to 9 to Zero 223 | // UID 7 bytes : offset 3 to 9 is UID 224 | for (int i = 0; i < 10; i++) response[i] = 0; 225 | uidLength = activateTypeA(response, 1); 226 | if ((response[0] == 0xFF) && (response[1] == 0xFF)) 227 | return 0; 228 | // check for valid uid 229 | if ((response[3] == 0x00) && (response[4] == 0x00) && (response[5] == 0x00) && (response[6] == 0x00)) 230 | return 0; 231 | if ((response[3] == 0xFF) && (response[4] == 0xFF) && (response[5] == 0xFF) && (response[6] == 0xFF)) 232 | return 0; 233 | for (int i = 0; i < 7; i++) buffer[i] = response[i+3]; 234 | mifareHalt(); 235 | return uidLength; 236 | } 237 | 238 | bool PN5180ISO14443::isCardPresent() { 239 | uint8_t buffer[10]; 240 | return (readCardSerial(buffer) >=4); 241 | } 242 | 243 | -------------------------------------------------------------------------------- /PN5180iClass.cpp: -------------------------------------------------------------------------------- 1 | // NAME: PN5180iClass.cpp 2 | // 3 | // DESC: iClass protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | //#define DEBUG 1 20 | 21 | #include 22 | #include "PN5180iClass.h" 23 | #include "Debug.h" 24 | 25 | PN5180iClass::PN5180iClass(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) : PN5180(SSpin, BUSYpin, RSTpin) { 26 | } 27 | 28 | iClassErrorCode PN5180iClass::ActivateAll() { 29 | PN5180DEBUG(F("Activate All...\n")); 30 | 31 | // Disable CRCs 32 | writeRegister(CRC_TX_CONFIG, 0x00000000); 33 | writeRegister(CRC_RX_CONFIG, 0x00000000); 34 | 35 | uint8_t actall[] = {ICLASS_CMD_ACTALL}; 36 | 37 | uint8_t *readBuffer; 38 | iClassErrorCode rc = issueiClassCommand(actall, sizeof(actall), &readBuffer); 39 | if (ICLASS_EC_OK != rc) { 40 | return rc; 41 | } 42 | 43 | return ICLASS_EC_OK; 44 | } 45 | 46 | iClassErrorCode PN5180iClass::Identify(uint8_t *csn) { 47 | PN5180DEBUG(F("Identify...\n")); 48 | 49 | writeRegister(CRC_TX_CONFIG, 0x00000000); 50 | writeRegister(CRC_RX_CONFIG, 0x00000029); 51 | 52 | uint8_t identify[] = {ICLASS_CMD_IDENTIFY}; 53 | 54 | for (int i=0; i<8; i++) { 55 | csn[i] = 0; 56 | } 57 | 58 | uint8_t *readBuffer; 59 | iClassErrorCode rc = issueiClassCommand(identify, sizeof(identify), &readBuffer); 60 | if (ICLASS_EC_OK != rc) { 61 | return rc; 62 | } 63 | 64 | // Anticollision CSN 65 | for (int i=0; i<8; i++) { 66 | csn[i] = readBuffer[i]; 67 | } 68 | 69 | return ICLASS_EC_OK; 70 | } 71 | 72 | 73 | iClassErrorCode PN5180iClass::Select(uint8_t *csn) { 74 | PN5180DEBUG(F("Select...\n")); 75 | 76 | writeRegister(CRC_TX_CONFIG, 0x00000000); 77 | writeRegister(CRC_RX_CONFIG, 0x00000029); 78 | 79 | uint8_t select[] = {ICLASS_CMD_SELECT, 1, 2, 3, 4, 5, 6, 7, 8}; 80 | 81 | for (int i=0; i<8; i++) { 82 | select[i+1] = csn[i]; 83 | } 84 | 85 | uint8_t *readBuffer; 86 | iClassErrorCode rc = issueiClassCommand(select, sizeof(select), &readBuffer); 87 | if (ICLASS_EC_OK != rc) { 88 | return rc; 89 | } 90 | 91 | // Replace with real CSN 92 | for (int i=0; i<8; i++) { 93 | csn[i] = readBuffer[i]; 94 | } 95 | 96 | return ICLASS_EC_OK; 97 | } 98 | 99 | iClassErrorCode PN5180iClass::ReadCheck(uint8_t *ccnr) { 100 | PN5180DEBUG(F("ReadCheck...\n")); 101 | 102 | // Disable CRCs 103 | writeRegister(CRC_TX_CONFIG, 0x00000000); 104 | writeRegister(CRC_RX_CONFIG, 0x00000000); 105 | 106 | uint8_t readcheck[] = {ICLASS_CMD_READCHECK, 0x02}; 107 | 108 | uint8_t *readBuffer; 109 | iClassErrorCode rc = issueiClassCommand(readcheck, sizeof(readcheck), &readBuffer); 110 | if (ICLASS_EC_OK != rc) { 111 | return rc; 112 | } 113 | 114 | for (int i=0; i<8; i++) { 115 | ccnr[i] = readBuffer[i]; 116 | } 117 | 118 | return ICLASS_EC_OK; 119 | } 120 | 121 | iClassErrorCode PN5180iClass::Check(uint8_t *mac) { 122 | PN5180DEBUG(F("Check...\n")); 123 | 124 | // Disable CRCs 125 | writeRegister(CRC_TX_CONFIG, 0x00000000); 126 | writeRegister(CRC_RX_CONFIG, 0x00000000); 127 | 128 | uint8_t check[] = {ICLASS_CMD_CHECK, 0, 0, 0, 0, 1, 2, 3, 4}; 129 | 130 | // Copied into last 4 bytes 131 | for (int i=0; i<4; i++) { 132 | check[i+5] = mac[i]; 133 | } 134 | 135 | uint8_t *readBuffer; 136 | iClassErrorCode rc = issueiClassCommand(check, sizeof(check), &readBuffer); 137 | if (ICLASS_EC_OK != rc) { 138 | return rc; 139 | } 140 | 141 | return ICLASS_EC_OK; 142 | } 143 | 144 | iClassErrorCode PN5180iClass::Read(uint8_t blockNum, uint8_t *blockData) { 145 | PN5180DEBUG(F("Read...\n")); 146 | 147 | writeRegister(CRC_TX_CONFIG, 0x00000069); 148 | writeRegister(CRC_RX_CONFIG, 0x00000029); 149 | 150 | uint8_t read[] = {ICLASS_CMD_READ, blockNum}; 151 | 152 | uint8_t *readBuffer; 153 | iClassErrorCode rc = issueiClassCommand(read, sizeof(read), &readBuffer); 154 | if (ICLASS_EC_OK != rc) { 155 | return rc; 156 | } 157 | 158 | for (int i=0; i<8; i++) { 159 | blockData[i] = readBuffer[i]; 160 | } 161 | 162 | return ICLASS_EC_OK; 163 | } 164 | 165 | iClassErrorCode PN5180iClass::Halt() { 166 | PN5180DEBUG(F("Halt...\n")); 167 | 168 | // Disable CRCs 169 | writeRegister(CRC_TX_CONFIG, 0x00000000); 170 | writeRegister(CRC_RX_CONFIG, 0x00000000); 171 | 172 | uint8_t halt[] = {ICLASS_CMD_HALT}; 173 | 174 | uint8_t *readBuffer; 175 | iClassErrorCode rc = issueiClassCommand(halt, sizeof(halt), &readBuffer); 176 | if (ICLASS_EC_OK != rc) { 177 | return rc; 178 | } 179 | 180 | return ICLASS_EC_OK; 181 | } 182 | 183 | iClassErrorCode PN5180iClass::issueiClassCommand(uint8_t *cmd, uint8_t cmdLen, uint8_t **resultPtr) { 184 | #ifdef DEBUG 185 | PN5180DEBUG(F("Issue Command 0x")); 186 | PN5180DEBUG(formatHex(cmd[1])); 187 | PN5180DEBUG("...\n"); 188 | #endif 189 | 190 | sendData(cmd, cmdLen); 191 | delay(10); 192 | 193 | if (0 == (getIRQStatus() & RX_SOF_DET_IRQ_STAT)) { 194 | return EC_NO_CARD; 195 | } 196 | 197 | uint32_t rxStatus; 198 | readRegister(RX_STATUS, &rxStatus); 199 | 200 | PN5180DEBUG(F("RX-Status=")); 201 | PN5180DEBUG(formatHex(rxStatus)); 202 | 203 | uint16_t len = (uint16_t)(rxStatus & 0x000001ff); 204 | 205 | PN5180DEBUG(", len="); 206 | PN5180DEBUG(len); 207 | PN5180DEBUG("\n"); 208 | 209 | *resultPtr = readData(len); 210 | if (0L == *resultPtr) { 211 | PN5180DEBUG(F("*** ERROR in readData!\n")); 212 | return ICLASS_EC_UNKNOWN_ERROR; 213 | } 214 | 215 | #ifdef DEBUG 216 | Serial.print("Read="); 217 | for (int i=0; i3.3V is absolutely necessary 22 | // on most Arduinos for all input pins of PN5180! 23 | // If used with an ESP-32, there is no need for a logic-level converter, since 24 | // it operates on 3.3V already. 25 | // 26 | // Arduino <-> Level Converter <-> PN5180 pin mapping: 27 | // 5V <--> 5V 28 | // 3.3V <--> 3.3V 29 | // GND <--> GND 30 | // 5V <-> HV 31 | // GND <-> GND (HV) 32 | // LV <-> 3.3V 33 | // GND (LV) <-> GND 34 | // SCLK,13 <-> HV1 - LV1 --> SCLK 35 | // MISO,12 <--- <-- MISO 36 | // MOSI,11 <-> HV3 - LV3 --> MOSI 37 | // SS,10 <-> HV4 - LV4 --> NSS (=Not SS -> active LOW) 38 | // BUSY,9 <--- BUSY 39 | // Reset,7 <-> HV2 - LV2 --> RST 40 | // 41 | // ESP-32 <--> PN5180 pin mapping: 42 | // 3.3V <--> 3.3V 43 | // GND <--> GND 44 | // SCLK, 18 --> SCLK 45 | // MISO, 19 <-- MISO 46 | // MOSI, 23 --> MOSI 47 | // SS, 16 --> NSS (=Not SS -> active LOW) 48 | // BUSY, 5 <-- BUSY 49 | // Reset, 17 --> RST 50 | // 51 | 52 | /* 53 | * Pins on ICODE2 Reader Writer: 54 | * 55 | * ICODE2 | PN5180 56 | * pin label | pin I/O name 57 | * 1 +5V 58 | * 2 +3,3V 59 | * 3 RST 10 I RESET_N (low active) 60 | * 4 NSS 1 I SPI NSS 61 | * 5 MOSI 3 I SPI MOSI 62 | * 6 MISO 5 O SPI MISO 63 | * 7 SCK 7 I SPI Clock 64 | * 8 BUSY 8 O Busy Signal 65 | * 9 GND 9 Supply VSS - Ground 66 | * 10 GPIO 38 O GPO1 - Control for external DC/DC 67 | * 11 IRQ 39 O IRQ 68 | * 12 AUX 40 O AUX1 - Analog/Digital test signal 69 | * 13 REQ 2? I/O AUX2 - Analog test bus or download 70 | * 71 | */ 72 | 73 | //#define WRITE_ENABLED 1 74 | 75 | #include 76 | #include 77 | 78 | #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_NANO) 79 | 80 | #define PN5180_NSS 10 81 | #define PN5180_BUSY 9 82 | #define PN5180_RST 7 83 | 84 | #elif defined(ARDUINO_ARCH_ESP32) 85 | 86 | #define PN5180_NSS 16 87 | #define PN5180_BUSY 5 88 | #define PN5180_RST 17 89 | 90 | #else 91 | #error Please define your pinout here! 92 | #endif 93 | 94 | PN5180ISO15693 nfc(PN5180_NSS, PN5180_BUSY, PN5180_RST); 95 | 96 | void setup() { 97 | Serial.begin(115200); 98 | Serial.println(F("==================================")); 99 | Serial.println(F("Uploaded: " __DATE__ " " __TIME__)); 100 | Serial.println(F("PN5180 ISO15693 Demo Sketch")); 101 | 102 | nfc.begin(); 103 | 104 | Serial.println(F("----------------------------------")); 105 | Serial.println(F("PN5180 Hard-Reset...")); 106 | nfc.reset(); 107 | 108 | Serial.println(F("----------------------------------")); 109 | Serial.println(F("Reading product version...")); 110 | uint8_t productVersion[2]; 111 | nfc.readEEprom(PRODUCT_VERSION, productVersion, sizeof(productVersion)); 112 | Serial.print(F("Product version=")); 113 | Serial.print(productVersion[1]); 114 | Serial.print("."); 115 | Serial.println(productVersion[0]); 116 | 117 | if (0xff == productVersion[1]) { // if product version 255, the initialization failed 118 | Serial.println(F("Initialization failed!?")); 119 | Serial.println(F("Press reset to restart...")); 120 | Serial.flush(); 121 | exit(-1); // halt 122 | } 123 | 124 | Serial.println(F("----------------------------------")); 125 | Serial.println(F("Reading firmware version...")); 126 | uint8_t firmwareVersion[2]; 127 | nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); 128 | Serial.print(F("Firmware version=")); 129 | Serial.print(firmwareVersion[1]); 130 | Serial.print("."); 131 | Serial.println(firmwareVersion[0]); 132 | 133 | Serial.println(F("----------------------------------")); 134 | Serial.println(F("Reading EEPROM version...")); 135 | uint8_t eepromVersion[2]; 136 | nfc.readEEprom(EEPROM_VERSION, eepromVersion, sizeof(eepromVersion)); 137 | Serial.print(F("EEPROM version=")); 138 | Serial.print(eepromVersion[1]); 139 | Serial.print("."); 140 | Serial.println(eepromVersion[0]); 141 | 142 | /* 143 | Serial.println(F("----------------------------------")); 144 | Serial.println(F("Reading IRQ pin config...")); 145 | uint8_t irqConfig; 146 | nfc.readEEprom(IRQ_PIN_CONFIG, &irqConfig, 1)); 147 | Serial.print(F("IRQ_PIN_CONFIG=0x")); 148 | Serial.println(irqConfig, HEX); 149 | 150 | Serial.println(F("----------------------------------")); 151 | Serial.println(F("Reading IRQ_ENABLE register...")); 152 | uint32_t irqEnable; 153 | nfc.readRegister(IRQ_ENABLE, &irqEnable)); 154 | Serial.print(F("IRQ_ENABLE=0x")); 155 | Serial.println(irqConfig, HEX); 156 | */ 157 | 158 | Serial.println(F("----------------------------------")); 159 | Serial.println(F("Enable RF field...")); 160 | nfc.setupRF(); 161 | } 162 | 163 | uint32_t loopCnt = 0; 164 | bool errorFlag = false; 165 | 166 | //SLIX2 Passwords, first is manufacture standard 167 | uint8_t standardpassword[] = {0x0F, 0x0F, 0x0F, 0x0F}; 168 | //New Password 169 | uint8_t password[] = {0x12, 0x34, 0x56, 0x78}; 170 | 171 | void loop() { 172 | if (errorFlag) { 173 | uint32_t irqStatus = nfc.getIRQStatus(); 174 | showIRQStatus(irqStatus); 175 | 176 | if (0 == (RX_SOF_DET_IRQ_STAT & irqStatus)) { // no card detected 177 | Serial.println(F("*** No card detected!")); 178 | } 179 | 180 | nfc.reset(); 181 | nfc.setupRF(); 182 | 183 | errorFlag = false; 184 | } 185 | 186 | Serial.println(F("----------------------------------")); 187 | Serial.print(F("Loop #")); 188 | Serial.println(loopCnt++); 189 | 190 | /* 191 | // code for unlocking an ICODE SLIX2 protected tag 192 | ISO15693ErrorCode myrc = nfc.unlockICODESLIX2(password); 193 | if (ISO15693_EC_OK == myrc) { 194 | Serial.println("unlockICODESLIX2 successful"); 195 | } 196 | */ 197 | 198 | /* 199 | // code for set a new SLIX2 privacy password 200 | nfc.getInventory(uid); 201 | Serial.println("set new password"); 202 | 203 | ISO15693ErrorCode myrc2 = nfc.newpasswordICODESLIX2(password, standardpassword, uid); 204 | if (ISO15693_EC_OK == myrc2) { 205 | Serial.println("sucess! new password set"); 206 | }else{ 207 | Serial.println("fail! no new password set: "); 208 | Serial.println(nfc.strerror(myrc2)); 209 | Serial.println(" "); 210 | } 211 | */ 212 | 213 | uint8_t uid[8]; 214 | ISO15693ErrorCode rc = nfc.getInventory(uid); 215 | if (ISO15693_EC_OK != rc) { 216 | Serial.print(F("Error in getInventory: ")); 217 | Serial.println(nfc.strerror(rc)); 218 | errorFlag = true; 219 | return; 220 | } 221 | Serial.print(F("Inventory successful, UID=")); 222 | for (int i=0; i<8; i++) { 223 | Serial.print(uid[7-i], HEX); // LSB is first 224 | if (i < 2) Serial.print(":"); 225 | } 226 | Serial.println(); 227 | 228 | Serial.println(F("----------------------------------")); 229 | uint8_t blockSize, numBlocks; 230 | rc = nfc.getSystemInfo(uid, &blockSize, &numBlocks); 231 | if (ISO15693_EC_OK != rc) { 232 | Serial.print(F("Error in getSystemInfo: ")); 233 | Serial.println(nfc.strerror(rc)); 234 | errorFlag = true; 235 | return; 236 | } 237 | Serial.print(F("System Info retrieved: blockSize=")); 238 | Serial.print(blockSize); 239 | Serial.print(F(", numBlocks=")); 240 | Serial.println(numBlocks); 241 | 242 | Serial.println(F("----------------------------------")); 243 | uint8_t readBuffer[blockSize]; 244 | for (int no=0; no 22 | #include "PN5180.h" 23 | #include "Debug.h" 24 | 25 | // PN5180 1-Byte Direct Commands 26 | // see 11.4.3.3 Host Interface Command List 27 | #define PN5180_WRITE_REGISTER (0x00) 28 | #define PN5180_WRITE_REGISTER_OR_MASK (0x01) 29 | #define PN5180_WRITE_REGISTER_AND_MASK (0x02) 30 | #define PN5180_READ_REGISTER (0x04) 31 | #define PN5180_WRITE_EEPROM (0x06) 32 | #define PN5180_READ_EEPROM (0x07) 33 | #define PN5180_SEND_DATA (0x09) 34 | #define PN5180_READ_DATA (0x0A) 35 | #define PN5180_SWITCH_MODE (0x0B) 36 | #define PN5180_LOAD_RF_CONFIG (0x11) 37 | #define PN5180_RF_ON (0x16) 38 | #define PN5180_RF_OFF (0x17) 39 | 40 | uint8_t PN5180::readBuffer[508]; 41 | 42 | PN5180::PN5180(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) { 43 | PN5180_NSS = SSpin; 44 | PN5180_BUSY = BUSYpin; 45 | PN5180_RST = RSTpin; 46 | 47 | /* 48 | * 11.4.1 Physical Host Interface 49 | * The interface of the PN5180 to a host microcontroller is based on a SPI interface, 50 | * extended by signal line BUSY. The maximum SPI speed is 7 Mbps and fixed to CPOL 51 | * = 0 and CPHA = 0. 52 | */ 53 | // Settings for PN5180: 7Mbps, MSB first, SPI_MODE0 (CPOL=0, CPHA=0) 54 | PN5180_SPI_SETTINGS = SPISettings(7000000, MSBFIRST, SPI_MODE0); 55 | } 56 | 57 | void PN5180::begin() { 58 | pinMode(PN5180_NSS, OUTPUT); 59 | pinMode(PN5180_BUSY, INPUT); 60 | pinMode(PN5180_RST, OUTPUT); 61 | 62 | digitalWrite(PN5180_NSS, HIGH); // disable 63 | digitalWrite(PN5180_RST, HIGH); // no reset 64 | 65 | SPI.begin(); 66 | PN5180DEBUG(F("SPI pinout: ")); 67 | PN5180DEBUG(F("SS=")); PN5180DEBUG(SS); 68 | PN5180DEBUG(F(", MOSI=")); PN5180DEBUG(MOSI); 69 | PN5180DEBUG(F(", MISO=")); PN5180DEBUG(MISO); 70 | PN5180DEBUG(F(", SCK=")); PN5180DEBUG(SCK); 71 | PN5180DEBUG("\n"); 72 | } 73 | 74 | void PN5180::end() { 75 | digitalWrite(PN5180_NSS, HIGH); // disable 76 | SPI.end(); 77 | } 78 | 79 | /* 80 | * WRITE_REGISTER - 0x00 81 | * This command is used to write a 32-bit value (little endian) to a configuration register. 82 | * The address of the register must exist. If the condition is not fulfilled, an exception is 83 | * raised. 84 | */ 85 | bool PN5180::writeRegister(uint8_t reg, uint32_t value) { 86 | uint8_t *p = (uint8_t*)&value; 87 | 88 | #ifdef DEBUG 89 | PN5180DEBUG(F("Write Register 0x")); 90 | PN5180DEBUG(formatHex(reg)); 91 | PN5180DEBUG(F(", value (LSB first)=0x")); 92 | for (int i=0; i<4; i++) { 93 | PN5180DEBUG(formatHex(p[i])); 94 | } 95 | PN5180DEBUG("\n"); 96 | #endif 97 | 98 | /* 99 | For all 4 byte command parameter transfers (e.g. register values), the payload 100 | parameters passed follow the little endian approach (Least Significant Byte first). 101 | */ 102 | uint8_t buf[6] = { PN5180_WRITE_REGISTER, reg, p[0], p[1], p[2], p[3] }; 103 | 104 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 105 | transceiveCommand(buf, 6); 106 | SPI.endTransaction(); 107 | 108 | return true; 109 | } 110 | 111 | /* 112 | * WRITE_REGISTER_OR_MASK - 0x01 113 | * This command modifies the content of a register using a logical OR operation. The 114 | * content of the register is read and a logical OR operation is performed with the provided 115 | * mask. The modified content is written back to the register. 116 | * The address of the register must exist. If the condition is not fulfilled, an exception is 117 | * raised. 118 | */ 119 | bool PN5180::writeRegisterWithOrMask(uint8_t reg, uint32_t mask) { 120 | uint8_t *p = (uint8_t*)&mask; 121 | 122 | #ifdef DEBUG 123 | PN5180DEBUG(F("Write Register 0x")); 124 | PN5180DEBUG(formatHex(reg)); 125 | PN5180DEBUG(F(" with OR mask (LSB first)=0x")); 126 | for (int i=0; i<4; i++) { 127 | PN5180DEBUG(formatHex(p[i])); 128 | } 129 | PN5180DEBUG("\n"); 130 | #endif 131 | 132 | uint8_t buf[6] = { PN5180_WRITE_REGISTER_OR_MASK, reg, p[0], p[1], p[2], p[3] }; 133 | 134 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 135 | transceiveCommand(buf, 6); 136 | SPI.endTransaction(); 137 | 138 | return true; 139 | } 140 | 141 | /* 142 | * WRITE _REGISTER_AND_MASK - 0x02 143 | * This command modifies the content of a register using a logical AND operation. The 144 | * content of the register is read and a logical AND operation is performed with the provided 145 | * mask. The modified content is written back to the register. 146 | * The address of the register must exist. If the condition is not fulfilled, an exception is 147 | * raised. 148 | */ 149 | bool PN5180::writeRegisterWithAndMask(uint8_t reg, uint32_t mask) { 150 | uint8_t *p = (uint8_t*)&mask; 151 | 152 | #ifdef DEBUG 153 | PN5180DEBUG(F("Write Register 0x")); 154 | PN5180DEBUG(formatHex(reg)); 155 | PN5180DEBUG(F(" with AND mask (LSB first)=0x")); 156 | for (int i=0; i<4; i++) { 157 | PN5180DEBUG(formatHex(p[i])); 158 | } 159 | PN5180DEBUG("\n"); 160 | #endif 161 | 162 | uint8_t buf[6] = { PN5180_WRITE_REGISTER_AND_MASK, reg, p[0], p[1], p[2], p[3] }; 163 | 164 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 165 | transceiveCommand(buf, 6); 166 | SPI.endTransaction(); 167 | 168 | return true; 169 | } 170 | 171 | /* 172 | * READ_REGISTER - 0x04 173 | * This command is used to read the content of a configuration register. The content of the 174 | * register is returned in the 4 byte response. 175 | * The address of the register must exist. If the condition is not fulfilled, an exception is 176 | * raised. 177 | */ 178 | bool PN5180::readRegister(uint8_t reg, uint32_t *value) { 179 | PN5180DEBUG(F("Reading register 0x")); 180 | PN5180DEBUG(formatHex(reg)); 181 | PN5180DEBUG(F("...\n")); 182 | 183 | uint8_t cmd[2] = { PN5180_READ_REGISTER, reg }; 184 | 185 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 186 | transceiveCommand(cmd, 2, (uint8_t*)value, 4); 187 | SPI.endTransaction(); 188 | 189 | PN5180DEBUG(F("Register value=0x")); 190 | PN5180DEBUG(formatHex(*value)); 191 | PN5180DEBUG("\n"); 192 | 193 | return true; 194 | } 195 | 196 | /* 197 | * WRITE_EEPROM - 0x06 198 | */ 199 | bool PN5180::writeEEPROM(uint8_t addr, uint8_t *data, int len) { 200 | if ((addr > 254) || ((addr+len) > 254)) { 201 | PN5180DEBUG(F("ERROR: Writing beyond addr 254!\n")); 202 | return false; 203 | } 204 | 205 | PN5180DEBUG(F("Writing to EEPROM at 0x")); 206 | PN5180DEBUG(formatHex(addr)); 207 | PN5180DEBUG(F(", size=")); 208 | PN5180DEBUG(len); 209 | PN5180DEBUG(F("...\n")); 210 | 211 | uint8_t buffer[len+2]; 212 | buffer[0] = PN5180_WRITE_EEPROM; 213 | buffer[1] = addr; 214 | for (int i=0; i 254) || ((addr+len) > 254)) { 238 | PN5180DEBUG(F("ERROR: Reading beyond addr 254!\n")); 239 | return false; 240 | } 241 | 242 | PN5180DEBUG(F("Reading EEPROM at 0x")); 243 | PN5180DEBUG(formatHex(addr)); 244 | PN5180DEBUG(F(", size=")); 245 | PN5180DEBUG(len); 246 | PN5180DEBUG(F("...\n")); 247 | 248 | uint8_t cmd[3] = { PN5180_READ_EEPROM, addr, len }; 249 | 250 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 251 | transceiveCommand(cmd, 3, buffer, len); 252 | SPI.endTransaction(); 253 | 254 | #ifdef DEBUG 255 | PN5180DEBUG(F("EEPROM values: ")); 256 | for (int i=0; i 260) { 283 | PN5180DEBUG(F("ERROR: sendData with more than 260 bytes is not supported!\n")); 284 | return false; 285 | } 286 | 287 | #ifdef DEBUG 288 | PN5180DEBUG(F("Send data (len=")); 289 | PN5180DEBUG(len); 290 | PN5180DEBUG(F("):")); 291 | for (int i=0; i 508) { 341 | Serial.println(F("*** FATAL: Reading more than 508 bytes is not supported!")); 342 | return 0L; 343 | } 344 | if (NULL == buffer) { 345 | buffer = readBuffer; 346 | } 347 | 348 | PN5180DEBUG(F("Reading Data (len=")); 349 | PN5180DEBUG(len); 350 | PN5180DEBUG(F(")...\n")); 351 | 352 | uint8_t cmd[2] = { PN5180_READ_DATA, 0x00 }; 353 | 354 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 355 | transceiveCommand(cmd, 2, buffer, len); 356 | SPI.endTransaction(); 357 | 358 | #ifdef DEBUG 359 | PN5180DEBUG(F("Data read: ")); 360 | for (int i=0; i0D ISO 15693 ASK100 26 8D ISO 15693 26 386 | * 0E ISO 15693 ASK10 26 8E ISO 15693 53 387 | */ 388 | bool PN5180::loadRFConfig(uint8_t txConf, uint8_t rxConf) { 389 | PN5180DEBUG(F("Load RF-Config: txConf=")); 390 | PN5180DEBUG(formatHex(txConf)); 391 | PN5180DEBUG(F(", rxConf=")); 392 | PN5180DEBUG(formatHex(rxConf)); 393 | PN5180DEBUG("\n"); 394 | 395 | uint8_t cmd[3] = { PN5180_LOAD_RF_CONFIG, txConf, rxConf }; 396 | 397 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 398 | transceiveCommand(cmd, 3); 399 | SPI.endTransaction(); 400 | 401 | return true; 402 | } 403 | 404 | /* 405 | * RF_ON - 0x16 406 | * This command is used to switch on the internal RF field. If enabled the TX_RFON_IRQ is 407 | * set after the field is switched on. 408 | */ 409 | bool PN5180::setRF_on() { 410 | PN5180DEBUG(F("Set RF ON\n")); 411 | 412 | uint8_t cmd[2] = { PN5180_RF_ON, 0x00 }; 413 | 414 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 415 | transceiveCommand(cmd, 2); 416 | SPI.endTransaction(); 417 | 418 | while (0 == (TX_RFON_IRQ_STAT & getIRQStatus())); // wait for RF field to set up 419 | clearIRQStatus(TX_RFON_IRQ_STAT); 420 | return true; 421 | } 422 | 423 | /* 424 | * RF_OFF - 0x17 425 | * This command is used to switch off the internal RF field. If enabled, the TX_RFOFF_IRQ 426 | * is set after the field is switched off. 427 | */ 428 | bool PN5180::setRF_off() { 429 | PN5180DEBUG(F("Set RF OFF\n")); 430 | 431 | uint8_t cmd[2] { PN5180_RF_OFF, 0x00 }; 432 | 433 | SPI.beginTransaction(PN5180_SPI_SETTINGS); 434 | transceiveCommand(cmd, 2); 435 | SPI.endTransaction(); 436 | 437 | while (0 == (TX_RFOFF_IRQ_STAT & getIRQStatus())); // wait for RF field to shut down 438 | clearIRQStatus(TX_RFOFF_IRQ_STAT); 439 | return true; 440 | } 441 | 442 | //--------------------------------------------------------------------------------------------- 443 | 444 | /* 445 | 11.4.3.1 A Host Interface Command consists of either 1 or 2 SPI frames depending whether the 446 | host wants to write or read data from the PN5180. An SPI Frame consists of multiple 447 | bytes. 448 | 449 | All commands are packed into one SPI Frame. An SPI Frame consists of multiple bytes. 450 | No NSS toggles allowed during sending of an SPI frame. 451 | 452 | For all 4 byte command parameter transfers (e.g. register values), the payload 453 | parameters passed follow the little endian approach (Least Significant Byte first). 454 | 455 | Direct Instructions are built of a command code (1 Byte) and the instruction parameters 456 | (max. 260 bytes). The actual payload size depends on the instruction used. 457 | Responses to direct instructions contain only a payload field (no header). 458 | All instructions are bound to conditions. If at least one of the conditions is not fulfilled, an exception is 459 | raised. In case of an exception, the IRQ line of PN5180 is asserted and corresponding interrupt 460 | status register contain information on the exception. 461 | */ 462 | 463 | /* 464 | * A Host Interface Command consists of either 1 or 2 SPI frames depending whether the 465 | * host wants to write or read data from the PN5180. An SPI Frame consists of multiple 466 | * bytes. 467 | * All commands are packed into one SPI Frame. An SPI Frame consists of multiple bytes. 468 | * No NSS toggles allowed during sending of an SPI frame. 469 | * For all 4 byte command parameter transfers (e.g. register values), the payload 470 | * parameters passed follow the little endian approach (Least Significant Byte first). 471 | * The BUSY line is used to indicate that the system is BUSY and cannot receive any data 472 | * from a host. Recommendation for the BUSY line handling by the host: 473 | * 1. Assert NSS to Low 474 | * 2. Perform Data Exchange 475 | * 3. Wait until BUSY is high 476 | * 4. Deassert NSS 477 | * 5. Wait until BUSY is low 478 | * If there is a parameter error, the IRQ is set to ACTIVE and a GENERAL_ERROR_IRQ is set. 479 | */ 480 | bool PN5180::transceiveCommand(uint8_t *sendBuffer, size_t sendBufferLen, uint8_t *recvBuffer, size_t recvBufferLen) { 481 | #ifdef DEBUG 482 | PN5180DEBUG(F("Sending SPI frame: '")); 483 | for (uint8_t i=0; i0) PN5180DEBUG(" "); 485 | PN5180DEBUG(formatHex(sendBuffer[i])); 486 | } 487 | PN5180DEBUG("'\n"); 488 | #endif 489 | 490 | // 0. 491 | while (LOW != digitalRead(PN5180_BUSY)); // wait until busy is low 492 | // 1. 493 | digitalWrite(PN5180_NSS, LOW); delay(2); 494 | // 2. 495 | for (uint8_t i=0; i 0) PN5180DEBUG(" "); 527 | PN5180DEBUG(formatHex(recvBuffer[i])); 528 | } 529 | PN5180DEBUG("'\n"); 530 | #endif 531 | 532 | return true; 533 | } 534 | 535 | /* 536 | * Reset NFC device 537 | */ 538 | void PN5180::reset() { 539 | digitalWrite(PN5180_RST, LOW); // at least 10us required 540 | delay(10); 541 | digitalWrite(PN5180_RST, HIGH); // 2ms to ramp up required 542 | delay(10); 543 | 544 | while (0 == (IDLE_IRQ_STAT & getIRQStatus())); // wait for system to start up 545 | 546 | clearIRQStatus(0xffffffff); // clear all flags 547 | } 548 | 549 | /** 550 | * @name getInterrrupt 551 | * @desc read interrupt status register and clear interrupt status 552 | */ 553 | uint32_t PN5180::getIRQStatus() { 554 | PN5180DEBUG(F("Read IRQ-Status register...\n")); 555 | 556 | uint32_t irqStatus; 557 | readRegister(IRQ_STATUS, &irqStatus); 558 | 559 | PN5180DEBUG(F("IRQ-Status=0x")); 560 | PN5180DEBUG(formatHex(irqStatus)); 561 | PN5180DEBUG("\n"); 562 | 563 | return irqStatus; 564 | } 565 | 566 | bool PN5180::clearIRQStatus(uint32_t irqMask) { 567 | PN5180DEBUG(F("Clear IRQ-Status with mask=x")); 568 | PN5180DEBUG(formatHex(irqMask)); 569 | PN5180DEBUG("\n"); 570 | 571 | return writeRegister(IRQ_CLEAR, irqMask); 572 | } 573 | 574 | /* 575 | * Get TRANSCEIVE_STATE from RF_STATUS register 576 | */ 577 | #ifdef DEBUG 578 | extern void showIRQStatus(uint32_t); 579 | #endif 580 | 581 | PN5180TransceiveStat PN5180::getTransceiveState() { 582 | PN5180DEBUG(F("Get Transceive state...\n")); 583 | 584 | uint32_t rfStatus; 585 | if (!readRegister(RF_STATUS, &rfStatus)) { 586 | #ifdef DEBUG 587 | showIRQStatus(getIRQStatus()); 588 | #endif 589 | PN5180DEBUG(F("ERROR reading RF_STATUS register.\n")); 590 | return PN5180TransceiveStat(0); 591 | } 592 | 593 | /* 594 | * TRANSCEIVE_STATEs: 595 | * 0 - idle 596 | * 1 - wait transmit 597 | * 2 - transmitting 598 | * 3 - wait receive 599 | * 4 - wait for data 600 | * 5 - receiving 601 | * 6 - loopback 602 | * 7 - reserved 603 | */ 604 | uint8_t state = ((rfStatus >> 24) & 0x07); 605 | PN5180DEBUG(F("TRANSCEIVE_STATE=0x")); 606 | PN5180DEBUG(formatHex(state)); 607 | PN5180DEBUG("\n"); 608 | 609 | return PN5180TransceiveStat(state); 610 | } 611 | -------------------------------------------------------------------------------- /PN5180ISO15693.cpp: -------------------------------------------------------------------------------- 1 | // NAME: PN5180ISO15693.h 2 | // 3 | // DESC: ISO15693 protocol on NXP Semiconductors PN5180 module for Arduino. 4 | // 5 | // Copyright (c) 2018 by Andreas Trappmann. All rights reserved. 6 | // 7 | // This file is part of the PN5180 library for the Arduino environment. 8 | // 9 | // This library is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU Lesser General Public 11 | // License as published by the Free Software Foundation; either 12 | // version 2.1 of the License, or (at your option) any later version. 13 | // 14 | // This library is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | // Lesser General Public License for more details. 18 | // 19 | //#define DEBUG 1 20 | 21 | #include 22 | #include "PN5180ISO15693.h" 23 | #include "Debug.h" 24 | 25 | PN5180ISO15693::PN5180ISO15693(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) 26 | : PN5180(SSpin, BUSYpin, RSTpin) { 27 | } 28 | 29 | /* 30 | * Inventory, code=01 31 | * 32 | * Request format: SOF, Req.Flags, Inventory, AFI (opt.), Mask len, Mask value, CRC16, EOF 33 | * Response format: SOF, Resp.Flags, DSFID, UID, CRC16, EOF 34 | * 35 | */ 36 | ISO15693ErrorCode PN5180ISO15693::getInventory(uint8_t *uid) { 37 | // Flags, CMD, maskLen 38 | uint8_t inventory[] = { 0x26, 0x01, 0x00 }; 39 | // |\- inventory flag + high data rate 40 | // \-- 1 slot: only one card, no AFI field present 41 | PN5180DEBUG(F("Get Inventory...\n")); 42 | 43 | for (int i=0; i<8; i++) { 44 | uid[i] = 0; 45 | } 46 | 47 | uint8_t *readBuffer; 48 | ISO15693ErrorCode rc = issueISO15693Command(inventory, sizeof(inventory), &readBuffer); 49 | if (ISO15693_EC_OK != rc) { 50 | return rc; 51 | } 52 | 53 | PN5180DEBUG(F("Response flags: ")); 54 | PN5180DEBUG(formatHex(readBuffer[0])); 55 | PN5180DEBUG(F(", Data Storage Format ID: ")); 56 | PN5180DEBUG(formatHex(readBuffer[1])); 57 | PN5180DEBUG(F(", UID: ")); 58 | 59 | for (int i=0; i<8; i++) { 60 | uid[i] = readBuffer[2+i]; 61 | #ifdef DEBUG 62 | PN5180DEBUG(formatHex(uid[7-i])); // LSB comes first 63 | if (i<2) PN5180DEBUG(":"); 64 | #endif 65 | } 66 | 67 | PN5180DEBUG("\n"); 68 | 69 | return ISO15693_EC_OK; 70 | } 71 | 72 | /* 73 | * Read single block, code=20 74 | * 75 | * Request format: SOF, Req.Flags, ReadSingleBlock, UID (opt.), BlockNumber, CRC16, EOF 76 | * Response format: 77 | * when ERROR flag is set: 78 | * SOF, Resp.Flags, ErrorCode, CRC16, EOF 79 | * 80 | * Response Flags: 81 | * xxxx.3xx0 82 | * |||\_ Error flag: 0=no error, 1=error detected, see error field 83 | * \____ Extension flag: 0=no extension, 1=protocol format is extended 84 | * 85 | * If Error flag is set, the following error codes are defined: 86 | * 01 = The command is not supported, i.e. the request code is not recognized. 87 | * 02 = The command is not recognized, i.e. a format error occurred. 88 | * 03 = The option is not supported. 89 | * 0F = Unknown error. 90 | * 10 = The specific block is not available. 91 | * 11 = The specific block is already locked and cannot be locked again. 92 | * 12 = The specific block is locked and cannot be changed. 93 | * 13 = The specific block was not successfully programmed. 94 | * 14 = The specific block was not successfully locked. 95 | * A0-DF = Custom command error codes 96 | * 97 | * when ERROR flag is NOT set: 98 | * SOF, Flags, BlockData (len=blockLength), CRC16, EOF 99 | */ 100 | ISO15693ErrorCode PN5180ISO15693::readSingleBlock(uint8_t *uid, uint8_t blockNo, uint8_t *blockData, uint8_t blockSize) { 101 | // flags, cmd, uid, blockNo 102 | uint8_t readSingleBlock[] = { 0x22, 0x20, 1,2,3,4,5,6,7,8, blockNo }; // UID has LSB first! 103 | // |\- high data rate 104 | // \-- no options, addressed by UID 105 | for (int i=0; i<8; i++) { 106 | readSingleBlock[2+i] = uid[i]; 107 | } 108 | 109 | #ifdef DEBUG 110 | PN5180DEBUG("Read Single Block #"); 111 | PN5180DEBUG(blockNo); 112 | PN5180DEBUG(", size="); 113 | PN5180DEBUG(blockSize); 114 | PN5180DEBUG(": "); 115 | for (int i=0; i> 4) { 323 | case 0: PN5180DEBUG(F("All families")); break; 324 | case 1: PN5180DEBUG(F("Transport")); break; 325 | case 2: PN5180DEBUG(F("Financial")); break; 326 | case 3: PN5180DEBUG(F("Identification")); break; 327 | case 4: PN5180DEBUG(F("Telecommunication")); break; 328 | case 5: PN5180DEBUG(F("Medical")); break; 329 | case 6: PN5180DEBUG(F("Multimedia")); break; 330 | case 7: PN5180DEBUG(F("Gaming")); break; 331 | case 8: PN5180DEBUG(F("Data storage")); break; 332 | case 9: PN5180DEBUG(F("Item management")); break; 333 | case 10: PN5180DEBUG(F("Express parcels")); break; 334 | case 11: PN5180DEBUG(F("Postal services")); break; 335 | case 12: PN5180DEBUG(F("Airline bags")); break; 336 | default: PN5180DEBUG(F("Unknown")); break; 337 | } 338 | PN5180DEBUG("\n"); 339 | } 340 | #ifdef DEBUG 341 | else PN5180DEBUG(F("No AFI\n")); 342 | #endif 343 | 344 | if (infoFlags & 0x04) { // VICC Memory size 345 | *numBlocks = *p++; 346 | *blockSize = *p++; 347 | *blockSize = (*blockSize) & 0x1f; 348 | 349 | *blockSize = *blockSize + 1; // range: 1-32 350 | *numBlocks = *numBlocks + 1; // range: 1-256 351 | uint16_t viccMemSize = (*blockSize) * (*numBlocks); 352 | 353 | PN5180DEBUG("VICC MemSize="); 354 | PN5180DEBUG(viccMemSize); 355 | PN5180DEBUG(" BlockSize="); 356 | PN5180DEBUG(*blockSize); 357 | PN5180DEBUG(" NumBlocks="); 358 | PN5180DEBUG(*numBlocks); 359 | PN5180DEBUG("\n"); 360 | } 361 | #ifdef DEBUG 362 | else PN5180DEBUG(F("No VICC memory size\n")); 363 | #endif 364 | 365 | if (infoFlags & 0x08) { // IC reference 366 | uint8_t icRef = *p++; 367 | PN5180DEBUG("IC Ref="); 368 | PN5180DEBUG(formatHex(icRef)); 369 | PN5180DEBUG("\n"); 370 | } 371 | #ifdef DEBUG 372 | else PN5180DEBUG(F("No IC ref\n")); 373 | #endif 374 | 375 | return ISO15693_EC_OK; 376 | } 377 | 378 | 379 | // ICODE SLIX specific commands 380 | 381 | /* 382 | * The GET RANDOM NUMBER command is required to receive a random number from the label IC. 383 | * The passwords that will be transmitted with the SET PASSWORD,ENABLEPRIVACY and DESTROY commands 384 | * have to be calculated with the password and therandom number (see Section 9.5.3.2 "SET PASSWORD") 385 | */ 386 | ISO15693ErrorCode PN5180ISO15693::getRandomNumber(uint8_t *randomData) { 387 | uint8_t getrandom[] = {0x02, 0xB2, 0x04}; 388 | uint8_t *readBuffer; 389 | ISO15693ErrorCode rc = issueISO15693Command(getrandom, sizeof(getrandom), &readBuffer); 390 | if (rc == ISO15693_EC_OK) { 391 | randomData[0] = readBuffer[1]; 392 | randomData[1] = readBuffer[2]; 393 | } 394 | return rc; 395 | } 396 | 397 | /* 398 | * The SET PASSWORD command enables the different passwords to be transmitted to the label 399 | * to access the different protected functionalities of the following commands. 400 | * The SET PASSWORD command has to be executed just once for the related passwords if the label is powered 401 | */ 402 | ISO15693ErrorCode PN5180ISO15693::setPassword(uint8_t *password, uint8_t *random) { 403 | uint8_t setPassword[] = {0x02, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00}; 404 | uint8_t *readBuffer; 405 | setPassword[4] = password[0] ^ random[0]; 406 | setPassword[5] = password[1] ^ random[1]; 407 | setPassword[6] = password[2] ^ random[0]; 408 | setPassword[7] = password[3] ^ random[1]; 409 | ISO15693ErrorCode rc = issueISO15693Command(setPassword, sizeof(setPassword), &readBuffer); 410 | return rc; 411 | } 412 | 413 | ISO15693ErrorCode PN5180ISO15693::enablePrivacy(uint8_t *password, uint8_t *random) { 414 | uint8_t setPrivacy[] = {0x02, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x00}; 415 | uint8_t *readBuffer; 416 | setPrivacy[3] = password[0] ^ random[0]; 417 | setPrivacy[4] = password[1] ^ random[1]; 418 | setPrivacy[5] = password[2] ^ random[0]; 419 | setPrivacy[6] = password[3] ^ random[1]; 420 | ISO15693ErrorCode rc = issueISO15693Command(setPrivacy, sizeof(setPrivacy), &readBuffer); 421 | return rc; 422 | } 423 | 424 | ISO15693ErrorCode PN5180ISO15693::writePassword(uint8_t *password, uint8_t *uid) { 425 | uint8_t writePassword[] = {0x22, 0xB4, 0x04, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7], 0x04, 0x00, 0x00, 0x00, 0x00}; 426 | uint8_t *readBuffer; 427 | writePassword[12] = password[0]; 428 | writePassword[13] = password[1]; 429 | writePassword[14] = password[2]; 430 | writePassword[15] = password[3]; 431 | ISO15693ErrorCode rc = issueISO15693Command(writePassword, sizeof(writePassword), &readBuffer); 432 | return rc; 433 | } 434 | 435 | 436 | // unlock a ICODE SLIX2 tag with given password 437 | ISO15693ErrorCode PN5180ISO15693::unlockICODESLIX2(uint8_t *password) { 438 | // get a random number from the tag 439 | uint8_t random[]= {0x00, 0x00}; 440 | ISO15693ErrorCode rc = getRandomNumber(random); 441 | if (rc != ISO15693_EC_OK) { 442 | return rc; 443 | } 444 | 445 | // set password to unlock the tag 446 | rc = setPassword(password, random); 447 | return rc; 448 | } 449 | 450 | // lock a ICODE SLIX2 tag with given password (set to privacy mode) 451 | ISO15693ErrorCode PN5180ISO15693::lockICODESLIX2(uint8_t *password) { 452 | // get a random number from the tag 453 | uint8_t random[]= {0x00, 0x00}; 454 | ISO15693ErrorCode rc = getRandomNumber(random); 455 | if (rc != ISO15693_EC_OK) { 456 | return rc; 457 | } 458 | 459 | // enable privacy command to lock the tag 460 | rc = enablePrivacy(password, random); 461 | return rc; 462 | } 463 | 464 | // set a new privacy password for slix2 Tags 465 | ISO15693ErrorCode PN5180ISO15693::newpasswordICODESLIX2(uint8_t *newpassword, uint8_t *oldpassword, uint8_t *uid) { 466 | // get a random number from the tag 467 | uint8_t random[]= {0x00, 0x00}; 468 | ISO15693ErrorCode rc = getRandomNumber(random); 469 | if (rc != ISO15693_EC_OK) { 470 | return rc; 471 | } 472 | 473 | // set password to unlock the tag 474 | rc = setPassword(oldpassword, random); 475 | 476 | if (rc != ISO15693_EC_OK) { 477 | return rc; 478 | } 479 | 480 | // write new password 481 | rc = writePassword(newpassword, uid); 482 | 483 | return rc; 484 | 485 | } 486 | 487 | 488 | /* 489 | * ISO 15693 - Protocol 490 | * 491 | * General Request Format: 492 | * SOF, Req.Flags, Command code, Parameters, Data, CRC16, EOF 493 | * 494 | * Request Flags: 495 | * xxxx.3210 496 | * |||\_ Subcarrier flag: 0=single sub-carrier, 1=two sub-carrier 497 | * ||\__ Datarate flag: 0=low data rate, 1=high data rate 498 | * |\___ Inventory flag: 0=no inventory, 1=inventory 499 | * \____ Protocol extension flag: 0=no extension, 1=protocol format is extended 500 | * 501 | * If Inventory flag is set: 502 | * 7654.xxxx 503 | * ||\_ AFI flag: 0=no AFI field present, 1=AFI field is present 504 | * |\__ Number of slots flag: 0=16 slots, 1=1 slot 505 | * \___ Option flag: 0=default, 1=meaning is defined by command description 506 | * 507 | * If Inventory flag is NOT set: 508 | * 7654.xxxx 509 | * ||\_ Select flag: 0=request shall be executed by any VICC according to Address_flag 510 | * || 1=request shall be executed only by VICC in selected state 511 | * |\__ Address flag: 0=request is not addressed. UID field is not present. 512 | * | 1=request is addressed. UID field is present. Only VICC with UID shall answer 513 | * \___ Option flag: 0=default, 1=meaning is defined by command description 514 | * 515 | * General Response Format: 516 | * SOF, Resp.Flags, Parameters, Data, CRC16, EOF 517 | * 518 | * Response Flags: 519 | * xxxx.3210 520 | * |||\_ Error flag: 0=no error, 1=error detected, see error field 521 | * ||\__ RFU: 0 522 | * |\___ RFU: 0 523 | * \____ Extension flag: 0=no extension, 1=protocol format is extended 524 | * 525 | * If Error flag is set, the following error codes are defined: 526 | * 01 = The command is not supported, i.e. the request code is not recognized. 527 | * 02 = The command is not recognized, i.e. a format error occurred. 528 | * 03 = The option is not supported. 529 | * 0F = Unknown error. 530 | * 10 = The specific block is not available. 531 | * 11 = The specific block is already locked and cannot be locked again. 532 | * 12 = The specific block is locked and cannot be changed. 533 | * 13 = The specific block was not successfully programmed. 534 | * 14 = The specific block was not successfully locked. 535 | * A0-DF = Custom command error codes 536 | * 537 | * Function return values: 538 | * 0 = OK 539 | * -1 = No card detected 540 | * >0 = Error code 541 | */ 542 | ISO15693ErrorCode PN5180ISO15693::issueISO15693Command(uint8_t *cmd, uint8_t cmdLen, uint8_t **resultPtr) { 543 | #ifdef DEBUG 544 | PN5180DEBUG(F("Issue Command 0x")); 545 | PN5180DEBUG(formatHex(cmd[1])); 546 | PN5180DEBUG("...\n"); 547 | #endif 548 | 549 | sendData(cmd, cmdLen); 550 | delay(10); 551 | uint32_t status = getIRQStatus(); 552 | if (0 == (status & RX_SOF_DET_IRQ_STAT)) { 553 | return EC_NO_CARD; 554 | } 555 | while (0 == (status & RX_IRQ_STAT)) { 556 | delay(10); 557 | status = getIRQStatus(); 558 | } 559 | 560 | uint32_t rxStatus; 561 | readRegister(RX_STATUS, &rxStatus); 562 | 563 | PN5180DEBUG(F("RX-Status=")); 564 | PN5180DEBUG(formatHex(rxStatus)); 565 | 566 | uint16_t len = (uint16_t)(rxStatus & 0x000001ff); 567 | 568 | PN5180DEBUG(", len="); 569 | PN5180DEBUG(len); 570 | PN5180DEBUG("\n"); 571 | 572 | *resultPtr = readData(len); 573 | if (0L == *resultPtr) { 574 | PN5180DEBUG(F("*** ERROR in readData!\n")); 575 | return ISO15693_EC_UNKNOWN_ERROR; 576 | } 577 | 578 | #ifdef DEBUG 579 | Serial.print("Read="); 580 | for (int i=0; i= 0xA0) { // custom command error codes 604 | return ISO15693_EC_CUSTOM_CMD_ERROR; 605 | } 606 | else return (ISO15693ErrorCode)errorCode; 607 | } 608 | 609 | #ifdef DEBUG 610 | if (responseFlags & (1<<3)) { // extendsion flag 611 | PN5180DEBUG("Extension flag is set!\n"); 612 | } 613 | #endif 614 | 615 | clearIRQStatus(RX_SOF_DET_IRQ_STAT | IDLE_IRQ_STAT | TX_IRQ_STAT | RX_IRQ_STAT); 616 | return ISO15693_EC_OK; 617 | } 618 | 619 | bool PN5180ISO15693::setupRF() { 620 | PN5180DEBUG(F("Loading RF-Configuration...\n")); 621 | if (loadRFConfig(0x0d, 0x8d)) { // ISO15693 parameters 622 | PN5180DEBUG(F("done.\n")); 623 | } 624 | else return false; 625 | 626 | PN5180DEBUG(F("Turning ON RF field...\n")); 627 | if (setRF_on()) { 628 | PN5180DEBUG(F("done.\n")); 629 | } 630 | else return false; 631 | 632 | writeRegisterWithAndMask(SYSTEM_CONFIG, 0xfffffff8); // Idle/StopCom Command 633 | writeRegisterWithOrMask(SYSTEM_CONFIG, 0x00000003); // Transceive Command 634 | 635 | return true; 636 | } 637 | 638 | const __FlashStringHelper *PN5180ISO15693::strerror(ISO15693ErrorCode errno) { 639 | PN5180DEBUG(F("ISO15693ErrorCode=")); 640 | PN5180DEBUG(errno); 641 | PN5180DEBUG("\n"); 642 | 643 | switch (errno) { 644 | case EC_NO_CARD: return F("No card detected!"); 645 | case ISO15693_EC_OK: return F("OK!"); 646 | case ISO15693_EC_NOT_SUPPORTED: return F("Command is not supported!"); 647 | case ISO15693_EC_NOT_RECOGNIZED: return F("Command is not recognized!"); 648 | case ISO15693_EC_OPTION_NOT_SUPPORTED: return F("Option is not supported!"); 649 | case ISO15693_EC_UNKNOWN_ERROR: return F("Unknown error!"); 650 | case ISO15693_EC_BLOCK_NOT_AVAILABLE: return F("Specified block is not available!"); 651 | case ISO15693_EC_BLOCK_ALREADY_LOCKED: return F("Specified block is already locked!"); 652 | case ISO15693_EC_BLOCK_IS_LOCKED: return F("Specified block is locked and cannot be changed!"); 653 | case ISO15693_EC_BLOCK_NOT_PROGRAMMED: return F("Specified block was not successfully programmed!"); 654 | case ISO15693_EC_BLOCK_NOT_LOCKED: return F("Specified block was not successfully locked!"); 655 | default: 656 | if ((errno >= 0xA0) && (errno <= 0xDF)) { 657 | return F("Custom command error code!"); 658 | } 659 | else return F("Undefined error code in ISO15693!"); 660 | } 661 | } 662 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | --------------------------------------------------------------------------------