/*
*         Copyright (c), NXP Semiconductors Caen / France
*
*                     (C)NXP Semiconductors
*       All rights are reserved. Reproduction in whole or in part is
*      prohibited without the written consent of the copyright owner.
*  NXP reserves the right to make changes without notice at any time.
* NXP makes no warranty, expressed, implied or statutory, including but
* not limited to any implied warranty of merchantability or fitness for any
*particular purpose, or that the use will not infringe any third party patent,
* copyright or trademark. NXP must not be liable for any loss or damage
*                          arising from its use.
*/

#ifdef RW_SUPPORT
#ifndef NO_NDEF_SUPPORT
#include <TML/inc/tool.h>
#include <NfcLibrary/NdefLibrary/inc/RW_NDEF.h>

/* TODO: No support for tag larger than 1024 bytes (requiring SECTOR_SELECT command use) */

#define T2T_MAGIC_NUMBER    0xE1
#define T2T_NDEF_TLV        0x03

typedef enum
{
    Initial,
    Reading_CC,
    Reading_Data,
    Reading_NDEF,
    Writing_Data
} RW_NDEF_T2T_state_t;

typedef struct
{
    unsigned char BlkNb;
    unsigned short MessagePtr;
    unsigned short MessageSize;
    unsigned char *pMessage;
} RW_NDEF_T2T_Ndef_t;

static RW_NDEF_T2T_state_t eRW_NDEF_T2T_State = Initial;
static RW_NDEF_T2T_Ndef_t RW_NDEF_T2T_Ndef;

void RW_NDEF_T2T_Reset(void)
{
    eRW_NDEF_T2T_State = Initial;
    RW_NDEF_T2T_Ndef.pMessage = NdefBuffer;
}

void RW_NDEF_T2T_Read_Next(unsigned char *pRsp, unsigned short Rsp_size, unsigned char *pCmd, unsigned short *pCmd_size)
{
    /* By default no further command to be sent */
    *pCmd_size = 0;

    switch(eRW_NDEF_T2T_State)
    {
    case Initial:
        /* Read CC */
        pCmd[0] = 0x30;
        pCmd[1] = 0x03;
        *pCmd_size = 2;
        eRW_NDEF_T2T_State = Reading_CC;
        break;

    case Reading_CC:
        /* Is CC Read and Is Ndef ?*/
        if ((Rsp_size == 17) && (pRsp[Rsp_size-1] == 0x00) && (pRsp[0] == T2T_MAGIC_NUMBER))
        {
            /* Read First data */
            pCmd[0] = 0x30;
            pCmd[1] = 0x04;
            *pCmd_size = 2;

            eRW_NDEF_T2T_State = Reading_Data;
        }
        break;

    case Reading_Data:
        /* Is Read success ?*/
        if ((Rsp_size == 17) && (pRsp[Rsp_size-1] == 0x00))
        {
            unsigned char Tmp = 0;
            /* If not NDEF Type skip TLV */
            while (pRsp[Tmp] != T2T_NDEF_TLV)
            {
                Tmp += 2 + pRsp[Tmp+1];
                if (Tmp > Rsp_size) return;
            }

            if(pRsp[Tmp+1] == 0xFF)
            {
                RW_NDEF_T2T_Ndef.MessageSize = (pRsp[Tmp+2] << 8) + pRsp[Tmp+3];
                Tmp += 2;
            }
            else RW_NDEF_T2T_Ndef.MessageSize = pRsp[Tmp+1];

            /* If provisioned buffer is not large enough, notify the application and stop reading */
            if (RW_NDEF_T2T_Ndef.MessageSize > RW_MAX_NDEF_FILE_SIZE)
            {
                if(pRW_NDEF_PullCb != NULL) pRW_NDEF_PullCb(NULL, 0);
                break;
            }

            /* Is NDEF read already completed ? */
            if (RW_NDEF_T2T_Ndef.MessageSize <= ((Rsp_size-1) - Tmp - 2))
            {
                memcpy (RW_NDEF_T2T_Ndef.pMessage, &pRsp[Tmp+2], RW_NDEF_T2T_Ndef.MessageSize);

                /* Notify application of the NDEF reception */
                if(pRW_NDEF_PullCb != NULL) pRW_NDEF_PullCb(RW_NDEF_T2T_Ndef.pMessage, RW_NDEF_T2T_Ndef.MessageSize);
            }
            else
            {
                RW_NDEF_T2T_Ndef.MessagePtr = (Rsp_size-1) - Tmp - 2;
                memcpy (RW_NDEF_T2T_Ndef.pMessage, &pRsp[Tmp+2], RW_NDEF_T2T_Ndef.MessagePtr);
                RW_NDEF_T2T_Ndef.BlkNb = 8;

                /* Read NDEF content */
                pCmd[0] = 0x30;
                pCmd[1] = RW_NDEF_T2T_Ndef.BlkNb;
                *pCmd_size = 2;
                eRW_NDEF_T2T_State = Reading_NDEF;
            }
        }
        break;

        case Reading_NDEF:
        /* Is Read success ?*/
        if ((Rsp_size == 17) && (pRsp[Rsp_size-1] == 0x00))
        {
            /* Is NDEF read already completed ? */
            if ((RW_NDEF_T2T_Ndef.MessageSize - RW_NDEF_T2T_Ndef.MessagePtr) < 16)
            {
                memcpy (&RW_NDEF_T2T_Ndef.pMessage[RW_NDEF_T2T_Ndef.MessagePtr], pRsp, RW_NDEF_T2T_Ndef.MessageSize - RW_NDEF_T2T_Ndef.MessagePtr);

                /* Notify application of the NDEF reception */
                if(pRW_NDEF_PullCb != NULL) pRW_NDEF_PullCb(RW_NDEF_T2T_Ndef.pMessage, RW_NDEF_T2T_Ndef.MessageSize);
            }
            else
            {
                memcpy (&RW_NDEF_T2T_Ndef.pMessage[RW_NDEF_T2T_Ndef.MessagePtr], pRsp, 16);
                RW_NDEF_T2T_Ndef.MessagePtr += 16;
                RW_NDEF_T2T_Ndef.BlkNb += 4;

                /* Read NDEF content */
                pCmd[0] = 0x30;
                pCmd[1] = RW_NDEF_T2T_Ndef.BlkNb;
                *pCmd_size = 2;
            }
        }
        break;

    default:
        break;
    }
}

