diff options
author | Nick Pelly <npelly@google.com> | 2010-09-23 12:47:58 -0700 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2010-09-23 13:53:18 -0700 |
commit | 5d9927ba30ba449badb9f6df0fbeb4d6aedc6e2a (patch) | |
tree | 190f9251c6db03d3550ec7f30b51a2561c01d9cf /src/phFriNfc_LlcpTransport_Connection.c | |
parent | 4ff7c86a2c706b150078274455406f1b04966e1a (diff) | |
download | external_libnfc-nxp-5d9927ba30ba449badb9f6df0fbeb4d6aedc6e2a.zip external_libnfc-nxp-5d9927ba30ba449badb9f6df0fbeb4d6aedc6e2a.tar.gz external_libnfc-nxp-5d9927ba30ba449badb9f6df0fbeb4d6aedc6e2a.tar.bz2 |
Initial libnfc checkin
Source: Trusted_NFC_Device_Host_AA03.01e02_google.zip code drop (23-Sep-2010)
Change-Id: Ie47f18423f949a8d3e0815d13f55c814312add24
Signed-off-by: Nick Pelly <npelly@google.com>
Diffstat (limited to 'src/phFriNfc_LlcpTransport_Connection.c')
-rw-r--r-- | src/phFriNfc_LlcpTransport_Connection.c | 2765 |
1 files changed, 2765 insertions, 0 deletions
diff --git a/src/phFriNfc_LlcpTransport_Connection.c b/src/phFriNfc_LlcpTransport_Connection.c new file mode 100644 index 0000000..314204c --- /dev/null +++ b/src/phFriNfc_LlcpTransport_Connection.c @@ -0,0 +1,2765 @@ +/* + * 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 phFriNfc_LlcpTransport_Connection.c + * \brief + * + * Project: NFC-FRI + * + */ +/*include files*/ +#include <phLibNfcStatus.h> +#include <phLibNfc.h> +#include <phNfcLlcpTypes.h> +#include <phFriNfc_LlcpTransport.h> +#include <phFriNfc_LlcpTransport_Connection.h> +#include <phFriNfc_Llcp.h> +#include <phFriNfc_LlcpUtils.h> + + +/* Function definition */ +static NFCSTATUS phFriNfc_Llcp_Send_DisconnectMode_Frame(phFriNfc_LlcpTransport_t* psTransport, + uint8_t dsap, + uint8_t ssap, + uint8_t dmOpCode); + +static NFCSTATUS phFriNfc_Llcp_Send_ReceiveReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket); + +static NFCSTATUS phFriNfc_Llcp_Send_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket); + +/********** End Function definition ***********/ + +/* TODO: comment functionphFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB */ +static void phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB(void* pContext, + NFCSTATUS status) +{ + phFriNfc_LlcpTransport_t *psTransport; + phFriNfc_LlcpTransport_Socket_t psTempLlcpSocket; + phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; + phNfc_sData_t sFrmrBuffer; + uint8_t index; + uint8_t socketFound = FALSE; + + /* Get Send CB context */ + psTransport = (phFriNfc_LlcpTransport_t*)pContext; + + /* Reset the FLAG send pending*/ + psTransport->bSendPending = FALSE; + + if(status == NFCSTATUS_SUCCESS) + { + if(psTransport->bFrmrPending) + { + /* Reset FRMR pending */ + psTransport->bFrmrPending = FALSE; + + /* Send Frmr */ + sFrmrBuffer.buffer = psTransport->FrmrInfoBuffer; + sFrmrBuffer.length = 0x04; /* Size of FRMR Information field */ + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psTransport->sLlcpHeader, + NULL, + &sFrmrBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + } + else if(psTransport->bDmPending) + { + /* Reset DM pending */ + psTransport->bDmPending = FALSE; + + /* Send DM pending */ + status = phFriNfc_Llcp_Send_DisconnectMode_Frame(psTransport, + psTransport->DmInfoBuffer[0], + psTransport->DmInfoBuffer[1], + psTransport->DmInfoBuffer[2]); + } + + + /* Test the socket */ + switch(psTransport->pSocketTable[psTransport->socketIndex].eSocket_State) + { + case phFriNfc_LlcpTransportSocket_eSocketAccepted: + { + /* Set socket state to Connected */ + psTransport->pSocketTable[psTransport->socketIndex].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnected; + /* Call the Accept Callback */ + psTransport->pSocketTable[psTransport->socketIndex].pfSocketAccept_Cb(psTransport->pSocketTable[psTransport->socketIndex].pAcceptContext,status); + }break; + + case phFriNfc_LlcpTransportSocket_eSocketRejected: + { + /* Store the Llcp socket in a local Llcp socket */ + psTempLlcpSocket = psTransport->pSocketTable[psTransport->socketIndex]; + + /* Reset the socket and set the socket state to default */ + status = phFriNfc_LlcpTransport_Close(&psTransport->pSocketTable[psTransport->socketIndex]); + + /* Call the Reject Callback */ + psTempLlcpSocket.pfSocketSend_Cb(psTempLlcpSocket.pRejectContext,status); + }break; + + case phFriNfc_LlcpTransportSocket_eSocketConnected: + { + if(psTransport->pSocketTable[psTransport->socketIndex].sLlcpHeader.ptype == PHFRINFC_LLCP_PTYPE_I && psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb != NULL) + { + psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb(psTransport->pSocketTable[psTransport->socketIndex].pSendContext,status); + if(psTransport->pSocketTable[psTransport->socketIndex].bSocketSendPending != TRUE) + { + psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb = NULL; + } + } + }break; + } + + + /* Update Index value with the next socket */ + index = psTransport->socketIndex+1; + + /* Search for a socket with a flag Pending */ + do + { + if(index >= PHFRINFC_LLCP_NB_SOCKET_MAX) + { + index = 0; + } + + if(psTransport->pSocketTable[index].bSocketAcceptPending == TRUE + || psTransport->pSocketTable[index].bSocketConnectPending == TRUE + || psTransport->pSocketTable[index].bSocketDiscPending == TRUE + || psTransport->pSocketTable[index].bSocketRNRPending == TRUE + || psTransport->pSocketTable[index].bSocketRRPending == TRUE + || psTransport->pSocketTable[index].bSocketSendPending == TRUE + || psTransport->pSocketTable[index].pfSocketSend_Cb != NULL) + { + /* socket found */ + socketFound = TRUE; + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + else + { + if(index == psTransport->socketIndex) + { + break; + } + else + { + index ++; + } + } + }while(index != ((psTransport->socketIndex+1)%PHFRINFC_LLCP_NB_SOCKET_MAX)); + + + if(socketFound == TRUE) + { + socketFound = FALSE; + /* perform the command pending */ + + /* I FRAME */ + if(psLocalLlcpSocket->bSocketSendPending == TRUE) + { + /* Test the RW window */ + if(psLocalLlcpSocket->socket_VS != (psLocalLlcpSocket->socket_VSA + psLocalLlcpSocket->remoteRW)) + { + /* Set the Header */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + psLocalLlcpSocket->sSequence.ns = psLocalLlcpSocket->socket_VS; + psLocalLlcpSocket->sSequence.nr = psLocalLlcpSocket->socket_VR; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index ; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + &psLocalLlcpSocket->sSequence, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Update VS */ + psLocalLlcpSocket->socket_VS = (psLocalLlcpSocket->socket_VS+1)%16; + + /* Reset Send Pending Flag */ + psLocalLlcpSocket->bSocketSendPending = FALSE; + } + } + /* RR FRAME */ + else if(psLocalLlcpSocket->bSocketRRPending == TRUE) + { + /* Reset RR pending */ + psLocalLlcpSocket->bSocketRRPending = FALSE; + + /* Send RR Frame */ + status = phFriNfc_Llcp_Send_ReceiveReady_Frame(psLocalLlcpSocket); + } + + /* RNR Frame */ + else if(psLocalLlcpSocket->bSocketRNRPending == TRUE) + { + /* Reset RNR pending */ + psLocalLlcpSocket->bSocketRNRPending = FALSE; + + /* Send RNR Frame */ + status = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(psLocalLlcpSocket); + } + /* CC Frame */ + else if(psLocalLlcpSocket->bSocketAcceptPending == TRUE) + { + /* Reset Accept pending */ + psLocalLlcpSocket->bSocketAcceptPending = FALSE; + + /* Fill the psLlcpHeader stuture with the DSAP,CC PTYPE and the SSAP */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CC; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Set the socket state to accepted */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketAccepted; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Send a CC Frame */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + NULL, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + } + /* CONNECT FRAME */ + else if(psLocalLlcpSocket->bSocketConnectPending == TRUE) + { + /* Reset Accept pending */ + psLocalLlcpSocket->bSocketConnectPending = FALSE; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Set the socket in connecting state */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnecting; + + /* send CONNECT */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + NULL, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + } + /* DISC FRAME */ + else if(psLocalLlcpSocket->bSocketDiscPending == TRUE) + { + /* Reset Disc Pending */ + psLocalLlcpSocket->bSocketDiscPending = FALSE; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Set the socket in connecting state */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Send DISC */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + NULL, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Call ErrCB due to a DISC */ + psLocalLlcpSocket->pSocketErrCb(psLocalLlcpSocket->pContext, PHFRINFC_LLCP_ERR_DISCONNECTED); + } + /* Call SEND IFRAME CB */ + else if(psLocalLlcpSocket->pfSocketSend_Cb != NULL) + { + psLocalLlcpSocket->pfSocketSend_Cb(psLocalLlcpSocket->pSendContext,status); + if(psTransport->pSocketTable[psTransport->socketIndex].bSocketSendPending != TRUE) + { + psLocalLlcpSocket->pfSocketSend_Cb = NULL; + } + } + } + /* Reset the current length of the send buffer */ + //psTransport->pSocketTable[psTransport->socketIndex].sSocketSendBuffer.length = psTransport->pSocketTable[psTransport->socketIndex].bufferSendMaxLength; + } + else + { + /* Send CB error */ + } +} + +static NFCSTATUS phFriNfc_Llcp_Send_DisconnectMode_Frame(phFriNfc_LlcpTransport_t* psTransport, + uint8_t dsap, + uint8_t ssap, + uint8_t dmOpCode) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + phFriNfc_Llcp_sPacketHeader_t sLocalLlcpHeader; + uint8_t dmValue; + phNfc_sData_t sLocalBuffer; + + /* Test if a send is pending */ + if(psTransport->bSendPending) + { + /* DM pending */ + psTransport->bDmPending = TRUE; + + /* Store DM Info */ + psTransport->DmInfoBuffer[0] = dsap; + psTransport->DmInfoBuffer[1] = ssap; + psTransport->DmInfoBuffer[2] = dmOpCode; + + status = NFCSTATUS_PENDING; + } + else + { + /* Store the DM OpCode */ + dmValue = dmOpCode; + + /* Set the header */ + sLocalLlcpHeader.dsap = dsap; + sLocalLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_DM; + sLocalLlcpHeader.ssap = ssap; + + sLocalBuffer.buffer = &dmValue; + sLocalBuffer.length = PHFRINFC_LLCP_DM_LENGTH; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Send DM frame */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &sLocalLlcpHeader, + NULL, + &sLocalBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + } + + return status; +} + +static NFCSTATUS phFriNfc_Llcp_Send_ReceiveReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + /* Test if a send is pending */ + if(pLlcpSocket->psTransport->bSendPending == TRUE) + { + pLlcpSocket->bSocketRRPending = TRUE; + status = NFCSTATUS_PENDING; + } + else + { + /* Set the header of the RR frame */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_RR; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* Set sequence number for RR Frame */ + pLlcpSocket->sSequence.ns = 0; + pLlcpSocket->sSequence.nr = pLlcpSocket->socket_VR; + + /* Update VRA */ + pLlcpSocket->socket_VRA = (uint8_t)pLlcpSocket->sSequence.nr; + + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Send RR frame */ + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + &pLlcpSocket->sSequence, + NULL, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + } + + return status; +} + +static NFCSTATUS phFriNfc_Llcp_Send_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + + /* Test if a send is pending */ + if(pLlcpSocket->psTransport->bSendPending == TRUE) + { + pLlcpSocket->bSocketRNRPending = TRUE; + status = NFCSTATUS_PENDING; + } + else + { + /* Set the header of the RNR frame */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_RNR; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* Set sequence number for RNR Frame */ + pLlcpSocket->sSequence.ns = 0x00; + pLlcpSocket->sSequence.nr = pLlcpSocket->socket_VR; + + /* Update VRA */ + pLlcpSocket->socket_VRA = (uint8_t)pLlcpSocket->sSequence.nr; + + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Send RNR frame */ + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + &pLlcpSocket->sSequence, + NULL, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + } + return status; +} + +static NFCSTATUS phFriNfc_Llcp_Send_FrameReject_Frame(phFriNfc_LlcpTransport_t *psTransport, + uint8_t dsap, + uint8_t rejectedPTYPE, + uint8_t ssap, + phFriNfc_Llcp_sPacketSequence_t* sLlcpSequence, + uint8_t WFlag, + uint8_t IFlag, + uint8_t RFlag, + uint8_t SFlag, + uint8_t vs, + uint8_t vsa, + uint8_t vr, + uint8_t vra) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + phNfc_sData_t sFrmrBuffer; + uint8_t flagValue; + uint8_t sequence; + uint8_t index; + uint8_t socketFound = FALSE; + + /* Search a socket waiting for a FRAME */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ + if(psTransport->pSocketTable[index].socket_sSap == dsap + && psTransport->pSocketTable[index].socket_dSap == ssap) + { + /* socket found */ + socketFound = TRUE; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Set socket state to disconnected */ + psTransport->pSocketTable[index].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; + + /* Call ErrCB due to a FRMR*/ + psTransport->pSocketTable[index].pSocketErrCb( psTransport->pSocketTable[index].pContext,PHFRINFC_LLCP_ERR_FRAME_REJECTED); + + /* Close the socket */ + status = phFriNfc_LlcpTransport_ConnectionOriented_Close(&psTransport->pSocketTable[index]); + + /* Set FRMR Header */ + psTransport->sLlcpHeader.dsap = dsap; + psTransport->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_FRMR; + psTransport->sLlcpHeader.ssap = ssap; + + /* Set FRMR Information Field */ + flagValue = (WFlag<<7) | (IFlag<<6) | (RFlag<<5) | (SFlag<<4) | rejectedPTYPE; + sequence = (uint8_t)((sLlcpSequence->ns<<4)|(sLlcpSequence->nr)); + + psTransport->FrmrInfoBuffer[0] = flagValue; + psTransport->FrmrInfoBuffer[1] = sequence; + psTransport->FrmrInfoBuffer[2] = (vs<<4)|vr ; + psTransport->FrmrInfoBuffer[3] = (vsa<<4)|vra ; + + /* Test if a send is pending */ + if(psTransport->bSendPending) + { + psTransport->bFrmrPending = TRUE; + status = NFCSTATUS_PENDING; + } + else + { + sFrmrBuffer.buffer = psTransport->FrmrInfoBuffer; + sFrmrBuffer.length = 0x04; /* Size of FRMR Information field */ + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Send FRMR frame */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psTransport->sLlcpHeader, + NULL, + &sFrmrBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + } + } + else + { + /* No active socket*/ + /* FRMR Frame not handled*/ + } + return status; +} + +static NFCSTATUS phFriNfc_Llcp_GetSocket_Params(phNfc_sData_t *psParamsTLV, + phNfc_sData_t *psServiceName, + uint8_t *pRemoteRW_Size, + uint16_t *pRemoteMIU) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + phNfc_sData_t sValueBuffer; + uint32_t offset = 0; + uint8_t type; + + /* Check for NULL pointers */ + if ((psParamsTLV == NULL) || (pRemoteRW_Size == NULL) || (pRemoteMIU == NULL)) + { + return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER); + } + else + { + /* Decode TLV */ + while (offset < psParamsTLV->length) + { + status = phFriNfc_Llcp_DecodeTLV(psParamsTLV, &offset, &type,&sValueBuffer); + if (status != NFCSTATUS_SUCCESS) + { + /* Error: Ill-formed TLV */ + return status; + } + switch(type) + { + case PHFRINFC_LLCP_TLV_TYPE_SN: + { + /* Test if a SN is present in the TLV */ + if(sValueBuffer.length == 0) + { + /* Error : Ill-formed SN parameter TLV */ + return PHNFCSTVAL(CID_FRI_NFC_LLCP,NFCSTATUS_INVALID_PARAMETER); + } + /* Get the Service Name */ + *psServiceName = sValueBuffer; + }break; + + case PHFRINFC_LLCP_TLV_TYPE_RW: + { + /* Check length */ + if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_RW) + { + /* Error : Ill-formed MIUX parameter TLV */ + return PHNFCSTVAL(CID_FRI_NFC_LLCP,NFCSTATUS_INVALID_PARAMETER); + } + *pRemoteRW_Size = sValueBuffer.buffer[0]; + }break; + + case PHFRINFC_LLCP_TLV_TYPE_MIUX: + { + /* Check length */ + if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_MIUX) + { + /* Error : Ill-formed MIUX parameter TLV */ + return PHNFCSTVAL(CID_FRI_NFC_LLCP,NFCSTATUS_INVALID_PARAMETER); + } + *pRemoteMIU = PHFRINFC_LLCP_MIU_DEFAULT + (((sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1]) & PHFRINFC_LLCP_TLV_MIUX_MASK); + }break; + } + } + } + return status; +} + + +/* TODO: comment function Handle_ConnectFrame */ +static void Handle_ConnectionFrame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + uint8_t index; + uint8_t socketFound = FALSE; + phFriNfc_LlcpTransport_Socket_t *pLlcpSocket = NULL; + phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; + pphFriNfc_LlcpTransportSocketListenCb_t pListen_Cb = NULL; + void *pListenContext = NULL; + + phNfc_sData_t sServiceName; + uint8_t remoteRW = PHFRINFC_LLCP_RW_DEFAULT; + uint16_t remoteMIU = PHFRINFC_LLCP_MIU_DEFAULT; + + status = phFriNfc_Llcp_GetSocket_Params(psData, + &sServiceName, + &remoteRW, + &remoteMIU); + + if(status != NFCSTATUS_SUCCESS) + { + /* Incorrect TLV */ + /* send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, + PHFRINFC_LLCP_PTYPE_CONNECT, + dsap, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00); + } + else + { + if(dsap == PHFRINFC_LLCP_SAP_SDP) + { + /* Search a socket with the SN */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in Listen state and if its SN is the good one */ + if(psTransport->pSocketTable[index].bSocketListenPending + && (sServiceName.length == psTransport->pSocketTable[index].pServiceName->length) + && !memcmp(sServiceName.buffer,psTransport->pSocketTable[index].pServiceName->buffer,sServiceName.length)) + { + /* socket with the SN found */ + socketFound = TRUE; + + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + + /* Get the new ssap number, it is the ssap number of the socket found */ + dsap = psLocalLlcpSocket->socket_sSap; + /* Get the ListenCB of the socket */ + pListen_Cb = psLocalLlcpSocket->pfSocketListen_Cb; + pListenContext = psLocalLlcpSocket->pListenContext; + break; + } + } + } + else + { + /* Search a socket with the DSAP */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in Listen state and if its port number is the good one */ + if(psTransport->pSocketTable[index].bSocketListenPending && psTransport->pSocketTable[index].socket_sSap == dsap) + { + /* socket with the SN found */ + socketFound = TRUE; + + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + + /* Get the Listen CB and the Context of the socket */ + pListen_Cb = psLocalLlcpSocket->pfSocketListen_Cb; + pListenContext = psLocalLlcpSocket->pListenContext; + break; + } + } + } + } + + /* Test if a socket has beeen found */ + if(socketFound) + { + /* Reset the FLAG socketFound*/ + socketFound = FALSE; + + /* Search a socket free and no socket connect on this DSAP*/ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + if(psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDefault && socketFound != TRUE) + { + socketFound = TRUE; + + psTransport->pSocketTable[index].index = index; + psTransport->socketIndex = psTransport->pSocketTable[index].index; + + /* Create a communication socket */ + pLlcpSocket = &psTransport->pSocketTable[index]; + + /* Set the communication option of the Remote Socket */ + pLlcpSocket->remoteMIU = remoteMIU; + pLlcpSocket->remoteRW = remoteRW; + + /* Set SSAP/DSAP of the new socket created for the communication with the remote */ + pLlcpSocket->socket_dSap = ssap; + pLlcpSocket->socket_sSap = dsap; + + /* Set the state and the type of the new socket */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketBound; + pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eConnectionOriented; + + } + else if(((psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) + || (psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketAccepted)) + && ((psTransport->pSocketTable[index].socket_sSap == ssap)&&(psTransport->pSocketTable[index].socket_dSap == dsap))) + + { + socketFound = FALSE; + + if(pLlcpSocket != NULL) + { + /* Reset Socket Information */ + pLlcpSocket->remoteMIU = 0; + pLlcpSocket->remoteRW = 0; + + /* Set SSAP/DSAP of the new socket created for the communication with the remote */ + pLlcpSocket->socket_dSap = 0; + pLlcpSocket->socket_sSap = 0; + + /* Set the state and the type of the new socket */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; + pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; + break; + } + } + } + + + + /* Test if a socket has been found */ + if(socketFound) + { + /* Call the Listen CB */ + pListen_Cb(pListenContext,pLlcpSocket); + } + else + { + /* No more socket are available */ + /* Send a DM (0x21) */ + status = phFriNfc_Llcp_Send_DisconnectMode_Frame (psTransport, + ssap, + dsap, + PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE); + } + } + else + { + /* Service Name not found or Port number not found */ + /* Send a DM (0x02) */ + status = phFriNfc_Llcp_Send_DisconnectMode_Frame (psTransport, + ssap, + dsap, + PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND); + } +} + +/* TODO: comment function Handle_ConnectFrame */ +static void Handle_ConnectionCompleteFrame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t remoteRW = PHFRINFC_LLCP_RW_DEFAULT; + uint16_t remoteMIU = PHFRINFC_LLCP_MIU_DEFAULT; + uint8_t socketFound = FALSE; + phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; + + status = phFriNfc_Llcp_GetSocket_Params(psData, + NULL, + &remoteRW, + &remoteMIU); + + if(status != NFCSTATUS_SUCCESS) + { + /* Incorrect TLV */ + /* send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, + PHFRINFC_LLCP_PTYPE_CC, + dsap, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00); + } + else + { + /* Search a socket in connecting state and with the good SSAP */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in Connecting state and if its SSAP number is the good one */ + if(psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnecting + && psTransport->pSocketTable[index].socket_sSap == dsap) + { + /* socket with the SN found */ + socketFound = TRUE; + + /* Update the DSAP value with the incomming Socket sSap */ + psTransport->pSocketTable[index].socket_dSap = ssap; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + } + /* Test if a socket has been found */ + if(socketFound) + { + /* Set the socket state to connected */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnected; + + /* Reset the socket_VS,socket_VR,socket_VSA and socket_VRA variables */ + psLocalLlcpSocket->socket_VR = 0; + psLocalLlcpSocket->socket_VRA = 0; + psLocalLlcpSocket->socket_VS = 0; + psLocalLlcpSocket->socket_VSA = 0; + + /* Store the Remote parameters (MIU,RW) */ + psLocalLlcpSocket->remoteMIU = remoteMIU; + psLocalLlcpSocket->remoteRW = remoteRW; + + /* Call the Connect CB */ + psLocalLlcpSocket->pfSocketConnect_Cb(psLocalLlcpSocket->pConnectContext,0x00,NFCSTATUS_SUCCESS); + } + else + { + /* No socket Active */ + /* CC Frame not handled */ + } + } +} + +/* TODO: comment function Handle_DisconnectFrame */ +static void Handle_DisconnectFrame(phFriNfc_LlcpTransport_t *psTransport, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t socketFound = FALSE; + phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; + + /* Search a socket in connected state and the good SSAP */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in Connected state and if its SSAP number is the good one */ + if(psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected + && psTransport->pSocketTable[index].socket_sSap == dsap) + { + /* socket found */ + socketFound = TRUE; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Test if a send IFRAME is pending with this socket */ + if((psLocalLlcpSocket->bSocketSendPending == TRUE) || (psLocalLlcpSocket->bSocketRecvPending == TRUE)) + { + /* Call the send CB, a disconnect abort the send request */ + if (psLocalLlcpSocket->pfSocketSend_Cb != NULL && psLocalLlcpSocket->bSocketSendPending == TRUE) + { + /* Copy CB + context in local variables */ + pphFriNfc_LlcpTransportSocketSendCb_t pfSendCb = psLocalLlcpSocket->pfSocketSend_Cb; + void* pSendContext = psLocalLlcpSocket->pSendContext; + /* Reset CB + context */ + psLocalLlcpSocket->pfSocketSend_Cb = NULL; + psLocalLlcpSocket->pSendContext = NULL; + /* Perform callback */ + pfSendCb(pSendContext, NFCSTATUS_FAILED); + } + /* Call the send CB, a disconnect abort the receive request */ + if (psLocalLlcpSocket->pfSocketRecv_Cb != NULL && psLocalLlcpSocket->bSocketRecvPending == TRUE) + { + /* Copy CB + context in local variables */ + pphFriNfc_LlcpTransportSocketRecvCb_t pfRecvCb = psLocalLlcpSocket->pfSocketRecv_Cb; + void* pRecvContext = psLocalLlcpSocket->pRecvContext; + /* Reset CB + context */ + psLocalLlcpSocket->pfSocketRecv_Cb = NULL; + psLocalLlcpSocket->pRecvContext = NULL; + /* Perform callback */ + pfRecvCb(pRecvContext, NFCSTATUS_FAILED); + } + psLocalLlcpSocket->bSocketRecvPending = FALSE; + psLocalLlcpSocket->bSocketSendPending = FALSE; + } + + /* Test if a send is pending with this scoket */ + if(psTransport->bSendPending) + { + /* Set DM pending */ + psTransport->bDmPending = TRUE; + + /* Set the socket disconnecting */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; + + /* Send pending, store the DISC request */ + psTransport->DmInfoBuffer[0] = ssap; + psTransport->DmInfoBuffer[1] = dsap; + psTransport->DmInfoBuffer[2] = PHFRINFC_LLCP_DM_OPCODE_DISCONNECTED; + } + else + { + /* Set the socket disconnected */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Send a DM*/ + status = phFriNfc_Llcp_Send_DisconnectMode_Frame(psTransport, + ssap, + dsap, + PHFRINFC_LLCP_DM_OPCODE_DISCONNECTED); + + /* Call ErrCB due to a DISC */ + psTransport->pSocketTable[index].pSocketErrCb(psTransport->pSocketTable[index].pContext, PHFRINFC_LLCP_ERR_DISCONNECTED); + } + } + else + { + /* No socket Active */ + /* DISC Frame not handled */ + } +} + +/* TODO: comment function Handle_ConnectFrame */ +static void Handle_DisconnetModeFrame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t socketFound = FALSE; + uint8_t dmOpCode; + phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; + + /* Test if the DM buffer is correct */ + if(psData->length != PHFRINFC_LLCP_DM_LENGTH) + { + /* send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, + PHFRINFC_LLCP_PTYPE_DM, + dsap, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00); + } + else + { + /* Search a socket waiting for a DM (Disconnecting State) */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in Disconnecting or connecting state and if its SSAP number is the good one */ + if((psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDisconnecting + || psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnecting) + && psTransport->pSocketTable[index].socket_sSap == dsap) + { + /* socket found */ + socketFound = TRUE; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Set dmOpcode */ + dmOpCode = psData->buffer[0]; + + switch(dmOpCode) + { + case PHFRINFC_LLCP_DM_OPCODE_DISCONNECTED: + { + /* Set the socket state to disconnected */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; + + /* Call Disconnect CB */ + if (psLocalLlcpSocket->pfSocketDisconnect_Cb != NULL) + { + psLocalLlcpSocket->pfSocketDisconnect_Cb(psLocalLlcpSocket->pDisonnectContext,NFCSTATUS_SUCCESS); + } + + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + /* Set the socket state to bound */ + psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; + if(psLocalLlcpSocket->pfSocketConnect_Cb != NULL) + { + /* Call Connect CB */ + psLocalLlcpSocket->pfSocketConnect_Cb(psLocalLlcpSocket->pConnectContext,dmOpCode,NFCSTATUS_FAILED); + } + }break; + } + } + } +} + +/* TODO: comment function Handle_Receive_IFrame */ +static void Handle_Receive_IFrame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; + phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; + + uint32_t dataLengthAvailable = 0; + uint32_t dataLengthWrite = 0; + uint8_t index; + uint8_t socketFound = FALSE; + uint8_t WFlag = 0; + uint8_t IFlag = 0; + uint8_t RFlag = 0; + uint8_t SFlag = 0; + uint8_t nr_val; + uint32_t offset = 0; + uint32_t rw_offset; + + /* Get NS and NR Value of the I Frame*/ + phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); + + + /* Update the buffer pointer */ + psData->buffer = psData->buffer + PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE; + + /* Update the length value (without the header length) */ + psData->length = psData->length - PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE; + + /* Search a socket waiting for an I FRAME (Connected State) */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ + if(( (psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) + || (psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketAccepted)) + && psTransport->pSocketTable[index].socket_sSap == dsap + && psTransport->pSocketTable[index].socket_dSap == ssap) + { + /* socket found */ + socketFound = TRUE; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Test NS */ + /*if(sLlcpLocalSequence.ns != psLocalLlcpSocket->socket_VR) + { + SFlag = TRUE; + }*/ + + /* Calculate offset of current frame in RW, and check validity */ + if(sLlcpLocalSequence.ns >= psLocalLlcpSocket->socket_VRA) + { + rw_offset = sLlcpLocalSequence.ns - psLocalLlcpSocket->socket_VRA; + } + else + { + rw_offset = 16 - (psLocalLlcpSocket->socket_VRA - sLlcpLocalSequence.ns); + } + if(rw_offset >= psLocalLlcpSocket->localRW) + { + /* FRMR 0x01 */ + SFlag = TRUE; + } + + /* Check Info length */ + if(psData->length > (uint32_t)(psLocalLlcpSocket->localMIUX + PHFRINFC_LLCP_MIU_DEFAULT)) + { + IFlag = TRUE; + } + + + /* Test NR */ + nr_val = (uint8_t)sLlcpLocalSequence.nr; + do + { + if(nr_val == psLocalLlcpSocket->socket_VS) + { + break; + } + + nr_val = (nr_val+1)%16; + + if(nr_val == psLocalLlcpSocket->socket_VSA) + { + /* FRMR 0x02 */ + RFlag = TRUE; + break; + } + }while(nr_val != sLlcpLocalSequence.nr); + + + if( WFlag != 0 || IFlag != 0 || RFlag != 0 || SFlag != 0) + { + /* Send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, + PHFRINFC_LLCP_PTYPE_I, + dsap, + &sLlcpLocalSequence, + WFlag, + IFlag, + RFlag, + SFlag, + psLocalLlcpSocket->socket_VS, + psLocalLlcpSocket->socket_VSA, + psLocalLlcpSocket->socket_VR, + psLocalLlcpSocket->socket_VRA); + + } + else + { + /* Test if the Linear Buffer length is null */ + if(psLocalLlcpSocket->bufferLinearLength == 0) + { + /* Test if a Receive is pending and RW empty */ + if(psLocalLlcpSocket->bSocketRecvPending == TRUE && (psLocalLlcpSocket->indexRwWrite == psLocalLlcpSocket->indexRwRead)) + { + /* Reset Flag */ + psTransport->pSocketTable[psTransport->socketIndex].bSocketRecvPending = FALSE; + + /* Save I_FRAME into the Receive Buffer */ + memcpy(psLocalLlcpSocket->sSocketRecvBuffer->buffer,psData->buffer,psData->length); + psLocalLlcpSocket->sSocketRecvBuffer->length = psData->length; + + /* Update VR */ + psLocalLlcpSocket->socket_VR = (psLocalLlcpSocket->socket_VR+1)%16; + + /* Update VSA */ + psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; + + /* Call the Receive CB */ + psLocalLlcpSocket->pfSocketRecv_Cb(psLocalLlcpSocket->pRecvContext, NFCSTATUS_SUCCESS); + + /* Test if a send is pending with this socket */ + if(psLocalLlcpSocket->bSocketSendPending == TRUE && (psLocalLlcpSocket->socket_VS != (psLocalLlcpSocket->socket_VSA + psLocalLlcpSocket->remoteRW))) + { + /* Test if a send is pending at LLC layer */ + if(psTransport->bSendPending != TRUE) + { + /* Reset Send Pending */ + psLocalLlcpSocket->bSocketSendPending = FALSE; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Set the Header */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + psLocalLlcpSocket->sSequence.ns = psLocalLlcpSocket->socket_VS; + psLocalLlcpSocket->sSequence.nr = psLocalLlcpSocket->socket_VR; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + &psLocalLlcpSocket->sSequence, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Update VS */ + psLocalLlcpSocket->socket_VS = (psLocalLlcpSocket->socket_VS+1)%16; + } + } + else + { + /* RR */ + status = phFriNfc_Llcp_Send_ReceiveReady_Frame(psLocalLlcpSocket); + } + } + else + { + /* Test if RW is full */ + if((psLocalLlcpSocket->indexRwWrite - psLocalLlcpSocket->indexRwRead)<psLocalLlcpSocket->localRW) + { + if(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length == 0) + { + /* Save I_FRAME into the RW Buffers */ + memcpy(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer,psData->buffer,psData->length); + psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = psData->length; + + if(psLocalLlcpSocket->ReceiverBusyCondition != TRUE) + { + /* Receiver Busy condition */ + psLocalLlcpSocket->ReceiverBusyCondition = TRUE; + + /* Send RNR */ + status = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(psLocalLlcpSocket); + } + /* Update the RW write index */ + psLocalLlcpSocket->indexRwWrite++; + } + } + } + } + else + { + /* Copy the buffer into the RW buffer */ + memcpy(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer,psData->buffer,psData->length); + + /* Update the length */ + psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = psData->length; + + /* Test the length of the available place in the linear buffer */ + dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&psLocalLlcpSocket->sCyclicFifoBuffer); + + if(dataLengthAvailable >= psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length) + { + /* Store Data into the linear buffer */ + dataLengthWrite = phFriNfc_Llcp_CyclicFifoWrite(&psLocalLlcpSocket->sCyclicFifoBuffer, + psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer, + psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length); + + /* Update VR */ + psLocalLlcpSocket->socket_VR = (psLocalLlcpSocket->socket_VR+1)%16; + + /* Update VSA */ + psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; + + /* Update the length */ + psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = 0x00; + + /* Test if a Receive Pending*/ + if(psLocalLlcpSocket->bSocketRecvPending == TRUE) + { + /* Reset Flag */ + psLocalLlcpSocket->bSocketRecvPending = FALSE; + + phFriNfc_LlcpTransport_ConnectionOriented_Recv(psLocalLlcpSocket, + psLocalLlcpSocket->sSocketRecvBuffer, + psLocalLlcpSocket->pfSocketRecv_Cb, + psLocalLlcpSocket->pRecvContext); + } + + /* Test if a send is pending with this socket */ + if((psLocalLlcpSocket->bSocketSendPending == TRUE) && (psLocalLlcpSocket->socket_VS != (psLocalLlcpSocket->socket_VSA + psLocalLlcpSocket->remoteRW))) + { + /* Test if a send is pending at LLC layer */ + if(psTransport->bSendPending != TRUE) + { + /* Reset Send Pending */ + psLocalLlcpSocket->bSocketSendPending = FALSE; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Set the Header */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + psLocalLlcpSocket->sSequence.ns = psLocalLlcpSocket->socket_VS; + psLocalLlcpSocket->sSequence.nr = psLocalLlcpSocket->socket_VR; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + &psLocalLlcpSocket->sSequence, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Update VS */ + psLocalLlcpSocket->socket_VS = (psLocalLlcpSocket->socket_VS+1)%16; + } + } + else + { + /* RR */ + status = phFriNfc_Llcp_Send_ReceiveReady_Frame(psLocalLlcpSocket); + } + } + else + { + if(psLocalLlcpSocket->ReceiverBusyCondition != TRUE) + { + /* Receiver Busy condition */ + psLocalLlcpSocket->ReceiverBusyCondition = TRUE; + + /* Send RNR */ + status = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(psLocalLlcpSocket); + } + + /* Update the RW write index */ + psLocalLlcpSocket->indexRwWrite++; + } + } + } + } + else + { + /* No active socket*/ + /* I FRAME not Handled */ + } +} + +static void Handle_ReceiveReady_Frame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t socketFound = FALSE; + uint8_t WFlag = 0; + uint8_t IFlag = 0; + uint8_t RFlag = 0; + uint8_t SFlag = 0; + uint32_t offset = 0; + uint8_t nr_val; + + phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; + phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; + + /* Get NS and NR Value of the I Frame*/ + phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); + + /* Search a socket waiting for an RR FRAME (Connected State) */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ + if(psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected + && psTransport->pSocketTable[index].socket_sSap == dsap + && psTransport->pSocketTable[index].socket_dSap == ssap) + { + /* socket found */ + socketFound = TRUE; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + psLocalLlcpSocket->index = psTransport->pSocketTable[index].index; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Test NR */ + nr_val = (uint8_t)sLlcpLocalSequence.nr; + do + { + if(nr_val == psLocalLlcpSocket->socket_VS) + { + break; + } + + nr_val = (nr_val+1)%16; + + if(nr_val == psLocalLlcpSocket->socket_VSA) + { + RFlag = TRUE; + break; + } + + }while(nr_val != sLlcpLocalSequence.nr); + + + /* Test if Info field present */ + if(psData->length > 1) + { + WFlag = TRUE; + IFlag = TRUE; + } + + if (WFlag || IFlag || RFlag || SFlag) + { + /* Send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, PHFRINFC_LLCP_PTYPE_RR, dsap, + &sLlcpLocalSequence, + WFlag, IFlag, RFlag, SFlag, + psLocalLlcpSocket->socket_VS, + psLocalLlcpSocket->socket_VSA, + psLocalLlcpSocket->socket_VR, + psLocalLlcpSocket->socket_VRA); + } + else + { + /* Test Receiver Busy condition */ + if(psLocalLlcpSocket->RemoteBusyConditionInfo == TRUE) + { + /* Notify the upper layer */ + psLocalLlcpSocket->pSocketErrCb(psLocalLlcpSocket->pContext,PHFRINFC_LLCP_ERR_NOT_BUSY_CONDITION); + psLocalLlcpSocket->RemoteBusyConditionInfo = FALSE; + } + /* Update VSA */ + psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; + + /* Test if a send is pendind */ + if(psLocalLlcpSocket->bSocketSendPending == TRUE) + { + /* Test the RW window */ + if(psLocalLlcpSocket->socket_VS != (psLocalLlcpSocket->socket_VSA + psLocalLlcpSocket->remoteRW)) + { + /* Test if a send is pending at LLC layer */ + if(psTransport->bSendPending != TRUE) + { + /* Reset Send Pending */ + psLocalLlcpSocket->bSocketSendPending = FALSE;; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Set the Header */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + psLocalLlcpSocket->sSequence.ns = psLocalLlcpSocket->socket_VS; + psLocalLlcpSocket->sSequence.nr = psLocalLlcpSocket->socket_VR; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + &psLocalLlcpSocket->sSequence, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Update VS */ + psLocalLlcpSocket->socket_VS = (psLocalLlcpSocket->socket_VS+1)%16; + } + } + } + } + } + else + { + /* No active socket*/ + /* RR Frame not handled*/ + } +} + +static void Handle_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t socketFound = FALSE; + bool_t bWFlag = 0; + bool_t bIFlag = 0; + bool_t bRFlag = 0; + bool_t bSFlag = 0; + uint32_t offset = 0; + uint8_t nr_val; + + phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; + phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; + + /* Get NS and NR Value of the I Frame*/ + phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); + + /* Search a socket waiting for an RNR FRAME (Connected State) */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ + if(psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected + && psTransport->pSocketTable[index].socket_sSap == dsap + && psTransport->pSocketTable[index].socket_dSap == ssap) + { + /* socket found */ + socketFound = TRUE; + + /* Store a pointer to the socket found */ + psLocalLlcpSocket = &psTransport->pSocketTable[index]; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Test NR */ + nr_val = (uint8_t)sLlcpLocalSequence.nr; + do + { + + if(nr_val == psLocalLlcpSocket->socket_VS) + { + break; + } + + nr_val = (nr_val+1)%16; + + if(nr_val == psLocalLlcpSocket->socket_VSA) + { + /* FRMR 0x02 */ + bRFlag = TRUE; + break; + } + }while(nr_val != sLlcpLocalSequence.nr); + + /* Test if Info field present */ + if(psData->length > 1) + { + /* Send FRMR */ + bWFlag = TRUE; + bIFlag = TRUE; + } + + if( bWFlag != 0 || bIFlag != 0 || bRFlag != 0 || bSFlag != 0) + { + /* Send FRMR */ + status = phFriNfc_Llcp_Send_FrameReject_Frame(psTransport, + ssap, PHFRINFC_LLCP_PTYPE_RNR, dsap, + &sLlcpLocalSequence, + bWFlag, bIFlag, bRFlag, bSFlag, + psLocalLlcpSocket->socket_VS, + psLocalLlcpSocket->socket_VSA, + psLocalLlcpSocket->socket_VR, + psLocalLlcpSocket->socket_VRA); + } + else + { + /* Notify the upper layer */ + psLocalLlcpSocket->pSocketErrCb(psTransport->pSocketTable[index].pContext,PHFRINFC_LLCP_ERR_BUSY_CONDITION); + psLocalLlcpSocket->RemoteBusyConditionInfo = TRUE; + + /* Update VSA */ + psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; + + /* Test if a send is pendind */ + if(psLocalLlcpSocket->bSocketSendPending == TRUE && (psLocalLlcpSocket->socket_VS != (psLocalLlcpSocket->socket_VSA + psLocalLlcpSocket->remoteRW))) + { + /* Test if a send is pending at LLC layer */ + if(psTransport->bSendPending != TRUE) + { + /* Reset Send Pending */ + psLocalLlcpSocket->bSocketSendPending = FALSE; + + /* Send Pending */ + psTransport->bSendPending = TRUE; + + /* Set the Header */ + psLocalLlcpSocket->sLlcpHeader.dsap = psLocalLlcpSocket->socket_dSap; + psLocalLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + psLocalLlcpSocket->sLlcpHeader.ssap = psLocalLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + psLocalLlcpSocket->sSequence.ns = psLocalLlcpSocket->socket_VS; + psLocalLlcpSocket->sSequence.nr = psLocalLlcpSocket->socket_VR; + + /* Store the index of the socket */ + psTransport->socketIndex = psLocalLlcpSocket->index; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(psTransport->pLlcp, + &psLocalLlcpSocket->sLlcpHeader, + &psLocalLlcpSocket->sSequence, + &psLocalLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + psTransport); + + /* Update VS */ + psLocalLlcpSocket->socket_VS = (psLocalLlcpSocket->socket_VS+1)%16; + } + } + } + } + else + { + /* No active socket*/ + /* RNR Frame not handled*/ + } +} + +static void Handle_FrameReject_Frame(phFriNfc_LlcpTransport_t *psTransport, + uint8_t dsap, + uint8_t ssap) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + uint8_t socketFound = FALSE; + + /* Search a socket waiting for a FRAME */ + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ + if(psTransport->pSocketTable[index].socket_sSap == dsap + && psTransport->pSocketTable[index].socket_dSap == ssap) + { + /* socket found */ + socketFound = TRUE; + break; + } + } + + /* Test if a socket has been found */ + if(socketFound) + { + /* Set socket state to disconnected */ + psTransport->pSocketTable[index].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnected; + + /* Call ErrCB due to a FRMR*/ + psTransport->pSocketTable[index].pSocketErrCb( psTransport->pSocketTable[index].pContext,PHFRINFC_LLCP_ERR_FRAME_REJECTED); + + /* Close the socket */ + status = phFriNfc_LlcpTransport_ConnectionOriented_Close(&psTransport->pSocketTable[index]); + } + else + { + /* No active socket*/ + /* FRMR Frame not handled*/ + } +} + +/* TODO: comment function Handle_ConnectionOriented_IncommingFrame */ +void Handle_ConnectionOriented_IncommingFrame(phFriNfc_LlcpTransport_t *psTransport, + phNfc_sData_t *psData, + uint8_t dsap, + uint8_t ptype, + uint8_t ssap) +{ + phFriNfc_Llcp_sPacketSequence_t sSequence = {0,0}; + + switch(ptype) + { + case PHFRINFC_LLCP_PTYPE_CONNECT: + { + Handle_ConnectionFrame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_DISC: + { + Handle_DisconnectFrame(psTransport, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_CC: + { + Handle_ConnectionCompleteFrame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_DM: + { + Handle_DisconnetModeFrame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_FRMR: + { + Handle_FrameReject_Frame(psTransport, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_I: + { + Handle_Receive_IFrame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_RR: + { + Handle_ReceiveReady_Frame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_RNR: + { + Handle_ReceiveNotReady_Frame(psTransport, + psData, + dsap, + ssap); + }break; + + case PHFRINFC_LLCP_PTYPE_RESERVED1: + case PHFRINFC_LLCP_PTYPE_RESERVED2: + case PHFRINFC_LLCP_PTYPE_RESERVED3: + case PHFRINFC_LLCP_PTYPE_RESERVED4: + { + phFriNfc_Llcp_Send_FrameReject_Frame( psTransport, + dsap, ptype, ssap, + &sSequence, + TRUE, FALSE, FALSE, FALSE, + 0, 0, 0, 0); + }break; + } +} + +/** +* \ingroup grp_lib_nfc +* \brief <b>Get the local options of a socket</b>. +* +* This function returns the local options (maximum packet size and receive window size) used +* for a given connection-oriented socket. This function shall not be used with connectionless +* sockets. +* +* \param[out] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psLocalOptions A pointer to be filled with the local options of the socket. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. +* \retval NFCSTATUS_SHUTDOWN Shutdown in progress. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_SocketGetLocalOptions(phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, + phLibNfc_Llcp_sSocketOptions_t *psLocalOptions) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + /* Get Local MIUX */ + psLocalOptions->miu = pLlcpSocket->psSocketOption->miu; + + /* Get Local Receive Window */ + psLocalOptions->rw = pLlcpSocket->psSocketOption->rw; + + return status; +} + +/** +* \ingroup grp_lib_nfc +* \brief <b>Get the local options of a socket</b>. +* +* This function returns the remote options (maximum packet size and receive window size) used +* for a given connection-oriented socket. This function shall not be used with connectionless +* sockets. +* +* \param[out] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psRemoteOptions A pointer to be filled with the remote options of the socket. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. +* \retval NFCSTATUS_SHUTDOWN Shutdown in progress. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_SocketGetRemoteOptions(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + phLibNfc_Llcp_sSocketOptions_t* psRemoteOptions) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + /* Get Remote MIUX */ + psRemoteOptions->miu = pLlcpSocket->remoteMIU; + + /* Get Remote Receive Window */ + psRemoteOptions->rw = pLlcpSocket->remoteRW; + + return status; +} + + +/** +* \ingroup grp_fri_nfc +* \brief <b>Listen for incoming connection requests on a socket</b>. +* +* This function switches a socket into a listening state and registers a callback on +* incoming connection requests. In this state, the socket is not able to communicate +* directly. The listening state is only available for connection-oriented sockets +* which are still not connected. The socket keeps listening until it is closed, and +* thus can trigger several times the pListen_Cb callback. +* +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psServiceName A pointer to a Service Name +* \param[in] pListen_Cb The callback to be called each time the +* socket receive a connection request. +* \param[in] pContext Upper layer context to be returned in +* the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state to switch +* to listening state. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Listen(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + phNfc_sData_t *psServiceName, + pphFriNfc_LlcpTransportSocketListenCb_t pListen_Cb, + void* pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint8_t index; + + /* Check if the service name is already registered */ + if (psServiceName != NULL) + { + for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) + { + phFriNfc_LlcpTransport_Socket_t* pCurrentSocket = &pLlcpSocket->psTransport->pSocketTable[index]; + + if((pCurrentSocket->pServiceName == NULL) || + (pCurrentSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketRegistered)) + { + /* Do not check inactive or non-SDP registered sockets */ + continue; + } + if(pCurrentSocket->pServiceName->length != psServiceName->length) { + /* Service name do not match, check next */ + continue; + } + if(memcmp(pCurrentSocket->pServiceName->buffer, psServiceName->buffer, psServiceName->length) == 0) + { + /* Service name already in use */ + return NFCSTATUS_INVALID_PARAMETER; + } + } + } + + /* Store the listen callback */ + pLlcpSocket->pfSocketListen_Cb = pListen_Cb; + + /* store the context */ + pLlcpSocket->pListenContext = pContext; + + /* Set RecvPending to TRUE */ + pLlcpSocket->bSocketListenPending = TRUE; + + /* Store the listen socket SN */ + pLlcpSocket->pServiceName = psServiceName; + + /* Set the socket state*/ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketRegistered; + + return status; +} + +/** +* \ingroup grp_fri_nfc +* \brief <b>Accept an incoming connection request for a socket</b>. +* +* This functions allows the client to accept an incoming connection request. +* It must be used with the socket provided within the listen callback. The socket +* is implicitly switched to the connected state when the function is called. +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psOptions The options to be used with the socket. +* \param[in] psWorkingBuffer A working buffer to be used by the library. +* \param[in] pErr_Cb The callback to be called each time the accepted socket +* is in error. +* \param[in] pAccept_RspCb The callback to be called when the Accept operation is completed +* \param[in] pContext Upper layer context to be returned in the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_BUFFER_TOO_SMALL The working buffer is too small for the MIU and RW +* declared in the options. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Accept(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + phFriNfc_LlcpTransport_sSocketOptions_t* psOptions, + phNfc_sData_t* psWorkingBuffer, + pphFriNfc_LlcpTransportSocketErrCb_t pErr_Cb, + pphFriNfc_LlcpTransportSocketAcceptCb_t pAccept_RspCb, + void* pContext) + +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + uint32_t offset = 0; + uint16_t miux; + uint8_t i; + + /* Store the options in the socket */ + pLlcpSocket->psSocketOption = psOptions; + + /* Set socket local params (MIUX & RW) */ + pLlcpSocket ->localMIUX = (pLlcpSocket->psSocketOption->miu - PHFRINFC_LLCP_MIU_DEFAULT) & PHFRINFC_LLCP_TLV_MIUX_MASK; + pLlcpSocket ->localRW = pLlcpSocket->psSocketOption->rw & PHFRINFC_LLCP_TLV_RW_MASK; + + /* Set the pointer and the length for the Receive Window Buffer */ + for(i=0;i<pLlcpSocket->localRW;i++) + { + pLlcpSocket->sSocketRwBufferTable[i].buffer = psWorkingBuffer->buffer + (i*pLlcpSocket->psSocketOption->miu); + pLlcpSocket->sSocketRwBufferTable[i].length = 0; + } + + /* Set the pointer and the length for the Send Buffer */ + pLlcpSocket->sSocketSendBuffer.buffer = psWorkingBuffer->buffer + pLlcpSocket->bufferRwMaxLength; + pLlcpSocket->sSocketSendBuffer.length = pLlcpSocket->bufferSendMaxLength; + + /* Set the pointer and the length for the Linear Buffer */ + pLlcpSocket->sSocketLinearBuffer.buffer = psWorkingBuffer->buffer + pLlcpSocket->bufferRwMaxLength + pLlcpSocket->bufferSendMaxLength; + pLlcpSocket->sSocketLinearBuffer.length = pLlcpSocket->bufferLinearLength; + + if(pLlcpSocket->sSocketLinearBuffer.length != 0) + { + /* Init Cyclic Fifo */ + phFriNfc_Llcp_CyclicFifoInit(&pLlcpSocket->sCyclicFifoBuffer, + pLlcpSocket->sSocketLinearBuffer.buffer, + pLlcpSocket->sSocketLinearBuffer.length); + } + + pLlcpSocket->pSocketErrCb = pErr_Cb; + pLlcpSocket->pContext = pContext; + + /* store the pointer to the Accept callback */ + pLlcpSocket->pfSocketAccept_Cb = pAccept_RspCb; + pLlcpSocket->pAcceptContext = pContext; + + /* Reset the socket_VS,socket_VR,socket_VSA and socket_VRA variables */ + pLlcpSocket->socket_VR = 0; + pLlcpSocket->socket_VRA = 0; + pLlcpSocket->socket_VS = 0; + pLlcpSocket->socket_VSA = 0; + + /* MIUX */ + if(pLlcpSocket->localMIUX != PHFRINFC_LLCP_MIUX_DEFAULT) + { + /* Encode MIUX value */ + phFriNfc_Llcp_EncodeMIUX(&pLlcpSocket->localMIUX, + &miux); + + /* Encode MIUX in TLV format */ + status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, + &offset, + PHFRINFC_LLCP_TLV_TYPE_MIUX, + PHFRINFC_LLCP_TLV_LENGTH_MIUX, + (uint8_t*)&miux); + if(status != NFCSTATUS_SUCCESS) + { + /* Call the CB */ + status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); + /* Call the callback */ + pAccept_RspCb(pLlcpSocket->pAcceptContext,status); + return status; + } + } + + /* Recive Window */ + if(pLlcpSocket->psSocketOption->rw != PHFRINFC_LLCP_RW_DEFAULT) + { + /* Encode RW value */ + phFriNfc_Llcp_EncodeRW(&pLlcpSocket->psSocketOption->rw); + + /* Encode RW in TLV format */ + status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, + &offset, + PHFRINFC_LLCP_TLV_TYPE_RW, + PHFRINFC_LLCP_TLV_LENGTH_RW, + &pLlcpSocket->psSocketOption->rw); + if(status != NFCSTATUS_SUCCESS) + { + /* Call the CB */ + status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); + /* Call the callback */ + pAccept_RspCb(pLlcpSocket->pAcceptContext,status); + return status; + } + } + + + /* Test if a send is pending */ + if(pLlcpSocket->psTransport->bSendPending == TRUE) + { + pLlcpSocket->bSocketAcceptPending = TRUE; + + /* Update Send Buffer length value */ + pLlcpSocket->sSocketSendBuffer.length = offset; + + status = NFCSTATUS_PENDING; + } + else + { + /* Fill the psLlcpHeader stuture with the DSAP,CC PTYPE and the SSAP */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CC; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Set the socket state to accepted */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketAccepted; + + /* Update Send Buffer length value */ + pLlcpSocket->sSocketSendBuffer.length = offset; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Send a CC Frame */ + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + NULL, + &pLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + } + return status; +} + + /** +* \ingroup grp_fri_nfc +* \brief <b>Reject an incoming connection request for a socket</b>. +* +* This functions allows the client to reject an incoming connection request. +* It must be used with the socket provided within the listen callback. The socket +* is implicitly closed when the function is called. +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phLibNfc_LlcpTransport_ConnectionOriented_Reject( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + pphFriNfc_LlcpTransportSocketRejectCb_t pReject_RspCb, + void *pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + /* Set the state of the socket */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketRejected; + + /* Store the Reject callback */ + pLlcpSocket->pfSocketSend_Cb = pReject_RspCb; + pLlcpSocket->pRejectContext = pContext; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Send a DM*/ + status = phFriNfc_Llcp_Send_DisconnectMode_Frame(pLlcpSocket->psTransport, + pLlcpSocket->socket_dSap, + pLlcpSocket->socket_sSap, + PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED); + + return status; +} + +/** +* \ingroup grp_fri_nfc +* \brief <b>Try to establish connection with a socket on a remote SAP</b>. +* +* This function tries to connect to a given SAP on the remote peer. If the +* socket is not bound to a local SAP, it is implicitly bound to a free SAP. +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] nSap The destination SAP to connect to. +* \param[in] psUri The URI corresponding to the destination SAP to connect to. +* \param[in] pConnect_RspCb The callback to be called when the connection +* operation is completed. +* \param[in] pContext Upper layer context to be returned in +* the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_PENDING Connection operation is in progress, +* pConnect_RspCb will be called upon completion. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Connect( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + uint8_t nSap, + phNfc_sData_t* psUri, + pphFriNfc_LlcpTransportSocketConnectCb_t pConnect_RspCb, + void* pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + uint32_t offset = 0; + uint16_t miux = 0; + + /* Test if a nSap is present */ + if(nSap != PHFRINFC_LLCP_SAP_DEFAULT) + { + /* Set DSAP port number with the nSap value */ + pLlcpSocket->socket_dSap = nSap; + } + else + { + /* Set DSAP port number with the SDP port number */ + pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_SDP; + } + + /* Store the Connect callback and context */ + pLlcpSocket->pfSocketConnect_Cb = pConnect_RspCb; + pLlcpSocket->pConnectContext = pContext; + + /* Set the socket Header */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CONNECT; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* MIUX */ + if(pLlcpSocket->localMIUX != PHFRINFC_LLCP_MIUX_DEFAULT) + { + /* Encode MIUX value */ + phFriNfc_Llcp_EncodeMIUX(&pLlcpSocket->localMIUX, + &miux); + + /* Encode MIUX in TLV format */ + status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, + &offset, + PHFRINFC_LLCP_TLV_TYPE_MIUX, + PHFRINFC_LLCP_TLV_LENGTH_MIUX, + (uint8_t*)&miux); + if(status != NFCSTATUS_SUCCESS) + { + return status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); + } + } + + /* Recive Window */ + if(pLlcpSocket->psSocketOption->rw != PHFRINFC_LLCP_RW_DEFAULT) + { + /* Encode RW value */ + phFriNfc_Llcp_EncodeRW(&pLlcpSocket->psSocketOption->rw); + + /* Encode RW in TLV format */ + status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, + &offset, + PHFRINFC_LLCP_TLV_TYPE_RW, + PHFRINFC_LLCP_TLV_LENGTH_RW, + &pLlcpSocket->psSocketOption->rw); + if(status != NFCSTATUS_SUCCESS) + { + status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); + } + } + + /* Test if a Service Name is present */ + if(psUri != NULL) + { + /* Encode SN in TLV format */ + status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, + &offset, + PHFRINFC_LLCP_TLV_TYPE_SN, + (uint8_t)psUri->length, + psUri->buffer); + if(status != NFCSTATUS_SUCCESS) + { + status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); + } + } + + /* Test if a send is pending */ + if(pLlcpSocket->psTransport->bSendPending == TRUE) + { + pLlcpSocket->bSocketConnectPending = TRUE; + + /* Update Send Buffer length value */ + pLlcpSocket->sSocketSendBuffer.length = offset; + + status = NFCSTATUS_PENDING; + } + else + { + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Update Send Buffer length value */ + pLlcpSocket->sSocketSendBuffer.length = offset; + + /* Set the socket in connecting state */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnecting; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + NULL, + &pLlcpSocket->sSocketSendBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + } + + return status; +} + + +/** +* \ingroup grp_lib_nfc +* \brief <b>Disconnect a currently connected socket</b>. +* +* This function initiates the disconnection of a previously connected socket. +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] pDisconnect_RspCb The callback to be called when the +* operation is completed. +* \param[in] pContext Upper layer context to be returned in +* the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_PENDING Disconnection operation is in progress, +* pDisconnect_RspCb will be called upon completion. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. +* \retval NFCSTATUS_SHUTDOWN Shutdown in progress. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phLibNfc_LlcpTransport_ConnectionOriented_Disconnect(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + pphLibNfc_LlcpSocketDisconnectCb_t pDisconnect_RspCb, + void* pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + /* Store the Disconnect callback and context*/ + pLlcpSocket->pfSocketDisconnect_Cb = pDisconnect_RspCb; + pLlcpSocket->pDisonnectContext = pContext; + + /* Test if a send IFRAME is pending with this socket */ + if((pLlcpSocket->bSocketSendPending == TRUE) || (pLlcpSocket->bSocketRecvPending == TRUE)) + { + pLlcpSocket->bSocketSendPending = FALSE; + pLlcpSocket->bSocketRecvPending = FALSE; + + /* Call the send CB, a disconnect abort the send request */ + if (pLlcpSocket->pfSocketSend_Cb != NULL) + { + /* Copy CB + context in local variables */ + pphFriNfc_LlcpTransportSocketSendCb_t pfSendCb = pLlcpSocket->pfSocketSend_Cb; + void* pSendContext = pLlcpSocket->pSendContext; + /* Reset CB + context */ + pLlcpSocket->pfSocketSend_Cb = NULL; + pLlcpSocket->pSendContext = NULL; + /* Perform callback */ + pfSendCb(pSendContext, NFCSTATUS_FAILED); + } + /* Call the send CB, a disconnect abort the receive request */ + if (pLlcpSocket->pfSocketRecv_Cb != NULL) + { + /* Copy CB + context in local variables */ + pphFriNfc_LlcpTransportSocketRecvCb_t pfRecvCb = pLlcpSocket->pfSocketRecv_Cb; + void* pRecvContext = pLlcpSocket->pRecvContext; + /* Reset CB + context */ + pLlcpSocket->pfSocketRecv_Cb = NULL; + pLlcpSocket->pRecvContext = NULL; + /* Perform callback */ + pfRecvCb(pRecvContext, NFCSTATUS_FAILED); + } + } + + /* Set the socket Header */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* Test if a send is pending */ + if( pLlcpSocket->psTransport->bSendPending == TRUE) + { + pLlcpSocket->bSocketDiscPending = TRUE; + status = NFCSTATUS_PENDING; + } + else + { + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Set the socket in connecting state */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; + + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + NULL, + NULL, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + } + return status; +} + +/* TODO: comment function phFriNfc_LlcpTransport_Connectionless_SendTo_CB */ +static void phFriNfc_LlcpTransport_ConnectionOriented_DisconnectClose_CB(void* pContext, + NFCSTATUS status) +{ + phFriNfc_LlcpTransport_Socket_t *pLlcpSocket = (phFriNfc_LlcpTransport_Socket_t*)pContext; + + if(status == NFCSTATUS_SUCCESS) + { + /* Reset the pointer to the socket closed */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; + pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; + pLlcpSocket->pContext = NULL; + pLlcpSocket->pSocketErrCb = NULL; + pLlcpSocket->psSocketOption = NULL; + pLlcpSocket->socket_sSap = PHFRINFC_LLCP_SAP_DEFAULT; + pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_DEFAULT; + pLlcpSocket->bSocketRecvPending = FALSE; + pLlcpSocket->bSocketSendPending = FALSE; + pLlcpSocket->bSocketListenPending = FALSE; + pLlcpSocket->bSocketDiscPending = FALSE; + pLlcpSocket->pfSocketSend_Cb = NULL; + pLlcpSocket->pfSocketRecv_Cb = NULL; + pLlcpSocket->pfSocketListen_Cb = NULL; + pLlcpSocket->pfSocketConnect_Cb = NULL; + pLlcpSocket->pfSocketDisconnect_Cb = NULL; + pLlcpSocket->pServiceName = NULL; + pLlcpSocket->socket_VS = 0; + pLlcpSocket->socket_VSA = 0; + pLlcpSocket->socket_VR = 0; + pLlcpSocket->socket_VRA = 0; + } + else + { + /* Disconnect close Error */ + } +} + +/** +* \ingroup grp_fri_nfc +* \brief <b>Close a socket on a LLCP-connected device</b>. +* +* This function closes a LLCP socket previously created using phFriNfc_LlcpTransport_Socket. +* If the socket was connected, it is first disconnected, and then closed. +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. + +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Close(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + if(pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) + { + status = phLibNfc_LlcpTransport_ConnectionOriented_Disconnect(pLlcpSocket, + phFriNfc_LlcpTransport_ConnectionOriented_DisconnectClose_CB, + pLlcpSocket); + } + else + { + LLCP_PRINT("Socket Closed"); + /* Reset the pointer to the socket closed */ + pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; + pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; + pLlcpSocket->pContext = NULL; + pLlcpSocket->pSocketErrCb = NULL; + pLlcpSocket->psSocketOption = NULL; + pLlcpSocket->socket_sSap = PHFRINFC_LLCP_SAP_DEFAULT; + pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_DEFAULT; + pLlcpSocket->bSocketRecvPending = FALSE; + pLlcpSocket->bSocketSendPending = FALSE; + pLlcpSocket->bSocketListenPending = FALSE; + pLlcpSocket->bSocketDiscPending = FALSE; + pLlcpSocket->RemoteBusyConditionInfo = FALSE; + pLlcpSocket->ReceiverBusyCondition = FALSE; + pLlcpSocket->pfSocketSend_Cb = NULL; + pLlcpSocket->pfSocketRecv_Cb = NULL; + pLlcpSocket->pfSocketListen_Cb = NULL; + pLlcpSocket->pfSocketConnect_Cb = NULL; + pLlcpSocket->pfSocketDisconnect_Cb = NULL; + pLlcpSocket->pServiceName = NULL; + pLlcpSocket->socket_VS = 0; + pLlcpSocket->socket_VSA = 0; + pLlcpSocket->socket_VR = 0; + pLlcpSocket->socket_VRA = 0; + } + return NFCSTATUS_SUCCESS; +} + + +/** +* \ingroup grp_fri_nfc +* \brief <b>Send data on a socket</b>. +* +* This function is used to write data on a socket. This function +* can only be called on a connection-oriented socket which is already +* in a connected state. +* +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psBuffer The buffer containing the data to send. +* \param[in] pSend_RspCb The callback to be called when the +* operation is completed. +* \param[in] pContext Upper layer context to be returned in +* the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_PENDING Reception operation is in progress, +* pSend_RspCb will be called upon completion. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Send(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + phNfc_sData_t* psBuffer, + pphFriNfc_LlcpTransportSocketSendCb_t pSend_RspCb, + void* pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + + + /* Test the RW window */ + if(pLlcpSocket->socket_VS == (pLlcpSocket->socket_VSA + pLlcpSocket->remoteRW)) + { + /* Store the Send CB and context */ + pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; + pLlcpSocket->pSendContext = pContext; + + /* Set Send pending */ + pLlcpSocket->bSocketSendPending = TRUE; + + /* Store send buffer pointer */ + pLlcpSocket->sSocketSendBuffer = *psBuffer; + + /* Set status */ + status = NFCSTATUS_PENDING; + } + else + { + /* Test if a send is pending */ + if(pLlcpSocket->psTransport->bSendPending == TRUE) + { + /* Store the Send CB and context */ + pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; + pLlcpSocket->pSendContext = pContext; + + /* Set Send pending */ + pLlcpSocket->bSocketSendPending = TRUE; + + /* Store send buffer pointer */ + pLlcpSocket->sSocketSendBuffer = *psBuffer; + + /* Set status */ + status = NFCSTATUS_PENDING; + } + else + { + /* Store the Send CB and context */ + pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; + pLlcpSocket->pSendContext = pContext; + + /* Set the Header */ + pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; + pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; + pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; + + /* Set Sequence Numbers */ + pLlcpSocket->sSequence.ns = pLlcpSocket->socket_VS; + pLlcpSocket->sSequence.nr = pLlcpSocket->socket_VR; + + /* Send Pending */ + pLlcpSocket->psTransport->bSendPending = TRUE; + + /* Store the index of the socket */ + pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; + + /* Send I_PDU */ + status = phFriNfc_Llcp_Send(pLlcpSocket->psTransport->pLlcp, + &pLlcpSocket->sLlcpHeader, + &pLlcpSocket->sSequence, + psBuffer, + phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, + pLlcpSocket->psTransport); + + /* Update VS */ + pLlcpSocket->socket_VS = (pLlcpSocket->socket_VS+1)%16; + } + + } + return status; +} + + + /** +* \ingroup grp_fri_nfc +* \brief <b>Read data on a socket</b>. +* +* This function is used to read data from a socket. It reads at most the +* size of the reception buffer, but can also return less bytes if less bytes +* are available. If no data is available, the function will be pending until +* more data comes, and the response will be sent by the callback. This function +* can only be called on a connection-oriented socket. +* +* +* \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. +* \param[in] psBuffer The buffer receiving the data. +* \param[in] pRecv_RspCb The callback to be called when the +* operation is completed. +* \param[in] pContext Upper layer context to be returned in +* the callback. +* +* \retval NFCSTATUS_SUCCESS Operation successful. +* \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters +* could not be properly interpreted. +* \retval NFCSTATUS_PENDING Reception operation is in progress, +* pRecv_RspCb will be called upon completion. +* \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of +* a valid type to perform the requsted operation. +* \retval NFCSTATUS_FAILED Operation failed. +*/ +NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Recv( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, + phNfc_sData_t* psBuffer, + pphFriNfc_LlcpTransportSocketRecvCb_t pRecv_RspCb, + void* pContext) +{ + NFCSTATUS status = NFCSTATUS_SUCCESS; + uint32_t dataLengthStored = 0; + uint32_t dataLengthAvailable = 0; + uint32_t dataLengthRead = 0; + uint32_t dataLengthWrite = 0; + bool_t dataBufferized = FALSE; + + /* Test if the WorkingBuffer Length is null */ + if(pLlcpSocket->bufferLinearLength == 0) + { + /* Test If data is present in the RW Buffer */ + if(pLlcpSocket->indexRwRead != pLlcpSocket->indexRwWrite) + { + if(pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length != 0) + { + /* Save I_FRAME into the Receive Buffer */ + memcpy(psBuffer->buffer,pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].buffer,pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length); + psBuffer->length = pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length; + + dataBufferized = TRUE; + + /* Update VR */ + pLlcpSocket->socket_VR = (pLlcpSocket->socket_VR+1)%16; + + /* Update RW Buffer length */ + pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length = 0; + + /* Update Value Rw Read Index*/ + pLlcpSocket->indexRwRead++; + } + } + + if(dataBufferized == TRUE) + { + /* Call the Receive CB */ + pRecv_RspCb(pContext,NFCSTATUS_SUCCESS); + + if(pLlcpSocket->ReceiverBusyCondition == TRUE) + { + /* Reset the ReceiverBusyCondition Flag */ + pLlcpSocket->ReceiverBusyCondition = FALSE; + /* RR */ + phFriNfc_Llcp_Send_ReceiveReady_Frame(pLlcpSocket); + } + } + else + { + /* Set Receive pending */ + pLlcpSocket->bSocketRecvPending = TRUE; + + /* Store the buffer pointer */ + pLlcpSocket->sSocketRecvBuffer = psBuffer; + + /* Store the Recv CB and context */ + pLlcpSocket->pfSocketRecv_Cb = pRecv_RspCb; + pLlcpSocket->pRecvContext = pContext; + + /* Set status */ + status = NFCSTATUS_PENDING; + } + } + else + { + /* Test if data is present in the linear buffer*/ + dataLengthStored = phFriNfc_Llcp_CyclicFifoUsage(&pLlcpSocket->sCyclicFifoBuffer); + + if(dataLengthStored != 0) + { + if(psBuffer->length > dataLengthStored) + { + psBuffer->length = dataLengthStored; + } + + /* Read data from the linear buffer */ + dataLengthRead = phFriNfc_Llcp_CyclicFifoFifoRead(&pLlcpSocket->sCyclicFifoBuffer, + psBuffer->buffer, + psBuffer->length); + + if(dataLengthRead != 0) + { + /* Test If data is present in the RW Buffer */ + if(pLlcpSocket->indexRwRead != pLlcpSocket->indexRwWrite) + { + do + { + /* Get the data length available in the linear buffer */ + dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&pLlcpSocket->sCyclicFifoBuffer); + + /* Test if enought place is available */ + if(dataLengthAvailable > pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length ) + { + /* Write data into the linear buffer */ + dataLengthWrite = phFriNfc_Llcp_CyclicFifoWrite(&pLlcpSocket->sCyclicFifoBuffer, + pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].buffer, + pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length); + /* Update VR */ + pLlcpSocket->socket_VR = (pLlcpSocket->socket_VR+1)%16; + + /* Set flag bufferized to TRUE */ + dataBufferized = TRUE; + + /* Update RW Buffer length */ + pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length = 0; + + /* Update Value Rw Read Index*/ + pLlcpSocket->indexRwRead++; + } + }while(dataLengthAvailable > pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length); + } + + /* Test if data has been bufferized after a read access */ + if(dataBufferized == TRUE) + { + /* Get the data length available in the linear buffer */ + dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&pLlcpSocket->sCyclicFifoBuffer); + if((dataLengthAvailable >= pLlcpSocket->psSocketOption->miu) && (pLlcpSocket->ReceiverBusyCondition == TRUE)) + { + /* Reset the ReceiverBusyCondition Flag */ + pLlcpSocket->ReceiverBusyCondition = FALSE; + /* RR */ + phFriNfc_Llcp_Send_ReceiveReady_Frame(pLlcpSocket); + } + } + + /* Call the Receive CB */ + pRecv_RspCb(pContext,NFCSTATUS_SUCCESS); + } + else + { + /* Call the Receive CB */ + pRecv_RspCb(pContext,NFCSTATUS_FAILED); + } + } + else + { + /* Set Receive pending */ + pLlcpSocket->bSocketRecvPending = TRUE; + + /* Store the buffer pointer */ + pLlcpSocket->sSocketRecvBuffer = psBuffer; + + /* Store the Recv CB and context */ + pLlcpSocket->pfSocketRecv_Cb = pRecv_RspCb; + pLlcpSocket->pRecvContext = pContext; + + /* Set status */ + status = NFCSTATUS_PENDING; + } + } + + return status; +} + + |