This commit is contained in:
ipwxp
2025-09-25 19:04:00 +08:00
commit fcccb1789b
114 changed files with 223396 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#include "uFR.h"
#ifdef ESP32
HardwareSerial* uFR::Packet::serial;
#else
SoftwareSerial* uFR::Packet::serial;
#endif
uFR::CommonPacket::CommonPacket(PacketType type, uint8_t command) {
data = new uint8_t[PACKET_LENGTH];
errorCode = read(data);
if (errorCode == 0) errorCode = validate(data, type, command);
}
uFR::CommonPacket::~CommonPacket() {
delete[] data;
}
uFR::EXTPacket::EXTPacket(uint8_t length) {
data = new uint8_t[length];
errorCode = read(data, length);
}
uFR::EXTPacket::~EXTPacket() {
delete[] data;
}
uint8_t uFR::Packet::checksum(uint8_t *packet, uint8_t size) {
uint8_t result = packet[0];
// XOR size bytes
for (uint8_t i = 1; i < size; i++)
result ^= packet[i];
return result + 0x07;
}
uint8_t uFR::CommonPacket::validate(uint8_t packet[PACKET_LENGTH], PacketType type, uint8_t command) {
if (checksum(packet) != packet[CHKSUM_BYTE]) return CHKSUM_ERROR_RESPONSE;
if (packet[HEADER_BYTE] == ERR_HEADER) {
if (packet[TRAILER_BYTE] == ERR_TRAILER) return packet[CMD_BYTE];
return COMMUNICATION_ERROR;
}
if (packet[HEADER_BYTE] != type || packet[CMD_BYTE] != command) return COMMUNICATION_ERROR;
switch (type) {
case PACKET_ACK:
if (packet[TRAILER_BYTE] != ACK_TRAILER) return COMMUNICATION_ERROR;
break;
case PACKET_RSP:
if (packet[TRAILER_BYTE] != RESPONSE_TRAILER) return COMMUNICATION_ERROR;
break;
default:
return COMMUNICATION_ERROR;
}
return 0;
}
uint8_t uFR::CommonPacket::read(uint8_t response[PACKET_LENGTH]) {
unsigned long time = millis();
uint8_t incoming = 0;
// Read bytes until header found
while(incoming != ACK_HEADER && incoming != ERR_HEADER && incoming != RESPONSE_HEADER) {
if((unsigned long)(millis() - time) > TIMEOUT_MS) return COMMUNICATION_TIMEOUT;
if (serial->available() > 0) incoming = serial->read();
}
// Read remaining bytes (PACKET_LENGTH - 1)
while (serial->available() < 6)
if ((unsigned long)(millis() - time) > TIMEOUT_MS) return COMMUNICATION_TIMEOUT;
// Store bytes
response[0] = incoming;
for (uint8_t i = 1; i < PACKET_LENGTH; i++)
response[i] = serial->read();
return 0;
}
uint8_t uFR::EXTPacket::read(uint8_t *response, uint8_t length) {
unsigned long time = millis();
uint8_t i = 0;
int b;
// Read length bytes
while (i < length) {
if ((unsigned long)(millis() - time) > TIMEOUT_MS) return COMMUNICATION_TIMEOUT_EXT;
b = serial->read();
if(b != -1) {
response[i] = b;
i++;
}
}
// Read and check checksum byte (length + 1)
while (serial->available() < 1)
if ((unsigned long)(millis() - time) > TIMEOUT_MS) return COMMUNICATION_TIMEOUT_EXT;
if (serial->read() != checksum(response, length)) return CHKSUM_ERROR_EXT;
return 0;
}
void uFR::Packet::copyData(uint8_t *array, uint16_t start, uint16_t length) {
for (uint16_t i = 0; i < length; i++)
array[i + start] = data[i];
}
void uFR::Packet::copyDataReverse(uint8_t *array, uint16_t start, uint16_t length) {
for (uint16_t i = 0; i < length; i++)
array[i + start] = data[length - i - 1];
}
+30
View File
@@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map For uFR
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
uFR KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
hardReset KEYWORD2
setRedLED KEYWORD2
getReaderType KEYWORD2
getReaderSerial KEYWORD2
setReaderKey KEYWORD2
getUserData KEYWORD2
setUserData KEYWORD2
softReset KEYWORD2
getCardIDSimple KEYWORD2
getCardID KEYWORD2
getCardTypeDLogic KEYWORD2
TypeDLogicToString KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+347
View File
@@ -0,0 +1,347 @@
#include "uFR.h"
#define PROCESS_EXT(length) \
EXTPacket extPacket(length); \
if (extPacket.getErrorCode() != 0) return extPacket.getErrorCode()
#define PROCESS_ACK(command) \
CommonPacket ackPacket(PACKET_ACK, command); \
if (ackPacket.getErrorCode() != 0) return ackPacket.getErrorCode()
#define PROCESS_RSP(command) \
CommonPacket rspPacket(PACKET_RSP, command); \
if (rspPacket.getErrorCode() != 0) return rspPacket.getErrorCode()
#ifdef ESP32
uFR::uFR(uint8_t uart) : readerSerial(HardwareSerial(uart)) {
setPacketSerial();
}
uFR::uFR(uint8_t uart, uint8_t rx_pin, uint8_t tx_pin) : readerSerial(HardwareSerial(uart)) {
esp32_rx_pin = rx_pin;
esp32_tx_pin = tx_pin;
setPacketSerial();
}
uFR::uFR(uint8_t uart, uint8_t reset) : readerSerial(HardwareSerial(uart)) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
resetPin = reset;
setPacketSerial();
}
uFR::uFR(uint8_t uart, uint8_t reset, uint8_t rx_pin, uint8_t tx_pin) : readerSerial(HardwareSerial(uart)) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
resetPin = reset;
esp32_rx_pin = rx_pin;
esp32_tx_pin = tx_pin;
setPacketSerial();
}
#else
uFR::uFR(uint8_t rx, uint8_t tx) : readerSerial(SoftwareSerial(rx, tx)) {
setPacketSerial();
}
uFR::uFR(uint8_t rx, uint8_t tx, uint8_t reset) : readerSerial(SoftwareSerial(rx, tx)) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
resetPin = reset;
setPacketSerial();
}
#endif
void uFR::setPacketSerial() {
Packet::serial = &readerSerial;
}
void uFR::begin(unsigned long baud) {
if(resetPin != 0) {
delay(10);
digitalWrite(resetPin, LOW);
}
#ifdef ESP32
if(esp32_rx_pin != 0 && esp32_tx_pin != 0) {
readerSerial.begin(baud, SERIAL_8N1, esp32_rx_pin, esp32_tx_pin);
}
else
{
readerSerial.begin(baud);
}
#else
readerSerial.begin(baud);
#endif
}
void uFR::hardReset() {
if (resetPin != 0) {
digitalWrite(resetPin, HIGH);
delay(10);
digitalWrite(resetPin, LOW);
}
}
void uFR::flushSerial() {
while (readerSerial.available() > 0)
readerSerial.read();
}
void uFR::sendPacketCMD(uint8_t command, uint8_t EXTlength, uint8_t par0, uint8_t par1) {
uint8_t packet[PACKET_LENGTH] = {
CMD_HEADER,
command,
CMD_TRAILER,
EXTlength,
par0,
par1,
Packet::checksum(packet)
};
readerSerial.write(packet, PACKET_LENGTH);
}
void uFR::sendPacketEXT(uint8_t *packet, uint8_t length) {
readerSerial.write(packet, length);
readerSerial.write(Packet::checksum(packet, length));
}
// ========================================================================================
uint8_t uFR::setRedLED(bool state) {
flushSerial();
sendPacketCMD(RED_LIGHT_CONTROL, 0, state);
PROCESS_RSP(RED_LIGHT_CONTROL);
return 0;
}
uint8_t uFR::setUserInterfaceSignal(uint8_t light_signal_mode, uint8_t beep_signal_mode) {
flushSerial();
sendPacketCMD(USER_INTERFACE_SIGNAL, 0, light_signal_mode, beep_signal_mode);
PROCESS_RSP(USER_INTERFACE_SIGNAL);
return 0;
}
uint8_t uFR::setGreenLightBlinking(bool state) {
flushSerial();
sendPacketCMD(SET_LED_CONFIG, 0, state);
PROCESS_RSP(SET_LED_CONFIG);
return 0;
}
uint8_t uFR::getReaderType(uint8_t readerType[READER_TYPE_SIZE]) {
flushSerial();
sendPacketCMD(GET_READER_TYPE);
PROCESS_RSP(GET_READER_TYPE);
PROCESS_EXT(READER_TYPE_SIZE);
extPacket.copyDataReverse(readerType, 0, READER_TYPE_SIZE);
return 0;
}
uint8_t uFR::getReaderSerial(uint8_t readerSerialNumber[READER_SERIAL_SIZE]) {
flushSerial();
sendPacketCMD(GET_READER_SERIAL);
PROCESS_RSP(GET_READER_SERIAL);
PROCESS_EXT(READER_SERIAL_SIZE);
extPacket.copyDataReverse(readerSerialNumber, 0, READER_SERIAL_SIZE);
return 0;
}
uint8_t uFR::setReaderKey(uint8_t key[READER_KEY_SIZE], uint8_t index) {
flushSerial();
sendPacketCMD(READER_KEY_WRITE, READER_KEY_SIZE + 1, index);
PROCESS_ACK(READER_KEY_WRITE);
sendPacketEXT(key, READER_KEY_SIZE);
PROCESS_RSP(READER_KEY_WRITE);
return 0;
}
uint8_t uFR::getUserData(uint8_t data[USER_DATA_SIZE]) {
flushSerial();
sendPacketCMD(USER_DATA_READ);
PROCESS_RSP(USER_DATA_READ);
PROCESS_EXT(USER_DATA_SIZE);
extPacket.copyData(data, 0, USER_DATA_SIZE);
return 0;
}
uint8_t uFR::setUserData(uint8_t data[USER_DATA_SIZE]) {
flushSerial();
sendPacketCMD(USER_DATA_WRITE, USER_DATA_SIZE + 1);
PROCESS_ACK(USER_DATA_WRITE);
sendPacketEXT(data, USER_DATA_SIZE);
PROCESS_RSP(USER_DATA_WRITE);
return 0;
}
uint8_t uFR::softReset() {
flushSerial();
sendPacketCMD(SELF_RESET);
PROCESS_RSP(SELF_RESET);
return 0;
}
uint8_t uFR::getCardIDSimple(uint8_t cardID[CARD_ID_SIZE], uint8_t *cardType) {
flushSerial();
sendPacketCMD(GET_CARD_ID);
PROCESS_RSP(GET_CARD_ID);
PROCESS_EXT(CARD_ID_SIZE);
extPacket.copyDataReverse(cardID, 0, CARD_ID_SIZE);
if (cardType) *cardType = rspPacket[PAR0_BYTE];
return 0;
}
uint8_t uFR::getCardID(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length, uint8_t *cardType) {
flushSerial();
sendPacketCMD(GET_CARD_ID_EX);
PROCESS_RSP(GET_CARD_ID_EX);
PROCESS_EXT(CARD_ID_EX_SIZE);
//extPacket.copyDataReverse(cardID, 0, rspPacket[PAR1_BYTE]);
//extPacket.copyData is used to make the order of bytes of cardID as on the card
extPacket.copyData(cardID, 0, rspPacket[PAR1_BYTE]);
if (cardType) *cardType = rspPacket[PAR0_BYTE];
if (length) *length = rspPacket[PAR1_BYTE];
return 0;
}
uint8_t uFR::getDesfireUID(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length, uint8_t InternalAESKeyIndexReader, uint32_t AID, uint8_t key_number_in_application) {
uint8_t desfire_uid_size = 7; //as I can see in protocol, there are no length definitions. UID is always 7B.
*length = desfire_uid_size;
uint8_t data_to_send[22];
memset(data_to_send, 0, 22);
data_to_send[0]=1;
data_to_send[1]=InternalAESKeyIndexReader;
data_to_send[18] = *((uint8_t *)&AID);
data_to_send[19] = *((uint8_t *)&AID+1);
data_to_send[20] = *((uint8_t *)&AID+2);
data_to_send[21]= key_number_in_application;
/*
Serial.print("data_to_send = ");
for(int i;i<22;i++)
{
Serial.print(data_to_send[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
*/
flushSerial();
sendPacketCMD(GET_DESFIRE_UID, 23);
PROCESS_ACK(GET_DESFIRE_UID);
sendPacketEXT(data_to_send, 22);
PROCESS_RSP(GET_DESFIRE_UID);
/*
Serial.print("RSP:");
for(int i;i<7;++i)
{
Serial.print(rspPacket[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
*/
if(rspPacket[3]!=12)
{
return PARAMETERS_ERROR;
}
PROCESS_EXT(11);
extPacket.copyData(cardID, 0, desfire_uid_size);
return 0;
}
uint8_t uFR::getDesfireUIDPK(uint8_t cardID[CARD_ID_EX_SIZE], uint8_t *length, uint8_t *AESKey, uint32_t AID, uint8_t key_number_in_application) {
uint8_t desfire_uid_size = 7; //as I can see in protocol, there are no length definitions. UID is always 7B.
*length = desfire_uid_size;
uint8_t data_to_send[22];
memset(data_to_send, 0, 22);
data_to_send[0]=0;
data_to_send[1]=0;
memcpy(&data_to_send[2], AESKey, 16);
data_to_send[18] = *((uint8_t *)&AID);
data_to_send[19] = *((uint8_t *)&AID+1);
data_to_send[20] = *((uint8_t *)&AID+2);
data_to_send[21]= key_number_in_application;
/*
Serial.print("data_to_send = ");
for(int i;i<22;i++)
{
Serial.print(data_to_send[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
*/
flushSerial();
sendPacketCMD(GET_DESFIRE_UID, 23);
PROCESS_ACK(GET_DESFIRE_UID);
sendPacketEXT(data_to_send, 22);
PROCESS_RSP(GET_DESFIRE_UID);
/*
Serial.print("RSP:");
for(int i;i<7;++i)
{
Serial.print(rspPacket[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
*/
if(rspPacket[3]!=12)
{
return PARAMETERS_ERROR;
}
PROCESS_EXT(11);
extPacket.copyData(cardID, 0, desfire_uid_size);
return 0;
}
uint8_t uFR::getCardTypeDLogic(uint8_t *cardType) {
flushSerial();
sendPacketCMD(GET_DLOGIC_CARD_TYPE);
PROCESS_RSP(GET_DLOGIC_CARD_TYPE);
*cardType = rspPacket[PAR0_BYTE];
return 0;
}
// ========================================================================================
// Needs beautifying
const char * TypeDLogicToString(uint8_t type) {
switch (type) {
case 0x00: return "TAG_UNKNOWN"; break;
case 0x01: return "DL_MIFARE_ULTRALIGHT"; break;
case 0x02: return "DL_MIFARE_ULTRALIGHT_EV1_11"; break;
case 0x03: return "DL_MIFARE_ULTRALIGHT_EV1_21"; break;
case 0x04: return "DL_MIFARE_ULTRALIGHT_C"; break;
case 0x05: return "DL_NTAG_203"; break;
case 0x06: return "DL_NTAG_210"; break;
case 0x07: return "DL_NTAG_212"; break;
case 0x08: return "DL_NTAG_213"; break;
case 0x09: return "DL_NTAG_215"; break;
case 0x0A: return "DL_NTAG_216"; break;
case 0x0B: return "DL_MIKRON_MIK640D"; break;
case 0x0C: return "NFC_T2T_GENERIC"; break;
case 0x20: return "DL_MIFARE_MINI"; break;
case 0x21: return "DL_MIFARE_CLASSIC_1K"; break;
case 0x22: return "DL_MIFARE_CLASSIC_4K"; break;
case 0x23: return "DL_MIFARE_PLUS_S_2K"; break;
case 0x24: return "DL_MIFARE_PLUS_S_4K"; break;
case 0x25: return "DL_MIFARE_PLUS_X_2K"; break;
case 0x26: return "DL_MIFARE_PLUS_X_4K"; break;
case 0x27: return "DL_MIFARE_DESFIRE"; break;
case 0x28: return "DL_MIFARE_DESFIRE_EV1_2K"; break;
case 0x29: return "DL_MIFARE_DESFIRE_EV1_4K"; break;
case 0x2A: return "DL_MIFARE_DESFIRE_EV1_8K"; break;
case 0x2B: return "DL_MIFARE_DESFIRE_EV2_2K"; break;
case 0x2C: return "DL_MIFARE_DESFIRE_EV2_4K"; break;
case 0x2D: return "DL_MIFARE_DESFIRE_EV2_8K"; break;
case 0x40: return "DL_GENERIC_ISO14443_4"; break;
case 0x41: return "DL_GENERIC_ISO14443_TYPE_B"; break;
case 0x80: return "DL_IMEI_UID"; break;
default: return "TYPE_ERROR";
}
}
+284
View File
@@ -0,0 +1,284 @@
/// 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();
};
};