| /* |
| * Copyright (C) 2010 NXP Semiconductors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * \file phFriNfc_MifStdFormat.c |
| * \brief NFC Ndef Formatting For Mifare standard card. |
| * |
| * Project: NFC-FRI |
| * |
| * $Date: Tue Oct 20 20:13:03 2009 $ |
| * $Author: ing02260 $ |
| * $Revision: 1.9 $ |
| * $Aliases: NFC_FRI1.1_WK943_R32_1,NFC_FRI1.1_WK949_PREP1,NFC_FRI1.1_WK943_R32_10,NFC_FRI1.1_WK943_R32_13,NFC_FRI1.1_WK943_R32_14,NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $ |
| * |
| */ |
| |
| #include <phFriNfc_MifStdFormat.h> |
| #include <phFriNfc_OvrHal.h> |
| |
| /*! \ingroup grp_file_attributes |
| * \name NDEF Mapping |
| * |
| * File: \ref phFriNfc_MifStdFormat.c |
| * |
| */ |
| /*@{*/ |
| #define PHFRINFCMIFSTDFMT_FILEREVISION "$Revision: 1.9 $" |
| #define PHFRINFCMIFSTDFMT_FILEALIASES "$Aliases: NFC_FRI1.1_WK943_R32_1,NFC_FRI1.1_WK949_PREP1,NFC_FRI1.1_WK943_R32_10,NFC_FRI1.1_WK943_R32_13,NFC_FRI1.1_WK943_R32_14,NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $" |
| /*@}*/ |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function fills the |
| * send buffer for transceive function |
| */ |
| static void phFriNfc_MfStd_H_FillSendBuf(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, |
| uint16_t BlockNo); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function authenticates |
| * a block or a sector from the card. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_Transceive(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function calls |
| * disconnect. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_CallDisCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, |
| NFCSTATUS Status); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function calls |
| * disconnect. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_CallCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| #ifndef PH_HAL4_ENABLE |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function calls |
| * disconnect. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_CallPoll(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| #endif /* #ifndef PH_HAL4_ENABLE */ |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process the |
| * poll call. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process the |
| * authenticate call. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProAuth(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process the |
| * read access bit call. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProRdSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process the |
| * write access bit call. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProWrSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function writes the |
| * sector trailer using the block number. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_WrRdAuth(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function checks the |
| * access bits of each sector trailer. |
| */ |
| static uint32_t phFriNfc_MfStd_H_ChkAcsBit(uint16_t BlockNo, |
| const uint8_t *RecvBuf, |
| const uint8_t AcsBits1[], |
| const uint8_t AcsBits2[]); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function change the |
| * authentication state and change the block number if required |
| */ |
| static void phFriNfc_MfStd_H_ChangeAuthSt(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function finds the |
| * contiguous ndef compliant blocks. |
| */ |
| static void phFriNfc_MfStd_H_NdefComplSect(uint8_t CardTypes, |
| uint8_t Sector[]); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function writes the |
| * MAD block values. |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProWrMADBlk(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process |
| * the error status of the authentication |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProErrAuth(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process |
| * the error status of the writing sector trailer |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ErrWrSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process |
| * the error status of the reading sector trailer |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ErrRdSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall process |
| * the error status of the writing sector trailer |
| */ |
| static NFCSTATUS phFriNfc_MfStd_H_ProUpdMADBlk(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall store the |
| * ndef compliant in the MAD array which will be later used for updating the MAD sector |
| */ |
| static void phFriNfc_MfStd_H_StrNdefData(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| /*! |
| * \brief \copydoc page_ovr Helper function for Mifare standard. This function shall find the ndef compliant |
| * and calculate the block number to write the NDEF TLV |
| */ |
| static void phFriNfc_MfStd_H_BlkNoToWrTLV(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); |
| |
| static int phFriNfc_MfStd_MemCompare ( void *s1, void *s2, unsigned int n ); |
| |
| |
| void phFriNfc_MfStd_Reset(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| uint8_t NfcForSectArray[] = PH_FRINFC_SMTCRDFMT_NFCFORUMSECT_KEYA_ACS_BIT, |
| MADSectArray[] = PH_FRINFC_SMTCRDFMT_MSTD_MADSECT_KEYA_ACS_BIT_1K; |
| |
| /* Authentication state */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| /* Set default key for A or B */ |
| (void)memset(NdefSmtCrdFmt->AddInfo.MfStdInfo.Default_KeyA_OR_B, |
| PH_FRINFC_MFSTD_FMT_DEFAULT_KEY, /* 0xFF */ |
| PH_FRINFC_MFSTD_FMT_VAL_6); |
| |
| /* MAD sector key A */ |
| (void)memcpy(NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSect_KeyA, |
| MADSectArray, //PH_FRINFC_MFSTD_FMT_VAL_0, |
| PH_FRINFC_MFSTD_FMT_VAL_6); |
| |
| /* Copy access bits for MAD sectors */ |
| (void)memcpy(NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSect_AccessBits, |
| &MADSectArray[PH_FRINFC_MFSTD_FMT_VAL_6], |
| PH_FRINFC_MFSTD_FMT_VAL_3); |
| |
| /* NFC forum sector key A */ |
| (void)memcpy(NdefSmtCrdFmt->AddInfo.MfStdInfo.NFCForumSect_KeyA, |
| NfcForSectArray, //PH_FRINFC_MFSTD_FMT_VAL_0, |
| PH_FRINFC_MFSTD_FMT_VAL_6); |
| |
| /* Copy access bits for NFC forum sectors */ |
| (void)memcpy(NdefSmtCrdFmt->AddInfo.MfStdInfo.NFCForumSect_AccessBits, |
| &NfcForSectArray[PH_FRINFC_MFSTD_FMT_VAL_6], |
| PH_FRINFC_MFSTD_FMT_VAL_3); |
| |
| /* Sector compliant array initialised to 0 */ |
| (void)memset(NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl, |
| PH_FRINFC_MFSTD_FMT_VAL_0, /* 0x00 */ |
| PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K); |
| |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag = (uint8_t)PH_FRINFC_MFSTD_FMT_VAL_0; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = (uint8_t)PH_FRINFC_MFSTD_FMT_NOT_A_MAD_BLK; |
| |
| } |
| |
| NFCSTATUS phFriNfc_MfStd_Format( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, const uint8_t *ScrtKeyB ) |
| { |
| NFCSTATUS Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, |
| NFCSTATUS_INVALID_PARAMETER); |
| uint8_t index = PH_FRINFC_MFSTD_FMT_VAL_0; |
| |
| if(ScrtKeyB != NULL) |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = |
| PH_FRINFC_MFSTD_FMT_NOT_A_MAD_BLK; |
| /* Store Key B in the context */ |
| while(index < PH_FRINFC_MFSTD_FMT_VAL_6) |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.ScrtKeyB[index] = ScrtKeyB[index]; |
| index++; |
| } |
| /* Set the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* Initialise current block to the first sector trailer */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = PH_FRINFC_MFSTD_FMT_VAL_3; |
| /* Set the authenticate state */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY; |
| /* Start authentication */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| return Result; |
| } |
| |
| void phFriNfc_MfStd_Process(void *Context, |
| NFCSTATUS Status) |
| { |
| phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt = (phFriNfc_sNdefSmtCrdFmt_t *)Context; |
| /* Copy the formatting status */ |
| NdefSmtCrdFmt->FmtProcStatus = Status; |
| if(Status == NFCSTATUS_SUCCESS) |
| { |
| switch(NdefSmtCrdFmt->State) |
| { |
| case PH_FRINFC_MFSTD_FMT_AUTH_SECT: |
| Status = phFriNfc_MfStd_H_ProAuth(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_DIS_CON: |
| #ifndef PH_HAL4_ENABLE |
| Status = phFriNfc_MfStd_H_CallPoll(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_POLL: |
| #endif /* #ifndef PH_HAL4_ENABLE */ |
| Status = phFriNfc_MfStd_H_CallCon(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_CON: |
| Status = phFriNfc_MfStd_H_ProCon(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_RD_SECT_TR: |
| Status = phFriNfc_MfStd_H_ProRdSectTr(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_SECT_TR: |
| Status = phFriNfc_MfStd_H_ProWrSectTr(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_MAD_BLK: |
| Status = phFriNfc_MfStd_H_ProWrMADBlk(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_TLV: |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_UPD_MAD_BLK: |
| Status = phFriNfc_MfStd_H_ProUpdMADBlk(NdefSmtCrdFmt); |
| break; |
| |
| default: |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, |
| NFCSTATUS_INVALID_DEVICE_REQUEST); |
| break; |
| } |
| } |
| else |
| { |
| switch(NdefSmtCrdFmt->State) |
| { |
| case PH_FRINFC_MFSTD_FMT_AUTH_SECT: |
| Status = phFriNfc_MfStd_H_ProErrAuth(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_SECT_TR: |
| Status = phFriNfc_MfStd_H_ErrWrSectTr(NdefSmtCrdFmt); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_RD_SECT_TR: |
| Status = phFriNfc_MfStd_H_ErrRdSectTr(NdefSmtCrdFmt); |
| break; |
| |
| default: |
| Status = NdefSmtCrdFmt->FmtProcStatus; |
| break; |
| } |
| } |
| |
| /* Status is not success then call completion routine */ |
| if(Status != NFCSTATUS_PENDING) |
| { |
| phFriNfc_SmtCrdFmt_HCrHandler(NdefSmtCrdFmt, Status); |
| } |
| } |
| |
| static void phFriNfc_MfStd_H_FillSendBuf(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, |
| uint16_t BlockNo) |
| { |
| void *mem = NULL; |
| uint8_t MADSectTr1k[] = PH_FRINFC_SMTCRDFMT_MSTD_MADSECT_KEYA_ACS_BIT_1K, /* MAD key A, |
| Access bits and GPB of MAD sector */ |
| MADSectTr4k[] = PH_FRINFC_SMTCRDFMT_MSTD_MADSECT_KEYA_ACS_BIT_4K, /* MAD key A, |
| Access bits and GPB of MAD sector */ |
| NFCSectTr[] = PH_FRINFC_SMTCRDFMT_NFCFORUMSECT_KEYA_ACS_BIT, /* NFC forum key A, |
| Access bits and GPB of NFC sector */ |
| NDEFMsgTLV[16] = {0x03, 0x00, 0xFE, 0x00, 0x00, 0x00, /* NDEF message TLV (INITIALISED state) */ |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00}, |
| MADBlk[16] = {0x0F, 0x00, 0x03, 0xE1, 0x03, 0xE1, |
| 0x03, 0xE1, 0x03, 0xE1, |
| 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; |
| /* Block number in send buffer */ |
| NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_0] = (uint8_t)BlockNo; |
| /* Initialise send receive length */ |
| *NdefSmtCrdFmt->SendRecvLength = PH_FRINFC_MFSTD_FMT_MAX_RECV_LENGTH; |
| |
| /* Depending on the different state, fill the send buffer */ |
| switch(NdefSmtCrdFmt->State) |
| { |
| case PH_FRINFC_MFSTD_FMT_AUTH_SECT: |
| /* Depending on the authentication state, fill the send buffer */ |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState) |
| { |
| case PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY: |
| case PH_FRINFC_MFSTD_FMT_AUTH_KEYB: |
| /* Fill send buffer with the default key */ |
| PH_FRINFC_MFSTD_FMT_AUTH_SEND_BUF_DEF(mem); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_NFC_KEY: |
| /* Fill send buffer with NFC forum sector key */ |
| PH_FRINFC_MFSTD_FMT_AUTH_SEND_BUF_NFCSECT_KEYA(mem); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB: |
| /* Fill send buffer with NFC forum sector key */ |
| PH_FRINFC_MFSTD_FMT_AUTH_SEND_BUF_SCRT_KEY(mem); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_MAD_KEY: |
| default: |
| /* Fill send buffer with MAD sector key */ |
| PH_FRINFC_MFSTD_FMT_AUTH_SEND_BUF_MADSECT_KEYA(mem); |
| break; |
| } |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_RD_SECT_TR: |
| #ifdef PH_HAL4_ENABLE |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; |
| #else |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| |
| /* Send length is always one for read operation */ |
| NdefSmtCrdFmt->SendLength = PH_FRINFC_MFSTD_FMT_VAL_1; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_SECT_TR: |
| /* Fill send buffer for writing sector trailer */ |
| #ifdef PH_HAL4_ENABLE |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite16; |
| #else |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite16; |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| /* Copy the relevant sector trailer value in the buffer */ |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock) |
| { |
| case PH_FRINFC_MFSTD_FMT_VAL_3: |
| if (NdefSmtCrdFmt->CardType == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD) |
| { |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| MADSectTr1k, |
| sizeof(MADSectTr1k)); |
| } |
| else |
| { |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| MADSectTr4k, |
| sizeof(MADSectTr4k)); |
| } |
| break; |
| case 67: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| MADSectTr4k, |
| sizeof(MADSectTr4k)); |
| break; |
| default: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| NFCSectTr, |
| sizeof(NFCSectTr)); |
| break; |
| } |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_11], |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.ScrtKeyB, |
| sizeof(NdefSmtCrdFmt->AddInfo.MfStdInfo.ScrtKeyB)); |
| |
| /* Send length is always 17 for write operation */ |
| NdefSmtCrdFmt->SendLength = PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_TLV: |
| /* Fill send buffer for writing TLV */ |
| #ifdef PH_HAL4_ENABLE |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite16; |
| #else |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite16; |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| /* Copy the NDEF message TLV */ |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| NDEFMsgTLV, sizeof(NDEFMsgTLV)); |
| /* Send length is always 17 for write operation */ |
| NdefSmtCrdFmt->SendLength = PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_WR_MAD_BLK: |
| /* Fill send buffer for writing MAD block */ |
| #ifdef PH_HAL4_ENABLE |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite16; |
| #else |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite16; |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| |
| if((BlockNo == PH_FRINFC_MFSTD_FMT_VAL_2) || |
| (BlockNo == 65) || (BlockNo == 66)) |
| { |
| /* MAD block number 2, 65 and 66 has 0x03, 0xE1 in the |
| first two bytes */ |
| MADBlk[PH_FRINFC_MFSTD_FMT_VAL_0] = 0x03; |
| MADBlk[PH_FRINFC_MFSTD_FMT_VAL_1] = 0xE1; |
| } |
| /* Copy the MAD Block values */ |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| MADBlk, sizeof(MADBlk)); |
| /* Send length is always 17 for write operation */ |
| NdefSmtCrdFmt->SendLength = PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_UPD_MAD_BLK: |
| default: |
| /* Fill send buffer for writing MAD block */ |
| #ifdef PH_HAL4_ENABLE |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite16; |
| #else |
| NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite16; |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| NdefSmtCrdFmt->SendLength = PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH; |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk) |
| { |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_1: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk, |
| (PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_2: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| &NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[16], |
| (PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_64: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| &NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[32], |
| (PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_65: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| &NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[48], |
| (PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_66: |
| default: |
| (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFSTD_FMT_VAL_1], |
| &NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[64], |
| (PH_FRINFC_MFSTD_FMT_WR_SEND_LENGTH - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| break; |
| } |
| break; |
| } |
| PHNFC_UNUSED_VARIABLE(mem); |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_Transceive(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| |
| /* set the data for additional data exchange*/ |
| NdefSmtCrdFmt->psDepAdditionalInfo.DepFlags.MetaChaining = 0; |
| NdefSmtCrdFmt->psDepAdditionalInfo.DepFlags.NADPresent = 0; |
| NdefSmtCrdFmt->psDepAdditionalInfo.NAD = 0; |
| |
| /*set the completion routines for the card operations*/ |
| NdefSmtCrdFmt->SmtCrdFmtCompletionInfo.CompletionRoutine = phFriNfc_NdefSmtCrd_Process; |
| NdefSmtCrdFmt->SmtCrdFmtCompletionInfo.Context = NdefSmtCrdFmt; |
| |
| *NdefSmtCrdFmt->SendRecvLength = PH_FRINFC_SMTCRDFMT_MAX_SEND_RECV_BUF_SIZE; |
| |
| /* Call the Overlapped HAL Transceive function */ |
| Result = phFriNfc_OvrHal_Transceive( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| NdefSmtCrdFmt->psRemoteDevInfo, |
| NdefSmtCrdFmt->Cmd, |
| &NdefSmtCrdFmt->psDepAdditionalInfo, |
| NdefSmtCrdFmt->SendRecvBuf, |
| NdefSmtCrdFmt->SendLength, |
| NdefSmtCrdFmt->SendRecvBuf, |
| NdefSmtCrdFmt->SendRecvLength); |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_CallDisCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, |
| NFCSTATUS Status) |
| { |
| NFCSTATUS Result = Status; |
| |
| /*Set Ndef State*/ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_DIS_CON; |
| |
| #ifdef PH_HAL4_ENABLE |
| |
| /*Call the Overlapped HAL POLL function */ |
| Result = phFriNfc_OvrHal_Reconnect( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| NdefSmtCrdFmt->psRemoteDevInfo); |
| #else |
| /*Call the Overlapped HAL POLL function */ |
| Result = phFriNfc_OvrHal_Disconnect( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| NdefSmtCrdFmt->psRemoteDevInfo); |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_CallCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| /*Set Ndef State*/ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_CON; |
| |
| /*Call the Overlapped HAL POLL function */ |
| #ifdef PH_HAL4_ENABLE |
| Result = phFriNfc_OvrHal_Connect( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| NdefSmtCrdFmt->psRemoteDevInfo, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.DevInputParam); |
| #else |
| Result = phFriNfc_OvrHal_Connect( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| phHal_eOpModesMifare, |
| NdefSmtCrdFmt->psRemoteDevInfo, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.DevInputParam); |
| #endif /* #ifdef PH_HAL4_ENABLE */ |
| |
| return Result; |
| } |
| |
| #ifndef PH_HAL4_ENABLE |
| |
| static NFCSTATUS phFriNfc_MfStd_H_CallPoll(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| /*Set ndef State*/ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_POLL; |
| /* Opmodes */ |
| NdefSmtCrdFmt->OpModeType[PH_FRINFC_MFSTD_FMT_VAL_0] = phHal_eOpModesMifare; |
| NdefSmtCrdFmt->OpModeType[PH_FRINFC_MFSTD_FMT_VAL_1] = phHal_eOpModesArrayTerminator; |
| |
| /* Number of devices to poll */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.NoOfDevices = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| /*Call the Overlapped HAL POLL function */ |
| Result = phFriNfc_OvrHal_Poll( NdefSmtCrdFmt->LowerDevice, |
| &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, |
| NdefSmtCrdFmt->OpModeType, |
| NdefSmtCrdFmt->psRemoteDevInfo, |
| &NdefSmtCrdFmt->AddInfo.MfStdInfo.NoOfDevices, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.DevInputParam); |
| return Result; |
| } |
| |
| #endif /* #ifndef PH_HAL4_ENABLE */ |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProCon(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| uint8_t Buffer[1] = {PH_FRINFC_MFSTD_FMT_NDEF_COMPL}, |
| index = PH_FRINFC_MFSTD_FMT_VAL_1; |
| uint32_t memcompare = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| phFriNfc_MfStd_H_ChangeAuthSt(NdefSmtCrdFmt); |
| if(PH_FRINFC_MFSTD_FMT_CUR_BLK_CHK) |
| { |
| PH_FRINFC_MFSTD_FMT_CHK_END_OF_CARD(); |
| } |
| else |
| { |
| /* Set the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* Start authentication */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProAuth(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| |
| /* Depending on the authentication key check the */ |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState) |
| { |
| case PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY: |
| if((NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == |
| PH_FRINFC_MFSTD_FMT_VAL_3) && |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag == |
| PH_FRINFC_MFSTD_FMT_VAL_0)) |
| { |
| /* Authenticate with default key for block 3 is successful, |
| so fill the MAD block of sector 0 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_VAL_1; |
| /* Write the MAD block */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_MAD_BLK; |
| } |
| else if((NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == 67) |
| && (NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag == |
| PH_FRINFC_MFSTD_FMT_VAL_0)) |
| { |
| /* Authenticate with default key for block 3 is successful, |
| so fill the MAD block of sector 64 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = 64; |
| /* Write the MAD block */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_MAD_BLK; |
| } |
| else |
| { |
| /* Not a MAD sector */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag = |
| PH_FRINFC_MFSTD_FMT_VAL_0; |
| /* Write the MAD block */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_SECT_TR; |
| } |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_KEYB: |
| if((NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_1) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_2) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_64) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_65) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66)) |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk; |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_UPD_MAD_BLK; |
| } |
| else |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = |
| PH_FRINFC_MFSTD_FMT_NOT_A_MAD_BLK; |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_SECT_TR; |
| } |
| |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB: |
| if((NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_1) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_2) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_64) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_65) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66)) |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk; |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_UPD_MAD_BLK; |
| } |
| else |
| { |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = |
| PH_FRINFC_MFSTD_FMT_NOT_A_MAD_BLK; |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_SECT_TR; |
| } |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_AUTH_NFC_KEY: |
| case PH_FRINFC_MFSTD_FMT_AUTH_MAD_KEY: |
| default: |
| if((NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_2)) |
| { |
| /* Updating the MAD block is complete */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = |
| PH_FRINFC_MFSTD_FMT_NOT_A_MAD_BLK; |
| /* If Mifare 4k card, write the TLV */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_TLV; |
| } |
| else |
| { |
| /* Depending on the sector trailer, check the access bit */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_RD_SECT_TR; |
| } |
| break; |
| } |
| /* Call read, write or authenticate */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ErrWrSectTr( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) |
| { |
| NFCSTATUS Result = NdefSmtCrdFmt->FmtProcStatus; |
| /* If default key A is used for authentication and if write fails, then try to |
| authenticate using key B*/ |
| if(NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState == |
| PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY) |
| { |
| /* Change the state to authentication */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* internal authenticate state = key B */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = PH_FRINFC_MFSTD_FMT_AUTH_KEYB; |
| /* Now call authenticate */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| else |
| { |
| Result = phFriNfc_MfStd_H_ProWrSectTr(NdefSmtCrdFmt); |
| } |
| return Result; |
| } |
| static NFCSTATUS phFriNfc_MfStd_H_ProRdSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| uint8_t Buffer[1] = {PH_FRINFC_MFSTD_FMT_NDEF_COMPL}, |
| index = PH_FRINFC_MFSTD_FMT_VAL_1, |
| SectIndex = PH_FRINFC_MFSTD_FMT_VAL_0; |
| uint32_t memcompare = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| /* Calculate sector index */ |
| SectIndex = (uint8_t)PH_FRINFC_MFSTD_FMT_SECT_INDEX_CALC; |
| |
| /* Depending on the sector trailer, check the access bit */ |
| memcompare = phFriNfc_MfStd_H_ChkAcsBit(NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock, |
| NdefSmtCrdFmt->SendRecvBuf, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSect_AccessBits, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.NFCForumSect_AccessBits); |
| |
| /* Check the sector for ndef compliance */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] = (uint8_t) |
| ((memcompare != PH_FRINFC_MFSTD_FMT_VAL_0)? |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL: |
| PH_FRINFC_MFSTD_FMT_NDEF_COMPL); |
| |
| /* Increment the current block */ |
| PH_FRINFC_MFSTD_FMT_CUR_BLK_INC(); |
| SectIndex++; |
| if(PH_FRINFC_MFSTD_FMT_CUR_BLK_CHK) |
| { |
| PH_FRINFC_MFSTD_FMT_CHK_END_OF_CARD(); |
| } |
| else |
| { |
| /* Set the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* Set the authenticate state */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = |
| PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY; |
| /* Start authentication */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProWrSectTr(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| uint8_t Buffer[1] = {PH_FRINFC_MFSTD_FMT_NDEF_COMPL}, |
| index = PH_FRINFC_MFSTD_FMT_VAL_1, |
| SectIndex = PH_FRINFC_MFSTD_FMT_VAL_0; |
| uint32_t memcompare = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| /* Calculate sector index */ |
| SectIndex = (uint8_t)PH_FRINFC_MFSTD_FMT_SECT_INDEX_CALC; |
| |
| /* Sector is ndef compliance */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] = (uint8_t) |
| ((NdefSmtCrdFmt->FmtProcStatus != NFCSTATUS_SUCCESS)? |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL: |
| PH_FRINFC_MFSTD_FMT_NDEF_COMPL); |
| |
| /* Increment the current block */ |
| PH_FRINFC_MFSTD_FMT_CUR_BLK_INC(); |
| SectIndex++; |
| if(PH_FRINFC_MFSTD_FMT_CUR_BLK_CHK) |
| { |
| PH_FRINFC_MFSTD_FMT_CHK_END_OF_CARD(); |
| } |
| else |
| { |
| /* Set the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* Set the authenticate state */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = |
| PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY; |
| /* Start authentication */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| return Result; |
| } |
| |
| static uint32_t phFriNfc_MfStd_H_ChkAcsBit(uint16_t BlockNo, |
| const uint8_t *RecvBuf, |
| const uint8_t AcsBits1[], |
| const uint8_t AcsBits2[]) |
| { |
| uint32_t mem = PH_FRINFC_MFSTD_FMT_VAL_0; |
| |
| /* Compare the access bits read from the sector trailer */ |
| mem = (uint32_t)(((BlockNo == PH_FRINFC_MFSTD_FMT_VAL_3) || |
| (BlockNo == 67))? |
| phFriNfc_MfStd_MemCompare((void*)&RecvBuf[PH_FRINFC_MFSTD_FMT_VAL_6], |
| (void*)AcsBits1, |
| PH_FRINFC_MFSTD_FMT_VAL_3): |
| phFriNfc_MfStd_MemCompare((void*)&RecvBuf[PH_FRINFC_MFSTD_FMT_VAL_6], |
| (void*)AcsBits2, |
| PH_FRINFC_MFSTD_FMT_VAL_3)); |
| |
| return mem; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_WrRdAuth(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| /* Fill send buffer and send length */ |
| phFriNfc_MfStd_H_FillSendBuf(NdefSmtCrdFmt, |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock); |
| /* Call ovrhal transceive */ |
| Result = phFriNfc_MfStd_H_Transceive(NdefSmtCrdFmt); |
| |
| return Result; |
| } |
| |
| static void phFriNfc_MfStd_H_ChangeAuthSt(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| uint8_t SectIndex = PH_FRINFC_MFSTD_FMT_VAL_0; |
| |
| if( NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState == |
| PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB) |
| { |
| /* Calculate sector index */ |
| SectIndex = (uint8_t)PH_FRINFC_MFSTD_FMT_SECT_INDEX_CALC; |
| |
| /* Check the sector for ndef compliance */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] = |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL; |
| |
| PH_FRINFC_MFSTD_FMT_CUR_BLK_INC(); |
| } |
| PH_FRINFC_MFSTD_FMT_NXT_AUTH_STATE(); |
| } |
| |
| static void phFriNfc_MfStd_H_NdefComplSect(uint8_t CardTypes, |
| uint8_t Sector[]) |
| { |
| uint8_t count = PH_FRINFC_MFSTD_FMT_VAL_0, |
| NdefComplSectMax = PH_FRINFC_MFSTD_FMT_VAL_0, |
| NdefComplSectTemp = PH_FRINFC_MFSTD_FMT_VAL_1, |
| SectIndex = PH_FRINFC_MFSTD_FMT_VAL_0, |
| MaxCont = PH_FRINFC_MFSTD_FMT_VAL_0, |
| MaxSect = PH_FRINFC_MFSTD_FMT_VAL_0; |
| |
| /* Get the maximum sector depending on the sector */ |
| MaxSect = ((CardTypes == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD)? |
| PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_1K: |
| PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K); |
| /* Sector index */ |
| NdefComplSectTemp = SectIndex = PH_FRINFC_MFSTD_FMT_VAL_1; |
| /* Check the sector index depending on the card type */ |
| while(((SectIndex < PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K) && |
| (CardTypes == PH_FRINFC_SMTCRDFMT_MFSTD_4K_CRD)) || |
| ((SectIndex < PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_1K) && |
| (CardTypes == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD))) |
| { |
| if (Sector[SectIndex] == |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL) |
| { |
| if (MaxCont > count) |
| { |
| /* Store the maximum contiguous */ |
| NdefComplSectMax = NdefComplSectTemp; |
| count = MaxCont; |
| } |
| MaxCont = PH_FRINFC_MFSTD_FMT_VAL_0; |
| /* Increment the sector index */ |
| PH_FRINFC_MFSTD_FMT_INCR_SECT; |
| /* Get the next compliant sector */ |
| NdefComplSectTemp = SectIndex; |
| } |
| else |
| { |
| /* Increment the sector index */ |
| PH_FRINFC_MFSTD_FMT_INCR_SECT; |
| } |
| MaxCont ++; |
| |
| } |
| if (MaxCont > count) |
| { |
| /* Store the maximum contiguous */ |
| NdefComplSectMax = NdefComplSectTemp; |
| count = MaxCont; |
| } |
| /* Set the sector value has non ndef compliant which are not present with |
| contiguous ndef compliant sectors */ |
| if((((count < (MaxSect - PH_FRINFC_MFSTD_FMT_VAL_1)) && (CardTypes |
| == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD)) || |
| ((count < (MaxSect - PH_FRINFC_MFSTD_FMT_VAL_2)) && (CardTypes |
| == PH_FRINFC_SMTCRDFMT_MFSTD_4K_CRD))) && |
| ((NdefComplSectMax > PH_FRINFC_MFSTD_FMT_VAL_0) && |
| (NdefComplSectMax < (MaxSect - PH_FRINFC_MFSTD_FMT_VAL_2)))) |
| { |
| (void)memset(&Sector[PH_FRINFC_MFSTD_FMT_VAL_1], |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL, |
| (NdefComplSectMax - PH_FRINFC_MFSTD_FMT_VAL_1)); |
| |
| (void)memset(&Sector[(NdefComplSectMax + count)], |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL, |
| (MaxSect - (NdefComplSectMax + count))); |
| } |
| } |
| |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProWrMADBlk(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock) |
| { |
| case PH_FRINFC_MFSTD_FMT_VAL_1: |
| /* MAD blocks, still not completed */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_MAD_BLK; |
| /* MAD block number 2 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_VAL_2; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_VAL_2: |
| /* Now write to MAD block is completed */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag = |
| PH_FRINFC_MFSTD_FMT_VAL_1; |
| /* Now write the sector trailer, so change the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_SECT_TR; |
| /* MAD block number 3 = Sector trailer */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_VAL_3; |
| break; |
| |
| case 64: |
| /* MAD blocks, still not completed */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_MAD_BLK; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = 65; |
| break; |
| |
| case 65: |
| /* MAD blocks, still not completed */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_MAD_BLK; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = 66; |
| break; |
| |
| case 66: |
| default: |
| /* Now write to MAD block is completed */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.WrMADBlkFlag = |
| PH_FRINFC_MFSTD_FMT_VAL_1; |
| /* Now write the sector trailer, so change the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_WR_SECT_TR; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = 67; |
| break; |
| |
| } |
| /* Write the block */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProErrAuth( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) |
| { |
| NFCSTATUS Result = NdefSmtCrdFmt->FmtProcStatus; |
| uint8_t Buffer[1] = {PH_FRINFC_MFSTD_FMT_NDEF_COMPL}, |
| index = PH_FRINFC_MFSTD_FMT_VAL_1; |
| uint32_t memcompare = PH_FRINFC_MFSTD_FMT_VAL_1; |
| |
| if ((NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == 67) && |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState == |
| PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB)) |
| { |
| /* Error in the MAD sector 16, so the remaining sector |
| information cant be updated */ |
| (void)memset(&NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[16], |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL, |
| (PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K - 16)); |
| PH_FRINFC_MFSTD_FMT_CHK_END_OF_CARD(); |
| } |
| else if(((NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock > |
| PH_FRINFC_MFSTD_FMT_VAL_3) && |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState != |
| PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB)) || |
| ((NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == |
| PH_FRINFC_MFSTD_FMT_VAL_3) && |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState < |
| PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB))) |
| { |
| /* Authenticate failed, so disconnect, poll and connect */ |
| Result = phFriNfc_MfStd_H_CallDisCon(NdefSmtCrdFmt, |
| Result); |
| } |
| else |
| { |
| if (NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == |
| PH_FRINFC_MFSTD_FMT_VAL_3) |
| { |
| (void)memset(NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl, |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL, |
| PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K); |
| } |
| } |
| |
| return Result; |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ProUpdMADBlk(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) |
| { |
| NFCSTATUS Result = NFCSTATUS_SUCCESS; |
| switch(NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk) |
| { |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_1: |
| /* Write the next MAD Block */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = (uint8_t) |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_2; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_2; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_2: |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_66: |
| if((NdefSmtCrdFmt->CardType == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD) || |
| (NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock == |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66)) |
| { |
| /* Get the block from where the TLV has to be written */ |
| phFriNfc_MfStd_H_BlkNoToWrTLV(NdefSmtCrdFmt); |
| |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = |
| PH_FRINFC_MFSTD_FMT_AUTH_NFC_KEY; |
| } |
| else |
| { |
| /* Write the next MAD Block */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = (uint8_t) |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_64; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_64; |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = |
| PH_FRINFC_MFSTD_FMT_AUTH_SCRT_KEYB; |
| } |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_64: |
| /* Write the next MAD Block */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = (uint8_t) |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_65; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_65; |
| break; |
| |
| case PH_FRINFC_MFSTD_FMT_MAD_BLK_65: |
| default: |
| /* Write the next MAD Block */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.UpdMADBlk = (uint8_t) |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = |
| PH_FRINFC_MFSTD_FMT_MAD_BLK_66; |
| break; |
| } |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| return Result; |
| } |
| |
| static void phFriNfc_MfStd_H_StrNdefData( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) |
| { |
| uint8_t SectIndex = PH_FRINFC_MFSTD_FMT_VAL_1, |
| index = PH_FRINFC_MFSTD_FMT_VAL_0; |
| |
| (void)memset(NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk, |
| 0x00, |
| PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K); |
| |
| /* Zeroth sector of the Mifare card is MAD sector, CRC is 0x14 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[PH_FRINFC_MFSTD_FMT_VAL_0] = 0x14; |
| /* Info byte is 0x01, because the NDEF application is written and as per the MAD spec, |
| the value for miscellaneous application is 0x01 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[PH_FRINFC_MFSTD_FMT_VAL_1] = 0x01; |
| |
| if(NdefSmtCrdFmt->CardType == PH_FRINFC_SMTCRDFMT_MFSTD_4K_CRD) |
| { |
| /* If 4k card then sector number 16 is MAD sector, CRC is 0xE8 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[32] = 0xE8; |
| /* Info byte is 0x01, because the NDEF application is written and |
| as per the MAD spec, |
| the value for miscellaneous application is 0x01 */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[33] = 0x01; |
| } |
| /* NDEF information has to be updated from */ |
| index = PH_FRINFC_MFSTD_FMT_VAL_2; |
| /* Depending on the card type, check the sector index */ |
| while (((SectIndex < PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K) && |
| (NdefSmtCrdFmt->CardType == PH_FRINFC_SMTCRDFMT_MFSTD_4K_CRD)) || |
| ((SectIndex < PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_1K) && |
| (NdefSmtCrdFmt->CardType == PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD))) |
| { |
| /* Is the sector ndef compliant? */ |
| if(NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] == |
| PH_FRINFC_MFSTD_FMT_NDEF_COMPL) |
| { |
| /* Ndef compliant sector, update the MAD sector array |
| in the context with values 0x03 and 0xE1 |
| 0x03 and 0xE1 is NDEF information in MAD sector */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[index] = |
| PH_FRINFC_MFSTD_FMT_NDEF_INFO1; |
| index++; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[index] = |
| PH_FRINFC_MFSTD_FMT_NDEF_INFO2; |
| index++; |
| } |
| else |
| { |
| /* Not a Ndef compliant sector, update the MAD sector array |
| in the context with values 0x00 and 0x00 |
| 0x00 and 0x00 is NDEF information in MAD sector */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[index] = 0x00; |
| index++; |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.MADSectBlk[index] = 0x00; |
| index++; |
| } |
| /* Go to next sector */ |
| SectIndex++; |
| /* is the sector, a MAD sector 16? */ |
| if(SectIndex == PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_1K) |
| { |
| /* MAD sector number 16, so skip this sector */ |
| SectIndex = SectIndex + PH_FRINFC_MFSTD_FMT_VAL_1; |
| index = index + PH_FRINFC_MFSTD_FMT_VAL_2; |
| } |
| } |
| } |
| |
| static void phFriNfc_MfStd_H_BlkNoToWrTLV( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) |
| { |
| uint8_t SectIndex = (uint8_t)PH_FRINFC_MFSTD_FMT_VAL_1; |
| while (((SectIndex < (uint8_t)PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K) && |
| (NdefSmtCrdFmt->CardType == (uint8_t)PH_FRINFC_SMTCRDFMT_MFSTD_4K_CRD)) || |
| ((SectIndex < (uint8_t)PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_1K) && |
| (NdefSmtCrdFmt->CardType == (uint8_t)PH_FRINFC_SMTCRDFMT_MFSTD_1K_CRD))) |
| { |
| if (NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] == |
| (uint8_t)PH_FRINFC_MFSTD_FMT_NDEF_COMPL) |
| { |
| /* Get the first NFC forum sector's block */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.CurrentBlock = (uint16_t) |
| (((SectIndex & 0xE0) >= 32)? |
| (128 + ((SectIndex % 32) * 16)): |
| (SectIndex * (uint8_t)PH_FRINFC_MFSTD_FMT_VAL_4)); |
| /* Break out of the loop */ |
| SectIndex += (uint8_t)PH_FRINFC_MFSTD_FMT_MAX_SECT_IND_4K; |
| } |
| SectIndex++; |
| } |
| } |
| |
| static NFCSTATUS phFriNfc_MfStd_H_ErrRdSectTr( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) |
| { |
| NFCSTATUS Result = NdefSmtCrdFmt->FmtProcStatus; |
| uint8_t Buffer[1] = {PH_FRINFC_MFSTD_FMT_NDEF_COMPL}, |
| index = PH_FRINFC_MFSTD_FMT_VAL_1, |
| SectIndex = PH_FRINFC_MFSTD_FMT_VAL_0; |
| uint32_t memcompare = PH_FRINFC_MFSTD_FMT_VAL_1; |
| /* If default key A is used for authentication and if write fails, then try to |
| authenticate using key B*/ |
| if(NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState == |
| PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY) |
| { |
| /* Change the state to authentication */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* internal authenticate state = key B */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = PH_FRINFC_MFSTD_FMT_AUTH_KEYB; |
| /* Now call authenticate */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| else |
| { |
| /* Calculate sector index */ |
| SectIndex = (uint8_t)PH_FRINFC_MFSTD_FMT_SECT_INDEX_CALC; |
| |
| /* Sector is ndef compliance */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.SectCompl[SectIndex] = (uint8_t) |
| ((NdefSmtCrdFmt->FmtProcStatus != NFCSTATUS_SUCCESS)? |
| PH_FRINFC_MFSTD_FMT_NON_NDEF_COMPL: |
| PH_FRINFC_MFSTD_FMT_NDEF_COMPL); |
| |
| /* Increment the current block */ |
| PH_FRINFC_MFSTD_FMT_CUR_BLK_INC(); |
| SectIndex++; |
| if(PH_FRINFC_MFSTD_FMT_CUR_BLK_CHK) |
| { |
| PH_FRINFC_MFSTD_FMT_CHK_END_OF_CARD(); |
| } |
| else |
| { |
| /* Set the state */ |
| NdefSmtCrdFmt->State = PH_FRINFC_MFSTD_FMT_AUTH_SECT; |
| /* Set the authenticate state */ |
| NdefSmtCrdFmt->AddInfo.MfStdInfo.AuthState = |
| PH_FRINFC_MFSTD_FMT_AUTH_DEF_KEY; |
| /* Start authentication */ |
| Result = phFriNfc_MfStd_H_WrRdAuth(NdefSmtCrdFmt); |
| } |
| } |
| return Result; |
| } |
| |
| static int phFriNfc_MfStd_MemCompare( void *s1, void *s2, unsigned int n ) |
| { |
| int8_t diff = 0; |
| int8_t *char_1 =(int8_t *)s1; |
| int8_t *char_2 =(int8_t *)s2; |
| if(NULL == s1 || NULL == s2) |
| { |
| PHDBG_CRITICAL_ERROR("NULL pointer passed to memcompare"); |
| } |
| else |
| { |
| for(;((n>0)&&(diff==0));n--,char_1++,char_2++) |
| { |
| diff = *char_1 - *char_2; |
| } |
| } |
| return (int)diff; |
| } |
| |
| |
| |
| #ifdef UNIT_TEST |
| #include <phUnitTestNfc_MifStdFormat_static.c> |
| #endif |