diff options
Diffstat (limited to 'src/phLlcNfc.c')
-rw-r--r-- | src/phLlcNfc.c | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/src/phLlcNfc.c b/src/phLlcNfc.c new file mode 100644 index 0000000..af0a3a1 --- /dev/null +++ b/src/phLlcNfc.c @@ -0,0 +1,520 @@ +/* + * 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 *ps_packet_info = NULL; + + 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_packet_info = &(ps_llc_ctxt->s_frameinfo.s_llcpacket); + + 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, + ps_packet_info, + &(ps_packet_info->llcbuf_len), + phLlcNfc_e_rset); + } + if (NFCSTATUS_SUCCESS == result) + { + /* Call DAL write */ + result = phLlcNfc_Interface_Write(ps_llc_ctxt, + (uint8_t*)&(ps_packet_info->s_llcbuf), + (uint32_t)ps_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 *ps_packet_info = NULL, + 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); + + ps_packet_info = &(ps_frame_info->s_llcpacket); + + /* 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 */ + { + (void)memcpy ((void *)ps_packet_info, (void *)&s_packet_info, + sizeof(phLlcNfc_LlcPacket_t)); + /* Call write to the below layer, only if previous write + is completed */ + result = phLlcNfc_Interface_Write (ps_llc_ctxt, + (uint8_t *)&(ps_packet_info->s_llcbuf), + (uint32_t)ps_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; +} |