| /* |
| * 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; |
| } |