285 lines
9.5 KiB
C++
285 lines
9.5 KiB
C++
/// Digital Logic uFR NFC card reader library for Arduino
|
|
///
|
|
/// Based on IS21 DLogic serial communication protocol
|
|
///
|
|
/// Version: 1.0.0
|
|
/// 2018 Marko Djordjevic
|
|
|
|
|
|
#include <Arduino.h>
|
|
#ifdef ESP32
|
|
#include <HardwareSerial.h>
|
|
#else
|
|
#include <SoftwareSerial.h>
|
|
#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();
|
|
};
|
|
};
|