/// Digital Logic uFR NFC card reader library for Arduino /// /// Based on IS21 DLogic serial communication protocol /// /// Version: 1.0.0 /// 2018 Marko Djordjevic #include #ifdef ESP32 #include #else #include #endif #define TIMEOUT_MS 100 // Debugging // Communication constants #define MAX_PACKET_LENGTH 64 #define HEADER_BYTE 0 #define CMD_BYTE 1 #define TRAILER_BYTE 2 #define EXT_LENGTH_BYTE 3 #define PAR0_BYTE 4 #define PAR1_BYTE 5 #define CHKSUM_BYTE 6 #define PACKET_LENGTH 7 #define CMD_HEADER 0x55 #define ACK_HEADER 0xAC #define RESPONSE_HEADER 0xDE #define ERR_HEADER 0xEC #define CMD_TRAILER 0xAA #define ACK_TRAILER 0xCA #define RESPONSE_TRAILER 0xED #define ERR_TRAILER 0xCE // CMD codes #define GET_READER_TYPE 0x10 #define GET_READER_SERIAL 0x11 #define READER_KEY_WRITE 0x12 #define GET_CARD_ID 0x13 #define LINEAR_READ 0x14 #define LINEAR_WRITE 0x15 #define BLOCK_READ 0x16 #define BLOCK_WRITE 0x17 #define BLOCK_IN_SECTOR_READ 0x18 #define BLOCK_IN_SECTOR_WRITE 0x19 #define SECTOR_TRAILER_WRITE 0X1A #define USER_DATA_READ 0x1B #define USER_DATA_WRITE 0x1C #define VALUE_BLOCK_READ 0x1D #define VALUE_BLOCK_WRITE 0x1E #define VALUE_BLOCK_IN_SECTOR_READ 0x1F #define VALUE_BLOCK_IN_SECTOR_WRITE 0x20 #define VALUE_BLOCK_INC 0x21 #define VALUE_BLOCK_DEC 0x22 #define VALUE_BLOCK_IN_SECTOR_INC 0x23 #define VALUE_BLOCK_IN_SECTOR_DEC 0x24 #define LINEAR_FORMAT_CARD 0x25 #define USER_INTERFACE_SIGNAL 0x26 #define GET_CARD_ID_EX 0x2C #define SECTOR_TRAILER_WRITE_UNSAFE 0x2F #define SELF_RESET 0x30 #define GET_DLOGIC_CARD_TYPE 0x3C #define SET_CARD_ID_SEND_CONF 0x3D #define GET_CARD_ID_SEND_CONF 0x3E #define SET_LED_CONFIG 0x6E #define SET_UART_SPEED 0x70 #define RED_LIGHT_CONTROL 0x71 #define GET_DESFIRE_UID 0x80 // ERR codes #define OK 0x00 #define COMMUNICATION_ERROR 0x01 #define COMMUNICATION_TIMEOUT 0x50 #define COMMUNICATION_TIMEOUT_EXT 0x51 #define CHKSUM_ERROR 0x02 #define CHKSUM_ERROR_RESPONSE 0x52 #define CHKSUM_ERROR_EXT 0x53 #define READING_ERROR 0x03 #define WRITING_ERROR 0x04 #define BUFFER_OVERFLOW 0x05 #define MAX_ADDRESS_EXCEEDED 0x06 #define MAX_KEY_INDEX_EXCEEDED 0x07 #define NO_CARD 0x08 #define COMMAND_NOT_SUPPORTED 0x09 #define FORBIDEN_DIRECT_WRITE_IN_SECTOR_TRAILER 0x0A #define ADDRESSED_BLOCK_IS_NOT_SECTOR_TRAILER 0x0B #define WRONG_ADDRESS_MODE 0x0C #define WRONG_ACCESS_BITS_VALUES 0x0D #define AUTH_ERROR 0x0E #define PARAMETERS_ERROR 0x0F #define WRITE_VERIFICATION_ERROR 0x70 #define BUFFER_SIZE_EXCEEDED 0x71 #define VALUE_BLOCK_INVALID 0x72 #define VALUE_BLOCK_ADDR_INVALID 0x73 #define VALUE_BLOCK_MANIPULATION_ERROR 0x74 // MIFARE CLASSIC type id's: #define MIFARE_CLASSIC_1k 0x08 #define MF1ICS50 0x08 #define SLE66R35 0x88 // Infineon = Mifare Classic 1k #define MIFARE_CLASSIC_4k 0x18 #define MF1ICS70 0x18 #define MIFARE_CLASSIC_MINI 0x09 #define MF1ICS20 0x09 // DLOGIC CARD TYPE #define TAG_UNKNOWN 0 #define DL_MIFARE_ULTRALIGHT 0x01 #define DL_MIFARE_ULTRALIGHT_EV1_11 0x02 #define DL_MIFARE_ULTRALIGHT_EV1_21 0x03 #define DL_MIFARE_ULTRALIGHT_C 0x04 #define DL_NTAG_203 0x05 #define DL_NTAG_210 0x06 #define DL_NTAG_212 0x07 #define DL_NTAG_213 0x08 #define DL_NTAG_215 0x09 #define DL_NTAG_216 0x0A #define DL_MIKRON_MIK640D 0x0B #define NFC_T2T_GENERIC 0x0C #define DL_MIFARE_MINI 0x20 #define DL_MIFARE_CLASSIC_1K 0x21 #define DL_MIFARE_CLASSIC_4K 0x22 #define DL_MIFARE_PLUS_S_2K 0x23 #define DL_MIFARE_PLUS_S_4K 0x24 #define DL_MIFARE_PLUS_X_2K 0x25 #define DL_MIFARE_PLUS_X_4K 0x26 #define DL_MIFARE_DESFIRE 0x27 #define DL_MIFARE_DESFIRE_EV1_2K 0x28 #define DL_MIFARE_DESFIRE_EV1_4K 0x29 #define DL_MIFARE_DESFIRE_EV1_8K 0x2A #define DL_MIFARE_DESFIRE_EV2_2K 0x2B #define DL_MIFARE_DESFIRE_EV2_4K 0x2C #define DL_MIFARE_DESFIRE_EV2_8K 0x2D //#define DL_UNKNOWN_ISO_14443_4 0x40 #define DL_GENERIC_ISO14443_4 0x40 #define DL_GENERIC_ISO14443_TYPE_B 0x41 #define DL_IMEI_UID 0x80 // Function return sizes in bytes #define READER_TYPE_SIZE 4 #define READER_SERIAL_SIZE 4 #define READER_KEY_SIZE 6 #define USER_DATA_SIZE 16 #define CARD_ID_SIZE 4 #define CARD_ID_EX_SIZE 10 // USER_INTERFACE_SIGNAL #define NONE 0 #define LONG_GREEN 1 #define SHORT_BEEP 1 #define LONG_RED 2 #define LONG_BEEP 2 #define ALTERNATNG_LIGHT 3 #define DOUBLE_SHORT_BEEP 3 #define FLASH_LIGHT 4 #define TRIPLE_SHORT_BEEP 4 #define TRIPLET_MELODY 5 enum PacketType { PACKET_ACK = ACK_HEADER, PACKET_ERR = ERR_HEADER, PACKET_RSP = RESPONSE_HEADER }; class uFR { public: #ifdef ESP32 uFR(uint8_t uart); uFR(uint8_t uart, uint8_t reset); uFR(uint8_t uart, uint8_t rx_pin, uint8_t tx_pin); uFR(uint8_t uart, uint8_t reset, uint8_t rx_pin, uint8_t tx_pin); #else uFR(uint8_t rx, uint8_t tx); uFR(uint8_t rx, uint8_t tx, uint8_t reset); #endif void begin(unsigned long baud = 115200); // Resets the reader if reset pin is used; make sure to add delay! inline void end() { readerSerial.end(); } // Resets through reset pin (if declared) void hardReset(); // Make sure to add delay! // All following functions return error codes after execution // If 0 is returned, the function has executed normally // Controls the reader's red LED. Green LED stops flashing while red LED is on uint8_t setRedLED(bool state); uint8_t setUserInterfaceSignal(uint8_t light_signal_mode = 0, uint8_t beep_signal_mode = 0); uint8_t setGreenLightBlinking(bool state); uint8_t getReaderType(uint8_t readerType[READER_TYPE_SIZE]); uint8_t getReaderSerial(uint8_t readerSerialNumber[READER_SERIAL_SIZE]); // Writes MIFARE key into reader EEPROM, at index location (0-31) uint8_t setReaderKey(uint8_t key[READER_KEY_SIZE], uint8_t index); // User data are 16 bytes form internal EEPROM uint8_t getUserData(uint8_t data[USER_DATA_SIZE]); uint8_t setUserData(uint8_t data[USER_DATA_SIZE]); // Sends reset command (add 2s delay!) uint8_t softReset(); // Gets card UID that is present in reader's RF field. Obsolete uint8_t getCardIDSimple(uint8_t cardID[CARD_ID_SIZE], uint8_t *cardType = nullptr); // Length - UID size in bytes (4, 7 or 10) uint8_t getCardID(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length = nullptr, uint8_t *cardType = nullptr); // Gets Desfire UID uint8_t getDesfireUID(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length = nullptr, uint8_t InternalAESKeyIndexReader = 0, uint32_t AID = 0, uint8_t key_number_in_application = 0); // Gets Desfire UID with provided AES key uint8_t getDesfireUIDPK(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length, uint8_t *AESKey = nullptr, uint32_t AID = 0, uint8_t key_number_in_application = 0); // Card type per DLogic enumeration uint8_t getCardTypeDLogic(uint8_t *cardType); // ------------------------------------------------------------- static const char * TypeDLogicToString(uint8_t type); private: #ifdef ESP32 HardwareSerial readerSerial; uint8_t esp32_rx_pin = 0; uint8_t esp32_tx_pin = 0; #else SoftwareSerial readerSerial; #endif uint8_t resetPin = 0; void flushSerial(); // Flush serial input buffer void sendPacketCMD(uint8_t command, uint8_t EXTlength = 0, uint8_t par0 = 0, uint8_t par1 = 0); void sendPacketEXT(uint8_t *packet, uint8_t length); void setPacketSerial (); // Sets static protected packet serial pointer class Packet { public: static uint8_t checksum(uint8_t *packet, uint8_t size = PACKET_LENGTH - 1); inline uint8_t getErrorCode() { return errorCode; } inline uint8_t getLength() { return length; } void copyData(uint8_t *array, uint16_t start, uint16_t length); void copyDataReverse(uint8_t *array, uint16_t start, uint16_t length); inline uint8_t operator[] (uint8_t i) { return data[i]; } friend void uFR::setPacketSerial (); protected: #ifdef ESP32 static HardwareSerial *serial; #else static SoftwareSerial *serial; #endif uint8_t errorCode = 0; uint8_t length = PACKET_LENGTH; uint8_t *data; }; class CommonPacket : public Packet { // Returns error code uint8_t read(uint8_t response[PACKET_LENGTH]); uint8_t validate(uint8_t packet[PACKET_LENGTH], PacketType type, uint8_t command); public: CommonPacket(PacketType type, uint8_t command); ~CommonPacket(); }; class EXTPacket : public Packet { // Returns error code, reads AND validates uint8_t read(uint8_t *response, uint8_t length); public: EXTPacket(uint8_t length); ~EXTPacket(); }; };