/* * 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.c * \brief Common LLC for the upper layer. * * Project: NFC-FRI-1.1 * * $Date: Wed Apr 28 17:07:03 2010 $ * $Author: ing02260 $ * $Revision: 1.59 $ * $Aliases: NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $ * */ /*************************** Includes *******************************/ #include <phNfcTypes.h> #include <phNfcStatus.h> #include <phOsalNfc.h> #include <phNfcInterface.h> #include <phLlcNfc_DataTypes.h> #include <phLlcNfc.h> #include <phLlcNfc_Frame.h> #include <phLlcNfc_Interface.h> #include <phLlcNfc_Timer.h> /*********************** End of includes ****************************/ /***************************** Macros *******************************/ /************************ End of macros *****************************/ /***************************** Global variables *******************************/ #ifdef LLC_RELEASE_FLAG uint8_t g_release_flag; #endif /* #ifdef LLC_RELEASE_FLAG */ /************************ End of global variables *****************************/ /*********************** Local functions ****************************/ /** * \ingroup grp_hal_nfc_llc * * \brief \b Init function * * \copydoc page_reg Initialise all variables of the LLC component (Asynchronous function). * * \param[in] pContext LLC context provided by the upper layer. The LLC * context will be given to the upper layer through the * \ref phLlcNfc_Register function * \param[in] pLinkInfo Link information of the hardware * * \retval NFCSTATUS_PENDING If the command is yet to be processed. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * \retval Other errors Errors related to the lower layers * */ static NFCSTATUS phLlcNfc_Init ( void *pContext, void *pLinkInfo ); /** * \ingroup grp_hal_nfc_llc * * \brief \b Send function * * \copydoc page_reg This asynchronous function gets the information from the upper layer and creates the * proper LLC packet to send the information it to the hardware. The number of * bytes written is obtained from the send response callback which has been * registered in \ref phLlcNfc_Register function * * \param[in] pContext LLC context is provided by the upper layer. The LLC * context earlier was given to the upper layer through the * \ref phLlcNfc_Register function * \param[in] pLinkInfo Link information of the hardware. * \param[in] pLlc_Buf The information given by the upper layer to send it to * the lower layer * \param[in] llcBufLength the length of pLlc_Buf, that needs to be sent to the * lower layer is given by the upper layer * * \retval NFCSTATUS_PENDING If the command is yet to be process. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * \retval Other errors Errors related to the lower layers * */ static NFCSTATUS phLlcNfc_Send ( void *pContext, void *pLinkInfo, uint8_t *pLlcBuf, uint16_t llcBufLength ); /** * \ingroup grp_hal_nfc_llc * * \brief \b Receive function * * \copydoc page_reg This asynchronous function gets the length and the required buffer from * the upper layer to receive the information from the the hardware. The * received data will be given through the receive response callback * which has been registered in the \b phLlcNfc_Register function * * \param[in] pContext LLC context is provided by the upper layer. The LLC * context earlier was given to the upper layer through the * \b phLlcNfc_Register function * \param[in] pLinkInfo Link information of the hardware * \param[in] pLlc_Buf The information given by the upper layer to receive data from * the lower layer * \param[in] llcBufLength The length of pLlc_Buf given by the upper layer * * \retval NFCSTATUS_PENDING If the command is yet to be process. * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. * \retval Other errors Errors related to the lower layers * */ static NFCSTATUS phLlcNfc_Receive ( void *pContext, void *pLinkInfo, uint8_t *pLlcBuf, uint16_t llcBufLength ); /******************** End of Local functions ************************/ /********************** Global variables ****************************/ /******************** End of Global Variables ***********************/ NFCSTATUS phLlcNfc_Register ( phNfcIF_sReference_t *psReference, phNfcIF_sCallBack_t if_callback, void *psIFConfig ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Context_t *ps_llc_ctxt = NULL; phNfcLayer_sCfg_t *psconfig = (phNfcLayer_sCfg_t *)psIFConfig; PH_LLCNFC_PRINT("Llc Register called\n"); if ((NULL == psReference) || (NULL == psIFConfig) || (NULL == psReference->plower_if) || #if 0 (NULL == if_callback.pif_ctxt) || #endif (NULL == if_callback.notify) || (NULL == if_callback.receive_complete) || (NULL == if_callback.send_complete)) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else { /* Now LLC is in RESET state */ ps_llc_ctxt = (phLlcNfc_Context_t*)phOsalNfc_GetMemory( sizeof(phLlcNfc_Context_t)); if (NULL == ps_llc_ctxt) { /* Memory allocation failed */ result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INSUFFICIENT_RESOURCES); } else { result = NFCSTATUS_SUCCESS; (void)memset(ps_llc_ctxt, 0, sizeof(phLlcNfc_Context_t)); /* Register the LLC functions to the upper layer */ psReference->plower_if->init = (pphNfcIF_Interface_t)&phLlcNfc_Init; psReference->plower_if->release = (pphNfcIF_Interface_t)&phLlcNfc_Release; psReference->plower_if->send = (pphNfcIF_Transact_t)&phLlcNfc_Send; psReference->plower_if->receive = (pphNfcIF_Transact_t)&phLlcNfc_Receive; /* Copy the LLC context to the upper layer */ psReference->plower_if->pcontext = ps_llc_ctxt; /* Register the callback function from the upper layer */ ps_llc_ctxt->cb_for_if.receive_complete = if_callback.receive_complete; ps_llc_ctxt->cb_for_if.send_complete = if_callback.send_complete; ps_llc_ctxt->cb_for_if.notify = if_callback.notify; /* Get the upper layer context */ ps_llc_ctxt->cb_for_if.pif_ctxt = if_callback.pif_ctxt; result = phLlcNfc_Interface_Register(ps_llc_ctxt, psconfig); if (NFCSTATUS_SUCCESS == result) { #ifdef LLC_RELEASE_FLAG g_release_flag = FALSE; #endif /* #ifdef LLC_RELEASE_FLAG */ } } } PH_LLCNFC_DEBUG("Llc Register result : 0x%x\n", result); return result; } static NFCSTATUS phLlcNfc_Init ( void *pContext, void *pLinkInfo ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Context_t *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext; phLlcNfc_LlcPacket_t s_packet_info; PH_LLCNFC_PRINT("Llc Init called\n"); if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo)) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else { /* Initialisation */ ps_llc_ctxt->phwinfo = pLinkInfo; /* Call the internal frame initialise */ phLlcNfc_H_Frame_Init(ps_llc_ctxt); /* Call the internal LLC TL interface initialise */ result = phLlcNfc_Interface_Init(ps_llc_ctxt); if (NFCSTATUS_SUCCESS == result) { /* Call the internal LLC timer initialise */ result = phLlcNfc_TimerInit(ps_llc_ctxt); } if (NFCSTATUS_SUCCESS == result) { /* Create the static timer */ phLlcNfc_CreateTimers(); /* Create a U frame */ result = phLlcNfc_H_CreateUFramePayload(ps_llc_ctxt, &s_packet_info, &(s_packet_info.llcbuf_len), phLlcNfc_e_rset); } if (NFCSTATUS_SUCCESS == result) { /* Call DAL write */ result = phLlcNfc_Interface_Write(ps_llc_ctxt, (uint8_t*)&(s_packet_info.s_llcbuf), (uint32_t)s_packet_info.llcbuf_len); } if (NFCSTATUS_PENDING == result) { /* Start the timer */ result = phLlcNfc_StartTimers(PH_LLCNFC_CONNECTIONTIMER, 0); if (NFCSTATUS_SUCCESS == result) { ps_llc_ctxt->s_frameinfo.sent_frame_type = init_u_rset_frame; result = NFCSTATUS_PENDING; } } if (NFCSTATUS_PENDING != result) { (void)phLlcNfc_Release(ps_llc_ctxt, pLinkInfo); } } PH_LLCNFC_DEBUG("Llc Init result : 0x%x\n", result); return result; } NFCSTATUS phLlcNfc_Release( void *pContext, void *pLinkInfo ) { NFCSTATUS result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); phLlcNfc_Context_t *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext; /* 1. Free all the memory allocated in initialise */ PH_LLCNFC_PRINT("Llc release called\n"); if ((NULL != ps_llc_ctxt) && (NULL != pLinkInfo)) { result = NFCSTATUS_SUCCESS; ps_llc_ctxt->phwinfo = pLinkInfo; #ifdef INCLUDE_DALINIT_DEINIT if (NULL != ps_llc_ctxt->lower_if.release) { result = ps_llc_ctxt->lower_if.release( ps_llc_ctxt->lower_if.pcontext, pLinkInfo); } #endif if (NULL != ps_llc_ctxt->lower_if.transact_abort) { result = ps_llc_ctxt->lower_if.transact_abort( ps_llc_ctxt->lower_if.pcontext, pLinkInfo); } if (NULL != ps_llc_ctxt->lower_if.unregister) { result = ps_llc_ctxt->lower_if.unregister( ps_llc_ctxt->lower_if.pcontext, pLinkInfo); } /* Call the internal LLC timer un-initialise */ phLlcNfc_TimerUnInit(ps_llc_ctxt); phLlcNfc_H_Frame_DeInit(&ps_llc_ctxt->s_frameinfo); (void)memset(ps_llc_ctxt, 0, sizeof(phLlcNfc_Context_t)); phOsalNfc_FreeMemory(ps_llc_ctxt); ps_llc_ctxt = NULL; #ifdef LLC_RELEASE_FLAG g_release_flag = TRUE; #endif /* #ifdef LLC_RELEASE_FLAG */ } PH_LLCNFC_DEBUG("Llc release result : 0x%04X\n", result); return result; } static NFCSTATUS phLlcNfc_Send ( void *pContext, void *pLinkInfo, uint8_t *pLlcBuf, uint16_t llcBufLength ) { /* 1. Check the function parameters for valid values 2. Create the I frame llc payload using the upper layer buffer 3. Send the updated buffer to the below layer 4. Store the I frame in a list, till acknowledge is received */ NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Context_t *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext; phLlcNfc_Frame_t *ps_frame_info = NULL; phLlcNfc_LlcPacket_t s_packet_info; phLlcNfc_StoreIFrame_t *ps_store_frame = NULL; #if 0 uint8_t count = 1; #endif /* #if 0 */ PH_LLCNFC_PRINT ("Llc Send called\n"); if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo) || (NULL == pLlcBuf) || (0 == llcBufLength) || (llcBufLength > PH_LLCNFC_MAX_IFRAME_BUFLEN)) { /* Parameter check failed */ result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else if (ps_llc_ctxt->s_frameinfo.s_send_store.winsize_cnt >= ps_llc_ctxt->s_frameinfo.window_size) { /* Window size check failed */ result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED); } else { ps_frame_info = &(ps_llc_ctxt->s_frameinfo); ps_store_frame = &(ps_frame_info->s_send_store); PH_LLCNFC_DEBUG ("Buffer length : 0x%04X\n", llcBufLength); PH_LLCNFC_PRINT_BUFFER (pLlcBuf, llcBufLength); /* Copy the hardware information */ ps_llc_ctxt->phwinfo = pLinkInfo; /* Create I frame with the user buffer */ (void)phLlcNfc_H_CreateIFramePayload ( &(ps_llc_ctxt->s_frameinfo), &s_packet_info, pLlcBuf, (uint8_t)llcBufLength); /* Store the I frame in the send list */ (void)phLlcNfc_H_StoreIFrame (ps_store_frame, s_packet_info); result = NFCSTATUS_PENDING; #ifdef CTRL_WIN_SIZE_COUNT /* No check required */ if ((TRUE != ps_frame_info->write_pending) && (PH_LLCNFC_READPEND_REMAIN_BYTE != ps_frame_info->read_pending)) #else /* #ifdef CTRL_WIN_SIZE_COUNT */ if (1 == ps_frame_info->s_send_store.winsize_cnt) #endif /* #ifdef CTRL_WIN_SIZE_COUNT */ { /* Call write to the below layer, only if previous write is completed */ result = phLlcNfc_Interface_Write (ps_llc_ctxt, (uint8_t *)&(s_packet_info.s_llcbuf), (uint32_t)s_packet_info.llcbuf_len); if ((NFCSTATUS_PENDING == result) || (NFCSTATUS_BUSY == PHNFCSTATUS (result))) { ps_frame_info->write_status = result; if (NFCSTATUS_BUSY == PHNFCSTATUS(result)) { result = NFCSTATUS_PENDING; ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t) ((resend_i_frame == ps_frame_info->write_wait_call) ? ps_frame_info->write_wait_call : user_i_frame); } else { /* 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; } } #if 0 /* Get the added frame array count */ count = (uint8_t)((((ps_store_frame->start_pos + ps_store_frame->winsize_cnt) - count)) % PH_LLCNFC_MOD_NS_NR); #endif /* #if 0 */ } else { ps_frame_info->write_status = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_BUSY); ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t) ((resend_i_frame == ps_frame_info->write_wait_call) ? ps_frame_info->write_wait_call : user_i_frame); } } PH_LLCNFC_DEBUG ("Llc Send result : 0x%04X\n", result); return result; } static NFCSTATUS phLlcNfc_Receive ( void *pContext, void *pLinkInfo, uint8_t *pLlcBuf, uint16_t llcBufLength ) { NFCSTATUS result = NFCSTATUS_SUCCESS; phLlcNfc_Context_t *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext; phLlcNfc_LlcPacket_t *ps_recv_pkt = NULL; PH_LLCNFC_PRINT("Llc Receive called\n"); if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo) || (NULL == pLlcBuf) || (0 == llcBufLength) || (llcBufLength > PH_LLCNFC_MAX_IFRAME_BUFLEN)) { result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER); } else { ps_llc_ctxt->phwinfo = pLinkInfo; ps_recv_pkt = &(ps_llc_ctxt->s_frameinfo.s_recvpacket); /* Always read the first byte to read the length, then read the entire data later using the 1 byte buffer */ llcBufLength = PH_LLCNFC_BYTES_INIT_READ; /* Call write to the below layer */ result = phLlcNfc_Interface_Read(ps_llc_ctxt, PH_LLCNFC_READWAIT_OFF, &(ps_recv_pkt->s_llcbuf.llc_length_byte), llcBufLength); ps_llc_ctxt->s_frameinfo.upper_recv_call = TRUE; if (NFCSTATUS_PENDING != result) { ps_llc_ctxt->state = phLlcNfc_Initialised_State; } } PH_LLCNFC_DEBUG("Llc Receive result : 0x%04X\n", result); return result; }