/*
* 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_Llcp.c
* \brief NFC LLCP core
*
* Project: NFC-FRI
*
*/
/*include files*/
#include <phNfcTypes.h>
#include <phNfcHalTypes.h>
#include <phLibNfcStatus.h>
#include <phFriNfc_LlcpUtils.h>
#include <phFriNfc_Llcp.h>
NFCSTATUS phFriNfc_Llcp_DecodeTLV( phNfc_sData_t *psRawData,
uint32_t *pOffset,
uint8_t *pType,
phNfc_sData_t *psValueBuffer )
{
uint8_t type;
uint8_t length;
uint32_t offset = *pOffset;
/* Check for NULL pointers */
if ((psRawData == NULL) || (pOffset == NULL) || (pType == NULL) || (psValueBuffer == NULL))
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Check offset */
if (offset > psRawData->length)
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Check if enough room for Type and Length (with overflow check) */
if ((offset+2 > psRawData->length) && (offset+2 > offset))
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Get Type and Length from current TLV, and update offset */
type = psRawData->buffer[offset];
length = psRawData->buffer[offset+1];
offset += 2;
/* Check if enough room for Value with announced Length (with overflow check) */
if ((offset+length > psRawData->length) && (offset+length > offset))
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Save response, and update offset */
*pType = type;
psValueBuffer->buffer = psRawData->buffer + offset;
psValueBuffer->length = length;
offset += length;
/* Save updated offset */
*pOffset = offset;
return NFCSTATUS_SUCCESS;
}
NFCSTATUS phFriNfc_Llcp_EncodeTLV( phNfc_sData_t *psValueBuffer,
uint32_t *pOffset,
uint8_t type,
uint8_t length,
uint8_t *pValue)
{
uint32_t offset = *pOffset;
uint8_t i;
/* Check for NULL pointers */
if ((psValueBuffer == NULL) || (pOffset == NULL) || (pValue == NULL))
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Check offset */
if (offset > psValueBuffer->length)
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Check if enough room for Type and Length (with overflow check) */
if ((offset+2 > psValueBuffer->length) && (offset+2 > offset))
{
return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
}
/* Set the TYPE */
psValueBuffer->buffer[offset] = type;
offset += 1;
/* Set the LENGTH */
psValueBuffer->buffer[offset] = length;
offset += 1;
/* Set the VALUE */
for(i=0;i<length;i++,offset++)
{
psValueBuffer->buffer[offset] = pValue[i];
}
/* Save updated offset */
*pOffset = offset;
return NFCSTATUS_SUCCESS;
}
/* TODO: comment function EncodeMIUX */
void phFriNfc_Llcp_EncodeMIUX(uint16_t miux,
uint8_t* pMiuxEncoded)
{
/* MASK */
miux = miux & PHFRINFC_LLCP_TLV_MIUX_MASK;
pMiuxEncoded[0] = miux >> 8;
pMiuxEncoded[1] = miux & 0xff;
}
/* TODO: comment function EncodeRW */
void phFriNfc_Llcp_EncodeRW(uint8_t *pRw)
{
/* MASK */
*pRw = *pRw & PHFRINFC_LLCP_TLV_RW_MASK;
}
/**
* Initializes a Fifo Cyclic Buffer to point to some allocated memory.
*/
void phFriNfc_Llcp_CyclicFifoInit(P_UTIL_FIFO_BUFFER pUtilFifo,
const uint8_t *pBuffStart,
uint32_t buffLength)
{
pUtilFifo->pBuffStart = (uint8_t *)pBuffStart;
pUtilFifo->pBuffEnd = (uint8_t *)pBuffStart + buffLength-1;
pUtilFifo->pIn = (uint8_t *)pBuffStart;
pUtilFifo->pOut = (uint8_t *)pBuffStart;
pUtilFifo->bFull = FALSE;
}
/**
* Clears the Fifo Cyclic Buffer - loosing any data that was in it.
*/
void phFriNfc_Llcp_CyclicFifoClear(P_UTIL_FIFO_BUFFER pUtilFifo)
{
pUtilFifo->pIn = pUtilFifo->pBuffStart;
pUtilFifo->pOut = pUtilFifo->pBuffStart;
pUtilFifo->bFull = FALSE;
}
/**
* Attempts to write dataLength bytes to the specified Fifo Cyclic Buffer.
*/
uint32_t phFriNfc_Llcp_CyclicFifoWrite(P_UTIL_FIFO_BUFFER pUtilFifo,
uint8_t *pData,
uint32_t dataLength)
{
uint32_t dataLengthWritten = 0;
uint8_t * pNext;
while(dataLengthWritten < dataLength)
{
pNext = (uint8_t*)pUtilFifo->pIn+1;
if(pNext > pUtilFifo->pBuffEnd)
{
//Wrap around
pNext = pUtilFifo->pBuffStart;
}
if(pUtilFifo->bFull)
{
//Full
break;
}
if(pNext == pUtilFifo->pOut)
{
// Trigger Full flag
pUtilFifo->bFull = TRUE;
}
dataLengthWritten++;
*pNext = *pData++;
pUtilFifo->pIn = pNext;
}
return dataLengthWritten;
}
/**
* Attempts to read dataLength bytes from the specified Fifo Cyclic Buffer.
*/
uint32_t phFriNfc_Llcp_CyclicFifoFifoRead(P_UTIL_FIFO_BUFFER pUtilFifo,
uint8_t *pBuffer,
uint32_t dataLength)
{
uint32_t dataLengthRead = 0;
uint8_t * pNext;
while(dataLengthRead < dataLength)
{
if((pUtilFifo->pOut == pUtilFifo->pIn) && (pUtilFifo->bFull == FALSE))
{
//No more bytes in buffer
break;
}
else
{
dataLengthRead++;
if(pUtilFifo->pOut == pUtilFifo->pBuffEnd)
{
/* Wrap around */
pNext = pUtilFifo->pBuffStart;
}
else
{
pNext = (uint8_t*)pUtilFifo->pOut + 1;
}
*pBuffer++ = *pNext;
pUtilFifo->pOut = pNext;
pUtilFifo->bFull = FALSE;
}
}
return dataLengthRead;
}
/**
* Returns the number of bytes currently stored in Fifo Cyclic Buffer.
*/
uint32_t phFriNfc_Llcp_CyclicFifoUsage(P_UTIL_FIFO_BUFFER pUtilFifo)
{
uint32_t dataLength;
uint8_t * pIn = (uint8_t *)pUtilFifo->pIn;
uint8_t * pOut = (uint8_t *)pUtilFifo->pOut;
if (pUtilFifo->bFull)
{
dataLength = pUtilFifo->pBuffEnd - pUtilFifo->pBuffStart + 1;
}
else
{
if(pIn >= pOut)
{
dataLength = pIn - pOut;
}
else
{
dataLength = pUtilFifo->pBuffEnd - pOut;
dataLength += (pIn+1) - pUtilFifo->pBuffStart;
}
}
return dataLength;
}
/**
* Returns the available room for writing in Fifo Cyclic Buffer.
*/
uint32_t phFriNfc_Llcp_CyclicFifoAvailable(P_UTIL_FIFO_BUFFER pUtilFifo)
{
uint32_t dataLength;
uint32_t size;
uint8_t * pIn = (uint8_t *)pUtilFifo->pIn;
uint8_t * pOut = (uint8_t *)pUtilFifo->pOut;
if (pUtilFifo->bFull)
{
dataLength = 0;
}
else
{
if(pIn >= pOut)
{
size = pUtilFifo->pBuffEnd - pUtilFifo->pBuffStart + 1;
dataLength = size - (pIn - pOut);
}
else
{
dataLength = pOut - pIn;
}
}
return dataLength;
}
uint32_t phFriNfc_Llcp_Header2Buffer( phFriNfc_Llcp_sPacketHeader_t *psHeader, uint8_t *pBuffer, uint32_t nOffset )
{
uint32_t nOriginalOffset = nOffset;
pBuffer[nOffset++] = (uint8_t)((psHeader->dsap << 2) | (psHeader->ptype >> 2));
pBuffer[nOffset++] = (uint8_t)((psHeader->ptype << 6) | psHeader->ssap);
return nOffset - nOriginalOffset;
}
uint32_t phFriNfc_Llcp_Sequence2Buffer( phFriNfc_Llcp_sPacketSequence_t *psSequence, uint8_t *pBuffer, uint32_t nOffset )
{
uint32_t nOriginalOffset = nOffset;
pBuffer[nOffset++] = (uint8_t)((psSequence->ns << 4) | (psSequence->nr));
return nOffset - nOriginalOffset;
}
uint32_t phFriNfc_Llcp_Buffer2Header( uint8_t *pBuffer, uint32_t nOffset, phFriNfc_Llcp_sPacketHeader_t *psHeader )
{
psHeader->dsap = (pBuffer[nOffset] & 0xFC) >> 2;
psHeader->ptype = ((pBuffer[nOffset] & 0x03) << 2) | ((pBuffer[nOffset+1] & 0xC0) >> 6);
psHeader->ssap = pBuffer[nOffset+1] & 0x3F;
return PHFRINFC_LLCP_PACKET_HEADER_SIZE;
}
uint32_t phFriNfc_Llcp_Buffer2Sequence( uint8_t *pBuffer, uint32_t nOffset, phFriNfc_Llcp_sPacketSequence_t *psSequence )
{
psSequence->ns = pBuffer[nOffset] >> 4;
psSequence->nr = pBuffer[nOffset] & 0x0F;
return PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
}