/* * 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_MifULFormat.c * \brief NFC Ndef Formatting For Mifare ultralight card. * * Project: NFC-FRI * * $Date: Mon Dec 13 14:14:12 2010 $ * $Author: ing02260 $ * $Revision: 1.9 $ * $Aliases: $ * */ #include #include /*! \ingroup grp_file_attributes * \name NDEF Mapping * * File: \ref phFriNfc_MifULFormat.c * */ /*@{*/ #define PHFRINFCMIFULFORMAT_FILEREVISION "$Revision: 1.9 $" #define PHFRINFCMIFULFORMAT_FILEALIASES "$Aliases: $" /*@}*/ #ifdef FRINFC_READONLY_NDEF /* Mifare UL OTP block number is 3 */ #define RD_LOCK_OTP_BLOCK_NUMBER 0x02U #define OTP_BLOCK_NUMBER 0x03U /* READ ONLY value that shall be written in the OTP to make the card read only */ #define READ_ONLY_VALUE_IN_OTP 0x0FU /* Mifare UL OTP block number is 3 */ #define MIFARE_UL_READ_MAX_SIZE 16U /* Lock byte value */ #define MIFARE_UL_LOCK_BYTE_VALUE 0xFFU #endif /* #ifdef FRINFC_READONLY_NDEF */ /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function calls the * transceive function */ static NFCSTATUS phFriNfc_MfUL_H_Transceive(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function calls the * read or write operation */ static NFCSTATUS phFriNfc_MfUL_H_WrRd(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function fills the * send buffer for transceive function */ static void phFriNfc_MfUL_H_fillSendBuf(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t BlockNo); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function shall process * the read bytes */ static NFCSTATUS phFriNfc_MfUL_H_ProRd16Bytes(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function shall process the * OTP bytes written */ static NFCSTATUS phFriNfc_MfUL_H_ProWrOTPBytes(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); static int MemCompare1 ( void *s1, void *s2, unsigned int n ); /*The function does a comparision of two strings and returns a non zero value if two strings are unequal*/ static int MemCompare1 ( 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; } void phFriNfc_MfUL_Reset(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { uint8_t OTPByte[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_0; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByte, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); #ifdef FRINFC_READONLY_NDEF NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[0] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[1] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[3] = 0; #endif /* #ifdef FRINFC_READONLY_NDEF */ } NFCSTATUS phFriNfc_MfUL_Format(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS Result = NFCSTATUS_SUCCESS; uint8_t OTPByte[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_0; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByte, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); /* Set the state */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RD_16BYTES; /* Initialise current block to the lock bits block */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_2; /* Start authentication */ Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); return Result; } #ifdef FRINFC_READONLY_NDEF NFCSTATUS phFriNfc_MfUL_ConvertToReadOnly ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_RD_16BYTES; result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); return result; } #endif /* #ifdef FRINFC_READONLY_NDEF */ void phFriNfc_MfUL_Process(void *Context, NFCSTATUS Status) { phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt = (phFriNfc_sNdefSmtCrdFmt_t *)Context; if(Status == NFCSTATUS_SUCCESS) { switch(NdefSmtCrdFmt->State) { case PH_FRINFC_MFUL_FMT_RD_16BYTES: Status = phFriNfc_MfUL_H_ProRd16Bytes(NdefSmtCrdFmt); break; case PH_FRINFC_MFUL_FMT_WR_OTPBYTES: Status = phFriNfc_MfUL_H_ProWrOTPBytes(NdefSmtCrdFmt); break; case PH_FRINFC_MFUL_FMT_WR_TLV: #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { /* Write NDEF TLV in block number 5 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_5; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV1; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ break; #ifdef FRINFC_READONLY_NDEF case PH_FRINFC_MFUL_FMT_RO_RD_16BYTES: { if (MIFARE_UL_READ_MAX_SIZE == *NdefSmtCrdFmt->SendRecvLength) { uint8_t otp_lock_page_size = 0; uint8_t i = 0; otp_lock_page_size = sizeof (NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes); (void)memcpy ((void *)NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes, (void *)NdefSmtCrdFmt->SendRecvBuf, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes)); NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] = MIFARE_UL_LOCK_BYTE_VALUE; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[3] = MIFARE_UL_LOCK_BYTE_VALUE; i = (uint8_t)(i + otp_lock_page_size); otp_lock_page_size = sizeof (NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes); (void)memcpy ((void *)NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, (void *)(NdefSmtCrdFmt->SendRecvBuf + i), sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[(otp_lock_page_size - 1)] = READ_ONLY_VALUE_IN_OTP; NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } break; } case PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES: { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } case PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES: { /* Do nothing */ break; } #endif /* #ifdef FRINFC_READONLY_NDEF */ #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_WR_TLV1: break; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ default: Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } /* Status is not success then call completion routine */ if(Status != NFCSTATUS_PENDING) { phFriNfc_SmtCrdFmt_HCrHandler(NdefSmtCrdFmt, Status); } } static NFCSTATUS phFriNfc_MfUL_H_WrRd( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Fill the send buffer */ phFriNfc_MfUL_H_fillSendBuf(NdefSmtCrdFmt, NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock); /* Call transceive */ Result = phFriNfc_MfUL_H_Transceive(NdefSmtCrdFmt); return Result; } static NFCSTATUS phFriNfc_MfUL_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 void phFriNfc_MfUL_H_fillSendBuf( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t BlockNo) { #ifdef PH_NDEF_MIFARE_ULC uint8_t NDEFTLV1[4] = {0x01, 0x03, 0xA0, 0x10}; uint8_t NDEFTLV2[4] = {0x44, 0x03, 0x00, 0xFE}; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ uint8_t NDEFTLV[4] = {0x03, 0x00, 0xFE, 0x00}; /* First byte for send buffer is always the block number */ NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_0] = (uint8_t)BlockNo; switch(NdefSmtCrdFmt->State) { #ifdef FRINFC_READONLY_NDEF case PH_FRINFC_MFUL_FMT_RO_RD_16BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ *NdefSmtCrdFmt->SendRecvBuf = RD_LOCK_OTP_BLOCK_NUMBER; /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; } case PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; *NdefSmtCrdFmt->SendRecvBuf = RD_LOCK_OTP_BLOCK_NUMBER; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; } case PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; *NdefSmtCrdFmt->SendRecvBuf = OTP_BLOCK_NUMBER; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; } #endif /* #ifdef FRINFC_READONLY_NDEF */ case PH_FRINFC_MFUL_FMT_RD_16BYTES: #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; case PH_FRINFC_MFUL_FMT_WR_OTPBYTES: /* Send length for read command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Copy the OTP bytes */ (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; case PH_FRINFC_MFUL_FMT_WR_TLV: #ifndef PH_NDEF_MIFARE_ULC default: #endif /* #ifndef PH_NDEF_MIFARE_ULC */ /* Send length for read command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Copy the NDEF TLV */ #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV1, PH_FRINFC_MFUL_FMT_VAL_4); } else if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_UL_CARD) { (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV, PH_FRINFC_MFUL_FMT_VAL_4); } else { } #else (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV, PH_FRINFC_MFUL_FMT_VAL_4); #endif /* #ifdef PH_NDEF_MIFARE_ULC */ break; #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_WR_TLV1: if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { /* Send length for write command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV2, PH_FRINFC_MFUL_FMT_VAL_4); } break; default: break; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ } } static NFCSTATUS phFriNfc_MfUL_H_ProRd16Bytes( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_FORMAT_ERROR); uint32_t memcompare = PH_FRINFC_MFUL_FMT_VAL_0; uint8_t ZeroBuf[] = {0x00, 0x00, 0x00, 0x00}; #ifdef PH_NDEF_MIFARE_ULC uint8_t OTPByteUL[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; uint8_t OTPByteULC[] = PH_FRINFC_MFULC_FMT_OTP_BYTES; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ /* Check the lock bits (byte number 2 and 3 of block number 2) */ if ((NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_2] == PH_FRINFC_MFUL_FMT_LOCK_BITS_VAL) && (NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_3] == PH_FRINFC_MFUL_FMT_LOCK_BITS_VAL)) { #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->SendRecvBuf[8] == 0x02 && NdefSmtCrdFmt->SendRecvBuf[9] == 0x00) { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByteULC, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); } else if (NdefSmtCrdFmt->SendRecvBuf[8] == 0xFF && NdefSmtCrdFmt->SendRecvBuf[9] == 0xFF) { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_UL_CARD; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByteUL, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); } else { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_UL_CARD; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ memcompare = (uint32_t) MemCompare1(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_4], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); if (memcompare == PH_FRINFC_MFUL_FMT_VAL_0) { /* Write NDEF TLV in block number 4 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_4; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV; } else { /* IS the card new, OTP bytes = {0x00, 0x00, 0x00, 0x00} */ memcompare = (uint32_t)MemCompare1(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_4], ZeroBuf, PH_FRINFC_MFUL_FMT_VAL_4); /* If OTP bytes are Zero then the card is Zero */ if (memcompare == PH_FRINFC_MFUL_FMT_VAL_0) { /* Write OTP bytes in block number 3 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_3; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_OTPBYTES; } } } #ifdef PH_NDEF_MIFARE_ULC if( ((NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_TLV) || (NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_OTPBYTES)) && ((NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) || (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_UL_CARD)) ) #else if((NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_TLV) || (NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_OTPBYTES)) #endif /* #ifdef PH_NDEF_MIFARE_ULC */ { Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); } return Result; } static NFCSTATUS phFriNfc_MfUL_H_ProWrOTPBytes( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV; /* Write NDEF TLV in block number 4 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_4; Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); return Result; }