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