1/*
2 * Copyright (C) 2010 NXP Semiconductors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * \file  phFriNfc_Llcp.c
19 * \brief NFC LLCP core
20 *
21 * Project: NFC-FRI
22 *
23 */
24
25/*include files*/
26#include <phNfcTypes.h>
27#include <phNfcHalTypes.h>
28#include <phLibNfcStatus.h>
29#include <phFriNfc_LlcpUtils.h>
30#include <phFriNfc_Llcp.h>
31
32NFCSTATUS phFriNfc_Llcp_DecodeTLV( phNfc_sData_t  *psRawData,
33                                   uint32_t       *pOffset,
34                                   uint8_t        *pType,
35                                   phNfc_sData_t  *psValueBuffer )
36{
37   uint8_t type;
38   uint8_t length;
39   uint32_t offset = *pOffset;
40
41   /* Check for NULL pointers */
42   if ((psRawData == NULL) || (pOffset == NULL) || (pType == NULL) || (psValueBuffer == NULL))
43   {
44      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
45   }
46
47   /* Check offset */
48   if (offset > psRawData->length)
49   {
50      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
51   }
52
53   /* Check if enough room for Type and Length (with overflow check) */
54   if ((offset+2 > psRawData->length) && (offset+2 > offset))
55   {
56      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
57   }
58
59   /* Get Type and Length from current TLV, and update offset */
60   type = psRawData->buffer[offset];
61   length = psRawData->buffer[offset+1];
62   offset += 2;
63
64   /* Check if enough room for Value with announced Length (with overflow check) */
65   if ((offset+length > psRawData->length) && (offset+length > offset))
66   {
67      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
68   }
69
70   /* Save response, and update offset */
71   *pType = type;
72   psValueBuffer->buffer = psRawData->buffer + offset;
73   psValueBuffer->length = length;
74   offset += length;
75
76   /* Save updated offset */
77   *pOffset = offset;
78
79   return NFCSTATUS_SUCCESS;
80}
81
82NFCSTATUS phFriNfc_Llcp_EncodeTLV( phNfc_sData_t  *psValueBuffer,
83                                   uint32_t       *pOffset,
84                                   uint8_t        type,
85                                   uint8_t        length,
86                                   uint8_t        *pValue)
87{
88   uint32_t offset = *pOffset;
89   uint32_t finalOffset = offset + 2 + length; /* 2 stands for Type and Length fields size */
90   uint8_t i;
91
92   /* Check for NULL pointers */
93   if ((psValueBuffer == NULL) || (pOffset == NULL) || (pValue == NULL))
94   {
95      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
96   }
97
98   /* Check offset */
99   if (offset > psValueBuffer->length)
100   {
101      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
102   }
103
104   /* Check if enough room for Type, Length and Value (with overflow check) */
105   if ((finalOffset > psValueBuffer->length) || (finalOffset < offset))
106   {
107      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
108   }
109
110   /* Set the TYPE */
111   psValueBuffer->buffer[offset] = type;
112   offset += 1;
113
114   /* Set the LENGTH */
115   psValueBuffer->buffer[offset] = length;
116   offset += 1;
117
118   /* Set the VALUE */
119   for(i=0;i<length;i++,offset++)
120   {
121      psValueBuffer->buffer[offset]  = pValue[i];
122   }
123
124   /* Save updated offset */
125   *pOffset = offset;
126
127   return NFCSTATUS_SUCCESS;
128}
129
130NFCSTATUS phFriNfc_Llcp_AppendTLV( phNfc_sData_t  *psValueBuffer,
131                                   uint32_t       nTlvOffset,
132                                   uint32_t       *pCurrentOffset,
133                                   uint8_t        length,
134                                   uint8_t        *pValue)
135{
136   uint32_t offset = *pCurrentOffset;
137   uint32_t finalOffset = offset + length;
138
139   /* Check for NULL pointers */
140   if ((psValueBuffer == NULL) || (pCurrentOffset == NULL) || (pValue == NULL))
141   {
142      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
143   }
144
145   /* Check offset */
146   if (offset > psValueBuffer->length)
147   {
148      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
149   }
150
151   /* Check if enough room for Type and Length (with overflow check) */
152   if ((finalOffset > psValueBuffer->length) || (finalOffset < offset))
153   {
154      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
155   }
156
157   /* Update the LENGTH */
158   psValueBuffer->buffer[nTlvOffset+1] += length;
159
160   /* Set the VALUE */
161   memcpy(psValueBuffer->buffer + offset, pValue, length);
162   offset += length;
163
164   /* Save updated offset */
165   *pCurrentOffset = offset;
166
167   return NFCSTATUS_SUCCESS;
168}
169
170
171/* TODO: comment function EncodeMIUX */
172void phFriNfc_Llcp_EncodeMIUX(uint16_t miux,
173                              uint8_t* pMiuxEncoded)
174{
175   /* MASK */
176   miux = miux & PHFRINFC_LLCP_TLV_MIUX_MASK;
177
178   pMiuxEncoded[0] = miux >> 8;
179   pMiuxEncoded[1] = miux & 0xff;
180}
181
182/* TODO: comment function EncodeRW */
183void phFriNfc_Llcp_EncodeRW(uint8_t *pRw)
184{
185   /* MASK */
186   *pRw = *pRw & PHFRINFC_LLCP_TLV_RW_MASK;
187}
188
189/**
190 * Initializes a Fifo Cyclic Buffer to point to some allocated memory.
191 */
192void phFriNfc_Llcp_CyclicFifoInit(P_UTIL_FIFO_BUFFER   pUtilFifo,
193                                  const uint8_t        *pBuffStart,
194                                  uint32_t             buffLength)
195{
196   pUtilFifo->pBuffStart = (uint8_t *)pBuffStart;
197   pUtilFifo->pBuffEnd   = (uint8_t *)pBuffStart + buffLength-1;
198   pUtilFifo->pIn        = (uint8_t *)pBuffStart;
199   pUtilFifo->pOut       = (uint8_t *)pBuffStart;
200   pUtilFifo->bFull      = FALSE;
201}
202
203/**
204 * Clears the Fifo Cyclic Buffer - loosing any data that was in it.
205 */
206void phFriNfc_Llcp_CyclicFifoClear(P_UTIL_FIFO_BUFFER pUtilFifo)
207{
208   pUtilFifo->pIn = pUtilFifo->pBuffStart;
209   pUtilFifo->pOut = pUtilFifo->pBuffStart;
210   pUtilFifo->bFull      = FALSE;
211}
212
213/**
214 * Attempts to write dataLength bytes to the specified Fifo Cyclic Buffer.
215 */
216uint32_t phFriNfc_Llcp_CyclicFifoWrite(P_UTIL_FIFO_BUFFER   pUtilFifo,
217                                       uint8_t              *pData,
218                                       uint32_t             dataLength)
219{
220   uint32_t dataLengthWritten = 0;
221   uint8_t * pNext;
222
223   while(dataLengthWritten < dataLength)
224   {
225      pNext = (uint8_t*)pUtilFifo->pIn+1;
226
227      if(pNext > pUtilFifo->pBuffEnd)
228      {
229         //Wrap around
230         pNext = pUtilFifo->pBuffStart;
231      }
232
233      if(pUtilFifo->bFull)
234      {
235         //Full
236         break;
237      }
238
239      if(pNext == pUtilFifo->pOut)
240      {
241         // Trigger Full flag
242         pUtilFifo->bFull = TRUE;
243      }
244
245      dataLengthWritten++;
246      *pNext = *pData++;
247      pUtilFifo->pIn = pNext;
248   }
249
250   return dataLengthWritten;
251}
252
253/**
254 * Attempts to read dataLength bytes from the specified  Fifo Cyclic Buffer.
255 */
256uint32_t phFriNfc_Llcp_CyclicFifoFifoRead(P_UTIL_FIFO_BUFFER   pUtilFifo,
257                                          uint8_t              *pBuffer,
258                                          uint32_t             dataLength)
259{
260   uint32_t  dataLengthRead = 0;
261   uint8_t * pNext;
262
263   while(dataLengthRead < dataLength)
264   {
265      if((pUtilFifo->pOut == pUtilFifo->pIn) && (pUtilFifo->bFull == FALSE))
266      {
267         //No more bytes in buffer
268         break;
269      }
270      else
271      {
272         dataLengthRead++;
273
274         if(pUtilFifo->pOut == pUtilFifo->pBuffEnd)
275         {
276            /* Wrap around */
277            pNext = pUtilFifo->pBuffStart;
278         }
279         else
280         {
281            pNext = (uint8_t*)pUtilFifo->pOut + 1;
282         }
283
284         *pBuffer++ = *pNext;
285
286         pUtilFifo->pOut = pNext;
287
288         pUtilFifo->bFull = FALSE;
289      }
290   }
291
292   return dataLengthRead;
293}
294
295/**
296 * Returns the number of bytes currently stored in Fifo Cyclic Buffer.
297 */
298uint32_t phFriNfc_Llcp_CyclicFifoUsage(P_UTIL_FIFO_BUFFER pUtilFifo)
299{
300   uint32_t dataLength;
301   uint8_t * pIn        = (uint8_t *)pUtilFifo->pIn;
302   uint8_t * pOut       = (uint8_t *)pUtilFifo->pOut;
303
304   if (pUtilFifo->bFull)
305   {
306      dataLength = pUtilFifo->pBuffEnd - pUtilFifo->pBuffStart + 1;
307   }
308   else
309   {
310      if(pIn >= pOut)
311      {
312         dataLength = pIn - pOut;
313      }
314      else
315      {
316         dataLength = pUtilFifo->pBuffEnd - pOut;
317         dataLength += (pIn+1) - pUtilFifo->pBuffStart;
318      }
319   }
320
321   return dataLength;
322}
323
324
325/**
326 * Returns the available room for writing in Fifo Cyclic Buffer.
327 */
328uint32_t phFriNfc_Llcp_CyclicFifoAvailable(P_UTIL_FIFO_BUFFER pUtilFifo)
329{
330   uint32_t dataLength;
331   uint32_t  size;
332   uint8_t * pIn         = (uint8_t *)pUtilFifo->pIn;
333   uint8_t * pOut        = (uint8_t *)pUtilFifo->pOut;
334
335   if (pUtilFifo->bFull)
336   {
337      dataLength = 0;
338   }
339   else
340   {
341      if(pIn >= pOut)
342      {
343         size = pUtilFifo->pBuffEnd - pUtilFifo->pBuffStart + 1;
344         dataLength = size - (pIn - pOut);
345      }
346      else
347      {
348         dataLength = pOut - pIn;
349      }
350   }
351
352   return dataLength;
353}
354
355
356
357uint32_t phFriNfc_Llcp_Header2Buffer( phFriNfc_Llcp_sPacketHeader_t *psHeader, uint8_t *pBuffer, uint32_t nOffset )
358{
359   uint32_t nOriginalOffset = nOffset;
360   pBuffer[nOffset++] = (uint8_t)((psHeader->dsap << 2)  | (psHeader->ptype >> 2));
361   pBuffer[nOffset++] = (uint8_t)((psHeader->ptype << 6) | psHeader->ssap);
362   return nOffset - nOriginalOffset;
363}
364
365uint32_t phFriNfc_Llcp_Sequence2Buffer( phFriNfc_Llcp_sPacketSequence_t *psSequence, uint8_t *pBuffer, uint32_t nOffset )
366{
367   uint32_t nOriginalOffset = nOffset;
368   pBuffer[nOffset++] = (uint8_t)((psSequence->ns << 4) | (psSequence->nr));
369   return nOffset - nOriginalOffset;
370}
371
372uint32_t phFriNfc_Llcp_Buffer2Header( uint8_t *pBuffer, uint32_t nOffset, phFriNfc_Llcp_sPacketHeader_t *psHeader )
373{
374   psHeader->dsap  = (pBuffer[nOffset] & 0xFC) >> 2;
375   psHeader->ptype = ((pBuffer[nOffset]  & 0x03) << 2) | ((pBuffer[nOffset+1] & 0xC0) >> 6);
376   psHeader->ssap  = pBuffer[nOffset+1] & 0x3F;
377   return PHFRINFC_LLCP_PACKET_HEADER_SIZE;
378}
379
380uint32_t phFriNfc_Llcp_Buffer2Sequence( uint8_t *pBuffer, uint32_t nOffset, phFriNfc_Llcp_sPacketSequence_t *psSequence )
381{
382   psSequence->ns = pBuffer[nOffset] >> 4;
383   psSequence->nr = pBuffer[nOffset] & 0x0F;
384   return PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
385}
386
387
388