void RW_NDEF_T2T_Write_Next(unsigned char *pRsp, unsigned short Rsp_size, unsigned char *pCmd, unsigned short *pCmd_size)
{
    /* By default no further command to be sent */
    *pCmd_size = 0;

    switch(eRW_NDEF_T2T_State)
    {
    case Initial:
        /* Read CC */
        pCmd[0] = 0x30;
        pCmd[1] = 0x03;
        *pCmd_size = 2;
        eRW_NDEF_T2T_State = Reading_CC;
        break;

    case Reading_CC:
        /* Is CC Read, Is Ndef and is R/W ?*/
        if ((Rsp_size == 17) && (pRsp[Rsp_size-1] == 0x00) && (pRsp[0] == T2T_MAGIC_NUMBER) && (pRsp[3] == 0x00))
        {
            /* Is size enough ? */
            if (pRsp[2]*8 >= RW_NdefMessage_size)
            {
                /* Write First data */
                pCmd[0] = 0xA2;
                pCmd[1] = 0x04;
                pCmd[2] = 0x03;
                if (RW_NdefMessage_size > 0xFF)
                {
                    pCmd[3] = 0xFF;
                    pCmd[4] = (RW_NdefMessage_size & 0xFF00) >> 8;
                    pCmd[5] = RW_NdefMessage_size & 0xFF;
                    RW_NDEF_T2T_Ndef.MessagePtr = 0;
                }
                else
                {
                    pCmd[3] = (unsigned char) RW_NdefMessage_size;
                    memcpy(&pCmd[4], pRW_NdefMessage, 2);
                    RW_NDEF_T2T_Ndef.MessagePtr = 2;
                }
                RW_NDEF_T2T_Ndef.BlkNb = 5;
                *pCmd_size = 6;
                eRW_NDEF_T2T_State = Writing_Data;
            }
        }
        break;

    case Writing_Data:
        /* Is Write success ?*/
        if ((Rsp_size == 2) && (pRsp[Rsp_size-1] == 0x00))
        {
            /* Is NDEF write already completed ? */
            if (RW_NdefMessage_size <= RW_NDEF_T2T_Ndef.MessagePtr)
            {
                /* Notify application of the NDEF reception */
                if(pRW_NDEF_PushCb != NULL) pRW_NDEF_PushCb(pRW_NdefMessage, RW_NdefMessage_size);
            }
            else
            {
                /* Write NDEF content */
                pCmd[0] = 0xA2;
                pCmd[1] = RW_NDEF_T2T_Ndef.BlkNb;
                memcpy(&pCmd[2], pRW_NdefMessage+RW_NDEF_T2T_Ndef.MessagePtr, 4);
                *pCmd_size = 6;

                RW_NDEF_T2T_Ndef.MessagePtr+=4;
                RW_NDEF_T2T_Ndef.BlkNb++;
            }
        }
        break;

    default:
        break;
    }
}
#endif
#endif
