/*----------------------------------------------------------------------------*/ /* Copyright 2016-2023 NXP */ /* */ /* NXP Confidential. This software is owned or controlled by NXP and may only */ /* be used strictly in accordance with the applicable license terms. */ /* By expressly accepting such terms or by downloading, installing, */ /* activating and/or otherwise using the software, you are agreeing that you */ /* have read, and that you agree to comply with and are bound by, such */ /* license terms. If you do not agree to be bound by the applicable license */ /* terms, then you may not retain, install, activate or otherwise use the */ /* software. */ /*----------------------------------------------------------------------------*/ /** \file * Internal functions for Tag Operation Application Layer Component of * Reader Library Framework. * $Author$ * $Revision$ (v07.10.00) * $Date$ */ #include #include #include #include #include #include #ifdef NXPBUILD__PHAL_TOP_SW #ifdef NXPBUILD__PHAL_TOP_T1T_SW #include "phalTop_Sw_Int_T1T.h" static void phMemCpy(void* dest, void* src, uint16_t wLength); phStatus_t phalTop_Sw_Int_T1T_SetReadOnly( phalTop_Sw_DataParams_t * pDataParams ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_BUF aRxData[11]; uint16_t PH_MEMLOC_REM wRxLength = 0; uint16_t PH_MEMLOC_COUNT wIndex; uint16_t PH_MEMLOC_COUNT wTempIndex; uint16_t PH_MEMLOC_COUNT wLockCtrlTlvSize; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Check if tag is in valid state */ if(pDataParams->bTagState == PHAL_TOP_STATE_NONE) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_INVALID_STATE, PH_COMP_AL_TOP); } /* Check for NDEF length > 0 (in initialized state NDEF length is 0) */ if(pDataParams->bTagState == PHAL_TOP_STATE_INITIALIZED) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_EMPTY_NDEF, PH_COMP_AL_TOP); } /* Check if tag is already in read-only state */ if(pDataParams->bTagState == PHAL_TOP_STATE_READONLY) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_READONLY_TAG, PH_COMP_AL_TOP); } /* Update RW access */ pT1T->bRwa = PHAL_TOP_T1T_CC_RWA_RO; /* Write Read/Write access byte*/ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_RWA, pT1T->bRwa, aRxData, &wRxLength)); /* Update Lock-0 */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteNoEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_LOCK0, 0xFF, aRxData, &wRxLength)); /* Update Lock-1 */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteNoEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_LOCK1, 0xFF, aRxData, &wRxLength)); /* Update dynamic lock bytes */ for(wIndex = 0; wIndex < pT1T->bLockTlvCount; wIndex++) { wLockCtrlTlvSize = (((uint16_t)(pT1T->asLockCtrlTlv[wIndex].bSizeInBits)) / 8U); for(wTempIndex = 0; wTempIndex < wLockCtrlTlvSize; wTempIndex++) { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteNoEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->asLockCtrlTlv[wIndex].wByteAddr + wTempIndex), 0xFF, aRxData, &wRxLength)); } if(0u != ((pT1T->asLockCtrlTlv[wIndex].bSizeInBits) % 8U)) { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteNoEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->asLockCtrlTlv[wIndex].wByteAddr + wTempIndex), 0xFF, aRxData, &wRxLength)); } } pDataParams->bTagState = PHAL_TOP_STATE_READONLY; return PH_ERR_SUCCESS; } void phalTop_Sw_Int_T1T_CalculateMaxNdefSize( phalTop_Sw_DataParams_t * pDataParams, phalTop_T1T_t * pT1T ) { uint16_t PH_MEMLOC_COUNT wIndex; uint16_t PH_MEMLOC_REM wTagSize; if(pT1T->bTagMemoryType == PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC) { pDataParams->dwMaxNdefLength = 90; } else { /* Reset max. NDEF length */ pDataParams->dwMaxNdefLength = 0; /* Calculate total tag size including lock and reserved bytes */ { uint16_t wTms = 0; wTms = pT1T->bTms; wTagSize = (wTms + 1U) * 8U; } /* Calculate NDEF Header Address */ if((pT1T->bLockTlvCount !=0U) && (pT1T->bMemoryTlvCount != 0U)) { pT1T->wNdefHeaderAddr = ((pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset > pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset)? pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset: ((pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset) + 5U)); } else if(pT1T->bLockTlvCount !=0U) { pT1T->wNdefHeaderAddr = pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset + 5U; } else if(pT1T->bMemoryTlvCount != 0U) { pT1T->wNdefHeaderAddr = pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset + 5U; } else { pT1T->wNdefHeaderAddr = 12; } /* Calculate max. NDEF TLV length */ for(wIndex = pT1T->wNdefHeaderAddr; wIndex < wTagSize; wIndex++) { /* Update Lock/Reserved/OTP block status when segment changes */ if((wIndex % PHAL_TOP_T1T_SEGMENT_SIZE) == 0U) { pT1T->sSegment.bAddress = (uint8_t)(wIndex / PHAL_TOP_T1T_SEGMENT_SIZE); (void)phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T); } /* Increment max. NDEF length if not lock/OTP/reserved byte */ if(0u != (phalTop_Sw_Int_T1T_CheckLockReservedOtp(pT1T, wIndex))) { pDataParams->dwMaxNdefLength++; } } /* Subtract T and L field length to get NDEF message (V field) length */ if(pDataParams->dwMaxNdefLength < 0xFFU) { pDataParams->dwMaxNdefLength -= 2u; } else { pDataParams->dwMaxNdefLength -= 4u; } } } phStatus_t phalTop_Sw_Int_T1T_UpdateLockReservedOtp( phalTop_T1T_t * pT1T ) { uint16_t PH_MEMLOC_COUNT wOffset; uint16_t PH_MEMLOC_COUNT wIndex; uint16_t PH_MEMLOC_REM wSegmentOffset; uint16_t PH_MEMLOC_REM wLockCtrlTlvSize; (void)memset(pT1T->sSegment.bLockReservedOtp, 0, 16); if(pT1T->sSegment.bAddress == 0U) { pT1T->sSegment.bLockReservedOtp[0x00] = 0xFF; pT1T->sSegment.bLockReservedOtp[0x0D] = 0xFF; pT1T->sSegment.bLockReservedOtp[0x0E] = 0xFF; pT1T->sSegment.bLockReservedOtp[0x0F] = 0xFF; } else { /* Update Lock Bytes */ for(wIndex = 0; wIndex < pT1T->bLockTlvCount; wIndex++) { if((pT1T->asLockCtrlTlv[wIndex].wByteAddr / PHAL_TOP_T1T_SEGMENT_SIZE) == pT1T->sSegment.bAddress) { wSegmentOffset = pT1T->asLockCtrlTlv[wIndex].wByteAddr % PHAL_TOP_T1T_SEGMENT_SIZE; wLockCtrlTlvSize = (((uint16_t)(pT1T->asLockCtrlTlv[wIndex].bSizeInBits)) / 8U); for(wOffset = wSegmentOffset; wOffset < (wSegmentOffset + wLockCtrlTlvSize); wOffset++) { pT1T->sSegment.bLockReservedOtp[wOffset / 8U] |= (uint8_t)(1U << (wOffset % 8U)); } } } /* Update Memory Bytes */ for(wIndex = 0; wIndex < pT1T->bMemoryTlvCount; wIndex++) { if((pT1T->asMemCtrlTlv[wIndex].wByteAddr / PHAL_TOP_T1T_SEGMENT_SIZE) == (pT1T->sSegment.bAddress)) { wSegmentOffset = pT1T->asMemCtrlTlv[wIndex].wByteAddr % PHAL_TOP_T1T_SEGMENT_SIZE; for(wOffset = wSegmentOffset; wOffset < (wSegmentOffset + (pT1T->asMemCtrlTlv[wIndex].bSizeInBytes)); wOffset++) { pT1T->sSegment.bLockReservedOtp[wOffset / 8U] |= (uint8_t)(1U << (wOffset % 8U)); } } } } return PH_ERR_SUCCESS; } uint8_t phalTop_Sw_Int_T1T_CheckLockReservedOtp( phalTop_T1T_t * pT1T, uint16_t wIndex ) { if((pT1T->sSegment.bLockReservedOtp[(wIndex % PHAL_TOP_T1T_SEGMENT_SIZE) / 8U] != 0U) && (((1U << (wIndex % 8U)) != 0U))) { /* Lock/Reserved/OTP block */ return PH_OFF; } else { /* Data block */ return PH_ON; } } phStatus_t phalTop_Sw_Int_T1T_Read( phalTop_T1T_t * pT1T, uint16_t wAddress, uint8_t * pData, uint8_t bFreshRead ) { phStatus_t PH_MEMLOC_REM status; uint16_t PH_MEMLOC_REM wLength; uint8_t PH_MEMLOC_REM * pRxData = NULL; if(pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC) { if(bFreshRead == PH_ON) { /* Get segment address */ pT1T->sSegment.bAddress = (uint8_t)(wAddress / PHAL_TOP_T1T_SEGMENT_SIZE); /* Read segment */ PH_CHECK_SUCCESS_FCT(status, phalT1T_ReadSegment( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)((pT1T->sSegment.bAddress << 4U) & 0xF0U), &pRxData, &wLength)); /* Remove ADDS */ pT1T->sSegment.pData = pRxData + 1U; } (*pData) = pT1T->sSegment.pData[(wAddress % PHAL_TOP_T1T_SEGMENT_SIZE)]; } else { if(bFreshRead == PH_ON) { /* First segment */ pT1T->sSegment.bAddress = 0; /* Read first segment */ PH_CHECK_SUCCESS_FCT(status, phalT1T_ReadAll( pT1T->pAlT1TDataParams, pT1T->bUid, &pRxData, &wLength)); /* Remove HR0 and HR1 */ pT1T->sSegment.pData = pRxData + 2U; } *pData = pT1T->sSegment.pData[wAddress]; } return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_Write( phalTop_Sw_DataParams_t * pDataParams, phalTop_T1T_t * pT1T, uint16_t wAddress, uint8_t * pData, uint16_t pDataIndex ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_BUF aRxData[11]; uint8_t PH_MEMLOC_BUF aTempData[11]; uint16_t PH_MEMLOC_REM wRxLength = 0; uint8_t PH_MEMLOC_REM bFirstBlock = 0; uint8_t PH_MEMLOC_REM bLastBlock = 0; uint8_t PH_MEMLOC_BUF bIndex = 0; if(pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC) { if((wAddress % 8U) == 0U) { if((pDataIndex + 8U) <= pDataParams->dwNdefLength) { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseBlock( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(wAddress / 8U), &pData[pDataIndex], aRxData, &wRxLength)); } else { /* If Last block of NDEF message is less than 8 bytes, write * byte by byte */ bLastBlock = 1; } } if(((pT1T->wNdefMsgAddr % 8U) != 0U) && (pT1T->wNdefMsgAddr == wAddress)) { /* If First block of NDEF message is not starting from start of a * block, write byte by byte. */ bFirstBlock = 1; } } else { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)wAddress, pData[pDataIndex], aRxData, &wRxLength)); /* Write Terminator TLV, if enabled and space is available */ if((pT1T->bTerminatorTlvPresence == PH_ON) && ((pDataIndex + 1U) == pDataParams->dwNdefLength)) { /* Loop is needed, if current byte address is Lock, Reserved Memory * or OTP. Loop till we find data byte. */ for(bIndex = ((uint8_t)(wAddress + 1U)); bIndex < ((pT1T->bTms + 1U) * 8U); bIndex++) { if(0u != (phalTop_Sw_Int_T1T_CheckLockReservedOtp(pT1T, bIndex))) { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, bIndex, 0xFE, aRxData, &wRxLength)); break; } } } } /* Write partially filled first block */ if(0U != (bFirstBlock)) { PH_CHECK_SUCCESS_FCT(status, phalT1T_ReadBlock( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(wAddress / 8U), aTempData, &wRxLength)); phMemCpy(&aTempData[(wAddress % 8U) + 1U], &pData[pDataIndex], (8U - (wAddress % 8U))); PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseBlock( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(wAddress / 8U), &aTempData[1], aRxData, &wRxLength)); } /* Write partially filled last block */ else if(0U != (bLastBlock)) { (void)memset(aTempData, 0, 8); phMemCpy(aTempData, &pData[pDataIndex], ((pDataParams->dwNdefLength) - pDataIndex)); /* Add terminator TLV, if enabled */ if(((pDataParams->dwNdefLength - pDataIndex) < 8U) && (pT1T->bTerminatorTlvPresence == PH_ON)) { aTempData[(pDataParams->dwNdefLength - pDataIndex)] = 0xFE; } PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseBlock( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(wAddress / 8U), aTempData, aRxData, &wRxLength)); /* Write terminator TLV, if enabled and space is available */ if(((pDataParams->dwNdefLength - pDataIndex) == 8U) && (pT1T->bTerminatorTlvPresence == PH_ON)) { (void)memset(aTempData, 0, 8); aTempData[0] = 0xFE; /* Loop is needed, if current byte address is Lock, Reserved Memory * or OTP. Loop till we find data byte. */ for(bIndex = ((uint8_t)((wAddress / 8U) + 1U)); (bIndex * 8U) < ((pT1T->bTms + 1U) * 8U); bIndex++) { if(0u != (phalTop_Sw_Int_T1T_CheckLockReservedOtp(pT1T, (((uint16_t)(bIndex)) * 8U)))) { PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseBlock( pT1T->pAlT1TDataParams, pT1T->bUid, bIndex, aTempData, aRxData, &wRxLength)); } } } } else { return PH_ERR_SUCCESS; /* Do Nothing */ } return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_ClearState( phalTop_Sw_DataParams_t * pDataParams, phalTop_T1T_t * pT1T ) { /* Reset parameters */ pT1T->bLockTlvCount = 0; pT1T->bRwa = 0; pT1T->bTms = 0; pDataParams->bVno = 0; pT1T->bMemoryTlvCount = 0; pT1T->bTagMemoryType = 0; pDataParams->bTagState = 0; pT1T->bTerminatorTlvPresence = 0; pDataParams->dwMaxNdefLength = 0; pT1T->wNdefHeaderAddr = 0; pDataParams->dwNdefLength = 0; pT1T->wNdefMsgAddr = 0; pT1T->sSegment.bAddress = 0; return PH_ERR_SUCCESS; } /* Finds the count and position of memory, lock and NDEF TLV */ phStatus_t phalTop_Sw_Int_T1T_DetectTlvBlocks( phalTop_Sw_DataParams_t * pDataParams, phalTop_T1T_t * pT1T ) { phStatus_t PH_MEMLOC_REM status; uint16_t PH_MEMLOC_COUNT wIndex; uint8_t PH_MEMLOC_REM bPageAddr; uint8_t PH_MEMLOC_REM bByteOffset; uint8_t PH_MEMLOC_REM bBytesPerPage; uint8_t PH_MEMLOC_BUF aLength[3]; uint8_t PH_MEMLOC_REM bExitLoop = 0; uint8_t PH_MEMLOC_BUF aData[1]; uint16_t PH_MEMLOC_REM wShift = 1; /* Check for NDEF TLV is done only in first segment */ wIndex = PHAL_TOP_T1T_SEGMENT_START_INDEX; /* Loop through first segment */ while(wIndex < PHAL_TOP_T1T_SEGMENT_END_INDEX) { PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, wIndex, aData, PH_OFF)); switch(aData[0]) { case PHAL_TOP_T1T_NULL_TLV: break; case PHAL_TOP_T1T_LOCK_CTRL_TLV: if(pT1T->bLockTlvCount >= PHAL_TOP_T1T_MAX_LOCK_CTRL_TLV) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_UNSUPPORTED_TAG, PH_COMP_AL_TOP); } if(pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC) { /* Read TLV length */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 1U), aData, PH_OFF)); /* Validate length */ if(aData[0] != 3U) { bExitLoop = 1; break; } pT1T->asLockCtrlTlv[pT1T->bLockTlvCount].wOffset = wIndex; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 2U), aData, PH_OFF)); bPageAddr = (uint8_t)((aData[0] & 0xF0U) >> 4U); bByteOffset = aData[0] & 0x0FU; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 3U), aData, PH_OFF)); pT1T->asLockCtrlTlv[pT1T->bLockTlvCount].bSizeInBits = aData[0]; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 4U), aData, PH_OFF)); bBytesPerPage = aData[0] & 0x0FU; pT1T->asLockCtrlTlv[pT1T->bLockTlvCount].bBytesPerPage = aData[0] & 0x0FU; pT1T->asLockCtrlTlv[pT1T->bLockTlvCount].bBytesLockedPerBit = (uint8_t)((aData[0] & 0xF0U) >> 4U); { uint16_t wPageAddr = 0; wPageAddr = bPageAddr; wShift = 1U; wPageAddr = (wPageAddr * (wShift << ((uint16_t)(bBytesPerPage)))); wPageAddr += bByteOffset; pT1T->asLockCtrlTlv[pT1T->bLockTlvCount].wByteAddr = wPageAddr; } pT1T->bLockTlvCount++; wIndex = wIndex + 4U; } break; case PHAL_TOP_T1T_MEMORY_CTRL_TLV: if(pT1T->bMemoryTlvCount >= PHAL_TOP_T1T_MAX_MEM_CTRL_TLV) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_UNSUPPORTED_TAG, PH_COMP_AL_TOP); } if(pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC) { /* Read TLV length */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 1U), aData, PH_OFF)); /* Validate length */ if(aData[0] != 3U) { bExitLoop = 1; break; } pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount].wOffset = wIndex; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 2U), aData, PH_OFF)); bPageAddr = (uint8_t)((aData[0] & 0xF0U) >> 4U); bByteOffset = (uint8_t)(aData[0] & 0x0FU); PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 3U), aData, PH_OFF)); pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount].bSizeInBytes = aData[0]; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 4U), aData, PH_OFF)); bBytesPerPage = aData[0] & 0x0FU; pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount].bBytesPerPage = aData[0] & 0x0FU; { uint16_t wByteAddress = 0; wShift = 1U; wByteAddress = (uint16_t)bPageAddr; wByteAddress = (wByteAddress * (wShift << ((uint16_t)(bBytesPerPage)))); wByteAddress = wByteAddress + bByteOffset; pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount].wByteAddr = wByteAddress; } pT1T->bMemoryTlvCount++; wIndex = wIndex + 4U; } break; case PHAL_TOP_T1T_NDEF_TLV: pT1T->wNdefHeaderAddr = wIndex; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 1U), aData, PH_OFF)); aLength[0] = aData[0]; if(aLength[0] == 0xFFU) { PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 2U), aData, PH_OFF)); aLength[1] = aData[0]; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 3U), aData, PH_OFF)); aLength[2] = aData[0]; pDataParams->dwNdefLength = ((uint16_t)aLength[1] << 8U) | aLength[2]; pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 4U; wIndex = wIndex + pDataParams->dwNdefLength + 3U; } else { pDataParams->dwNdefLength = aLength[0]; pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 2U; wIndex = wIndex + pDataParams->dwNdefLength + 1U; } bExitLoop = 1; break; case PHAL_TOP_T1T_PROPRIETARY_TLV: PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 1U), aData, PH_OFF)); aLength[0] = aData[0]; if(aLength[0] == 0xFFU) { PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 2U), aData, PH_OFF)); aLength[1] = aData[0]; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, (wIndex + 3U), aData, PH_OFF)); aLength[2] = aData[0]; wIndex = wIndex + (((uint16_t)aLength[1] << 8U) | aLength[2]) + 3U; } else { wIndex = wIndex + aLength[0] + 1U; } break; case PHAL_TOP_T1T_TERMINATOR_TLV: pT1T->bTerminatorTlvPresence = PH_ON; bExitLoop = 1; break; default: bExitLoop = 1; break; } if (0U != (bExitLoop)) { break; } wIndex++; } return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_CheckNdef( phalTop_Sw_DataParams_t * pDataParams, uint8_t * pTagState ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_REM aData[1] = {0}; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Update UID */ (void)memcpy(pT1T->bUid, ((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abUid, 4); /* Reset tag state */ *pTagState = PHAL_TOP_STATE_NONE; /* Clear values from previous detection, if any */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_ClearState(pDataParams, pT1T)); /* Check for NDEF support */ if((((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abHR[0] & 0x10U) != 0x10U) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_NON_NDEF_TAG, PH_COMP_AL_TOP); } /* Check for memory type */ if((((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abHR[0] & 0x01U) == 0x01U) { pT1T->bTagMemoryType = PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC; } else { pT1T->bTagMemoryType = PHAL_TOP_T1T_TAG_MEMORY_TYPE_DYNAMIC; } /* Read NDEF Magic Number (NMN) */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, PHAL_TOP_T1T_CC_NMN_ADDR, aData, PH_ON)); /* Validate NMN */ if(aData[0] != PHAL_TOP_T1T_NDEF_NMN) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_NON_NDEF_TAG, PH_COMP_AL_TOP); } /* Read version number */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, PHAL_TOP_T1T_CC_VNO_ADDR, aData, PH_OFF)); /* Update version */ pDataParams->bVno = aData[0]; /* Validate if version is supported */ if((uint8_t)(pDataParams->bVno & 0xF0U) > (uint8_t)(PHAL_TOP_T1T_NDEF_SUPPORTED_VNO & 0xF0U)) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_UNSUPPORTED_VERSION, PH_COMP_AL_TOP); } /* Read TMS */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, PHAL_TOP_T1T_CC_TMS_ADDR, aData, PH_OFF)); /* Update TMS */ pT1T->bTms = aData[0]; /* Validate TMS */ if(pT1T->bTms < 0x0EU) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_MISCONFIGURED_TAG, PH_COMP_AL_TOP); } /* Validate TMS and Tag Memory Type */ if(((pT1T->bTms == 0x0EU) && (pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC)) || ((pT1T->bTms > 0x0EU) && (pT1T->bTagMemoryType != PHAL_TOP_T1T_TAG_MEMORY_TYPE_DYNAMIC))) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_MISCONFIGURED_TAG, PH_COMP_AL_TOP); } /* Read R/W access */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, PHAL_TOP_T1T_CC_RWA_ADDR, aData, PH_OFF)); /* Update read/write access */ pT1T->bRwa = aData[0]; /* Validate read/write access */ if((pT1T->bRwa != PHAL_TOP_T1T_CC_RWA_RW) && (pT1T->bRwa != PHAL_TOP_T1T_CC_RWA_RO)) { /* RFU/Proprietary options; Not supported */ return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_UNSUPPORTED_TAG, PH_COMP_AL_TOP); } /* Detect TLVs */ PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_DetectTlvBlocks(pDataParams, pT1T)); if((pT1T->wNdefHeaderAddr != 0U) && (pDataParams->dwNdefLength != 0U)) { if(pT1T->bRwa == PHAL_TOP_T1T_CC_RWA_RW) { pDataParams->bTagState = PHAL_TOP_STATE_READWRITE; } else { /* NOTE: Lock bytes status are not checked. */ pDataParams->bTagState = PHAL_TOP_STATE_READONLY; } } else { /* If dynamic memory; check for lock and memory TLVs */ if((pT1T->bTagMemoryType == PHAL_TOP_T1T_TAG_MEMORY_TYPE_DYNAMIC) && ((pT1T->bLockTlvCount == 0U) || (pT1T->bMemoryTlvCount == 0U))) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_MISCONFIGURED_TAG, PH_COMP_AL_TOP); } pDataParams->bTagState = PHAL_TOP_STATE_INITIALIZED; } /* Update max. NDEF size */ phalTop_Sw_Int_T1T_CalculateMaxNdefSize(pDataParams, pT1T); /* Update reserved/lock bytes status for first sector */ pT1T->sSegment.bAddress = 0; PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T)); /* Update state in out parameter */ *pTagState = pDataParams->bTagState; return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_FormatNdef( phalTop_Sw_DataParams_t * pDataParams ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_BUF aRxData[11]; uint16_t PH_MEMLOC_REM wRxLength = 0; uint16_t PH_MEMLOC_COUNT wIndex; uint16_t PH_MEMLOC_COUNT wWriteIndex; uint8_t PH_MEMLOC_BUF aTlv[5]; uint8_t PH_MEMLOC_BUF aNdefData[3] = {0xD0, 0x00, 0x00}; uint16_t PH_MEMLOC_BUF wShift = 1; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Check for NDEF support */ if((((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abHR[0] & 0x10U) != 0x10U) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_UNSUPPORTED_TAG, PH_COMP_AL_TOP); } /* Check for NDEF presence */ if(pDataParams->bTagState != PHAL_TOP_STATE_NONE) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_FORMATTED_TAG, PH_COMP_AL_TOP); } /* If TMS is not configured, use default configuration */ if(pT1T->bTms < 0x0EU) { /* Check for memory type */ if((((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abHR[0] & 0x01U) == 0x01U) { /* Topaz96 */ pT1T->bTms = 0x0E; } else { /* Topaz512 */ pT1T->bTms = 0x3F; } } /* Set R/W access */ pT1T->bRwa = PHAL_TOP_T1T_CC_RWA_RW; /* Set version number */ pDataParams->bVno = PHAL_TOP_T1T_NDEF_SUPPORTED_VNO; /* Write NDEF Magic Number */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_NMN, PHAL_TOP_T1T_NDEF_NMN, aRxData, &wRxLength)); /* Write NDEF version number */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_VNO, pDataParams->bVno, aRxData, &wRxLength)); /* Write TMS byte*/ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_TMS, pT1T->bTms, aRxData, &wRxLength)); /* Write Read/Write access byte*/ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_RWA, pT1T->bRwa, aRxData, &wRxLength)); /* Update memory type */ if((((phalT1T_Sw_DataParams_t *)(pT1T->pAlT1TDataParams))->abHR[0] & 0x01U) == 0x01U) { pT1T->bTagMemoryType = PHAL_TOP_T1T_TAG_MEMORY_TYPE_STATIC; } else { pT1T->bTagMemoryType = PHAL_TOP_T1T_TAG_MEMORY_TYPE_DYNAMIC; /* Update default Lock control TLVs (for Topaz512) */ if(pT1T->bLockTlvCount == 0U) { /* Update Lock TLVs (default for Topaz512) */ pT1T->bLockTlvCount = 1; pT1T->asLockCtrlTlv[0].wOffset = 0x0C; pT1T->asLockCtrlTlv[0].wByteAddr = 0x7A; pT1T->asLockCtrlTlv[0].bBytesLockedPerBit = 0x03; pT1T->asLockCtrlTlv[0].bBytesPerPage = 0x03; pT1T->asLockCtrlTlv[0].bSizeInBits = 0x30; } /* Update Memory control TLVs (for Topaz512) */ if(pT1T->bMemoryTlvCount == 0U) { /* Update Memory TLVs (default for Topaz512) */ pT1T->bMemoryTlvCount = 1; pT1T->asMemCtrlTlv[0].wOffset = 0x11; pT1T->asMemCtrlTlv[0].wByteAddr = 0x78; pT1T->asMemCtrlTlv[0].bBytesPerPage = 0x03; pT1T->asMemCtrlTlv[0].bSizeInBytes = 0x02; } } /* Write lock control TLVs */ for(wIndex = 0; ((wIndex < pT1T->bLockTlvCount) && (wIndex < PHAL_TOP_T1T_MAX_LOCK_CTRL_TLV)); wIndex++) { /* Create lock TLVs */ aTlv[0] = 0x01; aTlv[1] = 0x03; { uint16_t wBytesPage = 0; wShift = 1U; wBytesPage = (wShift << ((uint16_t)(pT1T->asLockCtrlTlv[wIndex].bBytesPerPage))); aTlv[2] = (uint8_t)((uint16_t)(pT1T->asLockCtrlTlv[wIndex].wByteAddr / wBytesPage) << 4U) | (uint8_t)(pT1T->asLockCtrlTlv[wIndex].wByteAddr % wBytesPage); } aTlv[3] = pT1T->asLockCtrlTlv[wIndex].bSizeInBits; aTlv[4] = (pT1T->asLockCtrlTlv[wIndex].bBytesLockedPerBit << 4U) | pT1T->asLockCtrlTlv[wIndex].bBytesPerPage; /* Write lock TLVs */ for(wWriteIndex = 0; wWriteIndex < 5U; wWriteIndex++) { /* Write byte */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->asLockCtrlTlv[wIndex].wOffset + wWriteIndex), aTlv[wWriteIndex], aRxData, &wRxLength)); } } /* Write memory control TLVs */ for(wIndex = 0; ((wIndex < pT1T->bMemoryTlvCount) && (wIndex < PHAL_TOP_T1T_MAX_MEM_CTRL_TLV)); wIndex++) { /* Create memory TLV */ aTlv[0] = 0x02; aTlv[1] = 0x03; { uint16_t wBytesPerPage = 0; wShift = 1U; wBytesPerPage = (wShift << ((uint16_t)(pT1T->asMemCtrlTlv[wIndex].bBytesPerPage))); aTlv[2] = (uint8_t)((uint16_t)(pT1T->asMemCtrlTlv[wIndex].wByteAddr / wBytesPerPage) << 4U) | (uint8_t)(pT1T->asMemCtrlTlv[wIndex].wByteAddr % wBytesPerPage); } aTlv[3] = pT1T->asMemCtrlTlv[wIndex].bSizeInBytes; aTlv[4] = pT1T->asMemCtrlTlv[wIndex].bBytesPerPage; /* Write memory TLV */ for(wWriteIndex = 0; wWriteIndex < 5U; wWriteIndex++) { /* Write byte */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->asMemCtrlTlv[wIndex].wOffset + wWriteIndex), aTlv[wWriteIndex], aRxData, &wRxLength)); } } /* Calculate NDEF header address */ if((pT1T->bLockTlvCount !=0U) && (pT1T->bMemoryTlvCount != 0U)) { pT1T->wNdefHeaderAddr = ((pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset > pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset) ? pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset : pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset) + 5U; } else if(pT1T->bLockTlvCount != 0U) { pT1T->wNdefHeaderAddr = pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset + 5U; } else if(pT1T->bMemoryTlvCount != 0U) { pT1T->wNdefHeaderAddr = pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset + 5U; } else { pT1T->wNdefHeaderAddr = 12; } pDataParams->dwNdefLength = 0; pDataParams->bTagState = PHAL_TOP_STATE_INITIALIZED; /* Update max. NDEF size */ phalTop_Sw_Int_T1T_CalculateMaxNdefSize(pDataParams, pT1T); /* Write empty NDEF Message */ status = phalTop_Sw_Int_T1T_WriteNdef(pDataParams, aNdefData, 3); if((status & PH_ERR_MASK) != PH_ERR_SUCCESS) { /* Reset state on error */ pDataParams->bTagState = PHAL_TOP_STATE_NONE; pT1T->wNdefHeaderAddr = 0x00; return status; } /* Update state and NDEF presence */ pDataParams->bTagState = PHAL_TOP_STATE_READWRITE; pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 2U; pDataParams->dwNdefLength = 0x03; return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_EraseNdef( phalTop_Sw_DataParams_t * pDataParams ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_REM aRxData[11]; uint16_t PH_MEMLOC_REM wRxLength = 0; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Check if tag is in valid state */ if(pDataParams->bTagState == PHAL_TOP_STATE_NONE) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_INVALID_STATE, PH_COMP_AL_TOP); } /* Check if tag is read-only */ if(pDataParams->bTagState == PHAL_TOP_STATE_READONLY) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_READONLY_TAG, PH_COMP_AL_TOP); } /* Check if tag is already in initialized state */ if(pDataParams->bTagState == PHAL_TOP_STATE_INITIALIZED) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_EMPTY_NDEF, PH_COMP_AL_TOP); } /* Make NDEF length '0' */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->wNdefHeaderAddr + 1U), 0x00, aRxData, &wRxLength)); /* Update state */ pDataParams->bTagState = PHAL_TOP_STATE_INITIALIZED; pDataParams->dwNdefLength = 0; pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 2U; return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_ReadNdef( phalTop_Sw_DataParams_t * pDataParams, uint8_t * pData, uint32_t * pLength ) { phStatus_t PH_MEMLOC_REM status; uint16_t PH_MEMLOC_COUNT wIndex; uint16_t PH_MEMLOC_COUNT wTempIndex; uint8_t PH_MEMLOC_BUF aData[1]; uint8_t PH_MEMLOC_REM bFreshRead; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Reset NDEF length */ *pLength = 0; /* Check if tag is in valid state */ if(pDataParams->bTagState == PHAL_TOP_STATE_NONE) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_INVALID_STATE, PH_COMP_AL_TOP); } /* Check for NDEF length > 0 (in initialized state NDEF length is 0) */ if(pDataParams->bTagState == PHAL_TOP_STATE_INITIALIZED) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_EMPTY_NDEF, PH_COMP_AL_TOP); } /* Buffer allocated by user is less than NDEF message size on Tag. */ if (pDataParams->dwNdefLength > PH_NXPNFCRDLIB_CONFIG_MAX_NDEF_DATA) { return PH_ADD_COMPCODE_FIXED(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_TOP); } pT1T->sSegment.bAddress = (uint8_t)(pT1T->wNdefMsgAddr / PHAL_TOP_T1T_SEGMENT_SIZE); PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T)); /* Do a fresh read of segment for one time */ bFreshRead = PH_ON; wIndex = pT1T->wNdefMsgAddr; wTempIndex = 0; while(wTempIndex < pDataParams->dwNdefLength) { if(((wIndex / PHAL_TOP_T1T_SEGMENT_SIZE) != pT1T->sSegment.bAddress)) { pT1T->sSegment.bAddress = (uint8_t)(wIndex / PHAL_TOP_T1T_SEGMENT_SIZE); PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T)); /* Do a fresh read of segment for one time */ bFreshRead = PH_ON; } if(0u != (phalTop_Sw_Int_T1T_CheckLockReservedOtp(pT1T, wIndex))) { PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Read( pT1T, wIndex, aData, bFreshRead)); bFreshRead = PH_OFF; pData[wTempIndex] = aData[0]; wTempIndex++; } wIndex++; } /* Update NDEF length */ *pLength = pDataParams->dwNdefLength; return PH_ERR_SUCCESS; } phStatus_t phalTop_Sw_Int_T1T_WriteNdef( phalTop_Sw_DataParams_t * pDataParams, uint8_t * pData, uint32_t dwLength ) { phStatus_t PH_MEMLOC_REM status; uint8_t PH_MEMLOC_BUF aRxData[11]; uint16_t PH_MEMLOC_REM wRxLength = 0; uint16_t PH_MEMLOC_COUNT wIndex; uint32_t PH_MEMLOC_COUNT wTempIndex; phalTop_T1T_t PH_MEMLOC_REM * pT1T = &pDataParams->ualTop.salTop_T1T; if((pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]) != NULL) { pT1T->pAlT1TDataParams = pDataParams->pTopTagsDataParams[pDataParams->bTagType - 1U]; } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_AL_TOP); } /* Check if tag is in valid state */ if(pDataParams->bTagState == PHAL_TOP_STATE_NONE) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_INVALID_STATE, PH_COMP_AL_TOP); } /* Check if tag is read-only */ if(pDataParams->bTagState == PHAL_TOP_STATE_READONLY) { return PH_ADD_COMPCODE_FIXED(PHAL_TOP_ERR_READONLY_TAG, PH_COMP_AL_TOP); } /* Check NDEF length */ if((dwLength > pDataParams->dwMaxNdefLength) || (dwLength == 0U)) { return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_TOP); } /* Make NDEF Magic Number value '0' */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_NMN, 0x00, aRxData, &wRxLength)); /* Write NDEF version number */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_VNO, PHAL_TOP_T1T_NDEF_SUPPORTED_VNO, aRxData, &wRxLength)); /* Write Read/Write access byte*/ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_RWA, pT1T->bRwa, aRxData, &wRxLength)); /* Calculate NDEF Header Address */ if((pT1T->bLockTlvCount !=0U) && (pT1T->bMemoryTlvCount != 0U)) { pT1T->wNdefHeaderAddr = ((pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset > pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset)? (pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset): ((pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset) + 5U)); } else if(pT1T->bLockTlvCount !=0U) { pT1T->wNdefHeaderAddr = pT1T->asLockCtrlTlv[pT1T->bLockTlvCount - 1U].wOffset + 5U; } else if(pT1T->bMemoryTlvCount != 0U) { pT1T->wNdefHeaderAddr = pT1T->asMemCtrlTlv[pT1T->bMemoryTlvCount - 1U].wOffset + 5U; } else { pT1T->wNdefHeaderAddr = 12; } /* Write NDEF TLV */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)pT1T->wNdefHeaderAddr, PHAL_TOP_T1T_NDEF_TLV, aRxData, &wRxLength)); /* Write NDEF length */ if(dwLength > 0xFEU) { pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 4U; PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->wNdefHeaderAddr + 1U), 0xFF, aRxData, &wRxLength)); PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->wNdefHeaderAddr + 2U), (uint8_t)(dwLength >> 8U), aRxData, &wRxLength)); PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->wNdefHeaderAddr + 3U), (uint8_t)dwLength, aRxData, &wRxLength)); } else { pT1T->wNdefMsgAddr = pT1T->wNdefHeaderAddr + 2U; PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, (uint8_t)(pT1T->wNdefHeaderAddr + 1U), (uint8_t)dwLength, aRxData, &wRxLength)); } /* Update NDEF Length */ pDataParams->dwNdefLength = dwLength; /* Update Lock/Reserved/OTP presence */ pT1T->sSegment.bAddress = (uint8_t)(pT1T->wNdefMsgAddr / PHAL_TOP_T1T_SEGMENT_SIZE); PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T)); /* Write NDEF data */ wIndex = pT1T->wNdefMsgAddr; wTempIndex = 0; while(wTempIndex < (pDataParams->dwNdefLength)) { if((wIndex/PHAL_TOP_T1T_SEGMENT_SIZE) != pT1T->sSegment.bAddress) { pT1T->sSegment.bAddress = (uint8_t)(wIndex / PHAL_TOP_T1T_SEGMENT_SIZE); PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_UpdateLockReservedOtp(pT1T)); } if(0u != (phalTop_Sw_Int_T1T_CheckLockReservedOtp(pT1T, wIndex))) { PH_CHECK_SUCCESS_FCT(status, phalTop_Sw_Int_T1T_Write( pDataParams, pT1T, wIndex, pData, (uint16_t)wTempIndex)); wTempIndex++; } wIndex++; } /* Write NDEF Magic Number */ PH_CHECK_SUCCESS_FCT(status, phalT1T_WriteEraseByte( pT1T->pAlT1TDataParams, pT1T->bUid, PHAL_TOP_T1T_BLOCK_NMN, PHAL_TOP_T1T_NDEF_NMN, aRxData, &wRxLength)); pDataParams->bTagState = PHAL_TOP_STATE_READWRITE; return PH_ERR_SUCCESS; } static void phMemCpy(void* dest, void* src, uint16_t wLength) { uint32_t dwLength = 0; dwLength = wLength; (void)memcpy(dest, src, dwLength); } #endif /* NXPBUILD__PHAL_TOP_T1T_SW */ #endif /* NXPBUILD__PHAL_TOP_SW */