/* * 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_TopazDynamicMap.c * \brief NFC Ndef Mapping For Remote Devices. * * Project: NFC-FRI * * $Date: Wed Oct 27 10:21:29 2010 $ * $Author: ing02260 $ * $Revision: 1.41 $ * $Aliases: $ * */ #include <phFriNfc_NdefMap.h> #include <phFriNfc_TopazMap.h> #include <phFriNfc_MapTools.h> #include <phFriNfc_OvrHal.h> #if !(defined(PH_FRINFC_MAP_TOPAZ_DISABLED ) || defined (PH_FRINFC_MAP_TOPAZ_DYNAMIC_DISABLED )) /*! \ingroup grp_file_attributes * \name NDEF Mapping * * File: \ref phFriNfcNdefMap.c * */ /*@{*/ #define PHFRINFCTOPAZMAP_FILEREVISION "$Revision: 1.41 $" #define PHFRINFCTOPAZMAP_FILEALIASES "$Aliases: $" /*@}*/ /*! * \name Topaz Mapping - Helper data structures and macros * */ /*@{*/ /********************************** Start of data structures *********************************/ #ifdef FRINFC_READONLY_NDEF #define DYN_CC_BLOCK_NUMBER (0x01U) #define DYN_STATIC_LOCK_BLOCK_NUM (0x0EU) #define DYN_STATIC_LOCK0_BYTE_NUM (0x00U) #define DYN_STATIC_LOCK0_BYTE_VALUE (0xFFU) #define DYN_STATIC_LOCK1_BYTE_NUM (0x01U) #define DYN_STATIC_LOCK1_BYTE_VALUE (0x7FU) #define DYN_CC_RWA_BYTE_NUMBER (0x03U) #define DYN_CC_READ_ONLY_VALUE (0x0FU) #endif /* #ifdef FRINFC_READONLY_NDEF */ /*! * \brief \copydoc page_ovr enum for the topaz sequence of execution. */ typedef enum phFriNfc_Tpz_ParseSeq { LOCK_T_TLV, LOCK_L_TLV, LOCK_V_TLV, MEM_T_TLV, MEM_L_TLV, MEM_V_TLV, NDEF_T_TLV, NDEF_L_TLV, NDEF_V_TLV }phFriNfc_Tpz_ParseSeq_t; typedef enum phFriNfc_Tpz_WrSeq { WR_NDEF_T_TLV, WR_NMN_0, WR_LEN_1_0, WR_LEN_2_0, WR_LEN_3_0, WR_DATA, WR_DATA_READ_REQD, WR_LEN_1_VALUE, WR_LEN_2_VALUE, WR_LEN_3_VALUE, WR_NMN_E1 }phFriNfc_Tpz_WrSeq_t; #ifdef FRINFC_READONLY_NDEF typedef enum phFriNfc_Tpz_RO_Seq { WR_READONLY_CC, RD_LOCK_BYTES, WR_LOCK_BYTES, RD_STATIC_LOCK_BYTE0, WR_STATIC_LOCK_BYTE0, WR_STATIC_LOCK_BYTE1 }phFriNfc_Tpz_RO_Seq_t; #endif /* #ifdef FRINFC_READONLY_NDEF */ /********************************** End of data structures *********************************/ /********************************** Start of Macros *********************************/ /* New state for TOPAZ dynamic card*/ #define PH_FRINFC_TOPAZ_STATE_RD_FOR_WR_NDEF (0x10U) #ifdef FRINFC_READONLY_NDEF #define PH_FRINFC_TOPAZ_STATE_READ_ONLY (0x11U) #endif /* #ifdef FRINFC_READONLY_NDEF */ #define NIBBLE_SIZE (0x04U) /* Byte shifting for the topaz */ #define TOPAZ_BYTE_SHIFT (0x08U) /* Lock and memory control TLV length. Always 3 bytes */ #define TOPAZ_MEM_LOCK_TLV_LENGTH (0x03U) /* UID byte length */ #define TOPAZ_UID_BYTES_LENGTH (0x08U) /* Number os static lock and reserved bytes */ #define TOPAZ_STATIC_LOCK_RES_BYTES (0x18U) /* Number of static lock and reserved memory. This value is 3 (because block number D, E and F are lock and reserved blocks */ #define TOPAZ_STATIC_LOCK_BLOCK_AREAS (0x03U) /* First lock or reserved block in the static area of the card */ #define TOPAZ_STATIC_LOCK_FIRST_BLOCK_NO (0x0DU) /* First lock or reserved byte number in the static area of the card */ #define TOPAZ_STATIC_LOCK_RES_START (0x68U) /* End lock or reserved byte number in the static area of the card */ #define TOPAZ_STATIC_LOCK_RES_END (0x78U) /* CC byte length */ #define TOPAZ_CC_BYTES_LENGTH (0x04U) /* In TOPAZ card each block has 8 bytes */ #define TOPAZ_BYTES_PER_BLOCK (0x08U) /* Each byte has 8 bites */ #define TOPAZ_BYTE_SIZE_IN_BITS (0x08U) /* This mask is to get the least significant NIBBLE from a BYTE */ #define TOPAZ_NIBBLE_MASK (0x0FU) /* This is used to mask the least significant BYTE from a TWO BYTE value */ #define TOPAZ_BYTE_LENGTH_MASK (0x00FFU) /* Total segments in TOPAZ 512 bytes card. Each segment = 128 bytes, so there are 4 segements in the card */ #define TOPAZ_TOTAL_SEG_TO_READ (0x04U) /* SPEC version value shall be 0x10 as per the TYPE 1 specification */ #define TOPAZ_SPEC_VERSION (0x10U) /* Response length for READ SEGMENT command is 128 bytes */ #define TOPAZ_SEGMENT_READ_LENGTH (0x80U) /* Response length for WRITE-1E command is 1 byte */ #define TOPAZ_WRITE_1_RESPONSE (0x01U) /* Response length for WRITE-8E command is 8 bytes */ #define TOPAZ_WRITE_8_RESPONSE (0x08U) /* Response length for READ-8 command is 8 bytes */ #define TOPAZ_READ_8_RESPONSE (0x08U) /* Data bytes that can be written for the WRITE-8E command is 8 bytes */ #define TOPAZ_WRITE_8_DATA_LENGTH (0x08U) /* Get the exact byte address of the card from the segment number and the parse index of each segment */ #define TOPAZ_BYTE_ADR_FROM_SEG(seg, parse_index) \ (((seg) * TOPAZ_SEGMENT_READ_LENGTH) + (parse_index)) /* Get the segment number of the card from the byte address */ #define TOPAZ_SEG_FROM_BYTE_ADR(byte_addr) \ ((byte_addr) / TOPAZ_SEGMENT_READ_LENGTH) /* Get the block number of the card from the byte address */ #define TOPAZ_BLK_FROM_BYTE_ADR(byte_addr) \ ((byte_addr) / TOPAZ_BYTES_PER_BLOCK) /* Get the block offset of a block number of the card from the byte address */ #define TOPAZ_BYTE_OFFSET_FROM_BYTE_ADR(byte_addr) \ ((byte_addr) % TOPAZ_BYTES_PER_BLOCK) /* Get the exact byte address of the card from the block number and the byte offset of the block number */ #define TOPAZ_BYTE_ADR_FROM_BLK(block_no, byte_offset) \ (((block_no) * TOPAZ_BYTES_PER_BLOCK) + (byte_offset)) /* To increment the block number and if block number overlaps with the static lock and reserved blocks, then skip the blocks */ #define TOPAZ_INCREMENT_SKIP_STATIC_BLOCK(block_no) \ ((((block_no) + 1) == TOPAZ_STATIC_LOCK_FIRST_BLOCK_NO) ? \ (((block_no) + 1) + TOPAZ_STATIC_LOCK_BLOCK_AREAS) : \ ((block_no) + 1)) /* Check topaz spec version number */ #define TOPAZ_COMPARE_VERSION(device_ver, tag_ver) \ ((device_ver & 0xF0) >= (tag_ver & 0xF0)) #ifdef FRINFC_READONLY_NDEF #define TOPAZ_CONVERT_BITS_TO_BYTES(bits_to_bytes) \ (((bits_to_bytes % TOPAZ_BYTE_SIZE_IN_BITS) > 0) ? \ ((bits_to_bytes / TOPAZ_BYTE_SIZE_IN_BITS) + 1) : \ (bits_to_bytes / TOPAZ_BYTE_SIZE_IN_BITS)) #endif /* #ifdef FRINFC_READONLY_NDEF */ /********************************** End of Macros *********************************/ /*@}*/ /*! * \name Topaz Mapping - Helper Functions * */ /*@{*/ /*! * \brief \copydoc page_ovr Helper function for Topaz. This function shall read defined * bytes from the card. */ static NFCSTATUS phFriNfc_Tpz_H_NxpRead ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function shall process * received read id command. */ static NFCSTATUS phFriNfc_Tpz_H_ChkReadID ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function shall process * read response. */ static NFCSTATUS phFriNfc_Tpz_H_ProReadResp ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function calls the * completion routine */ static void phFriNfc_Tpz_H_Complete ( phFriNfc_NdefMap_t *NdefMap, NFCSTATUS Status); /*! * \brief \copydoc page_ovr Helper function for Topaz check ndef. This function checks * the lock bits and set a card state */ static NFCSTATUS phFriNfc_Tpz_H_ChkLockBits ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function writes defined * bytes into the card */ static NFCSTATUS phFriNfc_Tpz_H_NxpWrite ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_write_data, uint8_t wr_data_len); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function parses the read bytes * till the NDEF TLV is found. Also, it returns error if it founds wrong TLVs. */ static NFCSTATUS phFriNfc_Tpz_H_ParseTLVs ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function parses the read bytes * till the TYPE of the LOCK control TLV is found. * Also, it returns error if it founds wrong TYPE. */ static NFCSTATUS phFriNfc_Tpz_H_ParseLockTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function parses the read bytes * till the TYPE of the MEMORY control TLV is found. * Also, it returns error if it founds wrong TYPE. */ static NFCSTATUS phFriNfc_Tpz_H_ParseMemTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function parses the read bytes * till the TYPE of the NDEF control TLV is found. * Also, it returns error if it founds wrong TYPE. */ static NFCSTATUS phFriNfc_Tpz_H_ParseNdefTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gets the lock bytes * information. */ static NFCSTATUS phFriNfc_Tpz_H_GetLockBytesInfo ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_lock_info); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gets the reserved bytes * information. */ static NFCSTATUS phFriNfc_Tpz_H_GetMemBytesInfo ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_mem_info); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function copies and checks the CC bytes. * This function checks for the lock bytes value and card state also. */ static NFCSTATUS phFriNfc_Tpz_H_CheckCCBytes ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function checks the CC bytes. * If . */ static NFCSTATUS phFriNfc_Tpz_H_CheckCCBytesForWrite ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function copies the read bytes. * This function also checks for the lock and reserved bytes and skips the bytes before copying it * in the buffer. */ static NFCSTATUS phFriNfc_Tpz_H_CopyReadData ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function copies the stored read bytes. * This function is used only for the offset " PH_FRINFC_NDEFMAP_SEEK_CUR ". */ static NFCSTATUS phFriNfc_Tpz_H_RemainingReadDataCopy ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gives the exact byte address * of the value field after the NDEF TYPE field */ static uint16_t phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gives the exact byte address * of the value field after the NDEF TYPE field */ static uint16_t phFriNfc_Tpz_H_GetNDEFValueFieldAddrForWrite ( phFriNfc_NdefMap_t *psNdefMap, uint16_t size_to_write); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gives the number of bytes to skip. * This function checks the input byte address and checks if any lock or reserved bytes matches with the * given address. if yes, then it will return number od bytes to skip. */ static uint16_t phFriNfc_Tpz_H_GetSkipSize ( phFriNfc_NdefMap_t *psNdefMap, uint16_t byte_adr_card); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function gives the actual data that can * be read and written in the card. * This function checks for the lock and reserved bytes and subtracts the remaining size to give the * actual size. */ static NFCSTATUS phFriNfc_Tpz_H_ActualCardSize ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function processes the response for * the write data */ static NFCSTATUS phFriNfc_Tpz_H_ProWrResp ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function processes the read 8 commands, * that is required for writing the data */ static NFCSTATUS phFriNfc_Tpz_H_ProRdForWrResp ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function copies the user data to the * write buffer and writes the data to the card. If the lock or memory blocks are in between the * write data, then read the current block */ static NFCSTATUS phFriNfc_Tpz_H_CopySendWrData ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function compares the input block * number with lock bytes block number and returns the p_skip_size which is the lock bytes * size */ static uint16_t phFriNfc_Tpz_H_CompareLockBlocks ( phFriNfc_NdefMap_t *psNdefMap, uint8_t block_no, uint16_t *p_skip_size); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function compares the input block * number with reserved bytes block number and returns the p_skip_size which is the reserved bytes * size */ static uint16_t phFriNfc_Tpz_H_CompareMemBlocks ( phFriNfc_NdefMap_t *psNdefMap, uint8_t block_no, uint16_t *p_skip_size); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function copies the read data and update * the user bytes by skipping lock or memory control areas. Also, used while updating the value field * skips the initial bytes and to start at the proper value field byte offset of the block */ static NFCSTATUS phFriNfc_Tpz_H_CopyReadDataAndWrite ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function reads the required block for writing, * as some of the bytes shall not be overwritten */ static NFCSTATUS phFriNfc_Tpz_H_RdForWrite ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function reads the length block for writing, * updates the length bytes with 0 */ static NFCSTATUS phFriNfc_Tpz_H_UpdateLenFieldZeroAfterRead ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function reads the length block for writing, * updates the length bytes with exact bytes that was written in the card */ static NFCSTATUS phFriNfc_Tpz_H_UpdateLenFieldValuesAfterRead ( phFriNfc_NdefMap_t *psNdefMap); /*! * \brief \copydoc page_ovr Helper function for Topaz. This function writes the NDEF TYPE of the * NDEF TLV to the specific byte address. This function is called only if the previous write is * failed or there is no NDEF TLV with correct CC bytes */ static NFCSTATUS phFriNfc_Tpz_H_UpdateNdefTypeField ( phFriNfc_NdefMap_t *psNdefMap); #ifdef FRINFC_READONLY_NDEF static NFCSTATUS phFriNfc_Tpz_H_ProcessReadOnly ( phFriNfc_NdefMap_t *psNdefMap); static NFCSTATUS phFriNfc_Tpz_H_UpdateAndWriteLockBits ( phFriNfc_NdefMap_t *psNdefMap); #endif /* #ifdef FRINFC_READONLY_NDEF */ /*! * \brief Check whether a particular Remote Device is NDEF compliant. * * The function checks whether the peer device is NDEF compliant. * * \param[in] NdefMap Pointer to a valid instance of the \ref phFriNfc_NdefMap_t * structure describing the component context. * * \retval NFCSTATUS_PENDING The action has been successfully triggered. * \retval Others An error has occurred. * */ NFCSTATUS phFriNfc_TopazDynamicMap_ChkNdef( phFriNfc_NdefMap_t *NdefMap) { NFCSTATUS Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_PARAMETER); if ( NdefMap != NULL) { /* Update the previous operation */ NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_CHECK_OPE; /* Update the CR index to know from which operation completion routine has to be called */ NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_CHK_NDEF; NdefMap->TopazContainer.Cur_RW_Index = PH_FRINFC_TOPAZ_VAL0; NdefMap->TopazContainer.CurrentSeg = 0; NdefMap->TopazContainer.NdefTLVByteAddress = 0; NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID; NdefMap->TopazContainer.CurrentBlock = 0; NdefMap->TopazContainer.WriteSeq = 0; NdefMap->TopazContainer.ExpectedSeq = 0; (void)memset ((void *)&(NdefMap->LockTlv), 0, sizeof (phFriNfc_LockCntrlTLVCont_t)); (void)memset ((void *)&(NdefMap->MemTlv), 0, sizeof (phFriNfc_ResMemCntrlTLVCont_t)); /* Set card state */ NdefMap->CardType = PH_FRINFC_NDEFMAP_TOPAZ_DYNAMIC_CARD; /* Change the state to Read */ NdefMap->State = PH_FRINFC_TOPAZ_STATE_READ; NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_DYNAMIC_INIT_CHK_NDEF; #ifdef TOPAZ_RAW_SUPPORT *NdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_RSEG; #else #ifdef PH_HAL4_ENABLE NdefMap->Cmd.JewelCmd = phHal_eJewel_ReadSeg; #else NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif #endif /* #ifdef TOPAZ_RAW_SUPPORT */ Result = phFriNfc_Tpz_H_NxpRead(NdefMap); } return Result; } /*! * \brief Initiates Reading of NDEF information from the Remote Device. * * The function initiates the reading of NDEF information from a Remote Device. * It performs a reset of the state and starts the action (state machine). * A periodic call of the \ref phFriNfcNdefMap_Process has to be done once the action * has been triggered. */ NFCSTATUS phFriNfc_TopazDynamicMap_RdNdef( phFriNfc_NdefMap_t *NdefMap, uint8_t *PacketData, uint32_t *PacketDataLength, uint8_t Offset) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Copy user buffer to the context */ NdefMap->ApduBuffer = PacketData; /* Copy user length to the context */ NdefMap->ApduBufferSize = *PacketDataLength; /* Update the user memory size to a context variable */ NdefMap->NumOfBytesRead = PacketDataLength; /* Number of bytes read from the card is zero. This variable returns the number of bytes read from the card. */ *NdefMap->NumOfBytesRead = 0; /* Index to know the length read */ NdefMap->ApduBuffIndex = PH_FRINFC_TOPAZ_VAL0; /* Store the offset in the context */ NdefMap->Offset = Offset; /* Update the CR index to know from which operation completion routine has to be called */ NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_RD_NDEF; NdefMap->TopazContainer.SkipLockBlkFlag = 0; NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_READ_OPE; if ((PH_FRINFC_NDEFMAP_SEEK_CUR == Offset) && (TRUE == NdefMap->TopazContainer.ReadWriteCompleteFlag)) { Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_EOF_NDEF_CONTAINER_REACHED); } else if ((PH_NDEFMAP_CARD_STATE_INITIALIZED == NdefMap->CardState) || (0 == NdefMap->TopazContainer.ActualNDEFMsgSize)) { /* Length field of NDEF TLV is 0, so read cannot proceed */ Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_READ_FAILED); } else if ((PH_FRINFC_NDEFMAP_SEEK_BEGIN == Offset) || (PH_FRINFC_NDEFMAP_READ_OPE != NdefMap->PrevOperation)) { /* If previous operation is not read then the read shall start from BEGIN */ NdefMap->Offset = PH_FRINFC_NDEFMAP_SEEK_BEGIN; /* Initialise byte number */ NdefMap->TopazContainer.Cur_RW_Index = PH_FRINFC_TOPAZ_VAL0; NdefMap->TopazContainer.RemainingReadSize = 0; NdefMap->TopazContainer.ReadBufferSize = 0; NdefMap->TopazContainer.ReadWriteCompleteFlag = FALSE; NdefMap->TopazContainer.CurrentBlock = 0; NdefMap->TopazContainer.WriteSeq = 0; NdefMap->TopazContainer.CurrentSeg = (uint8_t)TOPAZ_SEG_FROM_BYTE_ADR ( phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead (NdefMap)); /* Change the state to Read ID */ NdefMap->State = PH_FRINFC_TOPAZ_STATE_READID; /*Change the state to Read ID*/ NdefMap->TopazContainer.ReadWriteCompleteFlag = 0; #ifdef TOPAZ_RAW_SUPPORT NdefMap->SendRecvBuf[0] = PH_FRINFC_TOPAZ_CMD_READID; #else #ifdef PH_HAL4_ENABLE NdefMap->Cmd.JewelCmd = phHal_eJewel_RID; #else NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRid; #endif #endif /* #ifdef TOPAZ_RAW_SUPPORT */ Result = phFriNfc_Tpz_H_NxpRead(NdefMap); } else { /* Change the state to Read */ NdefMap->State = PH_FRINFC_TOPAZ_STATE_READ; Result = phFriNfc_Tpz_H_RemainingReadDataCopy (NdefMap); } return Result; } #ifdef FRINFC_READONLY_NDEF NFCSTATUS phFriNfc_TopazDynamicMap_ConvertToReadOnly ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t cc_read_only_byte = 0x0FU; psNdefMap->State = PH_FRINFC_TOPAZ_STATE_READ_ONLY; psNdefMap->TopazContainer.read_only_seq = 0; psNdefMap->TopazContainer.CurrentBlock = 0x01U; psNdefMap->TopazContainer.ByteNumber = 0x03U; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = (uint8_t)PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, &cc_read_only_byte, 1); if (NFCSTATUS_PENDING == result) { psNdefMap->TopazContainer.read_only_seq = (uint8_t)WR_READONLY_CC; } return result; } #endif /* #ifdef FRINFC_READONLY_NDEF */ /*! * \brief Initiates Writing of NDEF information to the Remote Device. * * The function initiates the writing of NDEF information to a Remote Device. * It performs a reset of the state and starts the action (state machine). * A periodic call of the \ref phFriNfcNdefMap_Process has to be done once the action * has been triggered. */ NFCSTATUS phFriNfc_TopazDynamicMap_WrNdef( phFriNfc_NdefMap_t *NdefMap, uint8_t *PacketData, uint32_t *PacketDataLength, uint8_t Offset) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Copy user buffer to the context */ NdefMap->ApduBuffer = PacketData; /* Copy user length to the context */ NdefMap->ApduBufferSize = *PacketDataLength; /* Index to know the length written */ NdefMap->ApduBuffIndex = 0; /* Update the user memory size to a context variable */ NdefMap->WrNdefPacketLength = PacketDataLength; /* Number of bytes written to the card is zero. This variable returns the number of bytes written to the card. */ *NdefMap->WrNdefPacketLength = 0; /* Update the CR index to know from which operation completion routine has to be called */ NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_WR_NDEF; /* Store the offset in the context */ NdefMap->Offset = Offset; /* Update the previous operation to write operation */ NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_WRITE_OPE; if (PH_NDEFMAP_CARD_STATE_READ_ONLY == NdefMap->CardState) { Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_WRITE_FAILED); } else if ((PH_FRINFC_NDEFMAP_SEEK_CUR == Offset) && (TRUE == NdefMap->TopazContainer.ReadWriteCompleteFlag)) { /* Offset = Current, but the read has reached the End of Card */ Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_EOF_NDEF_CONTAINER_REACHED); } else if (0 == NdefMap->TopazContainer.NdefTLVByteAddress) { /* No NDEF TLV found in the card, so write not possible */ Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else if ((PH_FRINFC_NDEFMAP_SEEK_BEGIN == Offset) || (PH_FRINFC_NDEFMAP_WRITE_OPE != NdefMap->PrevOperation)) { NdefMap->Offset = PH_FRINFC_NDEFMAP_SEEK_BEGIN; /* Initialise byte number */ NdefMap->TopazContainer.Cur_RW_Index = PH_FRINFC_TOPAZ_VAL0; /* State has to be changed */ NdefMap->State = PH_FRINFC_TOPAZ_STATE_READ; NdefMap->TopazContainer.ReadWriteCompleteFlag = FALSE; NdefMap->TopazContainer.CurrentSeg = 0; NdefMap->TopazContainer.CurrentBlock = 1; NdefMap->TopazContainer.WriteSeq = 0; #ifdef TOPAZ_RAW_SUPPORT *NdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ8; #else /* Topaz command = Jewel Nxp Read */ #ifdef PH_HAL4_ENABLE NdefMap->Cmd.JewelCmd = phHal_eJewel_Read; #else NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif NdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call read segment */ Result = phFriNfc_Tpz_H_NxpRead (NdefMap); } else { #if 0 /* This part is to handle the Current offset, Current offset is not yet validated */ Result = phFriNfc_Tpz_H_NxpWrite(NdefMap); #endif /* #if 0 */ } return Result; } /*! * \brief Completion Routine, Processing function, needed to avoid long blocking. * \note The lower (Overlapped HAL) layer must register a pointer to this function as a Completion * Routine in order to be able to notify the component that an I/O has finished and data are * ready to be processed. * */ void phFriNfc_TopazDynamicMap_Process( void *Context, NFCSTATUS Status) { phFriNfc_NdefMap_t *NdefMap; NdefMap = (phFriNfc_NdefMap_t *)Context; if((NFCSTATUS_SUCCESS & PHNFCSTBLOWER) == (Status & PHNFCSTBLOWER)) { switch(NdefMap->State) { case PH_FRINFC_TOPAZ_STATE_READ: { Status = phFriNfc_Tpz_H_ProReadResp (NdefMap); break; } case PH_FRINFC_TOPAZ_STATE_WRITE: { Status = phFriNfc_Tpz_H_ProWrResp (NdefMap); break; } case PH_FRINFC_TOPAZ_STATE_RD_FOR_WR_NDEF: { Status = phFriNfc_Tpz_H_ProRdForWrResp (NdefMap); break; } case PH_FRINFC_TOPAZ_STATE_READID: { Status = phFriNfc_Tpz_H_ChkReadID(NdefMap); break; } #ifdef FRINFC_READONLY_NDEF case PH_FRINFC_TOPAZ_STATE_READ_ONLY: { Status = phFriNfc_Tpz_H_ProcessReadOnly (NdefMap); break; } #endif /* #ifdef FRINFC_READONLY_NDEF */ default: { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } } /* Call for the Completion Routine*/ if(Status != NFCSTATUS_PENDING) { phFriNfc_Tpz_H_Complete(NdefMap, Status); } } #ifdef FRINFC_READONLY_NDEF static NFCSTATUS phFriNfc_Tpz_H_UpdateAndWriteLockBits ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; uint8_t remaining_lock_bits = 0; uint8_t byte_index = 0; uint8_t lock_bytes_value[TOPAZ_BYTES_PER_BLOCK] = {0}; uint8_t lock_byte_index = 0; uint8_t no_of_bits_left_in_block = 0; ps_tpz_info = &(psNdefMap->TopazContainer); ps_locktlv_info = &(psNdefMap->LockTlv); (void)memcpy ((void *)lock_bytes_value, (void *)psNdefMap->SendRecvBuf, TOPAZ_BYTES_PER_BLOCK); if (ps_tpz_info->CurrentBlock == ps_locktlv_info->BlkNum) { /* Get the lock bits that has to locked */ remaining_lock_bits = ps_locktlv_info->LockTlvBuff[1]; byte_index = (uint8_t)ps_locktlv_info->ByteNum; } else { /* This condition applies only for the lock bits not ending with " ps_locktlv_info->BlkNum ". Calculate the remaining lock bits */ remaining_lock_bits = (uint8_t)(ps_locktlv_info->LockTlvBuff[1] - ps_tpz_info->lock_bytes_written); } no_of_bits_left_in_block = (uint8_t)((TOPAZ_BYTES_PER_BLOCK - byte_index) * TOPAZ_BYTE_SIZE_IN_BITS); if (no_of_bits_left_in_block >= remaining_lock_bits) { /* Entire lock bits can be written */ uint8_t mod_value = 0; mod_value = (uint8_t)(remaining_lock_bits % TOPAZ_BYTES_PER_BLOCK); if (mod_value) { /* The lock bits ends in between of a byte */ /* lock bits to write is greater than 8 bits */ if (mod_value > TOPAZ_BYTE_SIZE_IN_BITS) { while (lock_byte_index < (TOPAZ_CONVERT_BITS_TO_BYTES(remaining_lock_bits) - 1)) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } /* Last byte of the lock bits shall be filled partially, Set only the remaining lock bits and dont change the other bit value */ lock_bytes_value[byte_index] = 0; lock_bytes_value[byte_index] = (uint8_t) SET_BITS8 (lock_bytes_value[byte_index], 0, mod_value, 1); } else { /* lock bits to write is less than 8 bits, so there is only one byte to write. Set only the remaining lock bits and dont change the other bit value */ lock_bytes_value[0] = (uint8_t) SET_BITS8 (lock_bytes_value[0], 0, mod_value, 1); } } /* if (mod_value) */ else { /* The lock bits exactly ends at a byte MOD operation is 00, that means entire byte value shall be 0xFF, means every bit shall be to 1 */ while (lock_byte_index < TOPAZ_CONVERT_BITS_TO_BYTES(remaining_lock_bits)) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } } /* else of if (mod_value) */ ps_tpz_info->lock_bytes_written = remaining_lock_bits; } else /* if (no_of_bits_left_in_block >= remaining_lock_bits) */ { /* Partial lock bits can be written. use next read to write the remaining lock bits */ while (lock_byte_index < (no_of_bits_left_in_block / TOPAZ_BYTES_PER_BLOCK)) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } ps_tpz_info->lock_bytes_written = (uint8_t)(no_of_bits_left_in_block / TOPAZ_BYTES_PER_BLOCK); } /* else of if (no_of_bits_left_in_block >= remaining_lock_bits) */ #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, lock_bytes_value, sizeof (lock_bytes_value)); return result; } static NFCSTATUS phFriNfc_Tpz_H_ProcessReadOnly ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_Tpz_RO_Seq_t e_readonly_seq = RD_LOCK_BYTES; phFriNfc_TopazCont_t *ps_tpz_info = NULL; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; static uint8_t static_lock_bytes[2] = {0}; ps_tpz_info = &(psNdefMap->TopazContainer); ps_locktlv_info = &(psNdefMap->LockTlv); e_readonly_seq = (phFriNfc_Tpz_RO_Seq_t)psNdefMap->TopazContainer.read_only_seq; switch (e_readonly_seq) { case WR_READONLY_CC: { if (TOPAZ_WRITE_1_RESPONSE == *psNdefMap->SendRecvLength) { psNdefMap->TopazContainer.CurrentBlock = (uint8_t) psNdefMap->LockTlv.BlkNum; e_readonly_seq = RD_LOCK_BYTES; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ8; #else /* Topaz command = Jewel Nxp Read */ #ifdef PH_HAL4_ENABLE psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read; #else psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call read segment */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case RD_LOCK_BYTES: { if (TOPAZ_READ_8_RESPONSE == *psNdefMap->SendRecvLength) { result = phFriNfc_Tpz_H_UpdateAndWriteLockBits (psNdefMap); if (NFCSTATUS_PENDING == result) { e_readonly_seq = WR_LOCK_BYTES; } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case WR_LOCK_BYTES: { if (TOPAZ_WRITE_8_RESPONSE == *psNdefMap->SendRecvLength) { ps_tpz_info->CurrentBlock = (uint8_t) (ps_tpz_info->CurrentBlock + 1); if (ps_locktlv_info->LockTlvBuff[1] - ps_tpz_info->lock_bytes_written) { #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ8; #else /* Topaz command = Jewel Nxp Read */ #ifdef PH_HAL4_ENABLE psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read; #else psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call read segment */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); e_readonly_seq = RD_LOCK_BYTES; } else { ps_tpz_info->CurrentBlock = (uint8_t) DYN_STATIC_LOCK_BLOCK_NUM; ps_tpz_info->ByteNumber = (uint8_t) DYN_STATIC_LOCK0_BYTE_NUM; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = (uint8_t)PH_FRINFC_TOPAZ_CMD_READ8; #else /* Topaz command = Jewel Nxp Read */ #ifdef PH_HAL4_ENABLE psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read; #else psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call read segment */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); e_readonly_seq = RD_STATIC_LOCK_BYTE0; } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case RD_STATIC_LOCK_BYTE0: { if (TOPAZ_READ_8_RESPONSE == *psNdefMap->SendRecvLength) { uint8_t lock_byte_value = 0; (void)memcpy ((void *)static_lock_bytes, (void *)(psNdefMap->SendRecvBuf + ps_tpz_info->ByteNumber), sizeof (static_lock_bytes)); lock_byte_value = (uint8_t)(static_lock_bytes[0] | DYN_STATIC_LOCK0_BYTE_VALUE); #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = (uint8_t)PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, &lock_byte_value, 1); if (NFCSTATUS_PENDING == result) { e_readonly_seq = (uint8_t)WR_STATIC_LOCK_BYTE0; } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case WR_STATIC_LOCK_BYTE0: { if (TOPAZ_WRITE_1_RESPONSE == *psNdefMap->SendRecvLength) { uint8_t lock_byte_value = (static_lock_bytes[1] | DYN_STATIC_LOCK1_BYTE_VALUE); ps_tpz_info->CurrentBlock = (uint8_t) DYN_STATIC_LOCK_BLOCK_NUM; ps_tpz_info->ByteNumber = (uint8_t) DYN_STATIC_LOCK1_BYTE_NUM; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = (uint8_t)PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, &lock_byte_value, 1); if (NFCSTATUS_PENDING == result) { e_readonly_seq = (uint8_t)WR_STATIC_LOCK_BYTE1; } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case WR_STATIC_LOCK_BYTE1: { if (TOPAZ_WRITE_1_RESPONSE == *psNdefMap->SendRecvLength) { /* READ ONLY successful */ } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); break; } } psNdefMap->TopazContainer.read_only_seq = (uint8_t)e_readonly_seq; return result; } #endif /* #ifdef FRINFC_READONLY_NDEF */ static NFCSTATUS phFriNfc_Tpz_H_ProWrResp ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; phFriNfc_Tpz_WrSeq_t write_seq; uint8_t write_buf[] = {0x00}; uint8_t write_index = 0; uint16_t write_len = 0; uint16_t len_byte_addr = 0; ps_tpz_info = &(psNdefMap->TopazContainer); write_seq = (phFriNfc_Tpz_WrSeq_t)(ps_tpz_info->WriteSeq); write_len = (uint16_t)((psNdefMap->ApduBufferSize < ps_tpz_info->NDEFRWSize) ? psNdefMap->ApduBufferSize : ps_tpz_info->NDEFRWSize); switch (write_seq) { case WR_NDEF_T_TLV: { /* TYPE field of the NDEF TLV write is complete */ if (TOPAZ_WRITE_8_RESPONSE == *psNdefMap->SendRecvLength) { psNdefMap->State = (uint8_t) PH_FRINFC_TOPAZ_STATE_WRITE; /* Now, Write 0 to the magic number byte */ ps_tpz_info->WriteSeq = (uint8_t)WR_NMN_0; write_seq = WR_NMN_0; ps_tpz_info->CurrentBlock = 1; ps_tpz_info->ByteNumber = 0; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buf, sizeof (write_buf)); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case WR_NMN_0: { /* Magic number set to 0 write is complete */ if (TOPAZ_WRITE_1_RESPONSE == *psNdefMap->SendRecvLength) { ps_tpz_info->WriteSeq = (uint8_t)(write_seq + 1); write_seq = (phFriNfc_Tpz_WrSeq_t)(write_seq + 1); /* Now the sequence = WR_LEN_1_0, so Length block is read, and only length bytes are made 0, before writing data to 0 */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case WR_LEN_1_0: { /* Length field is updated with the value 0 */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else if (write_len >= 0xFF) { ps_tpz_info->ByteNumber = 0; ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_INCREMENT_SKIP_STATIC_BLOCK ( ps_tpz_info->CurrentBlock); ps_tpz_info->WriteSeq = (uint8_t)(write_seq + 1); write_seq = (phFriNfc_Tpz_WrSeq_t)(write_seq + 1); /* Now the sequence = WR_LEN_1_1, so Length block is read, and only length bytes are made 0, before writing data to 0 */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { /* NDEF data length < 0xFF */ len_byte_addr = phFriNfc_Tpz_H_GetNDEFValueFieldAddrForWrite (psNdefMap, write_len); ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_BLK_FROM_BYTE_ADR (len_byte_addr); ps_tpz_info->ByteNumber = (uint8_t) TOPAZ_BYTE_OFFSET_FROM_BYTE_ADR (len_byte_addr); ps_tpz_info->WriteSeq = (uint8_t)WR_DATA; write_seq = WR_DATA; if (0 != ps_tpz_info->ByteNumber) { /* If data starts in between the block then read the data */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { /* Data starts at the beginning of the block, so start writing the user data */ result = phFriNfc_Tpz_H_CopySendWrData (psNdefMap); } } break; } case WR_LEN_2_0: case WR_LEN_2_VALUE: { /* 2nd length field is updated with the value 0 or the correct written value */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else { ps_tpz_info->ByteNumber = 0; ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_INCREMENT_SKIP_STATIC_BLOCK ( ps_tpz_info->CurrentBlock); ps_tpz_info->WriteSeq = (uint8_t)(write_seq + 1); write_seq = (phFriNfc_Tpz_WrSeq_t)(write_seq + 1); /* If length byte starts in between the block then read the length block */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } break; } case WR_LEN_3_0: { /* 3rd length field is updated with the value 0 */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else { len_byte_addr = phFriNfc_Tpz_H_GetNDEFValueFieldAddrForWrite (psNdefMap, write_len); ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_BLK_FROM_BYTE_ADR (len_byte_addr); ps_tpz_info->ByteNumber = (uint8_t) TOPAZ_BYTE_OFFSET_FROM_BYTE_ADR (len_byte_addr); ps_tpz_info->WriteSeq = (uint8_t)(write_seq + 1); write_seq = (phFriNfc_Tpz_WrSeq_t)(write_seq + 1); if (0 != ps_tpz_info->ByteNumber) { /* If data starts in between the block then read the data */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { /* Data starts at the beginning of the block, so start writing the user data */ result = phFriNfc_Tpz_H_CopySendWrData (psNdefMap); } } break; } case WR_DATA: { /* Data is written from the input buffer */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else if (write_len == psNdefMap->ApduBuffIndex) { /* Data to be written is completely written to the card */ *psNdefMap->WrNdefPacketLength = psNdefMap->ApduBuffIndex; ps_tpz_info->WriteSeq = (uint8_t)WR_LEN_1_VALUE; write_seq = WR_LEN_1_VALUE; /* To write the first length byte, it has to be read and then the length has to be updated */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { ps_tpz_info->ByteNumber = 0; /* Go to the next block */ ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_INCREMENT_SKIP_STATIC_BLOCK ( ps_tpz_info->CurrentBlock); /* Copy and write the user data */ result = phFriNfc_Tpz_H_CopySendWrData (psNdefMap); } break; } case WR_DATA_READ_REQD: { /* This sequence is executed, if the first read has some lock or reserved blocks bytes and the lock or reserved blocks are extended to the next block */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else { ps_tpz_info->ByteNumber = 0; /* Go to the next block */ ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_INCREMENT_SKIP_STATIC_BLOCK ( ps_tpz_info->CurrentBlock); /* Write is complete for one block, now because lock bytes are shifted to next blocks, the next block is read and update the written data by skipping the lock or reserved memory bytes */ result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } break; } case WR_LEN_3_VALUE: { /* 3rd LENGTH field byte is updated with correct written value */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else { #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ psNdefMap->State = (uint8_t)PH_FRINFC_TOPAZ_STATE_WRITE; write_buf[write_index] = PH_FRINFC_TOPAZ_CC_BYTE0; write_index = (uint8_t)(write_index + 1); ps_tpz_info->ByteNumber = 0; ps_tpz_info->CurrentBlock = 1; ps_tpz_info->WriteSeq = (uint8_t)WR_NMN_E1; write_seq = WR_NMN_E1; /* Length byte write is complete, so now update the magic number byte with value 0xE1 */ result = phFriNfc_Tpz_H_NxpWrite(psNdefMap, write_buf, write_index); } break; } case WR_LEN_1_VALUE: { /* 1st LENGTH field byte is updated */ if (TOPAZ_WRITE_8_RESPONSE != *psNdefMap->SendRecvLength) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } else if (write_len < 0xFF) { /* Total length to write is less than 0xFF, so LENGTH field has only one byte, then update the magic number byte with value 0xE1 */ #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ psNdefMap->State = (uint8_t)PH_FRINFC_TOPAZ_STATE_WRITE; write_buf[write_index] = PH_FRINFC_TOPAZ_CC_BYTE0; write_index = (uint8_t)(write_index + 1); ps_tpz_info->ByteNumber = 0; ps_tpz_info->CurrentBlock = 1; ps_tpz_info->WriteSeq = (uint8_t)WR_NMN_E1; write_seq = WR_NMN_E1; result = phFriNfc_Tpz_H_NxpWrite(psNdefMap, write_buf, write_index); } else { /* 2nd byte of the LENGTH field has to be updated so, read the block, before updating it */ ps_tpz_info->ByteNumber = 0; ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_INCREMENT_SKIP_STATIC_BLOCK ( ps_tpz_info->CurrentBlock); ps_tpz_info->WriteSeq = (uint8_t)WR_LEN_2_VALUE; write_seq = WR_LEN_2_VALUE; result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } break; } case WR_NMN_E1: { /* Magic number is written, so update the actual ndef length. */ if (TOPAZ_WRITE_1_RESPONSE == *psNdefMap->SendRecvLength) { *psNdefMap->WrNdefPacketLength = (uint32_t) psNdefMap->ApduBuffIndex; ps_tpz_info->ActualNDEFMsgSize = (uint16_t) psNdefMap->ApduBuffIndex; } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } default: { break; } } return result; } static NFCSTATUS phFriNfc_Tpz_H_UpdateNdefTypeField ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t write_buf[TOPAZ_WRITE_8_DATA_LENGTH]; ps_tpz_info = &(psNdefMap->TopazContainer); (void)memcpy ((void *)write_buf, (void *) psNdefMap->SendRecvBuf, TOPAZ_WRITE_8_DATA_LENGTH); /* Update the TYPE field of the NDEF TLV */ write_buf[ps_tpz_info->ByteNumber] = PH_FRINFC_TOPAZ_NDEF_T; psNdefMap->State = (uint8_t)PH_FRINFC_TOPAZ_STATE_WRITE; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite(psNdefMap, write_buf, sizeof (write_buf)); return result; } static NFCSTATUS phFriNfc_Tpz_H_ProRdForWrResp ( phFriNfc_NdefMap_t *psNdefMap) { /* This function is used during the write operation */ NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; ps_tpz_info = &(psNdefMap->TopazContainer); psNdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE; if (TOPAZ_READ_8_RESPONSE == *psNdefMap->SendRecvLength) { switch ((phFriNfc_Tpz_WrSeq_t)ps_tpz_info->WriteSeq) { case WR_NDEF_T_TLV: { /* Read bytes are for updating the TYPE field of the NDEF TLV */ result = phFriNfc_Tpz_H_UpdateNdefTypeField (psNdefMap); break; } case WR_LEN_1_0: case WR_LEN_2_0: case WR_LEN_3_0: { /* Read bytes are for updating the LENGTH field to 0 of the NDEF TLV and also to update the data from the user buffer */ result = phFriNfc_Tpz_H_UpdateLenFieldZeroAfterRead (psNdefMap); break; } case WR_DATA: case WR_DATA_READ_REQD: { /* Read bytes are for skipping the lock and reserved bytes */ result = phFriNfc_Tpz_H_CopyReadDataAndWrite (psNdefMap); break; } case WR_LEN_1_VALUE: case WR_LEN_2_VALUE: case WR_LEN_3_VALUE: { /* Read bytes are for updating the LENGTH field to the correct values of the NDEF TLV */ result = phFriNfc_Tpz_H_UpdateLenFieldValuesAfterRead (psNdefMap); break; } default: { /* Code must not come come here */ break; } } } else { /* Error in the length, wither the HW has sent wrong response length or the response length byte is corrupted */ result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } return result; } static NFCSTATUS phFriNfc_Tpz_H_ChkReadID( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; int compare_result = 0; uint8_t recv_index = 0; if (PH_FRINFC_TOPAZ_VAL6 == *psNdefMap->SendRecvLength) { if (((psNdefMap->SendRecvBuf[recv_index] & PH_FRINFC_TOPAZ_HEADROM0_CHK) == PH_FRINFC_TOPAZ_DYNAMIC_HEADROM0_VAL)) { /* Copy UID to the context*/ compare_result = phOsalNfc_MemCompare ( psNdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid, &psNdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2], TOPAZ_UID_LENGTH_FOR_READ_WRITE); if (0 == compare_result) { /* State has to be changed */ psNdefMap->State = PH_FRINFC_TOPAZ_STATE_READ; /* Topaz command = READSEG */ #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_RSEG; #else #ifdef PH_HAL4_ENABLE psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read; #else psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead; #endif psNdefMap->Cmd.JewelCmd = phHal_eJewel_ReadSeg; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Read bytes from the card */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } return result; } #define TOPAZ_READ_ID_ZERO_LENGTH (0x06U) static NFCSTATUS phFriNfc_Tpz_H_NxpRead ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t send_index = 0; #ifdef TOPAZ_RAW_SUPPORT uint8_t read_append[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* set the data for additional data exchange*/ psNdefMap->psDepAdditionalInfo.DepFlags.MetaChaining = PH_FRINFC_TOPAZ_VAL0; psNdefMap->psDepAdditionalInfo.DepFlags.NADPresent = PH_FRINFC_TOPAZ_VAL0; psNdefMap->psDepAdditionalInfo.NAD = PH_FRINFC_TOPAZ_VAL0; psNdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_TopazDynamicMap_Process; psNdefMap->MapCompletionInfo.Context = psNdefMap; *psNdefMap->SendRecvLength = psNdefMap->TempReceiveLength; /* Depending on the jewel command, the send length is decided */ #ifdef TOPAZ_RAW_SUPPORT psNdefMap->Cmd.JewelCmd = phHal_eJewel_Raw; /* " send_index " is incremented because already received buffer is filled with TOPAZ command */ send_index = (uint8_t)(send_index + 1); switch (*psNdefMap->SendRecvBuf) #else switch(psNdefMap->Cmd.JewelCmd) #endif /* #ifdef TOPAZ_RAW_SUPPORT */ { #ifdef TOPAZ_RAW_SUPPORT case PH_FRINFC_TOPAZ_CMD_READID: { (void)memcpy ((void *)(psNdefMap->SendRecvBuf + send_index), (void *)read_append, TOPAZ_READ_ID_ZERO_LENGTH); send_index = (uint8_t)(send_index + TOPAZ_READ_ID_ZERO_LENGTH); break; } case PH_FRINFC_TOPAZ_CMD_READ8: { psNdefMap->SendRecvBuf[send_index] = psNdefMap->TopazContainer.CurrentBlock; send_index = (uint8_t)(send_index + 1); break; } case PH_FRINFC_TOPAZ_CMD_RSEG: { psNdefMap->SendRecvBuf[send_index] = (uint8_t) (psNdefMap->TopazContainer.CurrentSeg << NIBBLE_SIZE); send_index = (uint8_t)(send_index + 1); break; } #else /* #ifdef TOPAZ_RAW_SUPPORT */ #ifdef PH_HAL4_ENABLE case phHal_eJewel_RID: case phHal_eJewel_ReadAll: #else case phHal_eJewelCmdListJewelRid: case phHal_eJewelCmdListJewelReadAll: #endif { /* For READ ID and READ ALL, send length is 0 */ psNdefMap->SendLength = PH_FRINFC_TOPAZ_VAL0; break; } #ifdef PH_HAL4_ENABLE case phHal_eJewel_Read: #else case phHal_eJewelCmdListJewelRead: #endif { /* Need to check the User data size request*/ psNdefMap->SendLength = PH_FRINFC_TOPAZ_VAL3; break; } case phHal_eJewel_ReadSeg: { psNdefMap->SendRecvBuf[send_index] = (uint8_t) (psNdefMap->TopazContainer.CurrentSeg << NIBBLE_SIZE); send_index = (uint8_t)(send_index + 1); psNdefMap->SendLength = send_index; break; } case phHal_eJewel_Read8: { psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read4; psNdefMap->SendRecvBuf[send_index] = psNdefMap->TopazContainer.CurrentBlock; send_index = (uint8_t)(send_index + 1); psNdefMap->SendLength = send_index; break; } #endif /* #ifdef TOPAZ_RAW_SUPPORT */ default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } if(result == NFCSTATUS_SUCCESS) { #ifdef TOPAZ_RAW_SUPPORT if (PH_FRINFC_TOPAZ_CMD_READID != *psNdefMap->SendRecvBuf) { (void)memcpy ((void *)(psNdefMap->SendRecvBuf + send_index), (void *)read_append, sizeof (read_append)); send_index = (uint8_t)(send_index + sizeof (read_append)); (void)memcpy ((void *)(psNdefMap->SendRecvBuf + send_index), (void *)psNdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid, TOPAZ_UID_LENGTH_FOR_READ_WRITE); send_index = (uint8_t)(send_index + TOPAZ_UID_LENGTH_FOR_READ_WRITE); } psNdefMap->SendLength = send_index; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call the Overlapped HAL Transceive function */ result = phFriNfc_OvrHal_Transceive( psNdefMap->LowerDevice, &psNdefMap->MapCompletionInfo, psNdefMap->psRemoteDevInfo, psNdefMap->Cmd, &psNdefMap->psDepAdditionalInfo, psNdefMap->SendRecvBuf, psNdefMap->SendLength, psNdefMap->SendRecvBuf, psNdefMap->SendRecvLength); } return result; } static NFCSTATUS phFriNfc_Tpz_H_NxpWrite( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_write_data, uint8_t wr_data_len) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t send_index = 0; ps_tpz_info = &(psNdefMap->TopazContainer); /* set the data for additional data exchange*/ psNdefMap->psDepAdditionalInfo.DepFlags.MetaChaining = PH_FRINFC_TOPAZ_VAL0; psNdefMap->psDepAdditionalInfo.DepFlags.NADPresent = PH_FRINFC_TOPAZ_VAL0; psNdefMap->psDepAdditionalInfo.NAD = PH_FRINFC_TOPAZ_VAL0; psNdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_TopazDynamicMap_Process; psNdefMap->MapCompletionInfo.Context = psNdefMap; *psNdefMap->SendRecvLength = psNdefMap->TempReceiveLength; #ifdef TOPAZ_RAW_SUPPORT /* " send_index " is incremented because already received buffer is filled with TOPAZ command */ send_index = (uint8_t)(send_index + 1); psNdefMap->Cmd.JewelCmd = phHal_eJewel_Raw; switch (*psNdefMap->SendRecvBuf) #else /* #ifdef TOPAZ_RAW_SUPPORT */ switch (psNdefMap->Cmd.JewelCmd) #endif /* #ifdef TOPAZ_RAW_SUPPORT */ { #ifdef TOPAZ_RAW_SUPPORT case PH_FRINFC_TOPAZ_CMD_WRITE_1E: { psNdefMap->SendRecvBuf[send_index] = (uint8_t)((ps_tpz_info->CurrentBlock << (NIBBLE_SIZE - 1)) | ps_tpz_info->ByteNumber); send_index = (uint8_t)(send_index + 1); break; } case PH_FRINFC_TOPAZ_CMD_WRITE_E8: { psNdefMap->SendRecvBuf[send_index] = ps_tpz_info->CurrentBlock; send_index = (uint8_t)(send_index + 1); break; } #else /* #ifdef TOPAZ_RAW_SUPPORT */ case phHal_eJewel_Write1E: { psNdefMap->SendRecvBuf[send_index] = (uint8_t)((ps_tpz_info->CurrentBlock << (NIBBLE_SIZE - 1)) | ps_tpz_info->ByteNumber); send_index = (uint8_t)(send_index + 1); break; } case phHal_eJewel_Write8E: { psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write4E; psNdefMap->SendRecvBuf[send_index] = ps_tpz_info->CurrentBlock; send_index = (uint8_t)(send_index + 1); break; } #endif /* #ifdef TOPAZ_RAW_SUPPORT */ default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } if (NFCSTATUS_SUCCESS == result) { (void)memcpy ((void *)(psNdefMap->SendRecvBuf + send_index), (void *)p_write_data, wr_data_len); send_index = (uint8_t)(send_index + wr_data_len); #ifdef TOPAZ_RAW_SUPPORT (void)memcpy ((void *)(psNdefMap->SendRecvBuf + send_index), (void *)psNdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid, TOPAZ_UID_LENGTH_FOR_READ_WRITE); send_index = (uint8_t)(send_index + TOPAZ_UID_LENGTH_FOR_READ_WRITE); #endif /* #ifdef TOPAZ_RAW_SUPPORT */ psNdefMap->SendLength = send_index; /* Call the Overlapped HAL Transceive function */ result = phFriNfc_OvrHal_Transceive( psNdefMap->LowerDevice, &psNdefMap->MapCompletionInfo, psNdefMap->psRemoteDevInfo, psNdefMap->Cmd, &psNdefMap->psDepAdditionalInfo, psNdefMap->SendRecvBuf, psNdefMap->SendLength, psNdefMap->SendRecvBuf, psNdefMap->SendRecvLength); } return result; } static NFCSTATUS phFriNfc_Tpz_H_ProReadResp( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t write_buffer[] = {0x00}; ps_tpz_info = &(psNdefMap->TopazContainer); switch (psNdefMap->PrevOperation) { case PH_FRINFC_NDEFMAP_CHECK_OPE: { if (PH_FRINFC_TOPAZ_DYNAMIC_READSEG_RESP == *psNdefMap->SendRecvLength) { if (0 == ps_tpz_info->CurrentSeg) { result = phFriNfc_Tpz_H_CheckCCBytes (psNdefMap); } if (NFCSTATUS_SUCCESS == result) { result = phFriNfc_Tpz_H_ParseTLVs (psNdefMap); } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case PH_FRINFC_NDEFMAP_READ_OPE: { if (PH_FRINFC_TOPAZ_DYNAMIC_READSEG_RESP == *psNdefMap->SendRecvLength) { /* call the data bytes to internal buffer*/ result = phFriNfc_Tpz_H_CopyReadData (psNdefMap); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case PH_FRINFC_NDEFMAP_WRITE_OPE: { /* read the bytes for cheking the CC bytes and lock bit status*/ if(TOPAZ_READ_8_RESPONSE == *psNdefMap->SendRecvLength) { (void)memcpy ((void *)ps_tpz_info->CCByteBuf, (void *)(psNdefMap->SendRecvBuf), TOPAZ_CC_BYTES_LENGTH); result = phFriNfc_Tpz_H_CheckCCBytesForWrite (psNdefMap); if (NFCSTATUS_SUCCESS == result) { if ((0x00 == *ps_tpz_info->CCByteBuf) || (NDEF_T_TLV == ps_tpz_info->ExpectedSeq)) { /* This statement is for getting the new NDEF TLV byte address, because 1st CC byte is corrupted or no NDEF TLV in the card If the 1st CC byte (NDEF magic number) in the card is 0, means that previous write has failed, so to write the exact file OR The NDEF TLV is not present in the entire card, and the sequence is NDEF_T_TLV (this means, that lock and memory control TLV is found in the card) */ psNdefMap->State = (uint8_t) PH_FRINFC_TOPAZ_STATE_RD_FOR_WR_NDEF; ps_tpz_info->WriteSeq = (uint8_t)WR_NDEF_T_TLV; ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_BLK_FROM_BYTE_ADR ( ps_tpz_info->NdefTLVByteAddress); ps_tpz_info->ByteNumber = (uint8_t) TOPAZ_BYTE_OFFSET_FROM_BYTE_ADR ( ps_tpz_info->NdefTLVByteAddress); #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); } else { ps_tpz_info->WriteSeq = (uint8_t)WR_NMN_0; ps_tpz_info->CurrentBlock = 1; ps_tpz_info->ByteNumber = 0; psNdefMap->State = (uint8_t) PH_FRINFC_TOPAZ_STATE_WRITE; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_1E; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ /* Call read 8 */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buffer, sizeof (write_buffer)); } } } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } return result; } static void phFriNfc_Tpz_H_Complete(phFriNfc_NdefMap_t *NdefMap, NFCSTATUS Status) { /* set the state back to the Reset_Init state*/ NdefMap->State = PH_FRINFC_NDEFMAP_STATE_RESET_INIT; /* set the completion routine*/ NdefMap->CompletionRoutine[NdefMap->TopazContainer.CRIndex]. CompletionRoutine(NdefMap->CompletionRoutine->Context, Status); } static NFCSTATUS phFriNfc_Tpz_H_ChkLockBits( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; #ifdef ENABLE_LOCK_BITS_CHECK uint8_t *p_recv_buf = psNdefMap->SendRecvBuf; #endif /* #ifdef ENABLE_LOCK_BITS_CHECK */ psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_INITIALIZED; #ifdef ENABLE_LOCK_BITS_CHECK /* Set the card state */ psNdefMap->CardState = (uint8_t) (((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_0] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_0) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_1] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_1)) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_2] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7)) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_3] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7)) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_4] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7)) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_5] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7)) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_6] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7))) && ((p_recv_buf[PH_FRINFC_TOPAZ_DYNAMIC_LOCKBIT_BYTENO_7] == PH_FRINFC_TOPAZ_DYNAMIC_LOCKBYTE_2TO7)) ? PH_NDEFMAP_CARD_STATE_INITIALIZED : PH_NDEFMAP_CARD_STATE_READ_ONLY); #endif /* #ifdef ENABLE_LOCK_BITS_CHECK */ /* Set the card state from CC bytes */ if (PH_NDEFMAP_CARD_STATE_INITIALIZED == psNdefMap->CardState) { switch ((psNdefMap->TopazContainer.CCByteBuf[3] & 0xFF)) { case PH_FRINFC_TOPAZ_CC_READWRITE: { psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_INITIALIZED; break; } case PH_FRINFC_TOPAZ_CC_READONLY: { psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_ONLY; break; } default: { psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); break; } } } return result; } static NFCSTATUS phFriNfc_Tpz_H_CheckCCBytes ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); uint8_t *p_recv_buf = psNdefMap->SendRecvBuf; uint16_t parse_index = 0; parse_index = (uint16_t)(parse_index + TOPAZ_UID_BYTES_LENGTH); (void)memcpy ((void *)ps_tpz_info->CCByteBuf, (void *)(p_recv_buf + parse_index), TOPAZ_CC_BYTES_LENGTH); p_recv_buf = ps_tpz_info->CCByteBuf; parse_index = 0; #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE /* 1st CC byte value = 0 or 0xE1 */ if ((PH_FRINFC_TOPAZ_CC_BYTE0 == p_recv_buf[parse_index]) #ifdef TOPAZ_MAGIC_NO_0_CHK_ENABLE || (0 == p_recv_buf[parse_index]) #endif /* #if TOPAZ_MAGIC_NO_0_CHK_ENABLE */ ) #endif /* #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE */ { parse_index = (uint16_t)(parse_index + 1); /* 2nd CC byte value = 0x10 */ result = phFriNfc_Tpz_H_ChkSpcVer (psNdefMap, p_recv_buf[parse_index]); } #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } #endif /* #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE */ if (NFCSTATUS_SUCCESS == result) { parse_index = (uint16_t)(parse_index + 1); /* 3rd CC byte value = 0x3F for 512 card */ if (PH_FRINFC_TOPAZ_DYNAMIC_CC_BYTE2_MMSIZE == p_recv_buf[parse_index]) { /* Card size calculated as ((3rd CC byte * 8) - 4 CC bytes) */ psNdefMap->CardMemSize = (uint16_t)((p_recv_buf[parse_index] * TOPAZ_BYTES_PER_BLOCK) - TOPAZ_CC_BYTES_LENGTH); ps_tpz_info->RemainingSize = (uint16_t)(psNdefMap->CardMemSize + TOPAZ_UID_BYTES_LENGTH + TOPAZ_CC_BYTES_LENGTH); result = phFriNfc_Tpz_H_ChkLockBits (psNdefMap); } else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } } if (NFCSTATUS_SUCCESS != result) { psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID; } return result; } static NFCSTATUS phFriNfc_Tpz_H_CheckCCBytesForWrite ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t check_cc_rw[] = {TOPAZ_SPEC_VERSION, PH_FRINFC_TOPAZ_DYNAMIC_CC_BYTE2_MMSIZE, PH_FRINFC_TOPAZ_CC_READWRITE}; uint8_t check_index = 0; ps_tpz_info = &(psNdefMap->TopazContainer); #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE if ( (PH_FRINFC_TOPAZ_CC_BYTE0 == ps_tpz_info->CCByteBuf[check_index]) #if TOPAZ_MAGIC_NO_0_CHK_ENABLE || (0 == ps_tpz_info->CCByteBuf[check_index]) #endif /* #if TOPAZ_MAGIC_NO_0_CHK_ENABLE */ ) #endif /* #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE */ { check_index = (uint8_t)(check_index + 1); if ((!TOPAZ_COMPARE_VERSION(check_cc_rw[0], ps_tpz_info->CCByteBuf[1])) || (check_cc_rw[1] != ps_tpz_info->CCByteBuf[2]) || (check_cc_rw[2] != ps_tpz_info->CCByteBuf[3])) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } } #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE else { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } #endif /* #ifdef TOPAZ_MAGIC_NO_CHK_ENABLE */ return result; } static uint16_t phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead ( phFriNfc_NdefMap_t *psNdefMap) { phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); uint16_t skip_size = 0; uint16_t byte_addr = 0; uint8_t exit_index = 0; byte_addr = ps_tpz_info->NdefTLVByteAddress; while (exit_index < ((ps_tpz_info->ActualNDEFMsgSize >= 0xFF) ? 3 : 1)) { byte_addr = (uint16_t)(byte_addr + 1); if (TOPAZ_STATIC_LOCK_RES_START == byte_addr) { byte_addr = (uint16_t)(byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES); } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); byte_addr = (uint16_t)(byte_addr + skip_size); exit_index = (uint8_t)(exit_index + 1); } byte_addr = (uint16_t)(byte_addr + 1); if (TOPAZ_STATIC_LOCK_RES_START == byte_addr) { byte_addr = (uint16_t)(byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES); } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); byte_addr = (uint16_t)(byte_addr + skip_size); return byte_addr; } static uint16_t phFriNfc_Tpz_H_GetNDEFValueFieldAddrForWrite ( phFriNfc_NdefMap_t *psNdefMap, uint16_t size_to_write) { phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); uint16_t skip_size = 0; uint16_t byte_addr = 0; uint8_t exit_index = 0; byte_addr = ps_tpz_info->NdefTLVByteAddress; while (exit_index < ((size_to_write >= 0xFF) ? 3 : 1)) { byte_addr = (uint16_t)(byte_addr + 1); if (TOPAZ_STATIC_LOCK_RES_START == byte_addr) { byte_addr = (uint16_t)(byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES); } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); byte_addr = (uint16_t)(byte_addr + skip_size); exit_index = (uint8_t)(exit_index + 1); } byte_addr = (uint16_t)(byte_addr + 1); if (TOPAZ_STATIC_LOCK_RES_START == byte_addr) { byte_addr = (uint16_t)(byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES); } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); byte_addr = (uint16_t)(byte_addr + skip_size); return byte_addr; } static NFCSTATUS phFriNfc_Tpz_H_RemainingReadDataCopy ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); uint8_t copy_temp_buf[PH_FRINFC_NDEFMAP_TOPAZ_MAX_SIZE]; uint16_t copy_length = 0; uint16_t read_copy_length = 0; if (0 != ps_tpz_info->ReadBufferSize) { /* Data is already copied, so give it from the stored buffer */ if ((psNdefMap->ApduBufferSize - psNdefMap->ApduBuffIndex) >= ps_tpz_info->ReadBufferSize) { read_copy_length = ps_tpz_info->ReadBufferSize; (void)memcpy ((void *)(psNdefMap->ApduBuffer + psNdefMap->ApduBuffIndex), (void *)ps_tpz_info->ReadBuffer, ps_tpz_info->ReadBufferSize); } else { read_copy_length = (uint16_t)(psNdefMap->ApduBufferSize - psNdefMap->ApduBuffIndex); copy_length = (uint16_t)(ps_tpz_info->ReadBufferSize - read_copy_length); /* Copy data to user buffer */ (void)memcpy ((void *)(psNdefMap->ApduBuffer + psNdefMap->ApduBuffIndex), (void *)ps_tpz_info->ReadBuffer, read_copy_length); /* Copy data from " ReadBuffer " to temporary buffer */ (void)memcpy ((void *)copy_temp_buf, (void *)(ps_tpz_info->ReadBuffer + read_copy_length), copy_length); /* Copy data from temporary buffer to " ReadBuffer " */ (void)memcpy ((void *)ps_tpz_info->ReadBuffer, (void *)copy_temp_buf, copy_length); } psNdefMap->ApduBuffIndex = (uint16_t)(psNdefMap->ApduBuffIndex + read_copy_length); ps_tpz_info->ReadBufferSize = (uint8_t) (ps_tpz_info->ReadBufferSize - read_copy_length); ps_tpz_info->RemainingReadSize = (uint16_t)( ps_tpz_info->RemainingReadSize - read_copy_length); } if (0 == ps_tpz_info->RemainingReadSize) { /* No data to read, so return */ *psNdefMap->NumOfBytesRead = psNdefMap->ApduBuffIndex; ps_tpz_info->ReadBufferSize = 0; ps_tpz_info->ReadWriteCompleteFlag = TRUE; } else if (psNdefMap->ApduBuffIndex == psNdefMap->ApduBufferSize) { /* User data length is read completely */ *psNdefMap->NumOfBytesRead = psNdefMap->ApduBuffIndex; } else { /* Stored data is not enough, so continue reading the next segment */ ps_tpz_info->CurrentSeg = (uint8_t) (ps_tpz_info->CurrentSeg + 1); #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_RSEG; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_ReadSeg; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); } return result; } static NFCSTATUS phFriNfc_Tpz_H_CopyReadData ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; phFriNfc_ResMemCntrlTLVCont_t *ps_memtlv_info = NULL; uint16_t copy_index = 0; uint16_t copy_length = 0; uint16_t recv_length = 0; static uint16_t skip_size = 0; /* byte address read */ uint16_t copy_till_address = 0; uint16_t exact_copy_length = 0; uint16_t actual_ndef_length = 0; recv_length = *(psNdefMap->SendRecvLength); actual_ndef_length = ps_tpz_info->ActualNDEFMsgSize; if (PH_FRINFC_NDEFMAP_SEEK_CUR == psNdefMap->Offset) { actual_ndef_length = (uint16_t)( ps_tpz_info->RemainingReadSize + psNdefMap->ApduBuffIndex); } exact_copy_length = (uint16_t)((psNdefMap->ApduBufferSize > actual_ndef_length) ? actual_ndef_length : psNdefMap->ApduBufferSize); if (0 == ps_tpz_info->CurrentSeg) { /* Skip copying the UID bytes, CC bytes, and lock and reserved memory bytes */ recv_length = (*(psNdefMap->SendRecvLength) - TOPAZ_STATIC_LOCK_RES_BYTES); } if (TOPAZ_SEG_FROM_BYTE_ADR ( phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead (psNdefMap)) == ps_tpz_info->CurrentSeg) { copy_index = (uint16_t)(copy_index + ( phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead ( psNdefMap) % TOPAZ_SEGMENT_READ_LENGTH)); skip_size = 0; } if (0 != skip_size) { copy_index = (copy_index + skip_size); skip_size = 0; } while (copy_index < recv_length) { copy_length = (uint16_t)(recv_length - copy_index); copy_till_address = 0; /* IF MORE THAN ONE TLV EXISTS THEN ADD A WHILE LOOP HERE, AND PLACE THE IF STATEMENT INSIDE THE WHILE LOOP. ALSO, ps_locktlv_info = &(psNdefMap->LockTlv) change this to ps_locktlv_info = &(psNdefMap->LockTlv[index]) */ ps_locktlv_info = &(psNdefMap->LockTlv); if ( /* Check the lock bytes belong to this segment */ (ps_tpz_info->CurrentSeg == (ps_locktlv_info->ByteAddr / TOPAZ_SEGMENT_READ_LENGTH)) && /* Now to check if the copy_index has surpassed the lock byte address */ (TOPAZ_BYTE_ADR_FROM_SEG(ps_tpz_info->CurrentSeg, copy_index) <= ps_locktlv_info->ByteAddr) ) { if ((ps_locktlv_info->ByteAddr < TOPAZ_STATIC_LOCK_RES_START) || (ps_locktlv_info->ByteAddr >= (TOPAZ_STATIC_LOCK_RES_END + 8))) { copy_till_address = ps_locktlv_info->ByteAddr; } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, ps_locktlv_info->ByteAddr); } /* IF MORE THAN ONE TLV EXISTS THEN ADD A WHILE LOOP HERE, AND PLACE THE IF STATEMENT INSIDE THE WHILE LOOP. ALSO, ps_memtlv_info = &(psNdefMap->MemTlv) change this to ps_memtlv_info = &(psNdefMap->MemTlv[index]) */ ps_memtlv_info = &(psNdefMap->MemTlv); if ( /* Check the reserved bytes belong to this segment */ (ps_tpz_info->CurrentSeg == (ps_memtlv_info->ByteAddr / TOPAZ_SEGMENT_READ_LENGTH)) && /* Now to check if the copy_index has surpassed the reserved byte address */ (TOPAZ_BYTE_ADR_FROM_SEG(ps_tpz_info->CurrentSeg, copy_index) <= ps_memtlv_info->ByteAddr) ) { if ((ps_memtlv_info->ByteAddr < TOPAZ_STATIC_LOCK_RES_START) || (ps_memtlv_info->ByteAddr >= (TOPAZ_STATIC_LOCK_RES_END + 8))) { copy_till_address = (uint16_t) (((ps_memtlv_info->ByteAddr < copy_till_address) || (0 == copy_till_address))? ps_memtlv_info->ByteAddr : copy_till_address); } if (copy_till_address == ps_memtlv_info->ByteAddr) { skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, ps_memtlv_info->ByteAddr); } } copy_length = (uint16_t) ((copy_till_address == 0) ? copy_length : ((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index)); /* After lock bytes, there are immediate reserved bytes, so " copy_length " can be 0 */ if (0 != copy_length) { /* If complete user buffer is not filled and the read data is greater than the user data buffer, then get the remaining size that should be copied. The below " if " statement is used for the above scenario */ if ((copy_length > (uint16_t) (exact_copy_length - psNdefMap->ApduBuffIndex)) && (exact_copy_length != psNdefMap->ApduBuffIndex)) { copy_length = (uint16_t)(exact_copy_length - psNdefMap->ApduBuffIndex); } if (exact_copy_length != psNdefMap->ApduBuffIndex) { (void)memcpy ((void *)(psNdefMap->ApduBuffer + psNdefMap->ApduBuffIndex), (void *)(psNdefMap->SendRecvBuf + copy_index), copy_length); #if 0 if (((copy_till_address == 0) ? copy_length : ((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index)) > (uint16_t) (exact_copy_length - psNdefMap->ApduBuffIndex)) { /* Copy remaining buffer in the static memory */ (void)memcpy ((void *)(ps_tpz_info->ReadBuffer + ps_tpz_info->ReadBufferSize), (void *)(psNdefMap->SendRecvBuf + copy_index), (((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index) - copy_length)); ps_tpz_info->ReadBufferSize = (uint16_t)(((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index) - copy_length); /* Copy the data in the user buffer */ copy_index = (uint16_t)(copy_index + ((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index)); } else #endif /* #if 0 */ { /* Copy the data in the user buffer */ copy_index = (uint16_t)(copy_index + copy_length); } psNdefMap->ApduBuffIndex = (uint16_t)(psNdefMap->ApduBuffIndex + copy_length); } else { copy_length = (uint16_t) ((copy_till_address == 0) ? copy_length : ((copy_till_address % TOPAZ_SEGMENT_READ_LENGTH) - copy_index)); /* Actual NDEF message size is greater than the last index copied in the user buffer */ if (actual_ndef_length > (psNdefMap->ApduBuffIndex + ps_tpz_info->ReadBufferSize)) { /* The statement is correct, check the remaining length */ copy_length = ((copy_length > (actual_ndef_length - psNdefMap->ApduBuffIndex)) ? (actual_ndef_length - psNdefMap->ApduBuffIndex) : copy_length); /* Copy remaining buffer in the static memory */ (void)memcpy ((void *)(ps_tpz_info->ReadBuffer + ps_tpz_info->ReadBufferSize), (void *)(psNdefMap->SendRecvBuf + copy_index), copy_length); ps_tpz_info->ReadBufferSize = (uint8_t)( ps_tpz_info->ReadBufferSize + copy_length); } /* Copy the data in the user buffer */ copy_index = (uint16_t)(copy_index + copy_length); } } if (copy_index != copy_till_address) { skip_size = 0; } if ((copy_index + skip_size) <= recv_length) { copy_index = (uint16_t)(copy_index + skip_size); skip_size = 0; } else { skip_size = (uint16_t)((skip_size > 0) ? (recv_length - copy_index) : 0); copy_index = (uint16_t)recv_length; } } if (exact_copy_length != psNdefMap->ApduBuffIndex) { ps_tpz_info->CurrentSeg = (uint8_t) (ps_tpz_info->CurrentSeg + 1); #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_RSEG; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_ReadSeg; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpRead (psNdefMap); } else { *psNdefMap->NumOfBytesRead = psNdefMap->ApduBuffIndex; if (psNdefMap->ApduBuffIndex == actual_ndef_length) { ps_tpz_info->ReadBufferSize = 0; ps_tpz_info->ReadWriteCompleteFlag = TRUE; } else { ps_tpz_info->RemainingReadSize = (actual_ndef_length - psNdefMap->ApduBuffIndex); } } return result; } static NFCSTATUS phFriNfc_Tpz_H_ParseTLVs ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = &(psNdefMap->TopazContainer); uint8_t *p_recv_buf = NULL; uint16_t recv_length = 0; uint16_t parse_index = 0; phFriNfc_Tpz_ParseSeq_t expected_seq = (phFriNfc_Tpz_ParseSeq_t) ps_tpz_info->ExpectedSeq; uint16_t byte_addr = 0; /* This variable is kept static because if the size to skip LOCK or RESERVED bytes extends to next read then it shall be stored and used to skip the next read the bytes */ static uint16_t skip_size = 0; /* This variable is kept static because if the bytes extends from the read segment, then the index shall be stored This is to store index copied from the 1. lock memory VALUE field bytes in the LOCK and MEMORY CONTROL TLV. 2. Also, LENGTH field of the NDEF TLV */ static uint8_t lock_mem_ndef_index = 0; /* This variable is kept static because if the bytes extends from the read segment, then it has to stored This is to store the 1. lock memory VALUE field bytes in the LOCK and MEMORY CONTROL TLV. 2. Also, LENGTH field of the NDEF TLV */ static uint8_t lock_mem_buf[TOPAZ_MEM_LOCK_TLV_LENGTH] = {0}; /* This is used in case if there is no MAGIC NUMBER found OR TYPE field is not found after reading entire card */ static uint16_t ndef_tlv_byte_addr = 0; p_recv_buf = psNdefMap->SendRecvBuf; recv_length = *psNdefMap->SendRecvLength; if (0 == ps_tpz_info->CurrentSeg) { /* First read, so reset all the static variables */ lock_mem_ndef_index = 0; skip_size = 0; ndef_tlv_byte_addr = 0; /* Skip copying the UID bytes and CC bytes, which is first 12 bytes */ parse_index = (uint16_t)(TOPAZ_UID_BYTES_LENGTH + TOPAZ_CC_BYTES_LENGTH); /* Delete the lock and reserved memory bytes (which are the last 24 bytes in the card) */ recv_length = (uint16_t)(*(psNdefMap->SendRecvLength) - TOPAZ_STATIC_LOCK_RES_BYTES); } while ((parse_index < recv_length) && (NFCSTATUS_SUCCESS == result) && (NDEF_V_TLV != expected_seq)) { if (0 == skip_size) { /* Macro used to get the exact byte address of the card. This is done by using the current segment and the parse index */ byte_addr = TOPAZ_BYTE_ADR_FROM_SEG (ps_tpz_info->CurrentSeg, parse_index); /* Skip size is to skip the lock or memory reserved bytes */ skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); } if (0 != skip_size) { if ((recv_length - parse_index) >= skip_size) { parse_index = (uint16_t)(parse_index + skip_size); skip_size = 0; } else { parse_index = (uint16_t)(parse_index + (recv_length - parse_index)); skip_size = (uint16_t)(skip_size - (recv_length - parse_index)); } } else { switch (expected_seq) { case LOCK_T_TLV: { /* Parse the bytes till TYPE field of LOCK TLV is found, Once the TYPE field is found then change the sequence to LOCK_L_TLV */ result = phFriNfc_Tpz_H_ParseLockTLVType (psNdefMap, p_recv_buf, &parse_index, recv_length, &expected_seq); break; } case LOCK_L_TLV: { /* Parse the length field of LOCK TLV. Length field value of the LOCK TLV is always 3 */ if (TOPAZ_MEM_LOCK_TLV_LENGTH != p_recv_buf[parse_index]) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { parse_index = (uint16_t)(parse_index + 1); expected_seq = LOCK_V_TLV; } break; } case LOCK_V_TLV: { /* Parse the VALUE field of the LOCK TLV */ lock_mem_buf[lock_mem_ndef_index] = p_recv_buf[parse_index]; parse_index = (uint16_t)(parse_index + 1); lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); /* All the 3 bytes are copied in the local buffer */ if (TOPAZ_MEM_LOCK_TLV_LENGTH == lock_mem_ndef_index) { #ifdef FRINFC_READONLY_NDEF (void)memcpy ((void *)psNdefMap->LockTlv.LockTlvBuff, (void *)lock_mem_buf, sizeof (lock_mem_buf)); #endif /* #ifdef FRINFC_READONLY_NDEF */ /* Calculate the byte address and size of the lock bytes */ result = phFriNfc_Tpz_H_GetLockBytesInfo (psNdefMap, lock_mem_buf); lock_mem_ndef_index = 0; expected_seq = MEM_T_TLV; } break; } case MEM_T_TLV: { /* Parse the bytes till TYPE field of MEMORY TLV is found, Once the TYPE field is found then change the sequence to MEM_L_TLV */ result = phFriNfc_Tpz_H_ParseMemTLVType (psNdefMap, p_recv_buf, &parse_index, recv_length, &expected_seq); break; } case MEM_L_TLV: { /* Parse the length field of MEMORY TLV. Length field value of the MEMORY TLV is always 3 */ if (TOPAZ_MEM_LOCK_TLV_LENGTH != p_recv_buf[parse_index]) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { parse_index = (uint16_t)(parse_index + 1); expected_seq = MEM_V_TLV; } break; } case MEM_V_TLV: { /* Parse the VALUE field of the MEMORY TLV */ lock_mem_buf[lock_mem_ndef_index] = p_recv_buf[parse_index]; parse_index = (uint16_t)(parse_index + 1); lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); /* All the 3 bytes are copied in the local buffer */ if (TOPAZ_MEM_LOCK_TLV_LENGTH == lock_mem_ndef_index) { /* Calculate the byte address and size of the lock bytes */ ndef_tlv_byte_addr = TOPAZ_BYTE_ADR_FROM_SEG ( ps_tpz_info->CurrentSeg , parse_index); result = phFriNfc_Tpz_H_GetMemBytesInfo (psNdefMap, lock_mem_buf); lock_mem_ndef_index = 0; expected_seq = NDEF_T_TLV; } break; } case NDEF_T_TLV: { /* Parse the bytes till TYPE field of NDEF TLV is found, Once the TYPE field is found then change the sequence to NDEF_L_TLV */ result = phFriNfc_Tpz_H_ParseNdefTLVType (psNdefMap, p_recv_buf, &parse_index, recv_length, &expected_seq); break; } case NDEF_L_TLV: { /* Length field of the NDEF TLV */ if (0 == lock_mem_ndef_index) { /* This is the 1st time, the loop has entered this case, means that the NDEF byte address has to be updated */ ps_tpz_info->NdefTLVByteAddress = (uint16_t) TOPAZ_BYTE_ADR_FROM_SEG (ps_tpz_info->CurrentSeg, (parse_index - 1)); } if (0 != lock_mem_ndef_index) { /* There is already index has been updated, update remaining buffer */ lock_mem_buf[lock_mem_ndef_index] = p_recv_buf[parse_index]; parse_index = (uint16_t)(parse_index + 1); lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); if (TOPAZ_MEM_LOCK_TLV_LENGTH == lock_mem_ndef_index) { lock_mem_ndef_index = 0; ps_tpz_info->ActualNDEFMsgSize = (uint16_t)((lock_mem_buf[1] << TOPAZ_BYTE_SHIFT) | lock_mem_buf[2]); expected_seq = NDEF_V_TLV; } } /* Check for remaining size in the card and the actual ndef length */ else if (p_recv_buf[parse_index] <= (ps_tpz_info->RemainingSize - (parse_index + 1))) { /* This check is added to see that length field in the TLV is greater than the 1 byte */ if (0xFF == p_recv_buf[parse_index]) { lock_mem_buf[lock_mem_ndef_index] = p_recv_buf[parse_index]; lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); } else { /* Length field of the TLV is ONE byte, so update the actual ndef size */ lock_mem_ndef_index = 0; ps_tpz_info->ActualNDEFMsgSize = (uint16_t) p_recv_buf[parse_index]; expected_seq = NDEF_V_TLV; } parse_index = (uint16_t)(parse_index + 1); } else { /* Wrong length, remaining size in the card is lesser than the actual ndef message length */ lock_mem_ndef_index = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } break; } default: { break; } }/* end of switch (expected_seq) */ } /* end of if (0 != skip_size) */ } /* while ((parse_index < recv_length) && (NFCSTATUS_SUCCESS != result) && (NDEF_V_TLV != expected_seq)) */ ps_tpz_info->ExpectedSeq = (uint8_t)expected_seq; if (0 == ps_tpz_info->CurrentSeg) { /* First segment has the STATIC lock and reserved bytes, so delete it from the remaining size */ ps_tpz_info->RemainingSize = (uint16_t)(ps_tpz_info->RemainingSize - (parse_index + TOPAZ_STATIC_LOCK_RES_BYTES)); } else { ps_tpz_info->RemainingSize = (uint16_t)(ps_tpz_info->RemainingSize - parse_index); } if ((NDEF_V_TLV == expected_seq) && (NFCSTATUS_SUCCESS == result)) { /* NDEF TLV found */ result = phFriNfc_Tpz_H_ActualCardSize (psNdefMap); if ((PH_NDEFMAP_CARD_STATE_READ_ONLY != psNdefMap->CardState) && (0 != ps_tpz_info->ActualNDEFMsgSize)) { /* Check if the card state is READ ONLY or the actual NDEF size is 0 if actual NDEF size is 0, then card state is INITIALISED */ psNdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_WRITE; } } if ((NFCSTATUS_SUCCESS == result) && (NDEF_V_TLV != expected_seq)) { ps_tpz_info->CurrentSeg = (uint8_t)(ps_tpz_info->CurrentSeg + 1); if (TOPAZ_TOTAL_SEG_TO_READ == ps_tpz_info->CurrentSeg) { /* Max segment to read reached, so no more read can be done */ result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_RSEG; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_ReadSeg; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpRead(psNdefMap); } } if ((NFCSTATUS_SUCCESS != result) && (NFCSTATUS_PENDING != result)) { /* Error scenario */ ps_tpz_info->NdefTLVByteAddress = 0; ps_tpz_info->ActualNDEFMsgSize = 0; } if (NFCSTATUS_PENDING != result) { /* Exit scenario */ if ((0x00 == *ps_tpz_info->CCByteBuf) || ((NDEF_T_TLV == expected_seq) && (TOPAZ_TOTAL_SEG_TO_READ == ps_tpz_info->CurrentSeg))) { /* This statement is for getting the new NDEF TLV byte address, because 1st CC byte is corrupted or no NDEF TLV in the card If the 1st CC byte (NDEF magic number) in the card is 0, means that previous write has failed, so to write the exact TLV, calculate the byte number OR The NDEF TLV is not present in the entire card, and the sequence is NDEF_T_TLV (this means, that lock and memory control TLV is found in the card) */ uint16_t size_to_skip = 0; ps_tpz_info->ActualNDEFMsgSize = 0; if (0 != ndef_tlv_byte_addr) { /* ndef_tlv_byte_addr is updated, only after complete parsing the memory control TLV so the value shall not be 0 */ do { /* This loop is added to make sure the lock and reserved bytes are not overwritten */ size_to_skip = 0; size_to_skip = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, ndef_tlv_byte_addr); ndef_tlv_byte_addr = (uint16_t)(ndef_tlv_byte_addr + size_to_skip); }while (0 != size_to_skip); /* Update the TLV byte address */ ps_tpz_info->NdefTLVByteAddress = ndef_tlv_byte_addr; /* Update the remaining size */ ps_tpz_info->RemainingSize = (uint16_t)(psNdefMap->CardMemSize + TOPAZ_UID_BYTES_LENGTH + TOPAZ_CC_BYTES_LENGTH); ps_tpz_info->RemainingSize = (uint16_t) (ps_tpz_info->RemainingSize - (ndef_tlv_byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES)); (void)phFriNfc_Tpz_H_ActualCardSize (psNdefMap); /* Length byte is subtracted here to get the actual NDEF read and write size */ ps_tpz_info->NDEFRWSize = (uint16_t) (ps_tpz_info->NDEFRWSize - 2); ndef_tlv_byte_addr = 0; result = NFCSTATUS_SUCCESS; } } } return result; } static NFCSTATUS phFriNfc_Tpz_H_CopyReadDataAndWrite ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t write_buf[TOPAZ_WRITE_8_DATA_LENGTH]; uint16_t write_index = 0; uint16_t write_len = 0; uint16_t byte_addr = 0; static uint16_t skip_size = 0; ps_tpz_info = &(psNdefMap->TopazContainer); write_len = (uint16_t)((psNdefMap->ApduBufferSize < ps_tpz_info->NDEFRWSize) ? psNdefMap->ApduBufferSize : ps_tpz_info->NDEFRWSize); (void)memcpy ((void *)write_buf, (void *)psNdefMap->SendRecvBuf, TOPAZ_WRITE_8_DATA_LENGTH); if (ps_tpz_info->CurrentBlock == TOPAZ_BLK_FROM_BYTE_ADR ( phFriNfc_Tpz_H_GetNDEFValueFieldAddrForWrite (psNdefMap, write_len))) { skip_size = 0; } /* Byte Number != 0 menas that the VALUE field of the TLV is in between the block, so the first few bytes shall be copied and then user data has to be copied */ if (0 != ps_tpz_info->ByteNumber) { write_index = (uint16_t)(write_index + ps_tpz_info->ByteNumber); } if (0 != skip_size) { write_index = (uint16_t)(write_index + skip_size); } while ((write_index < TOPAZ_WRITE_8_DATA_LENGTH) && (write_len != psNdefMap->ApduBuffIndex)) { skip_size = 0; byte_addr = TOPAZ_BYTE_ADR_FROM_BLK (ps_tpz_info->CurrentBlock, ps_tpz_info->ByteNumber); skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); if (0 == skip_size) { write_buf[write_index] = psNdefMap->ApduBuffer[psNdefMap->ApduBuffIndex]; write_index = (uint16_t)(write_index + 1); psNdefMap->ApduBuffIndex = (uint16_t) (psNdefMap->ApduBuffIndex + 1); ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + 1); } else { if (skip_size >= (TOPAZ_WRITE_8_DATA_LENGTH - write_index)) { skip_size = (uint16_t)(skip_size - (TOPAZ_WRITE_8_DATA_LENGTH - write_index)); write_index = (uint16_t)TOPAZ_WRITE_8_DATA_LENGTH; } else { ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + skip_size); write_index = (uint16_t)(write_index + skip_size); skip_size = 0; } } } if (psNdefMap->ApduBuffIndex == write_len) { ps_tpz_info->WriteSeq = (uint8_t)WR_DATA; } else { if (0 != skip_size) { ps_tpz_info->WriteSeq = (uint8_t)WR_DATA_READ_REQD; } else { ps_tpz_info->WriteSeq = (uint8_t)WR_DATA; } } #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buf, sizeof (write_buf)); return result; } static NFCSTATUS phFriNfc_Tpz_H_UpdateLenFieldValuesAfterRead ( phFriNfc_NdefMap_t *psNdefMap) { /* This function is called, only when the LENGTH field has to be updated with the correct value */ NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint16_t write_len = 0; uint16_t write_index = 0; uint16_t byte_addr = 0; phFriNfc_Tpz_WrSeq_t write_seq; /* This variable is kept static because if the size to skip LOCK or RESERVED bytes extends to next read then it shall be stored and used to skip the next read the bytes */ static uint16_t skip_size = 0; uint8_t write_buf[TOPAZ_WRITE_8_DATA_LENGTH]; uint8_t exit_while = FALSE; ps_tpz_info = &(psNdefMap->TopazContainer); write_len = (uint16_t)((psNdefMap->ApduBufferSize < ps_tpz_info->NDEFRWSize) ? psNdefMap->ApduBufferSize : ps_tpz_info->NDEFRWSize); psNdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE; (void)memcpy ((void *)write_buf, (void *)psNdefMap->SendRecvBuf, TOPAZ_WRITE_8_DATA_LENGTH); write_seq = (phFriNfc_Tpz_WrSeq_t)ps_tpz_info->WriteSeq; if (WR_LEN_1_VALUE == write_seq) { /* First LENGTH field is geting updated, so the skip size reset is done */ skip_size = 0; } if (0 != ps_tpz_info->ByteNumber) { /* Byte Number is not 0, means that some data shall not be overwriteen till that position in the block */ write_index = (uint16_t)(write_index + ps_tpz_info->ByteNumber); } if (0 != skip_size) { /* This is possible after updating the FIRST length field skip size is skipped because of the pending LOCK or RESERVED bytes */ write_index = (uint16_t)(write_index + skip_size); } while ((write_index < TOPAZ_WRITE_8_DATA_LENGTH) && (FALSE == exit_while)) { skip_size = 0; /* Get the exact byte address from the block number and byte number */ byte_addr = TOPAZ_BYTE_ADR_FROM_BLK (ps_tpz_info->CurrentBlock, ps_tpz_info->ByteNumber); /* Get the skip size */ skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); if (0 == skip_size) { switch (write_seq) { case WR_LEN_1_VALUE: { /* First sequenc is always to update 1st LENGTH field of the TLV */ if (write_len < 0xFF) { /* This means the LENGTH field is only one BYTE */ write_buf[write_index] = (uint8_t) psNdefMap->ApduBuffIndex; /* Exit the loop */ exit_while = TRUE; } else { /* Update the 1st LENGTH field */ write_buf[write_index] = (uint8_t)0xFF; } break; } case WR_LEN_2_VALUE: { /* Update the 2nd LENGTH field */ write_buf[write_index] = (uint8_t) (psNdefMap->ApduBuffIndex >> BYTE_SIZE); break; } case WR_LEN_3_VALUE: { /* Update the 3rd LENGTH field */ write_buf[write_index] = (uint8_t) (psNdefMap->ApduBuffIndex & TOPAZ_BYTE_LENGTH_MASK); /* Exit the loop */ exit_while = TRUE; break; } default: { /* Invalid case */ break; } } write_index = (uint16_t)(write_index + 1); if ( /* As the write is done for 8 bytes, the write index cant go for more than or equal to 8 bytes, if it reaches 8 bytes then sequence shall not be incrmented */ (TOPAZ_WRITE_8_DATA_LENGTH != write_index) && /* If the last length field byte is updated then the write sequence shall not be incremented */ (WR_LEN_3_VALUE != write_seq) && /* Check added if the write length is less than 0xFF. If length is less than 0xFF, then write sequence shall not be incremented */ (write_len >= 0xFF) ) { /* Sequence is incremented to the next level */ write_seq = (phFriNfc_Tpz_WrSeq_t)(write_seq + 1); } /* Byte number is incremented */ ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + 1); } else { if (skip_size >= (TOPAZ_WRITE_8_DATA_LENGTH - write_index)) { skip_size = (uint16_t)(skip_size - (TOPAZ_WRITE_8_DATA_LENGTH - write_index)); write_index = (uint16_t)TOPAZ_WRITE_8_DATA_LENGTH; } else { ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + skip_size); write_index = (uint16_t)(write_index + skip_size); skip_size = 0; } } } ps_tpz_info->WriteSeq = (uint8_t)write_seq; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buf, sizeof (write_buf)); return result; } static NFCSTATUS phFriNfc_Tpz_H_UpdateLenFieldZeroAfterRead ( phFriNfc_NdefMap_t *psNdefMap) { /* This function is called, only when the LENGTH field has to be updated with the 0 */ NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint16_t write_len = 0; uint16_t write_index = 0; uint16_t prev_apdu_index = 0; uint16_t byte_addr = 0; phFriNfc_Tpz_WrSeq_t write_seq; /* This variable is kept static because if the size to skip LOCK or RESERVED bytes extends to next read then it shall be stored and used to skip the next read bytes */ static uint16_t skip_size = 0; uint8_t write_buf[TOPAZ_WRITE_8_DATA_LENGTH]; ps_tpz_info = &(psNdefMap->TopazContainer); write_len = (uint16_t)((psNdefMap->ApduBufferSize < ps_tpz_info->NDEFRWSize) ? psNdefMap->ApduBufferSize : ps_tpz_info->NDEFRWSize); psNdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE; (void)memcpy ((void *)write_buf, (void *)psNdefMap->SendRecvBuf, TOPAZ_WRITE_8_DATA_LENGTH); prev_apdu_index = psNdefMap->ApduBuffIndex; write_seq = (phFriNfc_Tpz_WrSeq_t)ps_tpz_info->WriteSeq; if (WR_LEN_1_0 == write_seq) { /* First LENGTH field is geting updated, so the skip size reset is done */ skip_size = 0; } if (0 != ps_tpz_info->ByteNumber) { /* Byte Number is not 0, means that some data shall not be overwriteen till that position in the block */ write_index = (uint16_t)(write_index + ps_tpz_info->ByteNumber); ps_tpz_info->ByteNumber = 0; } if (0 != skip_size) { /* This is possible after updating the FIRST length field skip size is skipped because of the pending LOCK or RESERVED bytes */ write_index = (uint16_t)(write_index + skip_size); } while ((write_index < TOPAZ_WRITE_8_DATA_LENGTH) && (write_len != psNdefMap->ApduBuffIndex)) { skip_size = 0; byte_addr = TOPAZ_BYTE_ADR_FROM_BLK (ps_tpz_info->CurrentBlock, ps_tpz_info->ByteNumber); skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); if (0 == skip_size) { switch (write_seq) { case WR_LEN_1_0: { /* First sequence is always to update 1st LENGTH field of the TLV */ write_buf[write_index] = 0x00; write_index = (uint16_t)(write_index + 1); if (write_len < 0xFF) { /* LENGTH field is only 1 byte, so update change the sequence to update user data */ write_seq = WR_DATA; } else { /* Go to the next LENGTH field to update */ write_seq = (phFriNfc_Tpz_WrSeq_t)((TOPAZ_WRITE_8_DATA_LENGTH != write_index) ? (write_seq + 1) : write_seq); } break; } case WR_LEN_2_0: case WR_LEN_3_0: { /* Update 2nd and 3rd LEGNTH field */ write_buf[write_index] = 0x00; write_index = (uint16_t)(write_index + 1); write_seq = (phFriNfc_Tpz_WrSeq_t)((TOPAZ_WRITE_8_DATA_LENGTH != write_index) ? (write_seq + 1) : write_seq); break; } case WR_DATA: default: { /* Update the buffer by the user data */ write_buf[write_index] = psNdefMap->ApduBuffer[psNdefMap->ApduBuffIndex]; write_index = (uint16_t)(write_index + 1); psNdefMap->ApduBuffIndex = (uint16_t) (psNdefMap->ApduBuffIndex + 1); break; } } ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + 1); } else { /* LOCK and MEMORY bytes are found */ if (skip_size >= (TOPAZ_WRITE_8_DATA_LENGTH - write_index)) { /* skip size has exceeded the block number, so calculate the remaining skip size */ skip_size = (uint16_t)(skip_size - (TOPAZ_WRITE_8_DATA_LENGTH - write_index)); write_index = (uint16_t)TOPAZ_WRITE_8_DATA_LENGTH; } else { /* skip the LOCK and MEMORY bytes size */ ps_tpz_info->ByteNumber = (uint8_t) (ps_tpz_info->ByteNumber + skip_size); write_index = (uint16_t)(write_index + skip_size); skip_size = 0; } } } if (psNdefMap->ApduBuffIndex == write_len) { /* User data has been completely copied and it is ready to write, so change the sequence */ ps_tpz_info->WriteSeq = (uint8_t)WR_DATA; } else if ((WR_DATA == write_seq) && (prev_apdu_index == psNdefMap->ApduBuffIndex)) { /* The user data has not been written, only the LENGTH field is updated */ ps_tpz_info->WriteSeq = (uint8_t)((write_len < 0xFF) ? WR_LEN_1_0 : WR_LEN_3_0); } else { /* Update the sequence in the context */ ps_tpz_info->WriteSeq = (uint8_t)write_seq; } ps_tpz_info->ByteNumber = 0; #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buf, sizeof (write_buf)); return result; } static NFCSTATUS phFriNfc_Tpz_H_RdForWrite ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; phFriNfc_Tpz_WrSeq_t write_seq; uint16_t byte_addr = 0; uint8_t exit_while = FALSE; uint16_t skip_size = 0; ps_tpz_info = &(psNdefMap->TopazContainer); write_seq = (phFriNfc_Tpz_WrSeq_t)(ps_tpz_info->WriteSeq); #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read8; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ psNdefMap->State = PH_FRINFC_TOPAZ_STATE_RD_FOR_WR_NDEF; switch (write_seq) { case WR_LEN_1_0: case WR_LEN_1_VALUE: { byte_addr = (ps_tpz_info->NdefTLVByteAddress + 1); /* This loop is to skip the lock amd reserved bytes */ while (FALSE == exit_while) { if (TOPAZ_STATIC_LOCK_FIRST_BLOCK_NO == TOPAZ_BLK_FROM_BYTE_ADR (byte_addr)) { byte_addr = (uint16_t)(byte_addr + TOPAZ_STATIC_LOCK_RES_BYTES); } skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); if (0 != skip_size) { byte_addr = (uint16_t)(byte_addr + skip_size); } else { exit_while = TRUE; } } break; } case WR_LEN_2_0: case WR_LEN_3_0: case WR_LEN_2_VALUE: case WR_LEN_3_VALUE: { byte_addr = (uint16_t)TOPAZ_BYTE_ADR_FROM_BLK (ps_tpz_info->CurrentBlock, ps_tpz_info->ByteNumber); /* This loop is for to skip the lock amd reserved bytes */ while (FALSE == exit_while) { skip_size = phFriNfc_Tpz_H_GetSkipSize (psNdefMap, byte_addr); if (0 != skip_size) { byte_addr = (uint16_t)(byte_addr + skip_size); } else { exit_while = TRUE; } } break; } case WR_DATA_READ_REQD: { /* Lock or reserved bytes found bytes */ byte_addr = (uint16_t)TOPAZ_BYTE_ADR_FROM_BLK (ps_tpz_info->CurrentBlock, ps_tpz_info->ByteNumber); break; } default: { break; } } ps_tpz_info->CurrentBlock = (uint8_t) TOPAZ_BLK_FROM_BYTE_ADR (byte_addr); ps_tpz_info->ByteNumber = (uint8_t) TOPAZ_BYTE_OFFSET_FROM_BYTE_ADR (byte_addr); result = phFriNfc_Tpz_H_NxpRead (psNdefMap); return result; } static uint16_t phFriNfc_Tpz_H_CompareLockBlocks ( phFriNfc_NdefMap_t *psNdefMap, uint8_t block_no, uint16_t *p_skip_size) { uint16_t return_addr = 0; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; ps_locktlv_info = &(psNdefMap->LockTlv); if (block_no == ps_locktlv_info->BlkNum) { /* ps_tpz_info->ByteNumber = (uint8_t)ps_locktlv_info->ByteNum; */ *p_skip_size = ps_locktlv_info->Size; return_addr = ps_locktlv_info->ByteAddr; } return return_addr; } static uint16_t phFriNfc_Tpz_H_CompareMemBlocks ( phFriNfc_NdefMap_t *psNdefMap, uint8_t block_no, uint16_t *p_skip_size) { uint16_t return_addr = 0; phFriNfc_ResMemCntrlTLVCont_t *ps_memtlv_info = NULL; ps_memtlv_info = &(psNdefMap->MemTlv); if (block_no == ps_memtlv_info->BlkNum) { /* ps_tpz_info->ByteNumber = (uint8_t)ps_memtlv_info->ByteNum; */ *p_skip_size = ps_memtlv_info->Size; return_addr = ps_memtlv_info->ByteAddr; } return return_addr; } static NFCSTATUS phFriNfc_Tpz_H_CopySendWrData ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; uint8_t write_buf[TOPAZ_WRITE_8_DATA_LENGTH]; uint16_t write_len; uint8_t copy_length; uint16_t skip_size = 0; ps_tpz_info = &(psNdefMap->TopazContainer); write_len = (uint16_t)((psNdefMap->ApduBufferSize < ps_tpz_info->NDEFRWSize) ? psNdefMap->ApduBufferSize : ps_tpz_info->NDEFRWSize); if (0 != phFriNfc_Tpz_H_CompareLockBlocks (psNdefMap, ps_tpz_info->CurrentBlock, &skip_size)) { ps_tpz_info->WriteSeq = (uint8_t)WR_DATA_READ_REQD; ps_tpz_info->ByteNumber = 0; result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else if (0 != phFriNfc_Tpz_H_CompareMemBlocks (psNdefMap, ps_tpz_info->CurrentBlock, &skip_size)) { ps_tpz_info->WriteSeq = (uint8_t)WR_DATA_READ_REQD; ps_tpz_info->ByteNumber = 0; result = phFriNfc_Tpz_H_RdForWrite (psNdefMap); } else { #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ psNdefMap->State = (uint8_t)PH_FRINFC_TOPAZ_STATE_WRITE; if ((write_len - psNdefMap->ApduBuffIndex) >= (uint16_t)TOPAZ_WRITE_8_DATA_LENGTH) { copy_length = (uint8_t)TOPAZ_WRITE_8_DATA_LENGTH; (void)memcpy ((void *)write_buf, (void *)(psNdefMap->ApduBuffer + psNdefMap->ApduBuffIndex), copy_length); psNdefMap->ApduBuffIndex = (uint16_t)(psNdefMap->ApduBuffIndex + copy_length); } else { copy_length = (uint8_t)(write_len - psNdefMap->ApduBuffIndex); (void)memcpy ((void *)write_buf, (void *)(psNdefMap->ApduBuffer + psNdefMap->ApduBuffIndex), TOPAZ_WRITE_8_DATA_LENGTH); psNdefMap->ApduBuffIndex = (uint16_t)(psNdefMap->ApduBuffIndex + copy_length); (void)memset ((void *)(write_buf + copy_length), 0x00, (TOPAZ_WRITE_8_DATA_LENGTH - copy_length)); } #ifdef TOPAZ_RAW_SUPPORT *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_WRITE_E8; #else psNdefMap->Cmd.JewelCmd = phHal_eJewel_Write8E; #endif /* #ifdef TOPAZ_RAW_SUPPORT */ result = phFriNfc_Tpz_H_NxpWrite (psNdefMap, write_buf, sizeof (write_buf)); } return result; } static NFCSTATUS phFriNfc_Tpz_H_ActualCardSize ( phFriNfc_NdefMap_t *psNdefMap) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_TopazCont_t *ps_tpz_info = NULL; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; phFriNfc_ResMemCntrlTLVCont_t *ps_memtlv_info = NULL; uint16_t ndef_value_byte_addr = 0; uint16_t ndef_read_write_size = 0; ps_tpz_info = &(psNdefMap->TopazContainer); if (ps_tpz_info->ActualNDEFMsgSize > ps_tpz_info->RemainingSize) { ps_tpz_info->ActualNDEFMsgSize = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { ndef_read_write_size = ps_tpz_info->RemainingSize; ndef_value_byte_addr = phFriNfc_Tpz_H_GetNDEFValueFieldAddrForRead (psNdefMap); ps_locktlv_info = &(psNdefMap->LockTlv); if (ps_locktlv_info->ByteAddr > ndef_value_byte_addr) { ndef_read_write_size = (ndef_read_write_size - ps_locktlv_info->Size); } ps_memtlv_info = &(psNdefMap->MemTlv); if (ps_memtlv_info->ByteAddr > ndef_value_byte_addr) { ndef_read_write_size = (ndef_read_write_size - ps_memtlv_info->Size); } if (ps_tpz_info->ActualNDEFMsgSize > ndef_read_write_size) { ps_tpz_info->ActualNDEFMsgSize = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { ps_tpz_info->NDEFRWSize = (uint16_t) ((ps_tpz_info->ActualNDEFMsgSize < 0xFF) ? (ndef_read_write_size - 2) : ndef_read_write_size); } } return result; } static NFCSTATUS phFriNfc_Tpz_H_ParseLockTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint16_t parse_index = *p_parse_index; phFriNfc_Tpz_ParseSeq_t expected_seq = *seq_to_execute; PHNFC_UNUSED_VARIABLE(psNdefMap); PHNFC_UNUSED_VARIABLE(total_len_to_parse); switch (p_parse_data[parse_index]) { case PH_FRINFC_TOPAZ_LOCK_CTRL_T: { expected_seq = LOCK_L_TLV; parse_index = (parse_index + 1); break; } case PH_FRINFC_TOPAZ_NULL_T: { expected_seq = LOCK_T_TLV; parse_index = (parse_index + 1); break; } default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); break; } } *seq_to_execute = expected_seq; *p_parse_index = parse_index; return result; } static NFCSTATUS phFriNfc_Tpz_H_ParseMemTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint16_t parse_index = *p_parse_index; phFriNfc_Tpz_ParseSeq_t expected_seq = *seq_to_execute; PHNFC_UNUSED_VARIABLE(psNdefMap); PHNFC_UNUSED_VARIABLE(total_len_to_parse); switch (p_parse_data[parse_index]) { case PH_FRINFC_TOPAZ_LOCK_CTRL_T: { expected_seq = LOCK_L_TLV; parse_index = (parse_index + 1); break; } case PH_FRINFC_TOPAZ_NULL_T: { expected_seq = MEM_T_TLV; parse_index = (parse_index + 1); break; } case PH_FRINFC_TOPAZ_MEM_CTRL_T: { expected_seq = MEM_L_TLV; parse_index = (parse_index + 1); break; } default: { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); break; } } *seq_to_execute = expected_seq; *p_parse_index = parse_index; return result; } static NFCSTATUS phFriNfc_Tpz_H_ParseNdefTLVType ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_parse_data, uint16_t *p_parse_index, uint16_t total_len_to_parse, phFriNfc_Tpz_ParseSeq_t *seq_to_execute) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint16_t parse_index = *p_parse_index; phFriNfc_Tpz_ParseSeq_t expected_seq = *seq_to_execute; PHNFC_UNUSED_VARIABLE(psNdefMap); PHNFC_UNUSED_VARIABLE(total_len_to_parse); switch (p_parse_data[parse_index]) { case PH_FRINFC_TOPAZ_MEM_CTRL_T: { /* TYPE field of Memory control TLV is found. This means that more than one memory control TLV exists */ expected_seq = MEM_L_TLV; parse_index = (parse_index + 1); break; } case PH_FRINFC_TOPAZ_NULL_T: { /* Skip the NULL TLV */ expected_seq = NDEF_T_TLV; parse_index = (parse_index + 1); break; } case PH_FRINFC_TOPAZ_NDEF_T: { /* TYPE field of NDEF TLV found, so next expected sequence is LENGTH field */ expected_seq = NDEF_L_TLV; parse_index = (parse_index + 1); break; } default: { /* Reset the sequence */ expected_seq = LOCK_T_TLV; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); break; } } *seq_to_execute = expected_seq; *p_parse_index = parse_index; return result; } static uint16_t phFriNfc_Tpz_H_GetSkipSize ( phFriNfc_NdefMap_t *psNdefMap, uint16_t byte_adr_card) { uint16_t return_size = 0; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; phFriNfc_ResMemCntrlTLVCont_t *ps_memtlv_info = NULL; ps_locktlv_info = &(psNdefMap->LockTlv); ps_memtlv_info = &(psNdefMap->MemTlv); /* If there are more than one LOCK CONTROL TLV, then ADD A LOOP HERE OF THE NUMBER OF TLVs FOUND */ if (byte_adr_card == ps_locktlv_info->ByteAddr) { return_size = ps_locktlv_info->Size; } /* If there are more than one MEMORY CONTROL TLV, then ADD A LOOP HERE OF THE NUMBER OF TLVs FOUND */ if (byte_adr_card == ps_memtlv_info->ByteAddr) { return_size = ps_memtlv_info->Size; } return return_size; } static NFCSTATUS phFriNfc_Tpz_H_GetLockBytesInfo ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_lock_info) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; uint8_t page_address = 0; uint8_t bytes_offset = 0; uint8_t lock_index = 0; ps_locktlv_info = &(psNdefMap->LockTlv); page_address = (uint8_t)(p_lock_info[lock_index] >> NIBBLE_SIZE); bytes_offset = (uint8_t)(p_lock_info[lock_index] & TOPAZ_NIBBLE_MASK); lock_index = (lock_index + 1); ps_locktlv_info->Size = (uint16_t) (((p_lock_info[lock_index] % TOPAZ_BYTE_SIZE_IN_BITS) > 0)? ((p_lock_info[lock_index] / TOPAZ_BYTE_SIZE_IN_BITS) + 1) : (p_lock_info[lock_index] / TOPAZ_BYTE_SIZE_IN_BITS)); lock_index = (lock_index + 1); ps_locktlv_info->BytesPerPage = (p_lock_info[lock_index] & TOPAZ_NIBBLE_MASK); ps_locktlv_info->BytesLockedPerLockBit = (p_lock_info[lock_index] >> NIBBLE_SIZE); /* Apply the formula to calculate byte address ByteAddr = PageAddr*2^BytesPerPage + ByteOffset */ ps_locktlv_info->ByteAddr = (uint16_t)((page_address * (1 << ps_locktlv_info->BytesPerPage)) + bytes_offset); if ( /* Out of bound memory check */ ((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size) > (uint16_t)(psNdefMap->TopazContainer.CCByteBuf[2] * TOPAZ_BYTES_PER_BLOCK)) || /* Check the static lock and reserved areas memory blocks */ ((ps_locktlv_info->ByteAddr >= TOPAZ_STATIC_LOCK_RES_START) && (ps_locktlv_info->ByteAddr < TOPAZ_STATIC_LOCK_RES_END)) || (((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1) >= TOPAZ_STATIC_LOCK_RES_START) && ((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1) < TOPAZ_STATIC_LOCK_RES_END)) ) { ps_locktlv_info->ByteAddr = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { ps_locktlv_info->BlkNum = (ps_locktlv_info->ByteAddr / TOPAZ_BYTES_PER_BLOCK); ps_locktlv_info->ByteNum = (ps_locktlv_info->ByteAddr % TOPAZ_BYTES_PER_BLOCK); } return result; } static NFCSTATUS phFriNfc_Tpz_H_GetMemBytesInfo ( phFriNfc_NdefMap_t *psNdefMap, uint8_t *p_mem_info) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_ResMemCntrlTLVCont_t *ps_memtlv_info = NULL; phFriNfc_LockCntrlTLVCont_t *ps_locktlv_info = NULL; uint8_t page_address = 0; uint8_t bytes_offset = 0; uint8_t mem_index = 0; ps_memtlv_info = &(psNdefMap->MemTlv); ps_locktlv_info = &(psNdefMap->LockTlv); page_address = (uint8_t)(p_mem_info[mem_index] >> NIBBLE_SIZE); bytes_offset = (uint8_t)(p_mem_info[mem_index] & TOPAZ_NIBBLE_MASK); mem_index = (mem_index + 1); ps_memtlv_info->Size = (uint16_t)p_mem_info[mem_index]; mem_index = (mem_index + 1); ps_memtlv_info->BytesPerPage = (p_mem_info[mem_index] & TOPAZ_NIBBLE_MASK); /* Apply the formula to calculate byte address ByteAddr = PageAddr * 2^BytesPerPage + ByteOffset */ ps_memtlv_info->ByteAddr = (uint16_t)((page_address * (1 << ps_memtlv_info->BytesPerPage)) + bytes_offset); if ( /* Check if the lock and memory bytes are overlapped */ ((ps_memtlv_info->ByteAddr >= ps_locktlv_info->ByteAddr) && (ps_memtlv_info->ByteAddr <= (ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1))) || (((ps_memtlv_info->ByteAddr + ps_memtlv_info->Size - 1) >= ps_locktlv_info->ByteAddr) && ((ps_memtlv_info->ByteAddr + ps_memtlv_info->Size - 1) <= (ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1))) || /* Check the static lock and reserved areas memory blocks */ ((ps_memtlv_info->ByteAddr >= TOPAZ_STATIC_LOCK_RES_START) && (ps_memtlv_info->ByteAddr < TOPAZ_STATIC_LOCK_RES_END)) || (((ps_memtlv_info->ByteAddr + ps_memtlv_info->Size - 1) >= TOPAZ_STATIC_LOCK_RES_START) && ((ps_memtlv_info->ByteAddr + ps_memtlv_info->Size - 1) < TOPAZ_STATIC_LOCK_RES_END)) || /* Check if the memory address is out bound */ ((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size) > (uint16_t)(psNdefMap->TopazContainer.CCByteBuf[2] * TOPAZ_BYTES_PER_BLOCK)) ) { ps_memtlv_info->ByteAddr = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { ps_memtlv_info->BlkNum = (ps_memtlv_info->ByteAddr / TOPAZ_BYTES_PER_BLOCK); ps_memtlv_info->ByteNum = (ps_memtlv_info->ByteAddr % TOPAZ_BYTES_PER_BLOCK); } return result; } #ifdef UNIT_TEST #include <phUnitTestNfc_TopazDynamic_static.c> #endif #endif /*#if !(defined(PH_FRINFC_MAP_TOPAZ_DISABLED ) || defined (PH_FRINFC_MAP_TOPAZ_DYNAMIC_DISABLED ))*/