/* * 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 phLlcNfc_Frame.c * \brief To append the I or S or U frames (LLC header). * * Project: NFC-FRI-1.1 * * $Date: Tue Jun 1 14:41:26 2010 $ * $Author: ing02260 $ * $Revision: 1.88 $ * $Aliases: NFC_FRI1.1_WK1023_R35_1 $ * */ /*************************** Includes *******************************/ #include #include #include #include #include #include #include #include #include #ifdef ANDROID #include #endif /*********************** End of includes ****************************/ /***************************** Macros *******************************/ /************************ End of macros *****************************/ /***************************** Global variables *******************************/ #ifdef LLC_RELEASE_FLAG extern uint8_t g_release_flag; #endif /* #ifdef LLC_RELEASE_FLAG */ /************************ End of global variables *****************************/ /*********************** Local functions ****************************/ static void phLlcNfc_H_UpdateCrc( uint8_t crcByte, uint16_t *pCrc ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions process the received U frame function * * \copydoc page_reg This function is to process the U frame received from * the device * * \param[in] psLlcCtxt Llc main structure information * \param[in] llcPacket LLC packet information, inlcuding length information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static NFCSTATUS phLlcNfc_H_ProcessUFrame ( phLlcNfc_Context_t *psLlcCtxt ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions process the received S frame function * * \copydoc page_reg This function is to process the S frame received from * the device * * \param[in] psLlcCtxt Llc main structure information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static void phLlcNfc_H_ProcessSFrame ( phLlcNfc_Context_t *psLlcCtxt ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions Update I frame list function * * \copydoc page_reg This function checks the nr value with the stored I frames * and deletes the nodes which has been acknowledged. * * \param[in/out] psFrameInfo Frame structure information * \param[in/out] psListInfo List information * * \retval number of deleted frames * */ static uint8_t phLlcNfc_H_UpdateIFrameList( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_StoreIFrame_t *psListInfo ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions \b Delete list function * * \copydoc page_reg Delete the front node from the list * * \param[in] psFrameInfo Frame structure information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static void phLlcNfc_H_DeleteIFrame ( phLlcNfc_StoreIFrame_t *psList ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions Get the LLC header function * * \copydoc page_reg This function checks for the correctness fo the llc header * * \param[in] llcHeader The byte which gives the header information * * \retval phLlcNfc_eU_frame U frame type. * \retval phLlcNfc_eI_frame I frame type. * \retval phLlcNfc_eS_frame S frame type. * \retval phLlcNfc_eErr_frame Error type * */ static phLlcNfc_FrameType_t phLlcNfc_H_ChkGetLlcFrameType ( uint8_t llcHeader ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions \b Peek the data function * * \copydoc page_reg Get the packet information from the front node from the list * * \param[in] psListInfo The List information * \param[in] packetinfo The packet information from the front node of the list * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static NFCSTATUS phLlcNfc_H_IFrameList_Peek ( phLlcNfc_StoreIFrame_t *psList, phLlcNfc_LlcPacket_t **psPacketinfo, uint8_t position ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions Update U frame information function * * \copydoc page_reg This function updates the U frame information in the * phLlcNfc_sFrame_t structure * * \param[in/out] psFrameInfo Frame information structure * \param[in] llcPayload Llc payload information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static NFCSTATUS phLlcNfc_H_Update_ReceivedRSETInfo ( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_Payload_t llcInfo ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC Reset frame information function * * \copydoc page_reg resets ns and nr value, when ack for U frame is received * * \param[in, out] psLlcCtxt Llc main structure information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ static void phLlcNfc_H_ResetFrameInfo ( phLlcNfc_Context_t *psLlcCtxt ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC Reset frame sending function * * \copydoc page_reg Send URSET frame to PN544 * * \param[in, out] psLlcCtxt Llc main structure information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_BUSY Write is pended, so wait till it completes. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ NFCSTATUS phLlcNfc_H_SendRSETFrame ( phLlcNfc_Context_t *psLlcCtxt ); /** * \ingroup grp_hal_nfc_llc_helper * * \brief LLC helper functions process the received I frame function * * \copydoc page_reg This function is to process the I frame received from * the device * * \param[in] psLlcCtxt Llc main structure information * * \retval NFCSTATUS_SUCCESS Operation successful. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * */ void phLlcNfc_H_ProcessIFrame ( phLlcNfc_Context_t *psLlcCtxt ); /******************** End of Local functions ************************/ /********************** Global variables ****************************/ /******************** End of Global Variables ***********************/ void phLlcNfc_H_Frame_Init ( phLlcNfc_Context_t *psLlcCtxt ) { if (NULL != psLlcCtxt) { /* Set all the other values to 0 */ (void)memset (&psLlcCtxt->s_frameinfo.s_llcpacket, 0, sizeof(phLlcNfc_LlcPacket_t)); psLlcCtxt->s_frameinfo.window_size = PH_LLCNFC_U_FRAME_MAX_WIN_SIZE; /* Initialise the window size, N(S) and N(R) */ #ifdef PIGGY_BACK psLlcCtxt->s_frameinfo.s_recv_store.winsize_cnt = 0; #endif psLlcCtxt->s_frameinfo.s_send_store.winsize_cnt = 0; psLlcCtxt->s_frameinfo.n_s = 0; psLlcCtxt->s_frameinfo.n_r = 0; psLlcCtxt->s_frameinfo.rejected_ns = DEFAULT_PACKET_INPUT; } } void phLlcNfc_H_Frame_DeInit ( phLlcNfc_Frame_t *psFrameInfo ) { if (NULL != psFrameInfo) { /* Empty the frame information */ (void)memset(&psFrameInfo->s_llcpacket, 0, sizeof(phLlcNfc_LlcPacket_t)); } } NFCSTATUS phLlcNfc_H_CreateUFramePayload ( phLlcNfc_Context_t *psLlcCtxt, phLlcNfc_LlcPacket_t *psLlcPacket, uint8_t *pLlcPacketLength, phLlcNfc_LlcCmd_t cmdType ) { /* U frame packet (RSET) Byte 0 = Length (4 to 6 bytes) Byte 1 = Header Byte 2 = window size (2 >= window size <= 4) Byte 3 = capabilities (SREJ option enable/disable) (optional) Byte 4 = Baud rate (optional) Byte 5 = CRC1 Byte 6 = CRC2 */ NFCSTATUS result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); phLlcNfc_Buffer_t *ps_llc_buf = NULL; uint8_t index = 0; if ((NULL != psLlcCtxt) && (NULL != psLlcPacket) && (NULL != pLlcPacketLength) && ((phLlcNfc_e_rset == cmdType) || (phLlcNfc_e_ua == cmdType))) { result = NFCSTATUS_SUCCESS; ps_llc_buf = &(psLlcPacket->s_llcbuf); /* Get the header information */ ps_llc_buf->sllcpayload.llcheader = (uint8_t)PH_LLCNFC_U_HEADER_INIT; if (phLlcNfc_e_rset == cmdType) { /* RSET command */ ps_llc_buf->sllcpayload.llcheader = (uint8_t)SET_BITS8( ps_llc_buf->sllcpayload.llcheader, PH_LLCNFC_U_FRAME_START_POS, PH_LLCNFC_U_FRAME_NO_OF_POS, (uint8_t)phLlcNfc_e_rset); /* Default window size */ ps_llc_buf->sllcpayload.llcpayload[index] = PH_LLCNFC_U_FRAME_MAX_WIN_SIZE; index++; /* Endpoint capabilities, SREJ not supported */ ps_llc_buf->sllcpayload.llcpayload[index] = PH_LLCNFC_SREJ_BYTE_VALUE; index++; #ifdef ENABLE_BAUDRATE /* baud rate 0x00 = 9600, 0x05 = 115200 */ ps_llc_buf->sllcpayload.llcpayload[index] = (uint8_t)phLlcNfc_e_115200; index++; #endif /* #ifdef ENABLE_BAUDRATE */ } else { /* UA frame */ ps_llc_buf->sllcpayload.llcheader = (uint8_t) SET_BITS8(ps_llc_buf->sllcpayload.llcheader, PH_LLCNFC_U_FRAME_START_POS, PH_LLCNFC_U_FRAME_NO_OF_POS, (uint8_t)phLlcNfc_e_ua); } /* LLC length byte updated (index + 2 CRC bytes + 1 byte of header) */ ps_llc_buf->llc_length_byte = (index + PH_LLCNFC_NUM_OF_CRC_BYTES + 1); /* Total LLC buffer size */ *pLlcPacketLength = psLlcPacket->llcbuf_len = (ps_llc_buf->llc_length_byte + 1); /* psLlcPacket->s_llcbuf : consists llc length byte + llc header + data + CRC (which needs to be calculated by the below function) psLlcPacket->llcbuf_len : Total length of the above buffer psLlcPacket->llcbuf_len - 2 : -2 because the CRC has to be calculated, only for the bytes which has llc length byte + llc header + data. But total length (llcbuf_len) consists of above mentioned things with 2 byte CRC psLlcPacket->s_llcbuf.sllcpayload.llcpayload : consists only data (no length byte and no llc header) (psLlcPacket->llcbuf_len - 4) : is the array index of the first CRC byte to be calculated (psLlcPacket->llcbuf_len - 3) : is the array index of the second CRC byte to be calculated */ index = psLlcPacket->llcbuf_len; phLlcNfc_H_ComputeCrc((uint8_t *)ps_llc_buf, (psLlcPacket->llcbuf_len - 2), &(ps_llc_buf->sllcpayload.llcpayload[(index - 4)]), &(ps_llc_buf->sllcpayload.llcpayload[(index - 3)])); } return result; } NFCSTATUS phLlcNfc_H_CreateSFramePayload ( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_LlcPacket_t *psLlcPacket, phLlcNfc_LlcCmd_t cmdType ) { /* S frame packet (RR or RNR or REJ or SREJ). Total bytes = 4 Byte 0 = Length (Length = 3 always for S frame) Byte 1 = Header Byte 2 = CRC1 Byte 3 = CRC2 */ NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Buffer_t *ps_llc_buf = NULL; uint8_t length = 0; ps_llc_buf = &(psLlcPacket->s_llcbuf); /* Initial S frame header */ ps_llc_buf->sllcpayload.llcheader = PH_LLCNFC_S_HEADER_INIT; /* Update the N(R) value */ ps_llc_buf->sllcpayload.llcheader = (uint8_t)SET_BITS8( ps_llc_buf->sllcpayload.llcheader, PH_LLCNFC_NR_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS, psFrameInfo->n_r); /* Update the type bits of S frame */ ps_llc_buf->sllcpayload.llcheader = (uint8_t) (ps_llc_buf->sllcpayload.llcheader | (uint8_t)cmdType); /* Maximum S frame length */ psLlcPacket->llcbuf_len = (uint8_t)PH_LLCNFC_MAX_S_FRAME_LEN; /* S frame length byte value */ ps_llc_buf->llc_length_byte = (uint8_t) (psLlcPacket->llcbuf_len - 1); /* psFrameInfo->s_llcpacket.s_llcbuf : consists llc length byte + llc header + data + CRC (which needs to be calculated by the below function) psFrameInfo->s_llcpacket.llcbuf_len : Total length of the above buffer psFrameInfo->s_llcpacket.llcbuf_len - 2 : -2 because the CRC has to be calculated, only for the bytes which has llc length byte + llc header + data. But total length (llcbuf_len) consists of above mentioned things with 2 byte CRC psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : consists only data (no length byte and no llc header) psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : contains only data sent by user. (psFrameInfo->s_llcpacket.llcbuf_len - 4) : is the array index of the first CRC byte to be calculated (psFrameInfo->s_llcpacket.llcbuf_len - 3) : is the array index of the second CRC byte to be calculated */ length = psLlcPacket->llcbuf_len; phLlcNfc_H_ComputeCrc( (uint8_t *)ps_llc_buf, (length - 2), &(ps_llc_buf->sllcpayload.llcpayload[(length - 4)]), &(ps_llc_buf->sllcpayload.llcpayload[(length - 3)])); return result; } NFCSTATUS phLlcNfc_H_CreateIFramePayload ( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_LlcPacket_t *psLlcPacket, uint8_t *pLlcBuf, uint8_t llcBufLength ) { NFCSTATUS result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); phLlcNfc_Buffer_t *ps_llc_buf = NULL; if ((NULL != psFrameInfo) && (NULL != psLlcPacket) && (NULL != pLlcBuf) && (llcBufLength > 0)) { result = NFCSTATUS_SUCCESS; ps_llc_buf = &(psLlcPacket->s_llcbuf); (void)memcpy(&(ps_llc_buf->sllcpayload.llcpayload[0]), pLlcBuf, llcBufLength); psLlcPacket->llcbuf_len = (uint8_t)llcBufLength; /* I frame header byte */ ps_llc_buf->sllcpayload.llcheader = PH_LLCNFC_I_HEADER_INIT; /* Set the N(S) value */ ps_llc_buf->sllcpayload.llcheader = (uint8_t) SET_BITS8( ps_llc_buf->sllcpayload.llcheader, PH_LLCNFC_NS_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS, psFrameInfo->n_s); /* Set the N(R) value */ ps_llc_buf->sllcpayload.llcheader = (uint8_t) SET_BITS8( ps_llc_buf->sllcpayload.llcheader, PH_LLCNFC_NR_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS, psFrameInfo->n_r); /* Update the length byte, llc length byte value includes data + CRC bytes + llc length byte */ ps_llc_buf->llc_length_byte = (psLlcPacket->llcbuf_len + PH_LLCNFC_NUM_OF_CRC_BYTES + 1); /* Update total length, Total length is always equal to llc length byte + 1 */ psLlcPacket->llcbuf_len = (ps_llc_buf->llc_length_byte + 1); /* psFrameInfo->s_llcpacket.s_llcbuf : consists llc length byte + llc header + data + CRC (which needs to be calculated by the below function) psFrameInfo->s_llcpacket.llcbuf_len : Total length of the above buffer psFrameInfo->s_llcpacket.llcbuf_len - 2 : -2 because the CRC has to be calculated, only for the bytes which has llc length byte + llc header + data. But total length (llcbuf_len) consists of above mentioned things with 2 byte CRC psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : contains only data sent by user. (psFrameInfo->s_llcpacket.llcbuf_len - 4) : is the array index of the first CRC byte to be calculated (psFrameInfo->s_llcpacket.llcbuf_len - 3) : is the array index of the second CRC byte to be calculated */ phLlcNfc_H_ComputeCrc( (uint8_t*)ps_llc_buf, (psLlcPacket->llcbuf_len - 2), &(ps_llc_buf->sllcpayload.llcpayload [(psLlcPacket->llcbuf_len - 4)]), &(ps_llc_buf->sllcpayload.llcpayload [(psLlcPacket->llcbuf_len - 3)])); } return result; } static phLlcNfc_FrameType_t phLlcNfc_H_ChkGetLlcFrameType ( uint8_t llcHeader ) { phLlcNfc_FrameType_t frame_type = phLlcNfc_eErr_frame; /* Mask the header byte to know the actual frame types */ switch((llcHeader & PH_LLCNFC_LLC_HEADER_MASK)) { case PH_LLCNFC_U_HEADER_INIT: { frame_type = phLlcNfc_eU_frame; break; } case PH_LLCNFC_S_HEADER_INIT: { frame_type = phLlcNfc_eS_frame; break; } default: { if (PH_LLCNFC_I_HEADER_INIT == (PH_LLCNFC_I_FRM_HEADER_MASK & llcHeader)) { frame_type = phLlcNfc_eI_frame; } else { frame_type = phLlcNfc_eErr_frame; } break; } } return frame_type; } static NFCSTATUS phLlcNfc_H_Update_ReceivedRSETInfo ( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_Payload_t llcInfo ) { NFCSTATUS result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); uint8_t payload_index = 0; if ((llcInfo.llcpayload[payload_index] >= PH_LLCNFC_U_FRAME_MIN_WIN_SIZE) && (llcInfo.llcpayload[payload_index] <= PH_LLCNFC_U_FRAME_MAX_WIN_SIZE)) { result = NFCSTATUS_SUCCESS; /* From the received buffer, get the window size from the 3rd byte (recvUBufLen[3]) of the buffer */ psFrameInfo->window_size = llcInfo.llcpayload[payload_index]; payload_index = (uint8_t)(payload_index + 1); /* If 4th byte of the receive buffer (pRecvUBuf[4]) is 0x01 then SREJ can come from the device*/ psFrameInfo->srej_on_off = ((PH_LLCNFC_SREJ_BYTE_VALUE == llcInfo.llcpayload[payload_index])? PH_LLCNFC_SREJ_BYTE_VALUE:0); /* For present implementation, this should be always false later stage remove if statement to work */ if (PH_LLCNFC_SREJ_BYTE_VALUE != psFrameInfo->srej_on_off) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); } else { payload_index = (uint8_t)(payload_index + 1); if (llcInfo.llcpayload[payload_index] > (uint8_t)phLlcNfc_e_1228000) { /* Error byte */ result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); } else { /* Get the baud rate from the 5th byte of the receive buffer */ psFrameInfo->baud_rate = (phLlcNfc_LlcBaudRate_t) (llcInfo.llcpayload[payload_index]); } } } return result; } static uint8_t phLlcNfc_H_UpdateIFrameList( phLlcNfc_Frame_t *psFrameInfo, phLlcNfc_StoreIFrame_t *psListInfo ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_LlcPacket_t *pspktInfo = NULL; uint8_t while_exit = FALSE; uint8_t nr = 0; uint8_t ns = 0; uint8_t no_of_del_frames = 0; PHNFC_UNUSED_VARIABLE(result); if(0 == psListInfo->winsize_cnt) { while_exit = TRUE; } while (FALSE == while_exit) { /* Get the first node from the list */ result = phLlcNfc_H_IFrameList_Peek (psListInfo, &pspktInfo, DEFAULT_PACKET_INPUT); if (NULL != pspktInfo) { /* Get the N(R) value of the received packet and N(S) value of the sent stored i frame */ ns = (uint8_t)GET_BITS8 ( pspktInfo->s_llcbuf.sllcpayload.llcheader, PH_LLCNFC_NS_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS); nr = (uint8_t)GET_BITS8( psFrameInfo->s_recvpacket.s_llcbuf.sllcpayload.llcheader, PH_LLCNFC_NR_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS); /* Check the value of each i frame N(S) and received ACKs N(R) */ #if 0 if(((ns <= nr) && ((nr - ns) <= psFrameInfo->window_size)) || ((ns > nr) && (((PH_LLCNFC_MOD_NS_NR + nr) - ns) <= PH_LLCNFC_U_FRAME_MAX_WIN_SIZE))) #endif if(((ns < nr) && ((nr - ns) <= psFrameInfo->window_size)) || ((ns > nr) && (((PH_LLCNFC_MOD_NS_NR + nr) - ns) <= PH_LLCNFC_U_FRAME_MAX_WIN_SIZE))) { phLlcNfc_H_DeleteIFrame (psListInfo); no_of_del_frames = (uint8_t)(no_of_del_frames + 1); } else { while_exit = TRUE; } if(0 == psListInfo->winsize_cnt) { while_exit = TRUE; } } else { while_exit = TRUE; } } return no_of_del_frames; } NFCSTATUS phLlcNfc_H_SendUserIFrame ( phLlcNfc_Context_t *psLlcCtxt, phLlcNfc_StoreIFrame_t *psListInfo ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_LlcPacket_t s_create_packet; phLlcNfc_LlcPacket_t *ps_get_packet = NULL; phLlcNfc_Payload_t *ps_llc_payload = NULL; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; uint8_t llc_header = 0, length = 0; if ((NULL == psLlcCtxt) || (NULL == psListInfo)) { result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else if (0 == psListInfo->winsize_cnt) { result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED); } else { ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_store_frame = &(ps_frame_info->s_send_store); if ( (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR)) ) { /* Get the stored I frame, only if the new frame is sent from the upper layer */ result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet, ps_frame_info->n_s); } if (NULL != ps_get_packet) { llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader; /* Update n(r) value for the header */ llc_header = (uint8_t)(llc_header | ps_frame_info->n_r); /* Create the packet */ (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet, sizeof (phLlcNfc_LlcPacket_t)); s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header; ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload); /* Length of the complete llc buffer, sent to PN544 */ length = s_create_packet.llcbuf_len; /* Compute CRC for the created packet */ phLlcNfc_H_ComputeCrc ((uint8_t *)&(s_create_packet.s_llcbuf), (length - 2), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)])); /* Send the i frame */ result = phLlcNfc_Interface_Write (psLlcCtxt, (uint8_t *)&(s_create_packet.s_llcbuf), (uint32_t)s_create_packet.llcbuf_len); ps_frame_info->write_status = result; if (NFCSTATUS_BUSY == PHNFCSTATUS (result)) { /* The below check is added because, write is already pended by some other operation, so it has to complete, when it completes, then immediately next write shall be called using the below updated variable The below variable is checked for the resend or rejected i frame because if due to timer or reject frame from PN544, an I frame has been sent (means write has been pended then the variable shall not be overwritten. */ ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t) (((resend_i_frame == ps_frame_info->write_wait_call) || (rejected_i_frame == ps_frame_info->write_wait_call)) ? ps_frame_info->write_wait_call : user_i_frame); } else { if (NFCSTATUS_PENDING == result) { /* Start the timer */ (void)phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, ps_frame_info->n_s); /* "sent_frame_type is updated" only if the data is written to the lower layer */ ps_frame_info->sent_frame_type = user_i_frame; } } } } return result; } NFCSTATUS phLlcNfc_H_SendRejectedIFrame ( phLlcNfc_Context_t *psLlcCtxt, phLlcNfc_StoreIFrame_t *psListInfo, uint8_t ns_rejected ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_LlcPacket_t s_create_packet; phLlcNfc_LlcPacket_t *ps_get_packet = NULL; phLlcNfc_Payload_t *ps_llc_payload = NULL; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; uint8_t llc_header = 0; uint8_t length = 0; if ((NULL == psLlcCtxt) || (NULL == psListInfo)) { result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else if (0 == psListInfo->winsize_cnt) { result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED); } else { ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_store_frame = &(ps_frame_info->s_send_store); if (ns_rejected < (uint8_t)(ps_store_frame->winsize_cnt + ps_store_frame->start_pos)) { /* To send rejected frame, first thing shall be done is windows size count shall be checked. if the start position */ if (invalid_frame != ps_store_frame->s_llcpacket[ns_rejected].frame_to_send) { /* Above check is added to know only if */ result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet, ns_rejected); } else { ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT; /* Get the stored I frame, only if the new frame is sent from the upper layer */ result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, psListInfo); } } if (NULL != ps_get_packet) { llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader; /* Update n(r) value for the header */ llc_header = (uint8_t)(llc_header | ps_frame_info->n_r); /* Create the packet */ (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet, sizeof (phLlcNfc_LlcPacket_t)); s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header; ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload); /* Length of the complete llc buffer, sent to PN544 */ length = s_create_packet.llcbuf_len; /* Compute CRC for the created packet */ phLlcNfc_H_ComputeCrc ((uint8_t *)&(s_create_packet.s_llcbuf), (length - 2), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)])); /* Send the i frame */ result = phLlcNfc_Interface_Write (psLlcCtxt, (uint8_t *)&(s_create_packet.s_llcbuf), (uint32_t)s_create_packet.llcbuf_len); ps_frame_info->write_status = result; if (NFCSTATUS_BUSY == PHNFCSTATUS (result)) { /* Already a frame is sent and response is waited for the sent frame, so update the below variable */ ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t) (((ns_rejected != ps_store_frame->start_pos) && (resend_i_frame != ps_frame_info->write_wait_call))? rejected_i_frame : ps_frame_info->write_wait_call); } else { /* NFCSTATUS_PENDING means that the no other write is pending, apart from the present write Start the timer */ (void)phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, ns_rejected); /* "sent_frame_type is updated" only if the data is written to the lower layer. This will be used in the write response callback and also indicates, what is the frame sent and why */ ps_frame_info->sent_frame_type = rejected_i_frame; if ((ns_rejected + 1) < ps_frame_info->n_s) { ps_frame_info->rejected_ns = (uint8_t)(ns_rejected + 1); ps_frame_info->write_status = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_BUSY); if (invalid_frame == ps_store_frame->s_llcpacket[ns_rejected].frame_to_send) { ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT; ps_frame_info->write_wait_call = user_i_frame; } else { ps_frame_info->write_wait_call = rejected_i_frame; } } else { ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT; /* This check is added to see that new frame has arrived from the upper layer */ if (ps_frame_info->n_s < (ps_store_frame->start_pos + ps_store_frame->winsize_cnt)) { ps_frame_info->write_wait_call = user_i_frame; } } } } } return result; } NFCSTATUS phLlcNfc_H_SendTimedOutIFrame ( phLlcNfc_Context_t *psLlcCtxt, phLlcNfc_StoreIFrame_t *psListInfo, uint8_t frame_to_send ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_Timerinfo_t *ps_timer_info = NULL; phLlcNfc_LlcPacket_t s_create_packet; phLlcNfc_LlcPacket_t *ps_get_packet = NULL; phLlcNfc_Payload_t *ps_llc_payload = NULL; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; PHNFC_UNUSED_VARIABLE(frame_to_send); if((NULL == psLlcCtxt) || (NULL == psListInfo)) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else if (psListInfo->winsize_cnt == 0) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED); } else { uint8_t llc_header = 0; uint8_t length = 0; uint8_t timer_count = 0; uint8_t timer_index = 0; uint8_t ns_index = 0; ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_timer_info = &(psLlcCtxt->s_timerinfo); ps_store_frame = &(ps_frame_info->s_send_store); timer_index = ps_timer_info->index_to_send; timer_count = ps_timer_info->guard_to_count; ns_index = ps_timer_info->timer_ns_value[timer_index]; PH_LLCNFC_DEBUG("SEND TIMEOUT CALL WIN SIZE CNT : 0x%02X\n", ps_store_frame->winsize_cnt); PH_LLCNFC_DEBUG("SEND TIMEOUT CALL START POS : 0x%02X\n", ps_store_frame->start_pos); PH_LLCNFC_DEBUG("SEND TIMEOUT CALL N S value : 0x%02X\n", ps_frame_info->n_s); PH_LLCNFC_DEBUG("SEND TIMEOUT TIMER INDEX : 0x%02X\n", timer_index); PH_LLCNFC_DEBUG("SEND TIMEOUT CALL frame type : 0x%02X\n", ps_timer_info->frame_type[timer_index]); if (resend_i_frame == ps_timer_info->frame_type[timer_index]) { /* Get the stored I frame */ result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet, ns_index); } PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Packet : 0x%p\n", ps_get_packet); if (NULL != ps_get_packet) { llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader; /* Update n(r) value for the header */ llc_header = (uint8_t)(llc_header | ps_frame_info->n_r); /* create the packet */ (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet, sizeof (phLlcNfc_LlcPacket_t)); s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header; ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload); /* Length of the complete llc buffer, sent to PN544 */ length = s_create_packet.llcbuf_len; /* Compute CRC */ phLlcNfc_H_ComputeCrc((uint8_t *)&(s_create_packet.s_llcbuf), (length - 2), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]), (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)])); /* Send the i frame */ result = phLlcNfc_Interface_Write (psLlcCtxt, (uint8_t *)&(s_create_packet.s_llcbuf), (uint32_t)s_create_packet.llcbuf_len); ps_frame_info->write_status = result; PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Write status : 0x%02X\n", result); if (NFCSTATUS_BUSY == PHNFCSTATUS (result)) { ps_frame_info->write_wait_call = resend_i_frame; } else { /* result = NFCSTATUS_PENDING and Timer is not started because the remaining timer will be running */ uint16_t time_out_value = 0; /* Each frame has the send count, so increment this as soon as the frame is sent */ ps_timer_info->iframe_send_count[timer_index] = (uint8_t) (ps_timer_info->iframe_send_count[timer_index] + 1); PH_LLCNFC_DEBUG("SEND TIMEOUT CALL timer index : 0x%02X\n", timer_index); if (timer_index > 0) { PH_LLCNFC_DEBUG("SEND TIMEOUT CALL GUARD TO VALUE : 0x%02X\n", ps_timer_info->guard_to_value[(timer_index - 1)]); /* Copy the maximum time-out value. */ time_out_value = (uint16_t) ((ps_timer_info->guard_to_value[(timer_index - 1)] >= PH_LLCNFC_GUARD_TO_VALUE) ? (ps_timer_info->guard_to_value[(timer_index - 1)] + PH_LLCNFC_RESOLUTION): PH_LLCNFC_GUARD_TO_VALUE); } else { /* If the timer_index is 0 means, the previous timed out frame is the last frame in the list */ time_out_value = (uint16_t) ((ps_timer_info->guard_to_value[(timer_count - 1)] >= PH_LLCNFC_GUARD_TO_VALUE) ? (ps_timer_info->guard_to_value[(timer_count - 1)] + PH_LLCNFC_RESOLUTION): PH_LLCNFC_GUARD_TO_VALUE); } ps_timer_info->guard_to_value[timer_index] = time_out_value; ps_frame_info->sent_frame_type = resend_i_frame; ps_timer_info->frame_type[timer_index] = invalid_frame; PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Next frame type : 0x%02X\n", ps_timer_info->frame_type[((timer_index + 1) % PH_LLCNFC_MAX_ACK_GUARD_TIMER)]); /* Now check if next timer has expired, if yes, set the index to next, on receiving the write response callback for this send, then next frame can be sent */ if (resend_i_frame == ps_timer_info->frame_type[((timer_index + 1) % PH_LLCNFC_MAX_ACK_GUARD_TIMER)]) { /* If next frame has to be sent, then update write wait */ ps_frame_info->write_status = NFCSTATUS_BUSY; ps_frame_info->write_wait_call = resend_i_frame; ps_timer_info->index_to_send = (uint8_t) ((timer_index + 1) % PH_LLCNFC_MAX_ACK_GUARD_TIMER); } else { /* Timer is not expired, Now, Check if the new frame is ready to be sent, if yes, then update the variable */ if ( (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR)) ) { ps_frame_info->write_status = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_BUSY); ps_frame_info->write_wait_call = user_i_frame; } } #if 0 result = phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, ((llc_header >> PH_LLCNFC_NS_START_BIT_POS) | MAX_NS_NR_VALUE)); #endif /* #if 0 */ } } else { if ( (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR)) ) { ps_frame_info->write_status = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_BUSY); ps_frame_info->write_wait_call = user_i_frame; } } } return result; } void phLlcNfc_H_ProcessIFrame ( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t ns_index = 0; #if defined (LLC_SEND_RR_ACK) /* uint8_t nr_index = 0; */ #endif /* #if defined (LLC_SEND_RR_ACK) */ phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; phLlcNfc_LlcPacket_t *ps_recv_pkt = NULL; phLlcNfc_LlcCmd_t cmdtype = phLlcNfc_e_error; phLlcNfc_eSentFrameType_t eframe_type = invalid_frame; uint8_t dont_send_s_frame = FALSE; uint8_t no_of_del_frames = 0; phNfc_sCompletionInfo_t notifyinfo = {0,0,0}; #ifdef RECV_NR_CHECK_ENABLE uint8_t recvd_nr = 0; #endif /* #ifdef RECV_NR_CHECK_ENABLE */ ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_store_frame = &(ps_frame_info->s_send_store); ps_recv_pkt = &(ps_frame_info->s_recvpacket); PHNFC_UNUSED_VARIABLE(result); /* Received buffer, N(S) value */ ns_index = (uint8_t)GET_BITS8( ps_recv_pkt->s_llcbuf.sllcpayload.llcheader, PH_LLCNFC_NS_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS); PH_LLCNFC_DEBUG("NS START POS BEFORE DEL : 0x%02X\n", ps_store_frame->start_pos); PH_LLCNFC_DEBUG("WIN SIZE BEFORE DEL : 0x%02X\n", ps_store_frame->winsize_cnt); /* Correct frame is received, so remove the stored i frame info */ no_of_del_frames = phLlcNfc_H_UpdateIFrameList (ps_frame_info, &(ps_frame_info->s_send_store)); PH_LLCNFC_DEBUG("NS START POS AFTER DEL : 0x%02X\n", ps_store_frame->start_pos); PH_LLCNFC_DEBUG("WIN SIZE AFTER DEL : 0x%02X\n", ps_store_frame->winsize_cnt); #ifdef RECV_NR_CHECK_ENABLE recvd_nr = (uint8_t)GET_BITS8( ps_recv_pkt->s_llcbuf.sllcpayload.llcheader, PH_LLCNFC_NR_START_BIT_POS, PH_LLCNFC_NR_NS_NO_OF_BITS); if (((ps_frame_info->n_s > recvd_nr) && (0 == ((ps_frame_info->n_s + 1) % PH_LLCNFC_MOD_NS_NR))) || (recvd_nr > ps_frame_info->n_s)) #else /* #ifdef RECV_NR_CHECK_ENABLE */ if (no_of_del_frames > 0) #endif /* #ifdef RECV_NR_CHECK_ENABLE */ { phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames); } /* Received buffer, N(S) value = N(R) of host (our structure) then send RR type of s frame else send REJ type of s frame */ if ((ns_index == ps_frame_info->n_r) #if defined (LLC_SEND_RR_ACK) || ((ns_index < ps_frame_info->n_r) && ((ps_frame_info->n_r - ns_index) < ps_frame_info->window_size)) || ((ns_index > ps_frame_info->n_r) && ((ns_index - ps_frame_info->n_r) > ps_frame_info->window_size)) #endif /* #if defined (LLC_SEND_RR_ACK) */ ) { PH_LLCNFC_PRINT(" Type bits of S frame to be sent is RR \n"); ps_frame_info->recv_error_count = 0; ps_frame_info->send_error_count = 0; psLlcCtxt->recvbuf_length = (ps_recv_pkt->llcbuf_len - PH_LLCNFC_LEN_APPEND); (void)memcpy ((void *)psLlcCtxt->precv_buf, (void *)( ps_recv_pkt->s_llcbuf.sllcpayload.llcpayload), psLlcCtxt->recvbuf_length); #if defined (LLC_SEND_RR_ACK) if (((ns_index < ps_frame_info->n_r) && ((ps_frame_info->n_r - ns_index) < ps_frame_info->window_size)) || ((ns_index > ps_frame_info->n_r) && ((ns_index - ps_frame_info->n_r) > ps_frame_info->window_size))) { ps_frame_info->n_r = ((ns_index + 1) % PH_LLCNFC_MOD_NS_NR); } else #endif /* #if defined (LLC_SEND_RR_ACK) */ { /* Update the N(R) value in I and S frame context */ ps_frame_info->n_r = ((ps_frame_info->n_r + 1) % PH_LLCNFC_MOD_NS_NR); #ifdef PIGGY_BACK ps_frame_info->resp_recvd_count = (uint8_t) (ps_frame_info->resp_recvd_count + 1); #endif /* #ifdef PIGGY_BACK */ } if (NFCSTATUS_BUSY == PHNFCSTATUS (ps_frame_info->write_status)) { /* Any how write cannot be done and some frame is ready to be sent so this frame will act as the ACK */ result = phLlcNfc_H_WriteWaitCall (psLlcCtxt); } else { if ( (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR)) ) { /* If user has sent a frame and DAL write is busy, then it has to be sent */ result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame); } } if (NFCSTATUS_PENDING == result) { dont_send_s_frame = TRUE; #ifdef LLC_UPP_LAYER_NTFY_WRITE_RSP_CB phLlcNfc_H_SendInfo (psLlcCtxt); #endif /* #ifdef LLC_UPP_LAYER_NTFY_WRITE_RSP_CB */ } else { cmdtype = phLlcNfc_e_rr; /* If i frame is sent from the stored list, it got the correct acknowledge i frame, so now for an i frame , s frame acknowledge is sent */ eframe_type = ((resend_i_frame == ps_frame_info->sent_frame_type)? resend_s_frame : s_frame); } #ifdef PIGGY_BACK phLlcNfc_H_SendInfo (psLlcCtxt); #endif /* #ifdef PIGGY_BACK */ } else { ps_frame_info->send_error_count = (uint8_t) (ps_frame_info->send_error_count + 1); #ifdef LLC_SEND_ERROR_COUNT if (ps_frame_info->send_error_count < RECV_ERROR_FRAME_COUNT) #endif /* #ifdef LLC_SEND_ERROR_COUNT */ { #ifdef LLC_RR_INSTEAD_OF_REJ if (((ps_frame_info->n_r > 0) && (ns_index == (ps_frame_info->n_r - 1))) || ((0 == ps_frame_info->n_r) && (ns_index == (PH_LLCNFC_MOD_NS_NR - 1)))) { cmdtype = phLlcNfc_e_rr; eframe_type = rej_rr_s_frame; } else #endif /* #ifdef LLC_RR_INSTEAD_OF_REJ */ { cmdtype = phLlcNfc_e_rej; eframe_type = ((resend_i_frame == ps_frame_info->sent_frame_type)? resend_rej_s_frame : reject_s_frame); } } #ifdef LLC_SEND_ERROR_COUNT else { #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION result = phLlcNfc_H_SendRSETFrame (psLlcCtxt); #else /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */ dont_send_s_frame = TRUE; PH_LLCNFC_DEBUG("SEND ERROR COUNT : 0x%02X\n", ps_frame_info->send_error_count); /* Error count has reached the limit, raise exception */ notifyinfo.status = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_BOARD_COMMUNICATION_ERROR); #if 0 phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1); #endif /* #if 0 */ /* Resend done, no answer from the device */ psLlcCtxt->cb_for_if.notify ( psLlcCtxt->cb_for_if.pif_ctxt, psLlcCtxt->phwinfo, NFC_NOTIFY_DEVICE_ERROR, ¬ifyinfo); #endif /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */ } #endif /* #ifdef LLC_SEND_ERROR_COUNT */ } #ifdef LLC_RELEASE_FLAG if (FALSE == g_release_flag) #endif /* #ifdef LLC_RELEASE_FLAG */ { (void)phLlcNfc_Interface_Read(psLlcCtxt, PH_LLCNFC_READWAIT_OFF, &(ps_recv_pkt->s_llcbuf.llc_length_byte), (uint8_t)PH_LLCNFC_BYTES_INIT_READ); #ifdef PIGGY_BACK /* Check if any write call is performed or not */ if (NFCSTATUS_PENDING != result) { /* No write is performed, So, now check */ if (NFCSTATUS_BUSY == PHNFCSTATUS (ps_frame_info->write_status)) { /* Any how write cannot be done and some frame is ready to be sent so this frame will act as the ACK */ result = phLlcNfc_H_WriteWaitCall (psLlcCtxt); } } if (NFCSTATUS_PENDING != result) { if (ps_frame_info->window_size == ps_frame_info->resp_recvd_count) { phLlcNfc_LlcPacket_t s_packet_info; /* Create S frame */ (void)phLlcNfc_H_CreateSFramePayload (ps_frame_info, &(s_packet_info), cmdtype); result = phLlcNfc_Interface_Write(psLlcCtxt, (uint8_t *)&(s_packet_info.s_llcbuf), (uint32_t)(s_packet_info.llcbuf_len)); if (0 == ps_frame_info->send_error_count) { ps_frame_info->write_wait_call = invalid_frame; } ps_frame_info->sent_frame_type = eframe_type; } else { result = phLlcNfc_StartTimers (PH_LLCNFC_ACKTIMER, 0); } } #else /* #ifdef PIGGY_BACK */ if ((TRUE != ps_frame_info->write_pending) && (PH_LLCNFC_READPEND_REMAIN_BYTE != ps_frame_info->read_pending) && (FALSE == dont_send_s_frame)) { phLlcNfc_LlcPacket_t s_packet_info = {0}; /* Create S frame */ (void)phLlcNfc_H_CreateSFramePayload (ps_frame_info, &(s_packet_info), cmdtype); result = phLlcNfc_Interface_Write(psLlcCtxt, (uint8_t *)&(s_packet_info.s_llcbuf), (uint32_t)(s_packet_info.llcbuf_len)); if (0 == ps_frame_info->send_error_count) { ps_frame_info->write_wait_call = invalid_frame; } ps_frame_info->sent_frame_type = eframe_type; } #endif /* #ifdef PIGGY_BACK */ } return ; } static NFCSTATUS phLlcNfc_H_ProcessUFrame ( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_LlcPacket_t *ps_uframe_pkt = NULL; #ifdef LLC_URSET_NO_DELAY phNfc_sCompletionInfo_t notifyinfo = {0,0,0}; #else /* #ifdef LLC_URSET_NO_DELAY */ uint32_t delay_timer_id = PH_OSALNFC_INVALID_TIMER_ID; #endif /* #ifdef LLC_URSET_NO_DELAY */ uint8_t cmdtype = phLlcNfc_e_error; phLlcNfc_StopTimers(PH_LLCNFC_CONNECTIONTIMER, 0); ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_uframe_pkt = &(ps_frame_info->s_recvpacket); /* Check the command type */ cmdtype = (ps_uframe_pkt->s_llcbuf.sllcpayload.llcheader & PH_LLCNFC_U_FRAME_MODIFIER_MASK); PHNFC_UNUSED_VARIABLE(result); switch(cmdtype) { case phLlcNfc_e_rset: { psLlcCtxt->s_frameinfo.rset_recvd = TRUE; /* command type is RSET, so update the U frame parameters */ result = phLlcNfc_H_Update_ReceivedRSETInfo (ps_frame_info, ps_uframe_pkt->s_llcbuf.sllcpayload); /* Create a UA frame */ result = phLlcNfc_H_CreateUFramePayload(psLlcCtxt, ps_uframe_pkt, &(ps_uframe_pkt->llcbuf_len), phLlcNfc_e_ua); if (NFCSTATUS_SUCCESS == result) { /* Call DAL write */ result = phLlcNfc_Interface_Write( psLlcCtxt, (uint8_t*)&(ps_uframe_pkt->s_llcbuf), (uint32_t)ps_uframe_pkt->llcbuf_len); phLlcNfc_H_ResetFrameInfo(psLlcCtxt); ps_frame_info->write_status = result; ps_frame_info->write_wait_call = invalid_frame; if (NFCSTATUS_PENDING == result) { ps_frame_info->sent_frame_type = ((ps_frame_info->sent_frame_type != init_u_rset_frame) ? u_a_frame : init_u_a_frame); } else { if (NFCSTATUS_BUSY == PHNFCSTATUS(result)) { ps_frame_info->write_wait_call = ((ps_frame_info->sent_frame_type != init_u_rset_frame) ? u_a_frame : init_u_a_frame); result = NFCSTATUS_PENDING; } } } break; } case phLlcNfc_e_ua: { phLlcNfc_H_ResetFrameInfo (psLlcCtxt); /* Add timer here, to delay the next command to the PN544 */ #ifdef LLC_URSET_NO_DELAY if (ps_frame_info->s_send_store.winsize_cnt > 0) { #if 0 /* Resend I frame */ result = phLlcNfc_H_SendTimedOutIFrame (psLlcCtxt, &(ps_frame_info->s_send_store, 0); #else result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, &(ps_frame_info->s_send_store)); #endif /* #if 0 */ } else { if ((init_u_rset_frame == ps_frame_info->sent_frame_type) && (NULL != psLlcCtxt->cb_for_if.notify)) { ps_frame_info->sent_frame_type = write_resp_received; notifyinfo.status = NFCSTATUS_SUCCESS; /* Send the notification to the upper layer */ psLlcCtxt->cb_for_if.notify( psLlcCtxt->cb_for_if.pif_ctxt, psLlcCtxt->phwinfo, NFC_NOTIFY_INIT_COMPLETED, ¬ifyinfo); } } #else /* #ifdef LLC_URSET_NO_DELAY */ delay_timer_id = phOsalNfc_Timer_Create (); phOsalNfc_Timer_Start (delay_timer_id, LLC_URSET_DELAY_TIME_OUT, phLlcNfc_URSET_Delay_Notify, (void*)0); #endif /* #ifdef LLC_URSET_NO_DELAY */ break; } default: { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); break; } } return result; } static void phLlcNfc_H_ProcessSFrame ( phLlcNfc_Context_t *psLlcCtxt) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t cmdtype = phLlcNfc_e_error; #if 0 prev_win_count = 0; #endif /* #if 0 */ phNfc_sTransactionInfo_t compinfo = {0, 0, 0, 0, 0}; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; phLlcNfc_LlcPacket_t *ps_recv_pkt = NULL; uint8_t no_of_del_frames = 0; phNfc_sCompletionInfo_t notifyinfo = {0,0,0}; ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_recv_pkt = &(ps_frame_info->s_recvpacket); ps_store_frame = &(ps_frame_info->s_send_store); cmdtype = (ps_recv_pkt->s_llcbuf.sllcpayload.llcheader & PH_LLCNFC_S_FRAME_TYPE_MASK); PHNFC_UNUSED_VARIABLE(result); PH_LLCNFC_DEBUG("NS START POS BEFORE DEL : 0x%02X\n", ps_store_frame->start_pos); PH_LLCNFC_DEBUG("WIN SIZE BEFORE DEL : 0x%02X\n", ps_store_frame->winsize_cnt); /* Correct frame is received, so remove the stored i frame info for the acknowledged frames */ no_of_del_frames = phLlcNfc_H_UpdateIFrameList (ps_frame_info, &(ps_frame_info->s_send_store)); PH_LLCNFC_DEBUG("NS START POS AFTER DEL : 0x%02X\n", ps_store_frame->start_pos); PH_LLCNFC_DEBUG("WIN SIZE AFTER DEL : 0x%02X\n", ps_store_frame->winsize_cnt); #if 0 prev_win_count = ps_frame_info->s_send_store.winsize_cnt; #endif /* #if 0 */ /* Pend the read */ result = phLlcNfc_Interface_Read (psLlcCtxt, PH_LLCNFC_READWAIT_OFF, &(ps_recv_pkt->s_llcbuf.llc_length_byte), (uint8_t)PH_LLCNFC_BYTES_INIT_READ); switch(cmdtype) { case phLlcNfc_e_rr: case phLlcNfc_e_rej: { /* RR frame received */ phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames); if (phLlcNfc_e_rr == cmdtype) { ps_frame_info->recv_error_count = 0; ps_frame_info->send_error_count = 0; } else { ps_frame_info->recv_error_count = (uint8_t) (ps_frame_info->recv_error_count + 1); } if (ps_frame_info->recv_error_count >= RECV_ERROR_FRAME_COUNT) { /* Do nothing */ } else if (NFCSTATUS_BUSY == PHNFCSTATUS(ps_frame_info->write_status)) { result = phLlcNfc_H_WriteWaitCall (psLlcCtxt); } else { if ( (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR)) ) { /* If user has sent a frame and DAL write is busy, then it has to be sent */ result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame); } } if ((0 != psLlcCtxt->send_cb_len) && (ps_store_frame->winsize_cnt < ps_frame_info->window_size)) { /* Due to the window size count (i.e., count has reached the limit), send completion was not sent for the previous send from the upper layer. So to allow next send from the upper layer, send completion is called */ compinfo.length = (uint16_t)psLlcCtxt->send_cb_len; compinfo.status = NFCSTATUS_SUCCESS; if (NULL != psLlcCtxt->cb_for_if.send_complete) { psLlcCtxt->send_cb_len = 0; /* Call the send callback, if the window size count becomes less than actual window size */ psLlcCtxt->cb_for_if.send_complete ( psLlcCtxt->cb_for_if.pif_ctxt, psLlcCtxt->phwinfo, &compinfo); } } break; } #if 0 case phLlcNfc_e_rej: { ps_frame_info->recv_error_count = (uint8_t) (ps_frame_info->recv_error_count + 1); /* RR frame received */ phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames); if (ps_frame_info->recv_error_count < RECV_ERROR_FRAME_COUNT) { /* Below check is added because if PN544 sends REJ to a frame, but the next frame has already been sent from PN544, then Send the user I frame */ result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame); } break; } #endif /* #if 0 */ case phLlcNfc_e_rnr: { phLlcNfc_StopAllTimers (); ps_frame_info->recv_error_count = (uint8_t) (ps_frame_info->recv_error_count + 1); break; } case phLlcNfc_e_srej: default: { ps_frame_info->recv_error_count = (uint8_t) (ps_frame_info->recv_error_count + 1); result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); break; } } if (ps_frame_info->recv_error_count >= RECV_ERROR_FRAME_COUNT) { #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION result = phLlcNfc_H_SendRSETFrame (psLlcCtxt); #else /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */ PH_LLCNFC_DEBUG("RECV ERROR COUNT : 0x%02X\n", ps_frame_info->recv_error_count); /* Raise the exception for CRC error received from the */ notifyinfo.status = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_BOARD_COMMUNICATION_ERROR); #if 0 phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1); #endif /* #if 0 */ /* Resend done, no answer from the device */ psLlcCtxt->cb_for_if.notify ( psLlcCtxt->cb_for_if.pif_ctxt, psLlcCtxt->phwinfo, NFC_NOTIFY_DEVICE_ERROR, ¬ifyinfo); #endif /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */ } return ; } void phLlcNfc_H_ComputeCrc( uint8_t *pData, uint8_t length, uint8_t *pCrc1, uint8_t *pCrc2 ) { uint8_t crc_byte = 0, index = 0; uint16_t crc = 0; #ifdef CRC_A crc = 0x6363; /* ITU-V.41 */ #else crc = 0xFFFF; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */ #endif /* #ifdef CRC_A */ do { crc_byte = pData[index]; phLlcNfc_H_UpdateCrc(crc_byte, &crc); index++; } while (index < length); #ifndef INVERT_CRC crc = ~crc; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */ #endif /* #ifndef INVERT_CRC */ *pCrc1 = (uint8_t) (crc & 0xFF); *pCrc2 = (uint8_t) ((crc >> 8) & 0xFF); return; } static void phLlcNfc_H_UpdateCrc( uint8_t crcByte, uint16_t *pCrc ) { crcByte = (crcByte ^ (uint8_t)((*pCrc) & 0x00FF)); crcByte = (crcByte ^ (uint8_t)(crcByte << 4)); *pCrc = (*pCrc >> 8) ^ ((uint16_t)crcByte << 8) ^ ((uint16_t)crcByte << 3) ^ ((uint16_t)crcByte >> 4); } NFCSTATUS phLlcNfc_H_StoreIFrame ( phLlcNfc_StoreIFrame_t *psList, phLlcNfc_LlcPacket_t sPacketInfo ) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t ns_index = 0, llc_header = 0; if ((NULL == psList) || (0 == sPacketInfo.llcbuf_len) || (PH_LLCNFC_I_HEADER_INIT != (sPacketInfo.s_llcbuf.sllcpayload.llcheader & PH_LLCNFC_I_FRM_HEADER_MASK))) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else { /* Get the index from the start index */ if(psList->winsize_cnt > 0) { ns_index = (uint8_t)((psList->start_pos + psList->winsize_cnt) % PH_LLCNFC_MOD_NS_NR); } else { ns_index = psList->start_pos; } llc_header = (uint8_t)(PH_LLCNFC_I_HEADER_INIT | (ns_index << PH_LLCNFC_NS_START_BIT_POS)); sPacketInfo.s_llcbuf.sllcpayload.llcheader = llc_header; (void)memcpy (&(psList->s_llcpacket[ns_index]), &(sPacketInfo), sizeof(phLlcNfc_LlcPacket_t)); /* This variable says that LLC has to send complete callback for stored I frame */ psList->s_llcpacket[ns_index].frame_to_send = invalid_frame; psList->winsize_cnt++; } return result; } static void phLlcNfc_H_DeleteIFrame ( phLlcNfc_StoreIFrame_t *psList ) { if (NULL != psList) { (void)memset( &(psList->s_llcpacket[psList->start_pos]), 0, sizeof(phLlcNfc_LlcPacket_t)); /* Go to next N(S) position */ psList->start_pos = ((psList->start_pos + 1) % PH_LLCNFC_MOD_NS_NR); if (psList->winsize_cnt > 0) { psList->winsize_cnt--; } } } static NFCSTATUS phLlcNfc_H_IFrameList_Peek ( phLlcNfc_StoreIFrame_t *psList, phLlcNfc_LlcPacket_t **psPacketinfo, uint8_t position ) { NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t index = 0; *psPacketinfo = NULL; if ((NULL != psList) && (psList->winsize_cnt > 0)) { result = NFCSTATUS_SUCCESS; if ((position < (psList->start_pos + psList->winsize_cnt)) || (DEFAULT_PACKET_INPUT == position)) { index = (uint8_t)((DEFAULT_PACKET_INPUT == position) ? psList->start_pos : position); *psPacketinfo = &(psList->s_llcpacket[index]); } } return result; } NFCSTATUS phLlcNfc_H_ProRecvFrame ( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); phLlcNfc_FrameType_t frame_type = phLlcNfc_eErr_frame; #ifdef LLC_DATA_BYTES uint8_t *print_buf = (uint8_t *) &(psLlcCtxt->s_frameinfo.s_recvpacket.s_llcbuf); uint8_t buf_len = psLlcCtxt->s_frameinfo.s_recvpacket.llcbuf_len; PH_LLCNFC_STRING("** Response "); #endif /* LLC_DATA_BYTES */ if (NULL != psLlcCtxt) { result = NFCSTATUS_SUCCESS; /* Get the received frame type */ frame_type = phLlcNfc_H_ChkGetLlcFrameType( psLlcCtxt->s_frameinfo.s_recvpacket.s_llcbuf.sllcpayload.llcheader); /* Depending on the received frame type, process the received buffer */ switch(frame_type) { case phLlcNfc_eU_frame: { PH_LLCNFC_PRINT("U frame received \n"); PH_LLCNFC_STRING("U frame "); PH_LLCNFC_PRINT_DATA(print_buf, buf_len); PH_LLCNFC_STRING(";\n"); result = phLlcNfc_H_ProcessUFrame(psLlcCtxt); break; } case phLlcNfc_eI_frame: { PH_LLCNFC_PRINT("I frame received \n"); PH_LLCNFC_STRING("I frame "); PH_LLCNFC_PRINT_DATA(print_buf, buf_len); PH_LLCNFC_STRING(";\n"); phLlcNfc_H_ProcessIFrame(psLlcCtxt); break; } case phLlcNfc_eS_frame: { PH_LLCNFC_PRINT("S frame received \n"); PH_LLCNFC_STRING("S frame "); PH_LLCNFC_PRINT_DATA(print_buf, buf_len); PH_LLCNFC_STRING(";\n"); phLlcNfc_H_ProcessSFrame(psLlcCtxt); break; } case phLlcNfc_eErr_frame: default: { PH_LLCNFC_PRINT("Error frame received \n"); result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT); break; } } } return result; } #ifdef CRC_ERROR_REJ NFCSTATUS phLlcNfc_H_SendRejectFrame( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_LlcPacket_t s_packet_info = {0}; result = phLlcNfc_H_CreateSFramePayload( &(psLlcCtxt->s_frameinfo), &(s_packet_info), phLlcNfc_e_rej); /* Send the "S" frame to the lower layer */ result = phLlcNfc_Interface_Write(psLlcCtxt, (uint8_t *)&(s_packet_info.s_llcbuf), (uint32_t)(s_packet_info.llcbuf_len)); if (NFCSTATUS_PENDING == result) { /* Increment the retry count of the reject frame */ psLlcCtxt->s_frameinfo.recv_error_count = (psLlcCtxt->s_frameinfo.recv_error_count + 1); } return result; } #endif /* #ifdef CRC_ERROR_REJ */ static void phLlcNfc_H_ResetFrameInfo ( phLlcNfc_Context_t *psLlcCtxt ) { uint8_t i = 0, win_cnt = 0, pos = 0, while_exit = FALSE, index_flag = FALSE; phLlcNfc_StoreIFrame_t *ps_send_store = NULL; phLlcNfc_Buffer_t *ps_buffer = NULL; ps_send_store = &(psLlcCtxt->s_frameinfo.s_send_store); win_cnt = ps_send_store->winsize_cnt; pos = ps_send_store->start_pos; PH_LLCNFC_PRINT ("\n\nLLC : phLlcNfc_H_ResetFrameInfo called\n\n"); PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->start_pos %08X\n", ps_send_store->start_pos); PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->winsize_cnt before reset %08X\n", ps_send_store->winsize_cnt); if (0 != pos) { /* If the start position of the ns = 0, then no need to shift the stored llc data, Else it has to be shifted to the first index of the array */ if(TRUE == ((pos + win_cnt) / PH_LLCNFC_MAX_I_FRAME_STORE)) { /* 'i' is the array index, So to store data in the array, windows size count shall be subtracted by 1 */ i = (win_cnt - 1); /* if window size > 1 and ns for 2 frames are 7 and 0, then to reset the ns index to 0, the frames are copied from the reverse order, so to do it a flag is declared */ index_flag = TRUE; pos = (((pos - 1) + win_cnt) % PH_LLCNFC_MAX_I_FRAME_STORE); } while (FALSE == while_exit) { (void)memcpy ((void *)&(ps_send_store->s_llcpacket[i]), (void *)&(ps_send_store->s_llcpacket[pos]), sizeof (phLlcNfc_LlcPacket_t)); ps_send_store->s_llcpacket[i].frame_to_send = invalid_frame; ps_buffer = &(ps_send_store->s_llcpacket[i].s_llcbuf); /* change n(s) value */ ps_buffer->sllcpayload.llcheader = (uint8_t) (PH_LLCNFC_I_HEADER_INIT | (i << PH_LLCNFC_NS_START_BIT_POS)); if(TRUE == index_flag) { if(0 == i) { while_exit = TRUE; } else { i = ((i - 1) % PH_LLCNFC_MAX_I_FRAME_STORE); if (0 == pos) { pos = (PH_LLCNFC_MAX_I_FRAME_STORE - 1); } else { pos = ((pos - 1) % PH_LLCNFC_MAX_I_FRAME_STORE); } } } else { if (i >= win_cnt) { while_exit = TRUE; } else { i = ((i + 1) % PH_LLCNFC_MAX_I_FRAME_STORE); pos = ((pos + 1) % PH_LLCNFC_MAX_I_FRAME_STORE); } } } } psLlcCtxt->s_timerinfo.guard_to_count = 0; psLlcCtxt->s_timerinfo.timer_flag = 0; ps_send_store->start_pos = 0; psLlcCtxt->s_frameinfo.n_r = psLlcCtxt->s_frameinfo.n_s = 0; if (ps_send_store->winsize_cnt > 0) { psLlcCtxt->s_frameinfo.rejected_ns = 0; } else { psLlcCtxt->s_frameinfo.rejected_ns = DEFAULT_PACKET_INPUT; } PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->winsize_cnt after reset %08X\n", ps_send_store->winsize_cnt); return; } NFCSTATUS phLlcNfc_H_WriteWaitCall ( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_StoreIFrame_t *ps_store_info = NULL; phLlcNfc_Frame_t *ps_frame_info = NULL; ps_frame_info = &(psLlcCtxt->s_frameinfo); ps_store_info = &(ps_frame_info->s_send_store); PH_LLCNFC_PRINT ("\nLLC : phLlcNfc_H_WriteWaitCall call ..\n"); PH_LLCNFC_DEBUG ("\n\nLLC : ps_frame_info->write_wait_call before call %08X\n", ps_frame_info->write_wait_call); ps_frame_info->write_status = NFCSTATUS_PENDING; switch (ps_frame_info->write_wait_call) { case user_i_frame: { ps_frame_info->write_wait_call = invalid_frame; result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_info); break; } case resend_i_frame: { ps_frame_info->write_wait_call = invalid_frame; result = phLlcNfc_H_SendTimedOutIFrame (psLlcCtxt, ps_store_info, 0); break; } case rejected_i_frame: { ps_frame_info->write_wait_call = invalid_frame; result = phLlcNfc_H_SendRejectedIFrame (psLlcCtxt, ps_store_info, ps_frame_info->rejected_ns); break; } case resend_s_frame: case reject_s_frame: case resend_rej_s_frame: { ps_frame_info->write_wait_call = invalid_frame; break; } case u_rset_frame: { ps_frame_info->write_wait_call = invalid_frame; result = phLlcNfc_H_SendRSETFrame (psLlcCtxt); break; } default : { ps_frame_info->write_wait_call = invalid_frame; break; } } PH_LLCNFC_DEBUG ("\n\nLLC : ps_frame_info->write_wait_call after call %08X\n", ps_frame_info->write_wait_call); PH_LLCNFC_PRINT ("\nLLC : phLlcNfc_H_WriteWaitCall end ..\n"); return result; } NFCSTATUS phLlcNfc_H_SendRSETFrame ( phLlcNfc_Context_t *psLlcCtxt ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_LlcPacket_t s_packet_info; phLlcNfc_Frame_t *ps_frame_info = NULL; ps_frame_info = &(psLlcCtxt->s_frameinfo); result = phLlcNfc_H_CreateUFramePayload(psLlcCtxt, &(s_packet_info), &(s_packet_info.llcbuf_len), phLlcNfc_e_rset); if (NFCSTATUS_SUCCESS == result) { /* Call DAL write */ result = phLlcNfc_Interface_Write(psLlcCtxt, (uint8_t*)&(s_packet_info.s_llcbuf), (uint32_t)s_packet_info.llcbuf_len); } ps_frame_info->write_status = result; if (NFCSTATUS_PENDING == result) { /* Start the timer */ result = phLlcNfc_StartTimers (PH_LLCNFC_CONNECTIONTIMER, 0); if (NFCSTATUS_SUCCESS == result) { ps_frame_info->sent_frame_type = u_rset_frame; result = NFCSTATUS_PENDING; } } else { ps_frame_info->write_wait_call = u_rset_frame; } return result; }