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: Demo ISO15693 Anti-collision and 6.62 kbps

Part Number: TRF7970A
Other Parts Discussed in Thread: MSP-EXP430F5529LP, DLP-7970ABP, , MSP-EXP430G2ET

I have the DLP-7970ABP and MSP-EXP430F5529LP running under NFC Tool Ver 1.8.  I will be using the TRF7970A for ISO-15693 tag reading.

Two functions I would like to see demonstrated are:

1) Anti-collision

2) 6.62 kbps data transmission (ISO-15693 "long")

NFC Tool does not have these as options.  Is there demo software for either of these?

Thank you.

  • Hello Mark,

    The NFC Tool as provided does not support anti-collision as our software is setup per the NFC forum specifications that do not require anticollision functionality. With that software base, it would be difficult to add such functionality as it is not natively included in that stack.

    To address needs like yours, we also offer a second software base which covers topics like ISO15693 anticollision with an optimized algorithm. You would be able to configure that base for low data rate without much trouble either.

    The software can be download here: http://www.ti.com/lit/zip/sloc297

    You would need an MSP-EXP430G2ET LaunchPad to work with this firmware 'out of the box' as the software is also designed to be used on MCU's with less memory resources than the F5529.

    To enable low data rate, you would need to do the following:

    1) Adjust the TRF79xxA_setupInitiator call to account for low data rate

    2) Change the flags used for transmission to not indicate high data rate.

    You may possible need to adjust a register for interoperability with all tags when using low data rate, but try the device default settings from the ISO control change first. If there any issues, the No Response Wait time may need to be adjusted.

  • This setup demonstrated collision avoidance. Thanks, that's my primary want.

    When I change the calls TRF79xxA_setupInitiator(0x02) to TRF79xxA_setupInitiator(0x00) (in iso15693.c & nsf_app.c) output modulation still is at the 26 kbps rate, rather than the expected 6.6 kbps.  Are there other places in the code I need to change configuration?

  • Hello Mark,

    I can clearly see now I did a terrible job communicating the changes required. Sorry.

    By "Adjust the TRF79xxA_setupInitiator call to account for low data rate" I had meant the function itself because low rate is not a covered case for it. So you'd need to adjust the actually API in order to add a new case, and then have the right ISO control register setting called.

  • I neglected to note I did go into TRF79xxA_setupInitiator() and set it up to respond to ISO Control register setting 0.

    Further experimentation found I can change modulation between AKS/OOK and 1:4/1:256 encoding. Still, no change to modulation rate.

    Setting a breakpoint on SPI_writeSingle(), I didn't see evidence of gremlins overwriting ISO Control.

    Nothing in the Errata suggests issues with 6.62 kbps.

    Perhaps I'm missing something with register settings.  Are there other register changes needed along with ISO Control?

  • Hello Mark,

    Can you post the modified TRF79xxA_setupInitiator function? I will try it on my end.

  • trf79xxa.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 "trf79xxa.h"
    
    //===============================================================
    
    uint8_t g_pui8TrfBuffer[NFC_FIFO_SIZE];
    
    static uint8_t	g_ui8CollisionPosition;
    
    static uint8_t	g_ui8FifoOffset;
    static uint8_t	g_ui8FifoRxLength;
    
    static tTrfStatus g_sTrfStatus;
    static tTrfSettings g_eTrfGeneralSettings;
    
    static volatile uint8_t g_ui8IrqFlag;
    static volatile uint8_t g_ui8TimeoutFlag;
    
    //*****************************************************************************
    //
    //! \addtogroup trf797x_api TRF7970A Driver API's
    //! @{
    //!
    //! This section describes all the functions contained within the TRF79xxA
    //! driver.
    //
    //*****************************************************************************
    
    //===============================================================
    //
    //! TRF79xxA_sendDirectCommand - Send a Direct Command to TRF79xxA.
    //!
    //! \param ui8Value is the direct command to be issued
    //!
    //! This function is used to transmit a Direct Command to TRF79xxA.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_sendDirectCommand(uint8_t ui8Value)
    {
    	SPI_directCommand(ui8Value);
    }
    
    //===============================================================
    //
    //! TRF79xxA_disableSlotCounter - Disables interrupts from 15693
    //! slot counter function.
    //!
    //! This function will configure the TRF79xxA to disable the
    //! firing of the IRQ interrupt when an ISO15693 slot marker
    //! hits the No Response timeout threshold.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_disableSlotCounter(void)
    {
    	uint8_t ui8Value;
    
    	ui8Value = TRF79xxA_readRegister(TRF79XXA_IRQ_MASK);
    	ui8Value &= 0xFE;		// Clear BIT0 in register 0x0D
    	TRF79xxA_writeRegister(TRF79XXA_IRQ_MASK,ui8Value);
    }
    
    //===============================================================
    //
    //! TRF79xxA_enableSlotCounter - Enables interrupts from 15693
    //! slot counter function.
    //!
    //! This function will configure the TRF79xxA to enable the
    //! firing of the IRQ interrupt when an ISO15693 slot marker
    //! hits the No Response timeout threshold.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_enableSlotCounter(void)
    {
    	uint8_t ui8Value;
    
    	ui8Value = TRF79xxA_readRegister(TRF79XXA_IRQ_MASK);
    	ui8Value |= BIT0;		// Set BIT0 in register 0x0D
    	TRF79xxA_writeRegister(TRF79XXA_IRQ_MASK,ui8Value);
    }
    
    //===============================================================
    //
    //! TRF79xxA_resetFIFO - Resets TRF79xxA FIFO
    //!
    //! This function used to reset the TRF79xxA FIFO.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_resetFIFO(void)
    {
    	uint8_t	ui8Command;
    
    	ui8Command = TRF79XXA_RESET_FIFO_CMD;
    	TRF79xxA_sendDirectCommand(ui8Command);
    }
    
    //===============================================================
    //
    //! TRF79xxA_initialSettings - Initialize TRF79xxA
    //!
    //! This function configures the TRF79xxA upon power up.
    //! Steps include:
    //!  - Setup SPI communication
    //!  - Send Soft Init and Idle Direct Commands
    //!  - Reset the FIFO
    //!  - Configure TRF79xxA modulator and regulator registers
    //!  - TRF7970A only: Write to regiser 0x18 per errata
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_initialSettings(void)
    {
    	g_ui8CollisionPosition = 0;
    	g_ui8FifoOffset = 0;
    	g_ui8FifoRxLength = 0;
    
    	g_sTrfStatus = TRF_IDLE;
    	g_eTrfGeneralSettings.eTrfPowerSetting = TRF79xxA_3V_FULL_POWER;
    	g_eTrfGeneralSettings.bRfFieldOn = false;
    	g_eTrfGeneralSettings.ui8IsoControl = 0x02;	// TRF79xxA Default
    
    	g_ui8IrqFlag = 0x00;
    	g_ui8TimeoutFlag = 0x00;
    
    	// Setup TRF79xxA SPI Module
    	SPI_setup();
    
    	// Delay to allow SPI to finish starting up
    	MCU_delayMillisecond(1);
    
    	// Send out SOFT_INIT + IDLE initial sequence to soft reset TRF7970A
    	TRF79xxA_sendDirectCommand(TRF79XXA_SOFT_INIT_CMD);
    	TRF79xxA_sendDirectCommand(TRF79XXA_IDLE_CMD);
    
    	// Delay to ensure soft reset has processed
    	MCU_delayMillisecond(1);
    
    #if (TRF79xxA_VERSION == 70)
    	g_eTrfGeneralSettings.ui8IsoControl = 0x21;
    #elif (TRF79xxA_VERSION == 60)
    	g_eTrfGeneralSettings.ui8IsoControl = 0x02;
    #endif
    
    	TRF79xxA_resetFIFO();			// Reset the FIFO
    
    	TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x01); 		// ASK 100%, no SYS_CLK output
    
    	TRF79xxA_writeRegister(TRF79XXA_REGULATOR_CONTROL, 0x01);
    
    #if (TRF79xxA_VERSION == 70)
    	TRF79xxA_writeRegister(TRF79XXA_NFC_TARGET_LEVEL, 0x00); 		// For TRF7970A Errata
    #endif
    }
    
    //===============================================================
    //
    //! TRF79xxA_processIRQ - Services TRF79xxA IRQ interrupts
    //!
    //! \param pui8IrqStatus is the received IRQ Status flags
    //!
    //! The Interrupt Service Routine determines how the IRQ should
    //! be handled. The TRF79xxA IRQ status register is read to
    //! determine the cause of the IRQ. Conditions are checked and
    //! appropriate actions taken.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_processIRQ(uint8_t * pui8IrqStatus)
    {
    	uint8_t	ui8DummyRead;
    	uint8_t	ui8Length;
    
    	if(*pui8IrqStatus == (TRF79XXA_IRQ_STATUS_TX_COMPLETE | TRF79XXA_IRQ_STATUS_FIFO_HIGH_OR_LOW))			// BIT5 and BIT7
    	{								// TX active and 32 bytes left in FIFO
    		g_sTrfStatus = TX_COMPLETE;
    	}
    
    	else if(*pui8IrqStatus == TRF79XXA_IRQ_STATUS_TX_COMPLETE)
    	{								// TX complete
    		g_sTrfStatus = TX_COMPLETE;
    		TRF79xxA_resetFIFO();				// reset the FIFO after TX
    	}
    
    	else if((*pui8IrqStatus & BIT1) == TRF79XXA_IRQ_STATUS_COLLISION_ERROR)
    	{								// Collision error
    		if ((g_eTrfGeneralSettings.ui8IsoControl == 0x08) || (g_eTrfGeneralSettings.ui8IsoControl == 0x88))
    		{
    			g_sTrfStatus = COLLISION_ERROR;
    
    			g_ui8CollisionPosition = TRF79xxA_readRegister(TRF79XXA_COLLISION_POSITION);
    
    			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_pui8TrfBuffer[g_ui8FifoOffset] = TRF79XXA_FIFO;		// write the recieved bytes to the correct place of the buffer
    
    					TRF79xxA_readContinuous(&g_pui8TrfBuffer[g_ui8FifoOffset], ui8Length);
    					g_ui8FifoOffset = g_ui8FifoOffset + ui8Length;
    				}
    			}
    			else
    			{
    				g_ui8FifoRxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    #if (TRF79xxA_VERSION == 70)
    				g_ui8FifoRxLength &= 0x7F;
    #elif (TRF79xxA_VERSION == 60)
    				g_ui8FifoRxLength = (0x0F & g_ui8FifoRxLength) + 1;
    #endif
    
    				g_pui8TrfBuffer[g_ui8FifoOffset] = TRF79XXA_FIFO;				// write the recieved bytes to the correct place of the buffer
    
    				TRF79xxA_readContinuous(&g_pui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);
    				g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;
    			}
    		}
    		else if((g_eTrfGeneralSettings.ui8IsoControl & 0xF8) == 0x00)		// Covers all ISO15693 Data Rates for RFID mode with RX CRC on
    		{
    			g_sTrfStatus = COLLISION_ERROR;
    		}
    		else
    		{
    			g_sTrfStatus = PROTOCOL_ERROR;
    		}
    
    		TRF79xxA_sendDirectCommand(TRF79XXA_STOP_DECODERS_CMD);
    		TRF79xxA_resetFIFO();		// reset the FIFO after TX
    		TRF79xxA_resetIrqStatus();
    
    		IRQ_CLR;
    	}
    	else if(*pui8IrqStatus == TRF79XXA_IRQ_STATUS_RX_COMPLETE)
    	{	// RX flag means that EOF has been recieved
    		// and the number of unread bytes is in FIFOstatus regiter	
    
    		g_ui8FifoRxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    #if (TRF79xxA_VERSION == 70)
    		g_ui8FifoRxLength &= 0x7F;
    #elif (TRF79xxA_VERSION == 60)
    		g_ui8FifoRxLength = (0x0F & g_ui8FifoRxLength) + 1;
    #endif
    		g_pui8TrfBuffer[g_ui8FifoOffset] = TRF79XXA_FIFO;				// write the received bytes to the correct place of the buffer
    
    		TRF79xxA_readContinuous(&g_pui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);
    
    		g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;
    
    		TRF79xxA_resetFIFO();			// reset the FIFO after last byte has been read out
    
    		if (g_sTrfStatus == RX_WAIT_EXTENSION)
    		{
    			g_ui8FifoRxLength = g_ui8FifoOffset;
    		}
    
    		g_sTrfStatus = RX_COMPLETE;
    	}	
    	else if(*pui8IrqStatus == (TRF79XXA_IRQ_STATUS_RX_COMPLETE | TRF79XXA_IRQ_STATUS_FIFO_HIGH_OR_LOW))
    	{									// RX active and 96 bytes allready in FIFO
    		g_sTrfStatus = RX_WAIT;
    
    		// Read FIFO Status to determine how many bytes are in the FIFO
    		g_ui8FifoRxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    #if (TRF79xxA_VERSION == 70)
    		g_ui8FifoRxLength &= 0x7F;
    #elif (TRF79xxA_VERSION == 60)
    		g_ui8FifoRxLength = (0x0F & g_ui8FifoRxLength) + 1;
    #endif
    
    		if (NFC_FIFO_SIZE > (g_ui8FifoOffset+g_ui8FifoRxLength))
    		{
    			// Read from the FIFO to empty it
    			g_pui8TrfBuffer[g_ui8FifoOffset] = TRF79XXA_FIFO;
    			TRF79xxA_readContinuous(&g_pui8TrfBuffer[g_ui8FifoOffset], g_ui8FifoRxLength);	// read all received bytes from FIFO
    			g_ui8FifoOffset = g_ui8FifoOffset + g_ui8FifoRxLength;					// Adjust buffer index
    		}
    		else
    		{
    			g_sTrfStatus = PROTOCOL_ERROR;
    			return;
    		}
    
    #if (TRF79xxA_VERSION == 70)
    		// Read FIFO Status again to determine if more bytes have been received
    		g_ui8FifoRxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    		g_ui8FifoRxLength &= 0x7F;
    
    		if (g_ui8FifoRxLength > 0)
    		{
    			g_sTrfStatus = RX_WAIT_EXTENSION;
    		}
    		else
    		{
    			g_ui8FifoRxLength = g_ui8FifoOffset;
    			g_sTrfStatus = RX_COMPLETE;
    			return;
    		}
    #elif (TRF79xxA_VERSION == 60)
    		// Cannot rely on FIFO Status results to indicate number of bytes left, therefore always must go to RX_WAIT_EXTENSION state.
    		g_sTrfStatus = RX_WAIT_EXTENSION;
    		g_ui8FifoRxLength = g_ui8FifoOffset;
    #endif
    	}
    	else if (*pui8IrqStatus == (TRF79XXA_IRQ_STATUS_RX_COMPLETE | TRF79XXA_IRQ_STATUS_NO_RESPONSE))
    	{
    		// RX has begun but as not completed, space exists in FIFO still, just wait longer to receive full reply.
    		g_sTrfStatus = RX_WAIT_EXTENSION;
    	}
    	else if((*pui8IrqStatus & BIT4) == TRF79XXA_IRQ_STATUS_CRC_ERROR)		// CRC error
    	{
    		if((*pui8IrqStatus & BIT6) == TRF79XXA_IRQ_STATUS_RX_COMPLETE)		// 4 Bit receive
    		{
    			ui8DummyRead = TRF79XXA_FIFO;		// write the recieved bytes to the correct place of the buffer
    
    			TRF79xxA_readContinuous(&ui8DummyRead, 1);
    		}
    
    		TRF79xxA_reset();
    
    		g_sTrfStatus = PROTOCOL_ERROR;
    	}
    	else if((*pui8IrqStatus & BIT2) == TRF79XXA_IRQ_STATUS_FRAMING_ERROR)	// byte framing error
    	{
    		if((*pui8IrqStatus & BIT5) == TRF79XXA_IRQ_STATUS_FIFO_HIGH_OR_LOW)
    		{
    			g_sTrfStatus = RX_WAIT;
    		}
    		else if ((*pui8IrqStatus & BIT6) == TRF79XXA_IRQ_STATUS_RX_COMPLETE)
    		{
    			if((g_eTrfGeneralSettings.ui8IsoControl & 0xF8) == 0x00)		// Covers all ISO15693 Data Rates for RFID mode with RX CRC on
    			{
    				g_sTrfStatus = COLLISION_ERROR;
    			}
    			else
    			{
    				g_sTrfStatus = PROTOCOL_ERROR;
    
    				TRF79xxA_reset();
    			}
    		}
    		else
    		{
    			g_sTrfStatus = PROTOCOL_ERROR;
    
    			TRF79xxA_reset();
    		}
    	}
    	else if(*pui8IrqStatus == TRF79XXA_IRQ_STATUS_IDLE)
    	{						// No response interrupt
    		g_sTrfStatus = NO_RESPONSE_RECEIVED;
    	}
    	else if(*pui8IrqStatus == TRF79XXA_IRQ_STATUS_NO_RESPONSE)
    	{						// No response interrupt
    		g_sTrfStatus = NO_RESPONSE_RECEIVED_15693;
    		g_ui8FifoOffset = 0;
    	}
    	else
    	{						// Interrupt register not properly set
    		g_sTrfStatus = PROTOCOL_ERROR;
    
    		TRF79xxA_sendDirectCommand(TRF79XXA_STOP_DECODERS_CMD);	// reset the FIFO after TX
    		TRF79xxA_reset();
    		TRF79xxA_resetIrqStatus();
    
    		IRQ_CLR;
    	}
    }							// Interrupt Service Routine
    
    
    //===============================================================
    //
    //! TRF79xxA_writeRaw - Write data to TRF79xxA
    //!
    //! \param pui8Payload is the buffer with data packet contents
    //! \param ui8Length is the size of the data packet
    //!
    //! This function writes provided data directly to the TRF79xxA.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_writeRaw(uint8_t * pui8Payload, uint8_t ui8Length)
    {
    	uint8_t ui8TxBytesRemaining;
    	uint8_t ui8TxIndex;
    	uint8_t ui8FifoTxLength;
    	uint8_t ui8TxBytesAvailable;
    	bool bContinuedSend = false;
    
    	g_sTrfStatus = TRF_IDLE;
    
    	// First send includes 5 bytes for command overhead
    	if (TRF79xxA_MAX_FIFO_SIZE+5 > ui8Length)
    	{
    		SPI_rawWrite(pui8Payload, ui8Length, bContinuedSend);
    	}
    	else
    	{
    		ui8TxBytesRemaining = ui8Length;
    		ui8TxIndex = 0;
    		ui8TxBytesAvailable = TRF79xxA_MAX_FIFO_SIZE+5; // First send includes 5 bytes for command overhead
    														// (Reset FIFO, Transmit with or without CRC, Continuous Write, Length High and Length Low)
    		bContinuedSend = false;							// First send is not continued
    
    		while(ui8TxBytesRemaining > 0)
    		{
    			if (ui8TxBytesRemaining > TRF79xxA_MAX_FIFO_SIZE)
    			{
    #if TRF79xxA_VERSION == 60
    				// Avoid 60A single byte FIFO TX case from sloa140 Section 1.5
    				if ((ui8TxBytesRemaining - ui8TxBytesAvailable) == 1)
    				{
    					SPI_rawWrite(&pui8Payload[ui8TxIndex], ui8TxBytesAvailable-1, bContinuedSend);
    					ui8TxBytesRemaining = ui8TxBytesRemaining - ui8TxBytesAvailable - 1;
    				}
    				else
    				{
    #endif
    					SPI_rawWrite(&pui8Payload[ui8TxIndex], ui8TxBytesAvailable, bContinuedSend);
    					ui8TxBytesRemaining = ui8TxBytesRemaining - ui8TxBytesAvailable;
    #if TRF79xxA_VERSION == 60
    				}
    #endif
    				ui8TxIndex = ui8TxIndex + ui8TxBytesAvailable;
    				bContinuedSend = true;
    			}
    			else
    			{
    				// Last send
    				SPI_rawWrite(&pui8Payload[ui8TxIndex], ui8TxBytesRemaining, bContinuedSend);
    				bContinuedSend = false;
    				ui8TxBytesRemaining = 0;
    			}
    
    			g_ui8TimeoutFlag = 0x00;
    			// Clear the IRQ Flag
    			g_ui8IrqFlag = 0x00;
    			// Setup for the Timer
    			MCU_setCounter(5);
    			while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    			{
    				// Do Nothing
    			}
    			RESET_COUNTER;
    
    			if (g_sTrfStatus == TX_WAIT)
    			{
    				ui8FifoTxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    #if (TRF79xxA_VERSION == 70)
    				ui8FifoTxLength &= 0x7F;
    #elif (TRF79xxA_VERSION == 60)
    				ui8FifoTxLength = 0x0F & ui8FifoTxLength;
    #endif
    				ui8TxBytesAvailable = TRF79xxA_MAX_FIFO_SIZE-ui8FifoTxLength;
    			}
    			else if (g_sTrfStatus == TX_COMPLETE)
    			{
    				if (ui8TxBytesRemaining == 0)
    				{
    					// Packet is sent
    					break;
    				}
    				else
    				{
    					ui8FifoTxLength = TRF79xxA_readRegister(TRF79XXA_FIFO_STATUS);
    #if (TRF79xxA_VERSION == 70)
    					ui8FifoTxLength &= 0x7F;
    #elif (TRF79xxA_VERSION == 60)
    					ui8FifoTxLength = 0x0F & ui8FifoTxLength;
    #endif
    					ui8TxBytesAvailable = TRF79xxA_MAX_FIFO_SIZE-ui8FifoTxLength;
    
    					bContinuedSend = true;
    				}
    			}
    			else
    			{
    				// Error occurred, break
    				g_sTrfStatus = TX_ERROR;
    				break;
    			}
    		}
    	}
    }
    
    //===============================================================
    //
    //! TRF79xxA_readContinuous - Read multiple TRF79xxA 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
    //!
    //! This function reads a specified number of TRF79xxA registers
    //! from a specified address.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_readContinuous(uint8_t * pui8Payload, uint8_t ui8Length)
    {
    	SPI_readCont(pui8Payload, ui8Length);
    }
    
    //===============================================================
    //
    //! TRF79xxA_readIrqStatus - Read out the IRQ Status Register
    //!
    //! This function reads the IRQ Status register of the TRF79xxA
    //! and store the result into the location pointed to by the
    //! input.
    //!
    //! \return pui8Value returns the value of the IRQ Status
    //! Register
    //
    //===============================================================
    
    uint8_t TRF79xxA_readIrqStatus(void)
    {
    	uint8_t pui8Value[2];
    
    	pui8Value[0] = TRF79XXA_IRQ_STATUS;
    #if (TRF79xxA_VERSION == 70)
    	SPI_readSingle(pui8Value);
    #elif (TRF79xxA_VERSION == 60)
    	SPI_readCont(pui8Value,2);		// Dummy read to properly clear IRQ Status for TRF796xA devices (except 64A)
    #endif
    
    	return pui8Value[0];
    }
    
    //===============================================================
    //
    //! TRF79xxA_readRegister - Read out a single TRF79xxA register
    //!
    //! This function reads a specific TRF79xxA register.
    //!
    //! \return pui8Value returns the value of the TRF79xxA Register
    //
    //===============================================================
    
    uint8_t TRF79xxA_readRegister(uint8_t ui8TrfRegister)
    {
    	uint8_t pui8Value[1];
    
    	pui8Value[0] = ui8TrfRegister;
    	SPI_readSingle(pui8Value);
    
    	return pui8Value[0];
    }
    
    //===============================================================
    //
    //! TRF79xxA_reset - Resets TRF79xxA
    //!
    //! This function will reset the TRF79xxA through the Software
    //! Init direct command followed by reinitializing basic settings
    //! and clearing affected global variables.
    //!
    //! \return None.
    //
    //===============================================================
    
    void
    TRF79xxA_reset(void)
    {
    	TRF79xxA_sendDirectCommand(TRF79XXA_SOFT_INIT_CMD);
    	TRF79xxA_sendDirectCommand(TRF79XXA_IDLE_CMD);
    
    	MCU_delayMillisecond(1);
    
    	TRF79xxA_resetFIFO();			// Reset the FIFO
    
    	TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x01); 		// ASK 100%, no SYS_CLK output
    
    	TRF79xxA_writeRegister(TRF79XXA_REGULATOR_CONTROL, 0x01);
    
    #if (TRF79xxA_VERSION == 70)
    	TRF79xxA_writeRegister(TRF79XXA_NFC_TARGET_LEVEL, 0x00); 		// For TRF7970A Errata
    #endif
    
    #if (TRF79xxA_VERSION == 70)
    	// msf - 9-20-19 - don't allow anything but control value 0x00
    	//g_eTrfGeneralSettings.ui8IsoControl = 0x21;
    	g_eTrfGeneralSettings.ui8IsoControl = 0x00;
    #elif (TRF79xxA_VERSION == 60)
    	g_eTrfGeneralSettings.ui8IsoControl = 0x02;
    #endif
    	g_eTrfGeneralSettings.bRfFieldOn = false;
    	g_ui8FifoOffset = 0;
    	g_ui8FifoRxLength = 0;
    }
    
    //===============================================================
    //
    //! TRF79xxA_resetIrqStatus - Resets the IRQ Status Register of
    //! the TRF79xxA
    //!
    //! This function resets/clears the TRF79xxA IRQ Status Register
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_resetIrqStatus(void)
    {
    	uint8_t puiIrqStatus[2];
    
    	puiIrqStatus[0] = TRF79XXA_IRQ_STATUS;
    	puiIrqStatus[1] = TRF79XXA_IRQ_MASK;
    
    	TRF79xxA_readContinuous(puiIrqStatus, 2);		// read second reg. as dummy read
    }
    
    //===============================================================
    //
    //! TRF79xxA_turnRfOff - Turn off the transmission of the TRF79xxA
    //! RF Field
    //!
    //! This function stops the TRF79xxA transmitting an RF field
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_turnRfOff(void)
    {
    	uint8_t	ui8Value;
    
    	ui8Value = g_eTrfGeneralSettings.eTrfPowerSetting;
    
    	TRF79xxA_writeRegister(TRF79XXA_CHIP_STATUS_CONTROL,ui8Value);
    
    	g_eTrfGeneralSettings.bRfFieldOn = false;	// Update RF Field variable
    }
    
    //===============================================================
    //
    //! TRF79xxA_turnRfOn - Turns on the transmission of the TRF79xxA
    //! RF Field
    //!
    //! This function enables the TRF79xxA transmit an RF field
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_turnRfOn(void)
    {
    	uint8_t	ui8Value;
    
    	ui8Value = g_eTrfGeneralSettings.eTrfPowerSetting | 0x20;	// Turn RF field On
    
    	TRF79xxA_writeRegister(TRF79XXA_CHIP_STATUS_CONTROL,ui8Value);
    
    	g_eTrfGeneralSettings.bRfFieldOn = true;	// Update RF Field variable
    }
    
    //===============================================================
    //
    //! TRF79xxA_writeContinuous - Write to consecutive TRF79xxA
    //! 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)
    //!
    //! This function writes data to a specific number of TRF79xxA
    //! registers from a specific address.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_writeContinuous(uint8_t * pui8Payload, uint8_t ui8Length)
    {
    	if (ui8Length > 1) // Cannot specify a length of 1
    	{
    		if (*pui8Payload == TRF79XXA_CHIP_STATUS_CONTROL)	// If the write starts at the Chip Status Control Register
    		{
    			if (((*pui8Payload+1) & BIT5) == BIT5)	// Check for RF field bit and update variable
    			{
    				g_eTrfGeneralSettings.bRfFieldOn = true;
    			}
    			else
    			{
    				g_eTrfGeneralSettings.bRfFieldOn = false;
    			}
    			if (ui8Length > 2)		// Check if the write length includes the ISO Control Register being written to (0x01)
    			{
    				g_eTrfGeneralSettings.ui8IsoControl = (*pui8Payload+2);	// If so, update the Iso Control Register variable
    			}
    		}
    		else if (*pui8Payload == TRF79XXA_ISO_CONTROL)	// If the write starts at the ISO Control Register
    		{
    			g_eTrfGeneralSettings.ui8IsoControl = *pui8Payload+1;	// Update the ISO Control Register variable
    		}
    
    		// Call continuous write function
    		SPI_writeCont(pui8Payload, ui8Length);
    	}
    	else
    	{
    		// Error, cannot specify a length of 1
    		return;
    	}
    }
    
    //===============================================================
    //
    //! TRF79xxA_writeRegister - Write single to a TRF79xxA Register
    //!
    //! \param ui8TrfRegister is the register address for the write
    //! \param ui8Value is the value to write to the specified
    //! register
    //!
    //! This function writes a new value into a single TRF79xxA
    //! register.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_writeRegister(uint8_t ui8TrfRegister, uint8_t ui8Value)
    {
    	uint8_t pui8Write[2];
    
    	if (ui8TrfRegister == TRF79XXA_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_eTrfGeneralSettings.ui8IsoControl = ui8Value;	// Update the ISO Control Register variable
    	}
    
    	if (ui8TrfRegister == TRF79XXA_CHIP_STATUS_CONTROL)
    	{
    		if ((ui8Value & BIT5) == BIT5)	// Check for RF field bit and update variable
    		{
    			g_eTrfGeneralSettings.bRfFieldOn = true;
    		}
    		else
    		{
    			g_eTrfGeneralSettings.bRfFieldOn = false;
    		}
    	}
    
    	pui8Write[0] = ui8TrfRegister;
    	pui8Write[1] = ui8Value;
    	SPI_writeSingle(pui8Write);
    }
    
    //===============================================================
    //
    //! TRF79xxA_setupInitiator - Write the initial settings for
    //! a set of TRF79xxA registers based on which protocol is to be
    //! enabled.
    //!
    //! \param ui8IsoControl is the value to write to the ISO Control
    //! register of the TRF79xxA
    //!
    //! This function is used to configure a series of TRF79xxA
    //! registers based on which RFID technology will be enabled in
    //! the ISO control register.
    //!
    //! This function will only enables one RFID technology at a time.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_setupInitiator(uint8_t ui8IsoControl)
    {
    	TRF79xxA_reset();			// Reset the TRF7970A to ensure a clean state of operation before changing modes
    
    	TRF79xxA_turnRfOn();		// Turn on the RF field
    
    	g_eTrfGeneralSettings.ui8IsoControl = ui8IsoControl;	// Update the ISO Control Register variable
    
    	// Register 0x01 - ISO Control Register
    	TRF79xxA_writeRegister(TRF79XXA_ISO_CONTROL,ui8IsoControl);
    
    	switch (ui8IsoControl)
    	{
    	case 0x08: 				// ISO14443A + RX CRC
    	case 0x88: 				// ISO14443A + no RX CRC
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x01); 		// Sys Clock Output = 13.56MHz, OOK = 100%
    
    #if (TRF79xxA_VERSION == 60)	// Some 60A registers aren't initialized properly on ISO Control Writes (SLOA155, Section 7.8)
    		// Register 0x07 - No Response Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 0x0E);
    
    		// Register 0x08 - RX Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_WAIT_TIME, 0x07);
    #endif
    		break;
    	case 0x0C: 				// ISO14443B
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x00); 		// Sys Clock Output = 13.56MHz, ASK 10%
    
    #if (TRF79xxA_VERSION == 60)	// Some 60A registers aren't initialized properly on ISO Control Writes (SLOA155, Section 7.8)
    		// Register 0x07 - No Response Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 0x0E);
    
    		// Register 0x08 - RX Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_WAIT_TIME, 0x07);
    #endif
    		break;
    	case 0x02:				// ISO15693 26.48 kbps, one subcarrier, 1 out of 4
    	case 0x03:              // ISO15693 26.48 kbps, one subcarrier, 1 out of 256
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x01); 		// Sys Clock Output = 13.56MHz, OOK = 100%
    	    // msf - test modulation change
    		//TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x00);       // Sys Clock Output = 13.56MHz, ASK 10%
    
    		// Resgister 0x07 - No Response Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 0x15);
    
    #if (TRF79xxA_VERSION == 60)	// Some 60A registers aren't initialized properly on ISO Control Writes (SLOA155, Section 7.8)
    		// Register 0x08 - RX Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_WAIT_TIME, 0x1F);
    #endif
    		break;
    		// msf - 8/19/19 - Support low data rate modes
    	case 0x00:				// ISO15693 long (6.62 kbps)
    	case 0x01:
    	case 0x04:              // (6.67 kbps)
    	case 0x05:
    		// Register 0x09 - System Clock Output, Modulation Scheme
    	    // OOK is the default
    		TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x01); 		// Sys Clock Output = 13.56MHz, OOK = 100%
    		//TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x00); 		// Sys Clock Output = 13.56MHz, ASK 10%
    
    		// Resgister 0x07 - No Response Wait Time
    		//TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 0x15);	// 31 * 37.76us = 1.171ms
    		TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 48);	// 48 * 37.76us = 1.812ms
    		break;
    
    	case 0x1A: 				// FeliCa 212kbps
    	case 0x1B: 				// FeliCa 424kbps
    		// Register 0x09 - System Clock Output, Modulation Scheme
    		TRF79xxA_writeRegister(TRF79XXA_MODULATOR_CONTROL, 0x00); 		// Sys Clock Output = 13.56MHz, ASK 10%
    
    #if (TRF79xxA_VERSION == 60)	// Some 60A registers aren't initialized properly on ISO Control Writes (SLOA155, Section 7.8)
    		// Register 0x07 - No Response Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_NO_RESPONSE_WAIT_TIME, 0x0E);
    
    		// Register 0x08 - RX Wait Time
    		TRF79xxA_writeRegister(TRF79XXA_RX_WAIT_TIME, 0x01);
    #endif
    		break;
    	default:
    		break;
    	}
    
    #if (TRF79xxA_VERSION == 70)
    	// Register 0x14 - Adjustable FIFO Level
    	TRF79xxA_writeRegister(TRF79XXA_FIFO_IRQ_LEVELS, 0x0C);
    
    	// Register 0x18 - NFC Target Detection Level
    	// This register must be written to 0x00 per TRF7970A Errata
    	TRF79xxA_writeRegister(TRF79XXA_NFC_TARGET_LEVEL, 0x00);
    #endif
    }
    
    //===============================================================
    //
    //! TRF79xxA_waitTxIRQ - Timeout sequence for just TX
    //!
    //! \param ui8TxTimeout is the TX timeout in milliseconds
    //!
    //! This function ensures data has been transmitted correctly
    //! only.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_waitTxIRQ(uint8_t ui8TxTimeout)
    {
    	g_sTrfStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while((g_sTrfStatus != TX_COMPLETE) && (g_sTrfStatus != TX_ERROR))
    	{										// Wait for end of TX
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		MCU_setCounter(ui8TxTimeout);
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		RESET_COUNTER;
    		if (g_sTrfStatus != TX_COMPLETE)
    		{
    			if (g_sTrfStatus == TX_WAIT)	// Wait longer since we received an 0xA0
    			{
    				TRF79xxA_waitTxIRQ(ui8TxTimeout);	// Wait longer for transmission to complete
    			}
    			else	// Failed to send packet properly - Exit TX Timeout
    			{
    				g_sTrfStatus = TX_ERROR;	// Set status to error
    			}
    		}
    	}
    }
    
    
    //===============================================================
    //
    //! TRF79xxA_waitRxIRQ - Timeout sequence for just RX
    //!
    //! \param ui8RxTimeout is the RX timeout in milliseconds
    //!
    //! This function determines if any data has been received prior
    //! to the RX timeout only.
    //!
    //! When the RX timeout occurs before data is received, then mark
    //! the TRF79xxA status as a No Response Received status.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_waitRxIRQ(uint8_t ui8RxTimeout)
    {
    	g_ui8FifoOffset = 0; // Reset the FIFO Offset prior to receiving data
    
    	g_sTrfStatus = RX_WAIT;
    	g_ui8TimeoutFlag = 0x00;
    	while(g_sTrfStatus == RX_WAIT)		// Wait for end of RX or timeout
    	{
    		// Clear the IRQ Flag
    		g_ui8IrqFlag = 0x00;
    		// Setup for the Timer
    		MCU_setCounter(ui8RxTimeout);
    		while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    		{
    			// Do Nothing
    		}
    		while (g_sTrfStatus == RX_WAIT_EXTENSION)
    		{
    			g_ui8IrqFlag = 0x00;
    #if (TRF79xxA_VERSION == 70)
    			if ((g_eTrfGeneralSettings.ui8IsoControl & 0x1F) > 0x07)
    			{
    				MCU_setCounter(7);
    			}
    			else
    			{
    				MCU_setCounter(50);
    			}
    #endif
    #if (TRF79xxA_VERSION == 60)
    			MCU_setCounter(5);
    #endif
    			while((g_ui8IrqFlag == 0x00) && (g_ui8TimeoutFlag == 0x00))	// Wait for an interrupt
    			{
    				// Do Nothing
    			}
    #if (TRF79xxA_VERSION == 60)
    			if (g_sTrfStatus == NO_RESPONSE_RECEIVED)
    			{
    				g_sTrfStatus = RX_COMPLETE;
    			}
    #endif
    		}
    		RESET_COUNTER;
    		if (g_sTrfStatus == RX_WAIT)
    		{
    			// Exit the while loop
    			g_sTrfStatus = NO_RESPONSE_RECEIVED;
    		}
    	}
    }
    
    
    //===============================================================
    //
    //! TRF79xxA_waitRxData -
    //!
    //! \return g_sTrfStatus returns the current TRF79xxA drive
    //! status
    //
    //===============================================================
    
    tTrfStatus TRF79xxA_waitRxData(uint8_t ui8TxTimeout, uint8_t ui8RxTimeout)
    {
    	switch (g_sTrfStatus)
    	{
    	case TRF_IDLE:
    	case TX_WAIT:
    		TRF79xxA_waitTxIRQ(ui8TxTimeout);		// TX timeout
    		TRF79xxA_waitRxIRQ(ui8RxTimeout);		// RX timeout
    		break;
    	case TX_COMPLETE:
    		TRF79xxA_waitRxIRQ(ui8RxTimeout);		// RX timeout
    		break;
    	case NO_RESPONSE_RECEIVED_15693:
    		// Do Nothing
    		break;
    	case COLLISION_ERROR:
    		if ((g_eTrfGeneralSettings.ui8IsoControl == 0x02) || (g_eTrfGeneralSettings.ui8IsoControl == 0x08) || (g_eTrfGeneralSettings.ui8IsoControl == 0x88))
    		{
    			// Do Nothing
    		}
    		else
    		{
    			return g_sTrfStatus;
    		}
    		break;
    	case RX_COMPLETE:
    	case RX_WAIT:
    	case RX_WAIT_EXTENSION:
    		// Do Nothing
    		break;
    	default:
    		g_sTrfStatus = TX_ERROR;
    		break;
    	}
    
    	return g_sTrfStatus;
    }
    
    //===============================================================
    //
    //! TRF79xxA_getTrfStatus - Returns current TRF79xxA driver
    //! status
    //!
    //! \return g_sTrfStatus returns the current TRF79xxA drive
    //! status
    //
    //===============================================================
    
    tTrfStatus TRF79xxA_getTrfStatus(void)
    {
    	return g_sTrfStatus;
    }
    
    //===============================================================
    //
    //! TRF79xxA_setTrfStatus - Set the TRF79xxA driver status
    //!
    //! \param sTrfStatus is the new TRF79xxA driver status
    //!
    //! This function sets the TRF79xxA driver status manually.
    //! This can be used to modify the TRF driver status without an
    //! IRQ event. Use with caution.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_setTrfStatus(tTrfStatus sTrfStatus)
    {
    	g_sTrfStatus = sTrfStatus;
    }
    
    //===============================================================
    //
    //! TRF79xxA_setTrfPowerSetting - Set the TRF79xxA power setting
    //!
    //! \param sTrfPowerSetting is the new TRF79xxA Power Setting
    //!
    //! This function allows for configuration of the TRF79xxA power
    //! setting.
    //!
    //! Options are:
    //!  - TRF79xxA_3V_FULL_POWER: 3V TRF79xxA input w/ full power RF output
    //!  - TRF79xxA_5V_FULL_POWER: 5V TRF79xxA input w/ full power RF output
    //!  - TRF79xxA_3V_HALF_POWER: 3V TRF79xxA input w/ half power RF output
    //!  - TRF79xxA_5V_HALF_POWER: 5V TRF79xxA input w/ half power RF output
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_setTrfPowerSetting(tTrfPowerOptions sTrfPowerSetting)
    {
    	g_eTrfGeneralSettings.eTrfPowerSetting = sTrfPowerSetting;
    }
    
    //===============================================================
    //
    //! TRF79xxA_getCollisionPosition - Return the current Collision
    //! Position value
    //!
    //! This function will return the current Collision Position
    //! value.
    //! This is only used for the ISO14443 Type A anti-collision
    //! process.
    //!
    //! \return g_ui8CollisionPosition returns the current Collision
    //! Position value
    //
    //===============================================================
    
    uint8_t TRF79xxA_getCollisionPosition(void)
    {
    	return g_ui8CollisionPosition;
    }
    
    //===============================================================
    //
    //! TRF79xxA_setCollisionPosition - Set the Collision Position
    //! variable
    //!
    //! \param ui8ColPos is the new Collision Position value
    //!
    //! This function sets the Collision Position variable.
    //! This is only used for the ISO14443 Type A anti-collision
    //! process.
    //!
    //! \return None.
    //
    //===============================================================
    
    void TRF79xxA_setCollisionPosition(uint8_t ui8ColPos)
    {
    	g_ui8CollisionPosition = ui8ColPos;
    }
    
    //===============================================================
    //
    //! TRF79xxA_getRxBytesReceived - Returns the Number of RX Bytes
    //! received by the TRF79xxA FIFO
    //!
    //! This function returns the number of bytes received by the
    //! TRF79xxA during the last packet reception.
    //!
    //! This is used to check for how much data has been received
    //! and to ensure packets with expected lengths were fully
    //! received.
    //!
    //! \return g_ui8FifoRxLength returns the current FIFO RX Length
    //
    //===============================================================
    
    uint8_t TRF79xxA_getRxBytesReceived(void)
    {
    	return g_ui8FifoRxLength;
    }
    
    //===============================================================
    //
    //! TRF79xxA_getTrfBuffer - Returns a point to the start of the
    //! TRF Buffer.
    //!
    //! This function will return a pointer for the start address of
    //! the TRF79xxA Data Buffer.
    //!
    //! This is used to access the data received from successful RF
    //! commands in files which do not have naturally have access to
    //! the g_pui8TrfBuffer.
    //!
    //! \return &g_pui8TrfBuffer[0] returns the start address of
    //! g_pui8TrfBuffer.
    //
    //===============================================================
    
    uint8_t * TRF79xxA_getTrfBuffer(void)
    {
    	return &g_pui8TrfBuffer[0];
    }
    
    //===============================================================
    //
    //! TRF79xxA_getIsoControlValue - Fetch the latest Iso Control
    //! Register value
    //!
    //! This function returns the current TRF79xxA ISO Control
    //! Register setting .
    //!
    //! 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
    //
    //===============================================================
    
    uint8_t TRF79xxA_getIsoControlValue(void)
    {
    	return g_eTrfGeneralSettings.ui8IsoControl;
    }
    
    //===============================================================
    //
    //! TRF79xxA_checkExternalRfField - Checks if an external RF field
    //! is present.
    //!
    //! This function performs RF collision avoidance as outlined in
    //! TI application notes (sloa192, sloa227) in order to determine
    //! if an external RF field is present.
    //!
    //! \return bExtFieldOn retuns the external RF field status
    //
    //===============================================================
    
    bool TRF79xxA_checkExternalRfField(void)
    {
    	bool bExtFieldOn;
    	uint8_t ui8Value;
    
    	TRF79xxA_writeRegister(TRF79XXA_CHIP_STATUS_CONTROL, 0x02);
    	TRF79xxA_sendDirectCommand(TRF79XXA_TEST_EXTERNAL_RF_CMD);
    	__delay_cycles(400); 		//	Delay for 50uS
    	ui8Value = TRF79xxA_readRegister(TRF79XXA_RSSI_LEVELS);
    
    	if ((ui8Value & 0x07) > 1)	// Check for RF field bit and update variable
    	{
    		bExtFieldOn = true;
    	}
    	else
    	{
    		bExtFieldOn = false;
    	}
    
    	return bExtFieldOn;
    }
    
    //===============================================================
    //
    //! TRF79xxA_timerHandler - Handler for assigned MCU Timer
    //! Interrupt of TX/RX Timeout functions.
    //!
    //! This function processes the Timer Interrupt for the TX/RX
    //! timeout functions. If a timeout occurs, the IRQ Status
    //! register is read out to determine the current TRF79xxA state.
    //!
    //! \return None.
    //
    //===============================================================
    
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void
    TRF79xxA_timerHandler(void)
    {
    	uint8_t ui8IrqStatus;
    
    	STOP_COUNTER;
    
    	g_ui8TimeoutFlag = 0x01;
    
    	ui8IrqStatus = TRF79xxA_readIrqStatus();
    
    	if(ui8IrqStatus == TRF79XXA_IRQ_STATUS_TX_COMPLETE)
    	{
    		g_sTrfStatus = TX_COMPLETE;
    	}
    	else if(ui8IrqStatus == TRF79XXA_IRQ_STATUS_IDLE)
    	{
    		g_sTrfStatus = NO_RESPONSE_RECEIVED;
    	}
    	else
    	{
    		g_sTrfStatus = RX_WAIT;
    	}
    }
    
    //===============================================================
    //
    //! TRF79xxA_irqHandler- Interrupt handler for IRQ interrupts
    //!
    //! Handles receiving IRQ's, getting IRQ status, and maintaining
    //! timers/global variables
    //!
    //! \return None.
    //
    //===============================================================
    
    #pragma vector = PORT2_VECTOR
    __interrupt void
    TRF79xxA_irqHandler(void)							// interrupt handler
    {
    	uint8_t ui8IrqStatus;
    
    	STOP_COUNTER;							// stop timer mode
    
    	g_ui8IrqFlag = 0x01;
    
    	do
    	{
    		IRQ_CLR;							// PORT2 interrupt flag clear
    
    		// IRQ status register has to be read
    		ui8IrqStatus = TRF79xxA_readIrqStatus();
    
    		if(ui8IrqStatus == 0xA0)				// TX active and only 3 bytes left in FIFO
    		{
    			g_sTrfStatus = TX_WAIT;
    			break;
    		}
    		else
    		{
    			TRF79xxA_processIRQ(&ui8IrqStatus);
    
    
    		}
    	} while((IRQ_PORT & IRQ_PIN) == IRQ_PIN);
    	__bic_SR_register_on_exit(LPM0_bits);
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    
    4863.iso15693.c
    /*
     * File Name: iso15693.c
     *
     * Description: ISO15693 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 "iso15693.h"
    
    
    //*****************************************************************************
    //
    //! \addtogroup iso15693_api ISO15693 Read/Write API's
    //! @{
    //!
    //! A ISO15693 Reader/Writer issues commands based on the ISO15693 specifications.
    //! The ISO15693 specification is for Vicinity Integrated Circuit Cards (VICCs)
    //! and communication with VICCs that are Type V tags occur at bitrates of
    //! 6.62 kbps (low data rate) or 26.48 kbps (high data rate).
    //!
    //! For more information on ISO15693 Readers and Tags please read the ISO15693
    //! Specifications.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //		Global Variables
    //*****************************************************************************
    
    extern uint8_t g_pui8TrfBuffer[NFC_FIFO_SIZE];
    static volatile tTrfStatus g_sTrfStatus;
    
    static uint8_t g_pui8Iso15693UId[8];
    static uint8_t g_pui8AnticollisionMaskBuffer[8];
    static uint8_t g_ui8TagDetectedCount;
    static uint8_t g_ui8RecursionCount;
    
    //*****************************************************************************
    //
    //! ISO15693_sendSingleSlotInventory - Issue a single slot Inventory command
    //! for ISO15693 tags.
    //!
    //! This function issues a single slot Inventory command for tag detection
    //! of ISO15693 tags. If a tag is found, the UID is stored in the
    //! g_pui8Iso15693UId buffer.
    //!
    //! If UART is enabled, the tag ID is sent out to a host via UART.
    //!
    //! \return ui8Status returns either STATUS_SUCCESS or STATUS_FAIL to indicate
    //! if the Inventory command resulted in a successful tag detection or not.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_sendSingleSlotInventory(void)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8LoopCount = 0;
    	uint8_t ui8Status = STATUS_FAIL;
    
    	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++] = 0x30;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_pui8TrfBuffer[ui8Offset++] = 0x26;		// ISO15693 flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x01;		// Inventory command code
    	g_pui8TrfBuffer[ui8Offset++] = 0x00;		// Mask Length = 0 (Also not sending AFI)
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the ISO15693 Inventory Command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(5,15);			// 5 millisecond TX timeout, 15 millisecond RX timeout
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    			ui8Status = STATUS_SUCCESS;
    
    			// UID Starts at the 3rd received bit (1st is flags and 2nd is DSFID)
    			for (ui8LoopCount = 2; ui8LoopCount < 10; ui8LoopCount++)
    			{
    				g_pui8Iso15693UId[ui8LoopCount-2] = g_pui8TrfBuffer[ui8LoopCount];	// Store UID into a Buffer
    			}
    
    			g_ui8TagDetectedCount = 1;
    #ifdef ENABLE_HOST
    			// Print out UID to UART Host
    			UART_putNewLine();
    			UART_sendCString("ISO15693 UID: ");
    			UART_putChar('[');
    			for (ui8LoopCount = 0; ui8LoopCount < 8; ui8LoopCount++)
    			{
    				UART_putByte(g_pui8Iso15693UId[7-ui8LoopCount]);		// Send UID to host
    			}
    			UART_putChar(']');
    			UART_putNewLine();
    #endif
    		}
    	}
    	else
    	{
    		ui8Status = STATUS_FAIL;
    	}
    
    #ifdef ENABLE_STANDALONE
    	if (ui8Status == STATUS_SUCCESS)
    	{
    		LED_15693_ON;		// LEDs indicate detected ISO15693 tag
    	}
    	else
    	{
    		LED_15693_OFF;
    	}
    #endif
    
    	return ui8Status;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_runAnticollision - Issue an Inventory command for either
    //! 1 or 16 slot anticollision of ISO15693 tags.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //! \param ui8MaskLength is the number of significant bits in the mask value.
    //! \param ui8Afi is the AFI to be issued with command (if AFI flag is
    //! included in ui8ReqFlag).
    //!
    //! Function issues a sixteen slot Inventory command for the detection of
    //! ISO15693 tags. If a tag is found, the UID is stored in the g_ui8Iso15693UId
    //! buffer. The process will run until all ISO15693 detected have responded
    //! with their UID's.
    //!
    //! The function uses a recursive call for the anticollision process. In order
    //! to avoid stack overflows, a recursion counter is used to limit the maximum
    //! number of recursions.
    //!
    //! The number of UID's which can be stored is set by g_ui8MaximumTagCount
    //! and the declaration of the g_ui8Iso15693UId buffer. Once the buffer for
    //! UID's is filled then no other UID's responses will be stored.
    //!
    //! If UART is enabled, the UID of each ISO15693 tag detected is sent out to a
    //! host via UART.
    //!
    //! \return ui8Status returns STATUS_SUCCESS if the anticollision function
    //! resulted in a successful tag detection. Otherwise, returns STATUS_FAIL.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_runAnticollision(uint8_t ui8ReqFlags, uint8_t ui8MaskLength, uint8_t ui8Afi)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8LoopCount1;
    	uint8_t ui8LoopCount2;
    	uint16_t ui16TransmitByteLength;
    	uint16_t ui16SlotNumber = 0x0000;
    	uint8_t ui8MaskValue;
    	uint8_t ui8MaskByteCount;
    	uint8_t ui8Status = STATUS_FAIL;
    
    	ui8ReqFlags &= ~BIT5;				// Clear Bit 5 to ensure 16 slot inventory is used.
    
    	ui8MaskByteCount = (((ui8MaskLength >> 2) + 1) >> 1);	// Set ui8MaskByteCount based on the inputted Mask Length
    															// ui8MaskByteCount will be 1 for length = 4 or 8,
    															// ui8MaskByteCount will be 2 for length = 12 or 16,
    															// and so on
    
    	// Calculate how long the output byte will be
    	if (ui8ReqFlags & 0x10) 							// Check if AFI will be included or not
    	{
    		ui16TransmitByteLength = ui8MaskByteCount + 4;	// Set packet size = Mask Value + Mask Length + AFI Byte + ISO15693 Command Code + ISO15693 Request Flags
    	}
    	else
    	{
    		ui16TransmitByteLength = ui8MaskByteCount + 3;	// Set packet size = Mask Value + Mask Length + ISO15693 Command Code + ISO15693 Request Flags
    	}
    
    	// Format Anti-collision command packet
    	g_pui8TrfBuffer[ui8Offset++] = 0x8F;					// Reset FIFO
    	g_pui8TrfBuffer[ui8Offset++] = 0x91;					// Send with CRC
    	g_pui8TrfBuffer[ui8Offset++] = 0x3D;					// Write Continuous
    	g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength >> 8);		// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength << 4);		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlags;			// ISO15693 Request Flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x01;					// Inventory Request Command Code
    
    	if (ui8ReqFlags & 0x10)								// Check if AFI will be included or not
    	{
    		g_pui8TrfBuffer[ui8Offset++] = ui8Afi;			// Optional AFI Byte
    		g_pui8TrfBuffer[ui8Offset++] = ui8MaskLength;	// Mask Length
    		if (ui8MaskLength > 0)
    		{
    			for (ui8LoopCount1 = 0; ui8LoopCount1 < ui8MaskByteCount; ui8LoopCount1++)
    			{
    				g_pui8TrfBuffer[ui8Offset++] = g_pui8AnticollisionMaskBuffer[(ui8MaskByteCount-ui8LoopCount1)];		// Fill in inputted Mask Values
    			}
    		}
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = ui8MaskLength;	// Mask Length
    		if (ui8MaskLength > 0)
    		{
    			for (ui8LoopCount1 = 0; ui8LoopCount1 < ui8MaskByteCount; ui8LoopCount1++)
    			{
    				g_pui8TrfBuffer[ui8Offset++] = g_pui8AnticollisionMaskBuffer[((ui8MaskByteCount-1)-ui8LoopCount1)];		// Fill in inputted Mask Values
    			}
    		}
    	}
    
    	TRF79xxA_enableSlotCounter();
    
    	TRF79xxA_resetIrqStatus();
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the ISO15693 Inventory Command
    
    	g_sTrfStatus = TRF79xxA_getTrfStatus();
    
    	if (g_sTrfStatus == TRF_IDLE || g_sTrfStatus == TX_WAIT)
    	{
    		TRF79xxA_waitTxIRQ(5);				// 5 millisecond TX timeout
    	}
    
    	for (ui8LoopCount2 = 1; ui8LoopCount2 <= 16; ui8LoopCount2++)
    	{
    		TRF79xxA_waitRxIRQ(15);		// 15 millisecond RX timeout
    
    		g_sTrfStatus = TRF79xxA_getTrfStatus();	// Get the TRF797x Status
    
    		switch (g_sTrfStatus)
    		{
    		case RX_COMPLETE:						// If data has been received, then UID is in the buffer
    			if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    			{
    				ui8Status = STATUS_SUCCESS;
    
    				// UID Starts at the 3rd received bit (1st is flags and 2nd is DSFID)
    				for (ui8LoopCount1 = 2; ui8LoopCount1 < 10; ui8LoopCount1++)
    				{
    					g_pui8Iso15693UId[ui8LoopCount1-2] = g_pui8TrfBuffer[ui8LoopCount1];	// Store UID to a Buffer
    				}
    
    				g_ui8TagDetectedCount++;
    #ifdef ENABLE_HOST
    				// Print out UID to UART Host
    				UART_putNewLine();
    				UART_sendCString("ISO15693 UID: ");
    				UART_putChar('[');
    				for (ui8LoopCount1 = 0; ui8LoopCount1 < 8; ui8LoopCount1++)
    				{
    					UART_putByte(g_pui8Iso15693UId[7-ui8LoopCount1]);		// Send UID to host
    				}
    				UART_putChar(']');
    				UART_putNewLine();
    #endif
    			}
    			break;
    
    		case COLLISION_ERROR:		// A collision has occurred for this slot
    			ui16SlotNumber |= (0x01 << (ui8LoopCount2-1));	// Mark a collision occurred in the correct Slot Number bit.
    			MCU_delayMillisecond(5);	// Allow time for tag to finish responding before issuing EOF
    			break;
    
    		case NO_RESPONSE_RECEIVED:	// No Response was received, break out of function as there is no tag for this slot
    			break;
    
    		case NO_RESPONSE_RECEIVED_15693:	// No Response was received, break out of function as there is no tag for this slot
    			break;
    
    		case PROTOCOL_ERROR:
    			// Protocol Error occurred, exit out of anticollision
    #ifdef ENABLE_HOST
    			UART_sendCString("ISO15693 Anticollision Error");
    			UART_putNewLine();
    #endif
    			// msf - 8/19/19 - try different configurations
    			//TRF79xxA_setupInitiator(0x02);	//ISO/IEC 15693 high bit rate, 26.48 kbps, one subcarrier, 1 out of 4
    			//TRF79xxA_setupInitiator(0x03);  //ISO/IEC 15693 high bit rate, 26.48 kbps, one subcarrier, 1 out of 256
    			TRF79xxA_setupInitiator(0x00);	//ISO/IEC 15693 low bit rate, 6.62 kbps, one subcarrier, 1 out of 4
    			//TRF79xxA_setupInitiator(0x01);  //ISO/IEC 15693 low bit rate, 6.62 kbps, one subcarrier, 1 out of 256
    			return ui8Status = STATUS_FAIL;
    
    		default:
    			break;
    		}
    
    		TRF79xxA_resetFIFO();				// FIFO has to be reset before receiving the next response
    
    		if (ui8LoopCount2 < 16)		// If 16 slots used, and the last slot as not been reached, then send EOF (i.e. next slot indicator)
    		{
    			TRF79xxA_sendDirectCommand(TRF79XXA_STOP_DECODERS_CMD);
    			TRF79xxA_sendDirectCommand(TRF79XXA_RUN_DECODERS_CMD);
    			TRF79xxA_sendDirectCommand(TRF79XXA_TRANSMIT_NEXT_SLOT_CMD);
    		}
    		else if (ui8LoopCount2 == 16)	// Once at the end of slot 16, then stop the slot counter
    		{
    			TRF79xxA_sendDirectCommand(TRF79XXA_STOP_DECODERS_CMD);
    			TRF79xxA_disableSlotCounter();
    		}
    	}
    
    	TRF79xxA_disableSlotCounter();
    
    	ui8MaskLength = ui8MaskLength + 4; 						// The mask length is a multiple of 4 bits
    
    	ui8MaskByteCount = (((ui8MaskLength >> 2) + 1) >> 1);	// Set ui8MaskByteCount based on the inputted Mask Length
    															// ui8MaskByteCount is 1 for length = 4 or 8,
    															// ui8MaskByteCount is 2 for length = 12 or 16,
    															// and so on
    
    	// If the slot number pointer is not 0, the slot count is 16 (to indicate anticollision is needed),
    	// the mask length doesn't exceed 60 bits, and the slot number is not 16 then proceed to recursive function call
    	while ((ui16SlotNumber != 0x00)
    			&& (ui8MaskLength < 61))
    	{
    		ui8MaskValue = 0x00;
    		ui8LoopCount1 = 0;
    
    		while (ui8LoopCount1 < 16)
    		{
    			if ((ui16SlotNumber & (0x01 << ui8LoopCount1)) != 0x00)
    			{
    				ui8MaskValue = ui8LoopCount1;
    
    				ui16SlotNumber &= ~(0x01 << ui8LoopCount1); 				// Clear that slot bit from the array
    
    				break;
    			}
    			ui8LoopCount1++;
    		}
    
    		if ((ui8MaskLength & 0x04) == 0x00)
    		{
    			ui8MaskValue = ui8MaskValue << 4;								// Shift slot pointer if mask length doesn't have Bit 2 (0x04) set (since it is a multiple of 4 bits)
    		}
    		else
    		{																	// Otherwise re-copy the mask values
    			for (ui8LoopCount1 = 7; ui8LoopCount1 > 0; ui8LoopCount1--)
    			{
    				g_pui8AnticollisionMaskBuffer[ui8LoopCount1] = g_pui8AnticollisionMaskBuffer[ui8LoopCount1 - 1];
    			}
    			g_pui8AnticollisionMaskBuffer[0] &= 0x00;									// And set the mask value for the first byte in the array = 0
    		}
    
    		g_pui8AnticollisionMaskBuffer[0] |= ui8MaskValue;								// Now update the mask value of the first byte based on the slot number pointer
    
    		MCU_delayMillisecond(2);
    
    		if (g_ui8RecursionCount < ISO15693_MAX_RECURSION_COUNT)
    		{
    			g_ui8RecursionCount++;
    			ui8Status = ISO15693_runAnticollision(ui8ReqFlags, ui8MaskLength, ui8Afi); // Issue a recursive call with new Mask
    		}
    		else
    		{
    #ifdef ENABLE_HOST
    			UART_sendCString("Error: Max Anticollision Recursions");
    			UART_putNewLine();
    #endif
    			return ui8Status = STATUS_FAIL;
    		}
    
    		// Restore the Global AnticollisionMaskBuffer with the values from the current anticollision function.
    		if ((ui8MaskLength & 0x04) == 0x00)
    		{
    			// If mask length doesn't have Bit 2 (0x04) set (since it is a multiple of 4 bits) - clear the upper nibble which is where the new mask value was placed
    			g_pui8AnticollisionMaskBuffer[0] &= 0x0F;
    		}
    		else
    		{	// Otherwise re-shift the mask values
    			for (ui8LoopCount1 = 0; ui8LoopCount1 < 7; ui8LoopCount1++)
    			{
    				g_pui8AnticollisionMaskBuffer[ui8LoopCount1] = g_pui8AnticollisionMaskBuffer[ui8LoopCount1 + 1];
    			}
    			g_pui8AnticollisionMaskBuffer[7] = 0x00;									// And set the mask value for the first byte in the array = 0
    		}
    	}
    
    #ifdef ENABLE_STANDALONE
    	if (ui8Status == STATUS_SUCCESS)
    	{
    		LED_15693_ON;		// LEDs indicate detected ISO15693 tag
    	}
    	else
    	{
    		LED_15693_OFF;
    	}
    #endif
    
    	// Clear any IRQs
    	TRF79xxA_resetIrqStatus();
    
    	// Reduce the recursion count as stack space will be freed on function exit
    	if (g_ui8RecursionCount > 0)
    	{
    		g_ui8RecursionCount--;
    	}
    
    	return ui8Status;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_sendGetSystemInfo - Issue the Get System Information command
    //! for ISO15693 tags.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //!
    //! This function issues a Get System Information command for ISO15693 tags.
    //! This can be used to determine how many blocks of data can be read from
    //! the tag.
    //!
    //! If UART is enabled, the contents of the Get System Information response
    //! is output via UART.
    //!
    //! \return ui16NumberOfBlocks returns the number of blocks contained
    //! in the ISO15693 tag.
    //
    //*****************************************************************************
    
    uint16_t ISO15693_sendGetSystemInfo(uint8_t ui8ReqFlag)
    {
    	uint8_t ui8Offset = 0;
    	uint16_t ui16NumberOfBlocks = 0x00;
    #ifdef ENABLE_HOST
    	uint8_t ui8LoopCount = 1;
    	uint8_t ui8RxLength = 0;
    #endif
    
    	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
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0xA0;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0x20;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag;	// ISO15693 flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x2B;			// Get System Information command code
    
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	}
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Get System Information command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(10,30);	// 10 millisecond TX timeout, 30 millisecond RX timeout
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    #ifdef ENABLE_HOST
    			// Output received data to UART
    			UART_sendCString("Get Sys Info Data: ");
    			UART_putChar('[');
    
    			ui8RxLength = TRF79xxA_getRxBytesReceived();
    
    			for (ui8LoopCount = 1; ui8LoopCount < ui8RxLength; ui8LoopCount++)
    			{
    				UART_putByte(g_pui8TrfBuffer[ui8LoopCount]);		// Send Get System Info data to host
    			}
    
    			UART_putChar(']');
    			UART_putNewLine();
    #endif
    			// Check to see that no error flags were sent and that there is a block number data available
    			if (g_pui8TrfBuffer[0] == 0x00 && ((g_pui8TrfBuffer[1] & 0x07) == 0x07))
    			{
    				ui16NumberOfBlocks = g_pui8TrfBuffer[12];
    			}
    			else if (g_pui8TrfBuffer[0] == 0x00 && (((g_pui8TrfBuffer[1] & 0x07) == 0x06) || ((g_pui8TrfBuffer[1] & 0x07) == 0x05)))
    			{
    				ui16NumberOfBlocks = g_pui8TrfBuffer[11];
    			}
    			else if (g_pui8TrfBuffer[0] == 0x00 && ((g_pui8TrfBuffer[1] & 0x07) == 0x04))
    			{
    				ui16NumberOfBlocks = g_pui8TrfBuffer[10];
    			}
    		}
    	}
    	else if ((g_sTrfStatus == NO_RESPONSE_RECEIVED) || (g_sTrfStatus == NO_RESPONSE_RECEIVED_15693))
    	{
    		// Case for TI HF-I Pro and Standard tags
    		ui16NumberOfBlocks = 0x0A;
    	}
    
    	return ui16NumberOfBlocks;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_sendGetSystemInfoExtended - Issue the Get System Information
    //! command for ISO15693 tags with the protocol extention flag set.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //!
    //! This function issues a Get System Information command for ISO15693 tags
    //! with the Protocol Extension bit set in the request flags. This can be
    //! used to determine how many blocks of data can be read from the tag.
    //!
    //! If UART is enabled, the contents of the Get System Information
    //! response is output via UART.
    //!
    //! \return ui16NumberOfBlocks returns the number of blocks contained in
    //! the ISO15693 tag.
    //
    //*****************************************************************************
    
    uint16_t ISO15693_sendGetSystemInfoExtended(uint8_t ui8ReqFlag)
    {
    	uint8_t ui8Offset = 0;
    	uint16_t ui16NumberOfBlocks = 0x00;
    #ifdef ENABLE_HOST
    	uint8_t ui8LoopCount = 1;
    	uint8_t ui8RxLength = 0;
    #endif
    
    	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
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0xA0;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0x20;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag | 0x08;		// ISO15693 flags + protocol extension bit
    	g_pui8TrfBuffer[ui8Offset++] = 0x2B;			// Get System Information command code
    
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	}
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Get System Information command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(10,30);	// 10 millisecond TX timeout, 30 millisecond RX timeout
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    #ifdef ENABLE_HOST
    			UART_sendCString("Get Sys Info Data: ");
    			UART_putChar('[');
    
    			ui8RxLength = TRF79xxA_getRxBytesReceived();
    
    			// Output received data to UART
    			for (ui8LoopCount = 1; ui8LoopCount < ui8RxLength; ui8LoopCount++)
    			{
    				UART_putByte(g_pui8TrfBuffer[ui8LoopCount]);		// Send Get System Info data to host
    			}
    
    			UART_putChar(']');
    			UART_putNewLine();
    #endif
    			// Check to see that no error flags were sent and that there is a block number data available
    			if (g_pui8TrfBuffer[0] == 0x00 && ((g_pui8TrfBuffer[1] & 0x07) == 0x07))
    			{
    				ui16NumberOfBlocks = ((g_pui8TrfBuffer[13] << 8) | (g_pui8TrfBuffer[12])) ;
    			}
    			else if (g_pui8TrfBuffer[0] == 0x00 && (((g_pui8TrfBuffer[1] & 0x07) == 0x06) || ((g_pui8TrfBuffer[1] & 0x07) == 0x05)))
    			{
    				ui16NumberOfBlocks = ((g_pui8TrfBuffer[12] << 8) | (g_pui8TrfBuffer[11])) ;
    			}
    			else if (g_pui8TrfBuffer[0] == 0x00 && ((g_pui8TrfBuffer[1] & 0x07) == 0x04))
    			{
    				ui16NumberOfBlocks = ((g_pui8TrfBuffer[11] << 8) | (g_pui8TrfBuffer[10])) ;
    			}
    		}
    	}
    
    	return ui16NumberOfBlocks;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_sendReadSingleBlock - Issue the Read Single Block command
    //! for ISO15693 tags.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //! \param ui8BlockNumber is the block number to read data from.
    //!
    //! This function issues a Read Single Block with the specified request flags
    //! and block number to read data from.
    //!
    //! If UART is enabled, the data read from the ISO15693 tag is output via UART.
    //!
    //! \return ui8Status returns either STATUS_SUCCESS or STATUS_FAIL
    //! to indicate if the Read Single Block was successful or not.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_sendReadSingleBlock(uint8_t ui8ReqFlag, uint8_t ui8BlockNumber)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    	uint8_t ui8LoopCount = 1;
    	uint8_t ui8RxLength = 0;
    #endif
    
    	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
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0xB0;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0x30;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag;	// ISO15693 flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x20;			// Read Single Block command code
    
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	}
    
    	g_pui8TrfBuffer[ui8Offset++] = ui8BlockNumber;		// Block # (variable, for HF-I Plus device can go to 0x3F, Pro and Standard handled with "error" response flags)
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Get System Information command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(5,15);		// 5 millisecond TX timeout, 15 millisecond RX timeout
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    #ifdef ENABLE_HOST
    			UART_sendCString("Block ");
    			UART_putByte(ui8BlockNumber);		// Output block number
    			UART_sendCString(" Data: ");
    			UART_putChar('[');
    
    			ui8RxLength = TRF79xxA_getRxBytesReceived();
    
    			if (ui8ReqFlag & BIT6) // Handle case for Option Flag causing one extra byte to be transmitted.
    			{
    				ui8Offset = 2;
    			}
    			else
    			{
    				ui8Offset = 1;
    			}
    
    			// Output received data to UART
    			for (ui8LoopCount = ui8Offset; ui8LoopCount < ui8RxLength; ui8LoopCount++)
    			{
    				UART_putByte(g_pui8TrfBuffer[ui8LoopCount]);		// Send out data read from tag to host
    			}
    
    			UART_putChar(']');
    			UART_putNewLine();
    #endif
    			// Response received
    			ui8Status = STATUS_SUCCESS;
    		}
    		else		// An error has been sent back in the response byte
    		{
    #ifdef ENABLE_HOST
    			// 	Indicates when an error occurs or block addresses are unreachable - useful for debugging
    			UART_sendCString("Block ");
    			UART_putByte(ui8BlockNumber);			// Output block number
    			UART_sendCString(" Error");
    			UART_putNewLine();
    			UART_sendCString("ISO15693 Error Code: ");
    			UART_putByte(g_pui8TrfBuffer[1]);		// Output ISO15693 error code
    			UART_putNewLine();
    #endif
    			// Response with error
    			ui8Status = STATUS_FAIL;
    		}
    	}
    	else
    	{
    		// No response
    		ui8Status = STATUS_FAIL;
    	}
    
    	return ui8Status;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_sendReadMultipleBlocks - Issue the Read Multiple Block command
    //! for ISO15693 tags.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //! \param ui8FirstBlock is the starting block number to read data from.
    //! \param ui8NumberOfBlocks is the amount of blocks to read data from.
    //!
    //! This function issues a Read Multiple Block with the specified request
    //! flags, the starting block number, and the number blocks to read data from.
    //!
    //! If UART is enabled, the data read from the ISO15693 tag is output via UART.
    //!
    //! \return ui8Status returns either STATUS_SUCCESS or STATUS_FAIL
    //! to indicate if the Read Multiple Block was successful or not.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_sendReadMultipleBlocks(uint8_t ui8ReqFlag, uint8_t ui8FirstBlock, uint8_t ui8NumberOfBlocks)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    	uint8_t ui8LoopCount1 = 0;
    	uint8_t ui8LoopCount2 = 0;
    	uint8_t ui8RxLength = 0;
    	uint8_t ui8BlockSize = 0;
    #endif
    
    	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
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0xC0;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0x40;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag;	// ISO15693 flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x23;			// Read Multiple Block command code
    
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	}
    
    	g_pui8TrfBuffer[ui8Offset++] = ui8FirstBlock;			// Number of the first block to read from
    
    	if (ui8NumberOfBlocks > 0)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = ui8NumberOfBlocks-1;	// Index for number of blocks to be read - this value is one less than
    	}
    	else
    	{
    		// Invalid count provided
    		return ui8Status = STATUS_FAIL;
    	}
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Get System Information command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(10,30+ui8NumberOfBlocks);	// 10 millisecond TX timeout, 30 millisecond RX timeout - adding number of blocks to extend timeout for larger read requests
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    #ifdef ENABLE_HOST
    			ui8RxLength = TRF79xxA_getRxBytesReceived();
    
    			if (ui8ReqFlag & BIT6) // Handle case for Option Flag causing one extra byte to be transmitted.
    			{
    				ui8Offset = 2;
    			}
    			else
    			{
    				ui8Offset = 1;
    			}
    
    			ui8LoopCount1 = ui8RxLength-ui8Offset;
    
    			while (ui8LoopCount1 > 0)
    			{
    				if (ui8LoopCount1 > ui8NumberOfBlocks)
    				{
    					ui8LoopCount1 = ui8LoopCount1 - ui8NumberOfBlocks;
    				}
    				else
    				{
    					ui8LoopCount1 = 0;
    				}
    				ui8BlockSize++;
    			}
    
    			for (ui8LoopCount2 = 0; ui8LoopCount2 < ui8NumberOfBlocks; ui8LoopCount2++)
    			{
    				UART_sendCString("Block ");
    				UART_putByte(ui8FirstBlock+ui8LoopCount2);		// Output block number
    				UART_sendCString(" Data: ");
    				UART_putChar('[');
    
    				// Output received data to UART
    				for (ui8LoopCount1 = 0; ui8LoopCount1 < ui8BlockSize; ui8LoopCount1++)
    				{
    					UART_putByte(g_pui8TrfBuffer[ui8Offset++]);		// Send out data read from tag to host
    				}
    
    				UART_putChar(']');
    				UART_putNewLine();
    			}
    #endif
    			// Response received
    			ui8Status = STATUS_SUCCESS;
    		}
    		else		// An error has been sent back in the response byte
    		{
    #ifdef ENABLE_HOST
    			// 	Indicates when an error occurs or block addresses are unreachable - useful for debugging
    			UART_sendCString("Block ");
    			UART_putByte(ui8FirstBlock);			// Output block number
    			UART_sendCString(" Error");
    			UART_putNewLine();
    			UART_sendCString("ISO15693 Error Code: ");
    			UART_putByte(g_pui8TrfBuffer[1]);		// Output ISO15693 error code
    			UART_putNewLine();
    #endif
    			// Response with error
    			ui8Status = STATUS_FAIL;
    		}
    	}
    	else
    	{
    		// No response
    		ui8Status = STATUS_FAIL;
    	}
    
    	return ui8Status;
    }
    
    
    //*****************************************************************************
    //
    //! ISO15693_sendReadSingleBlockExtended - Issue the Read Single Block
    //! command for ISO15693 tags with the protocol extention flag set
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //! \param ui16BlockNumber is the block number to read data from.
    //!
    //! This function issues a Read Single Block with the block number and the
    //! specified request flags, including the Protocol Extension bit, to read
    //! data from ISO15693 tags which require the use of extended protocol
    //! commands.
    //!
    //! If UART is enabled, the data read from the ISO15693 tag is output via UART.
    //!
    //! \return ui8Status returns either STATUS_SUCCESS or STATUS_FAIL
    //! to indicate if the Read Single Block was successful or not.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_sendReadSingleBlockExtended(uint8_t ui8ReqFlag, uint16_t ui16BlockNumber)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    	uint8_t ui8LoopCount = 1;
    	uint8_t ui8RxLength = 0;
    #endif
    
    	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
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0xC0;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	else
    	{
    		g_pui8TrfBuffer[ui8Offset++] = 0x40;		// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	}
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag | 0x08;	// ISO15693 flags with protocol extension bit set
    	g_pui8TrfBuffer[ui8Offset++] = 0x20;		// Read Single Block command code
    
    	if (ui8ReqFlag & 0x20)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    		g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	}
    
    	g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16BlockNumber & 0xFF);			// Block # (variable, for this device it can go to 0xFF)
    	g_pui8TrfBuffer[ui8Offset++] = (uint8_t) ((ui16BlockNumber >> 8) & 0xFF);		// Block # (variable, for this device it can go to 0x07)
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Read Single Block command
    
    	g_sTrfStatus = TRF79xxA_waitRxData(5,15);		// 5 millisecond TX timeout, 15 millisecond RX timeout
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    			// Response received
    			ui8Status = STATUS_SUCCESS;
    
    #ifdef ENABLE_HOST
    			UART_sendCString("Block ");
    			UART_putByte((ui16BlockNumber >> 8) & 0xFF);			// Output block number
    			UART_putByte(ui16BlockNumber & 0xFF);
    			UART_sendCString(" Data: ");
    			UART_putChar('[');
    
    			ui8RxLength = TRF79xxA_getRxBytesReceived();
    
    			if (ui8ReqFlag & BIT6) // Handle case for Option Flag causing one extra byte to be transmitted.
    			{
    				ui8Offset = 2;
    			}
    			else
    			{
    				ui8Offset = 1;
    			}
    
    			// Output received data to UART
    			for (ui8LoopCount = ui8Offset; ui8LoopCount < ui8RxLength; ui8LoopCount++)
    			{
    				UART_putByte(g_pui8TrfBuffer[ui8LoopCount]);		// Send out data read from tag to host
    			}
    
    			UART_putChar(']');
    			UART_putNewLine();
    #endif
    		}
    		else
    		{
    			// Received an error from the tag
    			ui8Status = STATUS_FAIL;
    #ifdef ENABLE_HOST
    			// 	Indicates when an error occurs or block addresses are unreachable - useful for debugging
    			UART_sendCString("Block ");
    			UART_putByte(((ui16BlockNumber >> 8) & 0xFF));		// Output block number
    			UART_putByte((ui16BlockNumber & 0xFF));
    			UART_sendCString(" Error");
    			UART_putNewLine();
    			UART_sendCString("ISO15693 Error Code: ");
    			UART_putByte(g_pui8TrfBuffer[1]);						// Output ISO15693 error code
    			UART_putNewLine();
    #endif
    		}
    	}
    	else
    	{
    		// Did not receive a proper response from tag
    		ui8Status = STATUS_FAIL;
    	}
    
    	return ui8Status;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_sendWriteSingleBlock - Issue the Write Single Block command
    //! for ISO15693 tags.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //! \param ui8BlockNumber is the block number to write data to.
    //! \param ui8BlockSize is the tag block size.
    //! \param pui8BlockData is the data to be written.
    //!
    //! Function issues an addressed Write Single Block with the specified request
    //! flags as well as the address flag. The write single block command writes
    //! the provided data to the addressed ISO15693 tag.
    //!
    //! The function will always add the address flag to the command as a good
    //! practice to avoid overwriting other ISO15693 tags in the vicinity.
    //!
    //! This function natively supports writing to tags with more than 4 bytes of
    //! data per block through the ui8BlockSize variable.
    //!
    //! \return ui8Status returns either STATUS_SUCCESS or STATUS_FAIL to
    //! indicate if the Write Single Block was successful or not.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_sendWriteSingleBlock(uint8_t ui8ReqFlag, uint8_t ui8BlockNumber, uint8_t ui8BlockSize, uint8_t * pui8BlockData)
    {
    	uint8_t ui8Offset = 0;
    	uint8_t ui8Status = STATUS_FAIL;
    	uint8_t ui8LoopCount = 0;
    
    	ui8ReqFlag = ui8ReqFlag | 0x20; 		// Mandatory use of addressed writes - highly recommended practice
    
    	g_pui8TrfBuffer[ui8Offset++] = 0x8F;		// Reset FIFO
    	g_pui8TrfBuffer[ui8Offset++] = 0x91;		// Send with CRC
    	g_pui8TrfBuffer[ui8Offset++] = 0x3D;		// Write Continuous
    	g_pui8TrfBuffer[ui8Offset++] = (((0x0B+ui8BlockSize) & 0xF0) >> 0x04);	// Length of packet in bytes - upper and middle nibbles of transmit byte length
    	g_pui8TrfBuffer[ui8Offset++] = ((0x0B+ui8BlockSize) << 0x04);			// Length of packet in bytes - lower and broken nibbles of transmit byte length
    	g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlag;	// ISO15693 flags
    	g_pui8TrfBuffer[ui8Offset++] = 0x21;			// Write Single Block command code
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[0];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[1];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[2];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[3];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[4];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[5];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[6];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = g_pui8Iso15693UId[7];	// Tag UID
    	g_pui8TrfBuffer[ui8Offset++] = ui8BlockNumber;		// Block # (variable, for HF-I Plus device can go to 0x3F, Pro and Standard handled with "error" response flags)
    	for (ui8LoopCount = 0; ui8LoopCount < ui8BlockSize; ui8LoopCount++)
    	{
    		g_pui8TrfBuffer[ui8Offset++] = pui8BlockData[ui8LoopCount];			// Data to write to tag
    	}
    
    	TRF79xxA_writeRaw(&g_pui8TrfBuffer[0], ui8Offset);		// Issue the Get System Information command
    
    	g_sTrfStatus = TRF79xxA_getTrfStatus();
    
    	// Special handling to cover option flag use case for TI Tag-It HF-I ISO15693 transponders
    	if (g_sTrfStatus == TRF_IDLE || g_sTrfStatus == TX_WAIT)
    	{
    		// Check if the option flag is set
    		if (ui8ReqFlag & 0x40)
    		{
    			TRF79xxA_waitTxIRQ(10);	// 10 millisecond TX timeout
    
    			g_sTrfStatus = TRF79xxA_getTrfStatus();
    
    			if (g_sTrfStatus == TX_COMPLETE)	// If transmit is complete
    			{
    				MCU_delayMillisecond(10);
    				TRF79xxA_sendDirectCommand(TRF79XXA_TRANSMIT_NEXT_SLOT_CMD);		// Send out End of Frame marker
    				TRF79xxA_waitRxIRQ(30);				// 30 millisecond RX timeout
    			}
    			else								// Otherwise return an error
    			{
    				return ui8Status = STATUS_FAIL;
    			}
    		}
    		else
    		{
    			TRF79xxA_waitTxIRQ(10);	// 10 millisecond TX timeout
    			TRF79xxA_waitRxIRQ(30);	// 30 millisecond RX timeout
    		}
    	}
    	else if (g_sTrfStatus == TX_COMPLETE)
    	{
    		// Check if the option flag is set
    		if (ui8ReqFlag & 0x40)
    		{
    			MCU_delayMillisecond(10);
    			TRF79xxA_sendDirectCommand(TRF79XXA_TRANSMIT_NEXT_SLOT_CMD);		// Send out End of Frame marker
    		}
    
    		TRF79xxA_waitRxIRQ(30);				// 30 millisecond RX timeout
    	}
    	else
    	{
    		return ui8Status = STATUS_FAIL;
    	}
    
    	g_sTrfStatus = TRF79xxA_getTrfStatus();
    
    	if (g_sTrfStatus == RX_COMPLETE)		// If data has been received
    	{
    		if (g_pui8TrfBuffer[0] == 0x00)		// Confirm "no error" in response flags byte
    		{
    			// Response received
    			ui8Status = STATUS_SUCCESS;
    		}
    		else		// An error has been sent back in the response byte
    		{
    			ui8Status = STATUS_FAIL;
    		}
    	}
    	else
    	{
    		// No response
    		ui8Status = STATUS_FAIL;
    	}
    
    	return ui8Status;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_getUid - Fetches the ISO15693 Tag UID.
    //!
    //! \param ui8Index is the index for the ISO15693 UID array.
    //!
    //! This function allows for higher layers to fetch the tag UID of one ISO15693
    //! tag.
    //!
    //! \return g_pui8Iso15693UId returns a pointer to the UID buffer.
    //
    //*****************************************************************************
    
    uint8_t * ISO15693_getUid(void)
    {
    	return g_pui8Iso15693UId;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_getTagCount - Fetches the number of ISO15693 tags which have been
    //! detected.
    //!
    //! This function allows for higher layers to fetch the tag detected count in
    //! order to know how many ISO15693 tags have been detected by the anticollsion
    //! process.
    //!
    //! \return g_ui8TagDetectedCount returns the count of ISO15693 tags detected.
    //
    //*****************************************************************************
    
    uint8_t ISO15693_getTagCount(void)
    {
    	return g_ui8TagDetectedCount;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_resetTagCount - Reset number of the ISO15693 tags detected.
    //!
    //! This function allows for higher layers to reset the tag detected counter.
    //!
    //! \return None
    //
    //*****************************************************************************
    
    void ISO15693_resetTagCount(void)
    {
    	g_ui8TagDetectedCount = 0;
    }
    
    
    //*****************************************************************************
    //
    //! ISO15693_resetRecursionCount - Clear the recursion counter for the
    //! anticollision process.
    //!
    //! This function allows for higher layers to reset the anticollision process
    //! recursion counter.
    //!
    //! \return None
    //
    //*****************************************************************************
    
    void ISO15693_resetRecursionCount(void)
    {
    	g_ui8RecursionCount = 0;
    }
    
    //*****************************************************************************
    //
    //! ISO15693_init - Initialize all Global Variables for the ISO15693 layer.
    //!
    //! This function will initialize all the global variables for the ISO15693
    //! layer with the appropriate starting values or empty values/buffers.
    //!
    //! \return None
    //
    //*****************************************************************************
    
    void ISO15693_init(void)
    {
    	uint8_t ui8LoopCount;
    
    	g_ui8TagDetectedCount = 0;
    	g_ui8RecursionCount = 0;
    
    	for (ui8LoopCount = 0; ui8LoopCount < 8; ui8LoopCount++)
    	{
    		g_pui8Iso15693UId[ui8LoopCount] = 0xFF;  // Initialize with invalid UID
    	}
    	for (ui8LoopCount = 0; ui8LoopCount < 8; ui8LoopCount++)
    	{
    		g_pui8AnticollisionMaskBuffer[ui8LoopCount] = 0x00;
    	}
    }
    
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    
    nfc_app.c
    /*
     * File Name: nfc_app.c
     *
     * Description: Functions to handle the Application Layer processing of
     * the NFC/RFID stack.
     *
     * 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 "nfc_app.h"
    
    //*****************************************************************************
    //
    //! \addtogroup app_nfc_api Application Specific NFC API's
    //! @{
    //!
    //! Application specific API's for NFC/RFID Tag Detection, Selection, and
    //! Reading.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! NFC_findTag - Simple process to cycle through finding NFC/RFID tags of
    //! various NFC/RFID technologies.
    //!
    //! This function cycles through applications designed to detect, active, and
    //! read data from each supported NFC/RFID technology - ISO14443A, ISO14443B,
    //! ISO15693, and FeliCa.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    void NFC_findTag(void)
    {
    	// Clear IRQ Flags
    	IRQ_CLR;
    
    	TRF79xxA_reset();			// Soft Reset the TRF79xxA to ensure it is in a good state at the start of each process
    								// This is a recommended best practice
    
    #ifdef ENABLE_14443A
    	NFC_appIso14443a();			// Scan for NFC Type 4A / ISO14443A tags
    								// For NFC Type 4A tags - Attempt to read NDEF contents
    								// For NFC Type 2 tags - Read block data from the tag
    #endif
    
    #ifdef ENABLE_14443B
    	NFC_appIso14443b();			// Scans for NFC Type 4B / ISO14443B tags and attempts to read NDEF contents
    #endif
    
    #ifdef ENABLE_FELICA
    	NFC_appFeliCa();			// Scans for NFC Type 3 (Sony FeliCa) tags, reports FeliCa card type, gets mfg code, CIN, Pmm, and System code or Data Rate Capability
    								// then using IDm, reads single block and then reads four blocks, simple NDEF parsing afterwards implemented
    #endif
    
    #ifdef ENABLE_15693
    	NFC_appIso15693();			// Scans for NFC Type 5 / ISO15693 tags, reads all data blocks indicated.
    								// Can supports tags from 256bit tags (TI HF-I Std/Pro) to 64kbit (STM M24LR64) tags
    #endif
    
    #ifdef ENABLE_STANDALONE		// No card detected
    	LED_14443A_OFF;
    	LED_14443B_OFF;
    	LED_15693_OFF;
    #endif
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso14443a - Customizeable application to search for ISO14443A/NFC
    //! Type 2/4A Tag Platform compliant tags.
    //!
    //! Function configures TRF79xxA for ISO14443A and waits for a guard time which
    //! allows the PICC to become powered by the RF field before sending a command.
    //!
    //! Tag detection is handled in this example by issuing a REQA
    //! command, and if a reply is received, the ISO14443A anti-
    //! collision process is run until a single tag has provided it's
    //! entire UID. If the tag is Type 4 compliant, an NDEF read
    //! function is called. If the tag is not Type 4 Compliant, then
    //! a Type 2 Application is called.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    uint8_t NFC_appIso14443a(void)
    {
    #ifdef ENABLE_14443A
    
    #if (TRF79xxA_VERSION == 70)
    	if (TRF79xxA_checkExternalRfField() == true)
    	{
    		return STATUS_FAIL;
    	}
    #endif
    
    	TRF79xxA_setupInitiator(0x88);		// Configure the TRF79xxA for ISO14443A @ 106kbps and Receive no CRC
    
    	// 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)
    	MCU_delayMillisecond(6);
    
    	ISO14443A_setRecursionCount(0); 		// Clear the recursion count for anticollision loops
    
    	if (ISO14443A_selectTag(REQA) == STATUS_SUCCESS)	//  Do a complete anticollision sequence as described in ISO14443-3 standard for type A
    	{
    		if (ISO14443A_getType4ACompliance() == true)
    		{
    			NFC_appIso14443aType4NDEF();	// For a Type 4A compliant tag, the tag is put into Layer 4, and in order to attempt to read/write NDEF contents
    		}
    		else
    		{
    			NFC_appIso14443aType2(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
    	}
    
    	TRF79xxA_turnRfOff();
    #endif
    
    	return STATUS_SUCCESS;
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso14443aType4NDEF - Customizeable application to read NDEF data
    //! from a Type 4A NDEF Formatted tag.
    //!
    //! This function sends the needed commands to select and read NDEF data from
    //! a Type 4A Compliant NFC tag. Tags which are Type 4A compliant are selected
    //! via RATS. The PPS command can then be used to change the data rate from
    //! 106kbps up to 848kbps.
    //!
    //! If the tag contains an NDEF message, then the NDEF API's will attempt to
    //! select the NDEF file and read the data contained within it.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    void NFC_appIso14443aType4NDEF(void)
    {
    #ifdef ENABLE_14443A
    	TRF79xxA_writeRegister(TRF79XXA_ISO_CONTROL,0x08);	// Enable RX with CRC
    
    	if(ISO14443A_sendRATS() == STATUS_SUCCESS)
    	{
    		if(ISO14443A_sendPPS() == STATUS_SUCCESS)
    		{
    			NDEF_setBlockNumberBit(0);
    
    			if(NDEF_selectApplication() == STATUS_SUCCESS) // Selects NDEF Application
    			{
    				MCU_delayMillisecond(1);						// Short delay before sending next command
    				NDEF_readCapabilityContainer();
    				MCU_delayMillisecond(1);						// Short delay before sending next command
    				NDEF_readApplication();
    			}
    			else
    			{
    #ifdef ENABLE_STANDALONE
    				LED_14443A_OFF;
    #endif
    			}
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// Tag was not activated properly
    		LED_14443A_OFF;
    #endif
    	}
    #endif
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso14443aType2 - Customizeable application to read data from
    //! ISO14443A compliant tags that do not support NFC Forum Type 4A commands.
    //!
    //! \param ui8ReadBlocks is the number of blocks to read from the tag.
    //!
    //! This function reads block data from Type 2 Tags using the Read Four Blocks
    //! command. The number of blocks to be read needs to be customzied by the
    //! user either in an application specific manner, or by implementing a
    //! look-up table feature that uses the SAK response to determine what the tag
    //! is and how large it's memory contents are.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    void NFC_appIso14443aType2(uint8_t ui8ReadBlocks)
    {
    #ifdef ENABLE_14443A
    	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_sendT2TReadFourBlocks(ui8BlockNumber) == STATUS_FAIL)
    		{
    #ifdef ENABLE_HOST
    			UART_sendCString("Read Error, Blocks: ");
    			UART_putByte(ui8BlockNumber);
    			UART_sendCString(" to ");
    			UART_putByte(ui8BlockNumber+3);
    			UART_putNewLine();
    #endif
    #ifdef ENABLE_STANDALONE
    			LED_14443A_OFF;
    #endif
    			break;
    		}
    	}
    #endif
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso14443b - Customizeable application to search for ISO14443B/NFC
    //! Type 4B Tag Platform compliant tags.
    //!
    //! Function configures TRF79xxA for ISO14443B and waits for a guard time which
    //! allows the PICC to become powered by the RF field before sending a command.
    //!
    //! This function sends the needed commands to detection, select, and read NDEF
    //! data from a Type 4B Compliant NFC tag. Tag detection/selection is handled
    //! in this example by issuing a REQB command, and if a reply is received then
    //! issuing an ATTRIB command to activate and select the tag prior to reading
    //! any data.
    //!
    //! If the tag contains an NDEF message, then the NDEF API's will attempt to
    //! select the NDEF file and read the data contained within it.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    uint8_t NFC_appIso14443b(void)
    {
    #ifdef ENABLE_14443B
    	bool bTagFound = false;
    
    #if (TRF79xxA_VERSION == 70)
    	if (TRF79xxA_checkExternalRfField() == true)
    	{
    		return STATUS_FAIL;
    	}
    #endif
    
    	TRF79xxA_setupInitiator(0x0C);		// Configure the TRF79xxA for ISO14443B @ 106kbps
    
    	// 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 mSec duration. (ISO14443-3)
    
    	// *NOTE* Guard time extended to 10 milliseconds in order to support passively
    	// powered RF430CL330H designs such as seen in TIDA-00217.
    	MCU_delayMillisecond(10);
    
    	if (ISO14443B_sendPollCmd(REQB,0))	// Issue REQB Command with 1 slot to start
    	{
    		bTagFound = true;
    	}
    
    	// If a tag is found proceed to try and read/write an NDEF message to it
    	if(bTagFound)
    	{
    		if (ISO14443B_sendAttrib() == STATUS_SUCCESS)	// Send ATTRIB Request
    		{
    			if (ISO14443B_getType4BCompliance() == true)
    			{
    				NDEF_setBlockNumberBit(0);
    				// Attempt to selects NDEF Application - if successful move to NDEF Process
    				if(NDEF_selectApplication() == STATUS_SUCCESS)
    				{
    					// Read NDEF Content
    					NDEF_readCapabilityContainer();
    					NDEF_readApplication();
    				}
    			}
    			else
    			{
    #ifdef ENABLE_STANDALONE
    				LED_14443B_OFF;
    #endif
    			}
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// No card detected
    		LED_14443B_OFF;
    #endif
    	}
    
    	TRF79xxA_turnRfOff();		// Turn off RF field once done reading the tag(s)
    #endif
    
    	return STATUS_SUCCESS;
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso15693 - Customizeable application to search for ISO15693
    //! compliant tags.
    //!
    //! Function configures TRF79xxA for ISO1593 and waits for a guard time which
    //! allows the VICC to become powered by the RF field before sending a command.
    //!
    //! Tag detection/selection is handled in this example by issuing a Single Slot
    //! Inventory request. If a single tag does not reply, then a 16 Slot Inventory
    //! request is issued. If onle a single tag has been presented, then an API to
    //! read out it's block data will be called.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    uint8_t NFC_appIso15693(void)
    {
    #ifdef ENABLE_15693
    	uint8_t ui8TagFound = STATUS_FAIL;
    	uint8_t ui8AddressedFlag = 0x00;
    
    #if (TRF79xxA_VERSION == 70)
    	if (TRF79xxA_checkExternalRfField() == true)
    	{
    		return STATUS_FAIL;
    	}
    #endif
    
    	// msf - 8/19/19 - Different configurations
    	//TRF79xxA_setupInitiator(0x02);		// Configure the TRF79xxA for ISO15693 @ High Bit Rate, One Subcarrier, 1 out of 4
    	//TRF79xxA_setupInitiator(0x03);  //ISO/IEC 15693 high bit rate, 26.48 kbps, one subcarrier, 1 out of 256
    	TRF79xxA_setupInitiator(0x00);		// Configure the TRF79xxA for ISO15693 @ Low Bit Rate, One Subcarrier, 1 out of 4
    	//TRF79xxA_setupInitiator(0x01);  //ISO/IEC 15693 low bit rate, 6.62 kbps, one subcarrier, 1 out of 256
    
    	// The VCD should wait at least 1 ms after it activated the
    	// powering field before sending the first request, to
    	// ensure that the VICCs are ready to receive it. (ISO15693-3)
    	MCU_delayMillisecond(20);
    
    	ISO15693_resetTagCount();
    
    	ui8TagFound = ISO15693_sendSingleSlotInventory();							// Send a single slot inventory request to try and detect a single ISO15693 Tag
    
    	// Inventory failed - search with full anticollision routine
    	if (ui8TagFound == STATUS_FAIL)
    	{
    		ISO15693_resetRecursionCount();			// Clear the recursion counter
    		MCU_delayMillisecond(5);				// Delay before issuing the anticollision commmand
    		ui8TagFound = ISO15693_runAnticollision(0x06, 0x00, 0x00);		// Send 16 Slot Inventory request with no mask length and no AFI
    		ui8AddressedFlag = 0x20; 			// Collision occurred, send addressed commands
    	}
    
    	if (ui8TagFound == STATUS_SUCCESS)
    	{
    		if (ISO15693_getTagCount() > 1)
    		{
    #ifdef ENABLE_HOST
    			UART_putNewLine();
    			UART_sendCString("Multiple ISO15693 Tags Found");
    			UART_putNewLine();
    			UART_sendCString("# of Tags Detected: ");
    			UART_putByteDecimalValue(ISO15693_getTagCount());
    			UART_putNewLine();
    			UART_sendCString("Place only 1 tag in RF Field to read data");
    			UART_putNewLine();
    #endif
    		}
    		else
    		{
    			NFC_appIso15693ReadTag(0x02 | ui8AddressedFlag);					// Read an ISO15693 tag
    //			NFC_appIso15693ReadExtendedTag(0x0A | ui8AddressedFlag);			// Read an ISO15693 tag which has extended protocol implemented
    //			ISO15693_sendReadMultipleBlocks(0x22,0x00,25);						// Example to read 25 blocks starting @ Block 0 from a tag which supports Read Multiple Block command
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// No card detected
    		LED_15693_OFF;
    #endif
    	}
    
    	TRF79xxA_turnRfOff();						// Turn off RF field once done reading the tag(s)
    #endif
    
    	return STATUS_SUCCESS;
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso15693ReadTag - Read all blocks of a ISO15693 tag.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //!
    //! This function issues Get System Information command to determine how many
    //! blocks of data are stored within the ISO15693 tag.
    //!
    //! Afterwards, all blocks are read out using a Read Single block, unless an
    //! error occurs during the read process at which point the function will stop
    //! reading data and exit.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    void NFC_appIso15693ReadTag(uint8_t ui8ReqFlag)
    {
    #ifdef ENABLE_15693
    	uint16_t ui16ReadBlocks = 0x00;
    	uint16_t ui16LoopCount = 0x00;
    
    	ui16ReadBlocks = ISO15693_sendGetSystemInfo(ui8ReqFlag); 	// Get Tag Information with Request Flag = 0x02
    
    	if (ui16ReadBlocks != 0x00)
    	{
    		// Read all available blocks on the ISO15693 Tag
    		for (ui16LoopCount = 0; ui16LoopCount < ui16ReadBlocks+1; ui16LoopCount++)
    		{
    			if (ISO15693_sendReadSingleBlock(ui8ReqFlag, ui16LoopCount) == STATUS_FAIL)	// Keep reading blocks unless a No Response is received
    			{
    				LED_15693_OFF;
    				// No Response - stop reading
    				break;
    			}
    		}
    	}
    #endif
    }
    
    //*****************************************************************************
    //
    //! NFC_appIso15693ReadExtendedTag - Read all blocks of an ISO15693 tag that
    //! requires the Protocol Extension flag to be used.
    //!
    //! \param ui8ReqFlag are the request flags for ISO15693 commands.
    //!
    //! This function issues Get System Information command with the Protocol
    //! Extension bit set in the request flags to determine how many blocks of
    //! data is stored within the ISO15693 tag.
    //!
    //! Then all blocks are read out using a Read Single block for Extended
    //! ISO15693 tags, unless an error occurs during the read process at which
    //! point the function will stop reading data and exit.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    void NFC_appIso15693ReadExtendedTag(uint8_t ui8ReqFlag)
    {
    #ifdef ENABLE_15693
    	uint16_t ui16ReadBlocks = 0x00;
    	uint16_t ui16LoopCount = 0x00;
    
    	ui8ReqFlag |= 0x08; 	// Add in Protocol Extension Flag if it was omitted from the inputted request flags
    
    	ui16ReadBlocks = ISO15693_sendGetSystemInfoExtended(ui8ReqFlag);	// Issue a Get System Info with Protocol Extension
    
    	if (ui16ReadBlocks != 0x00)
    	{
    		// Read all available blocks on the ISO15693 Tag
    		for (ui16LoopCount = 0; ui16LoopCount < ui16ReadBlocks+1; ui16LoopCount++)
    		{
    			if (ISO15693_sendReadSingleBlockExtended(ui8ReqFlag, ui16LoopCount) == STATUS_FAIL)	// Keep reading blocks until a No Response is received
    			{
    				LED_15693_OFF;
    				// No Response - stop reading
    				break;
    			}
    		}
    	}
    #endif
    }
    
    //*****************************************************************************
    //
    //! NFC_appFeliCa - Customizeable application to search for FeliCa tags.
    //!
    //! Function configures TRF79xxA for FeliCa and waits for a guard time which
    //! allows the tag to become powered by the RF field before sending a command.
    //!
    //! Tag detection/selection is handled in this example by issuing a polling
    //! command followed by reading the Attribute Information Block (Block 0x00)
    //! of the tag.
    //!
    //! \return None.
    //
    //*****************************************************************************
    
    uint8_t NFC_appFeliCa(void)
    {
    #ifdef ENABLE_FELICA
    
    #if (TRF79xxA_VERSION == 70)
    	if (TRF79xxA_checkExternalRfField() == true)
    	{
    		return STATUS_FAIL;
    	}
    #endif
    
    	TRF79xxA_setupInitiator(0x1A);			// Use to configure the TRF79xxA for FeliCa @ 212kbps
    //	TRF79xxA_setupInitiator(0x1B);			// Use to configure the TRF79xxA for FeliCa @ 424kbps
    
    	MCU_delayMillisecond(20);					// Guard time of 20 mS.
    
    	if (FeliCa_pollSingleSlot() == STATUS_SUCCESS)	// Send a polling command with 4 time slots
    	{
    		FeliCa_putTagInformation();			// Print out tag information to the UART
    
    		FeliCa_readSingleBlock(0x00);			// Read single block without encryption
    
    		if(FeliCa_getNDEFLength() != 0x00)
    		{
    			FeliCa_readFourBlocks(0x01);		// Read four blocks, without encryption
    		}
    		else
    		{
    			LED_15693_OFF;
    			LED_14443B_OFF;
    		}
    	}
    	else
    	{
    #ifdef ENABLE_STANDALONE		// No card detected
    		LED_15693_OFF;
    		LED_14443B_OFF;
    #endif
    	}
    
    	TRF79xxA_turnRfOff();						// Turn off RF field once done reading the tag(s)
    #endif
    
    	return STATUS_SUCCESS;
    }
    
    //*****************************************************************************
    //
    //! NFC_init - Initialize the layers for each enabled tag type.
    //!
    //! This function calls the needed initialization functions for
    //! each enabled tag type technology and any other related files.
    //!
    //! \return None
    //
    //*****************************************************************************
    
    void NFC_init(void)
    {
    #ifdef ENABLE_14443A
    	ISO14443A_init();
    	NDEF_setBlockNumberBit(0);
    #endif
    #ifdef ENABLE_14443B
    	ISO14443B_init();
    	NDEF_setBlockNumberBit(0);
    #endif
    #ifdef ENABLE_15693
    	ISO15693_init();
    #endif
    #ifdef ENABLE_FELICA
    	FeliCa_init();
    #endif
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    Thanks, Ralph.

    Let me know if the files don't transfer.  Search for my initials: "msf" to see where I've modified the code.

  • Hello Mark,

    They did. I need to debug further but have limited time this week. I'll try and squeeze in more time tomorrow and hopefully solve it then, but there is a chance this may carry into early next week. 

  • Hello Mark,

    Thanks for your patience.

    Sometimes working on these things on a Monday is a good thing. Fresh week, fresh mind, and I immediately was struck with the answer to the problem.

    Each ISO15693 API that sends data is given a time to wait for both TX Complete and RX Complete before timing out. The code was optimized for ISO15693 high data rate with fairly aggressive timeouts. But for low data rate, these timeouts are too low. I tripled them and immediately got the tag reading.

    See the example below (original timeouts marked in comment)

    	g_sTrfStatus = TRF79xxA_waitRxData(15,45);		// 5 millisecond TX timeout, 15 millisecond RX timeout
    

    Try making these changes in your API's and that should address the last catch here.

  • I changed the two locations where I found TRF79xxA_waitRxData(5,15) in iso15693.c.  Still no luck.

    If I'm reading the modulation correctly off my 'scope, it still looks like 26.5 kbps.

    Maybe I'm suffering from version misalignment.  Perhaps if you could send your copies of trf79xxa.c & iso15693.c, I can compile them here.

  • Hello Mark,

    You need to adjust the timeouts for all calls of TRF79xxA_waitRxData in the ISO15693 file. I just showed one example. The timeouts are all customized based on the function.

    Here's the whole project I used, it's from my test branch so I don't remember if there were other changes I made so just verify that it works and then pull over what you need that is ISO15693 specific: TRF7970ABP_RFID_Reader_Demo_Low_Data.zip

  • Ralph,

    Indeed, the reader does now work with tags.  However, if I'm reading my 'scope output correctly, it still looks like 26.48 kbps. The cursors below are 150us apart. 

  • Mark - 

    I think you have a misconception that the ISO15693 downlink will ever occur at 6.62kbps...this, the setting of 0x00 from 0x02 (for the TRF79xxA ISO Control Register) is for the part to know (ahead of time) then what the reader is sending out in the down-link message with the matching request flags to the tag.

    To be clear - the downlink will always be (should be anyway) at a high ISO15693 data rate for low power HF RFID readers . (unless you really want to use pulse position, which would drop you to 1.6kbps, which is the other option on the reader side, not 6.62kbps), 1 of 4 data coding should always be used. 

    Request flags bytes to use here are: 

    single subcarrier, low data rate, single slot inventory: 0x20

    single subcarrier, low data rate, sixteen slot inventory: 0x00

    single subcarrier, high data rate, sixteen slot inventory: 0x06

    single subcarrier, high data rate, single slot inventory: 0x26

    etc.

  • Josh,

    Thank you for the clarification.  These "standards" include bewildering variations.

    Having demonstrated software for collision avoidance and external modulation control, I'm venturing out on my own, designing a new Class E amplifier for this chip!

    -Mark Freeman

  • if you have any questions or need more clarification on the standards, let us know - its easy to share the knowledge. 

    Here is an ISO15693 portion of some RFID training I put together some time back

    ISO15693_Brief_Overview.pdf

    WRT to the amp, this may help get you started,

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/667/TRF7970-Exernal-Power-Amplifier-for-general-applications_5F00_V53_2800_1_2900_.pdf

    it works well as long as you pay attention to the modulation depth changes as you go up in voltage, this is especially needed for ISO1444B mod depth setting - if not used (i.e. ISO15693 only), you can get rid of the switch. the BDP949 may need replacing as well - last I remember, these were going EOL. (quick check on Digikey confirms, so that would be job #1 if you use this as a reference)

     

  • Josh,

    Thanks for the summary.  That puts essential information in one place; if I'd read that first, I probably wouldn't have swapped VICC/VCD modulation in my head.

    I've never found an explanation how you would chose: OOK/ASK, High/low data rate, single/dual subcarrier, 1of4/1of256 modulation.

    I was looking for 6.62 kbps as the lower bandwidth will theoretically increase read range.  With the number of E2E questions asking to improve read range, publishing a copy of the 6.62 kbps code might help others.  Of course, they need to design a matching read filter.  I found only one of your competitor's chips which support 6.62 kbps, and it is EOL.

    I had reviewed the Aslanidis/Risch App Report previously, and plan to use the core of it as a starting point.  As my application is ISO15693 only, my implementation plan is to:

    • Build the base circuit without the modulator.  If there's a compelling reason for ASK, I'll design my own.
    • Investigate circuitry to protect the MOSFET; the first units will be experimental, and I don't want a mismatched load to burn up the transistor.
    • Re-tune the matching/filter circuit for ISO15693's narrower bandwidth.
    • Tune the receive filter for 6.62 kbps, possibly adding an amplifier.

    Regards,

    Mark