/* * Copyright 2010-2021 NXP * * 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. */ /* * Internal Download Management routines * Download Component */ #include #include #include #include #include /* Minimum length of payload including 1 byte CmdId */ #define PHDNLDNFC_MIN_PLD_LEN (0x04U) /* Offset of Length byte within the frame */ #define PHDNLDNFC_FRAME_HDR_OFFSET (0x00) /* Offset of FrameId within the frame */ #define PHDNLDNFC_FRAMEID_OFFSET (PHDNLDNFC_FRAME_HDR_LEN) /* Offset of status byte within the frame */ #define PHDNLDNFC_FRAMESTATUS_OFFSET PHDNLDNFC_FRAMEID_OFFSET /* Offset within frame where payload starts*/ #define PHDNLDNFC_PLD_OFFSET (PHDNLDNFC_MIN_PLD_LEN - 1) #define PHDNLDNFC_FRAME_RDDATA_OFFSET \ ((PHDNLDNFC_FRAME_HDR_LEN) + \ (PHDNLDNFC_MIN_PLD_LEN)) /* recvd frame offset where data starts */ /* Size of first secure write frame Signature */ #define PHDNLDNFC_FRAME_SIGNATURE_SIZE (0xC0U) /* Size of first secure write frame payload */ #define PHDNLDNFC_FIRST_FRAME_PLD_SIZE (0xE4U) /* Status response for first fragmented write frame */ #define PHDNLDNFC_FIRST_FRAGFRAME_RESP (0x2DU) /* Status response for subsequent fragmented write frame */ #define PHDNLDNFC_NEXT_FRAGFRAME_RESP (0x2EU) #define PHDNLDNFC_SET_HDR_FRAGBIT(n) \ ((n) | (1 << 10)) /* Header chunk bit set macro */ #define PHDNLDNFC_CLR_HDR_FRAGBIT(n) \ ((n) & ~(1U << 10)) /* Header chunk bit clear macro */ #define PHDNLDNFC_SET_HDR_FRAGBIT_SN220(n) \ ((n) | (1 << 13)) /* Header chunk bit set macro */ #define PHDNLDNFC_CLR_HDR_FRAGBIT_SN220(n) \ ((n) & ~(1U << 13)) /* Header chunk bit clear macro */ #define PHDNLDNFC_CHK_HDR_FRAGBIT(n) \ ((n)&0x04) /* macro to check if frag bit is set in Hdr */ /* Timeout value to wait before resending the last frame */ #define PHDNLDNFC_RETRY_FRAME_WRITE (50) /* size of EEPROM user data length */ #define PHDNLDNFC_USERDATA_EEPROM_LENSIZE (0x02U) /* size of EEPROM offset */ #define PHDNLDNFC_USERDATA_EEPROM_OFFSIZE (0x02U) #define PH_LIBNFC_VEN_RESET_ON_DOWNLOAD_TIMEOUT (1) /* Function prototype declarations */ static void phDnldNfc_ProcessSeqState(void* pContext, phTmlNfc_TransactInfo_t* pInfo); static void phDnldNfc_ProcessRWSeqState(void* pContext, phTmlNfc_TransactInfo_t* pInfo); static NFCSTATUS phDnldNfc_ProcessFrame(void* pContext, phTmlNfc_TransactInfo_t* pInfo); static NFCSTATUS phDnldNfc_ProcessRecvInfo(void* pContext, phTmlNfc_TransactInfo_t* pInfo); static NFCSTATUS phDnldNfc_BuildFramePkt(pphDnldNfc_DlContext_t pDlContext); static NFCSTATUS phDnldNfc_CreateFramePld(pphDnldNfc_DlContext_t pDlContext); static NFCSTATUS phDnldNfc_SetupResendTimer(pphDnldNfc_DlContext_t pDlContext); static NFCSTATUS phDnldNfc_UpdateRsp(pphDnldNfc_DlContext_t pDlContext, phTmlNfc_TransactInfo_t* pInfo, uint16_t wPldLen); static void phDnldNfc_RspTimeOutCb(uint32_t TimerId, void* pContext); static void phDnldNfc_ResendTimeOutCb(uint32_t TimerId, void* pContext); /* *************************** Function Definitions *************************** */ /******************************************************************************* ** ** Function phDnldNfc_CmdHandler ** ** Description Download Command Handler Mechanism ** - holds the sub states for each command processing ** - coordinates with TML download thread to complete a ** download command request ** - calls the user callback on completion of a cmd ** ** Parameters pContext - pointer to the download context structure ** TrigEvent - event requested by user ** ** Returns NFC status: ** NFCSTATUS_PENDING - download request sent to NFCC ** successfully,response pending ** NFCSTATUS_BUSY - handler is busy processing a download ** request ** NFCSTATUS_INVALID_PARAMETER - one or more of the supplied ** parameters could not be ** interpreted properly ** Other errors ** *******************************************************************************/ NFCSTATUS phDnldNfc_CmdHandler(void* pContext, phDnldNfc_Event_t TrigEvent) { NFCSTATUS status = NFCSTATUS_SUCCESS; pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if (NULL == pDlCtxt) { NXPLOG_FWDNLD_E("Invalid Input Parameter!!"); status = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { switch (TrigEvent) { case phDnldNfc_EventReset: case phDnldNfc_EventGetVer: case phDnldNfc_EventIntegChk: case phDnldNfc_EventGetSesnSt: case phDnldNfc_EventRaw: { if (phDnldNfc_EventInvalid == (pDlCtxt->tCurrEvent)) { NXPLOG_FWDNLD_D("Processing Normal Sequence.."); pDlCtxt->tCurrEvent = TrigEvent; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionBusy; phDnldNfc_ProcessSeqState(pDlCtxt, NULL); status = pDlCtxt->wCmdSendStatus; } else { NXPLOG_FWDNLD_E("Prev Norml Sequence not completed/restored!!"); status = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } break; } case phDnldNfc_EventWrite: case phDnldNfc_EventRead: case phDnldNfc_EventLog: case phDnldNfc_EventForce: { if (phDnldNfc_EventInvalid == (pDlCtxt->tCurrEvent)) { NXPLOG_FWDNLD_D("Processing R/W Sequence.."); pDlCtxt->tCurrEvent = TrigEvent; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionBusy; phDnldNfc_ProcessRWSeqState(pDlCtxt, NULL); status = pDlCtxt->wCmdSendStatus; } else { NXPLOG_FWDNLD_E("Prev R/W Sequence not completed/restored!!"); status = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } break; } default: { /* Unknown Event */ NXPLOG_FWDNLD_E("Unknown Event Parameter!!"); status = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); break; } } } return status; } /******************************************************************************* ** ** Function phDnldNfc_ProcessSeqState ** ** Description Processes all cmd/resp sequences except read & write ** ** Parameters pContext - pointer to the download context structure ** pInfo - pointer to the Transaction buffer updated by TML ** Thread ** ** Returns None ** *******************************************************************************/ static void phDnldNfc_ProcessSeqState(void* pContext, phTmlNfc_TransactInfo_t* pInfo) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; NFCSTATUS wIntStatus; uint32_t TimerId; pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if (NULL == pDlCtxt) { NXPLOG_FWDNLD_E("Invalid Input Parameter!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { switch (pDlCtxt->tCurrState) { case phDnldNfc_StateInit: { NXPLOG_FWDNLD_D("Initializing Sequence.."); if (0 == (pDlCtxt->TimerInfo.dwRspTimerId)) { TimerId = phOsalNfc_Timer_Create(); if (0 == TimerId) { NXPLOG_FWDNLD_W("Response Timer Create failed!!"); wStatus = NFCSTATUS_INSUFFICIENT_RESOURCES; pDlCtxt->wCmdSendStatus = wStatus; break; } else { NXPLOG_FWDNLD_D("Response Timer Created Successfully"); (pDlCtxt->TimerInfo.dwRspTimerId) = TimerId; (pDlCtxt->TimerInfo.TimerStatus) = 0; (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; } } pDlCtxt->tCurrState = phDnldNfc_StateSend; } [[fallthrough]]; case phDnldNfc_StateSend: { wStatus = phDnldNfc_BuildFramePkt(pDlCtxt); if (NFCSTATUS_SUCCESS == wStatus) { pDlCtxt->tCurrState = phDnldNfc_StateRecv; phTmlNfc_Read( pDlCtxt->tCmdRspFrameInfo.aFrameBuff, (uint16_t)PHDNLDNFC_CMDRESP_MAX_BUFF_SIZE, (pphTmlNfc_TransactCompletionCb_t)&phDnldNfc_ProcessSeqState, (void*)pDlCtxt); wStatus = phTmlNfc_Write( (pDlCtxt->tCmdRspFrameInfo.aFrameBuff), (uint16_t)(pDlCtxt->tCmdRspFrameInfo.dwSendlength), (pphTmlNfc_TransactCompletionCb_t)&phDnldNfc_ProcessSeqState, pDlCtxt); } pDlCtxt->wCmdSendStatus = wStatus; break; } case phDnldNfc_StateRecv: { wStatus = phDnldNfc_ProcessRecvInfo(pContext, pInfo); if (NFCSTATUS_SUCCESS == wStatus) { wStatus = phOsalNfc_Timer_Start((pDlCtxt->TimerInfo.dwRspTimerId), pDlCtxt->TimerInfo.rspTimeout, &phDnldNfc_RspTimeOutCb, pDlCtxt); if (NFCSTATUS_SUCCESS == wStatus) { NXPLOG_FWDNLD_D("Response timer started"); pDlCtxt->TimerInfo.TimerStatus = 1; pDlCtxt->tCurrState = phDnldNfc_StateTimer; } else { NXPLOG_FWDNLD_W("Response timer not started"); pDlCtxt->tCurrState = phDnldNfc_StateResponse; } /* set read status to pDlCtxt->wCmdSendStatus to enable callback */ pDlCtxt->wCmdSendStatus = wStatus; break; } else { /* Setting TimerExpStatus below to avoid frame processing in response * state */ (pDlCtxt->TimerInfo.wTimerExpStatus) = NFCSTATUS_RF_TIMEOUT; pDlCtxt->tCurrState = phDnldNfc_StateResponse; } } [[fallthrough]]; case phDnldNfc_StateTimer: { if (1 == (pDlCtxt->TimerInfo.TimerStatus)) /*Is Timer Running*/ { /*Stop Timer*/ (void)phOsalNfc_Timer_Stop(pDlCtxt->TimerInfo.dwRspTimerId); (pDlCtxt->TimerInfo.TimerStatus) = 0; /*timer stopped*/ } pDlCtxt->tCurrState = phDnldNfc_StateResponse; } [[fallthrough]]; case phDnldNfc_StateResponse: { if (NFCSTATUS_RF_TIMEOUT != (pDlCtxt->TimerInfo.wTimerExpStatus)) { /* Process response */ wStatus = phDnldNfc_ProcessFrame(pContext, pInfo); } else { if (phDnldNfc_EventReset != pDlCtxt->tCurrEvent) { wStatus = (pDlCtxt->TimerInfo.wTimerExpStatus); } else { wStatus = NFCSTATUS_SUCCESS; } (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; } /* Abort TML read operation which is always kept open */ wIntStatus = phTmlNfc_ReadAbort(); if (NFCSTATUS_SUCCESS != wIntStatus) { /* TODO:-Action to take in this case:-Tml read abort failed!? */ NXPLOG_FWDNLD_W("Tml Read Abort failed!!"); } pDlCtxt->tCurrEvent = phDnldNfc_EventInvalid; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionIdle; pDlCtxt->tCurrState = phDnldNfc_StateInit; /* Delete the timer & reset timer primitives in context */ (void)phOsalNfc_Timer_Delete(pDlCtxt->TimerInfo.dwRspTimerId); (pDlCtxt->TimerInfo.dwRspTimerId) = 0; (pDlCtxt->TimerInfo.TimerStatus) = 0; (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; if ((NULL != (pDlCtxt->UserCb)) && (NULL != (pDlCtxt->UserCtxt))) { pDlCtxt->UserCb((pDlCtxt->UserCtxt), wStatus, &(pDlCtxt->tRspBuffInfo)); } break; } default: { pDlCtxt->tCurrEvent = phDnldNfc_EventInvalid; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionIdle; break; } } } return; } /******************************************************************************* ** ** Function phDnldNfc_ProcessRWSeqState ** ** Description Processes read/write cmd/rsp sequence ** ** Parameters pContext - pointer to the download context structure ** pInfo - pointer to the Transaction buffer updated by TML ** Thread ** ** Returns None ** *******************************************************************************/ static void phDnldNfc_ProcessRWSeqState(void* pContext, phTmlNfc_TransactInfo_t* pInfo) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; NFCSTATUS wIntStatus = wStatus; uint32_t TimerId; pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if (NULL == pDlCtxt) { NXPLOG_FWDNLD_E("Invalid Input Parameter!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { switch (pDlCtxt->tCurrState) { case phDnldNfc_StateInit: { if (0 == (pDlCtxt->TimerInfo.dwRspTimerId)) { TimerId = phOsalNfc_Timer_Create(); if (0 == TimerId) { NXPLOG_FWDNLD_E("Response Timer Create failed!!"); wStatus = NFCSTATUS_INSUFFICIENT_RESOURCES; } else { NXPLOG_FWDNLD_D("Response Timer Created Successfully"); (pDlCtxt->TimerInfo.dwRspTimerId) = TimerId; (pDlCtxt->TimerInfo.TimerStatus) = 0; (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; } } pDlCtxt->tCurrState = phDnldNfc_StateSend; } [[fallthrough]]; case phDnldNfc_StateSend: { if (pDlCtxt->bResendLastFrame == false) { wStatus = phDnldNfc_BuildFramePkt(pDlCtxt); } else { pDlCtxt->bResendLastFrame = false; } if (NFCSTATUS_SUCCESS == wStatus) { pDlCtxt->tCurrState = phDnldNfc_StateRecv; wStatus = phTmlNfc_Write( (pDlCtxt->tCmdRspFrameInfo.aFrameBuff), (uint16_t)(pDlCtxt->tCmdRspFrameInfo.dwSendlength), (pphTmlNfc_TransactCompletionCb_t)&phDnldNfc_ProcessRWSeqState, pDlCtxt); } pDlCtxt->wCmdSendStatus = wStatus; break; } case phDnldNfc_StateRecv: { wStatus = phDnldNfc_ProcessRecvInfo(pContext, pInfo); if (NFCSTATUS_SUCCESS == wStatus) { /* processing For Pipelined write before calling timer below */ wStatus = phOsalNfc_Timer_Start((pDlCtxt->TimerInfo.dwRspTimerId), pDlCtxt->TimerInfo.rspTimeout, &phDnldNfc_RspTimeOutCb, pDlCtxt); if (NFCSTATUS_SUCCESS == wStatus) { NXPLOG_FWDNLD_D("Response timer started"); pDlCtxt->TimerInfo.TimerStatus = 1; pDlCtxt->tCurrState = phDnldNfc_StateTimer; } else { NXPLOG_FWDNLD_W("Response timer not started"); pDlCtxt->tCurrState = phDnldNfc_StateResponse; /* Todo:- diagnostic in this case */ } /* Call TML_Read function and register the call back function */ wStatus = phTmlNfc_Read( pDlCtxt->tCmdRspFrameInfo.aFrameBuff, (uint16_t)PHDNLDNFC_CMDRESP_MAX_BUFF_SIZE, (pphTmlNfc_TransactCompletionCb_t)&phDnldNfc_ProcessRWSeqState, (void*)pDlCtxt); /* set read status to pDlCtxt->wCmdSendStatus to enable callback */ pDlCtxt->wCmdSendStatus = wStatus; break; } else { /* Setting TimerExpStatus below to avoid frame processing in response * state */ (pDlCtxt->TimerInfo.wTimerExpStatus) = NFCSTATUS_RF_TIMEOUT; pDlCtxt->tCurrState = phDnldNfc_StateResponse; } } [[fallthrough]]; case phDnldNfc_StateTimer: { if (1 == (pDlCtxt->TimerInfo.TimerStatus)) /*Is Timer Running*/ { /* Stop Timer */ (void)phOsalNfc_Timer_Stop(pDlCtxt->TimerInfo.dwRspTimerId); (pDlCtxt->TimerInfo.TimerStatus) = 0; /*timer stopped*/ } pDlCtxt->tCurrState = phDnldNfc_StateResponse; } [[fallthrough]]; case phDnldNfc_StateResponse: { if (NFCSTATUS_RF_TIMEOUT != (pDlCtxt->TimerInfo.wTimerExpStatus)) { /* Process response */ wStatus = phDnldNfc_ProcessFrame(pContext, pInfo); if (NFCSTATUS_BUSY == wStatus) { /* store the status for use in subsequent processing */ wIntStatus = wStatus; /* setup the resend wait timer */ wStatus = phDnldNfc_SetupResendTimer(pDlCtxt); if (NFCSTATUS_SUCCESS == wStatus) { /* restore the last mem_bsy status to avoid re-building frame * below */ wStatus = wIntStatus; } } } else { wStatus = (pDlCtxt->TimerInfo.wTimerExpStatus); (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; } if ((0 != (pDlCtxt->tRWInfo.wRemBytes)) && (NFCSTATUS_SUCCESS == wStatus)) { /* Abort TML read operation which is always kept open */ wIntStatus = phTmlNfc_ReadAbort(); if (NFCSTATUS_SUCCESS != wIntStatus) { NXPLOG_FWDNLD_W("Tml read abort failed!"); } wStatus = phDnldNfc_BuildFramePkt(pDlCtxt); if (NFCSTATUS_SUCCESS == wStatus) { pDlCtxt->tCurrState = phDnldNfc_StateRecv; wStatus = phTmlNfc_Write( (pDlCtxt->tCmdRspFrameInfo.aFrameBuff), (uint16_t)(pDlCtxt->tCmdRspFrameInfo.dwSendlength), (pphTmlNfc_TransactCompletionCb_t)&phDnldNfc_ProcessRWSeqState, pDlCtxt); /* TODO:- Verify here if TML_Write returned NFC_PENDING status & take appropriate action otherwise ?? */ } } else if (NFCSTATUS_BUSY == wStatus) { /* No processing to be done,since resend wait timer should have * already been started */ } else { (pDlCtxt->tRWInfo.bFramesSegmented) = false; /* Abort TML read operation which is always kept open */ wIntStatus = phTmlNfc_ReadAbort(); if (NFCSTATUS_SUCCESS != wIntStatus) { NXPLOG_FWDNLD_W("Tml read abort failed!"); } pDlCtxt->tCurrEvent = phDnldNfc_EventInvalid; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionIdle; pDlCtxt->tCurrState = phDnldNfc_StateInit; pDlCtxt->bResendLastFrame = false; /* Delete the timer & reset timer primitives in context */ (void)phOsalNfc_Timer_Delete(pDlCtxt->TimerInfo.dwRspTimerId); (pDlCtxt->TimerInfo.dwRspTimerId) = 0; (pDlCtxt->TimerInfo.TimerStatus) = 0; (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; if ((NULL != (pDlCtxt->UserCb)) && (NULL != (pDlCtxt->UserCtxt))) { pDlCtxt->UserCb((pDlCtxt->UserCtxt), wStatus, &(pDlCtxt->tRspBuffInfo)); } } break; } default: { pDlCtxt->tCurrEvent = phDnldNfc_EventInvalid; pDlCtxt->tDnldInProgress = phDnldNfc_TransitionIdle; break; } } } return; } /******************************************************************************* ** ** Function phDnldNfc_BuildFramePkt ** ** Description Forms the frame packet ** ** Parameters pDlContext - pointer to the download context structure ** ** Returns NFC status ** *******************************************************************************/ static NFCSTATUS phDnldNfc_BuildFramePkt(pphDnldNfc_DlContext_t pDlContext) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; uint16_t wFrameLen = 0; uint16_t wCrcVal; uint8_t* pFrameByte; if (NULL == pDlContext) { NXPLOG_FWDNLD_E("Invalid Input Parameter!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { if (phDnldNfc_FTWrite == (pDlContext->FrameInp.Type)) { if ((0 == (pDlContext->tUserData.wLen)) || (NULL == (pDlContext->tUserData.pBuff))) { NXPLOG_FWDNLD_E("Invalid Input Parameter(s) for Write!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { if ((pDlContext->tRWInfo.bFirstWrReq) == true) { (pDlContext->tRWInfo.wRemBytes) = (pDlContext->tUserData.wLen); (pDlContext->tRWInfo.wOffset) = 0; } } } else if (phDnldNfc_FTRead == (pDlContext->FrameInp.Type)) { if ((0 == (pDlContext->tRspBuffInfo.wLen)) || (NULL == (pDlContext->tRspBuffInfo.pBuff))) { NXPLOG_FWDNLD_E("Invalid Input Parameter(s) for Read!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { if ((pDlContext->tRWInfo.bFramesSegmented) == false) { NXPLOG_FWDNLD_D("Verifying RspBuffInfo for Read Request.."); wFrameLen = (uint16_t)(pDlContext->tRspBuffInfo.wLen) + PHDNLDNFC_MIN_PLD_LEN; (pDlContext->tRWInfo.wRWPldSize) = (PHDNLDNFC_CMDRESP_MAX_PLD_SIZE - PHDNLDNFC_MIN_PLD_LEN); (pDlContext->tRWInfo.wRemBytes) = (pDlContext->tRspBuffInfo.wLen); (pDlContext->tRWInfo.dwAddr) = (pDlContext->FrameInp.dwAddr); (pDlContext->tRWInfo.wOffset) = 0; (pDlContext->tRWInfo.wBytesRead) = 0; if (PHDNLDNFC_CMDRESP_MAX_PLD_SIZE < wFrameLen) { (pDlContext->tRWInfo.bFramesSegmented) = true; } } } } else if (phDnldNfc_FTLog == (pDlContext->FrameInp.Type)) { if ((0 == (pDlContext->tUserData.wLen)) || (NULL == (pDlContext->tUserData.pBuff))) { NXPLOG_FWDNLD_E("Invalid Input Parameter(s) for Log!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } } else { } if (NFCSTATUS_SUCCESS == wStatus) { wStatus = phDnldNfc_CreateFramePld(pDlContext); } if (NFCSTATUS_SUCCESS == wStatus) { wFrameLen = 0; wFrameLen = (pDlContext->tCmdRspFrameInfo.dwSendlength); if (wFrameLen > PHDNLDNFC_CMDRESP_MAX_BUFF_SIZE) { NXPLOG_FWDNLD_D("wFrameLen exceeds the limit"); return NFCSTATUS_FAILED; } if (phDnldNfc_FTRaw != (pDlContext->FrameInp.Type)) { if (phDnldNfc_FTWrite != (pDlContext->FrameInp.Type)) { pFrameByte = (uint8_t*)&wFrameLen; pDlContext->tCmdRspFrameInfo.aFrameBuff[PHDNLDNFC_FRAME_HDR_OFFSET] = pFrameByte[1]; pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAME_HDR_OFFSET + 1] = pFrameByte[0]; NXPLOG_FWDNLD_D("Inserting FrameId .."); pDlContext->tCmdRspFrameInfo.aFrameBuff[PHDNLDNFC_FRAMEID_OFFSET] = (pDlContext->tCmdId); wFrameLen += PHDNLDNFC_FRAME_HDR_LEN; } else { if (0 != (pDlContext->tRWInfo.wRWPldSize)) { if ((pDlContext->tRWInfo.bFramesSegmented) == true) { /* Turning ON the Fragmentation bit in FrameLen */ if (nfcFL.chipType == sn220u) { wFrameLen = PHDNLDNFC_SET_HDR_FRAGBIT_SN220(wFrameLen); } else { wFrameLen = PHDNLDNFC_SET_HDR_FRAGBIT(wFrameLen); } } pFrameByte = (uint8_t*)&wFrameLen; pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAME_HDR_OFFSET] = pFrameByte[1]; pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAME_HDR_OFFSET + 1] = pFrameByte[0]; /* To ensure we have no frag bit set for crc calculation */ if (nfcFL.chipType == sn220u) { wFrameLen = PHDNLDNFC_CLR_HDR_FRAGBIT_SN220(wFrameLen); } else { wFrameLen = PHDNLDNFC_CLR_HDR_FRAGBIT(wFrameLen); } wFrameLen += PHDNLDNFC_FRAME_HDR_LEN; } } /*Check whether enough space is left for 2 bytes of CRC append*/ if (wFrameLen > (PHDNLDNFC_CMDRESP_MAX_BUFF_SIZE - 2)) { NXPLOG_FWDNLD_D("wFrameLen exceeds the limit"); return NFCSTATUS_FAILED; } /* calculate CRC16 */ wCrcVal = phDnldNfc_CalcCrc16((pDlContext->tCmdRspFrameInfo.aFrameBuff), wFrameLen); pFrameByte = (uint8_t*)&wCrcVal; /* Insert the computed Crc value */ pDlContext->tCmdRspFrameInfo.aFrameBuff[wFrameLen] = pFrameByte[1]; pDlContext->tCmdRspFrameInfo.aFrameBuff[wFrameLen + 1] = pFrameByte[0]; wFrameLen += PHDNLDNFC_FRAME_CRC_LEN; } (pDlContext->tCmdRspFrameInfo.dwSendlength) = wFrameLen; NXPLOG_FWDNLD_D("Frame created successfully"); } else { NXPLOG_FWDNLD_E("Frame creation failed!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } return wStatus; } /******************************************************************************* ** ** Function phDnldNfc_CreateFramePld ** ** Description Forms the frame payload ** ** Parameters pDlContext - pointer to the download context structure ** ** Returns NFC status ** *******************************************************************************/ static NFCSTATUS phDnldNfc_CreateFramePld(pphDnldNfc_DlContext_t pDlContext) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; uint32_t wBuffIdx = 0; uint16_t wChkIntgVal = 0; uint16_t wFrameLen = 0; if (NULL == pDlContext) { NXPLOG_FWDNLD_E("Invalid Input Parameter!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { memset((pDlContext->tCmdRspFrameInfo.aFrameBuff), 0, PHDNLDNFC_CMDRESP_MAX_BUFF_SIZE); (pDlContext->tCmdRspFrameInfo.dwSendlength) = 0; if (phDnldNfc_FTNone == (pDlContext->FrameInp.Type)) { (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_MIN_PLD_LEN; } else if (phDnldNfc_ChkIntg == (pDlContext->FrameInp.Type)) { (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_MIN_PLD_LEN; if (nfcFL.chipType < sn100u) { wChkIntgVal = nfcFL._PHDNLDNFC_USERDATA_EEPROM_OFFSET; memcpy(&(pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAME_RDDATA_OFFSET]), &wChkIntgVal, sizeof(wChkIntgVal)); wChkIntgVal = nfcFL._PHDNLDNFC_USERDATA_EEPROM_LEN; memcpy(&(pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAME_RDDATA_OFFSET + PHDNLDNFC_USERDATA_EEPROM_OFFSIZE]), &wChkIntgVal, sizeof(wChkIntgVal)); (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_USERDATA_EEPROM_LENSIZE; (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_USERDATA_EEPROM_OFFSIZE; } } else if (phDnldNfc_FTWrite == (pDlContext->FrameInp.Type)) { wBuffIdx = (pDlContext->tRWInfo.wOffset); if ((pDlContext->tRWInfo.bFramesSegmented) == false) { wFrameLen = (pDlContext->tUserData.pBuff[wBuffIdx]); wFrameLen <<= 8; wFrameLen |= (pDlContext->tUserData.pBuff[wBuffIdx + 1]); (pDlContext->tRWInfo.wRWPldSize) = wFrameLen; } if ((pDlContext->tRWInfo.wRWPldSize) > PHDNLDNFC_CMDRESP_MAX_PLD_SIZE) { if ((pDlContext->tRWInfo.bFirstChunkResp) == false) { (pDlContext->tRWInfo.wRemChunkBytes) = wFrameLen; (pDlContext->tRWInfo.wOffset) += PHDNLDNFC_FRAME_HDR_LEN; wBuffIdx = (pDlContext->tRWInfo.wOffset); } if (PHDNLDNFC_CMDRESP_MAX_PLD_SIZE < (pDlContext->tRWInfo.wRemChunkBytes)) { (pDlContext->tRWInfo.wBytesToSendRecv) = PHDNLDNFC_CMDRESP_MAX_PLD_SIZE; (pDlContext->tRWInfo.bFramesSegmented) = true; } else { (pDlContext->tRWInfo.wBytesToSendRecv) = (pDlContext->tRWInfo.wRemChunkBytes); (pDlContext->tRWInfo.bFramesSegmented) = false; } memcpy(&(pDlContext->tCmdRspFrameInfo .aFrameBuff[PHDNLDNFC_FRAMEID_OFFSET]), &(pDlContext->tUserData.pBuff[wBuffIdx]), (pDlContext->tRWInfo.wBytesToSendRecv)); } else { (pDlContext->tRWInfo.wRWPldSize) = 0; (pDlContext->tRWInfo.wBytesToSendRecv) = (wFrameLen + PHDNLDNFC_FRAME_HDR_LEN); memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[0]), &(pDlContext->tUserData.pBuff[wBuffIdx]), (pDlContext->tRWInfo.wBytesToSendRecv)); } (pDlContext->tCmdRspFrameInfo.dwSendlength) += (pDlContext->tRWInfo.wBytesToSendRecv); } else if (phDnldNfc_FTRead == (pDlContext->FrameInp.Type)) { (pDlContext->tRWInfo.wBytesToSendRecv) = ((pDlContext->tRWInfo.wRemBytes) > (pDlContext->tRWInfo.wRWPldSize)) ? (pDlContext->tRWInfo.wRWPldSize) : (uint16_t)(pDlContext->tRWInfo.wRemBytes); wBuffIdx = (PHDNLDNFC_PLD_OFFSET + ((sizeof(pDlContext->tRWInfo.wBytesToSendRecv)) % PHDNLDNFC_MIN_PLD_LEN) - 1); memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[wBuffIdx]), &(pDlContext->tRWInfo.wBytesToSendRecv), (sizeof(pDlContext->tRWInfo.wBytesToSendRecv))); wBuffIdx += (uint32_t)sizeof(pDlContext->tRWInfo.wBytesToSendRecv); memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[wBuffIdx]), &(pDlContext->tRWInfo.dwAddr), sizeof(pDlContext->tRWInfo.dwAddr)); (pDlContext->tCmdRspFrameInfo.dwSendlength) += (PHDNLDNFC_MIN_PLD_LEN + (sizeof(pDlContext->tRWInfo.dwAddr))); } else if (phDnldNfc_FTLog == (pDlContext->FrameInp.Type)) { (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_MIN_PLD_LEN; wBuffIdx = (PHDNLDNFC_MIN_PLD_LEN + PHDNLDNFC_FRAME_HDR_LEN); memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[wBuffIdx]), (pDlContext->tUserData.pBuff), (pDlContext->tUserData.wLen)); (pDlContext->tCmdRspFrameInfo.dwSendlength) += (uint16_t)(pDlContext->tUserData.wLen); } else if (phDnldNfc_FTForce == (pDlContext->FrameInp.Type)) { (pDlContext->tCmdRspFrameInfo.dwSendlength) += PHDNLDNFC_MIN_PLD_LEN; wBuffIdx = PHDNLDNFC_PLD_OFFSET; memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[wBuffIdx]), (pDlContext->tUserData.pBuff), (pDlContext->tUserData.wLen)); } else if (phDnldNfc_FTRaw == (pDlContext->FrameInp.Type)) { if ((0 == (pDlContext->tUserData.wLen)) || (NULL == (pDlContext->tUserData.pBuff))) { NXPLOG_FWDNLD_E("Invalid Input Parameter(s) for Raw Request!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { memcpy(&(pDlContext->tCmdRspFrameInfo.aFrameBuff[wBuffIdx]), (pDlContext->tUserData.pBuff), (pDlContext->tUserData.wLen)); (pDlContext->tCmdRspFrameInfo.dwSendlength) += (uint16_t)(pDlContext->tUserData.wLen); } } else { } } return wStatus; } /******************************************************************************* ** ** Function phDnldNfc_ProcessFrame ** ** Description Processes response frame received ** ** Parameters pContext - pointer to the download context structure ** pInfo - pointer to the Transaction buffer updated by TML ** Thread ** ** Returns NFCSTATUS_SUCCESS - parameters successfully validated ** NFCSTATUS_INVALID_PARAMETER - invalid parameters ** *******************************************************************************/ static NFCSTATUS phDnldNfc_ProcessFrame(void* pContext, phTmlNfc_TransactInfo_t* pInfo) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; uint16_t wCrcVal, wRecvdCrc, wRecvdLen, wPldLen; pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if ((NULL == pDlCtxt) || (NULL == pInfo)) { NXPLOG_FWDNLD_E("Invalid Input Parameters!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { if ((PH_DL_STATUS_OK != pInfo->wStatus) || (0 == pInfo->wLength) || (NULL == pInfo->pBuff)) { NXPLOG_FWDNLD_E("Dnld Cmd Request Failed!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } else { if (phDnldNfc_FTRaw == (pDlCtxt->FrameInp.Type)) { if ((0 != (pDlCtxt->tRspBuffInfo.wLen)) && (NULL != (pDlCtxt->tRspBuffInfo.pBuff))) { memcpy((pDlCtxt->tRspBuffInfo.pBuff), (pInfo->pBuff), (pInfo->wLength)); (pDlCtxt->tRspBuffInfo.wLen) = (pInfo->wLength); } else { NXPLOG_FWDNLD_E("Cannot update Response buff with received data!!"); } } else { /* calculate CRC16 */ wCrcVal = phDnldNfc_CalcCrc16( (pInfo->pBuff), ((pInfo->wLength) - PHDNLDNFC_FRAME_CRC_LEN)); wRecvdCrc = 0; wRecvdCrc = (((uint16_t)(pInfo->pBuff[(pInfo->wLength) - 2]) << 8U) | (pInfo->pBuff[(pInfo->wLength) - 1])); if (wRecvdCrc == wCrcVal) { wRecvdLen = (((uint16_t)(pInfo->pBuff[PHDNLDNFC_FRAME_HDR_OFFSET]) << 8U) | (pInfo->pBuff[PHDNLDNFC_FRAME_HDR_OFFSET + 1])); wPldLen = ((pInfo->wLength) - (PHDNLDNFC_FRAME_HDR_LEN + PHDNLDNFC_FRAME_CRC_LEN)); if (wRecvdLen != wPldLen) { NXPLOG_FWDNLD_E("Invalid frame payload length received"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } else { wStatus = phDnldNfc_UpdateRsp(pDlCtxt, pInfo, (wPldLen - 1)); } } else { NXPLOG_FWDNLD_E("Invalid frame received"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } } } return wStatus; } /******************************************************************************* ** ** Function phDnldNfc_ProcessRecvInfo ** ** Description Processes the response during the state phDnldNfc_StateRecv ** ** Parameters pContext - pointer to the download context structure ** pInfo - pointer to the Transaction buffer updated by TML ** Thread ** ** Returns NFCSTATUS_SUCCESS - parameters successfully validated ** NFCSTATUS_INVALID_PARAMETER - invalid parameters ** *******************************************************************************/ static NFCSTATUS phDnldNfc_ProcessRecvInfo(void* pContext, phTmlNfc_TransactInfo_t* pInfo) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; if (NULL != pContext) { if (NULL == pInfo) { NXPLOG_FWDNLD_E("Invalid pInfo received from TML!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } else { wStatus = PHNFCSTATUS(pInfo->wStatus); if (NFCSTATUS_SUCCESS == wStatus) { NXPLOG_FWDNLD_D("Send Success"); } else { NXPLOG_FWDNLD_E("Tml Write error!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } } else { NXPLOG_FWDNLD_E("Invalid context received from TML!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } return wStatus; } /******************************************************************************* ** ** Function phDnldNfc_SetupResendTimer ** ** Description Sets up the timer for resending the previous write frame ** ** Parameters pDlContext - pointer to the download context structure ** ** Returns NFC status ** *******************************************************************************/ static NFCSTATUS phDnldNfc_SetupResendTimer(pphDnldNfc_DlContext_t pDlContext) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; wStatus = phOsalNfc_Timer_Start((pDlContext->TimerInfo.dwRspTimerId), PHDNLDNFC_RETRY_FRAME_WRITE, &phDnldNfc_ResendTimeOutCb, pDlContext); if (NFCSTATUS_SUCCESS == wStatus) { NXPLOG_FWDNLD_D("Frame Resend wait timer started"); (pDlContext->TimerInfo.TimerStatus) = 1; pDlContext->tCurrState = phDnldNfc_StateTimer; } else { NXPLOG_FWDNLD_W("Frame Resend wait timer not started"); (pDlContext->TimerInfo.TimerStatus) = 0; /*timer stopped*/ pDlContext->tCurrState = phDnldNfc_StateResponse; /* Todo:- diagnostic in this case */ } return wStatus; } #if !defined(PH_LIBNFC_VEN_RESET_ON_DOWNLOAD_TIMEOUT) #error PH_LIBNFC_VEN_RESET_ON_DOWNLOAD_TIMEOUT has to be defined #endif /******************************************************************************* ** ** Function phDnldNfc_RspTimeOutCb ** ** Description Callback function in case of timer expiration ** ** Parameters TimerId - expired timer id ** pContext - pointer to the download context structure ** ** Returns None ** *******************************************************************************/ static void phDnldNfc_RspTimeOutCb(uint32_t TimerId, void* pContext) { pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if (NULL != pDlCtxt) { UNUSED_PROP(TimerId); if (1 == pDlCtxt->TimerInfo.TimerStatus) { /* No response received and the timer expired */ pDlCtxt->TimerInfo.TimerStatus = 0; /* Reset timer status flag */ NXPLOG_FWDNLD_D("%x", pDlCtxt->tLastStatus); #if (PH_LIBNFC_VEN_RESET_ON_DOWNLOAD_TIMEOUT == TRUE) if (PH_DL_STATUS_SIGNATURE_ERROR == pDlCtxt->tLastStatus) { /* Do a VEN Reset of the chip. */ NXPLOG_FWDNLD_E("Performing a VEN Reset"); phTmlNfc_IoCtl(phTmlNfc_e_EnableNormalMode); phTmlNfc_IoCtl(phTmlNfc_e_EnableDownloadMode); NXPLOG_FWDNLD_E("VEN Reset Done"); } #endif (pDlCtxt->TimerInfo.wTimerExpStatus) = NFCSTATUS_RF_TIMEOUT; if ((phDnldNfc_EventRead == pDlCtxt->tCurrEvent) || (phDnldNfc_EventWrite == pDlCtxt->tCurrEvent)) { phDnldNfc_ProcessRWSeqState(pDlCtxt, NULL); } else { phDnldNfc_ProcessSeqState(pDlCtxt, NULL); } } } return; } /******************************************************************************* ** ** Function phDnldNfc_ResendTimeOutCb ** ** Description Callback function in case of Frame Resend Wait timer ** expiration ** ** Parameters TimerId - expired timer id ** pContext - pointer to the download context structure ** ** Returns None ** *******************************************************************************/ static void phDnldNfc_ResendTimeOutCb(uint32_t TimerId, void* pContext) { pphDnldNfc_DlContext_t pDlCtxt = (pphDnldNfc_DlContext_t)pContext; if (NULL != pDlCtxt) { UNUSED_PROP(TimerId); if (1 == pDlCtxt->TimerInfo.TimerStatus) { /* No response received and the timer expired */ pDlCtxt->TimerInfo.TimerStatus = 0; /* Reset timer status flag */ (pDlCtxt->TimerInfo.wTimerExpStatus) = 0; pDlCtxt->tCurrState = phDnldNfc_StateSend; /* set the flag to trigger last frame re-transmission */ pDlCtxt->bResendLastFrame = true; phDnldNfc_ProcessRWSeqState(pDlCtxt, NULL); } } return; } /******************************************************************************* ** ** Function phDnldNfc_UpdateRsp ** ** Description verifies the payload status byte and copies data ** to response buffer if successful ** ** Parameters pDlContext - pointer to the download context structure ** pInfo - pointer to the Transaction buffer updated by TML ** Thread ** wPldLen - Length of the payload bytes to copy to response ** buffer ** ** Returns NFC status ** *******************************************************************************/ static NFCSTATUS phDnldNfc_UpdateRsp(pphDnldNfc_DlContext_t pDlContext, phTmlNfc_TransactInfo_t* pInfo, uint16_t wPldLen) { NFCSTATUS wStatus = NFCSTATUS_SUCCESS; uint16_t wReadLen = 0; if ((NULL == pDlContext) || (NULL == pInfo)) { NXPLOG_FWDNLD_E("Invalid Input Parameters!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_INVALID_PARAMETER); } else { if (PH_DL_CMD_WRITE == (pDlContext->tCmdId)) { if (PH_DL_STATUS_OK == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { /* first write frame response received case */ if ((pDlContext->tRWInfo.bFirstWrReq) == true) { NXPLOG_FWDNLD_D("First Write Frame Success Status received!!"); (pDlContext->tRWInfo.bFirstWrReq) = false; } if ((pDlContext->tRWInfo.bFirstChunkResp) == true) { if ((pDlContext->tRWInfo.bFramesSegmented) == false) { NXPLOG_FWDNLD_D("Chunked Write Frame Success Status received!!"); (pDlContext->tRWInfo.wRemChunkBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.bFirstChunkResp) = false; } else { NXPLOG_FWDNLD_E("UnExpected Status received!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } if (NFCSTATUS_SUCCESS == wStatus) { (pDlContext->tRWInfo.wRemBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.wOffset) += (pDlContext->tRWInfo.wBytesToSendRecv); } } else if (((pDlContext->tRWInfo.bFirstChunkResp) == false) && ((pDlContext->tRWInfo.bFramesSegmented) == true) && (PHDNLDNFC_FIRST_FRAGFRAME_RESP == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET]))) { (pDlContext->tRWInfo.bFirstChunkResp) = true; (pDlContext->tRWInfo.wRemChunkBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.wRemBytes) -= ((pDlContext->tRWInfo.wBytesToSendRecv) + PHDNLDNFC_FRAME_HDR_LEN); (pDlContext->tRWInfo.wOffset) += (pDlContext->tRWInfo.wBytesToSendRecv); /* first write frame response received case */ if ((pDlContext->tRWInfo.bFirstWrReq) == true) { NXPLOG_FWDNLD_D("First Write Frame Success Status received!!"); (pDlContext->tRWInfo.bFirstWrReq) = false; } } else if (((pDlContext->tRWInfo.bFirstChunkResp) == true) && ((pDlContext->tRWInfo.bFramesSegmented) == true) && (PHDNLDNFC_NEXT_FRAGFRAME_RESP == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET]))) { (pDlContext->tRWInfo.wRemChunkBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.wRemBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.wOffset) += (pDlContext->tRWInfo.wBytesToSendRecv); } else if (PH_DL_STATUS_FIRMWARE_VERSION_ERROR == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { NXPLOG_FWDNLD_E( "FW version Error !!!could be either due to FW major version " "mismatch or Firmware Already Up To Date !!"); (pDlContext->tRWInfo.bFirstWrReq) = false; /* resetting wRemBytes to 0 to avoid any further write frames send */ (pDlContext->tRWInfo.wRemBytes) = 0; (pDlContext->tRWInfo.wOffset) = 0; wStatus = NFCSTATUS_FW_VERSION_ERROR; } else if (PH_DL_STATUS_PLL_ERROR == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { NXPLOG_FWDNLD_E("PLL Error Status received!!"); (pDlContext->tLastStatus) = PH_DL_STATUS_PLL_ERROR; wStatus = NFCSTATUS_WRITE_FAILED; } else if (PH_DL_STATUS_SIGNATURE_ERROR == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { NXPLOG_FWDNLD_E("Signature Mismatch Error received!!"); /* save the status for use in loading the relevant recovery image * (either signature or platform) */ (pDlContext->tLastStatus) = PH_DL_STATUS_SIGNATURE_ERROR; wStatus = NFCSTATUS_REJECTED; } else if (PH_DL_STATUS_MEM_BSY == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { NXPLOG_FWDNLD_E("Mem Busy Status received!!"); (pDlContext->tLastStatus) = PH_DL_STATUS_MEM_BSY; wStatus = NFCSTATUS_BUSY; } else { NXPLOG_FWDNLD_E("Unsuccessful Status received!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } else if (PH_DL_CMD_READ == (pDlContext->tCmdId)) { if (PH_DL_STATUS_OK == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { wReadLen = (((uint16_t)(pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET + 3]) << 8U) | (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET + 2])); if (wReadLen != (pDlContext->tRWInfo.wBytesToSendRecv)) { NXPLOG_FWDNLD_E("Desired Length bytes not received!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } else { memcpy( &(pDlContext->tRspBuffInfo.pBuff[(pDlContext->tRWInfo.wOffset)]), &(pInfo->pBuff[PHDNLDNFC_FRAME_RDDATA_OFFSET]), wReadLen); (pDlContext->tRWInfo.wBytesRead) += wReadLen; (pDlContext->tRspBuffInfo.wLen) = (pDlContext->tRWInfo.wBytesRead); (pDlContext->tRWInfo.wRemBytes) -= (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.dwAddr) += (pDlContext->tRWInfo.wBytesToSendRecv); (pDlContext->tRWInfo.wOffset) += (pDlContext->tRWInfo.wBytesToSendRecv); } } else { NXPLOG_FWDNLD_E("Unsuccessful Status received!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } else { if (PH_DL_STATUS_OK == (pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET])) { if ((0 != (pDlContext->tRspBuffInfo.wLen)) && (NULL != (pDlContext->tRspBuffInfo.pBuff))) { memcpy((pDlContext->tRspBuffInfo.pBuff), &(pInfo->pBuff[PHDNLDNFC_FRAMESTATUS_OFFSET + 1]), wPldLen); (pDlContext->tRspBuffInfo.wLen) = wPldLen; } } else { NXPLOG_FWDNLD_E("Unsuccessful Status received!!"); wStatus = PHNFCSTVAL(CID_NFC_DNLD, NFCSTATUS_FAILED); } } } return wStatus; }