mirror of
https://gitlab.com/fabinfra/fabhardware/fabreader3.git
synced 2025-03-12 22:51:42 +01:00
fix V2 build
This commit is contained in:
parent
0f51245914
commit
d0eada7a40
14
Software/.vscode/settings.json
vendored
14
Software/.vscode/settings.json
vendored
@ -11,6 +11,16 @@
|
|||||||
"functional": "cpp",
|
"functional": "cpp",
|
||||||
"*.desfire": "cpp",
|
"*.desfire": "cpp",
|
||||||
"*.old": "cpp",
|
"*.old": "cpp",
|
||||||
"*.deprecated": "cpp"
|
"*.deprecated": "cpp",
|
||||||
}
|
"*.conf": "bitbake",
|
||||||
|
"*.inc": "bitbake"
|
||||||
|
},
|
||||||
|
"python.autoComplete.extraPaths": [
|
||||||
|
"${workspaceFolder}/sources/poky/bitbake/lib",
|
||||||
|
"${workspaceFolder}/sources/poky/meta/lib"
|
||||||
|
],
|
||||||
|
"python.analysis.extraPaths": [
|
||||||
|
"${workspaceFolder}/sources/poky/bitbake/lib",
|
||||||
|
"${workspaceFolder}/sources/poky/meta/lib"
|
||||||
|
]
|
||||||
}
|
}
|
BIN
Software/lib/.DS_Store
vendored
Normal file
BIN
Software/lib/.DS_Store
vendored
Normal file
Binary file not shown.
971
Software/lib/rfid-desfire/Desfire.cpp
Normal file
971
Software/lib/rfid-desfire/Desfire.cpp
Normal file
@ -0,0 +1,971 @@
|
|||||||
|
#include <Desfire.h>
|
||||||
|
|
||||||
|
MFRC522::StatusCode DESFire::PICC_RequestATS(byte *atsBuffer, byte *atsLength)
|
||||||
|
{
|
||||||
|
MFRC522::StatusCode result;
|
||||||
|
|
||||||
|
// Build command buffer
|
||||||
|
atsBuffer[0] = 0xE0; //PICC_CMD_RATS;
|
||||||
|
atsBuffer[1] = 0x50; // FSD=64, CID=0
|
||||||
|
|
||||||
|
// Calculate CRC_A
|
||||||
|
result = PCD_CalculateCRC(atsBuffer, 2, &atsBuffer[2]);
|
||||||
|
if (result != STATUS_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit the buffer and receive the response, validate CRC_A.
|
||||||
|
result = PCD_TransceiveData(atsBuffer, 4, atsBuffer, atsLength, NULL, 0, true);
|
||||||
|
if (result != STATUS_OK) {
|
||||||
|
PICC_HaltA();
|
||||||
|
Serial.println("WTF???");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End PICC_RequestATS()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmits Protocol and Parameter Selection Request (PPS)
|
||||||
|
*
|
||||||
|
* @return STATUS_OK on success, STATUS_??? otherwise.
|
||||||
|
*/
|
||||||
|
MFRC522::StatusCode DESFire::PICC_ProtocolAndParameterSelection(byte cid, ///< The lower nibble indicates the CID of the selected PICC in the range of 0x00 and 0x0E
|
||||||
|
byte pps0, ///< PPS0
|
||||||
|
byte pps1 ///< PPS1
|
||||||
|
) {
|
||||||
|
MFRC522::StatusCode result;
|
||||||
|
|
||||||
|
byte ppsBuffer[5];
|
||||||
|
byte ppsBufferSize = 5;
|
||||||
|
ppsBuffer[0] = 0xD0 | (cid & 0x0F);
|
||||||
|
ppsBuffer[1] = pps0;
|
||||||
|
ppsBuffer[2] = pps1;
|
||||||
|
|
||||||
|
// Calculate CRC_A
|
||||||
|
result = PCD_CalculateCRC(ppsBuffer, 3, &ppsBuffer[3]);
|
||||||
|
if (result != STATUS_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit the buffer and receive the response, validate CRC_A.
|
||||||
|
result = PCD_TransceiveData(ppsBuffer, 5, ppsBuffer, &ppsBufferSize, NULL, 0, true);
|
||||||
|
if (result == STATUS_OK) {
|
||||||
|
// This is how my MFRC522 is by default.
|
||||||
|
// Reading https://www.nxp.com/documents/data_sheet/MFRC522.pdf it seems CRC generation can only be disabled in this mode.
|
||||||
|
if (pps1 == 0x00) {
|
||||||
|
PCD_WriteRegister(TxModeReg, 0x00);
|
||||||
|
PCD_WriteRegister(RxModeReg, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End PICC_ProtocolAndParameterSelection()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see MIFARE_BlockExchangeWithData()
|
||||||
|
*/
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_BlockExchange(mifare_desfire_tag *tag, byte cmd, byte *backData, byte *backLen)
|
||||||
|
{
|
||||||
|
return MIFARE_BlockExchangeWithData(tag, cmd, NULL, NULL, backData, backLen);
|
||||||
|
} // End MIFARE_BlockExchange()
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Frame Format for DESFire APDUs
|
||||||
|
* ==============================
|
||||||
|
*
|
||||||
|
* The frame format for DESFire APDUs is based on only the ISO 14443-4 specifications for block formats.
|
||||||
|
* This is the format used by the example firmware, and seen in Figure 3.
|
||||||
|
* - PCB – Protocol Control Byte, this byte is used to transfer format information about each PDU block.
|
||||||
|
* - CID – Card Identifier field, this byte is used to identify specific tags. It contains a 4 bit CID value as well
|
||||||
|
* as information on the signal strength between the reader and the tag.
|
||||||
|
* - NAD – Node Address field, the example firmware does not support the use of NAD.
|
||||||
|
* - DESFire Command Code – This is discussed in the next section.
|
||||||
|
* - Data Bytes – This field contains all of the Data Bytes for the command
|
||||||
|
*
|
||||||
|
* |-----|-----|-----|---------|------|----------|
|
||||||
|
* | PCB | CID | NAD | Command | Data | Checksum |
|
||||||
|
* |-----|-----|-----|---------|------|----------|
|
||||||
|
*
|
||||||
|
* Documentation: http://read.pudn.com/downloads64/ebook/225463/M305_DESFireISO14443.pdf
|
||||||
|
* http://www.ti.com.cn/cn/lit/an/sloa213/sloa213.pdf
|
||||||
|
*/
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_BlockExchangeWithData(mifare_desfire_tag *tag, byte cmd, byte *sendData, byte *sendLen, byte *backData, byte *backLen)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[64];
|
||||||
|
byte bufferSize = 64;
|
||||||
|
byte sendSize = 3;
|
||||||
|
|
||||||
|
buffer[0] = tag->pcb;
|
||||||
|
buffer[1] = tag->cid;
|
||||||
|
buffer[2] = cmd;
|
||||||
|
|
||||||
|
// Append data if available
|
||||||
|
if (sendData != NULL && sendLen != NULL) {
|
||||||
|
if (*sendLen > 0) {
|
||||||
|
memcpy(&buffer[3], sendData, *sendLen);
|
||||||
|
sendSize = sendSize + *sendLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the PCB
|
||||||
|
if (tag->pcb == 0x0A)
|
||||||
|
tag->pcb = 0x0B;
|
||||||
|
else
|
||||||
|
tag->pcb = 0x0A;
|
||||||
|
|
||||||
|
// Calculate CRC_A
|
||||||
|
result.mfrc522 = PCD_CalculateCRC(buffer, sendSize, &buffer[sendSize]);
|
||||||
|
if (result.mfrc522 != STATUS_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.mfrc522 = PCD_TransceiveData(buffer, sendSize + 2, buffer, &bufferSize);
|
||||||
|
if (result.mfrc522 != STATUS_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the DESFire status code
|
||||||
|
result.desfire = (DesfireStatusCode)(buffer[2]);
|
||||||
|
|
||||||
|
// Copy data to backData and backLen
|
||||||
|
if (backData != NULL && backLen != NULL) {
|
||||||
|
memcpy(backData, &buffer[3], bufferSize - 5);
|
||||||
|
*backLen = bufferSize - 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_BlockExchangeWithData()
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetVersion(mifare_desfire_tag *tag, MIFARE_DESFIRE_Version_t *versionInfo)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
byte versionBuffer[64];
|
||||||
|
byte versionBufferSize = 64;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchange(tag, 0x60, versionBuffer, &versionBufferSize);
|
||||||
|
if (result.mfrc522 == STATUS_OK) {
|
||||||
|
byte hardwareVersion[2];
|
||||||
|
byte storageSize;
|
||||||
|
|
||||||
|
versionInfo->hardware.vendor_id = versionBuffer[0];
|
||||||
|
versionInfo->hardware.type = versionBuffer[1];
|
||||||
|
versionInfo->hardware.subtype = versionBuffer[2];
|
||||||
|
versionInfo->hardware.version_major = versionBuffer[3];
|
||||||
|
versionInfo->hardware.version_minor = versionBuffer[4];
|
||||||
|
versionInfo->hardware.storage_size = versionBuffer[5];
|
||||||
|
versionInfo->hardware.protocol = versionBuffer[6];
|
||||||
|
|
||||||
|
if (result.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
result = MIFARE_BlockExchange(tag, 0xAF, versionBuffer, &versionBufferSize);
|
||||||
|
if (result.mfrc522 == STATUS_OK) {
|
||||||
|
versionInfo->software.vendor_id = versionBuffer[0];
|
||||||
|
versionInfo->software.type = versionBuffer[1];
|
||||||
|
versionInfo->software.subtype = versionBuffer[2];
|
||||||
|
versionInfo->software.version_major = versionBuffer[3];
|
||||||
|
versionInfo->software.version_minor = versionBuffer[4];
|
||||||
|
versionInfo->software.storage_size = versionBuffer[5];
|
||||||
|
versionInfo->software.protocol = versionBuffer[6];
|
||||||
|
} else {
|
||||||
|
Serial.print("Failed to send AF: ");
|
||||||
|
Serial.println(GetStatusCodeName(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
byte nad = 0x60;
|
||||||
|
result = MIFARE_BlockExchange(tag, 0xAF, versionBuffer, &versionBufferSize);
|
||||||
|
if (result.mfrc522 == STATUS_OK) {
|
||||||
|
memcpy(versionInfo->uid, &versionBuffer[0], 7);
|
||||||
|
memcpy(versionInfo->batch_number, &versionBuffer[7], 5);
|
||||||
|
versionInfo->production_week = versionBuffer[12];
|
||||||
|
versionInfo->production_year = versionBuffer[13];
|
||||||
|
} else {
|
||||||
|
Serial.print("Failed to send AF: ");
|
||||||
|
Serial.println(GetStatusCodeName(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
Serial.println("GetVersion(): More data???");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("Version(): Failure.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetVersion
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_SelectApplication(mifare_desfire_tag *tag, mifare_desfire_aid_t *aid)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[64];
|
||||||
|
byte bufferSize = MIFARE_AID_SIZE;
|
||||||
|
|
||||||
|
for (byte i = 0; i < MIFARE_AID_SIZE; i++) {
|
||||||
|
buffer[i] = aid->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchangeWithData(tag, 0x5A, buffer, &bufferSize, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
// keep track of the application
|
||||||
|
memcpy(tag->selected_application, aid->data, MIFARE_AID_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetFileIDs(mifare_desfire_tag *tag, byte *files, byte *filesCount)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte bufferSize = MIFARE_MAX_FILE_COUNT + 5;
|
||||||
|
byte buffer[bufferSize];
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchange(tag, 0x6F, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
*filesCount = bufferSize;
|
||||||
|
memcpy(files, &buffer, *filesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetFileIDs
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetFileSettings(mifare_desfire_tag *tag, byte *file, mifare_desfire_file_settings_t *fileSettings)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[21];
|
||||||
|
byte bufferSize = 21;
|
||||||
|
byte sendLen = 1;
|
||||||
|
|
||||||
|
buffer[0] = *file;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchangeWithData(tag, 0xF5, buffer, &sendLen, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
fileSettings->file_type = buffer[0];
|
||||||
|
fileSettings->communication_settings = buffer[1];
|
||||||
|
fileSettings->access_rights = ((uint16_t)(buffer[2]) << 8) | (buffer[3]);
|
||||||
|
|
||||||
|
switch (buffer[0]) {
|
||||||
|
case MDFT_STANDARD_DATA_FILE:
|
||||||
|
case MDFT_BACKUP_DATA_FILE:
|
||||||
|
fileSettings->settings.standard_file.file_size = ((uint32_t)(buffer[4])) | ((uint32_t)(buffer[5]) << 8) | ((uint32_t)(buffer[6]) << 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDFT_VALUE_FILE_WITH_BACKUP:
|
||||||
|
fileSettings->settings.value_file.lower_limit = ((uint32_t)(buffer[4])) | ((uint32_t)(buffer[5]) << 8) | ((uint32_t)(buffer[6]) << 16) | ((uint32_t)(buffer[7]) << 24);
|
||||||
|
fileSettings->settings.value_file.upper_limit = ((uint32_t)(buffer[8])) | ((uint32_t)(buffer[9]) << 8) | ((uint32_t)(buffer[10]) << 16) | ((uint32_t)(buffer[11]) << 24);
|
||||||
|
fileSettings->settings.value_file.limited_credit_value = ((uint32_t)(buffer[12])) | ((uint32_t)(buffer[13]) << 8) | ((uint32_t)(buffer[14]) << 16) | ((uint32_t)(buffer[15]) << 24);
|
||||||
|
fileSettings->settings.value_file.limited_credit_enabled = buffer[16];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDFT_LINEAR_RECORD_FILE_WITH_BACKUP:
|
||||||
|
case MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP:
|
||||||
|
fileSettings->settings.record_file.record_size = ((uint32_t)(buffer[4])) | ((uint32_t)(buffer[5]) << 8) | ((uint32_t)(buffer[6]) << 16);
|
||||||
|
fileSettings->settings.record_file.max_number_of_records = ((uint32_t)(buffer[7])) | ((uint32_t)(buffer[8]) << 8) | ((uint32_t)(buffer[9]) << 16);
|
||||||
|
fileSettings->settings.record_file.current_number_of_records = ((uint32_t)(buffer[10])) | ((uint32_t)(buffer[11]) << 8) | ((uint32_t)(buffer[12]) << 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//return FAIL;
|
||||||
|
result.mfrc522 = STATUS_ERROR;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetFileSettings
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetKeySettings(mifare_desfire_tag *tag, byte *settings, byte *maxKeys)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[7];
|
||||||
|
byte bufferSize = 7;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchange(tag, 0x45, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
*settings = buffer[0];
|
||||||
|
*maxKeys = buffer[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetKeySettings()
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetKeyVersion(mifare_desfire_tag *tag, byte key, byte *version)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[6];
|
||||||
|
byte bufferSize = 6;
|
||||||
|
byte sendLen = 1;
|
||||||
|
|
||||||
|
buffer[0] = key;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchangeWithData(tag, 0x64, buffer, &sendLen, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
*version = buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_ReadData(mifare_desfire_tag *tag, byte fid, uint32_t offset, uint32_t length, byte *backData, size_t *backLen)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[64];
|
||||||
|
byte bufferSize = 64;
|
||||||
|
byte sendLen = 7;
|
||||||
|
size_t outSize = 0;
|
||||||
|
|
||||||
|
// file ID
|
||||||
|
buffer[0] = fid;
|
||||||
|
// offset
|
||||||
|
buffer[1] = (offset & 0x00000F);
|
||||||
|
buffer[2] = (offset & 0x00FF00) >> 8;
|
||||||
|
buffer[3] = (offset & 0xFF0000) >> 16;
|
||||||
|
// length
|
||||||
|
buffer[4] = (length & 0x0000FF);
|
||||||
|
buffer[5] = (length & 0x00FF00) >> 8;
|
||||||
|
buffer[6] = (length & 0xFF0000) >> 16;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchangeWithData(tag, 0xBD, buffer, &sendLen, buffer, &bufferSize);
|
||||||
|
if (result.mfrc522 == STATUS_OK) {
|
||||||
|
do {
|
||||||
|
// Copy the data
|
||||||
|
memcpy(backData + outSize, buffer, bufferSize);
|
||||||
|
outSize += bufferSize;
|
||||||
|
*backLen = outSize;
|
||||||
|
|
||||||
|
if (result.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
result = MIFARE_BlockExchange(tag, 0xAF, buffer, &bufferSize);
|
||||||
|
}
|
||||||
|
} while (result.mfrc522 == STATUS_OK && result.desfire == MF_ADDITIONAL_FRAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetValue(mifare_desfire_tag *tag, byte fid, int32_t *value)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
byte buffer[MFRC522::FIFO_SIZE];
|
||||||
|
byte bufferSize = MFRC522::FIFO_SIZE;
|
||||||
|
byte sendLen = 1;
|
||||||
|
size_t outSize = 0;
|
||||||
|
|
||||||
|
buffer[0] = fid;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchangeWithData(tag, 0x6C, buffer, &sendLen, buffer, &bufferSize);
|
||||||
|
if (IsStatusCodeOK(result)) {
|
||||||
|
*value = ((uint32_t)buffer[0] | ((uint32_t)buffer[1] << 8) | ((uint32_t)buffer[2] << 16) | ((uint32_t)buffer[3] << 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetValue()
|
||||||
|
|
||||||
|
DESFire::StatusCode DESFire::MIFARE_DESFIRE_GetApplicationIds(mifare_desfire_tag *tag, mifare_desfire_aid_t *aids, byte *applicationCount)
|
||||||
|
{
|
||||||
|
StatusCode result;
|
||||||
|
|
||||||
|
// MIFARE_MAX_APPLICATION_COUNT * MIFARE_AID_SIZE + PCB (1 byte) + CID (1 byte) + Checksum (2 bytes)
|
||||||
|
// I also add an extra byte in case NAD is needed
|
||||||
|
byte bufferSize = (MIFARE_MAX_APPLICATION_COUNT * MIFARE_AID_SIZE) + 5;
|
||||||
|
byte buffer[bufferSize];
|
||||||
|
byte aidBuffer[MIFARE_MAX_APPLICATION_COUNT * MIFARE_AID_SIZE];
|
||||||
|
byte aidBufferSize = 0;
|
||||||
|
|
||||||
|
result = MIFARE_BlockExchange(tag, 0x6A, buffer, &bufferSize);
|
||||||
|
if (result.mfrc522 != STATUS_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// MIFARE_MAX_APPLICATION_COUNT (28) * MIFARE_AID_SIZE + PCB (1) + CID (1) + Checksum (2) = 88
|
||||||
|
// Even if the NAD byte is not present we could GET a 0xAF response.
|
||||||
|
if (result.desfire == MF_OPERATION_OK && bufferSize == 0x00) {
|
||||||
|
// Empty application list
|
||||||
|
*applicationCount = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(aidBuffer, buffer, bufferSize);
|
||||||
|
aidBufferSize = bufferSize;
|
||||||
|
|
||||||
|
while (result.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
bufferSize = (MIFARE_MAX_APPLICATION_COUNT * MIFARE_AID_SIZE) + 5;
|
||||||
|
result = MIFARE_BlockExchange(tag, 0xAF, buffer, &bufferSize);
|
||||||
|
if (result.mfrc522 != STATUS_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Make sure we have space (Just in case)
|
||||||
|
if ((aidBufferSize + bufferSize) > (MIFARE_MAX_APPLICATION_COUNT * MIFARE_AID_SIZE)) {
|
||||||
|
result.mfrc522 = STATUS_NO_ROOM;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the new data
|
||||||
|
memcpy(aidBuffer + aidBufferSize, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Applications are identified with a 3 byte application identifier(AID)
|
||||||
|
// we also received the status byte:
|
||||||
|
if ((aidBufferSize % 3) != 0) {
|
||||||
|
Serial.println(F("MIFARE_DESFIRE_GetApplicationIds(): Data is not a modulus of 3."));
|
||||||
|
// TODO: Some kind of failure
|
||||||
|
result.mfrc522 = STATUS_ERROR;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
*applicationCount = aidBufferSize / 3;
|
||||||
|
|
||||||
|
for (byte i = 0; i < *applicationCount; i++) {
|
||||||
|
aids[i].data[0] = aidBuffer[(i * 3)];
|
||||||
|
aids[i].data[1] = aidBuffer[1 + (i * 3)];
|
||||||
|
aids[i].data[2] = aidBuffer[2 + (i * 3)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} // End MIFARE_DESFIRE_GetApplicationIds()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a __FlashStringHelper pointer to a status code name.
|
||||||
|
*
|
||||||
|
* @return const __FlashStringHelper *
|
||||||
|
*/
|
||||||
|
const __FlashStringHelper *DESFire::GetStatusCodeName(StatusCode code)
|
||||||
|
{
|
||||||
|
if (code.mfrc522 != MFRC522::STATUS_OK) {
|
||||||
|
return MFRC522::GetStatusCodeName(code.mfrc522);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code.desfire) {
|
||||||
|
case MF_OPERATION_OK: return F("Successful operation.");
|
||||||
|
case MF_NO_CHANGES: return F("No changes done to backup files.");
|
||||||
|
case MF_OUT_OF_EEPROM_ERROR: return F("Insufficient NV-Mem. to complete cmd.");
|
||||||
|
case MF_ILLEGAL_COMMAND_CODE: return F("Command code not supported.");
|
||||||
|
case MF_INTEGRITY_ERROR: return F("CRC or MAC does not match data.");
|
||||||
|
case MF_NO_SUCH_KEY: return F("Invalid key number specified.");
|
||||||
|
case MF_LENGTH_ERROR: return F("Length of command string invalid.");
|
||||||
|
case MF_PERMISSION_ERROR: return F("Curr conf/status doesnt allow cmd.");
|
||||||
|
case MF_PARAMETER_ERROR: return F("Value of the parameter(s) invalid.");
|
||||||
|
case MF_APPLICATION_NOT_FOUND: return F("Requested AID not present on PICC.");
|
||||||
|
case MF_APPL_INTEGRITY_ERROR: return F("Unrecoverable err within app.");
|
||||||
|
case MF_AUTHENTICATION_ERROR: return F("Current authentication status doesn't allow requested command.");
|
||||||
|
case MF_ADDITIONAL_FRAME: return F("Additional data frame to be sent.");
|
||||||
|
case MF_BOUNDARY_ERROR: return F("Attempt to read/write beyond limits.");
|
||||||
|
case MF_PICC_INTEGRITY_ERROR: return F("Unrecoverable error within PICC.");
|
||||||
|
case MF_COMMAND_ABORTED: return F("Previous command not fully completed.");
|
||||||
|
case MF_PICC_DISABLED_ERROR: return F("PICC disabled by unrecoverable error.");
|
||||||
|
case MF_COUNT_ERROR: return F("Cant create more apps, already @ 28.");
|
||||||
|
case MF_DUPLICATE_ERROR: return F("Cant create dup. file/app.");
|
||||||
|
case MF_EEPROM_ERROR: return F("Couldnt complete NV-write operation.");
|
||||||
|
case MF_FILE_NOT_FOUND: return F("Specified file number doesnt exist.");
|
||||||
|
case MF_FILE_INTEGRITY_ERROR: return F("Unrecoverable error within file.");
|
||||||
|
default: return F("Unknown error");
|
||||||
|
}
|
||||||
|
} // End GetStatusCodeName()
|
||||||
|
|
||||||
|
const __FlashStringHelper *DESFire::GetFileTypeName(mifare_desfire_file_types fileType)
|
||||||
|
{
|
||||||
|
switch (fileType) {
|
||||||
|
case MDFT_STANDARD_DATA_FILE: return F("Standard data file.");
|
||||||
|
case MDFT_BACKUP_DATA_FILE: return F("Backup data file.");
|
||||||
|
case MDFT_VALUE_FILE_WITH_BACKUP: return F("Value file with backup.");
|
||||||
|
case MDFT_LINEAR_RECORD_FILE_WITH_BACKUP: return F("Linear record file with backup.");
|
||||||
|
case MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP: return F("Cyclic record file with backup.");
|
||||||
|
default: return F("Unknown file type.");
|
||||||
|
}
|
||||||
|
} // End GetFileTypeName()
|
||||||
|
|
||||||
|
const __FlashStringHelper *DESFire::GetCommunicationModeName(mifare_desfire_communication_modes communicationMode)
|
||||||
|
{
|
||||||
|
switch (communicationMode) {
|
||||||
|
case MDCM_PLAIN: return(F("Plain Communication."));
|
||||||
|
case MDCM_MACED: return(F("Plain Comm secured by DES/3DES MACing."));
|
||||||
|
case MDCM_ENCIPHERED: return(F("Fully DES/3DES enciphered comm."));
|
||||||
|
default: return F("Unknown communication mode.");
|
||||||
|
}
|
||||||
|
} // End GetCommunicationModeName()
|
||||||
|
|
||||||
|
bool DESFire::IsStatusCodeOK(StatusCode code)
|
||||||
|
{
|
||||||
|
if (code.mfrc522 != STATUS_OK)
|
||||||
|
return false;
|
||||||
|
if (code.desfire != MF_OPERATION_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} // End IsStatusCodeOK();
|
||||||
|
|
||||||
|
void DESFire::PICC_DumpMifareDesfireMasterKey(mifare_desfire_tag *tag)
|
||||||
|
{
|
||||||
|
StatusCode response;
|
||||||
|
mifare_desfire_aid_t aid;
|
||||||
|
|
||||||
|
aid.data[0] = 0x00;
|
||||||
|
aid.data[1] = 0x00;
|
||||||
|
aid.data[2] = 0x00;
|
||||||
|
|
||||||
|
Serial.println(F("-- Desfire Master Key ---------------------------------------"));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
// Select the current application.
|
||||||
|
response = MIFARE_DESFIRE_SelectApplication(tag, &aid);
|
||||||
|
if (!IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Error: Failed to select application."));
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Key settings
|
||||||
|
byte keySettings;
|
||||||
|
byte keyCount = 0;
|
||||||
|
byte keyVersion;
|
||||||
|
|
||||||
|
response = MIFARE_DESFIRE_GetKeySettings(tag, &keySettings, &keyCount);
|
||||||
|
if (IsStatusCodeOK(response)) {
|
||||||
|
Serial.print(F(" Key settings : 0x"));
|
||||||
|
if (keySettings < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(keySettings, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Max num keys : "));
|
||||||
|
Serial.println(keyCount);
|
||||||
|
|
||||||
|
// Output key versions
|
||||||
|
if (keyCount > 0) {
|
||||||
|
Serial.println(F(" ----------------------------------------------------------"));
|
||||||
|
Serial.println(F(" Key Versions"));
|
||||||
|
|
||||||
|
// Get key versions (No output will be outputed later)
|
||||||
|
for (byte ixKey = 0; ixKey < keyCount; ixKey++) {
|
||||||
|
response = MIFARE_DESFIRE_GetKeyVersion(tag, ixKey, &keyVersion);
|
||||||
|
Serial.print(F(" Key 0x"));
|
||||||
|
if (ixKey < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(ixKey, HEX);
|
||||||
|
Serial.print(F(" : "));
|
||||||
|
|
||||||
|
if (IsStatusCodeOK(response)) {
|
||||||
|
Serial.print(F("0x"));
|
||||||
|
if (keyVersion < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(keyVersion, HEX);
|
||||||
|
} else {
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println(F(" Error: Failed to get application key settings."));
|
||||||
|
// Just to be sure..
|
||||||
|
keyCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
} // End PICC_DumpMifareDesfireMasterKey()
|
||||||
|
|
||||||
|
void DESFire::PICC_DumpMifareDesfireVersion(mifare_desfire_tag *tag, MIFARE_DESFIRE_Version_t *versionInfo)
|
||||||
|
{
|
||||||
|
Serial.println(F("-- Desfire Information --------------------------------------"));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
switch (versionInfo->hardware.version_major) {
|
||||||
|
case 0x00:
|
||||||
|
Serial.println(F(" Card type : MIFARE DESFire (MF3ICD40)"));
|
||||||
|
switch (versionInfo->hardware.storage_size) {
|
||||||
|
case 0x16:
|
||||||
|
Serial.print(F(" 2K"));
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
Serial.print(F(" 4K"));
|
||||||
|
break;
|
||||||
|
case 0x1A:
|
||||||
|
Serial.print(F(" 8K"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
Serial.print(F(" Card type : MIFARE DESFire EV1"));
|
||||||
|
switch (versionInfo->hardware.storage_size) {
|
||||||
|
case 0x16:
|
||||||
|
Serial.print(F(" 2K"));
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
Serial.print(F(" 4K"));
|
||||||
|
break;
|
||||||
|
case 0x1A:
|
||||||
|
Serial.print(F(" 8K"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
Serial.print(F(" Card type : MIFARE DESFire EV2"));
|
||||||
|
switch (versionInfo->hardware.storage_size) {
|
||||||
|
case 0x16:
|
||||||
|
Serial.print(F(" 2K"));
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
Serial.print(F(" 4K"));
|
||||||
|
break;
|
||||||
|
case 0x1A:
|
||||||
|
Serial.print(F(" 8K"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UID
|
||||||
|
Serial.print(F(" UID :"));
|
||||||
|
for (byte i = 0; i < 7; i++) {
|
||||||
|
if (versionInfo->uid[i] < 0x10)
|
||||||
|
Serial.print(F(" 0"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.print(versionInfo->uid[i], HEX);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Batch
|
||||||
|
Serial.print(F(" Batch number :"));
|
||||||
|
for (byte i = 0; i < 5; i++) {
|
||||||
|
if (versionInfo->batch_number[i] < 0x10)
|
||||||
|
Serial.print(F(" 0"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.print(versionInfo->batch_number[i], HEX);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.print(F(" Production week : 0x"));
|
||||||
|
if (versionInfo->production_week < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->production_week, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Production year : 0x"));
|
||||||
|
if (versionInfo->production_year < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->production_year, HEX);
|
||||||
|
|
||||||
|
Serial.println(F(" ----------------------------------------------------------"));
|
||||||
|
Serial.println(F(" Hardware Information"));
|
||||||
|
Serial.print(F(" Vendor ID : 0x"));
|
||||||
|
if (versionInfo->hardware.vendor_id < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(versionInfo->hardware.vendor_id, HEX);
|
||||||
|
if (versionInfo->hardware.vendor_id == 0x04)
|
||||||
|
Serial.print(F(" (NXP)"));
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.print(F(" Type : 0x"));
|
||||||
|
if (versionInfo->hardware.type < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->hardware.type, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Subtype : 0x"));
|
||||||
|
if (versionInfo->hardware.subtype < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->hardware.subtype, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Version : "));
|
||||||
|
Serial.print(versionInfo->hardware.version_major);
|
||||||
|
Serial.print(F("."));
|
||||||
|
Serial.println(versionInfo->hardware.version_minor);
|
||||||
|
|
||||||
|
Serial.print(F(" Storage size : 0x"));
|
||||||
|
if (versionInfo->hardware.storage_size < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(versionInfo->hardware.storage_size, HEX);
|
||||||
|
switch (versionInfo->hardware.storage_size) {
|
||||||
|
case 0x16:
|
||||||
|
Serial.print(F(" (2048 bytes)"));
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
Serial.print(F(" (4096 bytes)"));
|
||||||
|
break;
|
||||||
|
case 0x1A:
|
||||||
|
Serial.print(F(" (8192 bytes)"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.print(F(" Protocol : 0x"));
|
||||||
|
if (versionInfo->hardware.protocol < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->hardware.protocol, HEX);
|
||||||
|
|
||||||
|
Serial.println(F(" ----------------------------------------------------------"));
|
||||||
|
Serial.println(F(" Software Information"));
|
||||||
|
Serial.print(F(" Vendor ID : 0x"));
|
||||||
|
if (versionInfo->software.vendor_id < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(versionInfo->software.vendor_id, HEX);
|
||||||
|
if (versionInfo->software.vendor_id == 0x04)
|
||||||
|
Serial.print(F(" (NXP)"));
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.print(F(" Type : 0x"));
|
||||||
|
if (versionInfo->software.type < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->software.type, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Subtype : 0x"));
|
||||||
|
if (versionInfo->software.subtype < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->software.subtype, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Version : "));
|
||||||
|
Serial.print(versionInfo->software.version_major);
|
||||||
|
Serial.print(F("."));
|
||||||
|
Serial.println(versionInfo->software.version_minor);
|
||||||
|
|
||||||
|
Serial.print(F(" Storage size : 0x"));
|
||||||
|
if (versionInfo->software.storage_size < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(versionInfo->software.storage_size, HEX);
|
||||||
|
switch (versionInfo->software.storage_size) {
|
||||||
|
case 0x16:
|
||||||
|
Serial.print(F(" (2048 bytes)"));
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
Serial.print(F(" (4096 bytes)"));
|
||||||
|
break;
|
||||||
|
case 0x1A:
|
||||||
|
Serial.print(F(" (8192 bytes)"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.print(F(" Protocol : 0x"));
|
||||||
|
if (versionInfo->software.protocol < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(versionInfo->software.protocol, HEX);
|
||||||
|
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DESFire::PICC_DumpMifareDesfireApplication(mifare_desfire_tag *tag, mifare_desfire_aid_t *aid)
|
||||||
|
{
|
||||||
|
StatusCode response;
|
||||||
|
|
||||||
|
Serial.println(F("-- Desfire Application --------------------------------------"));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
Serial.print(F(" AID :"));
|
||||||
|
for (byte i = 0; i < 3; i++) {
|
||||||
|
if (aid->data[i] < 0x10)
|
||||||
|
Serial.print(F(" 0"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.print(aid->data[i], HEX);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Select the current application.
|
||||||
|
response = MIFARE_DESFIRE_SelectApplication(tag, aid);
|
||||||
|
if (!IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Error: Failed to select application."));
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Key settings
|
||||||
|
byte keySettings;
|
||||||
|
byte keyCount = 0;
|
||||||
|
byte keyVersion[16];
|
||||||
|
|
||||||
|
response = MIFARE_DESFIRE_GetKeySettings(tag, &keySettings, &keyCount);
|
||||||
|
if (IsStatusCodeOK(response)) {
|
||||||
|
Serial.print(F(" Key settings : 0x"));
|
||||||
|
if (keySettings < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(keySettings, HEX);
|
||||||
|
|
||||||
|
Serial.print(F(" Max num keys : "));
|
||||||
|
Serial.println(keyCount);
|
||||||
|
|
||||||
|
// Get key versions (No output will be outputed later)
|
||||||
|
for (byte ixKey = 0; ixKey < keyCount; ixKey++) {
|
||||||
|
response = MIFARE_DESFIRE_GetKeyVersion(tag, ixKey, &(keyVersion[ixKey]));
|
||||||
|
if (!IsStatusCodeOK(response))
|
||||||
|
keyVersion[ixKey] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial.println(F(" Error: Failed to get application key settings."));
|
||||||
|
// Just to be sure..
|
||||||
|
keyCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the files
|
||||||
|
byte files[MIFARE_MAX_FILE_COUNT];
|
||||||
|
byte filesCount = 0;
|
||||||
|
response = MIFARE_DESFIRE_GetFileIDs(tag, files, &filesCount);
|
||||||
|
if (!IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F(" Error: Failed to get application file IDs."));
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of files
|
||||||
|
Serial.print(F(" Num. Files : "));
|
||||||
|
Serial.println(filesCount);
|
||||||
|
|
||||||
|
// Output key versions
|
||||||
|
if (keyCount > 0) {
|
||||||
|
Serial.println(F(" ----------------------------------------------------------"));
|
||||||
|
Serial.println(F(" Key Versions"));
|
||||||
|
for (byte ixKey = 0; ixKey < keyCount; ixKey++) {
|
||||||
|
Serial.print(F(" Key 0x"));
|
||||||
|
if (ixKey < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(ixKey, HEX);
|
||||||
|
Serial.print(F(" : 0x"));
|
||||||
|
if (keyVersion[ixKey] < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(keyVersion[ixKey], HEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (byte i = 0; i < filesCount; i++) {
|
||||||
|
Serial.println(F(" ----------------------------------------------------------"));
|
||||||
|
Serial.println(F(" File Information"));
|
||||||
|
Serial.print(F(" File ID : 0x"));
|
||||||
|
if (files[i] < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.println(files[i], HEX);
|
||||||
|
|
||||||
|
// Get file settings
|
||||||
|
mifare_desfire_file_settings_t fileSettings;
|
||||||
|
|
||||||
|
response = MIFARE_DESFIRE_GetFileSettings(tag, &(files[i]), &fileSettings);
|
||||||
|
if (IsStatusCodeOK(response)) {
|
||||||
|
Serial.print(F(" File Type : 0x"));
|
||||||
|
if (fileSettings.file_type < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(fileSettings.file_type, HEX);
|
||||||
|
Serial.print(F(" ("));
|
||||||
|
Serial.print(GetFileTypeName((mifare_desfire_file_types)fileSettings.file_type));
|
||||||
|
Serial.println(F(")"));
|
||||||
|
|
||||||
|
Serial.print(F(" Communication : 0x"));
|
||||||
|
if (fileSettings.communication_settings < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(fileSettings.communication_settings, HEX);
|
||||||
|
Serial.print(F(" ("));
|
||||||
|
Serial.print(GetCommunicationModeName((mifare_desfire_communication_modes)fileSettings.communication_settings));
|
||||||
|
Serial.println(F(")"));
|
||||||
|
|
||||||
|
Serial.print(F(" Access rights : 0x"));
|
||||||
|
Serial.println(fileSettings.access_rights, HEX);
|
||||||
|
|
||||||
|
switch (fileSettings.file_type) {
|
||||||
|
case MDFT_STANDARD_DATA_FILE:
|
||||||
|
case MDFT_BACKUP_DATA_FILE:
|
||||||
|
Serial.print(F(" File Size : "));
|
||||||
|
Serial.print(fileSettings.settings.standard_file.file_size);
|
||||||
|
Serial.println(F(" bytes"));
|
||||||
|
break;
|
||||||
|
case MDFT_VALUE_FILE_WITH_BACKUP:
|
||||||
|
Serial.print(F(" Lower Limit : "));
|
||||||
|
Serial.println(fileSettings.settings.value_file.lower_limit);
|
||||||
|
Serial.print(F(" Upper Limit : "));
|
||||||
|
Serial.println(fileSettings.settings.value_file.upper_limit);
|
||||||
|
Serial.print(F(" Limited credit : "));
|
||||||
|
Serial.println(fileSettings.settings.value_file.limited_credit_value);
|
||||||
|
Serial.print(F(" Limited credit : "));
|
||||||
|
|
||||||
|
if (fileSettings.settings.value_file.limited_credit_enabled == 0x00)
|
||||||
|
Serial.print(F("Disabled ("));
|
||||||
|
else
|
||||||
|
Serial.print(F("Enabled (0x"));
|
||||||
|
if (fileSettings.settings.value_file.limited_credit_enabled < 0x10)
|
||||||
|
Serial.print(F("0"));
|
||||||
|
Serial.print(fileSettings.settings.value_file.limited_credit_enabled, HEX);
|
||||||
|
Serial.println(F(")"));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDFT_LINEAR_RECORD_FILE_WITH_BACKUP:
|
||||||
|
case MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP:
|
||||||
|
Serial.print(F(" Record size : "));
|
||||||
|
Serial.println(fileSettings.settings.record_file.record_size);
|
||||||
|
Serial.print(F(" max num records: "));
|
||||||
|
Serial.println(fileSettings.settings.record_file.max_number_of_records);
|
||||||
|
Serial.print(F(" num records : "));
|
||||||
|
Serial.println(fileSettings.settings.record_file.current_number_of_records);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fileSettings.file_type) {
|
||||||
|
case MDFT_STANDARD_DATA_FILE:
|
||||||
|
case MDFT_BACKUP_DATA_FILE:
|
||||||
|
{
|
||||||
|
// Get file data
|
||||||
|
byte fileContent[fileSettings.settings.standard_file.file_size];
|
||||||
|
size_t fileContentLength = fileSettings.settings.standard_file.file_size;
|
||||||
|
response = MIFARE_DESFIRE_ReadData(tag, files[i], 0, fileSettings.settings.standard_file.file_size, fileContent, &fileContentLength);
|
||||||
|
if (response.mfrc522 == STATUS_OK) {
|
||||||
|
Serial.println(F(" ------------------------------------------------------"));
|
||||||
|
Serial.println(F(" Data"));
|
||||||
|
|
||||||
|
if (response.desfire == MF_OPERATION_OK || response.desfire == MF_ADDITIONAL_FRAME) {
|
||||||
|
for (unsigned int iByte = 0; iByte < fileContentLength; iByte++) {
|
||||||
|
if ((iByte % 16) == 0) {
|
||||||
|
if (iByte != 0)
|
||||||
|
Serial.println();
|
||||||
|
Serial.print(F(" "));
|
||||||
|
}
|
||||||
|
if (fileContent[iByte] < 0x10)
|
||||||
|
Serial.print(F(" 0"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.print(fileContent[iByte], HEX);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MDFT_VALUE_FILE_WITH_BACKUP:
|
||||||
|
{
|
||||||
|
// Get value
|
||||||
|
int32_t fileValue;
|
||||||
|
response = MIFARE_DESFIRE_GetValue(tag, files[i], &fileValue);
|
||||||
|
Serial.print(F(" Value : "));
|
||||||
|
if (IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(fileValue);
|
||||||
|
} else {
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial.println(F(" Error: Failed to get file settings."));
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.println(GetStatusCodeName(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.println(F("-------------------------------------------------------------"));
|
||||||
|
}
|
187
Software/lib/rfid-desfire/Desfire.h
Normal file
187
Software/lib/rfid-desfire/Desfire.h
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#ifndef DESFIRE_h
|
||||||
|
#define DESFIRE_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <MFRC522.h>
|
||||||
|
|
||||||
|
/* --------------------------------------
|
||||||
|
* DESFire Logical Structure
|
||||||
|
* --------------------------------------
|
||||||
|
*/
|
||||||
|
#define MIFARE_MAX_APPLICATION_COUNT 28 /* max applications on one PICC */
|
||||||
|
#define MIFARE_MAX_FILE_COUNT 16 /* max # of files in each application */
|
||||||
|
#define MIFARE_UID_BYTES 7 /* number of UID bytes */
|
||||||
|
#define MIFARE_AID_SIZE 3 /* number of AID bytes */
|
||||||
|
|
||||||
|
class DESFire : public MFRC522 {
|
||||||
|
public:
|
||||||
|
// DESFire Status and Error Codes.
|
||||||
|
enum DesfireStatusCode : byte {
|
||||||
|
MF_OPERATION_OK = 0x00, /* successful operation */
|
||||||
|
MF_NO_CHANGES = 0x0C, /* no changes done to backup files */
|
||||||
|
MF_OUT_OF_EEPROM_ERROR = 0x0E, /* insufficient NV-Mem. to complete cmd */
|
||||||
|
MF_ILLEGAL_COMMAND_CODE = 0x1C, /* command code not supported */
|
||||||
|
MF_INTEGRITY_ERROR = 0x1E, /* CRC or MAC does not match data */
|
||||||
|
MF_NO_SUCH_KEY = 0x40, /* invalid key number specified */
|
||||||
|
MF_LENGTH_ERROR = 0x7E, /* length of command string invalid */
|
||||||
|
MF_PERMISSION_ERROR = 0x9D, /* curr conf/status doesnt allow cmd */
|
||||||
|
MF_PARAMETER_ERROR = 0x9E, /* value of the parameter(s) invalid */
|
||||||
|
MF_APPLICATION_NOT_FOUND = 0xA0, /* requested AID not present on PICC */
|
||||||
|
MF_APPL_INTEGRITY_ERROR = 0xA1, /* unrecoverable err within app */
|
||||||
|
MF_AUTHENTICATION_ERROR = 0xAE, /* cur auth status doesnt allow req cmd */
|
||||||
|
MF_ADDITIONAL_FRAME = 0xAF, /* additional data frame to be sent */
|
||||||
|
MF_BOUNDARY_ERROR = 0xBE, /* attempt to read/write beyond limits */
|
||||||
|
MF_PICC_INTEGRITY_ERROR = 0xC1, /* unrecoverable error within PICC */
|
||||||
|
MF_COMMAND_ABORTED = 0xCA, /* previous command not fully completed */
|
||||||
|
MF_PICC_DISABLED_ERROR = 0xCD, /* PICC disabled by unrecoverable error */
|
||||||
|
MF_COUNT_ERROR = 0xCE, /* cant create more apps, already @ 28 */
|
||||||
|
MF_DUPLICATE_ERROR = 0xDE, /* cant create dup. file/app */
|
||||||
|
MF_EEPROM_ERROR = 0xEE, /* couldnt complete NV-write operation */
|
||||||
|
MF_FILE_NOT_FOUND = 0xF0, /* specified file number doesnt exist */
|
||||||
|
MF_FILE_INTEGRITY_ERROR = 0xF1 /* unrecoverable error within file */
|
||||||
|
};
|
||||||
|
|
||||||
|
// DESFire file types
|
||||||
|
enum mifare_desfire_file_types : byte {
|
||||||
|
MDFT_STANDARD_DATA_FILE = 0x00,
|
||||||
|
MDFT_BACKUP_DATA_FILE = 0x01,
|
||||||
|
MDFT_VALUE_FILE_WITH_BACKUP = 0x02,
|
||||||
|
MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03,
|
||||||
|
MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
// DESFire communication modes
|
||||||
|
enum mifare_desfire_communication_modes : byte {
|
||||||
|
MDCM_PLAIN = 0x00, /* Plain Communication */
|
||||||
|
MDCM_MACED = 0x01, /* Plain Comm secured by DES/3DES MACing */
|
||||||
|
MDCM_ENCIPHERED = 0x03 /* Fully DES/3DES enciphered comm. */
|
||||||
|
};
|
||||||
|
|
||||||
|
// A struct used for passing a MIFARE DESFire Version
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
uint8_t vendor_id;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t subtype;
|
||||||
|
uint8_t version_major;
|
||||||
|
uint8_t version_minor;
|
||||||
|
uint8_t storage_size;
|
||||||
|
uint8_t protocol;
|
||||||
|
} hardware;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t vendor_id;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t subtype;
|
||||||
|
uint8_t version_major;
|
||||||
|
uint8_t version_minor;
|
||||||
|
uint8_t storage_size;
|
||||||
|
uint8_t protocol;
|
||||||
|
} software;
|
||||||
|
|
||||||
|
uint8_t uid[7];
|
||||||
|
uint8_t batch_number[5];
|
||||||
|
uint8_t production_week;
|
||||||
|
uint8_t production_year;
|
||||||
|
} MIFARE_DESFIRE_Version_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[MIFARE_AID_SIZE];
|
||||||
|
} mifare_desfire_aid_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MFRC522::StatusCode mfrc522;
|
||||||
|
DesfireStatusCode desfire;
|
||||||
|
} StatusCode;
|
||||||
|
|
||||||
|
// A struct used for passing a MIFARE DESFire Version
|
||||||
|
typedef struct {
|
||||||
|
uint8_t file_type;
|
||||||
|
uint8_t communication_settings;
|
||||||
|
uint16_t access_rights;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t file_size;
|
||||||
|
} standard_file;
|
||||||
|
struct {
|
||||||
|
int32_t lower_limit;
|
||||||
|
int32_t upper_limit;
|
||||||
|
int32_t limited_credit_value;
|
||||||
|
uint8_t limited_credit_enabled;
|
||||||
|
} value_file;
|
||||||
|
struct {
|
||||||
|
uint32_t record_size;
|
||||||
|
uint32_t max_number_of_records;
|
||||||
|
uint32_t current_number_of_records;
|
||||||
|
} record_file; /* linear and cyclic record files */
|
||||||
|
} settings;
|
||||||
|
} mifare_desfire_file_settings_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
byte cid; // Card ID
|
||||||
|
byte pcb; // Protocol Control Byte
|
||||||
|
byte selected_application[MIFARE_AID_SIZE];
|
||||||
|
} mifare_desfire_tag;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for setting up the Arduino
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
explicit DESFire() : MFRC522() {};
|
||||||
|
explicit DESFire(byte resetPowerDownPin) : MFRC522(resetPowerDownPin) {};
|
||||||
|
explicit DESFire(byte chipSelectPin, byte resetPowerDownPin) : MFRC522(chipSelectPin, resetPowerDownPin) {};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ISO/IEC 14443 functions not currentlly present in MFRC522 library
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
MFRC522::StatusCode PICC_RequestATS(byte *atsBuffer, byte *atsLength);
|
||||||
|
MFRC522::StatusCode PICC_ProtocolAndParameterSelection(byte cid, byte pps0, byte pps1 = 0x00);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for MIFARE DESFire
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode MIFARE_DESFIRE_GetVersion(mifare_desfire_tag *tag, MIFARE_DESFIRE_Version_t *versionInfo);
|
||||||
|
StatusCode MIFARE_DESFIRE_GetApplicationIds(mifare_desfire_tag *tag, mifare_desfire_aid_t *aids, byte *applicationCount);
|
||||||
|
StatusCode MIFARE_DESFIRE_SelectApplication(mifare_desfire_tag *tag, mifare_desfire_aid_t *aid);
|
||||||
|
StatusCode MIFARE_DESFIRE_GetKeySettings(mifare_desfire_tag *tag, byte *settings, byte *maxKeys);
|
||||||
|
StatusCode MIFARE_DESFIRE_GetKeyVersion(mifare_desfire_tag *tag, byte key, byte *version);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MIFARE DESFire application level commands
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode MIFARE_DESFIRE_GetFileIDs(mifare_desfire_tag *tag, byte *files, byte *filesCount);
|
||||||
|
StatusCode MIFARE_DESFIRE_GetFileSettings(mifare_desfire_tag *tag, byte *file, mifare_desfire_file_settings_t *fileSettings);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MIFARE DESFire data manipulation commands
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode MIFARE_DESFIRE_ReadData(mifare_desfire_tag *tag, byte fid, uint32_t offset, uint32_t length, byte *backData, size_t *backLen);
|
||||||
|
StatusCode MIFARE_DESFIRE_GetValue(mifare_desfire_tag *tag, byte fid, int32_t *value);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Support functions
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static const __FlashStringHelper *GetDesfireStatusCodeName(DesfireStatusCode code);
|
||||||
|
virtual const __FlashStringHelper *GetStatusCodeName(MFRC522::StatusCode code) { return MFRC522::GetStatusCodeName(code); };
|
||||||
|
static const __FlashStringHelper *GetStatusCodeName(StatusCode code);
|
||||||
|
static const __FlashStringHelper *GetFileTypeName(mifare_desfire_file_types fileType);
|
||||||
|
static const __FlashStringHelper *GetCommunicationModeName(mifare_desfire_communication_modes communicationMode);
|
||||||
|
bool IsStatusCodeOK(StatusCode code);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for debugging
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void PICC_DumpMifareDesfireMasterKey(mifare_desfire_tag *tag);
|
||||||
|
void PICC_DumpMifareDesfireVersion(mifare_desfire_tag *tag, MIFARE_DESFIRE_Version_t *versionInfo);
|
||||||
|
void PICC_DumpMifareDesfireApplication(mifare_desfire_tag *tag, mifare_desfire_aid_t *aid);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helper methods
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode MIFARE_BlockExchange(mifare_desfire_tag *tag, byte cmd, byte *backData = NULL, byte *backLen = NULL);
|
||||||
|
StatusCode MIFARE_BlockExchangeWithData(mifare_desfire_tag *tag, byte cmd, byte *sendData = NULL, byte *sendLen = NULL, byte *backData = NULL, byte *backLen = NULL);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
20
Software/lib/rfid-desfire/README.md
Normal file
20
Software/lib/rfid-desfire/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# RFID-DESFire #
|
||||||
|
|
||||||
|
Arduino library for MFRC522 and other RFID RC522 based modules.
|
||||||
|
|
||||||
|
This library extends the [MFRC522 library](https://github.com/miguelbalboa/rfid) adding extra functionality for MIFARE DESFire cards.
|
||||||
|
|
||||||
|
At the current stage no crypto has been implemented and a very limited subset of commands are available.
|
||||||
|
|
||||||
|
## Requirements ##
|
||||||
|
- [MFRC522 library](https://github.com/miguelbalboa/rfid)
|
||||||
|
|
||||||
|
### Future requirements ###
|
||||||
|
This libraries have been planned but need to be implemented and confirmed to be working properlly with DESFire library.
|
||||||
|
|
||||||
|
- [Arduino DES library](https://github.com/spaniakos/ArduinoDES/) (Not yet implemented)
|
||||||
|
- [Arduino AES library](https://github.com/spaniakos/AES/) (Not yet implemented)
|
||||||
|
|
||||||
|
## Credits ##
|
||||||
|
|
||||||
|
[EasyPay](https://github.com/nceruchalu/easypay) has been an invaluable source of information due to the great documentation in its comments.
|
BIN
Software/lib/rfid-desfire/docs/DesFireProgrammingGuide.pdf
Normal file
BIN
Software/lib/rfid-desfire/docs/DesFireProgrammingGuide.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
Software/lib/rfid-desfire/docs/sloa213.pdf
Normal file
BIN
Software/lib/rfid-desfire/docs/sloa213.pdf
Normal file
Binary file not shown.
143
Software/lib/rfid-desfire/examples/DumpInfo.ino
Normal file
143
Software/lib/rfid-desfire/examples/DumpInfo.ino
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------------------------------------------------------
|
||||||
|
* Example sketch/program showing how to read data from a PICC to serial.
|
||||||
|
* --------------------------------------------------------------------------------------------------------------------
|
||||||
|
* This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid
|
||||||
|
*
|
||||||
|
* Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID
|
||||||
|
* Reader on the Arduino SPI interface.
|
||||||
|
*
|
||||||
|
* When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE
|
||||||
|
* then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When
|
||||||
|
* you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output
|
||||||
|
* will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages
|
||||||
|
* when removing the PICC from reading distance too early.
|
||||||
|
*
|
||||||
|
* If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading).
|
||||||
|
* So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all
|
||||||
|
* details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so
|
||||||
|
* keep the PICCs at reading distance until complete.
|
||||||
|
*
|
||||||
|
* @license Released into the public domain.
|
||||||
|
*
|
||||||
|
* Typical pin layout used:
|
||||||
|
* -----------------------------------------------------------------------------------------
|
||||||
|
* MFRC522 Arduino Arduino Arduino Arduino Arduino
|
||||||
|
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro
|
||||||
|
* Signal Pin Pin Pin Pin Pin Pin
|
||||||
|
* -----------------------------------------------------------------------------------------
|
||||||
|
* RST/Reset RST 9 5 D9 RESET/ICSP-5 RST
|
||||||
|
* SPI SS SDA(SS) 10 53 D10 10 10
|
||||||
|
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
|
||||||
|
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14
|
||||||
|
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <MFRC522.h>
|
||||||
|
#include <Desfire.h>
|
||||||
|
|
||||||
|
#define RST_PIN 9 // Configurable, see typical pin layout above
|
||||||
|
#define SS_PIN 10 // Configurable, see typical pin layout above
|
||||||
|
|
||||||
|
DESFire mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600); // Initialize serial communications with the PC
|
||||||
|
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
|
||||||
|
SPI.begin(); // Init SPI bus
|
||||||
|
mfrc522.PCD_Init(); // Init MFRC522
|
||||||
|
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
|
||||||
|
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Look for new cards
|
||||||
|
if ( ! mfrc522.PICC_IsNewCardPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select one of the cards
|
||||||
|
if ( ! mfrc522.PICC_ReadCardSerial()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mfrc522.uid.sak != 0x20) {
|
||||||
|
// Dump debug info about the card; PICC_HaltA() is automatically called
|
||||||
|
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show an extra line
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
DESFire::mifare_desfire_tag tag;
|
||||||
|
DESFire::StatusCode response;
|
||||||
|
|
||||||
|
tag.pcb = 0x0A;
|
||||||
|
tag.cid = 0x00;
|
||||||
|
memset(tag.selected_application, 0, 3);
|
||||||
|
|
||||||
|
// Make sure none DESFire status codes have DESFireStatus code to OK
|
||||||
|
response.desfire = DESFire::MF_OPERATION_OK;
|
||||||
|
|
||||||
|
byte ats[16];
|
||||||
|
byte atsLength = 16;
|
||||||
|
response.mfrc522 = mfrc522.PICC_RequestATS(ats, &atsLength);
|
||||||
|
if ( ! mfrc522.IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Failed to get ATS!"));
|
||||||
|
Serial.println(mfrc522.GetStatusCodeName(response));
|
||||||
|
Serial.println(response.mfrc522);
|
||||||
|
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Should do checks but since I know my DESFire allows and requires PPS...
|
||||||
|
// PPS1 is ommitted and, therefore, 0x00 is used (106kBd)
|
||||||
|
response.mfrc522 = mfrc522.PICC_ProtocolAndParameterSelection(0x00, 0x11);
|
||||||
|
if ( ! mfrc522.IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Failed to perform protocol and parameter selection (PPS)!"));
|
||||||
|
Serial.println(mfrc522.GetStatusCodeName(response));
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MIFARE DESFire should respond to a GetVersion command
|
||||||
|
DESFire::MIFARE_DESFIRE_Version_t desfireVersion;
|
||||||
|
response = mfrc522.MIFARE_DESFIRE_GetVersion(&tag, &desfireVersion);
|
||||||
|
if ( ! mfrc522.IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Failed to get a response for GetVersion!"));
|
||||||
|
Serial.println(mfrc522.GetStatusCodeName(response));
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump MIFARE DESFire version information.
|
||||||
|
// NOTE: KEEP YOUR CARD CLOSE TO THE READER!
|
||||||
|
// This method takes some time and the card will be read
|
||||||
|
// once output ends! If you remove the card too fast
|
||||||
|
// a timeout will occur!
|
||||||
|
mfrc522.PICC_DumpMifareDesfireVersion(&tag, &desfireVersion);
|
||||||
|
|
||||||
|
mfrc522.PICC_DumpMifareDesfireMasterKey(&tag);
|
||||||
|
|
||||||
|
DESFire::mifare_desfire_aid_t aids[MIFARE_MAX_APPLICATION_COUNT];
|
||||||
|
byte applicationCount = 0;
|
||||||
|
response = mfrc522.MIFARE_DESFIRE_GetApplicationIds(&tag, aids, &applicationCount);
|
||||||
|
if ( ! mfrc522.IsStatusCodeOK(response)) {
|
||||||
|
Serial.println(F("Failed to get application IDs!"));
|
||||||
|
Serial.println(mfrc522.GetStatusCodeName(response));
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump all applications
|
||||||
|
for (byte aidIndex = 0; aidIndex < applicationCount; aidIndex++) {
|
||||||
|
mfrc522.PICC_DumpMifareDesfireApplication(&tag, &(aids[aidIndex]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call PICC_HaltA()
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
Serial.println();
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#include "display.h"
|
#include <Display.h>
|
||||||
#include <SSD1306Wire.h>
|
#include <SSD1306Wire.h>
|
||||||
|
|
||||||
Display::Display(int sda, int scl, int readerid)
|
Display::Display(int sda, int scl, int readerid)
|
||||||
@ -8,6 +8,10 @@ Display::Display(int sda, int scl, int readerid)
|
|||||||
display->init();
|
display->init();
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
display->flipScreenVertically();
|
display->flipScreenVertically();
|
||||||
|
|
||||||
|
ReaderInfo[0] = '\0'; // Empty string
|
||||||
|
strcpy(Title, "Boot ..."); // Set initial title
|
||||||
|
Info[0] = '\0'; // Empty string
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::clearReaderInfo()
|
void Display::clearReaderInfo()
|
||||||
@ -17,7 +21,7 @@ void Display::clearReaderInfo()
|
|||||||
writeReaderInfo(buffer);
|
writeReaderInfo(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::createReaderInfo(char state[])
|
void Display::createReaderInfo(const char* state)
|
||||||
{
|
{
|
||||||
if(strlen(state) < DISPLAY_BUFFER_SIZE - 1 - 6)
|
if(strlen(state) < DISPLAY_BUFFER_SIZE - 1 - 6)
|
||||||
{
|
{
|
||||||
@ -27,7 +31,7 @@ void Display::createReaderInfo(char state[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::writeReaderInfo(char text[])
|
void Display::writeReaderInfo(const char* text)
|
||||||
{
|
{
|
||||||
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
||||||
{
|
{
|
||||||
@ -36,7 +40,7 @@ void Display::writeReaderInfo(char text[])
|
|||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::writeTitle(char text[])
|
void Display::writeTitle(const char* text)
|
||||||
{
|
{
|
||||||
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
||||||
{
|
{
|
||||||
@ -45,7 +49,7 @@ void Display::writeTitle(char text[])
|
|||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::writeInfo(char text[])
|
void Display::writeInfo(const char* text)
|
||||||
{
|
{
|
||||||
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
if(strlen(text) < DISPLAY_BUFFER_SIZE - 1)
|
||||||
{
|
{
|
||||||
@ -71,7 +75,7 @@ void Display::updateDisplay()
|
|||||||
display->display();
|
display->display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::updateByMQTT(char* topic, byte* payload, unsigned int length)
|
void Display::updateByMQTT(const char* topic, byte* payload, unsigned int length)
|
||||||
{
|
{
|
||||||
char topic_displayTitle[] = "fabreader/00000/display/title";
|
char topic_displayTitle[] = "fabreader/00000/display/title";
|
||||||
sprintf(topic_displayTitle, "fabreader/%05d/display/title", readerid);
|
sprintf(topic_displayTitle, "fabreader/%05d/display/title", readerid);
|
||||||
@ -82,7 +86,7 @@ void Display::updateByMQTT(char* topic, byte* payload, unsigned int length)
|
|||||||
char topic_stopOTA[] = "fabreader/00000/stopOTA";
|
char topic_stopOTA[] = "fabreader/00000/stopOTA";
|
||||||
sprintf(topic_stopOTA, "fabreader/%05d/stopOTA", readerid);
|
sprintf(topic_stopOTA, "fabreader/%05d/stopOTA", readerid);
|
||||||
|
|
||||||
char buffer[length + 1] = {0};
|
char* buffer = new char[length + 1];
|
||||||
memcpy(buffer, payload, length);
|
memcpy(buffer, payload, length);
|
||||||
|
|
||||||
if(!strcmp(topic, topic_displayTitle))
|
if(!strcmp(topic, topic_displayTitle))
|
||||||
|
@ -9,18 +9,18 @@ class Display
|
|||||||
private:
|
private:
|
||||||
SSD1306Wire* display;
|
SSD1306Wire* display;
|
||||||
int readerid;
|
int readerid;
|
||||||
char ReaderInfo[DISPLAY_BUFFER_SIZE] = "";
|
char ReaderInfo[DISPLAY_BUFFER_SIZE];
|
||||||
char Title[DISPLAY_BUFFER_SIZE] = "Boot ...";
|
char Title[DISPLAY_BUFFER_SIZE];
|
||||||
char Info[DISPLAY_BUFFER_SIZE] = "";
|
char Info[DISPLAY_BUFFER_SIZE];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Display(int sda, int scl, int readerid);
|
Display(int sda, int scl, int readerid);
|
||||||
void createReaderInfo(char* state);
|
void createReaderInfo(const char* state);
|
||||||
void clearReaderInfo();
|
void clearReaderInfo();
|
||||||
void writeReaderInfo(char* text);
|
void writeReaderInfo(const char* text);
|
||||||
void writeTitle(char* text);
|
void writeTitle(const char* text);
|
||||||
void writeInfo(char* text);
|
void writeInfo(const char* text);
|
||||||
void updateDisplay();
|
void updateDisplay();
|
||||||
void updateByMQTT(char* topic, byte* payload, unsigned int length);
|
void updateByMQTT(const char* topic, byte* payload, unsigned int length);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
@ -2,7 +2,7 @@
|
|||||||
#define NFC_H
|
#define NFC_H
|
||||||
|
|
||||||
#include <PubSubClient.h>
|
#include <PubSubClient.h>
|
||||||
#include <DESFire.h>
|
#include <Desfire.h>
|
||||||
#define APDU_BUFFER_SIZE 256
|
#define APDU_BUFFER_SIZE 256
|
||||||
|
|
||||||
class NFC
|
class NFC
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "pins.h"
|
#include <Pins.h>
|
||||||
#include "nfc.h"
|
#include <NFC.h>
|
||||||
#include "otaproxy.h"
|
#include <OTAProxy.h>
|
||||||
#include "helpers.h"
|
#include <helpers.h>
|
||||||
#include "Desfire.h"
|
#include <Desfire.h>
|
||||||
#include "display.h"
|
#include <Display.h>
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
@ -53,7 +53,7 @@ void reconnect()
|
|||||||
|
|
||||||
Serial.println("Connecting MQTT ...");
|
Serial.println("Connecting MQTT ...");
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
if(MQTT_USERNAME == "")
|
if (strcmp(MQTT_USERNAME, "") == 0)
|
||||||
{
|
{
|
||||||
connected = mqtt->connect(clientId.c_str());
|
connected = mqtt->connect(clientId.c_str());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user