frist
This commit is contained in:
@@ -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];
|
||||
}
|
||||
@@ -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)
|
||||
#######################################
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user