diff --git a/Software/.vscode/settings.json b/Software/.vscode/settings.json index 1610e0a..bf8f31c 100644 --- a/Software/.vscode/settings.json +++ b/Software/.vscode/settings.json @@ -11,6 +11,16 @@ "functional": "cpp", "*.desfire": "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" + ] } \ No newline at end of file diff --git a/Software/lib/.DS_Store b/Software/lib/.DS_Store new file mode 100644 index 0000000..8e389f0 Binary files /dev/null and b/Software/lib/.DS_Store differ diff --git a/Software/lib/rfid-desfire/Desfire.cpp b/Software/lib/rfid-desfire/Desfire.cpp new file mode 100644 index 0000000..0acb3c0 --- /dev/null +++ b/Software/lib/rfid-desfire/Desfire.cpp @@ -0,0 +1,971 @@ +#include + +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("-------------------------------------------------------------")); +} \ No newline at end of file diff --git a/Software/lib/rfid-desfire/Desfire.h b/Software/lib/rfid-desfire/Desfire.h new file mode 100644 index 0000000..7c28d42 --- /dev/null +++ b/Software/lib/rfid-desfire/Desfire.h @@ -0,0 +1,187 @@ +#ifndef DESFIRE_h +#define DESFIRE_h + +#include +#include +#include + +/* -------------------------------------- +* 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 \ No newline at end of file diff --git a/Software/lib/rfid-desfire/README.md b/Software/lib/rfid-desfire/README.md new file mode 100644 index 0000000..42df717 --- /dev/null +++ b/Software/lib/rfid-desfire/README.md @@ -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. diff --git a/Software/lib/rfid-desfire/docs/DesFireProgrammingGuide.pdf b/Software/lib/rfid-desfire/docs/DesFireProgrammingGuide.pdf new file mode 100644 index 0000000..4337967 Binary files /dev/null and b/Software/lib/rfid-desfire/docs/DesFireProgrammingGuide.pdf differ diff --git a/Software/lib/rfid-desfire/docs/MIFAREDESFireEV1AESAuthenticationWithTRF7970A.pdf b/Software/lib/rfid-desfire/docs/MIFAREDESFireEV1AESAuthenticationWithTRF7970A.pdf new file mode 100644 index 0000000..fcab7be Binary files /dev/null and b/Software/lib/rfid-desfire/docs/MIFAREDESFireEV1AESAuthenticationWithTRF7970A.pdf differ diff --git a/Software/lib/rfid-desfire/docs/sloa213.pdf b/Software/lib/rfid-desfire/docs/sloa213.pdf new file mode 100644 index 0000000..fcab7be Binary files /dev/null and b/Software/lib/rfid-desfire/docs/sloa213.pdf differ diff --git a/Software/lib/rfid-desfire/examples/DumpInfo.ino b/Software/lib/rfid-desfire/examples/DumpInfo.ino new file mode 100644 index 0000000..64be0ae --- /dev/null +++ b/Software/lib/rfid-desfire/examples/DumpInfo.ino @@ -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 +#include +#include + +#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(); +} \ No newline at end of file diff --git a/Software/src/Display.cpp b/Software/src/Display.cpp index 9be1013..5178aed 100644 --- a/Software/src/Display.cpp +++ b/Software/src/Display.cpp @@ -1,4 +1,4 @@ -#include "display.h" +#include #include Display::Display(int sda, int scl, int readerid) @@ -8,6 +8,10 @@ Display::Display(int sda, int scl, int readerid) display->init(); display->setTextAlignment(TEXT_ALIGN_CENTER); display->flipScreenVertically(); + + ReaderInfo[0] = '\0'; // Empty string + strcpy(Title, "Boot ..."); // Set initial title + Info[0] = '\0'; // Empty string } void Display::clearReaderInfo() @@ -17,7 +21,7 @@ void Display::clearReaderInfo() writeReaderInfo(buffer); } -void Display::createReaderInfo(char state[]) +void Display::createReaderInfo(const char* state) { 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) { @@ -36,7 +40,7 @@ void Display::writeReaderInfo(char text[]) updateDisplay(); } -void Display::writeTitle(char text[]) +void Display::writeTitle(const char* text) { if(strlen(text) < DISPLAY_BUFFER_SIZE - 1) { @@ -45,7 +49,7 @@ void Display::writeTitle(char text[]) updateDisplay(); } -void Display::writeInfo(char text[]) +void Display::writeInfo(const char* text) { if(strlen(text) < DISPLAY_BUFFER_SIZE - 1) { @@ -71,7 +75,7 @@ void Display::updateDisplay() 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"; 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"; sprintf(topic_stopOTA, "fabreader/%05d/stopOTA", readerid); - char buffer[length + 1] = {0}; + char* buffer = new char[length + 1]; memcpy(buffer, payload, length); if(!strcmp(topic, topic_displayTitle)) diff --git a/Software/src/Display.h b/Software/src/Display.h index 2514fb1..02c76aa 100644 --- a/Software/src/Display.h +++ b/Software/src/Display.h @@ -9,18 +9,18 @@ class Display private: SSD1306Wire* display; int readerid; - char ReaderInfo[DISPLAY_BUFFER_SIZE] = ""; - char Title[DISPLAY_BUFFER_SIZE] = "Boot ..."; - char Info[DISPLAY_BUFFER_SIZE] = ""; + char ReaderInfo[DISPLAY_BUFFER_SIZE]; + char Title[DISPLAY_BUFFER_SIZE]; + char Info[DISPLAY_BUFFER_SIZE]; public: Display(int sda, int scl, int readerid); - void createReaderInfo(char* state); + void createReaderInfo(const char* state); void clearReaderInfo(); - void writeReaderInfo(char* text); - void writeTitle(char* text); - void writeInfo(char* text); + void writeReaderInfo(const char* text); + void writeTitle(const char* text); + void writeInfo(const char* text); void updateDisplay(); - void updateByMQTT(char* topic, byte* payload, unsigned int length); + void updateByMQTT(const char* topic, byte* payload, unsigned int length); }; #endif \ No newline at end of file diff --git a/Software/src/NFC.h b/Software/src/NFC.h index 31dbb90..45b07a4 100644 --- a/Software/src/NFC.h +++ b/Software/src/NFC.h @@ -2,7 +2,7 @@ #define NFC_H #include -#include +#include #define APDU_BUFFER_SIZE 256 class NFC diff --git a/Software/src/main.cpp b/Software/src/main.cpp index 2170d84..b96739c 100644 --- a/Software/src/main.cpp +++ b/Software/src/main.cpp @@ -2,12 +2,12 @@ #include #include "config.h" -#include "pins.h" -#include "nfc.h" -#include "otaproxy.h" -#include "helpers.h" -#include "Desfire.h" -#include "display.h" +#include +#include +#include +#include +#include +#include #include #include @@ -53,7 +53,7 @@ void reconnect() Serial.println("Connecting MQTT ..."); bool connected = false; - if(MQTT_USERNAME == "") + if (strcmp(MQTT_USERNAME, "") == 0) { connected = mqtt->connect(clientId.c_str()); }