This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TRF7970A not reading Android's Host-based card emulation tags

Other Parts Discussed in Thread: CC3200, TRF7970A, DLP-7970ABP, CC3100, TRF7960A

I have CC3200 Launchpad Rev 4.1 connected to DLP-7970ABP (TRF7970A). I was able to verify that tag reading works correctly running this example (http://www.ti.com/tool/cc3200_nfc_card_reader ) when tested on actual tags.

I've installed Android's sample HCE app (https://developer.android.com/samples/CardEmulation/index.html) to see if TRF7970A would read the tag correctly when my Galaxy S7 is running in HCE. Upon placing my phone on the NFC reader, TI's example app would freeze on attempting to scan for ISO15693 tags. Since HCE only supports ISO14443 standard, I went ahead and commented that line so that TRF7970A would only scan for ISO14443 tags. 

//Iso15693FindTag(); // Scan for 15693 tags
Iso14443aFindTag(); // Scan for 14443A tags

Now, the example TI app doesn't freeze but the NFC reader isn't reading the tag from my Android phone.

Are there any modifications necessary to the existing TI example code? Does anyone have a working code for reading Android's HCE?

  • Hello Sokwhan,

    That code example uses a very rudimentary handling of NDEF messages which a lot of content hardcoded. It could be possible that the Android HCE device responds differently than expected and that is causing the issue.

    In general, if you want to support NDEF messages, you will need to use a different firmware base such as what is offered in this application note: www.ti.com/.../sloa227.pdf

    The sloa227 firmware has been able to read many Android HCE applications before, so it should work with your phone. However, this firmware is not ported to the CC3200.

    I would recommend using that firmware as a base and port it to the CC3200 rather than try to update the NDEF functionality in the existing code as that firmware base is outdated in the meantime and also implementing NDEF processes is complicated and will take a lot of time.

    If you want to see an example of WiFi+NFC Reader with sloa227 working together, there is a TI Design where the Tiva C is used with the CC3100 and TRF7970A: www.ti.com/.../TIDM-TM4C129XNFC
  • Hi Ralph,

    Many thanks for your reply. Currently, I don't have any plans on exchanging NDEF messages with TRF7970A and Android HCE. In fact, the android sample application from google specifies that it's using a low-level interface and not NDEF from their comments.

    /**
    * This is a sample APDU Service which demonstrates how to interface with the card emulation support
    * added in Android 4.4, KitKat.
    *
    * This sample replies to any requests sent with the string "Hello World". In real-world
    * situations, you would need to modify this code to implement your desired communication
    * protocol.
    *
    *This sample will be invoked for any terminals selecting AIDs of 0xF11111111, 0xF22222222, or
    * 0xF33333333. See src/main/res/xml/aid_list.xml for more details.
    *
    *Note: This is a low-level interface. Unlike the NdefMessage many developers
    * are familiar with for implementing Android Beam in apps, card emulation only provides a
    * byte-array based communication channel. It is left to developers to implement higher level
    * protocol support as needed.
    */

    So I figured that the TI example should work out of the box, provided it reads ISO14443A type tags correctly (I've been able to verify that the example app reads ISO15693 tags, but not ISO14443A because I don't have any at hand, other than Android's HCE). Another NFC reader we have at hand was able to read the emulated tag from Android HCE correctly, so it's probably the code from TRF7970A that's at problem.

    I did notice that I have to specify the AID in Android app in order for the NFC message exchange to be taken in place, as seen from comments.

    This sample will be invoked for any terminals selecting AIDs of 0xF11111111, 0xF22222222, or
    * 0xF33333333. See src/main/res/xml/aid_list.xml for more details.

    I'm thinking maybe this is the cause of the issue. Any way of specifying the AID in TRF7970A?

    Below is the relevant part of the Android example app source code, which may come in handy

    /*
     * Copyright (C) 2013 The Android Open Source Project
     *
     * 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.
     */
    
    package com.example.android.cardemulation;
    
    import android.nfc.cardemulation.HostApduService;
    import android.os.Bundle;
    import com.example.android.common.logger.Log;
    
    import java.util.Arrays;
    
    /**
     * This is a sample APDU Service which demonstrates how to interface with the card emulation support
     * added in Android 4.4, KitKat.
     *
     * <p>This sample replies to any requests sent with the string "Hello World". In real-world
     * situations, you would need to modify this code to implement your desired communication
     * protocol.
     *
     * <p>This sample will be invoked for any terminals selecting AIDs of 0xF11111111, 0xF22222222, or
     * 0xF33333333. See src/main/res/xml/aid_list.xml for more details.
     *
     * <p class="note">Note: This is a low-level interface. Unlike the NdefMessage many developers
     * are familiar with for implementing Android Beam in apps, card emulation only provides a
     * byte-array based communication channel. It is left to developers to implement higher level
     * protocol support as needed.
     */
    public class CardService extends HostApduService {
        private static final String TAG = "CardService";
        // AID for our loyalty card service.
        private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
        // ISO-DEP command HEADER for selecting an AID.
        // Format: [Class | Instruction | Parameter 1 | Parameter 2]
        private static final String SELECT_APDU_HEADER = "00A40400";
        // "OK" status word sent in response to SELECT AID command (0x9000)
        private static final byte[] SELECT_OK_SW = HexStringToByteArray("9000");
        // "UNKNOWN" status word sent in response to invalid APDU command (0x0000)
        private static final byte[] UNKNOWN_CMD_SW = HexStringToByteArray("0000");
        private static final byte[] SELECT_APDU = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
    
        /**
         * Called if the connection to the NFC card is lost, in order to let the application know the
         * cause for the disconnection (either a lost link, or another AID being selected by the
         * reader).
         *
         * @param reason Either DEACTIVATION_LINK_LOSS or DEACTIVATION_DESELECTED
         */
        @Override
        public void onDeactivated(int reason) { }
    
        /**
         * This method will be called when a command APDU has been received from a remote device. A
         * response APDU can be provided directly by returning a byte-array in this method. In general
         * response APDUs must be sent as quickly as possible, given the fact that the user is likely
         * holding his device over an NFC reader when this method is called.
         *
         * <p class="note">If there are multiple services that have registered for the same AIDs in
         * their meta-data entry, you will only get called if the user has explicitly selected your
         * service, either as a default or just for the next tap.
         *
         * <p class="note">This method is running on the main thread of your application. If you
         * cannot return a response APDU immediately, return null and use the {@link
         * #sendResponseApdu(byte[])} method later.
         *
         * @param commandApdu The APDU that received from the remote device
         * @param extras A bundle containing extra data. May be null.
         * @return a byte-array containing the response APDU, or null if no response APDU can be sent
         * at this point.
         */
        // BEGIN_INCLUDE(processCommandApdu)
        @Override
        public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
            Log.i(TAG, "Received APDU: " + ByteArrayToHexString(commandApdu));
            // If the APDU matches the SELECT AID command for this service,
            // send the loyalty card account number, followed by a SELECT_OK status trailer (0x9000).
            if (Arrays.equals(SELECT_APDU, commandApdu)) {
                String account = AccountStorage.GetAccount(this);
                byte[] accountBytes = account.getBytes();
                Log.i(TAG, "Sending account number: " + account);
                return ConcatArrays(accountBytes, SELECT_OK_SW);
            } else {
                return UNKNOWN_CMD_SW;
            }
        }
        // END_INCLUDE(processCommandApdu)
    
        /**
         * Build APDU for SELECT AID command. This command indicates which service a reader is
         * interested in communicating with. See ISO 7816-4.
         *
         * @param aid Application ID (AID) to select
         * @return APDU for SELECT AID command
         */
        public static byte[] BuildSelectApdu(String aid) {
            // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
            return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X",
                    aid.length() / 2) + aid);
        }
    
        /**
         * Utility method to convert a byte array to a hexadecimal string.
         *
         * @param bytes Bytes to convert
         * @return String, containing hexadecimal representation.
         */
        public static String ByteArrayToHexString(byte[] bytes) {
            final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
            char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
            int v;
            for (int j = 0; j < bytes.length; j++) {
                v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
                hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
                hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
            }
            return new String(hexChars);
        }
    
        /**
         * Utility method to convert a hexadecimal string to a byte string.
         *
         * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
         *
         * @param s String containing hexadecimal characters to convert
         * @return Byte array generated from input
         * @throws java.lang.IllegalArgumentException if input length is incorrect
         */
        public static byte[] HexStringToByteArray(String s) throws IllegalArgumentException {
            int len = s.length();
            if (len % 2 == 1) {
                throw new IllegalArgumentException("Hex string must have even number of characters");
            }
            byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
            for (int i = 0; i < len; i += 2) {
                // Convert each character into a integer (base-16), then bit-shift into place
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                        + Character.digit(s.charAt(i+1), 16));
            }
            return data;
        }
    
        /**
         * Utility method to concatenate two byte arrays.
         * @param first First array
         * @param rest Any remaining arrays
         * @return Concatenated copy of input arrays
         */
        public static byte[] ConcatArrays(byte[] first, byte[]... rest) {
            int totalLength = first.length;
            for (byte[] array : rest) {
                totalLength += array.length;
            }
            byte[] result = Arrays.copyOf(first, totalLength);
            int offset = first.length;
            for (byte[] array : rest) {
                System.arraycopy(array, 0, result, offset, array.length);
                offset += array.length;
            }
            return result;
        }
    }
    

  • Hello Sokwhan,

    Yes. The TRF7970A is just an NFC Transceiver which will transmit and receive NFC data packets. The MCU controls what it can send. As long the over the air protocol used (in this case, ISO14443) is supported, you can send any command you want.

    It looks like you are right about the NDEF part which confirms my initial thought on that they were using some different selection.

    If I remember the initial firmware base right, you would need to modify the NDEFApplicationSelect function first to select that AID.

    The modification would be something like this I believe:

    g_pui8TrfBuffer[ui8Offset++] = 0x8F; // Reset FIFO
    g_pui8TrfBuffer[ui8Offset++] = 0x91; // Send with CRC
    g_pui8TrfBuffer[ui8Offset++] = 0x3D; // Write Continuous
    g_pui8TrfBuffer[ui8Offset++] = 0x00; // Length of packet in bytes - upper and middle nibbles of transmit byte length
    g_pui8TrfBuffer[ui8Offset++] = 0xD0; // Length of packet in bytes - lower and broken nibbles of transmit byte length
    g_pui8TrfBuffer[ui8Offset++] = 0x02 // I-Block PCB: Read Block 0 or Block 1, with CID = 0, NAD = 0, no chaining
    g_pui8TrfBuffer[ui8Offset++] = 0x00; // CLA
    g_pui8TrfBuffer[ui8Offset++] = 0xA4; // INS = Select (Application in this case)
    g_pui8TrfBuffer[ui8Offset++] = 0x04; // P1
    g_pui8TrfBuffer[ui8Offset++] = 0x00; // P2
    g_pui8TrfBuffer[ui8Offset++] = 0x06; // Lc
    g_pui8TrfBuffer[ui8Offset++] = 0xF2; // Data = 0xF222222222
    g_pui8TrfBuffer[ui8Offset++] = 0x22;
    g_pui8TrfBuffer[ui8Offset++] = 0x22;
    g_pui8TrfBuffer[ui8Offset++] = 0x22;
    g_pui8TrfBuffer[ui8Offset++] = 0x22;
    g_pui8TrfBuffer[ui8Offset++] = 0x22;
    g_pui8TrfBuffer[ui8Offset++] = 0x00; // Le

    Please note I used a newer firmware base to do this.

    After making this modification, you can try and see if you can select the HCE application.

    You would need to do further digging into how that works to then read out the data as well, though some API's may work already. I don't think the CapabilityContainerSelect would likely as that is specific to NDEF, but the ReadBinary functions may.
  • also, from:  

    Android uses the AID to determine which HCE service the reader wants to talk to. Typically, the first APDU an NFC reader sends to your device is a "SELECT AID" APDU; this APDU contains the AID that the reader wants to talk to. Android extracts that AID from the APDU, resolves it to an HCE service, then forwards that APDU to the resolved service.

    You can send a response APDU by returning the bytes of the response APDU from processCommandApdu(). Note that this method will be called on the main thread of your application, which shouldn't be blocked. So if you can't compute and return a response APDU immediately, return null. You can then do the necessary work on another thread, and use the sendResponseApdu() method defined in the HostApduService class to send the response when you are done.

    Android will keep forwarding new APDUs from the reader to your service, until either:

    1. The NFC reader sends another "SELECT AID" APDU, which the OS resolves to a different service;
    2. The NFC link between the NFC reader and your device is broken.

    In both of these cases, your class's onDeactivated() implementation is called with an argument indicating which of the two happened.

    If you are working with existing reader infrastructure, you need to implement the existing application-level protocol that the readers expect in your HCE service.

    If you are deploying new reader infrastructure which you control as well, you can define your own protocol and APDU sequence. In general try to limit the amount of APDUs and the size of the data that needs to be exchanged: this makes sure that your users will only have to hold their device over the NFC reader for a short amount of time. A sane upper bound is about 1KB of data, which can usually be exchanged within 300ms.

    you can also check out the requirements on Android systems by the GSMA, too

  • Hi Ralph & Josh.

    After attempting to debug this problem for a while, I'm starting to think that the problem lies somewhere completely different.

    On observing the IRQ status register (0x0C) in Trf7970PortB interrupt handler, the value of the register is always returned as 128 (0x80), indicating that TX is working as it should, but not the RX.  I suspect there is something wrong with setting the ISO control register value. Here is what the TI example had:

    if (iso_control == 0x88)
    
      {
    
    
    /*
      	write[0] = IRQ_MASK;
    	write[1] = 0x3E;
    	Trf7970WriteSingle(write, 2);
    */
    
    	write[0] = ISO_CONTROL;
    	write[1] = 0x88;
    	Trf7970WriteSingle(write, 2);
    
    	write[0] = MODULATOR_CONTROL;
    	write[1] = 0x01;
    	Trf7970WriteSingle(write, 2);
    
    	write[0] = ADJUSTABLE_FIFO_LEVEL;			//this is register 0x14
    	write[1] = 0x0F;
    	Trf7970WriteSingle(write, 2);
      }

    Above that line, there was a commented code for initializing ISO control register for ISO14443A using the continuous write mode. So I've tried to use that version instead:

      if (iso_control == 0x88)
    
      {
    
        write[0] = 0x20;
        write[1] = 0x20;    //full power out, 3.3VDC
        write[2] = 0x88;
        write[3] = 0x00;
        write[4] = 0x00;
        write[5] = 0xC1;
        write[6] = 0xBB;
        write[7] = 0x20;
        write[8] = 0x0E;
        write[9] = 0x07;
        write[10] = 0x21;
        write[11] = 0x20;
        write[12] = 0x87;
    
        Trf7970WriteCont(write, 13);
    }

    Now, the application would sometimes correctly read the tag from Android HCE, which is a progress. But often times, the application would hang on attempting to reset the irq status (Trf7970ResetIrqStatus). Specifically, the application hangs when attempting to perform a dummy read from the FIFO over SPI.

    Any suggestions would be appreciated.

  • you cannot leave the ISO control register at 0x88, the ISO14443A standard starts out using no CRC, but then transitions to using it during the selection process of the card - during anti-collision (to get the complete UID). then stays that way during the rest of the activated session - with the ISO control register set to 0x08

  • Hi, Josh.

    I've tried your suggestion but I'm still experiencing the application freezing issue, on Trf7970ResetIrqStatus() method.

    void Iso14443aAnticollision(u08_t reqa)
    {
    	u08_t nvb = NVB_INIT;
    	u08_t ui8BlockNumber;
    	int cx;
    
    	//u08_t found = 0;
    	//u08_t SW1 = 0;
        rxtx_state = 1;
        Iso14443_config(RX_CRC); //Set CRC on anticollision
        McuDelayMillisecond(2);
    
        Iso14443a_command(WUPA);			//send WUPA (0x52) to wake up all tags
        ...
    

    Below is the code. I'm genuinely not sure what else could be wrong. I'll post the code here.

    iso14443a.c

    /*
     * {iso14443a.c}
     *
     * {ISO14443A Specific Functions & Anti-collision}
     *
     * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
     *
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    #include "hw_types.h"
    #include <stdio.h>
    #include "iso14443a.h"
    #include "trf7970.h"
    #include "hw_types.h"
    #include "trf7970BoosterPack.h"
    #include "uart_if.h"
    #include "timer.h"
    #include "timer_if.h"
    #include "utils.h"
    #include "gpio.h"
    #include "gpio_if.h"
    #include "hw_memmap.h"
    #include "uart_if.h"
    
    
    //===============================================================
    
    u08_t	complete_uid[14];
    u08_t	coll_poss = 0;
    u08_t	uid_pos = 0, uid_pos1;
    extern u08_t buf[300];
    extern u08_t i_reg;
    extern u08_t irq_flag;
    extern u08_t rx_error_flag;
    extern s08_t rxtx_state;
    extern u08_t stand_alone_flag;
    extern u08_t remote_flag;
    extern u08_t Tag_Count;
    extern u08_t g_tag_found;
    extern unsigned char NDEF_Nlen;
    extern u08_t g_uid[300];
    extern u08_t g_rssi[10];
    extern char g_block_content[200];
    extern char g_tag_content[600];
    
    // command
    #define REQA		0x26
    #define WUPA		0x52
    
    #define NVB_INIT 	0x20
    #define NVB_FULL	0x70
    #define LEVEL1		0x93
    #define LEVEL2		0x95
    #define LEVEL3		0x97
    #define RX_CRC		0x08
    #define NO_RX_CRC	0x88
    #define UART_PRINT              	Report
    //===============================================================
    // NAME: void Iso14443aFindTag(void)
    //
    // BRIEF: Is used to detect ISO14443A conform tags in stand alone 
    // mode.
    //
    // INPUTS:
    //	
    // OUTPUTS:
    //
    // PROCESS:	[1] turn on RF driver
    //			[2] do a complete anti-collision sequence
    //			[3] turn off RF driver
    //
    // NOTE: If ISO14443A conform Tag is detected, ISO14443A LED will
    //       be turned on.
    //
    // CHANGE:
    // DATE  		WHO	DETAIL
    // 23Nov2010	RP	Original Code
    //===============================================================
    
    void
    Iso14443aFindTag(void)
    {
    	//u08_t j;
    	//u08_t tag_found = 0;
    
    	Trf7970TurnRfOn();
    	
    	Trf7970WriteIsoControl(0x88);
    
    	// When a PICC is exposed to an un-modulated operating field
    	// it shall be able to accept a quest within 5 ms.
    	// PCDs should periodically present an un-modulated field of at least
    	// 5,1 ms duration. (ISO14443-3)
    	McuDelayMillisecond(20);
    
    	Iso14443aAnticollision(0x00);						// do a complete anti-collision sequence as described1
    	//tag_found = iso14443aAnticollision(0x00);
    
    	// in ISO14443-3 standard for type A
    	Trf7970TurnRfOff();
    
    	Trf7970ResetIrqStatus();
    
    }
    
    //===============================================================
    // NAME: void Iso14443aAnticollision(u08_t reqa)
    //
    // BRIEF: Is used to start the ISO14443A Anticollision Loop.
    //
    // INPUTS:
    //	Parameters:
    //		u08_t		reqa		REQA or WUPA
    //
    // OUTPUTS:
    //
    // PROCESS:	[1] send REQA or WUPA command
    //			[2] receive ATQA
    //			[3] perform bit frame anticollison loop
    //
    // NOTE: Collisions returned as “(z)”.
    //       Timeouts returned as “()”.
    //
    // CHANGE:
    // DATE  		WHO	DETAIL
    // 23Nov2010	RP	Original Code
    //===============================================================
    
    void Iso14443aAnticollision(u08_t reqa)
    {
    	u08_t nvb = NVB_INIT;
    	u08_t ui8BlockNumber;
    	int cx;
    
    	//u08_t found = 0;
    	//u08_t SW1 = 0;
        rxtx_state = 1;
        Iso14443_config(RX_CRC);
        McuDelayMillisecond(2);
    
        Iso14443a_command(WUPA);			//send WUPA (0x52) to wake up all tags
    
    	if(i_reg == 0xFF || i_reg == 0x02)
    	{
    		UART_PRINT("Entered 1\n");
    		uid_pos = 0;
    		Iso14443aLoop(0x01, nvb, &buf[40]);			// cascade level 1
    		unsigned char len;
    		unsigned int j;
    		if(stand_alone_flag == 1)
    		{
    
    /*			RATS();										//for ISO14443-4A card selection
    			NDEFApplicationSelect();					//Selects NDEF Application D2760000850101
    			CapabilityContainerSelect();				//Selects the Capability Container
    			ReadBinary(0, 15);							//for contents of the capability container
    			SelectNDEF();								//Selects NDEF Application
    			len = ReadBinary(0, 2);						//reads NDEF Application for length of message
    			ReadBinary2(2, len);							//for NDEF content
    			UartSendCString("NDEF Message: ");
    			UartPutChar('[');
    			for(j = 8; j < len+1; j++)
    			//for(j = 34; j < 47; j++)
    			{
    				UartPutChar(buf[j]);
    			}
    				UartPutChar(']');
    				UartPutCrlf();*/
    
    
    			cx = 0;
    			for (ui8BlockNumber = 0; ui8BlockNumber < 0x4; ui8BlockNumber=ui8BlockNumber + 4) 	//for dynamically reading all data blocks on tag
    			{
    				NFC_TYPE2_READ_4_BLOCKS(ui8BlockNumber);										//reference T2T operation specification (command 0x30)
    				cx = cx + snprintf(g_tag_content+cx, sizeof(g_tag_content), "%s", g_block_content);
    
    			}
    //			UART_PRINT(g_tag_content);
    /*
    			{
    				NFC_TYPE2_WRITE_BLOCK();										//reference T2T operation specification (command 0x30)
    			}
    */
    
    
    			McuDelayMillisecond(50);
    		}
    	}
    	else
    	{
    		LED_14443A_OFF;
    	}
    
    	Iso14443_config(NO_RX_CRC);
    
    	return;
    }											// Iso14443aAnticollision
    
    
    //===============================================================
    // NAME: void Iso14443aLoop(u08_t select, u08_t nvb, u08_t
    // 			*uid)
    //
    // BRIEF: Is used to run through the cascade levels.
    //
    // INPUTS:
    //	Parameters:
    //		u08_t		select		indicates cascade level
    //		u08_t		nvb			number of valid bits
    //		u08_t		*uid		known part of UID
    //	
    // OUTPUTS:
    //	Globals:
    //		u08_t		complete_uid[14]	stores UID
    //
    // PROCESS:	(ISO14443-3)
    //
    // NOTE: Collisions returned as “(z)”.
    //       Timeouts returned as “()”.
    //
    // CHANGE:
    // DATE  		WHO	DETAIL
    // 23Nov2010	RP	Original Code
    //===============================================================
    
    void
    Iso14443aLoop(u08_t cascade_level, u08_t nvb, u08_t *uid)
    {
    	u08_t	i = 0;
    	//u08_t	j = 0;
    	//u08_t   len = 0;
    	u08_t	nvbytes = 0, nvbits = 0, xbits = 0, found = 0;
    	u08_t new_uid[4];
    	u08_t select, new_uid1[4], coll_poss1, nvbits1;
    	u08_t cascade_level1;
    #ifdef ENABLE_HOST
    	u08_t rssi[2];
    #endif
    
    	while (cascade_level < 4)
    	{
    		switch (cascade_level)
    		{
    		case 1:
    			select = 0x93;
    			break;
    		case 2:
    			select = 0x95;
    			break;
    		case 3:
    			select = 0x97;
    			break;
    		default:
    			break;
    		}
    
    		if((nvb & 0x0F) != 0x00)
    		{
    			nvbytes = (nvb >> 4) - 2;			// the number of known valid bytes
    			xbits = nvb & 0x07;					// the number of known valid bits
    
    			// Both are used in the UID calculation
    			for(i = 0; i < xbits; i++)
    			{
    				nvbits = (nvbits << 1) + 1;
    			}
    		}
    		rx_error_flag = 0;
    		coll_poss = 0x21;
    		rxtx_state = 1;							// The response will be stored in buf[1] upwards
    		Iso14443aSelectCommand(select, nvb, uid);
    
    		while (coll_poss < 0x20) {
    			if(i_reg == 0x00){
    				break;
    			}
    		};
    		if (coll_poss == 0x20)
    			i_reg = 0x02;						// In case coll_poss=0x20 means didn't receive response
    		for(i = 0; i < 5; i++)
    		{
    			complete_uid[i+uid_pos] = buf[i + 1];
    		}
    		if(rx_error_flag == 0x02)
    		{
    			i_reg = 0x02;
    		}
    		if(i_reg == 0x02 || i_reg == 0x00)		// collision or timeout
    		{
    			UART_PRINT("Collision or timeout\n");
    			break;
    		}
    		if(i_reg == 0xff)						// if data received
    		{
    			for (i=0; i<nvbytes; i++)
    				complete_uid[i+uid_pos] = *(uid + i);
    			complete_uid[nvbytes+uid_pos] = (buf[1] &~nvbits) | (*(uid + nvbytes) & nvbits);
    			for (i=1; i<(5-nvbytes); i++)
    				complete_uid[i+nvbytes+uid_pos] = buf[1+i];
    
    			nvb = NVB_FULL;
    			rxtx_state = 1;
    			Iso14443aSelectCommand(select, nvb, &complete_uid[uid_pos]);
    			McuDelayMillisecond(6);
    			if (buf[1] & BIT2)				//uid not complete
    			{
    				cascade_level++;
    				uid_pos += 5;
    				nvb = NVB_INIT;
    			}
    			else				// uid completed, print UID to uart.
    			{
    				g_tag_found = ISO14443A;
    
    				#ifdef ENABLE_HOST
    
    				char * cptr;
    				cptr = (char *) g_uid;
    
    
    				Tag_Count++;
    //				UartPutCrlf();
    //				UartSendCString("ISO14443A UID:  ");
    
    //				UartPutChar('[');
    				switch (cascade_level)
    				{
    				case 1:
    					for (i=0; i<4; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					break;
    				case 2:
    					for (i=1; i<4; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					for (i=5; i<9; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					break;
    				case 3:
    					for (i=1; i<4; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					for (i=6; i<9; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					for (i=10; i<14; i++)
    					{
    //						UartPutByte(complete_uid[i]);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i] >> 4) & 0x0F);
    						cptr = cptr + sprintf(cptr, "%x", (complete_uid[i]) & 0x0F);
    					}
    					break;
    				default:
    					break;
    				}
    //				UartPutChar(',');
    
    				rssi[0] = RSSI_LEVELS;			// read RSSI levels
    				Trf7970ReadSingle(rssi, 1);
    //				UartPutByte(rssi[0]);
    				cptr = (char*) g_rssi;
    				cptr = cptr + sprintf(cptr, "%x", (rssi[0] >> 4) & 0x0F);
    				cptr = cptr + sprintf(cptr, "%x", rssi[0] & 0x0F);
    //				UartPutChar(']');
    
    //				UartPutCrlf();
    //				Report((char*) g_uid);
    
    				#endif
    	//		build_message(my_message, complete_uid, 14, 0,    "ISO14443A UID:  ");
    
    				if(stand_alone_flag == 1)
    					found = 1;
    				i_reg = 0x01;					// do nothing after
    				break;
    			}
    		}
    //		_nop();
    	}
    
    	if(i_reg == 0x00)							// timer interrupt
    	{	
    //		if(stand_alone_flag == 1)
    //		{
    //			#ifdef ENABLE_HOST
    //				UartPutChar('(');
    //				UartSendCString("No tag found/Error");
    //				UartPutChar(')');
    //				UartPutCrlf();
    //			#endif
    //		}
    	}
    
    	if(i_reg == 0x02)									// if collision occurred go into anti-collision
    	{
    		for (i=0; i<4; i++)
    		{
    			new_uid[i] = buf[i+1];
    		}
    		// a RX interrupt will happen after collision interrupt
    		McuDelayMillisecond(5);
    
    		if (coll_poss == 0x60 || coll_poss == 0x70)			// if all of 4 or 5 bytes of last level were in collision
    		{
    			cascade_level++;
    			uid_pos += 5;
    			coll_poss = 0x20;
    		}
    		else
    		{
    			// combine UCLn collected of last loop
    			for (i=0; i<nvbytes; i++)
    				new_uid[i] = *(uid + i);
    			new_uid[nvbytes] = (new_uid[nvbytes] &~ nvbits) | (*(uid + nvbytes) & nvbits);
    
    		}
    		// calculate new parameters
    		nvbytes = (coll_poss >> 4) - 2;				// how many bytes were collected
    		xbits  = coll_poss & 0x07;					// how many bits were collected
    		coll_poss++;
    		nvbits = 0;
    		for (i = 0; i < xbits; i++)
    		{
    			nvbits = (nvbits << 1) + 1;				// left shift to make a mask for last broken byte (create all bit 1 belong to how many bit in broken byte)
    		}
    		nvbits1 = (nvbits << 1) + 1;
    		nvbits1 = nvbits1 - nvbits;				// bit_mask1 use to separate next bit after last broken bit
    
    		new_uid[nvbytes] = new_uid[nvbytes] & nvbits;		// only keep collision bits
    
    		//back up before loop
    		for (i=0; i<=4; i++)
    		{
    			new_uid1[i] = new_uid[i];
    		}
    		coll_poss1 = coll_poss;
    		uid_pos1 = uid_pos;
    		cascade_level1 = cascade_level;
    
    		Iso14443aLoop(cascade_level, coll_poss, new_uid);		// recursive call for anti-collision procedure
    		McuDelayMillisecond(6);
    
    		Iso14443a_halt();
    
    		i_reg = 0x01;
    		Iso14443a_command(WUPA);
    		McuDelayMillisecond(6);
    
    		uid_pos = uid_pos1;
    		new_uid1[nvbytes] = new_uid1[nvbytes] + nvbits1;
    		Iso14443aLoop(cascade_level1, coll_poss1, new_uid1);		// recursive call for anti-collision procedure
    	}
    
    	if(stand_alone_flag == 1)
    	{
    		if(found == 1)
    		{	
    			LED_14443A_ON;
    		}
    		else
    		{	
    			LED_14443A_OFF;
    		}
    	}
    
    }														// Iso14443aLoop
    
    void ISO14443IRQWaitTimeout(u08_t txtimeout, u08_t rxtimeout)
    {
    
    	i_reg = 0x01;
    	while(i_reg != 0x00)
    	{
    //		McuCounterSet();
    //		COUNT_VALUE = COUNT_1ms * txtimeout;
    		A2CounterLoad(COUNT_1ms * txtimeout);
    		irq_flag = 0x00;
    		START_COUNTER;						// start timer up mode
    		while(irq_flag == 0x00)				// wait for interrupt
    		{
    		}
    	}										// wait for end of TX
    	RESET_COUNTER;
    
    	i_reg = 0x01;
    	while(i_reg == 0x01)		// wait for end of RX or timeout
    	{
    //		McuCounterSet();
    //		COUNT_VALUE = COUNT_1ms * rxtimeout;
    		A2CounterLoad(COUNT_1ms * rxtimeout);
    		irq_flag = 0x00;
    		START_COUNTER;						// start timer up mode
    		while(irq_flag == 0x00)
    		{
    		}									// wait for interrupt
    	}
    	RESET_COUNTER;
    }
    
    void Iso14443aSelectCommand(u08_t select, u08_t nvb, u08_t *uid)
    {
    	u08_t length;
    	Iso14443_config(RX_CRC);
    	//buf[0] = RX_SPECIAL_SETTINGS;
    	//buf[1] = 0x88;
    	//Trf7970WriteSingle(&buf[0], 2);
    
    	length = 5 + (nvb >> 4);
    	if((nvb & 0x0F) != 0x00)
    	{
    		length++;
    	}
    
    	buf[0] = 0x8F;							// prepare the SELECT command
    	if(nvb == 0x70)							// select command, otherwise anti-collision command
    
    	{
    		buf[1] = 0x91;						// transmit with CRC
    	}
    	else
    	{
    		buf[1] = 0x90;
    	}
    	buf[2] = 0x3D;
    	buf[3] = 0x00;
    	buf[4] = nvb & 0xF0;					// number of complete bytes
    	if((nvb & 0x07) != 0x00)
    	{
    		buf[4] |= ((nvb & 0x07) << 1) + 1; 	// number of broken bits, last bit is 1 means broken byte
    	}
    	buf[5] = select;						// can be 0x93, 0x95 or 0x97
    	buf[6] = nvb;							// number of valid bits
    	buf[7] = *uid;
    	buf[8] = *(uid + 1);
    	buf[9] = *(uid + 2);
    	buf[10] = *(uid + 3);
    	buf[11] = *(uid + 4);
    
    	Trf7970RawWrite(&buf[0], length);
    
    	ISO14443IRQWaitTimeout(5,50);
    	McuDelayMillisecond(1);
    }
    
    void Iso14443a_halt()
    {
    	Iso14443_config(NO_RX_CRC);
    
    	buf[0] = 0x8F;							// prepare the SELECT command
    		buf[1] = 0x90;
    	buf[2] = 0x3D;
    	buf[3] = 0x00;
    	buf[4] = 0x20;					// number of complete bytes
    	buf[5] = 0x50;						//halt
    	buf[6] = 0x00;							// number of valid bits
    
    	Trf7970RawWrite(&buf[0], 7);
    
    	i_reg = 0x01;
    	while(i_reg != 0x00)
    	{
    //		McuCounterSet();
    //		COUNT_VALUE = COUNT_1ms * 2;		// 2ms for TIMEOUT
    		A2CounterLoad(COUNT_1ms * 2);
    
    		irq_flag = 0x00;
    		START_COUNTER;						// start timer up mode
    		while(irq_flag == 0x00)				// wait for interrupt
    		{
    		}
    		RESET_COUNTER;
    	}										// wait for end of TX
    }
    
    void Iso14443a_command(u08_t command)
    {
        buf[0] = 0x8F;
        buf[1] = 0x90;
        buf[2] = 0x3D;
        buf[3] = 0x00;
        buf[4] = 0x0F;
    	buf[5] = command;
    
        rxtx_state = 1;
    
        Trf7970RawWrite(&buf[0], 6);
    
        IRQ_CLR;								// PORT2 interrupt flag clear
    	IRQ_ON;
    
    	ISO14443IRQWaitTimeout(5,50);
    }
    
    
    void Iso14443_config(u08_t crc)
    {
    	Trf7970WriteIsoControl(crc);
    	Trf7970ReadSingle(buf,1);
    }
    
    //===============================================================
    // NAME: void NFC_TYPE2_READ_4_BLOCKS(void)
    //
    // BRIEF: Is used to read NFC Type 2 Tag Platform data blocks four at a time in stand alone mode.
    //
    // INPUTS: StartBlock
    //
    // OUTPUTS:4 Blocks Data at time
    //
    // PROCESS:	[1] inside Find Tags Loop
    //			[2] NFC Forum TT2 BLock Data read sequence
    //			[3] Return data to Host
    //			[4] Loop to read all data blocks
    //
    // NOTE:
    //
    // CHANGE:
    // DATE  		WHO	DETAIL
    // 01/18/2014	JDW	Original Code
    //===============================================================
    void NFC_TYPE2_READ_4_BLOCKS(u08_t ui8StartBlock)
    {
    	u08_t	i = 1, j = 0;
    	u16_t	k;
    	int cx = 0;
    
    	//buf[0] = SPECIAL_FUNCTION;				//to enable 4-bit RX
    	//buf[1] = 0x04;							//setting bit 2 in register 0x10
    	//Trf7970WriteSingle(&buf[0], 2);
    
    	buf[0] = 0x8F;							//Reset FIFO
        buf[1] = 0x91;							//Send with CRC
        buf[2] = 0x3D;							//Write Continuous
        buf[3] = 0x00;							//upper and middle nibbles of # of bytes going to FIFO
        buf[4] = 0x20;							//lower nibble # and broken # of bytes going to FIFO (in this case 2 complete bytes are going to be transmitted)
    	buf[5] = 0x30;							//Read Command
    	buf[6] = ui8StartBlock;					//Starting from Block # (called Bno)
    
        rxtx_state = 1;
    
        Trf7970RawWrite(&buf[0], 7);
    
        IRQ_CLR;								// PORT2 interrupt flag clear
    	IRQ_ON;
    
    	//ISO14443IRQWaitTimeout(5,50);
    
    	i_reg = 0x01;
    	irq_flag = 0x00;
    	START_COUNTER;										//	Starting Timeout
    
    	while(irq_flag == 0x00)
    	{
    	}													// wait for end of TX interrupt
    	RESET_COUNTER;
    
    //	McuCounterSet();									// TimerA set
    //	COUNT_VALUE = COUNT_1ms * 20;
    	A2CounterLoad(COUNT_1ms * 20);
    	START_COUNTER;										// start timer up mode
    
    	irq_flag = 0x00;
    
    	while(irq_flag == 0x00)
    	{
    	}													// wait for interrupt
    	RESET_COUNTER;
    
    	while(i_reg == 0x01)								// wait for RX complete
    	{
    		k++;
    
    		if(k == 0xFFF0)
    		{
    			i_reg = 0x00;
    			rx_error_flag = 0x00;
    		}
    	}
    
    	if( i_reg == 0xFF)
    		{		// if received block data in buffer
    		if(stand_alone_flag == 1)
    		{
    			//found = 1;
    			#ifdef ENABLE_HOST
    			cx = 0;
    			for(j = 0; j < 4; j++){
    				cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%s", "NFC Type2 Block ");
    				cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%x", (ui8StartBlock >> 4) & 0x0F );
    				cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%x", ui8StartBlock & 0x0F );
    				cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%s", " Data:      [" );
    				ui8StartBlock ++;
    				for(i = 1+(j*4); i < 5+(j*4); i++)
    				{
    					cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%x", (buf[i] >> 4) & 0x0F );
    					cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%x", buf[i] & 0x0F );
    
    				}
    				cx = cx + snprintf(g_block_content+cx, sizeof(g_block_content)-cx, "%s", "]\n" );
    			}
    //				//UartSendCString("NFC Type2 Block 04: ");
    //				UartPutChar('[');
    //				for(i = 5; i < 9; i++)
    //				{
    //					UartPutByte(buf[i]);		// send block data to host
    //				}
    //				UartPutChar(']');
    //				UartPutCrlf();
    //				//UartSendCString("NFC Type2 Block 05: ");
    //				UartPutChar('[');
    //				for(i = 9; i < 13; i++)
    //				{
    //					UartPutByte(buf[i]);		// send block data to host
    //				}
    //				UartPutChar(']');
    //				UartPutCrlf();
    //				//UartSendCString("NFC Type2 Block 06: ");
    //				UartPutChar('[');
    //				for(i = 13; i < 17; i++)
    //				{
    //					UartPutByte(buf[i]);		// send block data to host
    //				}
    //				UartPutChar(']');
    //				UartPutCrlf();
    
    			#endif
    		}
    	}
    
    }
    
    //===============================================================
    // NAME: void NFC_TYPE2_WRITE_BLOCK(void)
    //
    // BRIEF: Is used to read NFC Type 2 Tag Platform data blocks four at a time in stand alone mode.
    //
    // INPUTS: StartBlock
    //
    // OUTPUTS:4 Blocks Data at time
    //
    // PROCESS:	[1] inside Find Tags Loop
    //			[2] NFC Forum TT2 BLock Data write sequence
    //			[3] Return data to Host
    //			[4] Loop to read all data blocks
    //
    // NOTE:
    //
    // CHANGE:
    // DATE  		WHO	DETAIL
    // 01/18/2014	JDW	Original Code
    //===============================================================
    void NFC_TYPE2_WRITE_BLOCK(void) //test function on one block for now (01/27/2014, JDW)
    {
    	u08_t	i = 1, j = 0;
    	u16_t	k;
    
    	buf[0] = ISO_CONTROL;
    	buf[1] = 0x88;							//to RX with CRC
    	Trf7970WriteSingle(&buf[0], 2);
    
    	buf[0] = SPECIAL_FUNCTION;			//to enable 4-bit RX
    	buf[1] = 0x04;							//setting bit 2 in register 0x10
    	Trf7970WriteSingle(&buf[0], 2);
    
    	buf[0] = 0x8F;							//Reset FIFO
        buf[1] = 0x91;							//Send with CRC
        buf[2] = 0x3D;							//Write Continuous
        buf[3] = 0x00;							//upper and middle nibbles of # of bytes going to FIFO
        buf[4] = 0x60;							//lower nibble # and broken # of bytes going to FIFO (in this case 2 complete bytes are going to be transmitted)
    	buf[5] = 0xA2;							//Write Command
    	buf[6] = 0x03;							//Block # (called Bno) to write
    	buf[7] = 0xE1;							// for Type 2 NDEF formatting, using on Page 3: E1:10:12:00 (Mifare Ultralight C) or E1:11:12:10 (Mifare Ultralight) THIS IS OTP BLOCK!
    	buf[8] = 0x10;							//										Page 4: 01:03:A0:10
    	buf[9] = 0x12;							//										Page 5:	44:03:00:FE (blocks 3, 4 & 5 required to be considered NDEF formatted and empty)
    	buf[10] = 0x00;							//
    
    
        rxtx_state = 1;
    
        Trf7970RawWrite(&buf[0], 11);
    
        IRQ_CLR;								// PORT2 interrupt flag clear
    	IRQ_ON;
    
    	//ISO14443IRQWaitTimeout(5,50);
    
    	i_reg = 0x01;
    	irq_flag = 0x00;
    	START_COUNTER;										//	Starting Timeout
    
    	while(irq_flag == 0x00)
    	{
    	}													// wait for end of TX interrupt
    	RESET_COUNTER;
    
    //	McuCounterSet();									// TimerA set
    //	COUNT_VALUE = COUNT_1ms * 20;
    	A2CounterLoad(COUNT_1ms * 20);
    	START_COUNTER;										// start timer up mode
    
    	irq_flag = 0x00;
    
    	while(irq_flag == 0x00)
    	{
    	}													// wait for interrupt
    	RESET_COUNTER;
    
    
    
    
    
    	while(i_reg == 0x01)								// wait for RX complete
    	{
    		k++;
    
    		if(k == 0xFFF0)
    		{
    			i_reg = 0x00;
    			rx_error_flag = 0x00;
    
    		}
    	}
    
    	if( i_reg == 0xFF)
    		{		// if received block data in buffer
    		if(stand_alone_flag == 1)
    		{
    			//found = 1;
    			#ifdef ENABLE_HOST
    			for(j = 0; j < 4; j++){
    				UartSendCString("NFC Type2 Block ");
    				//UartPutByte(ui8StartBlock++);
    				UartSendCString(":  [");
    				for(i = 1+(j*4); i < 5+(j*4); i++)
    				{
    					UartPutByte(buf[i]);		// send block data to host
    				}
    				UartPutChar(']');
    				UartPutCrlf();
    			}
    
    			#endif
    		}
    	}
    
    }


    trf7970.c

    /*
     * {trf7970.c}
     *
     * {TRF7970 Communication functions}
     *
     * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
     *
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    
    /****************************************************************
    * FILENAME: Trf7970.c
    *
    * BRIEF: Contains functions to initialize and execute
    * communication the Trf7970 via the selected interface.
    *
    * Copyright (C) 2010 Texas Instruments, Inc.
    *
    * AUTHOR(S): Reiser Peter        DATE: 02 DEC 2010
    *
    * EDITED BY:
    * *
    *
    ****************************************************************/
    
    #include "trf7970.h"
    #include "trf7970BoosterPack.h"
    #include "spi_for_trf.h"
    #include "hw_memmap.h"
    #include "hw_gpio.h"
    #include "gpio.h"
    #include "timer.h"
    #include "timer_if.h"
    //===============================================================
    
    u08_t    command[2];
    u08_t    direct_mode = 0;
    extern u08_t    buf[140];
    extern u08_t    i_reg;
    #ifdef ENABLE14443A
    extern u08_t    coll_poss;
    #endif
    extern u08_t    irq_flag;
    extern u08_t    rx_error_flag;
    extern s08_t    rxtx_state;
    extern u08_t    stand_alone_flag;
    
    //P_EVENT_HANDLER				pIraEventHandler = 0;
    
    //===============================================================
    
    void Trf7970ISR(u08_t *irq_status);
    //===============================================================
    //                                                              ;
    //===============================================================
    /*
    void
    Trf7970CommunicationSetup(void)
    {
      if(SPIMODE)
      {
        SpiSetup();
      }
    
    }
    */
    //===============================================================
    // NAME: void Trf7970DirectCommand (u08_t *pbuf)
    //
    // BRIEF: Is used to transmit a Direct Command to Trf7970.
    //
    // INPUTS:
    //    Parameters:
    //        u08_t        *pbuf        Direct Command
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] transmit Direct Command
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970DirectCommand(u08_t *pbuf)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiDirectCommand(pbuf);
      }
    
    }
    
    //===============================================================
    // NAME: void Trf7970DirectMode (void)
    //
    // BRIEF: Is used to start Direct Mode.
    //
    // INPUTS:
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] start Direct Mode
    //
    // NOTE: No stop condition
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970DirectMode(void)
    {
      direct_mode = 1;
    
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiDirectMode();
      }
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970DisableSlotCounter(void)
    {
      buf[40] = IRQ_MASK;
      buf[41] = IRQ_MASK;                // next slot counter
      Trf7970ReadSingle(&buf[41], 1);
      buf[41] &= 0xFE;                // clear BIT0 in register 0x01
      Trf7970WriteSingle(&buf[40], 2);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970EnableSlotCounter(void)
    {
      buf[40] = IRQ_MASK;
      buf[41] = IRQ_MASK;                // next slot counter
      Trf7970ReadSingle (&buf[41], 1);
      buf[41] |= BIT0;                // set BIT0 in register 0x01
      Trf7970WriteSingle(&buf[40], 2);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970InitialSettings(void)
    {
      command[0] = SOFT_INIT;
      Trf7970DirectCommand(command);
    
      command[0] = IDLE;
      Trf7970DirectCommand(command);
    
    
      #ifdef TRF7970A
        command[0] = MODULATOR_CONTROL;
        command[1] = 0x01;                    // ASK 100%, no SYS_CLK output
        Trf7970WriteSingle(command, 2);
      #endif
    }
    
    //===============================================================
    // The Interrupt Service Routine determines how the IRQ should  ;
    // be handled. The Trf7970 IRQ status register is read to       ;
    // determine the cause of the IRQ. Conditions are checked and   ;
    // appropriate actions taken.                                   ;
    //===============================================================
    
    void
    Trf7970ISR(u08_t *irq_status)
    {
    	if(*irq_status == 0xA0)			// BIT5 and BIT7
    	{								// TX active and only 3 bytes left in FIFO
    //		i_reg = 0x00;
    	}
    
    	else if(*irq_status == BIT7)
    	{								// TX complete
    		i_reg = 0x00;
    		Trf7970Reset();				// reset the FIFO after TX
    	}
    
    	else if((*irq_status & BIT1) == BIT1)
    	{								// collision error
    		i_reg = 0x02;				// RX complete
    
    #ifdef ENABLE14443A
    		coll_poss = COLLISION_POSITION;
    		Trf7970ReadSingle(&coll_poss, 1);
    		buf[rxtx_state] = FIFO;					// write the recieved bytes to the correct place of the
    													// buffer;
    		if (coll_poss >= 0x20)
    		{
    			Trf7970ReadCont(&buf[rxtx_state], 5);
    		}
    #endif
    
    		Trf7970StopDecoders();						// reset the FIFO after TX
    
    		Trf7970Reset();
    
    		Trf7970ResetIrqStatus();
    
    		GPIOIntClear(GPIOA1_BASE, GPIO_PIN_4);
    	}
    	else if(*irq_status == BIT6)
    	{	// RX flag means that EOF has been recieved
    		// and the number of unread bytes is in FIFOstatus regiter
    		if(rx_error_flag == 0x02)
    		{
    			i_reg = 0x02;
    			return;
    		}
    
    		*irq_status = FIFO_STATUS;
    		Trf7970ReadSingle(irq_status, 1);					// determine the number of bytes left in FIFO
    
    		*irq_status = 0x7F & *irq_status;
    		buf[rxtx_state] = FIFO;						// write the recieved bytes to the correct place of the buffer
    
    		Trf7970ReadCont(&buf[rxtx_state], *irq_status);
    		rxtx_state = rxtx_state + *irq_status;
    
    		Trf7970Reset();					// reset the FIFO after last byte has been read out
    
    		i_reg = 0xFF;					// signal to the recieve funnction that this are the last bytes
    	}
    	else if(*irq_status == 0x60)
    	{									// RX active and 9 bytes allready in FIFO
    		i_reg = 0x01;
    		buf[rxtx_state] = FIFO;
    		Trf7970ReadCont(&buf[rxtx_state], 9);	// read 9 bytes from FIFO
    		rxtx_state = rxtx_state + 9;
    
    		if((IRQ_PORT & IRQ_PIN) == IRQ_PIN)			// if IRQ pin high
    		{
    			Trf7970ReadIrqStatus(irq_status);
    
    			GPIOIntClear(GPIOA1_BASE, GPIO_PIN_4);
    
    			if(*irq_status == 0x40)							// end of recieve
    			{
    				*irq_status = FIFO_STATUS;
    				Trf7970ReadSingle(irq_status, 1);					// determine the number of bytes left in FIFO
    
    				*irq_status = 0x7F & *irq_status;
    				buf[rxtx_state] = FIFO;						// write the recieved bytes to the correct place of the buffer
    
    
    				Trf7970ReadCont(&buf[rxtx_state], *irq_status);
    				rxtx_state = rxtx_state + *irq_status;
    
    				i_reg = 0xFF;			// signal to the recieve funnction that this are the last bytes
    				Trf7970Reset();		// reset the FIFO after last byte has been read out
    			}
    			else if(*irq_status == 0x50)	// end of recieve and error
    			{
    				i_reg = 0x02;
    			}
    		}
    		else
    		{
    			Trf7970ReadIrqStatus(irq_status);
    
    			if(irq_status[0] == 0x00)
    			{
    				i_reg = 0xFF;
    			}
    		}
    	}
    	else if((*irq_status & BIT4) == BIT4)				// CRC error
    	{
    		if((*irq_status & BIT5) == BIT5)
    		{
    			i_reg = 0x01;	// RX active
    			rx_error_flag = 0x02;
    		}
    		if((*irq_status & BIT6) == BIT6)			// 4 Bit receive
    		{
    			buf[100] = FIFO;						// write the received bytes to the correct place of the buffer
    
    			Trf7970ReadCont(&buf[100], 1);
    
    			Trf7970Reset();
    
    			i_reg = 0x02;	// end of RX
    			rx_error_flag = 0x02;
    		}
    		else
    		{
    			i_reg = 0x02;	// end of RX
    		}
    	}
    	else if((*irq_status & BIT2) == BIT2)	// byte framing error
    	{
    		if((*irq_status & BIT5) == BIT5)
    		{
    			i_reg = 0x01;	// RX active
    			rx_error_flag = 0x02;
    		}
    		else
    			i_reg = 0x02;	// end of RX
    	}
    	else if((*irq_status == BIT0))
    	{						// No response interrupt
    		i_reg = 0x00;
    	}
    	else
    	{						// Interrupt register not properly set
    		i_reg = 0x02;
    
    		Trf7970StopDecoders();	// reset the FIFO after TX
    
    		Trf7970Reset();
    
    		Trf7970ResetIrqStatus();
    
    		GPIOIntClear(GPIOA1_BASE, GPIO_PIN_4);
    	}
    }                            // Interrupt Service Routine
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void Trf7970PortB(void)                            // interrupt handler
    {
      u08_t irq_status[4], iso_control;
    
      irq_flag = 0x02;
    
    // Sergey to fix  STOP_COUNTER;                            // stop timer mode
      RESET_COUNTER;
    
      do
      {
    	  GPIOIntClear(GPIOA1_BASE, GPIO_PIN_4);                            // interrupt flag clear
    
    	iso_control = ISO_CONTROL;
    	Trf7970ReadSingle(&iso_control, 1);
        Trf7970ReadIrqStatus(irq_status);
    
    	if((iso_control & BIT5) != BIT5)			// RFID mode
    	{
    		Trf7970ISR(irq_status);
    	}
    
      } while(GPIOIntStatus(GPIOA1_BASE,1) & GPIO_PIN_4);
    //  __bic_SR_register_on_exit(LPM0_bits);
    }
    
    //===============================================================
    // NAME: void Trf7970RawWrite (u08_t *pbuf, u08_t length)
    //
    // BRIEF: Is used to write direct to the Trf7970.
    //
    // INPUTS:
    //    Parameters:
    //        u08_t        *pbuf        raw data
    //        u08_t        length        number of data bytes
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] send raw data to Trf7970
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970RawWrite(u08_t *pbuf, u08_t length)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiRawWrite(pbuf, length);
      }
    }
    
    
    
    //===============================================================
    // NAME: void Trf7970ReadCont (u08_t *pbuf, u08_t length)
    //
    // BRIEF: Is used to read a specified number of Trf7970 registers
    // from a specified address upwards.
    //
    // INPUTS:
    //    Parameters:
    //        u08_t        *pbuf        address of first register
    //        u08_t        length        number of registers
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] read registers
    //            [2] write contents to *pbuf
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970ReadCont(u08_t *pbuf, u08_t length)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiReadCont(pbuf, length);
      }
      else                                    // parallel mode
      {
    
      }
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970ReadIrqStatus(u08_t *pbuf)
    {
      *pbuf = IRQ_STATUS;
      *(pbuf + 1) = IRQ_MASK;
      Trf7970ReadCont(pbuf, 2);           // read second reg. as dummy read
    
    }
    
    //===============================================================
    // NAME: void Trf7970ReadSingle (u08_t *pbuf, u08_t number)
    //
    // BRIEF: Is used to read specified Trf7970 registers.
    //
    // INPUTS:
    //    Parameters:
    //        u08_t        *pbuf        addresses of the registers
    //        u08_t        number        number of the registers
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] read registers
    //            [2] write contents to *pbuf
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970ReadSingle(u08_t *pbuf, u08_t number)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiReadSingle(pbuf, number);
      }
    
    }
    
    //===============================================================
    // resets FIFO                                                  ;
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970Reset(void)
    
    {
      command[0] = RESET;
      Trf7970DirectCommand(command);
    
    }
    
    //===============================================================
    // resets IRQ Status                                            ;
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970ResetIrqStatus(void)
    {
      u08_t irq_status[4];
      irq_status[0] = IRQ_STATUS;
      irq_status[1] = IRQ_MASK;
    
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        Trf7970ReadCont(irq_status, 2);        // read second reg. as dummy read
      }
    
    }
    
    //===============================================================
    //                                                              ;
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970RunDecoders(void)
    {
      command[0] = RUN_DECODERS;
      Trf7970DirectCommand(command);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970StopDecoders(void)
    {
      command[0] = STOP_DECODERS;
      Trf7970DirectCommand(command);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970TransmitNextSlot(void)
    {
      command[0] = TRANSMIT_NEXT_SLOT;
      Trf7970DirectCommand(command);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970TurnRfOff(void)
    {
      command[0] = CHIP_STATE_CONTROL;
      command[1] = CHIP_STATE_CONTROL;
      Trf7970ReadSingle(&command[1], 1);
      command[1] &= 0x1F;
      Trf7970WriteSingle(command, 2);
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970TurnRfOn(void)
    {
      u08_t write[4];
      write[0] = CHIP_STATE_CONTROL;
      write[1] = 0x20;                    // 3.3VDC, Full power out
      Trf7970WriteSingle(write, 2);
    
    }
    
    //===============================================================
    // NAME: void SpiWriteCont (u08_t *pbuf, u08_t length)
    //
    // BRIEF: Is used to write to a specific number of reader chip
    // registers from a specific address upwards.
    //
    // INPUTS:
    //    u08_t    *pbuf    address of first register followed by the
    //                    contents to write
    //    u08_t    length    number of registers + 1
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] write to the registers
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    //===============================================================
    
    void
    Trf7970WriteCont(u08_t *pbuf, u08_t length)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiWriteCont(pbuf, length);
      }
      else                                    // parallel mode
      {
    
      }
    }
    
    //===============================================================
    // 02DEC2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970WriteIsoControl(u08_t iso_control)
    {
      u08_t write[16];
    /*
      write[0] = ISO_CONTROL;
      write[1] = iso_control;
      write[1] &= ~BIT5;
      Trf7970WriteSingle(write, 2);
    
      iso_control &= 0x1F;
      write[0] = IRQ_MASK;
      write[1] = 0x3F;
      Trf7970WriteSingle(write, 2);
    */
    //#ifdef ENABLE15693                // this standard can be disabled in ISO15693.h
      if (iso_control == 0x02)
      {
        write[0] = 0x20;                  //Continuous Write, starting with register 0x00
        write[1] = 0x20;                  //Value for Chip Status Control Register 0x00, 0x20 = +3.3VDC, full power, etc.
        write[2] = 0x02;                  //Value for ISO Control Register 0x01, 0x02 = high tag data rate, etc.
        write[3] = 0x00;
        write[4] = 0x00;
        write[5] = 0xC1;
        write[6] = 0xBB;
        write[7] = 0x00;
        write[8] = 0x30;
        write[9] = 0x1F;
        write[10] = 0x01;
        write[11] = 0x40;
        write[12] = 0x03;
    
        Trf7970WriteCont(write, 13);      //writes registers 0x00:0x0B
      }
    //#endif
    
    //#ifdef ENABLE14443A            // this standard can be disabled in ISO14443A.h
      if (iso_control == 0x88)
    
      {
    
        write[0] = 0x20;
        write[1] = 0x20;    //full power out, 3.3VDC
        write[2] = 0x88;
        write[3] = 0x00;
        write[4] = 0x00;
        write[5] = 0xC1;
        write[6] = 0xBB;
        write[7] = 0x20;
        write[8] = 0x0E;
        write[9] = 0x07;
        write[10] = 0x21;
        write[11] = 0x20;
        write[12] = 0x87;
    
        Trf7970WriteCont(write, 13);
    
    
    
    /*  	write[0] = IRQ_MASK;
    	write[1] = 0x3E;
    	Trf7970WriteSingle(write, 2);
    
    	//Prev code
    
    	write[0] = ISO_CONTROL;
    	write[1] = 0x88;
    	Trf7970WriteSingle(write, 2);
    
    	write[0] = MODULATOR_CONTROL;
    	write[1] = 0x01;
    	Trf7970WriteSingle(write, 2);
    
    	write[0] = ADJUSTABLE_FIFO_LEVEL;			//this is register 0x14
    	write[1] = 0x0F;
    	Trf7970WriteSingle(write, 2);*/
    
    	//End of prev code
      }
      /*
          write[0] = 0x20;
          write[1] = 0x20;    //full power out, 3.3VDC
          write[2] = 0x88;
          write[3] = 0x00;
          write[4] = 0x00;
          write[5] = 0xC1;
          write[6] = 0xBB;
          write[7] = 0x20;
          write[8] = 0x0E;
          write[9] = 0x07;
          write[10] = 0x21;
          write[11] = 0x20;
          write[12] = 0x87;
    
          Trf7970WriteCont(write, 13);
    */
    //#endif
    
    //#ifdef ENABLE14443B            // this standard can be disabled in ISO14443B.h
      if (iso_control == 0x0C)
      {
        write[0] = 0x20;
        write[1] = 0x20;  //full power out, 3.3VDC
        write[2] = 0x0C;
        write[3] = 0x00;
        write[4] = 0x00;
        write[5] = 0xC1;
        write[6] = 0xBB;
        write[7] = 0x00;
        write[8] = 0x0D;
        write[9] = 0x07;
        write[10] = 0x03;
        write[11] = 0x00;
        write[12] = 0x87;
    
        Trf7970WriteCont(write, 13);
    
        write[0] = IRQ_MASK;
        write[1] = 0x3E;
        Trf7970WriteSingle(write, 2);
    
        write[0] = ADJUSTABLE_FIFO_LEVEL;
        write[1] = 0x0F;
        Trf7970WriteSingle(write, 2);
      }
    //#endif
    
    //#ifdef ENABLEFELICA            // this standard can be disabled in felica.h
      if (iso_control == 0x1A)
      {
        write[0] = 	0x20;
        write[1] = 	0x20;  //full power out, 3.3VDC
        write[2] = 	0x1A;
        //write[3] = 	0x00;
        //write[4] = 	0x00;
        //write[5] = 	0xC1;
        //write[6] = 	0xBB;
        //write[7] = 	0x00;
        //write[8] = 	0x14;
        //write[9] = 	0x00;
        //write[10] = 0x00;
        //write[11] = 0x00;
        //write[12] = 0x87;
    
        Trf7970WriteCont(write, 03);
    
        write[0] = IRQ_MASK;
        write[1] = 0x3E;
        Trf7970WriteSingle(write, 2);
    
        write[0] = ADJUSTABLE_FIFO_LEVEL;
        write[1] = 0x0F;
        Trf7970WriteSingle(write, 2);
      }
    //#endif
    
    }
    
    //===============================================================
    // NAME: void Trf7970WriteSingle (u08_t *pbuf, u08_t length)
    //
    // BRIEF: Is used to write to specified reader chip registers.
    //
    // INPUTS:
    //    u08_t    *pbuf    addresses of the registers followed by the
    //                    contents to write
    //    u08_t    length    number of registers * 2
    //
    // OUTPUTS:
    //
    // PROCESS:    [1] write to the registers
    //
    // CHANGE:
    // DATE          WHO    DETAIL
    // 24Nov2010    RP    Original Code
    //===============================================================
    
    void
    Trf7970WriteSingle(u08_t *pbuf, u08_t length)
    {
      if(SPIMODE)                                // SPI mode given by jumper setting
      {
        SpiWriteSingle(pbuf, length);
      }
      else                                    // parallel mode
      {
    
      }
    }
    

     
  • that looks like very old code, from the TRF7960A or -70A EVM example.
    i would not use it.
    instead, use the code base like from sloc297 or other newer and more complete codebase.
  • Hi, Josh.

    I've managed to port the sloc297 example to CC3200. Reading ISO15693 type tags works as expected.

    However, I'm having troubles again with reading ISO14443A tags (Both actual tag & Android HCE). IRQ Status registers correctly show 0x80 (TX_COMPLETE) and 0x40 (RX_COMPLETE) but it shows 0x00 (NO_RESPONSE_RECEIVED?) right after. The NO_RESPONSE_RECEIVED is causing the tag reading to not proceed beyond Iso14443a_PollingCommand. I've added some debug outputs to terminal and here's what it's showing:

    ==================================
    Begin Find
    
    Entering tag selection
    IRQ Status: 80
    Status: TX_COMPLETE
    IRQ Status: 40
    Status: RX_COMPLETE
    IRQ Status: 0
    Status: NO_RESPONSE_RECEIVED
    Querying Iso14443a_PollingCommand status
    Status: NO_RESPONSE_RECEIVED

    Not sure why IRQ would immediately generate NO_RESPONSE_RECEIVED in this case. Any suggestions? Here's the edited source code:

    main.c

     

    //*****************************************************************************
    //
    //!	NFCReaderApp
    //!
    //! @brief  Runs NFC reader application and provisioning.
    //!
    //! @param  none
    //!
    //! @return none
    //
    //*****************************************************************************
    void NFCReaderApp ( void *pvParameters )
    {
    	while(1)
    	{
    		UART_PRINT("==================================\n\r");
    		UART_PRINT("Begin Find \n\r");
    		g_tag_found = 0;
    		// TRF IRQ disable and clear
    		IRQ_OFF;
    		// TRF disable
    		TRF_OFF;
    		// delay at least 10 ms
    		osi_Sleep(100);
    
    		// Enter LPM3
    		TRF_ON;
    		// Must wait at least 4.8 mSec to allow TRF7970A to initialize.
    		osi_Sleep(5);
    
    		//ISO15693FindTag();					// Scan for 15693 tags
    		ISO14443aFindTag();					// Scan for 14443A tags
    
    		if(g_tag_found) {
    			UART_PRINT("Tag Found \n\r");
    			//g_uiNFCAppState = SEND_EMAIL_sta;
    
    		}
    		osi_Sleep(1000);
    	}
    
    }

    iso14443a.c

     

    /*
     * File Name: iso14443a.c
     *
     * Description: ISO14443A Specific Functions
     *
     * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
     *
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    
    #include "hw_memmap.h"
    #include "iso14443a.h"
    #include "trf7970BoosterPack.h"
    #include "uart_if.h"
    #include "gpio.h"
    #include "gpio_if.h"
    
    //===============================================================
    //		Global Variables
    //===============================================================
    
    extern u08_t g_ui8TrfBuffer[NFC_FIFO_SIZE];
    static volatile tTRF797x_Status g_sTrfStatus;
    
    static tISO14443A_UidSize g_sUidSize = ISO14443A_UID_UNKNOWN;
    static u08_t g_pui8CompleteUid[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    static u08_t g_pui8PartialUid[5] = {0x00,0x00,0x00,0x00,0x00};
    static u08_t g_ui8UidPos = 0;
    static u08_t g_ui8ValidUidByteCount = 0;
    static u08_t g_ui8ValidUidBitCount = 0;
    static u08_t g_ui8ValidBits;
    
    static u08_t g_ui8RecursionCount = 0;
    static u08_t g_ui8MaxRecurviseCalls = 5;
    
    static u08_t g_ui8Iso14443aSAK;
    static bool g_bType4ACompliant = false;
    static u08_t g_ui8AtsSupportedBitrates = 0x00; // This is used to store the ATS reply for TA(1) which contains the Tags supported bitrates - needed to determine PPS request parameters.
    
    //===============================================================
    //
    // Iso14443a_TagSelection - Process to detect and select
    // ISO14443A/NFC Type 2/4A Tag Platform compliant tags.
    //
    // \param ui8Command is the Polling command to be issued by
    // the TRF797x for ISO14443A tag detection.
    //
    // This function issues polling command, processes the ATQA, and
    // handles sending correct anticollision and selection commands.
    //
    // When a collision occurs, this function will call the
    // anticollision function to handle the collision.
    //
    // \return ui8Status returns whether or not an ISO14443A
    // compliant tag has been successfully selected.
    //
    //===============================================================
    
    u08_t Iso14443a_TagSelection(u08_t ui8Command)
    {
    	UartPutCrlf();
    	UartSendCString("Entering tag selection\n\r");
    	u08_t ui8Index = 0;
    	u08_t ui8LoopCount = 0;
    	u08_t ui8Status = STATUS_FAIL;
    	bool bSendCT = false;
    	tISO14443A_UidStatus sUidProgress = CASCADE1;
    	tCollisionStatus sCollisionStatus = NO_COLLISION;
    
    	// Clear UID to store new one
    	for(ui8Index = 0; ui8Index < 10; ui8Index++)
    	{
    		g_pui8CompleteUid[ui8Index] = 0x00;
    	}
    	// Clear partial UID buffer
    	for (ui8LoopCount = 0; ui8LoopCount < 5; ui8LoopCount++)
    	{
    		g_pui8PartialUid[ui8LoopCount] = 0x00;
    	}
    
    	g_ui8UidPos = 0;				// Reset UID Position Marker
    	g_ui8ValidUidByteCount = 0;		// Reset Valid Bytes Received Counter
    	g_ui8ValidUidBitCount = 0; 		// Reset Valid Bits Received Counter
    	g_ui8Iso14443aSAK = 0;			// Reset the SAK
    	g_bType4ACompliant = false; 	// Reset Type 4A Compliance
    	g_ui8AtsSupportedBitrates = 0;	// Reset the ATS Reply for TA(1)
    	g_ui8ValidBits = 0; 			// Clear Valid Bit global
    
    	// Poll for a ISO14443A tag
    	if (Iso14443a_PollingCommand(ui8Command))
    	{
    		if (g_sTrfStatus == RX_COMPLETE)
    		{
    			// Check ATQA Response for UID size
    			if ((g_ui8TrfBuffer[0] & 0xC0) == 0x00)
    			{
    				g_sUidSize = ISO14443A_UID_SINGLE;
    			}
    			else if ((g_ui8TrfBuffer[0] & 0xC0) == 0x40)
    			{
    				g_sUidSize = ISO14443A_UID_DOUBLE;
    			}
    			else if ((g_ui8TrfBuffer[0] & 0xC0) == 0x80)
    			{
    				g_sUidSize = ISO14443A_UID_TRIPLE;
    			}
    			else
    			{
    				g_sUidSize = ISO14443A_UID_UNKNOWN;
    			}
    		}
    		else
    		{
    			// Collision occurred, UID size not known
    			g_sUidSize = ISO14443A_UID_UNKNOWN;
    		}
    	}
    	else
    	{
    		// No response to polling command, exit function
    		ui8Status = STATUS_FAIL;
    		g_ui8RecursionCount = 0; // Reset the recursion count for the anticollision loops
    		return ui8Status;
    	}
    
    	while (sUidProgress != UID_COMPLETE)
    	{
    
    		sCollisionStatus = Iso14443a_AnticollisionCommand(sUidProgress, NVB_INIT, &g_pui8CompleteUid[0]);	// Call anticollision loop function
    
    		UartSendCString("Collision Status: ");
    
    		// Process the response
    		if (sCollisionStatus == NO_COLLISION)
    		{
    			UartSendCString("NO_COLLISION\n\r");
    			// Store the UID and keep track if the CT byte needs to be sent
    			bSendCT = Iso14443a_StoreUid(sUidProgress,&g_ui8TrfBuffer[0]);
    
    			// Issue Select command
    			if (Iso14443a_SelectCommand(sUidProgress,&g_pui8CompleteUid[g_ui8UidPos],bSendCT)) 	// Issue the Select Command
    			{
    				// If successful, use SAK information to determine if the UID is complete
    				if ((g_ui8Iso14443aSAK & BIT2) == 0x00)
    				{
    					// UID complete, set status to success
    					ui8Status = STATUS_SUCCESS;
    					sUidProgress = UID_COMPLETE;
    
    					if (g_sUidSize == ISO14443A_UID_UNKNOWN)
    					{
    						if (sUidProgress == CASCADE1)
    						{
    							g_sUidSize = ISO14443A_UID_SINGLE;
    						}
    						else if (sUidProgress == CASCADE2)
    						{
    							g_sUidSize = ISO14443A_UID_DOUBLE;
    						}
    						else if (sUidProgress == CASCADE3)
    						{
    							g_sUidSize = ISO14443A_UID_TRIPLE;
    						}
    					}
    				}
    				else
    				{
    					// UID is not Complete, increase cascade level, update UidSize as well
    					if (sUidProgress == CASCADE1)
    					{
    						sUidProgress = CASCADE2;
    						if (g_sUidSize == ISO14443A_UID_UNKNOWN)
    						{
    							g_sUidSize = ISO14443A_UID_DOUBLE;
    						}
    					}
    					else if (sUidProgress == CASCADE2)
    					{
    						sUidProgress = CASCADE3;
    						if (g_sUidSize == ISO14443A_UID_UNKNOWN)
    						{
    							g_sUidSize = ISO14443A_UID_TRIPLE;
    						}
    					}
    					else
    					{
    						// Either Cascade was already CASCADE3 or an error occured, so break to hit re-try loop
    						sUidProgress = UID_INCOMPLETE;
    						break;
    					}
    
    				}
    			}
    			else
    			{
    				// Break to hit the re-try loop
    				sUidProgress = UID_INCOMPLETE;
    				break;
    			}
    		}
    		else if (sCollisionStatus == COLLISION)
    		{
    			UartSendCString("COLLISION\n\r");
    			// If a collision occurs, call the Anticollision loop to handle tag collisions
    			sCollisionStatus = Iso14443a_AnticollisionLoop(sUidProgress);
    
    			// Check if the anticollision loop is successful
    			if (sCollisionStatus == NO_COLLISION)
    			{
    				// If successful, use SAK information to determine if the UID is complete
    				if ((g_ui8Iso14443aSAK & BIT2) == 0x00)
    				{
    					// UID complete, set status to success
    					ui8Status = STATUS_SUCCESS;
    					sUidProgress = UID_COMPLETE;
    				}
    				else
    				{
    					// UID is not Complete, increase cascade level, update UidSize as well
    					if (sUidProgress == CASCADE1)
    					{
    						sUidProgress = CASCADE2;
    					}
    					else if (sUidProgress == CASCADE2)
    					{
    						sUidProgress = CASCADE3;
    					}
    					else
    					{
    						// Either Cascade was already CASCADE3 or an error occured, so break to hit re-try loop
    						sUidProgress = UID_INCOMPLETE;
    						break;
    					}
    				}
    			}
    			else
    			{
    				break;
    			}
    		}
    		else
    		{
    			// Other error occurred, do not proceed
    			sUidProgress = UID_INCOMPLETE;
    			g_ui8RecursionCount = 0; // Reset the recursion count for the anticollision loops
    			return ui8Status;
    		}
    	}
    
    	if (sUidProgress == UID_INCOMPLETE)
    	{	// Some error occurred, attempt to find the tag again
    
    		if (g_ui8RecursionCount < g_ui8MaxRecurviseCalls)
    		{
    			UartSendCString("Recursively calling TAG find\n\r");
    			g_ui8RecursionCount++;
    			ui8Status = Iso14443a_TagSelection(ui8Command);
    		}
    		else
    		{
    			g_ui8RecursionCount = 0; // Reset the recursion count for the anticollision loops
    			return ui8Status;
    		}
    	}
    
    	// This won't repetively trigger after the recursive call of Iso14443a_TagSelection since the sUidProgress will not change
    	if (sUidProgress == UID_COMPLETE)
    	{
    		LED_14443A_ON;
    #ifdef ENABLE_HOST
    		// UID Completed
    		UartPutCrlf();
    		UartSendCString("Anticollison Completed");
    		UartPutCrlf();
    
    		// Output UID to UART Terminal
    		UartSendCString("ISO14443A UID:  ");
    		UartPutChar('[');
    		if (g_sUidSize == ISO14443A_UID_UNKNOWN)	// Assume ID is a single if it has not been defined to this point.
    		{
    			g_sUidSize = ISO14443A_UID_SINGLE;
    		}
    		for (ui8LoopCount=0; ui8LoopCount<g_sUidSize; ui8LoopCount++)
    		{
    			UartPutByte(g_pui8CompleteUid[ui8LoopCount]);
    		}
    		UartPutChar(']');
    		UartPutCrlf();
    #endif
    		// Output compliance to ISO14443-4
    		if (g_ui8Iso14443aSAK & BIT5)
    		{
    #ifdef ENABLE_HOST
    			UartSendCString("Tag is ISO14443-4 Compliant");
    			UartPutCrlf();
    #endif
    			g_bType4ACompliant = true;
    		}
    		else
    		{
    #ifdef ENABLE_HOST
    			UartSendCString("Tag is not ISO14443-4 Compliant");
    			UartPutCrlf();
    #endif
    			g_bType4ACompliant = false;
    		}
    #ifdef ENABLE_HOST
    		UartPutCrlf();
    #endif
    	}
    
    	g_ui8RecursionCount = 0; // Reset the recursion count for the anticollision loops after anticollision is finished
    	return ui8Status;
    }
    
    //===============================================================
    //
    // Iso14443a_AnticollisionLoop - Issue the polling command for
    // ISO14443A compliant tags.
    //
    // \param sCascade is the current anticollision cascade.
    //
    // This function handles the ISO14443A anticollision procedures
    // including dealing with receiving broken bytes and issuing
    // anticollisions based on those broken bytes. It will run until
    // a complete UID is received unless an error occurs.
    //
    // This function uses a recursive call for the anticollision
    // process.
    //
    // \return sStatus returns a status based on what tag response is
    // received following the most recently issued Anticollision
    // command.
    //
    //===============================================================
    
    tCollisionStatus Iso14443a_AnticollisionLoop(tISO14443A_UidStatus sCascade)
    {
    	u08_t ui8NVB = NVB_INIT;
    	u08_t	ui8NVBytes = 0;
    	u08_t	ui8NVBits = 0;
    	u08_t	ui8NVBitCount = 0;
    	u08_t	ui8CollisionPosition = 0;
    	u08_t	ui8LoopCount = 0;
    	tCollisionStatus sStatus = COLLISION;
    
    	// Note: The g_ui8UidPos will be used differently in this function in that it will track where to place received
    	// valid UID bytes rather than mark the location of the first byte as it does in all other functions.
    	// When a full UID is received, the Iso14443a_StoreUid function will be called which will restore the g_ui8UidPos
    	// value to what is expected by the rest of the firmware. If a microcontroller with larger RAM reserves is used,
    	// a seperate global variable could be used instead.
    
    	ui8CollisionPosition = Trf797xGetCollisionPosition();		// Get the collision position information from the TRF driver
    
    	ui8NVBytes = (ui8CollisionPosition >> 4) - 2;	// This represents the number of known valid bytes of the UID
    	ui8NVBitCount = ui8CollisionPosition & 0x07;	// This represents the number of known valid bits of the UID (can't be more than 8 or else it would be a valid byte)
    
    	g_ui8ValidUidBitCount = ui8NVBitCount;			// Set the valid bit count to be equal to the received value from the TRF
    
    	// Use the number of bits received to generate the value of the bits received so far
    	for(ui8LoopCount = 0; ui8LoopCount < ui8NVBitCount; ui8LoopCount++)
    	{
    		ui8NVBits = (ui8NVBits << 1) + 1;			// Store the info for the valid bits
    	}
    
    	if (g_ui8ValidUidByteCount < ui8NVBytes)
    	{
    		if ((ui8NVBytes-g_ui8ValidUidByteCount) > 5)
    		{
    			sStatus = COLLISION_ERROR;
    			return sStatus;
    		}
    
    		// Store the received bytes of the UID in a storage buffer
    		for (ui8LoopCount = 0; ui8LoopCount < (ui8NVBytes-g_ui8ValidUidByteCount); ui8LoopCount++)
    		{
    			g_pui8PartialUid[ui8LoopCount+g_ui8UidPos] |= g_ui8TrfBuffer[ui8LoopCount];
    		}
    
    		g_ui8UidPos = ui8LoopCount+g_ui8UidPos;		// Set the UID Position indicator to the next array index
    
    		if (g_ui8UidPos > 4)
    		{
    			sStatus = COLLISION_ERROR;
    			return sStatus;
    		}
    
    		g_ui8ValidUidByteCount = ui8NVBytes;		// Set the Valid byte count equal to what was received by the TRF
    
    		// Store the received bits of the UID in a storage buffer
    				// "The valid bits shall be part of the UID CLn that was received before a collision occurred
    				// followed by a (0)b or (1)b, decided by the PCD. A typical implementation adds a (1)b."
    		if (g_ui8ValidUidBitCount < 7)
    		{
    			// Since the valid bits are not at the maximum amount of bits allowed, add the extra bit at the end of the UID
    			g_pui8PartialUid[g_ui8UidPos] = ((g_ui8TrfBuffer[g_ui8ValidUidByteCount] & ui8NVBits));
    			g_ui8ValidBits = g_pui8PartialUid[g_ui8UidPos];		// Save the current valid bits in a variable
    
    			// NVB is equivalent to the value received in the TRF797x Collision Position Register plus one for the extra bit added per the standard.
    			ui8NVB = ui8CollisionPosition+1; 		// "The PCD shall assign NVB with a value that specifies the number of valid bits of UID CLn."
    			g_ui8ValidUidBitCount++;				// Increment the valid bit count by one to mark the extra bit which was added per specifications.
    		}
    		else
    		{
    			g_pui8PartialUid[g_ui8UidPos] = (g_ui8TrfBuffer[g_ui8ValidUidByteCount] & ui8NVBits);
    			g_ui8ValidBits = g_pui8PartialUid[g_ui8UidPos];		// Save the current valid bits in a variable
    
    			// NVB is equivalent to the value received in the TRF797x Collision Position Register plus one for the extra bit added per the standard.
    			ui8NVB = ui8CollisionPosition; 			// "The PCD shall assign NVB with a value that specifies the number of valid bits of UID CLn."
    		}
    	}
    	else
    	{
    		// Update the valid bits based on the current valid bits as well as the newly received valid bits from the tag response
    				// "The valid bits shall be part of the UID CLn that was received before a collision occurred
    				// followed by a (0)b or (1)b, decided by the PCD. A typical implementation adds a (1)b."
    		if (g_ui8ValidUidBitCount < 7)
    		{
    			// Since the valid bits are not at the maximum amount of bits allowed, add the extra bit at the end of the UID
    			g_pui8PartialUid[g_ui8UidPos] = (g_ui8ValidBits | ((g_ui8TrfBuffer[0] & ui8NVBits) << (g_ui8ValidUidBitCount-ui8NVBitCount)));
    			g_ui8ValidBits = g_pui8PartialUid[g_ui8UidPos];		// Save the current valid bits in a variable
    
    			ui8NVB = ui8CollisionPosition+1; 		// "The PCD shall assign NVB with a value that specifies the number of valid bits of UID CLn."
    			g_ui8ValidUidBitCount++;				// Increment the valid bit count by one to mark the extra bit which was added per specifications.
    		}
    		else
    		{
    			g_pui8PartialUid[g_ui8UidPos] = (g_ui8ValidBits | ((g_ui8TrfBuffer[0] & ui8NVBits) << (g_ui8ValidUidBitCount-ui8NVBitCount)));
    			g_ui8ValidBits = g_pui8PartialUid[g_ui8UidPos];		// Save the current valid bits in a variable
    
    			ui8NVB = ui8CollisionPosition; 			// "The PCD shall assign NVB with a value that specifies the number of valid bits of UID CLn."
    		}
    	}
    
    	McuDelayMillisecond(1);							// Small delay prior to sending out packet.
    
    	sStatus = Iso14443a_AnticollisionCommand(sCascade,ui8NVB,&g_pui8PartialUid[0]);				// Issue anti-collision command with the partial UID
    
    	if (sStatus == NO_COLLISION)
    	{
    		// No Collision means the anticollision command was successful and the remaining bytes were received
    
    		g_pui8PartialUid[g_ui8UidPos] = g_pui8PartialUid[g_ui8UidPos] | g_ui8TrfBuffer[0]; 		// Combine broken byte with 1st received byte to finalize the 1st byte of the UID
    		g_ui8UidPos++;								// Increment the UID Position Indicator
    		g_ui8ValidUidBitCount = 0;					// Reset the valid bit counter
    		g_ui8ValidBits = 0;							// Reset the valid bit variable
    
    		// Store the other bytes
    		for (ui8LoopCount = 0; ui8LoopCount < (5-g_ui8UidPos); ui8LoopCount++)
    		{
    			g_pui8PartialUid[ui8LoopCount+g_ui8UidPos] = g_ui8TrfBuffer[(ui8LoopCount+1)];	// Store remaining received UID bytes into the partial UID buffer
    		}
    
    		// Issue the Select Command with the fully received UID
    		if (Iso14443a_SelectCommand(sCascade,&g_pui8PartialUid[0],false))
    		{
    			// Received the SAK from the Select Command (This is stored in a global within the Select function)
    
    			// If the UID Size is not known yet
    			if (g_sUidSize == ISO14443A_UID_UNKNOWN)
    			{
    				// Use SAK information to determine if the UID is complete
    				if ((g_ui8Iso14443aSAK & BIT2) == 0x00)
    				{
    					if (sCascade == CASCADE1)
    					{
    						g_sUidSize = ISO14443A_UID_SINGLE;
    					}
    					else if (sCascade == CASCADE2)
    					{
    						g_sUidSize = ISO14443A_UID_DOUBLE;
    					}
    					else if (sCascade == CASCADE3)
    					{
    						g_sUidSize = ISO14443A_UID_TRIPLE;
    					}
    				}
    				else
    				{
    					// UID is not complete, update UidSize as well
    					if (sCascade == CASCADE1)
    					{
    						g_sUidSize = ISO14443A_UID_DOUBLE;
    					}
    					else if (sCascade == CASCADE2)
    					{
    						g_sUidSize = ISO14443A_UID_TRIPLE;
    					}
    				}
    			}
    
    			// Store the partial UID into the global UID buffer
    			Iso14443a_StoreUid(sCascade,&g_pui8PartialUid[0]);
    
    			// Clear partial UID buffer in order to handle future collisions
    			for (ui8LoopCount = 0; ui8LoopCount < 5; ui8LoopCount++)
    			{
    				g_pui8PartialUid[ui8LoopCount] = 0x00;
    			}
    
    			// Set status to NO_COLLISION and exit function
    			sStatus = NO_COLLISION;
    			return sStatus;
    		}
    		else
    		{
    			sStatus = COLLISION_ERROR;
    		}
    	}
    	else if (sStatus == COLLISION)
    	{
    		// If a collision occurred, check the Recursion Counter and then call Anticollision Loop function again if the condition is met
    		if (g_ui8RecursionCount < g_ui8MaxRecurviseCalls)
    		{
    			g_ui8RecursionCount++;	// Increment Recursion Counter
    			sStatus = Iso14443a_AnticollisionLoop(sCascade);	// Recursive call of Anticollision Loop
    		}
    		else
    		{
    			sStatus = COLLISION_ERROR;
    		}
    	}
    	else
    	{
    		// For all other statuses, return the status that was received
    	}
    
    	return sStatus;
    }
    
    
    //===============================================================
    //
    // Iso14443a_PollingCommand - Issue the polling command for
    // ISO14443A compliant tags.
    //
    // \param ui8Command is the polling command to be issued.
    //
    // This function sends the Polling command based on the inputted
    // command (either REQA or WUPA).
    //
    // \return ui8Status returns whether or not an ISO14443A
    // compliant tag has responded to the Polling command.
    //
    //===============================================================
    
    u08_t Iso14443a_PollingCommand(u08_t ui8Command)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8Status = STATUS_FAIL;
    
    	if (Trf797xGetIsoControlValue() != 0x88)
    	{
    		// Trf797x has not been properly configured for ISO14443A
    		Trf797xWriteIsoControl(0x88);				// Configure the TRF797x for ISO14443A @ 106kbps and Receive without CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();							// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;				// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x90;				// Send without CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;				// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;				// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x0F;				// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = ui8Command;		// Send the polling command from function input - either REQA (0x26) or WUPA (0x52)
    
        Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);	// Issue the ISO14443A Polling Command
    
    	Trf797xIrqWaitTimeout(3,10);		// 3 millisecond TX timeout, 10 millisecond RX timeout
    
    	g_sTrfStatus = Trf797xGetTrfStatus();
    
    	UartSendCString("Querying Iso14443a_PollingCommand status\n\r");
    	StatusPrint(g_sTrfStatus);
    
    	if (g_sTrfStatus == RX_COMPLETE)	// Tag detected - could be either a single or collided tag
    	{
    		ui8Status = STATUS_SUCCESS;
    	}
    	else if (g_sTrfStatus == PROTOCOL_ERROR)
    	{
    		ui8Status = STATUS_SUCCESS;		// "A PCD detecting a collision in any bit of (b16 to b1) shall commence with the first step of the anticollision loop."
    	}
    
    	return ui8Status;
    }
    
    
    //===============================================================
    //
    // Iso14443a_AnticollisionCommand - Issue Anticollsion command
    // for ISO14443A compliant tags.
    //
    // \param sCascade is the current anticollision cascade
    // \param ui8NVB is the NVB value for the UID bytes and bits
    // \param pui8UID is the location of the UID bytes/bits to send.
    //
    // This function sends the Anticollision command based on the
    // current cascade level.
    //
    // \return sStatus returns a status based on what tag response is
    // received following the Anticollision command.
    //
    //===============================================================
    
    tCollisionStatus Iso14443a_AnticollisionCommand(tISO14443A_UidStatus sCascade, u08_t ui8NVB, u08_t * pui8UID)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8LoopCount = 0;
    	u08_t ui8UidLength = 0;
    	u08_t ui8RxLength = 0;
    	u08_t ui8Select = SEL_CASCADE1;
    	tCollisionStatus sStatus = NO_COLLISION;
    
    	if (sCascade == CASCADE1)
    	{
    		ui8Select = SEL_CASCADE1;
    	}
    	else if (sCascade == CASCADE2)
    	{
    		ui8Select = SEL_CASCADE2;
    	}
    	else if (sCascade == CASCADE3)
    	{
    		ui8Select = SEL_CASCADE3;
    	}
    	else
    	{
    		return sStatus = COLLISION_ERROR;
    	}
    
    	if (Trf797xGetIsoControlValue() != 0x88)
    	{
    		// Trf797x has not been properly configured for ISO14443A with no RX CRC
    		Trf797xWriteIsoControl(0x88);	// Configure the TRF797x for ISO14443A @ 106kbps and Receive without CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();				// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x90;		// Transmit without CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	if((ui8NVB & 0x07) != 0x00)				// Length of packet in bytes - lower nibble and broken bits of transmit byte length
    	{
    		g_ui8TrfBuffer[ui8Offset++] = (ui8NVB & 0xF0) | (((ui8NVB & 0x07) << 1) + 1); 	// Set the number of broken bits, last bit is 1 means broken byte
    	}
    	else
    	{
    		g_ui8TrfBuffer[ui8Offset++] = ui8NVB & 0xF0;	// No broken bits
    	}
    	g_ui8TrfBuffer[ui8Offset++] = ui8Select;			// Select Command; can be 0x93, 0x95 or 0x97
    	g_ui8TrfBuffer[ui8Offset++] = ui8NVB;				// Number of valid bits
    
    	ui8UidLength = (ui8NVB >> 4) - 2;
    	if ((ui8NVB & 0x0F) != 0x00)
    	{
    		ui8UidLength++;
    	}
    
    	for (ui8LoopCount = 0; ui8LoopCount < ui8UidLength; ui8LoopCount++)
    	{
    		g_ui8TrfBuffer[ui8Offset++] = pui8UID[ui8LoopCount];	// UID Bytes
    	}
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);		// Issue the Select Command
    
        Trf797xIrqWaitTimeout(5,15);							// 5 millisecond TX timeout, 15 millisecond RX timeout
    
        g_sTrfStatus = Trf797xGetTrfStatus();
    
        if (g_sTrfStatus == RX_COMPLETE)
        {
        	ui8RxLength = Trf797xGetRxBytesReceived();
    
        	if (ui8RxLength > 1)
        	{
    			sStatus = NO_COLLISION;
        	}
        	else
        	{
        		sStatus = COLLISION_ERROR;
        	}
        }
        else if (g_sTrfStatus == PROTOCOL_ERROR)
        {
        	sStatus = COLLISION;
        }
        else if (g_sTrfStatus == NO_RESPONSE_RECEIVED)
        {
        	sStatus = NO_RESPONSE;
        }
        else
        {
        	// Do nothing
        	sStatus = COLLISION_ERROR;
        }
    
        return sStatus;
    }
    
    
    //===============================================================
    //
    // Iso14443a_SelectCommand - Issue Select command for ISO14443A
    // compliant tags.
    //
    // \param sCascade is the current anticollision cascade.
    // \param pui8UID is the location of the UID bytes to send.
    // \param bSendCT determines if the CT byte must be sent.
    //
    // This function issues the Select command based on the current
    // cascade level.
    //
    // \return ui8Status returns whether or not an ISO14443A
    // compliant tag has responded to the Select command.
    //
    //===============================================================
    
    u08_t Iso14443a_SelectCommand(tISO14443A_UidStatus sCascade, u08_t * pui8UID, bool bSendCT)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8Status = STATUS_FAIL;
    	u08_t ui8Select = SEL_CASCADE1;
    
    	// Sending select command and will receive a SAK response which has a CRC.
    	if (Trf797xGetIsoControlValue() != 0x08)
    	{
    		// Trf797x has not been properly configured for ISO14443A with RX CRC
    		Trf797xWriteIsoControl(0x08);			// Configure the TRF797x for ISO14443A @ 106kbps and Receive with CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	if (sCascade == CASCADE1)
    	{
    		ui8Select = SEL_CASCADE1;
    	}
    	else if (sCascade == CASCADE2)
    	{
    		ui8Select = SEL_CASCADE2;
    	}
    	else if (sCascade == CASCADE3)
    	{
    		ui8Select = SEL_CASCADE3;
    	}
    	else
    	{
    		return ui8Status = STATUS_FAIL;
    	}
    
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;				// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x91;				// Transmit with CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;				// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;				// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x70;				// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = ui8Select;		// Select Command; can be 0x93, 0x95 or 0x97
    	g_ui8TrfBuffer[ui8Offset++] = NVB_FULL;			// Number of valid bits
    	if (bSendCT == true)
    	{
    		g_ui8TrfBuffer[ui8Offset++] = 0x88;			// CT
    		g_ui8TrfBuffer[ui8Offset++] = *pui8UID;		// UID Bytes
    		g_ui8TrfBuffer[ui8Offset++] = *(pui8UID + 1);
    		g_ui8TrfBuffer[ui8Offset++] = *(pui8UID + 2);
    		g_ui8TrfBuffer[ui8Offset++] = ( 0x88 ^ *pui8UID ^ *(pui8UID + 1) ^ *(pui8UID + 2) );	// Calculate BCC Byte
    	}
    	else
    	{
    		g_ui8TrfBuffer[ui8Offset++] = *pui8UID;		// UID Bytes
    		g_ui8TrfBuffer[ui8Offset++] = *(pui8UID + 1);
    		g_ui8TrfBuffer[ui8Offset++] = *(pui8UID + 2);
    		g_ui8TrfBuffer[ui8Offset++] = *(pui8UID + 3);
    		g_ui8TrfBuffer[ui8Offset++] = ( *pui8UID ^ *(pui8UID + 1) ^ *(pui8UID + 2) ^ *(pui8UID + 3) );	// Calculate BCC Byte
    	}
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);	// Issue the Select Command
    
    	Trf797xIrqWaitTimeout(5,15);					// 5 millisecond TX timeout, 15 millisecond RX timeout
    
        g_sTrfStatus = Trf797xGetTrfStatus();
        UartSendCString("Iso14443a_SelectCommand trfStatus: ");
        StatusPrint(g_sTrfStatus);
    
        if (g_sTrfStatus == RX_COMPLETE)
        {
        	ui8Status = STATUS_SUCCESS;
    
       		g_ui8Iso14443aSAK = g_ui8TrfBuffer[0];
        }
        else
        {
        	// Do nothing
        }
    
        return ui8Status;
    }
    
    
    //===============================================================
    //
    // Iso14443a_Halt - Issue the Halt command to the currently
    // selected ISO14443A compliant tag.
    //
    // This function sends the Polling command based on the inputted
    // command (either REQA or WUPA).
    //
    // \return ui8Status returns STATUS_FAIL if the tag erroneously
    // responded to the Halt command.
    //
    //===============================================================
    
    u08_t Iso14443a_Halt(void)
    {
    	u08_t ui8Offset = 0;
    
    	if (Trf797xGetIsoControlValue() != 0x88)
    	{
    		// Trf797x has not been properly configured for ISO14443A
    		Trf797xWriteIsoControl(0x88);			// Configure the TRF797x for ISO14443A @ 106kbps and Receive without CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x90;		// Send without CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x20;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x50;		// Halt Command
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);		// Issue the Halt Command
    
    	Trf797xIrqWaitTimeout(3,10);	// 3 millisecond TX timeout, 10 millisecond RX timeout
    
    	g_sTrfStatus = Trf797xGetTrfStatus();
    
    	if (g_sTrfStatus != NO_RESPONSE_RECEIVED)	// If PICC gives a response to the command, this means the Halt command failed or had an error
    	{
    		g_sTrfStatus = PROTOCOL_ERROR;
    		Trf797xSetTrfStatus(g_sTrfStatus);
    #ifdef ENABLE_HOST
    		UartSendCString("Halt command error \n \r");
    #endif
    		return STATUS_FAIL;
    	}
    	else
    	{
    		return STATUS_SUCCESS;
    	}
    }
    
    
    //===================================================================
    //
    // Iso14443a_Rats - Issue the RATS command to the currently selected
    // ISO14443A compliant tag.
    //
    // This function sends the RATS command to activate an ISO14443A
    // compliant tag for data exchange.
    //
    // \return ui8Status returns whether or not the selected ISO14443A
    // compliant tag responded to the RATS command.
    //
    //===================================================================
    
    u08_t Iso14443a_Rats(void)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8RxLength = 0;
    	u08_t ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    	u08_t ui8LoopCount = 0;
    #endif
    
    	if (Trf797xGetIsoControlValue() != 0x08)
    	{
    		// Trf797x has not been properly configured for ISO14443A
    		Trf797xWriteIsoControl(0x08);			// Configure the TRF797x for ISO14443A @ 106kbps and Receive with CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	// Buffer setup for FIFO writing
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x91;		// Send with CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x20;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = RATS_CMD;		//RATS Command
    	g_ui8TrfBuffer[ui8Offset++] = RATS_PARAM;	//RATS Parameters: 128 byte max receive and CID = 0
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);		// Issue the RATS command
    
    	Trf797xIrqWaitTimeout(3,10);	// 3 millisecond TX timeout, 10 millisecond RX timeout
    
    	g_sTrfStatus = Trf797xGetTrfStatus();
    
    	// If data received
    	if(g_sTrfStatus == RX_COMPLETE)
    	{
    		ui8RxLength = Trf797xGetRxBytesReceived();
    
    		if (g_ui8TrfBuffer[0] == ui8RxLength)
    		{
    			ui8Status = STATUS_SUCCESS;
    
    			ui8Offset = 0;
    
    			// Print out TL
    #ifdef ENABLE_HOST
    			UartSendCString("ISO14443A ATS Response - TL: ");
    			UartPutByte(g_ui8TrfBuffer[ui8Offset++]);
    			UartPutCrlf();
    
    			// If TL is greater than 1, at minimum Format Byte T0 will be present
    			if (g_ui8TrfBuffer[0] > 1)
    			{
    				// Print out the value of T0
    				UartSendCString("ISO14443A ATS Response - T0: ");
    				UartPutByte(g_ui8TrfBuffer[ui8Offset++]);
    				UartPutCrlf();
    				if (g_ui8TrfBuffer[1] & 0x10)
    				{
    					g_ui8AtsSupportedBitrates = g_ui8TrfBuffer[ui8Offset++];
    
    					// TA(1) has been received, print it out
    					UartSendCString("ISO14443A ATS Response - TA(1): ");
    					UartPutByte(g_ui8AtsSupportedBitrates);
    					UartPutCrlf();
    				}
    				if (g_ui8TrfBuffer[1] & 0x20)
    				{
    					// TB(1) has been received, print it out
    					UartSendCString("ISO14443A ATS Response - TB(1): ");
    					UartPutByte(g_ui8TrfBuffer[ui8Offset++]);
    					UartPutCrlf();
    				}
    				if (g_ui8TrfBuffer[1] & 0x40)
    				{
    					// TC(1) has been received, print it out
    					UartSendCString("ISO14443A ATS Response - TC(1): ");
    					UartPutByte(g_ui8TrfBuffer[ui8Offset++]);
    					UartPutCrlf();
    				}
    				if (ui8RxLength > ui8Offset)
    				{
    					// Historical Bytes have been received, print out all of them
    					UartSendCString("ISO14443A ATS Response - Historical Bytes: ");
    					for (ui8LoopCount = ui8Offset; ui8LoopCount < ui8RxLength; ui8LoopCount++)
    					{
    						UartPutByte(g_ui8TrfBuffer[ui8LoopCount]);
    					}
    					UartPutCrlf();
    				}
    			}
    			UartPutCrlf();
    #endif
    		}
    		else
    		{
    			ui8Status = STATUS_FAIL;
    		}
    	}
    	else
    	{
    		ui8Status = STATUS_FAIL;
    	}
    	return ui8Status;
    }
    
    
    
    //===================================================================
    //
    // Iso14443a_Pps - Issue the PPS command to the currently selected
    // ISO14443A compliant tag.
    //
    // This function sends the PPS command to modify the over the air
    // data rate of the selected ISO14443A compliant tag.
    //
    // \return ui8Status returns whether or not the selected ISO14443A
    // compliant tag responded to the PPS command.
    //
    //===================================================================
    
    u08_t Iso14443a_Pps(void)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8Status = STATUS_FAIL;
    	u08_t ui8PPSBitrate;
    
    	// Check if PPS is supported based on last received ATS reply
    	if ((g_ui8AtsSupportedBitrates == 0x00) || (g_ui8AtsSupportedBitrates == 0x80))
    	{
    #ifdef ENABLE_HOST
    		UartSendCString("Tag does not support data rates above 106kbps. No PPS issued.");
    		UartPutCrlf();
    		UartPutCrlf();
    #endif
    
    		return ui8Status = STATUS_SUCCESS;
    	}
    
    	if (Trf797xGetIsoControlValue() != 0x08)
    	{
    		// Trf797x has not been properly configured for ISO14443A
    		Trf797xWriteIsoControl(0x08);			// Configure the TRF797x for ISO14443A @ 106kbps and Receive with CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	ui8PPSBitrate = PPS1_106; 				// Set the PPS bit rate to 106kbps for best range performance
    											// It is recommended to keep the data rate low to get better transmission ranges
    
    	// Buffer setup for FIFO writing
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x91;		// Send with CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x30;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = PPSS;		// PPS Command
    	g_ui8TrfBuffer[ui8Offset++] = PPS0;
    	g_ui8TrfBuffer[ui8Offset++] = ui8PPSBitrate;	// Send PPS Bit Rate
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);		// Issue the PPS Command
    
    	Trf797xIrqWaitTimeout(3,10);		// 3 millisecond TX timeout, 10 millisecond RX timeout
    
    	g_sTrfStatus = Trf797xGetTrfStatus();
    
    	// If data received
    	if(g_sTrfStatus == RX_COMPLETE)
    	{
    		// Check PPS response
    		if (g_ui8TrfBuffer[0] == PPSS)
    		{
    			ui8Status = STATUS_SUCCESS;
    
    			// Execute Bitrate Change
    			McuDelayMillisecond(1);
    
    			if (ui8PPSBitrate == PPS1_106)
    			{
    				Trf797xWriteIsoControl(0x08);	// Configure the TRF797x for ISO14443A @ 106kbps and Receive with CRC
    
    #ifdef ENABLE_HOST
    				UartSendCString("PPS Successful: ISO14443A Bit Rate Set to 106kpbs");
    				UartPutCrlf();
    				UartPutCrlf();
    #endif
    			}
    			else if (ui8PPSBitrate == PPS1_212)
    			{
    				Trf797xWriteIsoControl(0x09);	// Configure the TRF797x for ISO14443A @ 212kbps and Receive with CRC
    
    #ifdef ENABLE_HOST
    				UartSendCString("PPS Successful: ISO14443A Bit Rate Set to 212kpbs");
    				UartPutCrlf();
    				UartPutCrlf();
    #endif
    			}
    			else if (ui8PPSBitrate == PPS1_424)
    			{
    				Trf797xWriteIsoControl(0x0A);	// Configure the TRF797x for ISO14443A @ 424kbps and Receive with CRC
    
    #ifdef ENABLE_HOST
    				UartSendCString("PPS Successful: ISO14443A Bit Rate Set to 424kpbs");
    				UartPutCrlf();
    				UartPutCrlf();
    #endif
    			}
    			else if (ui8PPSBitrate == PPS1_848)
    			{
    				Trf797xWriteIsoControl(0x0B);	// Configure the TRF797x for ISO14443A @ 848kbps and Receive with CRC
    
    #ifdef ENABLE_HOST
    				UartSendCString("PPS Successful: ISO14443A Bit Rate Set to 848kpbs");
    				UartPutCrlf();
    				UartPutCrlf();
    #endif
    			}
    			else
    			{
    				// Do Nothing
    			}
    			McuDelayMillisecond(6);
    		}
    		else
    		{
    			ui8Status = STATUS_FAIL;
    
    #ifdef ENABLE_HOST
    			UartSendCString("Error: PPS Reply Does Not Match Transmitted Frame");
    			UartPutCrlf();
    #endif
    		}
    	}
    	else
    	{
    		ui8Status = STATUS_FAIL;
    
    #ifdef ENABLE_HOST
    		UartSendCString("Error: PPS Reply Not Received");
    		UartPutCrlf();
    #endif
    	}
    
    	return ui8Status;
    }
    
    
    
    //===============================================================
    //
    // Iso14443a_StoreUid - Store the received UID bytes into the
    // global g_pui8CompleteUid buffer.
    //
    // \param sCascade is the current anticollision cascade.
    // \param pui8UID is the location of the UID bytes to store.
    //
    // This function stores the received UID bytes into the global
    // UID buffer. It will also parse out the CT byte and set a flag
    // to indicate if the CT byte was present.
    //
    // \return bSendCT returns whether or not the next transmission
    // will require the CT byte to be sent in addition to the UID
    // bytes.
    //
    //===============================================================
    
    bool Iso14443a_StoreUid(tISO14443A_UidStatus sCascade, u08_t * pui8UID)
    {
    	bool bSendCT = false;
    	u08_t ui8Offset = 0;
    
    	if ((g_sUidSize == ISO14443A_UID_SINGLE) && (sCascade == CASCADE1))
    	{
    		// UID has no CT, so store all bytes normally.
    		ui8Offset = 0;
    		bSendCT = false;
    	}
    	else if ((g_sUidSize == ISO14443A_UID_DOUBLE) && (sCascade == CASCADE2))
    	{
    		// UID has no CT, so store all bytes normally.
    		ui8Offset = 0;
    		bSendCT = false;
    	}
    	else if ((g_sUidSize == ISO14443A_UID_TRIPLE) && (sCascade == CASCADE3))
    	{
    		// UID has no CT, so store all bytes normally.
    		ui8Offset = 0;
    		bSendCT = false;
    	}
    	else
    	{
    		if (pui8UID[0] == 0x88)
    		{
    			// UID has a CT, set bool to return that a CT must be sent
    			ui8Offset = 1;		// Set offset to account for the location of the CT byte
    			bSendCT = true;		// Set variable to tell Select Command to include a CT in addition to UID bytes
    		}
    		else
    		{
    			// UID has no CT, so store all bytes normally.
    			ui8Offset = 0;
    			bSendCT = false;
    		}
    	}
    
    	// Store UID based on the current Cascade level
    	if (sCascade == CASCADE1)
    	{
    		g_pui8CompleteUid[0] = pui8UID[0+ui8Offset];
    		g_pui8CompleteUid[1] = pui8UID[1+ui8Offset];
    		g_pui8CompleteUid[2] = pui8UID[2+ui8Offset];
    		g_pui8CompleteUid[3] = pui8UID[3+ui8Offset];	// BCC Byte or last byte of UID
    		g_ui8UidPos = 0;	// Update the UID Position indicator to the first byte of the newly stored UID for when the Select command is issued
    	}
    	else if (sCascade == CASCADE2)
    	{
    		g_pui8CompleteUid[3] = pui8UID[0+ui8Offset];	// Override the BCC from prior Cascade as it is no longer needed
    		g_pui8CompleteUid[4] = pui8UID[1+ui8Offset];
    		g_pui8CompleteUid[5] = pui8UID[2+ui8Offset];
    		g_pui8CompleteUid[6] = pui8UID[3+ui8Offset];	// BCC Byte or last byte of UID
    		g_ui8UidPos = 3;	// Update the UID Position indicator to the first byte of the newly stored UID for when the Select command is issued
    	}
    	else if (sCascade == CASCADE3)
    	{
    		g_pui8CompleteUid[6] = pui8UID[0];	// Override the BCC from prior Cascade as it is no longer needed
    		g_pui8CompleteUid[7] = pui8UID[1];
    		g_pui8CompleteUid[8] = pui8UID[2];
    		g_pui8CompleteUid[9] = pui8UID[3];
    		bSendCT = false; 	// Ensure no accidental sending of the CT occurs incase uid6 for a Triple Size UID = 0x88 (which is permitted per ISO14443-3 specifications)
    		g_ui8UidPos = 6;	// Update the UID Position indicator to the first byte of the newly stored UID for when the Select command is issued
    	}
    
    	return bSendCT;
    }
    
    //===============================================================
    //
    // Iso14443a_Type2_Read4Blocks - Reads out four blocks of data
    // from NFC Type 2 Tag Platforms.
    //
    // \param ui8StartBlock is the block number to start reading the
    // tag data from.
    //
    // This function will issue a Read Block command with the
    // provided starting block number. The Read Block command
    // automatically will read out four blocks of data from the Type
    // 2 Tag.
    //
    // \return ui8Status returns whether or not the tag data was
    // successfully read.
    //
    //===============================================================
    
    u08_t Iso14443a_Type2_Read4Blocks(u08_t ui8StartBlock)
    {
    	u08_t ui8Offset = 0;
    	u08_t ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    	u08_t	ui8LoopCount1 = 1;
    	u08_t	ui8LoopCount2 = 0;
    #endif
    
    	if (Trf797xGetIsoControlValue() != 0x08)
    	{
    		// Trf797x has not been properly configured for ISO14443A
    		Trf797xWriteIsoControl(0x08);			// Configure the TRF797x for ISO14443A @ 106kbps and Receive with CRC
    	}
    	if (Trf797xCheckRfField() == false)
    	{
    		// RF field is not enabled, VICC will not receive the command
    		Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    		// When a PICC is exposed to an unmodulated operating field
    		// it shall be able to accept a quest within 5 ms.
    		// PCDs should periodically present an unmodulated field of at least
    		// 5.1 ms duration. (ISO14443-3)
    		McuDelayMillisecond(6);
    	}
    
    	g_ui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_ui8TrfBuffer[ui8Offset++] = 0x91;		// Send with CRC
    	g_ui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_ui8TrfBuffer[ui8Offset++] = 0x00;		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x20;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_ui8TrfBuffer[ui8Offset++] = 0x30;				// Read Command
    	g_ui8TrfBuffer[ui8Offset++] = ui8StartBlock;	// Starting from Block # (called Bno)
    
    	Trf797xRawWrite(&g_ui8TrfBuffer[0], ui8Offset);		// Issue the Type 2 Read Command
    
    	Trf797xIrqWaitTimeout(5,30);		// 5 millisecond TX timeout, 30 millisecond RX timeout
    
    	g_sTrfStatus = Trf797xGetTrfStatus();
    
    	if(g_sTrfStatus == RX_COMPLETE)		// If block data has been received
    	{
    		ui8Status = STATUS_SUCCESS;		// Mark tag has been successfully read
    
    #ifdef ENABLE_HOST
    		for(ui8LoopCount2 = 0; ui8LoopCount2 < 4; ui8LoopCount2++)
    		{
    			UartSendCString("NFC Type 2 Block ");
    			UartPutByte(ui8StartBlock++);
    			UartSendCString(":  [");
    			for(ui8LoopCount1 = (ui8LoopCount2*4); ui8LoopCount1 < 4+(ui8LoopCount2*4); ui8LoopCount1++)
    			{
    				UartPutByte(g_ui8TrfBuffer[ui8LoopCount1]);		// Print out the received data
    			}
    			UartPutChar(']');
    			UartPutCrlf();
    		}
    #endif
    	}
    	else
    	{
    		// Otherwise return a fail
    		ui8Status = STATUS_FAIL;
    	}
    
    	return ui8Status;
    }
    
    //===============================================================
    //
    // Iso14443a_Get_Type4ACompliance - Fetches g_bType4ACompliant value
    //
    // This function allows for higher layers to fetch the current
    // Type 4A NDEF compliance information.
    //
    // \return g_bType4ACompliant returns the current compliance for
    // Type 4A NDEF.
    //
    //===============================================================
    
    bool Iso14443a_Get_Type4ACompliance(void)
    {
    	return g_bType4ACompliant;
    }
    
    //===============================================================
    //
    // Iso14443a_Set_RecursionCount - Sets the g_ui8RecursionCount
    // variable
    //
    // \param
    //
    // This function allows for higher layers to adjust the global
    // recursion count. Useful for resetting it prior to running
    // anticollision routines.
    //
    // \return None.
    //
    //===============================================================
    
    void Iso14443a_Set_RecursionCount(u08_t ui8RecursionCount)
    {
    	g_ui8RecursionCount = ui8RecursionCount;
    }
    
    //===============================================================
    //
    // Iso14443a_Get_Uid - Fetches the ISO14443A Tag UID.
    //
    // This function allows for higher layers to fetch the tag UID of
    // an ISO14443A tag. In the current implementation, the UID
    // stored is from the most recent tag which finished the
    // anticollision procedure.
    //
    // \return g_pui8CompleteUid returns the currently stored UID.
    //
    //===============================================================
    
    u08_t * Iso14443a_Get_Uid(void)
    {
    	return g_pui8CompleteUid;
    }
    
    //===============================================================
    //
    // Iso14443a_Get_UidSize - Fetches the UID size of the most
    // recently read ISO14443A tag.
    //
    // This function allows for higher layers to fetch the size of
    // the current UID for an ISO14443A tag.
    //
    // \return g_sUidSize returns the current UID size.
    //
    //===============================================================
    
    tISO14443A_UidSize Iso14443a_Get_UidSize(void)
    {
    	return g_sUidSize;
    }
    
    //===============================================================
    //
    // Nfc_Iso14443a_Type4NdefApp - Customizeable application to read
    // NDEF data from a Type 4A NDEF Formatted tag.
    //
    // Tags which are Type 4 compliant are activated via RATS.
    // If the tag contains an NDEF message, then the NDEF data is
    // read from it.
    //
    // \return None.
    //
    //===============================================================
    
    void Nfc_Iso14443a_Type4NdefApp(void)
    {
    	if (Iso14443a_Rats() == STATUS_SUCCESS)
    	{
    		if (Iso14443a_Pps() == STATUS_SUCCESS)
    		{
    			Ndef_SetBlockNumberBit(0);
    
    			if (NDEF_ApplicationSelect() == STATUS_SUCCESS) // Selects NDEF Application
    			{
    				Ndef_ReadCC();
    				Ndef_ReadApplication();
    
    //				Ndef_WriteUri();
    //
    //				Ndef_ReadCC();
    //				Ndef_ReadApplication();
    
    #ifdef ENABLE_STANDALONE
    				LED_14443A_OFF;
    #endif
    			}
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// Tag was not activated properly
    		LED_14443A_OFF;
    #endif
    	}
    }
    
    //===============================================================
    //
    // Nfc_Iso14443a_Type2App - Customizeable application to search
    // for ISO14443A compliant tags.
    //
    // \param ui8ReadBlocks is the number of blocks to read from the
    // tag.
    //
    // Function handles readint the tag data from Type 2 Tags. The
    // function will read 4 blocks at a time.
    //
    // Requesting for 10 blocks to be read would result in 12 being
    // read.
    //
    // \return None.
    //
    //===============================================================
    
    void Nfc_Iso14443a_Type2App(uint8_t ui8ReadBlocks)
    {
    	uint8_t ui8BlockNumber = 0;
    
    	// If tag is not ISO14443-4 Compliant, then attempt to read data blocks for Type 2 Tag
    	for (ui8BlockNumber = 0x00; ui8BlockNumber < ui8ReadBlocks; ui8BlockNumber = ui8BlockNumber+4)
    	{
    		if (Iso14443a_Type2_Read4Blocks(ui8BlockNumber) == STATUS_FAIL)
    		{
    #ifdef ENABLE_HOST
    			UartSendCString("Error Reading Blocks: ");
    			UartPutByte(ui8BlockNumber);
    			UartSendCString(" thru ");
    			UartPutByte(ui8BlockNumber+3);
    			UartPutCrlf();
    #endif
    			break;
    		}
    	}
    }
    
    void ISO14443aFindTag(void)
    {
    	Trf797xTurnRfOn();						// Ensure TRF797x is outputting an RF Field
    
    	Trf797xWriteInitiatorSetup(0x88);		// Configure the TRF797x for ISO14443A @ 106kbps and Receive no CRC
    
    	IRQ_CLR;									// PORT2 interrupt flag clear
    	IRQ_ON;
    
    	// When a PICC is exposed to an unmodulated operating field
    	// it shall be able to accept a quest within 5 ms.
    	// PCDs should periodically present an unmodulated field of at least
    	// 5.1 ms duration. (ISO14443-3)
    	McuDelayMillisecond(6);
    
    
    	Iso14443a_Set_RecursionCount(0); 		// Clear the recursion count for anticollision loops
    
    	if (Iso14443a_TagSelection(REQA) == STATUS_SUCCESS)	//  Do a complete anticollision sequence as described in ISO14443-3 standard for type A
    	{
    		if (Iso14443a_Get_Type4ACompliance() == true)
    		{
    			UartSendCString("Type 4A Tag\n\r");
    			Nfc_Iso14443a_Type4NdefApp();	// For a Type 4A compliant tag, the tag is put into Layer 4, and in order to attempt to read/write NDEF contents
    		}
    		else
    		{
    			UartSendCString("Type 2 Tag\n\r");
    			Nfc_Iso14443a_Type2App(0x10);	// If a tag that is not Type 4A compliant then assume it is NFC Type 2. Proceed to read data block(s)
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// No card detected
    		LED_14443A_OFF;
    #endif
    	}
    
    	Trf797xTurnRfOff();
    }
    


    trf797x.c

    /*
     * File Name: trf797x.c
     *
     * Description: TRF797x Driver Functions
     *
     * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
     *
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    
    #include <string.h>
    #include <stdio.h>
    #include "hw_types.h"
    #include "hw_memmap.h"
    #include "trf797x.h"
    #include "trf7970BoosterPack.h"
    #include "timer_if.h"
    #include "gpio.h"
    #include "osi.h"
    
    //===============================================================
    
    u08_t g_ui8TrfBuffer[NFC_FIFO_SIZE];
    
    static u08_t	g_ui8CollisionPosition = 0;
    
    static u08_t	g_ui8FifoOffset = 0;
    static u08_t	g_ui8FifoRxLength = 0;
    
    static bool 	g_bRfFieldOn = false;
    static u08_t 	g_ui8IsoControlValue = 0x00;
    
    static tTRF797x_Status g_sTrf797xStatus = TRF_IDLE;
    
    static volatile u08_t g_ui8IrqFlag = 0x00;
    static volatile u08_t g_ui8TimeoutFlag = 0x00;
    
    u08_t    command[2];
    
    //===============================================================
    //
    // Trf797xCommunicationSetup - Initialize Communication to TRF797x
    //
    // Call the appropriate serial communication initialize based on
    // hardware setup
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xCommunicationSetup(void)
    {
    	A2CounterInit(A2CNTIntHandler);
    	STOP_COUNTER;
    	RESET_COUNTER;
    	command[0] = SOFT_INIT;
    	Trf797xDirectCommand(command);
    
    	command[0] = IDLE;
    	Trf797xDirectCommand(command);
    
    	command[0] = TRF797x_MODULATOR_CONTROL;
    	command[1] = 0x01;                    // ASK 100%, no SYS_CLK output
    	Trf797xWriteSingle(command, 2);
    
    	command[0] = TRF797x_NFC_TARGET_LEVEL;
    	command[1] = 0x00;
    	Trf797xWriteSingle(command, 2);
    }
    
    //===============================================================
    //
    // Trf797xDirectCommand - Send a Direct Command to TRF797x.
    //
    // \param ui8Value is the direct command to be issued
    //
    //  Function is used to transmit a Direct Command to TRF797x.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xDirectCommand(u08_t *ui8Value)
    {
    	SpiDirectCommand(ui8Value);
    }
    
    //===============================================================
    //
    // Trf797xDisableSlotCounter - Disables interrupts from 15693
    // slot counter function.
    //
    // Turns off the firing of the IRQ interrupt when a 15693 slot
    // hits the No Response timeout
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xDisableSlotCounter(void)
    {
    	u08_t pui8ModControl[2];
    
    	pui8ModControl[0] = TRF797x_IRQ_MASK;              // next slot counter
    	pui8ModControl[1] = TRF797x_IRQ_MASK;
    	Trf797xReadSingle(&pui8ModControl[1], 1);
    	pui8ModControl[1] &= 0xFE;                // clear BIT0 in register 0x01
    	Trf797xWriteSingle(pui8ModControl, 2);
    }
    
    //===============================================================
    //
    // Trf797xEnableSlotCounter - Enables interrupts from 15693
    // slot counter function.
    //
    // Turns on the firing of the IRQ interrupt when a 15693 slot
    // hits the No Response timeout
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xEnableSlotCounter(void)
    {
    	u08_t pui8ModControl[2];
    
    	pui8ModControl[0] = TRF797x_IRQ_MASK;              // next slot counter
    	pui8ModControl[1] = TRF797x_IRQ_MASK;
    	Trf797xReadSingle(&pui8ModControl[1],1);
    	pui8ModControl[1] |= BIT0;                // set BIT0 in register 0x01
    	Trf797xWriteSingle(pui8ModControl,2);
    }
    
    //===============================================================
    //
    // Trf797xEnableSlotCounter - Initialize TRF797x
    //
    // Handles setting up the clock register and writes register 0x18
    // as per TRF7970A Errata
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xInitialSettings(void)
    {
    	command[0] = SOFT_INIT;
    	Trf797xDirectCommand(command);
    	command[0] = IDLE;
    	Trf797xDirectCommand(command);
    
    	command[0] = TRF797x_MODULATOR_CONTROL;
    	command[1] = 0x01;                    // ASK 100%, no SYS_CLK output
    	Trf797xWriteSingle(command,2);
    
    	command[0] = TRF797x_NFC_TARGET_LEVEL;
    	command[1] = 0x00;
        Trf797xWriteSingle(command,2);
    }
    
    //===============================================================
    //
    // Trf797xISR - Services TRF797x IRQ interrupts
    //
    // \param pui8_IrqStatus is the received IRQ Status flags
    //
    // The Interrupt Service Routine determines how the IRQ should
    // be handled. The Trf797x IRQ status register is read to
    // determine the cause of the IRQ. Conditions are checked and
    // appropriate actions taken.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xISR(u08_t * pui8_IrqStatus)
    {
    	u08_t	ui8DummyRead;
    	u08_t	ui8Length;
    
    	if(*pui8_IrqStatus == (TRF797x_IRQ_STATUS_TX_COMPLETE | TRF797x_IRQ_STATUS_FIFO_HIGH_OR_LOW))			// BIT5 and BIT7
    	{								// TX active and 32 bytes left in FIFO
    		g_sTrf797xStatus = TX_COMPLETE;
    	}
    
    	else if(*pui8_IrqStatus == TRF797x_IRQ_STATUS_TX_COMPLETE)
    	{								// TX complete
    		g_sTrf797xStatus = TX_COMPLETE;
    		Trf797xReset();				// reset the FIFO after TX
    	}
    
    	else if((*pui8_IrqStatus & BIT1) == TRF797x_IRQ_STATUS_COLLISION_ERROR)
    	{								// Collision error
    		g_sTrf797xStatus = PROTOCOL_ERROR;
    
    		if ((g_ui8IsoControlValue == 0x08) || (g_ui8IsoControlValue == 0x88))
    		{
    			g_ui8CollisionPosition = TRF797x_COLLISION_POSITION;
    			Trf797xReadSingle(&g_ui8CollisionPosition, 1);
    
    			if (g_ui8CollisionPosition > 0x20)
    			{
    				ui8Length = g_ui8CollisionPosition - 0x20;		// number of valid bytes in FIFO
    
    				if((ui8Length & 0x0F) != 0x00)
    				{
    					ui8Length = ui8Length + 0x10;	// add 1 byte if broken byte recieved
    				}
    				ui8Length = ui8Length >> 4;
    
    				if(ui8Length != 0x00)
    				{
    					g_ui8TrfBuffer[g_ui8FifoOffset] = FIFO;		// write the recieved bytes to the correct place of the buffer
    
    					Trf797xReadCont(&g_ui8TrfBuffer[g_ui8FifoOffset], ui8Length);
    					g_ui8FifoOffset = g_ui8FifoOffset + ui8Length;
    				}
    			}
    			else
    			{
    				g_ui8FifoRxLength = TRF797x_FIFO_STATUS;
    				Trf797xReadSingle(&g_ui8FifoRxLength,1);	// determine the number of bytes left in FIFO
    
    				g_ui8FifoRxLength = 0x7F & g_ui8FifoRxLength;
    				g_ui8TrfBuffer[g_ui8FifoOffset] = FIFO;				// write the recieved bytes to the correct place of the buffer
    
    				Trf797xReadCont(&g_ui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);
    				g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;
    			}
    		}
    
    		Trf797xStopDecoders();
    
    		Trf797xReset();		// reset the FIFO after TX
    
    		Trf797xResetIrqStatus();
    
    		IRQ_CLR;
    	}
    	else if(*pui8_IrqStatus == TRF797x_IRQ_STATUS_RX_COMPLETE)
    	{	// RX flag means that EOF has been recieved
    		// and the number of unread bytes is in FIFOstatus regiter
    
    		g_ui8FifoRxLength = TRF797x_FIFO_STATUS;
    		Trf797xReadSingle(&g_ui8FifoRxLength, 1);	// determine the number of bytes left in FIFO
    
    		g_ui8FifoRxLength = 0x7F & g_ui8FifoRxLength;
    		g_ui8TrfBuffer[g_ui8FifoOffset] = FIFO;				// write the recieved bytes to the correct place of the buffer
    
    		Trf797xReadCont(&g_ui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);
    		g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;
    
    		Trf797xReset();			// reset the FIFO after last byte has been read out
    
    		if (g_sTrf797xStatus == RX_WAIT_EXTENSION)
    		{
    			g_ui8FifoRxLength = g_ui8FifoOffset;
    		}
    
    		g_sTrf797xStatus = RX_COMPLETE;
    	}
    	else if(*pui8_IrqStatus == (TRF797x_IRQ_STATUS_RX_COMPLETE | TRF797x_IRQ_STATUS_FIFO_HIGH_OR_LOW))
    	{									// RX active and 96 bytes allready in FIFO
    		g_sTrf797xStatus = RX_WAIT;
    
    		// Read FIFO Status to determine how many bytes are in the FIFO
    		g_ui8FifoRxLength = TRF797x_FIFO_STATUS;
    		Trf797xReadSingle(&g_ui8FifoRxLength, 1);
    		g_ui8FifoRxLength = 0x7F & g_ui8FifoRxLength;
    
    		if (NFC_FIFO_SIZE > (g_ui8FifoOffset+g_ui8FifoRxLength))
    		{
    			// Read from the FIFO to empty it
    			g_ui8TrfBuffer[g_ui8FifoOffset] = FIFO;
    			Trf797xReadCont(&g_ui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);	// read all received bytes from FIFO
    			g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;					// Adjust buffer index
    		}
    		else
    		{
    			g_sTrf797xStatus = PROTOCOL_ERROR;
    			return;
    		}
    
    		// Read FIFO Status again to determine if more bytes have been received
    		g_ui8FifoRxLength = TRF797x_FIFO_STATUS;
    		Trf797xReadSingle(&g_ui8FifoRxLength, 1);	// determine the number of bytes left in FIFO
    		g_ui8FifoRxLength = 0x7F & g_ui8FifoRxLength;
    
    		if (g_ui8FifoRxLength > 0)
    		{
    			g_sTrf797xStatus = RX_WAIT_EXTENSION;
    		}
    		else
    		{
    			g_ui8FifoRxLength = g_ui8FifoOffset;
    			g_sTrf797xStatus = RX_COMPLETE;
    			return;
    		}
    	}
    	else if (*pui8_IrqStatus == (TRF797x_IRQ_STATUS_RX_COMPLETE | TRF797x_IRQ_STATUS_NO_RESPONSE))
    	{
    		// RX has begun but as not completed, space exists in FIFO still, just wait longer to receive full reply.
    		g_sTrf797xStatus = RX_WAIT_EXTENSION;
    	}
    	else if((*pui8_IrqStatus & BIT4) == TRF797x_IRQ_STATUS_CRC_ERROR)		// CRC error
    	{
    		if((*pui8_IrqStatus & BIT5) == TRF797x_IRQ_STATUS_FIFO_HIGH_OR_LOW)
    		{
    			g_sTrf797xStatus = RX_WAIT;
    		}
    		if((*pui8_IrqStatus & BIT6) == TRF797x_IRQ_STATUS_RX_COMPLETE)		// 4 Bit receive
    		{
    			ui8DummyRead = FIFO;		// write the recieved bytes to the correct place of the buffer
    
    			Trf797xReadCont(&ui8DummyRead, 1);
    
    			Trf797xReset();
    
    			g_sTrf797xStatus = PROTOCOL_ERROR;
    		}
    		else
    		{
    			g_sTrf797xStatus = PROTOCOL_ERROR;
    		}
    	}
    	else if((*pui8_IrqStatus & BIT2) == TRF797x_IRQ_STATUS_FRAMING_ERROR)	// byte framing error
    	{
    		if((*pui8_IrqStatus & BIT5) == TRF797x_IRQ_STATUS_FIFO_HIGH_OR_LOW)
    		{
    			g_sTrf797xStatus = RX_WAIT;
    		}
    		else
    		{
    			g_sTrf797xStatus = PROTOCOL_ERROR;
    		}
    	}
    	else if(*pui8_IrqStatus == TRF797x_IRQ_STATUS_IDLE)
    	{						// No response interrupt
    		g_sTrf797xStatus = NO_RESPONSE_RECEIVED;
    	}
    	else if(*pui8_IrqStatus == TRF797x_IRQ_STATUS_NO_RESPONSE)
    	{						// No response interrupt
    		g_sTrf797xStatus = NO_RESPONSE_RECEIVED_15693;
    		g_ui8FifoOffset = 0;
    	}
    	else
    	{						// Interrupt register not properly set
    		g_sTrf797xStatus = PROTOCOL_ERROR;
    
    		Trf797xStopDecoders();	// reset the FIFO after TX
    		Trf797xReset();
    		Trf797xResetIrqStatus();
    
    		IRQ_CLR;
    	}
    }							// Interrupt Service Routine
    
    //===============================================================
    //
    // Trf797xIRQ - Interrupt handler for IRQ interrupts
    //
    // Handles receiving IRQ's, getting IRQ status, and maintaining
    // timers/global variables
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xIRQ(void)							// interrupt handler
    {
    	u08_t ui8IrqStatus, ui8IsoControl;
    
    	STOP_COUNTER;
    	RESET_COUNTER;							// stop timer mode
    
    
    	g_ui8IrqFlag = 0x01;
    
    	do
    	{
    		IRQ_CLR;							// PORT2 interrupt flag clear
    
    		// IRQ status register has to be read
    		Trf797xReadIrqStatus(&ui8IrqStatus);
    
    		UartSendCString("IRQ Status: ");
    		UartPutByteHex(ui8IrqStatus);
    		UartPutCrlf();
    
    		if(ui8IrqStatus == 0xA0)				// TX active and only 3 bytes left in FIFO
    		{
    			g_sTrf797xStatus = TX_WAIT;
    			break;
    		}
    		else
    		{
    			ui8IsoControl = TRF797x_ISO_CONTROL;
    			Trf797xReadSingle(&ui8IsoControl, 1);
    			if((ui8IsoControl & BIT5) != BIT5)			// RFID mode
    			{
    				Trf797xISR(&ui8IrqStatus);
    				StatusPrint(g_sTrf797xStatus);
    			}
    			else										// NFC mode
    			{
    				// Do Nothing
    			}
    		}
    	} while(GPIOIntStatus(GPIOA1_BASE,1) & GPIO_PIN_4);
    }
    
    //===============================================================
    //
    // Trf797xRawWrite - Write data to TRF797x
    //
    // \param pui8Payload is the buffer with data packet contents
    // \param ui8Length is the size of the data packet
    //
    // Function is used to write data directly to the TRF797x.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xRawWrite(u08_t * pui8Payload, u08_t ui8Length)
    {
    	u08_t ui8TxBytesRemaining;
    	u08_t ui8TxIndex;
    	u08_t ui8FifoTxLength;
    	u08_t ui8TxBytesAvailable;
    
    	if (127 > ui8Length)
    	{
    		SpiRawWrite(pui8Payload, ui8Length);
    	}
    	else
    	{
    		ui8TxBytesRemaining = ui8Length;
    		ui8TxIndex = 0;
    		ui8TxBytesAvailable = 127;
    
    		while(ui8TxBytesRemaining > 0)
    		{
    			if (ui8TxBytesRemaining > 127)
    			{
    				SpiRawWrite(&pui8Payload[ui8TxIndex], ui8TxBytesAvailable);
    				ui8TxBytesRemaining = ui8TxBytesRemaining - ui8TxBytesAvailable;
    				ui8TxIndex = ui8TxIndex + ui8TxBytesAvailable;
    			}
    			else
    			{
    				SpiRawWrite(&pui8Payload[ui8TxIndex], ui8TxBytesRemaining);
    			}
    
    			Trf797xIrqWaitTimeoutTxOnly(35);
    
    			g_sTrf797xStatus = Trf797xGetTrfStatus();
    
    			if ((g_sTrf797xStatus == TX_COMPLETE) || (g_sTrf797xStatus == TX_WAIT))
    			{
    				ui8FifoTxLength = TRF797x_FIFO_STATUS;
    				Trf797xReadSingle(&ui8FifoTxLength, 1);	// determine the number of bytes left in FIFO
    
    				ui8TxBytesAvailable = 127-ui8FifoTxLength;
    			}
    			else
    			{
    				// Error occurred, break
    				g_sTrf797xStatus = TX_ERROR;
    				break;
    			}
    		}
    	}
    }
    
    //===============================================================
    //
    // Trf797xReadCont - Read out multiple TRF797x registers
    //
    // \param pui8Payload is the address of the first register as
    // well as the pointer for buffer where the results will be
    // \param ui8Length is the number of registers to read
    //
    // Function used to read a specified number of TRF797x registers
    // from a specified address.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xReadCont(u08_t * pui8Payload, u08_t ui8Length)
    {
    	SpiReadCont(pui8Payload, ui8Length);
    }
    
    //===============================================================
    //
    // Trf797xReadIsoControl - Read the ISO Control Register
    //
    // Function used to read the ISO Control Register of the TRF797x
    //
    // \return pui8Value returns the value of the ISO Control
    // Register
    //
    //===============================================================
    
    u08_t
    Trf797xReadIsoControl(void)
    {
    	u08_t pui8Value[1];
    	*pui8Value = TRF797x_ISO_CONTROL;
    
    	SpiReadSingle(pui8Value, 1);
    
    	g_ui8IsoControlValue = pui8Value[0];	// Update the ISO Control Register variable
    
    	return pui8Value[0];
    }
    
    //===============================================================
    //
    // Trf797xReadIrqStatus - Read out the IRQ Status Register
    //
    // \param pui8Value is the pointer to the buffer where the
    // result will be
    //
    // Function used to read the IRQ Status register of the TRF797x
    // and store the result into the location pointed to by the input
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xReadIrqStatus(u08_t * pui8Value)
    {
    	*pui8Value = TRF797x_IRQ_STATUS;
    
    	SpiReadSingle(pui8Value, 1);
    
    /*
    	  *pui8Value = TRF797x_IRQ_STATUS;
    	  *(pui8Value + 1) = TRF797x_IRQ_MASK;
    	  Trf797xReadCont(pui8Value, 2);           // read second reg. as dummy read
    */
    }
    
    //===============================================================
    //
    // Trf797xReadSingle - Read out a single TRF797x registers
    //
    // \param pui8Value is the address of the register to read as
    // well as pointer for the buffer where the result will be
    //
    // Function used to read a specific TRF797x register
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xReadSingle(u08_t *pbuf, u08_t number)
    {
    	SpiReadSingle(pbuf, number);
    }
    
    //===============================================================
    //
    // Trf797xReadStatusControl - Read the Chip Status Control
    // Register
    //
    // Function used to read the Chip Status Control Register of the
    // TRF797x
    //
    // \return pui8Value returns the value of the Chip Status Control
    // Register
    //
    //===============================================================
    
    u08_t
    Trf797xReadStatusControl(void)
    {
    	u08_t pui8Value[1];
    	*pui8Value = TRF797x_STATUS_CONTROL;
    
    	SpiReadSingle(pui8Value, 1);
    
    	if ((pui8Value[0] & BIT5) == BIT5)	// Check for RF field bit and update variable
    	{
    		g_bRfFieldOn = true;
    	}
    	else
    	{
    		g_bRfFieldOn = false;
    	}
    
    	return pui8Value[0];
    }
    
    //===============================================================
    //
    // Trf797xReset - Resets TRF797x
    //
    // Function used to reset the TRF797x
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xReset(void)
    {
    	command[0] = RESET;
    	Trf797xDirectCommand(command);
    }
    
    //===============================================================
    //
    // Trf797xReset - Resets the IRQ Status Register of the TRF797x
    //
    // Function used to reset the TRF797x IRQ Status Register
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xResetIrqStatus(void)
    {
    	u08_t puiIrqStatus[2];
    
    	puiIrqStatus[0] = TRF797x_IRQ_STATUS;
    	puiIrqStatus[1] = TRF797x_IRQ_MASK;
    
    	Trf797xReadCont(puiIrqStatus, 2);		// read second reg. as dummy read
    }
    
    //===============================================================
    //
    // Trf797xRunDecoders - Direct command to enable TRF797x receivers
    //
    // Issue direct command 0x17 - Enable Receivers to the TRF797x
    //
    // \return None.
    //
    //===============================================================
    void
    Trf797xRunDecoders(void)
    {
    	command[0] = RUN_DECODERS;
    	Trf797xDirectCommand(command);
    }
    
    //===============================================================
    //
    // Trf797xStopDecoders - Direct command to disable TRF797x
    // receivers
    //
    // Issue direct command 0x16 - Block Receivers to the TRF797x
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xStopDecoders(void)
    {
    	command[0] = STOP_DECODERS;
    	Trf797xDirectCommand(command);
    }
    
    //===============================================================
    //
    // Trf797xTransmitNextSlot - Direct command to transmit next slot
    // for ISO15693 End of Frame
    //
    // Issue direct command 0x14 - End of Frame/Transmit Next Time Slot
    // (ISO15693) to the TRF797x
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xTransmitNextSlot(void)
    {
    	command[0] = TRANSMIT_NEXT_SLOT;
    	Trf797xDirectCommand(command);
    }
    
    //===============================================================
    //
    // Trf797xTurnRfOff - Turn off the transmission of the TRF797x
    // RF Field
    //
    // Function used stop the TRF797x transmitting an RF field
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xTurnRfOff(void)
    {
    	u08_t	pui8Command[2];
    
    	pui8Command[0] = TRF797x_STATUS_CONTROL;
    	pui8Command[1] = 0x00;			// 3.3VDC, full power out
    //	pui8Command[1] = 0x10;			// 3.3VDC, half power out
    	Trf797xWriteSingle(pui8Command, 2);
    
    	g_bRfFieldOn = false;	// Update RF Field variable
    }
    
    //===============================================================
    //
    // Trf797xTurnRfOn - Turns on the transmission of the TRF797x
    // RF Field
    //
    // Function used make the TRF797x transmit an RF field
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xTurnRfOn(void)
    {
    	u08_t	pui8Command[2];
    
    	pui8Command[0] = TRF797x_STATUS_CONTROL;
    	pui8Command[1] = 0x20;			// 3.3VDC, full power out
    //	pui8Command[1] = 0x30;			// 3.3VDC, half power out
    	Trf797xWriteSingle(pui8Command, 2);
    
    	g_bRfFieldOn = true;	// Update RF Field variable
    }
    
    //===============================================================
    //
    // Trf797xWriteCont - Write to consecutive TRF797x registers
    //
    // \param pui8Payload is the address of the first register
    // followed by the contents to write for each register
    // \param ui8Length is the number of registers to write + 1
    // Minimum value of ui8Length allowed = 2 (a write to 1 register)
    //
    // Function used to write to a specific number of TRF797x
    // registers from a specific address.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xWriteCont(u08_t * pui8Payload, u08_t ui8Length)
    {
    	if (ui8Length > 1) // Cannot specify a length of 1
    	{
    		if (*pui8Payload == 0x00)	// If the write starts at the Chip Status Control Register
    		{
    			if (((*pui8Payload+1) & BIT5) == BIT5)	// Check for RF field bit and update variable
    			{
    				g_bRfFieldOn = true;
    			}
    			else
    			{
    				g_bRfFieldOn = false;
    			}
    			if (ui8Length > 2)		// Check if the write length includes the ISO Control Register being written to (0x01)
    			{
    				g_ui8IsoControlValue = (*pui8Payload+2);	// If so, update the Iso Control Register variable
    			}
    		}
    		else if (*pui8Payload == 0x01)	// If the write starts at the ISO Control Register
    		{
    			g_ui8IsoControlValue = *pui8Payload+1;	// Update the ISO Control Register variable
    		}
    
    		// Call continuous write function
    		SpiWriteCont(pui8Payload, ui8Length);
    	}
    	else
    	{
    		// Error, cannot specify a length of 1
    		return;
    	}
    }
    
    //===============================================================
    //
    // Trf797xWriteIsoControl - Write to TRF797x ISO Control Register
    //
    // \param ui8IsoControl is the value to write to the ISO control
    // register of the TRF797x
    //
    // Function used to write a new value into the ISO Control
    // register of the TRF797x.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xWriteIsoControl(u08_t ui8IsoControl)
    {
    	u08_t pui8Write[2];
    
    	if((ui8IsoControl & BIT5) == BIT5)
    	{
    		// Attempt to enable Card Emulation/Peer to Peer which is not supported by firmware
    		// Exit function to avoid issues with that
    		return;
    	}
    
    	pui8Write[0] = TRF797x_ISO_CONTROL;
    	pui8Write[1] = ui8IsoControl;
    	pui8Write[1] &= ~BIT5;
    	Trf797xWriteSingle(pui8Write, 2);
    
    	g_ui8IsoControlValue = ui8IsoControl;	// Update the ISO Control Register variable
    }
    
    //===============================================================
    //
    // Trf797xWriteRegister - Write single to a TRF797x Register
    //
    // \param ui8TrfRegister is the register address for the write
    // \param ui8Value is the value to write to the specified
    // register
    //
    // Function used to write a new value into a single TRF797x
    // register.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xWriteRegister(u08_t ui8TrfRegister, u08_t ui8Value)
    {
    	u08_t pui8Write[2];
    
    	if (ui8TrfRegister == TRF797x_ISO_CONTROL)
    	{
    		// Attempt to enable Card Emulation/Peer to Peer which is not supported by firmware
    		// Exit function to avoid issues with that
    		if ((ui8Value & BIT5) == BIT5)
    		{
    			return;
    		}
    
    		g_ui8IsoControlValue = ui8Value;	// Update the ISO Control Register variable
    	}
    	if (ui8TrfRegister == TRF797x_STATUS_CONTROL)
    	{
    		if ((ui8Value & BIT5) == BIT5)	// Check for RF field bit and update variable
    		{
    			g_bRfFieldOn = true;
    		}
    		else
    		{
    			g_bRfFieldOn = false;
    		}
    	}
    
    	pui8Write[0] = ui8TrfRegister;
    	pui8Write[1] = ui8Value;
    	Trf797xWriteSingle(pui8Write, 2);
    }
    
    //===============================================================
    //
    // Trf797xWriteInitiatorSetup - Write the initial settings for
    // a set of TRF797x registers based on which protocol is to be
    // enabled.
    //
    // \param ui8IsoControl is the value to write to the ISO Control
    // register of the TRF797x
    //
    // Function used to write to a series of TRF797x registers based
    // on which technology will be enabled in the ISO control register
    // This function currently only enables 1 technology at a time
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xWriteInitiatorSetup(u08_t ui8IsoControl)
    {
    	u08_t pui8Write[2];
    	u08_t write[16];
    
    	g_ui8IsoControlValue = ui8IsoControl;	// Update the ISO Control Register variable
    
    	if (ui8IsoControl == 0x88) // ISO14443A
    	{
    
    
    		// Register 0x00
    		pui8Write[0] = TRF797x_STATUS_CONTROL;
    		pui8Write[1] = 0x20;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x01; // Sys Clock Output = 13.56MHz, OOK = 100%
    		Trf797xWriteSingle(pui8Write, 2);
    	}
    
    	if (ui8IsoControl == 0x0C) // ISO14443B
    	{
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x00; // Sys Clock Output = 13.56MHz, ASK 10%
    		Trf797xWriteSingle(pui8Write, 2);
    	}
    
    	if (ui8IsoControl == 0x02) // ISO15693
    	{
    
    		pui8Write[0] = TRF797x_STATUS_CONTROL;
    		pui8Write[1] = 0x20;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Resgister 0x07 - No Response Wait Time
    		pui8Write[0] = TRF797x_RX_NO_RESPONSE_WAIT_TIME;
    		pui8Write[1] = 0x15;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x01; // Sys Clock Output = 13.56MHz, OOK = 100%
    		Trf797xWriteSingle(pui8Write, 2);
    
    
    
    
    		/*		write[0] = 0x20;                  //Continuous Write, starting with register 0x00
    			    write[1] = 0x20;                  //Value for Chip Status Control Register 0x00, 0x20 = +3.3VDC, full power, etc.
    			    write[2] = 0x02;                  //Value for ISO Control Register 0x01, 0x02 = high tag data rate, etc.
    			    write[3] = 0x00;				  //0x02
    			    write[4] = 0x00;
    			    write[5] = 0xC1;
    			    write[6] = 0xBB;
    			    write[7] = 0x00;
    			    write[8] = 0x30;
    			    write[9] = 0x1F;
    			    write[10] = 0x01;
    			    write[11] = 0x40;
    			    write[12] = 0x03;*/
    
    	/*	// Register 0x00
    		pui8Write[0] = TRF797x_STATUS_CONTROL;
    		pui8Write[1] = 0x20;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x02
    		pui8Write[0] = TRF797x_ISO_14443_TX_OPTIONS;
    		pui8Write[1] = 0x00;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x03
    		pui8Write[0] = TRF797x_ISO_14443_BITRATE_OPTIONS;
    		pui8Write[1] = 0x00;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x04
    		pui8Write[0] = TRF797x_TX_TIMER_EPC_HIGH;
    		pui8Write[1] = 0xC1;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x05
    		pui8Write[0] = TRF797x_TX_TIMER_EPC_LOW;
    		pui8Write[1] = 0xBB;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x06
    		pui8Write[0] = TRF797x_TX_PULSE_LENGTH_CONTROL;
    		pui8Write[1] = 0x00;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Resgister 0x07 - No Response Wait Time
    		pui8Write[0] = TRF797x_RX_NO_RESPONSE_WAIT_TIME;
    		pui8Write[1] = 0x30;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Resgister 0x08 -
    		pui8Write[0] = TRF797x_RX_WAIT_TIME;
    		pui8Write[1] = 0x1F;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x01; // Sys Clock Output = 13.56MHz, OOK = 100%
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x0A
    		pui8Write[0] = TRF797x_RX_SPECIAL_SETTINGS;
    		pui8Write[1] = 0x40;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x0B
    		pui8Write[0] = TRF797x_REGULATOR_CONTROL;
    		pui8Write[1] = 0x03;
    		Trf797xWriteSingle(pui8Write, 2);
    */
    
    
    /*		write[0] = 0x20;                  //Continuous Write, starting with register 0x00
    	    write[1] = 0x20;                  //Value for Chip Status Control Register 0x00, 0x20 = +3.3VDC, full power, etc.
    	    write[2] = 0x02;                  //Value for ISO Control Register 0x01, 0x02 = high tag data rate, etc.
    	    write[3] = 0x00;				  //0x02
    	    write[4] = 0x00;
    	    write[5] = 0xC1;
    	    write[6] = 0xBB;
    	    write[7] = 0x00;
    	    write[8] = 0x30;
    	    write[9] = 0x1F;
    	    write[10] = 0x01;
    	    write[11] = 0x40;
    	    write[12] = 0x03;*/
    
    	    //Trf797xWriteCont(write, 13);      //writes registers 0x00:0x0B
    
    	}
    
    	if (ui8IsoControl == 0x1A) // FeliCa
    	{
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x00; // Sys Clock Output = 13.56MHz, ASK 10%
    		Trf797xWriteSingle(pui8Write, 2);
    	}
    
    	if (ui8IsoControl == 0x86) // PicoPass
    	{
    		// Register 0x01
    		pui8Write[0] = TRF797x_ISO_CONTROL;
    		pui8Write[1] = ui8IsoControl;
    		Trf797xWriteSingle(pui8Write, 2);
    
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		pui8Write[0] = TRF797x_MODULATOR_CONTROL;
    		pui8Write[1] = 0x00; // Sys Clock Output = 13.56MHz, ASK 10%
    		Trf797xWriteSingle(pui8Write, 2);
    	}
    
    	// Register 0x14 - Adjustable FIFO Level
    	pui8Write[0] = TRF797x_FIFO_IRQ_LEVELS;
    	if (ui8IsoControl == 0x86)
    	{
    		// TX water level set to 32 bytes for PicoPass
    		pui8Write[1] = 0x0F;
    	}
    	else
    	{
    		pui8Write[1] = 0x0C;
    	}
    	Trf797xWriteSingle(pui8Write, 2);
    
    }
    
    //===============================================================
    //
    // Trf797xWriteSingle - Write single to a TRF797x Register
    //
    // \param pui8Value is a pointer to a buffer which has the
    // Register address for the write followed by the data to be
    // written to that register
    //
    // Function used to write a new value into a single TRF797x
    // register.
    //
    // \return None.
    //
    //===============================================================
    
    void
    Trf797xWriteSingle(u08_t *pbuf, u08_t length)
    {
    	SpiWriteSingle(pbuf, length);
    }
    
    //===============================================================
    //
    // Trf797xIrqWaitTimeout - Timeout sequence for both TX and RX
    //
    // \param ui8TxTimeout is the TX timeout in milliseconds
    // \param ui8RxTimeout is the RX timeout in milliseconds
    //
    // Function is used to ensure data is transmitted correct as well
    // as determine if data has been received prior to the RX timeout
    // When the RX timeout occurs before data is received, then mark
    // the TRF797x status as a No Response Received status.
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xIrqWaitTimeout(u08_t ui8TxTimeout, u08_t ui8RxTimeout)
    {
    	g_ui8FifoOffset = 0; // Reset the FIFO Offset prior to receiving data
    
    	g_sTrf797xStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while((g_sTrf797xStatus != TX_COMPLETE) && (g_sTrf797xStatus != TX_ERROR))
    	{	// Wait for end of TX
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		// Calculate the timeout value for the timer
    		A2CounterLoad(COUNT_1ms * ui8TxTimeout);
    		// Start the Timeout
    		START_COUNTER;
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		STOP_COUNTER;
    		RESET_COUNTER;
    		if (g_sTrf797xStatus != TX_COMPLETE)
    		{
    			if (g_sTrf797xStatus == TX_WAIT)	// Wait longer since we received an 0xA0
    			{
    				UartSendCString("Received TX_WAIT\n\r");
    				Trf797xIrqWaitTimeoutTxOnly(ui8TxTimeout);	// Wait longer for transmission to complete
    			}
    			else	// Failed to send packet properly - Exit TX Timeout
    			{
    				g_sTrf797xStatus = TX_ERROR;	// Set status to error
    			}
    		}
    	}
    
    	if (g_sTrf797xStatus != TX_ERROR)
    	{
    		g_sTrf797xStatus = RX_WAIT;
    		g_ui8TimeoutFlag = 0x00;
    		while(g_sTrf797xStatus == RX_WAIT)		// Wait for end of RX or timeout
    		{
    			// Clear the IRQ Flag
    			g_ui8IrqFlag = 0x00;
    			// Setup for the Timer
    			// Calculate the timeout value for the timer
    			A2CounterLoad(COUNT_1ms * ui8TxTimeout);
    			// Start the Timeout
    			START_COUNTER;
    			while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    			{
    				// Do Nothing
    			}
    			while (g_sTrf797xStatus == RX_WAIT_EXTENSION)
    			{
    				STOP_COUNTER;
    				RESET_COUNTER;
    				g_ui8IrqFlag = 0x00;
    				if ((g_ui8IsoControlValue & 0x1F) > 0x07)
    				{
    					A2CounterLoad(COUNT_1ms * 7);
    				}
    				else
    				{
    					A2CounterLoad(COUNT_1ms * 50);
    				}
    				START_COUNTER;
    				while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    				{
    					// Do Nothing
    				}
    			}
    			STOP_COUNTER;
    			RESET_COUNTER;
    			if (g_sTrf797xStatus == RX_WAIT)
    			{
    				// Exit the while loop
    				g_sTrf797xStatus = NO_RESPONSE_RECEIVED;
    			}
    		}
    	}
    }
    
    //===============================================================
    //
    // Trf797xIrqWaitTimeoutTxOnly - Timeout sequence for just TX
    //
    // \param ui8TxTimeout is the TX timeout in milliseconds
    //
    // Function is used to handle delays for transmit only, which
    // is helpful when a response is not expected (such as with sleep
    // or halt commands)
    // This function will not delay to receive any responses
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xIrqWaitTimeoutTxOnly(u08_t ui8TxTimeout)
    {
    	g_sTrf797xStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while((g_sTrf797xStatus != TX_COMPLETE) && (g_sTrf797xStatus != NO_RESPONSE_RECEIVED) && (g_sTrf797xStatus != TX_ERROR))
    	{										// Wait for end of TX
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		// Calculate the timeout value for the timer
    		A2CounterLoad(COUNT_1ms * ui8TxTimeout);
    		// Start the Timeout
    		START_COUNTER;
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		STOP_COUNTER;
    		RESET_COUNTER;
    		if (g_sTrf797xStatus != TX_COMPLETE)
    		{
    			if (g_sTrf797xStatus == TX_WAIT)	// Wait longer since we received an 0xA0
    			{
    				Trf797xIrqWaitTimeoutTxOnly(ui8TxTimeout);	// Wait longer for transmission to complete
    			}
    			else	// Failed to send packet properly - Exit TX Timeout
    			{
    				g_sTrf797xStatus = TX_ERROR;	// Set status to error
    			}
    		}
    	}
    }
    
    
    //===============================================================
    //
    // Trf797xIrqWaitTimeoutRxOnly - Timeout sequence for just RX
    //
    // \param ui8RxTimeout is the RX timeout in milliseconds
    //
    // Function is used to handle delays for receive only, such as
    // when waiting for a response without sending a data package
    // during anticollision slot procedures.
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xIrqWaitTimeoutRxOnly(u08_t ui8RxTimeout)
    {
    	g_ui8FifoOffset = 0; // Reset the FIFO Offset prior to receiving data
    
    	g_sTrf797xStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while(g_sTrf797xStatus == RX_WAIT)		// Wait for end of RX or timeout
    	{
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		// Calculate the timeout value for the timer
    		A2CounterLoad(COUNT_1ms * ui8RxTimeout);
    		// Start the Timeout
    		START_COUNTER;
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		while (g_sTrf797xStatus == RX_WAIT_EXTENSION)
    		{
    			STOP_COUNTER;
    			RESET_COUNTER;
    			g_ui8IrqFlag = 0x00;
    			if ((g_ui8IsoControlValue & 0x1F) > 0x07)
    			{
    				A2CounterLoad(COUNT_1ms * 7);
    			}
    			else
    			{
    				A2CounterLoad(COUNT_1ms * 50);
    			}
    			START_COUNTER;
    			while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    			{
    				// Do Nothing
    			}
    		}
    		STOP_COUNTER;
    		RESET_COUNTER;
    		if (g_sTrf797xStatus == RX_WAIT)
    		{
    			// Exit the while loop
    			g_sTrf797xStatus = NO_RESPONSE_RECEIVED;
    		}
    	}
    }
    
    //===============================================================
    //
    // Trf797xIrqWaitTimeoutFeliCa - Timeout sequence for just RX
    // specifically for FeliCa slot timings
    //
    // Function is used to handle receive delays for FeliCa
    // anticollision only.
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xIrqWaitTimeoutFeliCa(void)
    {
    	g_ui8FifoOffset = 0; // Reset the FIFO Offset prior to receiving data
    
    	g_sTrf797xStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while(g_sTrf797xStatus == RX_WAIT)		// Wait for end of RX or timeout
    	{
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		// Calculate the timeout value for the timer
    		A2CounterLoad(2);
    
    		// Start the Timeout
    		START_COUNTER;
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		STOP_COUNTER;
    		RESET_COUNTER;
    		if (g_sTrf797xStatus == RX_WAIT)
    		{
    			// Exit the while loop
    			g_sTrf797xStatus = NO_RESPONSE_RECEIVED;
    		}
    	}
    }
    
    
    //===============================================================
    //
    // Trf797xGetTrfStatus - Returns current TRF797x driver status
    //
    // Function is used to pass the current TRF797x driver status
    // up to higher layers of the firmware
    //
    // \return g_sTrf797xStatus returns the current TRF797x drive
    // status
    //
    //===============================================================
    
    tTRF797x_Status Trf797xGetTrfStatus(void)
    {
    	return g_sTrf797xStatus;
    }
    
    //===============================================================
    //
    // Trf797xSetTrfStatus - Set the TRF797x driver status
    //
    // \param sTrfStatus is the new TRF797x driver status
    //
    // Function is used to allow higher layers of the firmware to
    // set the TRF797x driver status without an IRQ event. Use with
    // caution.
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xSetTrfStatus(tTRF797x_Status sTrfStatus)
    {
    	g_sTrf797xStatus = sTrfStatus;
    }
    
    //===============================================================
    //
    // Trf797xGetCollisionPosition - Return the current Collision
    // Position value
    //
    // Function is used to pass the current Collision Position value
    // up to higher layers of the firmware. Used for ISO14443 Type A
    // anti-collision process.
    //
    // \return g_ui8CollisionPosition returns the current Collision
    // Position value
    //
    //===============================================================
    
    u08_t Trf797xGetCollisionPosition(void)
    {
    	return g_ui8CollisionPosition;
    }
    
    //===============================================================
    //
    // Trf797xSetCollisionPosition - Set the Collision Position
    // variable
    //
    // \param ui8ColPos is the new Collision Position value
    //
    // Function is used to allow higher layers of the firmware to
    // set the Collision Position variable. Used for ISO14443 Type A
    // anti-collision process
    //
    // \return None.
    //
    //===============================================================
    
    void Trf797xSetCollisionPosition(u08_t ui8ColPos)
    {
    	g_ui8CollisionPosition = ui8ColPos;
    }
    
    //===============================================================
    //
    // Trf797xGetRxBytesReceived - Returns the Number of RX Bytes
    // received by the TRF797x FIFO
    //
    // Function is used to pass the number of RX bytes received
    // during the last packet reception up to higher layers of the
    // firmware.
    // This can be used by the application layer to check for the
    // length of bytes received and ensure packets were correctly
    // received.
    //
    // \return g_ui8FifoRxLength returns the current FIFO RX Length
    //
    //===============================================================
    
    u08_t Trf797xGetRxBytesReceived(void)
    {
    	return g_ui8FifoRxLength;
    }
    
    //===============================================================
    //
    // Trf797xGetIsoControlValue - Fetch the latest Iso Control
    // Register value
    //
    // Function is used to pass the current Iso Control Register
    // value up to higher layers of the firmware.
    //
    // The Iso Control Register value is updated whenever a read or
    // write to the Iso Control Register occurs.
    //
    // \return g_ui8IsoControlValue returns the current ISO Control
    // Register value
    //
    //===============================================================
    
    u08_t Trf797xGetIsoControlValue(void)
    {
    	return g_ui8IsoControlValue;
    }
    
    //===============================================================
    //
    // Trf797xReadRssiLevels - Reads the RSSI Levels register and then
    // returns the value of the latest RSSI measurement
    //
    // Function is used to determine the latest RSSI Level reading.
    // The RSSI Level register is updated when RF data is received
    // by the TRF797x. For most accurate reading, this function should
    // be called directly following a reception of RF data.
    //
    // \return pui8Read returns the latest RSSI Register value
    //
    //===============================================================
    
    u08_t Trf797xReadRssiLevels(void)
    {
    	u08_t pui8Read[1];
    
    	pui8Read[0] = TRF797x_RSSI_LEVELS;		// read RSSI levels
    	Trf797xReadSingle(pui8Read, 1);
    
    	return pui8Read[0];
    }
    
    //===============================================================
    //
    // Trf797xCheckRfField - Fetch the RfFieldOn variable
    //
    // Function is used to pass the current RfFieldOn value up to
    // higher layers of the firmware
    //
    // \return g_bRfFieldOn retuns the current RF field status
    //
    //===============================================================
    
    bool Trf797xCheckRfField(void)
    {
    	return g_bRfFieldOn;
    }
    
    //*****************************************************************************
    //
    //! This function gets triggered when A2CNT interrupt occures
    //!
    //! \param none
    //!
    //! \return None
    //!
    //*****************************************************************************
    void A2CNTIntHandler (void){
    
    	u08_t ui8IrqStatus;
    	ui8IrqStatus = 0x00;
    
    	STOP_COUNTER;
    
    	g_ui8TimeoutFlag = 0x01;
    
    	Trf797xReadIrqStatus(&ui8IrqStatus);
    
    	ui8IrqStatus = ui8IrqStatus & 0xF7;		// Set the parity flag to 0
    
    	if(ui8IrqStatus == TRF797x_IRQ_STATUS_TX_COMPLETE)
    	{
    		g_sTrf797xStatus = TX_COMPLETE;
    	}
    	else if(ui8IrqStatus == TRF797x_IRQ_STATUS_IDLE)
    	{
    		g_sTrf797xStatus = NO_RESPONSE_RECEIVED;
    	}
    	else
    	{
    		g_sTrf797xStatus = RX_WAIT;
    	}
    }
    
    void StatusPrint(tTRF797x_Status sTrfStatus) {
    	switch (sTrfStatus) {
    	case TRF_IDLE:
    		UartSendCString("Status: TRF_IDLE\n\r");
    		break;
    	case TX_COMPLETE:
    			UartSendCString("Status: TX_COMPLETE\n\r");
    			break;
    	case RX_COMPLETE:
    			UartSendCString("Status: RX_COMPLETE\n\r");
    			break;
    	case TX_ERROR:
    			UartSendCString("Status: TX_ERROR\n\r");
    			break;
    	case RX_WAIT:
    			UartSendCString("Status: RX_WAIT\n\r");
    			break;
    	case RX_WAIT_EXTENSION:
    			UartSendCString("Status: RX_WAIT_EXTENSION\n\r");
    			break;
    	case TX_WAIT:
    			UartSendCString("Status: TX_WAIT\n\r");
    			break;
    	case PROTOCOL_ERROR:
    			UartSendCString("Status: PROTOCOL_ERROR\n\r");
    			break;
    	case NO_RESPONSE_RECEIVED:
    			UartSendCString("Status: NO_RESPONSE_RECEIVED\n\r");
    			break;
    	case NO_RESPONSE_RECEIVED_15693:
    			UartSendCString("Status: NO_RESPONSE_RECEIVED_15693\n\r");
    			break;
    	default:
    		UartSendCString("Status: Unknown\n\r");
    		break;
    	}
    }
    

     

     

    I'll also include my entire project in case if that could be helpful.

    trf7970a-p2p-testproj.rar