diff options
Diffstat (limited to 'nfclib')
| -rw-r--r-- | nfclib/debug.h | 74 | ||||
| -rw-r--r-- | nfclib/directmode.c | 1059 | ||||
| -rw-r--r-- | nfclib/directmode.h | 78 | ||||
| -rw-r--r-- | nfclib/iso14443-4.c | 164 | ||||
| -rw-r--r-- | nfclib/iso14443-4.h | 33 | ||||
| -rw-r--r-- | nfclib/iso14443a.c | 1141 | ||||
| -rw-r--r-- | nfclib/iso14443a.h | 65 | ||||
| -rw-r--r-- | nfclib/iso14443b.c | 339 | ||||
| -rw-r--r-- | nfclib/iso14443b.h | 51 | ||||
| -rw-r--r-- | nfclib/iso15693.c | 694 | ||||
| -rw-r--r-- | nfclib/iso15693.h | 62 | ||||
| -rw-r--r-- | nfclib/llcp.c | 1051 | ||||
| -rw-r--r-- | nfclib/llcp.h | 248 | ||||
| -rw-r--r-- | nfclib/nfc.c | 241 | ||||
| -rw-r--r-- | nfclib/nfc.h | 42 | ||||
| -rw-r--r-- | nfclib/nfc_dep.c | 597 | ||||
| -rw-r--r-- | nfclib/nfc_dep.h | 109 | ||||
| -rw-r--r-- | nfclib/nfc_f.c | 166 | ||||
| -rw-r--r-- | nfclib/nfc_f.h | 48 | ||||
| -rw-r--r-- | nfclib/nfc_p2p.c | 1993 | ||||
| -rw-r--r-- | nfclib/nfc_p2p.h | 1536 | ||||
| -rw-r--r-- | nfclib/snep.c | 760 | ||||
| -rw-r--r-- | nfclib/snep.h | 206 | ||||
| -rw-r--r-- | nfclib/ssitrf79x0.c | 826 | ||||
| -rw-r--r-- | nfclib/ssitrf79x0.h | 62 | ||||
| -rw-r--r-- | nfclib/trf79x0.c | 1961 | ||||
| -rw-r--r-- | nfclib/trf79x0.h | 400 | ||||
| -rw-r--r-- | nfclib/trf79x0_hw_example.h | 489 | ||||
| -rw-r--r-- | nfclib/types.h | 36 |
29 files changed, 14531 insertions, 0 deletions
diff --git a/nfclib/debug.h b/nfclib/debug.h new file mode 100644 index 0000000..ad0b20c --- /dev/null +++ b/nfclib/debug.h @@ -0,0 +1,74 @@ +//*****************************************************************************
+//
+// debug.h - macro for debug output to terminal.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+//*****************************************************************************
+//
+// Debugging Macros from debug.h in NFCLib. These provide extra debug support.
+// comment out the undef's if you want to use them.
+//
+// DEBUG_PRINTF enables UART messages
+// DEBUG enables ASSERT statements for line / file specific information.
+//
+//*****************************************************************************
+//#define DEBUG_PRINT
+//#define DEBUG
+
+#ifdef DEBUG_PRINT
+#include "utils/uartstdio.h"
+#define DebugPrintf(...) UARTprintf(__VA_ARGS__)
+#else
+#define DebugPrintf(...)
+#endif
+
+//*****************************************************************************
+//
+// Prototype for the function that is called when an invalid argument is passed
+// to an API. This is only used when doing a DEBUG build.
+//
+//*****************************************************************************
+extern void __error__(char *pcFilename, uint32_t ui32Line);
+
+//*****************************************************************************
+//
+// The ASSERT macro, which does the actual assertion checking. Typically, this
+// will be for procedure arguments.
+//
+//*****************************************************************************
+#ifdef DEBUG
+#define ASSERT(expr) do \
+ { \
+ if(!(expr)) \
+ { \
+ __error__(__FILE__, __LINE__); \
+ } \
+ } \
+ while(0)
+#else
+#define ASSERT(expr)
+#endif
+
+#endif //__DEBUG_H__
diff --git a/nfclib/directmode.c b/nfclib/directmode.c new file mode 100644 index 0000000..4aef39e --- /dev/null +++ b/nfclib/directmode.c @@ -0,0 +1,1059 @@ +//*****************************************************************************
+//
+// directmode.h - Direct mode communications.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_timer.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/timer.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/ssi.h"
+#include "driverlib/interrupt.h"
+#include "ssitrf79x0.h"
+#include "trf79x0_hw.h"
+#include "directmode.h"
+#include "trf79x0.h"
+#include "iso14443a.h"
+
+#if defined(rvmdk)
+#define inline __inline
+#endif
+
+//*****************************************************************************
+//
+// Direct mode 0 implementation for ISO 14443 A.
+//
+// This file implements transmission of raw ISO 14443-2 modulation type A
+// formatted bit streams at ~106kbit/s on the TRF79x0 in direct mode 0.
+// The functionality will generate and receive the correct SOF and EOF markers
+// but everything else (parity and CRC) is the responsibility of the calling
+// code. iso14443.c has functions ISO14443ACalculateParity()/
+// ISO14443ACheckParity()/ ISO14443ACalculateCRC()/ ISO14443ACheckCRC() for
+// this purpose. Since it transmits and receives raw bit streams it can also
+// be used for MIFARE Classic communication which needs incorrect parity bits.
+//
+// The implementation uses one timer (TIMER 0) for timing, so this can not
+// be used by anything else, or at least must be set up again before each
+// use, with DirectModeInit().
+//
+// DirectModeEnable() and DirectModeDisable() keep track of state and will
+// not re-enable the mode if it was already active. DirectModeIsEnabled()
+// can be used to query the state. While direct mode is active no other
+// functionality on the TRF79x0 should be accessed and its IRQ is disabled.
+//
+// \note DirectModeDisable() implements a workaround for an apparent bug in
+// the TRF7960 which will perform a soft reset of the TRF7960. In order to
+// not leave the chip in an entirely unexpected state it will then call
+// ISO14443ASetupRegisters() to prepare the chip for ISO 14443 A operation
+// (which is most likely what you'll be using together with this code). If
+// you do not want ISO 14443 A operation you need to restore the necessary
+// settings yourself.
+//
+//*****************************************************************************
+
+//
+// Keep track whether direct mode is enabled.
+//
+static int g_iDirectModeEnabled = 0;
+
+//
+// Receive timeout. This is a loop count, not as reliable as SysCtlDelay(),
+// but not really critical.
+//
+#define DIRECTMODE_RECEIVE_TIMEOUT 30000
+
+//
+// Use timer 0 for direct mode timing.
+//
+#define DIRECTMODE_TIMER_PORT TIMER0_BASE
+#define DIRECTMODE_TIMER_SYSCTL SYSCTL_PERIPH_TIMER0
+
+//*****************************************************************************
+//
+// The macros below do exactly the same as GPIOPinWrite() and GPIOPinRead()
+// from gpio.c and TimerIntStatus() and TimerIntClear() from timer.c, just
+// without the function call and with compile time argument optimization.
+//
+//*****************************************************************************
+#define GPIOPinWrite(ulPort, ucPins, ucVal) \
+ (HWREG((ulPort) + (GPIO_O_DATA + ((ucPins) << 2))) = (ucVal))
+
+#define GPIOPinRead(ulPort, ucPins) \
+ (HWREG((ulPort) + (GPIO_O_DATA + ((ucPins) << 2))))
+
+#define TimerIntStatus(ulBase, bMasked) \
+ ((bMasked) ? HWREG((ulBase) + TIMER_O_MIS) : \
+ HWREG((ulBase) + TIMER_O_RIS))
+
+//*****************************************************************************
+//
+// Shortcut to mimic TimerIntClear() function in DriverLib without the call
+// overhead.
+//
+//*****************************************************************************
+#define TimerIntClear(ulBase, ulIntFlags) \
+ HWREG((ulBase) + TIMER_O_ICR) = (ulIntFlags)
+
+//*****************************************************************************
+//
+// Set timer value.
+// This function is missing from the StellarisWare timer API, so here it is
+// as a macro
+//
+//*****************************************************************************
+#define TimerValueSet(ulBase, ulTimer, ulValue) \
+ HWREG((ulBase) + ((ulTimer)==TIMER_A ? TIMER_O_TAV : TIMER_O_TBV)) = \
+ (ulValue)
+
+//*****************************************************************************
+//
+// This macro enables modulation/disables the field.
+//
+//*****************************************************************************
+#define MODOn() \
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, \
+ TRF79X0_MOD_PIN)
+
+//*****************************************************************************
+//
+// This macro disables modulation/enables the field.
+//
+//*****************************************************************************
+#define MODOff() \
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, 0)
+
+//*****************************************************************************
+//
+// Waits for the next one-eighth bit interval, depends on timer B being set up
+// for one-eighth bit intervals.
+//
+//*****************************************************************************
+#define WaitEighthBit() \
+{ \
+ while(!(TimerIntStatus(DIRECTMODE_TIMER_PORT, 0) & TIMER_TIMB_TIMEOUT)) \
+ { \
+ }; \
+ \
+ TimerIntClear(DIRECTMODE_TIMER_PORT, TIMER_TIMB_TIMEOUT); \
+}
+
+//*****************************************************************************
+//
+// Waits for the next quarter bit interval, depends on timer A being set up
+// for quarter bit intervals.
+//
+//*****************************************************************************
+#define WaitQuarterBit() \
+{ \
+ while(!(TimerIntStatus(DIRECTMODE_TIMER_PORT, 0) & TIMER_TIMA_TIMEOUT)) \
+ { \
+ } \
+ TimerIntClear(DIRECTMODE_TIMER_PORT, TIMER_TIMA_TIMEOUT); \
+}
+
+//*****************************************************************************
+//
+// Modulation sequences, names from ISO 14443-2.
+//
+// All these sequences end at 0.75 bit period and start
+// somewhere before 1 bit period. This way they can be freely combined
+// for an overall rate of one sequence per bit period, and give less than
+// 0.25 bit periods for computation.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// X: pulse after half-bit.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Wait 1/4 bit period.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Set MOD bit active.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+// - Set MOD bit inactive.
+//
+//*****************************************************************************
+#define SequenceX() \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ MODOn(); \
+ WaitQuarterBit(); \
+ MODOff();
+
+//*****************************************************************************
+//
+// Y: This sequence just waits out a full bit period with no other toggle.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Wait 1/4 bit period.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+//
+//*****************************************************************************
+#define SequenceY() \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit();
+
+//*****************************************************************************
+//
+// Z: Mode pulse at start of bit period.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Set MOD bit active.
+// - Wait 1/4 bit period.
+// - Set MOD bit inactive.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+//
+//*****************************************************************************
+#define SequenceZ() \
+ WaitQuarterBit(); \
+ MODOn(); \
+ WaitQuarterBit(); \
+ MODOff(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit();
+
+//*****************************************************************************
+//
+// Set up timers and GPIO port for direct mode operation.
+//
+// This sets up GPTM 0 timer A for quarter bit periods (used in sending)
+// and timer B for one-eighth bit periods (used in receiving).
+//
+//*****************************************************************************
+void
+DirectModeInit(void)
+{
+ //
+ // Enable GPIO port A for bit-banging receive.
+ //
+ SysCtlPeripheralEnable(TRF79X0_RX_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_EN_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_MOD_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_IRQ_PERIPH);
+
+ //
+ // Enable and configure timer in periodic up mode
+ //
+ SysCtlPeripheralEnable(DIRECTMODE_TIMER_SYSCTL);
+ TimerConfigure(DIRECTMODE_TIMER_PORT,
+ TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP |
+ TIMER_CFG_B_PERIODIC_UP);
+
+ //
+ // Configure timer max value for an fc/32 = 13.56MHz/32 = quarter bit
+ // at ~106kHz. This means that the timer must count up to
+ // SysClk/(13.56MHz/32) = (32*SysClk)/13.56MHz. This comes down to 117.99
+ // at 50MHz. The error at 50MHz is negligible, but at other frequencies or
+ // in the general case a fractional logic might be needed.
+ // Note that the argument for TimerLoadSet is actually the desired divisor
+ // minus 1. 117.99 would round to 118, so the argument must be 117.
+ // However since integer calculation is truncating and not rounding this is
+ // directly the result of the division. Should a different frequency be
+ // used where the result of the division is not also the rounded result of
+ // the division minus 1 then proper rounding logic must be added.
+ //
+ TimerLoadSet(DIRECTMODE_TIMER_PORT, TIMER_A,
+ ((SysCtlClockGet() * 32) / 13560000));
+
+ //
+ // Configure Timer B for fc/16 = one eighth bit at ~106kHz. Same
+ // considerations as above apply.
+ //
+ TimerLoadSet(DIRECTMODE_TIMER_PORT, TIMER_B,
+ ((SysCtlClockGet() * 16) / 13560000));
+}
+
+//*****************************************************************************
+//
+// Dual use send code for direct mode. Can either accept an opaque bit stream
+// ( (iMode && DIRECT_MODE_SEND_MASK) == DIRECT_MODE_SEND_OPAQUE ) or
+// structured bytes with parity (... DIRECT_MODE_SEND_PARITY), e.q. as
+// parity_data_t. In the first case uiBytes gives the number of opaque 8
+// bit units to send (e.g. sizeof(*pvBuffer) == uiBytes + (uiBits > 0 ?
+// 1 : 0) ), in the second case it's the number of logical bytes (since each
+// logical byte is encoded as a 16bit word the buffer size must be twice as
+// big). In both cases uiBits gives the number of least significant bits
+// that should additionally be sent.
+//
+//*****************************************************************************
+static inline void
+DirectModeSend(int iMode, void const *pvBuffer, unsigned int uiBytes,
+ unsigned int uiBits)
+{
+ //
+ // We'll keep the current pointer as an 8-bit value and the current byte as
+ // an 16-bit value in any case. In parity mode we'll arrange the pointer
+ // movement and uiCurrentByte assignment specially.
+ //
+ unsigned char const *pucCurrent;
+ unsigned short usPos, usCurrentByte;
+ unsigned char ucLastBit, ucCurrentBit, ucBitsRemain;
+
+ //
+ // Initialize the byte and bit position.
+ //
+ usPos = 0;
+ ucLastBit = 0;
+
+ iMode = iMode & DIRECT_MODE_SEND_MASK;
+
+ //
+ // Create a byte pointer to use with the rest of this function.
+ //
+ pucCurrent = pvBuffer;
+
+ //
+ // Set the MOD pin inactive.
+ //
+ MODOff();
+
+ //
+ // Start the timer.
+ //
+ TimerEnable(DIRECTMODE_TIMER_PORT, TIMER_A);
+
+ //
+ // SOF.
+ //
+ SequenceZ();
+
+ while(usPos++ < uiBytes)
+ {
+ //
+ // Prepare the bit counter and value for this byte for either
+ // 8 bits per byte or 9 bits per 16 bit word.
+ //
+ if(iMode == DIRECT_MODE_SEND_OPAQUE)
+ {
+ ucBitsRemain = 8;
+ usCurrentByte = *pucCurrent;
+ }
+ else
+ {
+ ucBitsRemain = 9;
+ usCurrentByte = pucCurrent[0] | (pucCurrent[1] << 8);
+ }
+
+ //
+ // Send the bits of this byte.
+ //
+ do
+ {
+ ucCurrentBit = usCurrentByte & 0x1;
+
+ if(ucCurrentBit)
+ {
+ //
+ // Transfer a 1 Bit.
+ //
+ SequenceX();
+ }
+ else
+ {
+ //
+ // Transfer a 0-Bit, encoded differently depending on if this
+ // was the last bit.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+ }
+
+ //
+ // Shift to next bit.
+ //
+ usCurrentByte >>= 1;
+
+ ucLastBit = ucCurrentBit;
+ }
+ while(--ucBitsRemain > 0);
+
+ //
+ // Increment the data pointer by either a byte or one 16 bit word.
+ //
+ pucCurrent += (iMode == DIRECT_MODE_SEND_OPAQUE) ? 1 : 2;
+ }
+
+ //
+ // This is the same as above for the possibly remaining fractional byte.
+ //
+ if(uiBits > 0)
+ {
+ ucBitsRemain = uiBits;
+ usCurrentByte = *pucCurrent;
+
+ //
+ // If sending parity then or in the parity.
+ //
+ if(iMode == DIRECT_MODE_SEND_PARITY)
+ {
+ usCurrentByte |= pucCurrent[-1] << 8;
+ }
+
+ do
+ {
+ ucCurrentBit = usCurrentByte & 0x1;
+
+ //
+ // Transfer a 1 Bit.
+ //
+ if(ucCurrentBit)
+ {
+ SequenceX();
+ }
+ else
+ {
+ //
+ // Transfer a 0-Bit, encoded differently depending on if this
+ // was the last bit.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+ }
+
+ //
+ // Shift to next bit.
+ //
+ usCurrentByte >>= 1;
+ ucLastBit = ucCurrentBit;
+ }
+ while(--ucBitsRemain > 0);
+ }
+
+ //
+ // EOF is either a 0 or a Y.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+
+ SequenceY();
+
+ //
+ // Disable the timer and return.
+ //
+ TimerDisable(DIRECTMODE_TIMER_PORT, TIMER_A);
+}
+
+//*****************************************************************************
+//
+// Dual-use receive code for direct mode 0. Similar to the send code can
+// either output an opaque bitstream (DIRECT_MODE_RECV_OPAQUE), or bytes with
+// associated parity bits (DIRECT_MODE_RECV_PARITY).
+//
+//*****************************************************************************
+static void
+DirectModeReceive(int iMode, void *pvBuffer, unsigned int *puiBytes,
+ unsigned int *puiBits)
+{
+ unsigned int uiMaxBytes, uiCountBytes, uiCountBits;
+ int iCurrentBitVal, iLastBitVal, iCount, iHaveSOF;
+ unsigned char *pucCurrent;
+ unsigned int uiCurrentByte;
+ unsigned int uiBitsRemain;
+ int iTimeout;
+
+ //
+ // Signal description: The input on MISO will start out low
+ // and then change to the sub carrier data stream which is either
+ // high, or high-low-high with a frequency of 848kHz. Exactly one
+ // half bit will be all high and one half bit will be alternating.
+ //
+
+ // Reception methodology: Use the IRQ logic as an edge detector.
+ // Configure the GPIO pin for edge triggered interrupts (the interrupt
+ // will not actually be enabled, so no handler will be called). Clear
+ // the interrupt before each sampling interval and check its unmasked
+ // status afterwards.
+ //
+ // The reception may not be perfectly aligned to the bit clock, in that
+ // case the edges will dominate the high signal, e.g. even if there is
+ // just one edge in a sampling period the complete period will read as
+ // "edges present". Look for changes in the sampling result to decode the
+ // manchester encoded stream: there will be a change in the middle of each
+ // bit (and the direction of that change signifies the bit value) and there
+ // might be change at the start/end of a bit. One bit is 8 sampling
+ // periods, so expected is a change every 8 periods. If a change occurs
+ // after 4 periods this is at the start/end of a bit and should be ignored
+ // (and the counter kept incrementing). When keeping in mind that the
+ // subcarier edges may dominate the steady signal that means that there
+ // must have been at least 7 periods since a recognized edge to recognize a
+ // subcarrier-steady edge as a data edge, or 6 periods since a recognized
+ // edge to recognize a steady-subcarrier edge as a data edge.
+ //
+
+ //
+ // Pointer to the next storage location.
+ //
+ pucCurrent = pvBuffer;
+
+ //
+ // Currently sampled data unit (either 8 or 9 bits).
+ //
+ uiCurrentByte = 0;
+
+ //
+ // Set up edge detection.
+ //
+ GPIOIntTypeSet(TRF79X0_RX_BASE, TRF79X0_RX_PIN, GPIO_BOTH_EDGES);
+
+ //
+ // Make sure that data parameters are correct before using them.
+ //
+ if((pvBuffer == NULL) || (puiBytes == NULL) || (*puiBytes == 0))
+ {
+ return;
+ }
+
+ //
+ // Maximal number of bytes to receive, and count of bytes and count of bits
+ // received so far.
+ //
+ uiMaxBytes = *puiBytes;
+ uiCountBytes = 0;
+ uiCountBits = 0;
+
+ //
+ // iCurrentBitVal contains the sampling result for the most recently ended
+ // sampling interval, while iLastBitVal is for the interval before that.
+ // Edges are detected by having iCurrentBitVal != iLastBitVal.
+ //
+ iCurrentBitVal = 0;
+ iLastBitVal = 0;
+
+ //
+ // iCount contains the number of quarter bit intervals since the last
+ // recognized data edge. It is initialized with a half bit period
+ // at the start to immediately detect the data edge in the middle of
+ // the SOF bit, and afterwards incremented for each sampling period and
+ // reset to 0 when a data edge is detected. When an edge is ignored count
+ // will also be set to exactly a half bit period in order to guarantee
+ // that the next edge will be detected as a data edge.
+ //
+ iCount = 4;
+
+ iMode = iMode & DIRECT_MODE_RECV_MASK;
+
+ //
+ // Initialized the number of bits left in the data unit.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ uiBitsRemain = 8;
+ }
+ else
+ {
+ uiBitsRemain = 9;
+ }
+
+ //
+ // Ignore the first bit which is a start-of-frame indicator.
+ //
+ iHaveSOF = 0;
+
+ //
+ // The signal starts out low, so wait for the rising edge.
+ //
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+ {
+ //
+ // Initialize the timeout.
+ //
+ iTimeout = DIRECTMODE_RECEIVE_TIMEOUT;
+
+ while(!(GPIOIntStatus(TRF79X0_RX_BASE, 0) &
+ TRF79X0_RX_PIN) && (iTimeout-- > 0))
+ {
+ }
+ }
+
+ //
+ // Set the timer to 0 and start it.
+ //
+ TimerValueSet(DIRECTMODE_TIMER_PORT, TIMER_B, 0);
+ TimerEnable(DIRECTMODE_TIMER_PORT, TIMER_B);
+
+ //
+ // Reset edge detector.
+ //
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ do
+ {
+ //
+ // Wait until the end of the current sampling interval.
+ //
+ WaitEighthBit();
+
+ //
+ // Copy over the sampling result to be processed, reset edge detector.
+ //
+ iCurrentBitVal = (GPIOIntStatus(TRF79X0_RX_BASE, 0) &
+ TRF79X0_RX_PIN);
+
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Check for a change in bit polarity.
+ //
+ if(iLastBitVal != iCurrentBitVal)
+ {
+ if(iLastBitVal)
+ {
+ //
+ // may be overly long.
+ //
+ if(iCount <= 6)
+ {
+ //
+ // ignore, but force iCount to sane value.
+ //
+ iCount = 4;
+ }
+ else
+ {
+ if(iHaveSOF)
+ {
+ //
+ // This edge is a 1 bit, add it to the current data
+ // unit.
+ //
+ uiBitsRemain--;
+
+ uiCurrentByte |= 1 << uiCountBits;
+
+ uiCountBits++;
+ }
+ else
+ {
+ iHaveSOF = 1;
+ }
+
+ //
+ // Reset iCount.
+ //
+ iCount = 0;
+ }
+ }
+ else
+ {
+ //
+ // may be overly short
+ //
+ if(iCount <= 5)
+ {
+ //
+ // ignore, but force iCount to sane value.
+ //
+ iCount = 4;
+ }
+ else
+ {
+ if(iHaveSOF)
+ {
+ //
+ // This edge is a 0 bit, add it to the current data
+ // unit.
+ //
+ uiBitsRemain--;
+ uiCountBits++;
+ }
+ else
+ {
+ iHaveSOF = 1;
+ }
+
+ //
+ // Reset iCount.
+ //
+ iCount = 0;
+ }
+ }
+ }
+
+ //
+ // Increment number of one eighth bit periods since last recognized
+ // edge.
+ //
+ iCount++;
+ iLastBitVal = iCurrentBitVal;
+
+ if(uiBitsRemain == 0)
+ {
+ //
+ // Store received data unit, advance pointer.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ uiBitsRemain = 8;
+ *pucCurrent = uiCurrentByte;
+ pucCurrent += 1;
+ }
+ else
+ {
+ uiBitsRemain = 9;
+ pucCurrent[0] = uiCurrentByte & 0xff;
+ pucCurrent[1] = uiCurrentByte >> 8;
+ pucCurrent += 2;
+ }
+
+ //
+ // Clear temporary store.
+ //
+ uiCurrentByte = 0;
+ uiCountBits = 0;
+
+ //
+ // Increment counter, abort when the receive buffer is full.
+ //
+ uiCountBytes++;
+ if((uiCountBytes + 1) >= uiMaxBytes)
+ {
+ break;
+ }
+ }
+
+ //
+ // More than 2 bit periods (16 eighth bit periods) since the last edge
+ // signify a time out, end of reception.
+ //
+ }
+ while(iCount < 16);
+
+ //
+ // Stop timer.
+ //
+ TimerDisable(DIRECTMODE_TIMER_PORT, TIMER_B);
+
+ //
+ // Store length.
+ //
+ *puiBytes = uiCountBytes;
+
+ if(puiBits != NULL)
+ {
+ if(uiCountBits > 0)
+ {
+ //
+ // Store incomplete byte.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ *pucCurrent = uiCurrentByte;
+ }
+ else
+ {
+ pucCurrent[0] = uiCurrentByte & 0xff;
+ pucCurrent[1] = uiCurrentByte >> 8;
+ }
+ }
+
+ //
+ // Store length of incomplete byte.
+ //
+ *puiBits = uiCountBits;
+ }
+}
+
+//*****************************************************************************
+//
+// Transmits and receives an ISO 14443-2 type A frame in direct mode 0.
+//
+// \param iMode is a flag field to specify the format of the input and output
+// parameters. Should be a combination of (either \b DIRECT_MODE_SEND_OPAQUE
+// or \b DIRECT_MODE_SEND_PARITY) and (either \b DIRECT_MODE_RECV_OPAQUE or
+// \b DIRECT_MODE_RECV_PARITY). See discussion below.
+// \param pvSendBuf is the data buffer to send.
+// \param uiSendBytes determines the number of full data units to be sent (8
+// or 9 bits each). For a discussion of data unit sizes see below.
+// \param uiSendBits determines how many bits from an additional, fractional
+// data unit should be sent. Setting this to a value other than 0 means that
+// \e pvSendBuf has space for an \e uiSendBytes + 1 data units.
+// \param pvRecvBuf is the data buffer for receiving.
+// \param puiRecvBytes inputs the space available in \e pvRecvBuf (in logical
+// data units) and outputs the number of full data units actually received
+// \param puiRecvBits outputs the number of additional bits received after the
+// last full data unit indicated in \e puiRecvBytes
+//
+// Both input and output can be in one of two formats: OPAQUE and PARITY.
+//
+// - \b OPAQUE specifies an opaque bit stream, where each byte in the input
+// corresponds to 8 bits sent on the radio interface and 8 bits received on
+// the radio interface correspond to 1 byte in the output.
+// - \b PARITY has for each byte in the input/output an associated parity bit.
+// These are stored as a 16 bit word: the payload byte is in the lower 8 bits
+// and the parity bit is the least significant bit of the higher byte.
+//
+// The principal data unit size for OPAQUE is 8 bits, and the principal data
+// unit size for PARITY is 9 bits (stored as a 16 bit word). All inputs
+// and outputs are in terms of data units, which means that the actual storage
+// size, in bytes, for PARITY mode is twice the number of data units.
+//
+// In both modes additional bits can be sent or received after the last
+// full data unit. PARITY mode is best suited for ISO 14443 operation
+// since it conveniently associates each byte with its parity bit, and
+// allows for direct access to the payload byte of each data unit through
+// simple masking, and not requiring shifts and masks over two bytes.
+//
+// Direct mode needs to have been enabled with DirectModeEnable() (with
+// argument \e iMode = 0) before calling this function. This function will
+// disable the master processor interrupt while it is running.
+//
+//*****************************************************************************
+void
+DirectModeTransceive(int iMode, void const *pvSendBuf, unsigned int uiSendBytes,
+ unsigned int uiSendBits, void *pvRecvBuf,
+ unsigned int *puiRecvBytes, unsigned int *puiRecvBits)
+{
+ int iDisabled;
+
+ //
+ // Disable interrupts.
+ //
+ iDisabled = IntMasterDisable();
+
+ //
+ // Send and receive
+ //
+ DirectModeSend(iMode, pvSendBuf, uiSendBytes, uiSendBits);
+ DirectModeReceive(iMode, pvRecvBuf, puiRecvBytes, puiRecvBits);
+
+ //
+ // Enable interrupts if necessary.
+ //
+ if(iDisabled == 0)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+// Starts direct mode.
+//
+// \param iMode is the direct mode to enable and must be 0 for now.
+//
+// This function sets the desired direct mode type on the TRF79x0 and then
+// enables direct mode. This also has the effect of disabling the
+// TRF79x0 IRQ. No TRF79x0 operation can be performed while direct mode is
+// active (and none should be attempted).
+// The function sets an internal flag and does nothing if direct mode has
+// already been enabled by this function and not been disabled with
+// DirectModeDisable().
+//
+//*****************************************************************************
+void
+DirectModeEnable(unsigned int iMode)
+{
+ unsigned char pucRegs[3];
+
+ //
+ // Check to see if direct mode is already enabled, and if so, do nothing
+ //
+ if(g_iDirectModeEnabled)
+ {
+ return;
+ }
+
+ //
+ // Read chip status control and ISO registers.
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_CHIP_STATUS_CTRL_REG, pucRegs, 2);
+
+ //
+ // Set direct mode type to bitstream.
+ //
+ if(iMode)
+ {
+ pucRegs[TRF79X0_ISO_CONTROL_REG] |= TRF79X0_ISO_CONTROL_DIR_MODE;
+
+ }
+ else
+ {
+ pucRegs[TRF79X0_ISO_CONTROL_REG] &= ~TRF79X0_ISO_CONTROL_DIR_MODE;
+ }
+
+ //
+ // Enable direct mode in saved registers.
+ //
+ pucRegs[0] |= TRF79X0_STATUS_CTRL_DIRECT;
+
+ //
+ // Write direct mode type to TRF79x0.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, pucRegs[1]);
+
+ //
+ // Clear pucRegs[2]
+ //
+ pucRegs[2] = 0;
+
+ //
+ // Start direct mode
+ // This write will not finish (which would end direct mode) but instead
+ // must be finished with TRF79x0DirectModeDisable(). Also the IRQ handler
+ // has been deactivated while the chip select is asserted since it can't
+ // use the SPI anyway.
+ //
+ SSITRF79x0WriteContinuousStart(TRF79X0_CHIP_STATUS_CTRL_REG);
+ SSITRF79x0WriteContinuousData(pucRegs, 1);
+
+ //
+ // Delay 8 dummy clock cycles
+ //
+ SSITRF79x0DummyWrite(&pucRegs[2], 1);
+
+ //
+ // Set up GPIO configuration: Use the input (normally MISO) as a GPIO to
+ // bit-bang the reception of the sub-carrier signal
+ //
+ GPIOPinTypeGPIOInput(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Set flag
+ //
+ g_iDirectModeEnabled = 1;
+}
+
+//*****************************************************************************
+//
+// Stops direct mode.
+//
+// This stops the direct mode and releases the communication interface.
+// It checks an internal flag and does nothing if direct mode has not been
+// enabled with DirectModeEnable() or has been disabled with
+// DirectModeDisable() before.
+//
+// \note There seems to be a bug in the TRF7960 which makes the chip unusable
+// for some time after exiting direct mode due to the MISO line not
+// working properly. Currently the required workaround is to send a
+// \b TRF79X0_SOFT_INIT_CMD command and then reinitialize the chip, with
+// ISO14443ASetupRegisters(). This is done by this function, so you'll
+// find the TRF79x0 configured for ISO 14443-A even if it wasn't before.
+//
+//*****************************************************************************
+void
+DirectModeDisable(void)
+{
+ int iDisabled;
+
+ //
+ // Check to see if direct mode is enabled, and if not, do nothing.
+ //
+ if(!g_iDirectModeEnabled)
+ {
+ return;
+ }
+
+ //
+ // Kludge: We want to prevent the IRQ handler from going off
+ // before we have reinitialized the interface. The call to
+ // SSITRF79x0WriteContinuousStop(), and by extension all the
+ // calls to TRF79x0DirectCommand or TRF79x0Read*, will enable the
+ // IRQ, so we disable the processor IRQ for the time being.
+ //
+ iDisabled = IntMasterDisable();
+
+ //
+ // Restore SSI pin settings.
+ //
+ GPIOPinTypeSSI(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Disable direct mode.
+ //
+ SSITRF79x0WriteContinuousStop();
+
+ //
+ // For good measure: Discard bytes from FIFO.
+ //
+ TRF79x0DirectCommand(TRF79X0_RESET_FIFO_CMD);
+
+ //
+ // Clear flag.
+ //
+ g_iDirectModeEnabled = 0;
+
+ //
+ // Re-enable processor IRQ if necessary.
+ //
+ if(iDisabled == 0)
+ {
+ IntMasterEnable();
+ }
+
+ //
+ // Enable TRF IRQ.
+ //
+ TRF79x0InterruptEnable();
+
+ //
+ // This code should be removed if a better solution is found since
+ // the direct mode code should not directly depend on ISO 14443-A
+ // and there might, hypothetically, be other protocols that the user
+ // might want to use.
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ ISO14443ASetupRegisters();
+ ISO14443APowerOn();
+}
+
+//*****************************************************************************
+//
+// Queries whether direct mode is enabled.
+//
+// \return A non-zero value indicates that direct mode is enabled and a zero
+// value indicates that direct mode is disabled.
+//
+//*****************************************************************************
+int
+DirectModeIsEnabled(void)
+{
+ return(g_iDirectModeEnabled);
+}
diff --git a/nfclib/directmode.h b/nfclib/directmode.h new file mode 100644 index 0000000..6124859 --- /dev/null +++ b/nfclib/directmode.h @@ -0,0 +1,78 @@ +//*****************************************************************************
+//
+// directmode.h - Direct mode communications.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __DIRECTMODE_H__
+#define __DIRECTMODE_H__
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//
+// Input to DirectModeTransceive is an opaque stream of bits, grouped as 8
+// bits into one byte. LSBit should be sent first.
+//
+#define DIRECT_MODE_SEND_OPAQUE 0
+
+//
+// Input to DirectModeTransceive is an array of bytes with associated parity
+// bit, stored as 16 bit words. The lower 8 bits in each word are the byte
+// (LSBit should be sent first), the lowest bit of the upper 8 bits is the
+// parity bit. The remaining 7 bits are ignored.
+//
+//
+#define DIRECT_MODE_SEND_PARITY 1
+
+//
+// Output from DirectModeTransceive should be an opaque bit stream, grouped as
+// 8 bits into one byte, LSBit was received first.
+//
+#define DIRECT_MODE_RECV_OPAQUE 0
+
+//
+// Output from DirectModeTransceive should be an array of bytes with
+// associated parity bit.
+//
+#define DIRECT_MODE_RECV_PARITY 2
+
+#define DIRECT_MODE_SEND_MASK 1
+#define DIRECT_MODE_RECV_MASK 2
+
+extern void DirectModeInit(void);
+extern void DirectModeTransceive(int iMode, void const *pvSendBuf,
+ unsigned int iSendBytes,
+ unsigned int iSendBits, void *pvRecvBuf,
+ unsigned int *piRecvBytes,
+ unsigned int *piRecvBits);
+
+extern void DirectModeEnable(unsigned int iMode);
+extern void DirectModeDisable(void);
+extern int DirectModeIsEnabled(void);
+
+#endif
diff --git a/nfclib/iso14443-4.c b/nfclib/iso14443-4.c new file mode 100644 index 0000000..4bb39af --- /dev/null +++ b/nfclib/iso14443-4.c @@ -0,0 +1,164 @@ +//*****************************************************************************
+//
+// iso14443-4.c - ISO 14443-4 implementation.
+//
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf7960.h"
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 RATS command.
+//
+//*****************************************************************************
+int
+ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS)
+{
+ unsigned char pucResponse[16];
+ unsigned int uiRxSize;
+ unsigned char pucRATS[2];
+ int i;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // RATS command.
+ //
+ pucRATS[0] = 0xE0;
+ pucRATS[1] = (ucFSDI << 4) || ucCID;
+
+ //
+ // Transmit RATS, receive ATS.
+ //
+ TRF7960Transceive(pucRATS, sizeof(pucRATS), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ if(uiRxSize >= 3)
+ {
+ //
+ // Valid ATS received, return it as an char buffer. Was transmitted LSByte first.
+ // pucResponse[0] is the length of the transmitted ATS, including TL byte, NOT including
+ // two CRC bytes
+ //
+ for(i = 0; i < pucResponse[0]; i++)
+ pucATS[i] = pucResponse[i];
+
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 PPS command.
+// ucCID must between 0~14, ucDRI & ucDSI must between 0~3
+//
+//*****************************************************************************
+int
+ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI)
+{
+ unsigned char pucResponse[3];
+ unsigned int uiRxSize;
+ unsigned char pucPPS[3];
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // PPS command.
+ //
+ pucPPS[0] = (0xD << 4) | ucCID;
+ pucPPS[1] = 0x11; // PPS1 is transmitted
+ pucPPS[2] = (ucDSI << 2) | ucDRI;
+
+ //
+ // Transmit PPS, receive PPS response.
+ //
+ TRF7960Transceive(pucPPS, sizeof(pucPPS), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ //
+ // check if receive the first byte of the response is PPSS
+ //
+ if(pucResponse[0] == pucPPS[0])
+ return(1);
+ else
+ {
+ //
+ // Not valid response
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 DESELECT command.
+// ucCID must between 0~14, ucDRI & ucDSI must between 0~3
+//
+//*****************************************************************************
+int
+ISO14443DESELECT(unsigned char ucCID)
+{
+ unsigned char pucResponse[2];
+ unsigned int uiRxSize;
+ unsigned char pucDESELECT[2];
+
+ uiRxSize = sizeof(pucResponse);
+
+ pucResponse[0] = 0;
+ pucResponse[1] = 0;
+
+ //
+ // DESELECT command.
+ //
+ pucDESELECT[0] = 0xCA; // S-block with DESELECT set and CID following
+ pucDESELECT[1] = ucCID & 0x0F;
+
+ //
+ // Transmit DESELECT, receive DESELECT response.
+ //
+ TRF7960Transceive(pucDESELECT, sizeof(pucDESELECT), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ //
+ // check if receive the first byte of the response is DESELECT
+ // check if the second byte contains the same CID
+ //
+ if(pucResponse[0] == pucDESELECT[0])
+ {
+ return(1);
+ }
+ else
+ {
+ //
+ // Not valid response
+ //
+ return(0);
+ }
+}
diff --git a/nfclib/iso14443-4.h b/nfclib/iso14443-4.h new file mode 100644 index 0000000..b2f9b8b --- /dev/null +++ b/nfclib/iso14443-4.h @@ -0,0 +1,33 @@ +//*****************************************************************************
+//
+// iso14443a.h - ISO 14443A implementation.
+//
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443-4_H__
+#define __ISO14443-4_H__
+
+extern int ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS);
+extern int ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI);
+extern int ISO14443DESELECT(unsigned char ucCID);
+
+#endif
diff --git a/nfclib/iso14443a.c b/nfclib/iso14443a.c new file mode 100644 index 0000000..10cd6b2 --- /dev/null +++ b/nfclib/iso14443a.c @@ -0,0 +1,1141 @@ +//*****************************************************************************
+//
+// iso14443a.c - ISO 14443A implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443a.h"
+
+//*****************************************************************************
+//
+// Global anti-collision state for use by ISO14443ASelectFirst() and
+// ISO14443ASelectNext().
+//
+//*****************************************************************************
+static struct ISO14443AAnticolState g_sAnticolState;
+
+//*****************************************************************************
+//
+// ISO14443-A Anti-collision implementation, iterative depth-first tree search
+// with optional backtracking.
+//
+// Usage:
+// In ISO 14443 A there are two types of resting states for cards: IDLE and
+// HALT. A card enters IDLE state after powering up and performing all the
+// necessary internal initialization. The specification states that the card
+// must be in IDLE state and ready to accept commands 5ms after being put into
+// an unmodulated (e.g. no commands sent) field of the necessary strength.
+//
+// This pause is guaranteed by ISO14443APowerOn().
+//
+// During the selection and anti-collision phase cards will be in intermediary
+// states (READY and READY*) but then always return to the original state
+// (IDLE and HALT).
+//
+// After a card has been selected by any of the ISO14443ASelect* functions
+// of this module it can be sent to the HALT state with ISO14443AHalt(),
+// and must be sent to HALT (or deactivated in another way) before calling
+// another ISO14443ASelect* function.
+//
+// Cards in the IDLE state react to both WUPA and REQA commands, cards in
+// HALT state react only to WUPA commands. Cards in HALT state can not
+// return to IDLE state except through completely powering off the card
+// and powering it up again, but the specification makes no claims as to how
+// long the field must be off in order for the card to power off and this time
+// will vary between card types.
+//
+// The ISO14443ASelectFirst/Next functions take one parameter (\e ucCmd) that
+// must be \b ISO14443A_REQA or \b ISO14443A_WUPA to specify which wake up
+// method to use. ISO14443ASelect will always use WUPA.
+//
+// This leads to two main usage protocols:
+// <h3>A: Detect only new cards</h3> <ul>
+// <li> Keep field enabled at all times
+// <li> Use ISO14443ASelectFirst() with ISO14443A_REQA to find new cards that
+// entered the field. Note: Ensure a pause of 5ms before each call to
+// ISO14443ASelectFirst(), e.g. with ISO14443APowerOn().
+// <li> If a card was found by SelectFirst, operate on that card and
+// deactivate it with ISO14443AHalt(). Note: all successful calls to any
+// ISO14443ASelect* function should always be paired with a call to
+// ISO14443AHalt() before the next call to any ISO14443ASelect* function.
+// <li> Repeatedly call ISO14443ASelectFirst() with \b ISO14443A_REQA in a
+// loop. It will only find new cards and not relist the cards that were
+// already handled and halted
+// </ul>
+// Pseudo C: <pre>
+// while(1) {
+// ISO14443APowerOn();
+// if(ISO14443ASelectFirst(ISO14443A_REQA, ...)) {
+//
+// <i>Do something with the card</i>
+//
+// ISO14443AHalt();
+// }
+//
+// <i>Do NOT power off the field</i>
+// }
+// </pre>
+//
+// <h3>B: List all cards in the field</h3> <ul>
+// <li> Optionally disable the field or do other things, but enable the
+// field at least for 5ms (e.g. with ISO14443APowerOn())
+// <li> Call ISO14443ASelectFirst() with \b ISO14443A_WUPA to find the first
+// card, handle it, call ISO14443AHalt(). If at least one card was
+// found, use ISO14443ASelectNext() with \b ISO14443A_WUPA in a loop to
+// find more cards, handle them and call ISO14443AHalt() on them.
+// <li> You may disable the field and restart the procedure at any time with
+// ISO14443APowerOn() and ISO14443ASelectFirst(). It will always list
+// all cards in the field, not only new cards.
+// </ul>
+// Pseudo C: <pre>
+// while(1) {
+// ISO14443APowerOn();
+// if(ISO14443ASelectFirst(ISO14443A_WUPA, ...)) {
+// do {
+//
+// <i>Do something with the card</i>
+//
+// ISO14443AHalt();
+// } while(ISO14443ASelectNext(ISO14443A_WUPA, ...));
+// }
+//
+// <i>You may power off the field here</i>
+// }
+// </pre>
+//
+// In both cases ISO14443ASelect() can be used at any time (after halting a
+// previously selected card) to select a card by known UID.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This structure stores the UID that we're currently working on.
+//
+//*****************************************************************************
+struct ISO14443AAnticolState
+{
+ //
+ // This field stores the raw responses that the anti-collision is actually
+ // performed over, e.g. 3 times 5 bytes. Same goes for \e ucCollisions.
+ // Before returning the UID to the calling code this must be cleaned,
+ // that is remove cascade tag and BCC.
+ //
+ unsigned char ucUID[15];
+ //
+ // Stores the collision positions discovered so far. It is a bit field
+ // with the same indices as \e ucUID.
+ //
+ unsigned char ucCollisions[15];
+ //
+ // Stores the number of bits that we've successfully received or
+ // disambiguated. Note: Real count for the \e ucUID field of this
+ // structure, not NVB format. For example 8 means 1 byte and 0 bits, 40
+ // means full cascade level 1, 41 means full cascade level 1 plus 1 bit in
+ // cascade level 2.
+ //
+ unsigned int iBitPos;
+};
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 A 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443A functions.
+//
+//*****************************************************************************
+void
+ISO14443ASetupRegisters(void)
+{
+ //
+ // Set the ISO format to ISO1443A 106Kbps.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_14443A_106K);
+
+ //
+ // Set the TX pulse to 106ns (0x20 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 66us (7 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation Depth to OOK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ (TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ |
+ TRF79X0_MOD_CTRL_MOD_OOK_100));
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_M848);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+}
+
+//*****************************************************************************
+//
+// Power on the field and wait for a time that is long enough to guarantee
+// that all cards in the field will be initialized.
+//
+//*****************************************************************************
+void
+ISO14443APowerOn(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Enable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg | TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms (as per ISO 14443-3 clause 5).
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Power off the field and wait for some time.
+//
+//*****************************************************************************
+void
+ISO14443APowerOff(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Disable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg & ~TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Transmit a HLTA command that should HALT the currently selected card. You
+// should always call this function after a successful call to either
+// ISO14443ASelect(), ISO14443ASelectFirst() or ISO14443ASelectNext() and
+// before any other call to any of those functions.
+//
+//*****************************************************************************
+void
+ISO14443AHalt(void)
+{
+ //
+ // HLTA command.
+ //
+ const unsigned char pucHLTA[2] = {0x50, 0x00};
+
+ TRF79x0Transceive(pucHLTA, sizeof(pucHLTA), 0, NULL, NULL, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-A REQA type command.
+//
+// \param ucCmd is the command, either \b ISO14443A_REQA or \b ISO14443A_WUPA
+// \param piATQA is a pointer to an integer to store the received ATQA and
+// will be set to -1 if a collision occurred.
+//
+// \return true if at least one card responded that is capable of bit-frame
+// anti-collision (e.g. no collision and one of the lower 5 bits of response
+// set, or collision within the first 5 bits, or collision not in the first
+// 5 bits but at least one of the first 5 bits is a 1-bit) and false
+// otherwise.
+//
+// \note User code usually does not need to call this function since it is
+// implicitly called in ISO14443ASelect(), ISO14443ASelectFirst() or
+// ISO14443ASelectNext().
+//
+//*****************************************************************************
+int
+ISO14443AREQA(unsigned char ucCmd, int *piATQA)
+{
+ unsigned char pucResponse[2];
+ unsigned int uiRxSize;
+ int iColPos;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Transmit WUPA/REQA, receive ATQA.
+ //
+ TRF79x0Transceive(&ucCmd, 0, 7, pucResponse, &uiRxSize, 0,
+ TRF79X0_TRANSCEIVE_NO_CRC);
+
+ if(uiRxSize == 2)
+ {
+ //
+ // Valid ATQA received, return it as an integer. Was transmitted
+ // LSByte first.
+ //
+ if(piATQA != NULL)
+ {
+ *piATQA = pucResponse[0] | (pucResponse[1] << 8);
+ }
+
+ //
+ // Return true if one of the lower 5 bits was set.
+ //
+ return((pucResponse[0] & 0x1F) != 0);
+ }
+ else
+ {
+ //
+ // No valid ATQA received.
+ //
+ if(piATQA != NULL)
+ {
+ *piATQA = -1;
+ }
+
+ if(uiRxSize == 0)
+ {
+ //
+ // No response at all -> no card with bit-frame anti-collision.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // Probably some collision.
+ //
+ iColPos = TRF79x0GetCollisionPosition();
+
+ if(iColPos > 5)
+ {
+ //
+ // Collision not within the first 5 bits, return true if one of
+ // the lower 5 bits was set.
+ //
+ return((pucResponse[0] & 0x1F) != 0);
+ }
+ else if(iColPos > 0 && iColPos <= 5)
+ {
+ //
+ // Collision within the first 5 bits, so at least one of them
+ // was 1.
+ //
+ return(1);
+ }
+ else
+ {
+ //
+ // No collision, but only 1 byte sent? That card's not right.
+ //
+ return(0);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Find one card through the anti-collision procedure with given \e psState.
+//
+// \param psState is the anti-collision state to start from. If this state
+// already specifies a full UID then it will be selected, otherwise
+// anti-collision will be tried to complete that starting state, with no
+// backtracking.
+// \param pucUID is an output buffer to write the selected UID and may be
+// \b NULL in which case the UID will not be returned.
+// \param puiUIDSize inputs the available space in bytes in \e pucUID and
+// returns with the actual length that has been stored there.
+// \param pucSAK is an output parameter that stores the received SAK value.
+// May be \b NULL in which case the SAK will not be returned
+//
+// This is a depth first search in a binary tree over the UID space. On each
+// attempt we can learn up to 4 bytes of the UID of the card(s) currently in
+// the field. If the UIDs of two cards differ we will learn that too and get
+// the collision position: the position of the bit where the UID of at least
+// two cards differs. We will mark this position in the appropriate field in
+// the structure ISO14443AnticolState and then branch first in the direction of
+// 0 and increase iBitPos to include this bit.
+//
+// \return This function returns 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+static int
+ISO14443ADoAnticol(struct ISO14443AAnticolState *psState, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ int iCascadeLevel, iPos;
+ unsigned char pucCmd[7], pucResponse[5];
+ unsigned int uiRxSize;
+ int iIdx, iMaskPosition, iCollPosition, iValidBits, iMaxLength, iNVB;
+
+ iCascadeLevel = 1;
+
+ while(iCascadeLevel < 4)
+ {
+ //
+ // Already known bits for this cascade level, e.g. not including
+ // the possible 5 bytes * 8 bits/byte for the lower levels.
+ //
+ iValidBits = psState->iBitPos - (iCascadeLevel - 1) * 5 * 8;
+
+ //
+ // Clamp to a full cascade level.
+ //
+ if(iValidBits > 40)
+ {
+ iValidBits = 40;
+ }
+
+ //
+ // NVB format: bytes.
+ //
+ iNVB = (iValidBits / 8) << 4;
+
+ //
+ // NVB format: bits.
+ //
+ iNVB |= (iValidBits % 8);
+
+ //
+ // Also count the command byte and the NVB byte itself.
+ //
+ iNVB += 0x20;
+
+ //
+ // Prepare command for this level: ANTICOLLISION if less than a full 5
+ // bytes for the current cascade level, SELECT otherwise.
+ //
+ switch (iCascadeLevel)
+ {
+ case 1:
+ {
+ pucCmd[0] = 0x93;
+ break;
+ }
+ case 2:
+ {
+ pucCmd[0] = 0x95;
+ break;
+ }
+ case 3:
+ {
+ pucCmd[0] = 0x97;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ pucCmd[1] = iNVB;
+
+ //
+ // Copy over known bytes (number of bits for this level divided by 8,
+ // rounded up).
+ //
+ memcpy(pucCmd + 2, psState->ucUID + (iCascadeLevel - 1) * 5,
+ (iValidBits + 7) / 8);
+
+ //
+ // Enforce a small delay of ~600us before each anti-collision frame.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 6) / 10000);
+
+ //
+ // Maximal expected response length.
+ //
+ uiRxSize = 5;
+
+ if(iNVB != 0x70)
+ {
+ //
+ // Anti-collision command.
+ //
+ TRF79x0Transceive(pucCmd, pucCmd[1] >> 4, pucCmd[1] & 0xf,
+ pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_NO_CRC);
+
+ if(uiRxSize == 0)
+ {
+ return(0);
+ }
+
+ iCollPosition = TRF79x0GetCollisionPosition();
+
+ if(iCollPosition < 0)
+ {
+ //
+ // No collision occurred, add full response data to known bits.
+ //
+ iCollPosition = 40;
+ }
+ else
+ {
+ //
+ // Collision occurred, only add the part that was received
+ // correctly.
+ //
+ // TF7960 Collision position register is in NVB format,
+ // convert to straight bit position. This will be the number
+ // of bits that were the same in all responding cards.
+ //
+ iCollPosition -= 0x20;
+ iCollPosition = ((iCollPosition >> 4) * 8) + (iCollPosition & 0xf);
+ }
+
+ //
+ // Bounds check the results and return 0 if it was invalid.
+ //
+ if(iCollPosition < 0 || iCollPosition > 40)
+ {
+ return(0);
+ }
+
+ //
+ // Mask out the invalid bits in the last byte of the response, if
+ // any.
+ //
+ // Graphic:
+ // UID bytes: | first || second || third || fourth || fifth |
+ // | iValidBits |
+ // | iCollPosition |
+ // In this graphic the first byte is fully valid. The second byte
+ // was sent partially invalid, but should have been masked on a
+ // previous run. The third byte is received partially invalid and
+ // needs to be masked. Response will only contain the second and
+ // third byte (although both are received properly byte-aligned).
+ //
+ //
+ // This many bits in response are valid or at least compatible
+ // with the UID.
+ //
+ iMaskPosition = iCollPosition - (iValidBits / 8) * 8;
+
+ if(iMaskPosition % 8)
+ {
+ //
+ // Need to construct a mask for iMaskPosition%8 bits and
+ // apply it at iMaskPosition/8.
+ //
+ pucResponse[iMaskPosition / 8] &= ~((~0) << (iMaskPosition % 8));
+ }
+
+ //
+ // Merge in up to iMaskPosition/8 (rounded up) byte into response
+ // at index iBitPos/8 (rounded down).
+ //
+ for(iIdx = 0; iIdx < (iMaskPosition + 7) / 8; iIdx++)
+ {
+ psState->ucUID[(psState->iBitPos / 8) + iIdx] |=
+ pucResponse[iIdx];
+ }
+
+ psState->iBitPos += iCollPosition - iValidBits;
+
+ //
+ // Only within this cascade level:
+ //
+ if(psState->iBitPos % 40 != 0)
+ {
+ //
+ // Mark backtracking point.
+ //
+ psState->ucCollisions[psState->iBitPos / 8] |=
+ 1 << (psState->iBitPos % 8);
+
+ //
+ // Walk into the 0 direction.
+ //
+ psState->iBitPos += 1;
+ }
+ }
+ else
+ {
+ //
+ // Select command.
+ //
+ TRF79x0Transceive(pucCmd, pucCmd[1] >> 4, pucCmd[1] & 0xf,
+ pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ if(uiRxSize == 1)
+ {
+ //
+ // SAK received.
+ //
+ if(pucResponse[0] & 0x04)
+ {
+ //
+ // UID not complete, increase cascade level.
+ //
+ iCascadeLevel++;
+
+ if(iCascadeLevel > 3)
+ {
+ break;
+ }
+ }
+ else
+ {
+ //
+ // UID complete, return.
+ //
+ break;
+ }
+ }
+ else
+ {
+ //
+ // Some error, card not selected.
+ //
+ memset(psState->ucUID, 0, sizeof(psState->ucUID));
+ psState->iBitPos = 0;
+ break;
+ }
+ }
+ }
+
+ //
+ // Some error, not fully selected.
+ //
+ if(((psState->iBitPos % 40) != 0) || (psState->iBitPos == 0))
+ {
+ return(0);
+ }
+
+ //
+ // Fully selected a card. pucResponse[0] should be from the last
+ // transaction, of a SELECT command, and therefore contain the SAK
+ //
+ if(pucSAK != NULL)
+ {
+ *pucSAK = pucResponse[0];
+ }
+
+ //
+ // If requested, return the UID, without cascade tag and BCC.
+ //
+ if(pucUID != NULL && puiUIDSize != NULL)
+ {
+ iMaxLength = *puiUIDSize;
+ iPos = 0;
+ *puiUIDSize = 0;
+
+ //
+ // From the 5 bytes in each cascade level the 3 middle bytes need to be
+ // copied for each level except for the last, where the first 4 bytes
+ // need to be copied.
+ //
+ for(iPos = 0; iPos < psState->iBitPos / 8; iPos += 5)
+ {
+ if(iPos + 5 < psState->iBitPos / 8)
+ {
+ //
+ // Not the last cascade level.
+ //
+ if(*puiUIDSize + 3 > iMaxLength)
+ {
+ //
+ // Not enough space
+ //
+ *puiUIDSize = 0;
+ break;
+ }
+
+ //
+ // Copy 3 bytes (e.g. don't copy cascade tag and BCC).
+ //
+ memcpy(pucUID + *puiUIDSize, psState->ucUID + iPos + 1, 3);
+
+ *puiUIDSize += 3;
+ }
+ else
+ {
+ //
+ // Last cascade level.
+ //
+ if(*puiUIDSize + 4 > iMaxLength)
+ {
+ //
+ // Not enough space.
+ //
+ *puiUIDSize = 0;
+
+ break;
+ }
+
+ //
+ // Copy 4 bytes (e.g. don't copy BCC).
+ //
+ memcpy(pucUID + *puiUIDSize, psState->ucUID + iPos, 4);
+
+ *puiUIDSize += 4;
+ }
+ }
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+// Selects the first (or only) card and returns its UID, UID length and
+// SAK bytes.
+//
+// \param ucCmd must be ISO14443A_REQA or ISO14443A_WUPA.
+// \param pucUID will store UID of the card that was selected. May be NULL
+// in which case the UID will not be returned.
+// \param puiUIDSize must be initialized with the length of the buffer in
+// \e pucUID and will return the number of bytes actually stored.
+// \param pucSAK will store the SAK byte of the card that was selected and may
+// be NULL in which case the SAK byte will not be returned.
+//
+// The function call initializes and updates a static internal state that
+// marks the position in the anti-collision procedure. ISO14443ASelectNext()
+// can be used to continue with the anti-collision from that starting point.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return Function returns 1 if a card was selected, 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelectFirst(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ //
+ // Initialize/clear static state.
+ //
+ memset(&g_sAnticolState, 0, sizeof(g_sAnticolState));
+
+ //
+ // Wake up all or only new tags.
+ //
+ if(ISO14443AREQA(ucCmd, NULL) == 0)
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&g_sAnticolState, pucUID, puiUIDSize, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Selects the next card and returns its UID, UID length and SAK bytes.
+//
+// \param ucCmd must be ISO14443A_REQA or ISO14443A_WUPA.
+// \param UID will store UID of the card that was selected and may be NULL
+// in which case the UID will not be returned.
+// \param puiUIDSize must be initialized with the length of the buffer in
+// \e UID and will return the number of bytes actually stored.
+// \param pucSAK will store the SAK byte of the card that was selected and may
+// be NULL in which case the SAK byte will not be returned.
+//
+// Uses the state that was initialized by ISO14443SelectFirst() and tries
+// to find more cards in the field.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return This function returns 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelectNext(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ //
+ // Backtrack through static state: starting at iBitPos and going reverse,
+ // find the first bit that's set in collisions, walk into the 1 direction,
+ // clear the collision indicator and set iBitPos to that position.
+ //
+ while(--g_sAnticolState.iBitPos > 0)
+ {
+ //
+ // Clear UID bit at this position to clean the state.
+ //
+ g_sAnticolState.ucUID[g_sAnticolState.iBitPos / 8] &=
+ ~(1 << (g_sAnticolState.iBitPos % 8));
+
+ if(g_sAnticolState.ucCollisions[g_sAnticolState.iBitPos / 8] &
+ (1 << (g_sAnticolState.iBitPos % 8)))
+ {
+ //
+ // This is our new starting point, set UID bit to walk into the
+ // 1 direction.
+ //
+ g_sAnticolState.ucUID[g_sAnticolState.iBitPos / 8] |=
+ 1 << (g_sAnticolState.iBitPos % 8);
+
+ //
+ // Remove backtracking marker.
+ //
+ g_sAnticolState.ucCollisions[g_sAnticolState.iBitPos / 8] &=
+ ~(1 << (g_sAnticolState.iBitPos % 8));
+
+ //
+ // Increment bit position to account for the bit that we just
+ // added, then break loop to perform anti-collision with the new
+ // partial UID.
+ //
+ g_sAnticolState.iBitPos++;
+
+ break;
+ }
+
+ //
+ // Not a backtracking point, go further back.
+ //
+ }
+
+ //
+ // No further backtracking points -> no other cards.
+ //
+ if(g_sAnticolState.iBitPos <= 0)
+ {
+ return(0);
+ }
+
+ //
+ // Wake up all or only new tags.
+ //
+ if(!ISO14443AREQA(ucCmd, NULL))
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&g_sAnticolState, pucUID, puiUIDSize, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Selects a card with given UID and return its SAK byte.
+//
+// \param pucUID must point to the UID of the card that should be selected and
+// may not be NULL.
+// \param uiUIDSize must be the length in bytes of the UID stored in \e pucUID.
+// \param pucSAK will store the SAK byte of the card that was selected. May be
+// \b NULL in which case the SAK byte will not be returned.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return This function will return 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelect(unsigned char const *pucUID, unsigned int uiUIDSize,
+ unsigned char *pucSAK)
+{
+ int iIdx, iPos;
+ struct ISO14443AAnticolState sState;
+
+ //
+ // Check if the given UID size is supported.
+ //
+ if((uiUIDSize != 4) && (uiUIDSize != 7) && (uiUIDSize != 10))
+ {
+ return(0);
+ }
+
+ //
+ // Prepare a state for the given UID.
+ //
+ sState.iBitPos = 0;
+
+ for(iPos = 0; iPos < uiUIDSize;)
+ {
+ //
+ // Check if this is the final cascade level.
+ //
+ if(iPos + 4 < uiUIDSize)
+ {
+ //
+ // If this was not the final cascade level then add a cascade tag.
+ //
+ sState.ucUID[sState.iBitPos / 8] = 0x88;
+
+ //
+ // Copy three bytes of UID.
+ //
+ memcpy(sState.ucUID + (sState.iBitPos / 8) + 1, pucUID + iPos, 3);
+
+ //
+ // Increment position in UID.
+ //
+ iPos += 3;
+ }
+ else
+ {
+ //
+ // For the final cascade level just copy four bytes of UID.
+ //
+ memcpy(sState.ucUID + (sState.iBitPos / 8), pucUID + iPos, 4);
+
+ //
+ // Increment position in UID.
+ //
+ iPos += 4;
+ }
+
+ //
+ // Calculate BCC.
+ //
+ sState.ucUID[sState.iBitPos / 8 + 4] = 0;
+
+ for(iIdx = 0; iIdx < 4; iIdx++)
+ {
+ sState.ucUID[sState.iBitPos / 8 + 4] ^=
+ sState.ucUID[sState.iBitPos / 8 + iIdx];
+ }
+
+ //
+ // Increment position in state.
+ //
+ sState.iBitPos += 40;
+ }
+
+ //
+ // Always wake up all cards.
+ //
+ if(!ISO14443AREQA(ISO14443A_WUPA, NULL))
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&sState, NULL, NULL, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Helper functions for ISO 14443-A frames to be sent or received in Direct
+// Mode.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Calculates odd parity for one byte.
+//
+//*****************************************************************************
+static unsigned char
+ParityByte(unsigned char ucByte)
+{
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ return((ucByte & 1) ^ 1);
+}
+
+//*****************************************************************************
+//
+// Checks that data has correct (odd) parity
+//
+// \param pusData is the data buffer to check and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData.
+//
+// \return This function returns 1 if the parity was correct and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ACheckParity(const unsigned short * const pusData, const long lSize)
+{
+ int iFailed, iIdx;
+
+ iFailed = 0;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ iFailed |= (pusData[iIdx] >> 8) ^ ParityByte(pusData[iIdx] & 0xff);
+ }
+
+ return(!iFailed);
+}
+
+//*****************************************************************************
+//
+// Sets data to correct (odd) parity
+//
+// \param pusData is the data buffer to update and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e data
+//
+//*****************************************************************************
+void
+ISO14443ACalculateParity(unsigned short * const pusData, const long lSize)
+{
+ int iIdx;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ pusData[iIdx] = (pusData[iIdx] & 0xff) |
+ (ParityByte(pusData[iIdx] & 0xff) << 8);
+ }
+}
+
+//*****************************************************************************
+//
+// Calculate CRC-A and return it.
+//
+//*****************************************************************************
+static unsigned short
+CalculateCRC(const unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+ int iIdx, iBit;
+ unsigned char ucByte, ucBit;
+
+ usCrc = 0x6363;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ ucByte = pusData[iIdx] & 0xff;
+
+ for(iBit = 0; iBit < 8; iBit++)
+ {
+ ucBit = (usCrc ^ ucByte) & 1;
+
+ ucByte >>= 1;
+ usCrc >>= 1;
+
+ if(ucBit)
+ {
+ usCrc ^= 0x8408;
+ }
+ }
+ }
+ return(usCrc);
+}
+
+//*****************************************************************************
+//
+// Check that data has correct CRC in last two bytes.
+//
+// \param pusData is the data buffer to check and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData.
+// Must be at least 2, since the CRC consists of two bytes.
+//
+// \return This function returns 1 if the CRC was correct and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ACheckCRC(const unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+
+ if(lSize < 2)
+ {
+ return(0);
+ }
+
+ usCrc = CalculateCRC(pusData, lSize - 2);
+
+ if(((usCrc & 0xff) == (pusData[lSize - 2] & 0xff)) &&
+ (((usCrc >> 8) & 0xff) == (pusData[lSize - 1] & 0xff)))
+ {
+ return(1);
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Appends correct CRC to the data
+//
+// \param pusData is the data buffer to update and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData. The
+// buffer in \e pusData must have room for an additional two logical bytes.
+//
+// \return This function returns the new length to correctly append the CRC.
+//
+//*****************************************************************************
+long
+ISO14443ACalculateCRC(unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+
+ usCrc = CalculateCRC(pusData, lSize);
+
+ pusData[lSize] = usCrc & 0xff;
+ pusData[lSize + 1] = (usCrc >> 8) & 0xff;
+
+ ISO14443ACalculateParity(pusData + lSize, 2);
+
+ return(lSize + 2);
+}
diff --git a/nfclib/iso14443a.h b/nfclib/iso14443a.h new file mode 100644 index 0000000..274ada7 --- /dev/null +++ b/nfclib/iso14443a.h @@ -0,0 +1,65 @@ +//*****************************************************************************
+//
+// iso14443a.h - ISO 14443A implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443A_H__
+#define __ISO14443A_H__
+
+//
+// REQA command, which wakes cards from IDLE state and puts them into READY
+// state. One of the two possible parameters for \e ucCmd in
+// ISO14443ASelectFirst() and ISO14443ASelectNext().
+//
+#define ISO14443A_REQA 0x26
+//
+// WUPA command, which wakes cards from IDLE or HALT state and puts them
+// into READY or READY* state. One of the two possible parameters for
+// \e ucCmd in ISO14443ASelectFirst() and ISO14443ASelectNext().
+//
+#define ISO14443A_WUPA 0x52
+
+extern void ISO14443ASetupRegisters(void);
+extern void ISO14443APowerOn(void);
+extern void ISO14443APowerOff(void);
+extern void ISO14443AHalt(void);
+extern int ISO14443AREQA(unsigned char ucCmd, int *piATQA);
+extern int ISO14443ASelect(unsigned char const *pucUID,
+ unsigned int uiUIDLength, unsigned char *pucSAK);
+extern int ISO14443ASelectFirst(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDLength,
+ unsigned char *pucSAK);
+extern int ISO14443ASelectNext(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDLength,
+ unsigned char *pucSAK);
+extern int ISO14443ACheckParity(const unsigned short * const pusData,
+ const long lLen);
+extern void ISO14443ACalculateParity(unsigned short * const pusData,
+ const long lLen);
+extern int ISO14443ACheckCRC(const unsigned short * const pusData,
+ const long lLen);
+extern long ISO14443ACalculateCRC(unsigned short * const pusData, const long lSize);
+
+extern int ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS);
+extern int ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI);
+extern int ISO14443DESELECT(unsigned char ucCID);
+#endif
diff --git a/nfclib/iso14443b.c b/nfclib/iso14443b.c new file mode 100644 index 0000000..a7cd7fb --- /dev/null +++ b/nfclib/iso14443b.c @@ -0,0 +1,339 @@ +//*****************************************************************************
+//
+// iso14443B.c - ISO 14443B implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443b.h"
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 B 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0Command() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+ISO14443BSetupRegisters(void)
+{
+ //
+ // Set the ISO format to ISO1443B 106Kbps.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_14443B_106K);
+
+ //
+ // Set the TX pulse to 106ns (0x20 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 66us (7 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation 10% ASK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ);
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_M848);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+}
+
+//*****************************************************************************
+//
+// Power on the field and wait for a time that is long enough to guarantee
+// that all cards in the field will be initialized.
+//
+//*****************************************************************************
+void
+ISO14443BPowerOn(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Enable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg | TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms (as per ISO 14443-3 clause 5).
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Power off the field and wait for some time.
+//
+//*****************************************************************************
+void
+ISO14443BPowerOff(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Disable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg & ~TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+int
+ISO14443BHalt(unsigned char *pucPUPI)
+{
+ unsigned char ucResponse;
+ unsigned int uiRxSize;
+
+ //
+ // HLTA command.
+ //
+ unsigned char pucHLTA[5];
+
+ pucHLTA[0] = 0x50;
+ pucHLTA[1] = pucPUPI[0];
+ pucHLTA[2] = pucPUPI[1];
+ pucHLTA[3] = pucPUPI[2];
+ pucHLTA[4] = pucPUPI[3];
+
+ TRF79x0Transceive(pucHLTA, sizeof(pucHLTA), 0, &ucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // Valid answer to HLTB received.
+ if((uiRxSize == 1) && (ucResponse == 0))
+ return(uiRxSize);
+ else
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-B SlotMARKER command.
+//
+// \param ucSlot is the slot number for the following operations, must between 1~15
+//
+//*****************************************************************************
+void
+ISO14443BSlotMARKER(unsigned char ucSlot)
+{
+ unsigned char ucAPn;
+
+ ucAPn = (ucSlot << 4) | 0x05;
+
+ TRF79x0Transceive(&ucAPn, 1, 0, 0, 0, 0, TRF79X0_TRANSCEIVE_CRC);
+// TRF79x0Send(&ucAPn, 1, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-B REQB type command.
+//
+// \param ucCmd is the command, either \b ISO14443B_REQB or \b ISO14443B_WUPB
+// \param ucAFI is the application family identifier
+// \param ucN is the number of the time slot that was used in anticollision process,
+// must between 0 ~ 4
+// \param piATQB is a pointer to an integer to store the received ATQB and
+// will be set to -1 if a collision occurred.
+//
+// \return true if at least one card responded and false
+// otherwise.
+//
+// \note User code usually does not need to call this function since it is
+// implicitly called in ISO14443BSelect(), ISO14443bSelectFirst() or
+// ISO14443BSelectNext().
+//
+//*****************************************************************************
+int
+ISO14443BREQB(unsigned char ucCmd, unsigned char ucAFI, unsigned char ucN,
+ unsigned char *pucATQB, unsigned int *puiATQBSize)
+{
+ unsigned char pucREQB[3];
+ unsigned char pucResponse[12];
+ unsigned int uiRxSize;
+ int i, slotTotal, slot;
+
+ switch(ucN)
+ {
+ case 0: slotTotal = 1; break;
+ case 1: slotTotal = 2; break;
+ case 2: slotTotal = 4; break;
+ case 3: slotTotal = 8; break;
+ case 4: slotTotal = 16; break;
+ default: slotTotal = 1; break;
+ }
+
+ uiRxSize = sizeof(pucResponse);
+ pucResponse[0] = 0;
+
+ //
+ // Transmit WUPB/REQB, receive ATQB.
+ //
+ pucREQB[0] = 0x05;
+ pucREQB[1] = ucAFI;
+ pucREQB[2] = ucCmd | ucN;
+
+ //
+ // the first byte of ATQB is 0x50
+ //
+ TRF79x0Transceive(pucREQB, sizeof(pucREQB), 0, pucResponse, &uiRxSize, 0,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((pucResponse[0] != 0x50) && (slot < slotTotal))
+ {
+ uiRxSize = 12;
+ pucResponse[0] = 0;
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO14443BSlotMARKER(slot++);
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ };
+
+ //
+ // Valid ATQB received. Was transmitted LSByte first.
+ //
+ if(pucResponse[0] == 0x50)
+ {
+ if(pucATQB != NULL)
+ {
+ for(i = 0; i < uiRxSize; i++)
+ pucATQB[i] = pucResponse[i];
+ }
+ *puiATQBSize = uiRxSize;
+
+ //
+ // Return true
+ //
+ return(1);
+ }
+ else
+ {
+ //
+ // No response at all
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-3 ATTRIB command.
+// EOF_SOF indicate the PCD capability to support suppression of the EOF and/or SOF
+// from PICC to PCD, which may reduce communication overhead.
+// The suppression of EOF and/or SOF is optional for the PICC.
+// SOF/EOF suppression applies only for communications at fc / 128 (~ 106 kbit/s).
+// For bit rates higher than fc / 128 (~ 106 kbit/s) the PICC shall always provide SOF and EOF
+// EOF_SOF set 0 indicate SOF&EOF required.
+//
+// ucTR1 & ucTR0 must between 0~2
+//
+//*****************************************************************************
+int
+ISO14443BATTRIB(unsigned char *pucPUPI, unsigned char ucTR0, unsigned char ucTR1, unsigned char ucEOF_SOF,
+ unsigned char ucMaxFrameSize, unsigned char ucBitRateD2C, unsigned char ucBitRateC2D,
+ unsigned char ucProtocolType, unsigned char ucCID, unsigned char *A2ATTRIB)
+{
+ unsigned char pucResponse[3];
+ unsigned int uiRxSize;
+ unsigned char pucATTRIB[9];
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // ATTRIB command.
+ //
+ pucATTRIB[0] = 0x1D;
+ pucATTRIB[1] = pucPUPI[0];
+ pucATTRIB[2] = pucPUPI[1];
+ pucATTRIB[3] = pucPUPI[2];
+ pucATTRIB[4] = pucPUPI[3];
+ pucATTRIB[5] = (ucTR0 << 6) | (ucTR1 << 4) | (ucEOF_SOF << 3) | (ucEOF_SOF << 2);
+ pucATTRIB[6] = (ucBitRateC2D << 6) | (ucBitRateD2C << 4) | ucMaxFrameSize;
+ pucATTRIB[7] = ucProtocolType & 0x0F;
+ pucATTRIB[8] = ucCID & 0x0F;
+
+ //
+ // Transmit ATTRIB without higher layer INF, receive answer to ATTRIB command without higher layer response
+ //
+ TRF79x0Transceive(pucATTRIB, sizeof(pucATTRIB), 0, pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ if(uiRxSize == 1 )
+ {
+ //
+ // Valid answer to ATTRIB command received, return it as an char, uiRxSize NOT including two CRC bytes
+ //
+ if(A2ATTRIB != NULL)
+ *A2ATTRIB = pucResponse[0];
+
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
diff --git a/nfclib/iso14443b.h b/nfclib/iso14443b.h new file mode 100644 index 0000000..16b2e3c --- /dev/null +++ b/nfclib/iso14443b.h @@ -0,0 +1,51 @@ +//*****************************************************************************
+//
+// iso14443b.h - ISO 14443B implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443B_H__
+#define __ISO14443B_H__
+
+//
+// REQB command, which wakes cards from IDLE state and puts them into READY
+// state. One of the two possible parameters for \e ucCmd in
+// ISO14443BSelectFirst() and ISO14443BSelectNext().
+//
+#define ISO14443B_REQB 0x00
+//
+// WUPB command, which wakes cards from IDLE or HALT state and puts them
+// into READY or READY* state. One of the two possible parameters for
+// \e ucCmd in ISO14443BSelectFirst() and ISO14443BSelectNext().
+//
+#define ISO14443B_WUPB 0x08
+
+extern void ISO14443BSetupRegisters(void);
+extern void ISO14443BPowerOn(void);
+extern void ISO14443BPowerOff(void);
+extern int ISO14443BHalt(unsigned char *pucPUPI);
+extern int ISO14443BREQB(unsigned char ucCmd, unsigned char ucAFI, unsigned char ucN,
+ unsigned char *pucATQB, unsigned int *puiATQBSize );
+extern int ISO14443BATTRIB(unsigned char *pucPUPI, unsigned char ucTR0, unsigned char ucTR1, unsigned char ucEOF_SOF,
+ unsigned char ucMaxFrameSize, unsigned char ucBitRateD2C, unsigned char ucBitRateC2D,
+ unsigned char ucProtocolType, unsigned char ucCID, unsigned char *A2ATTRIB);
+
+#endif
diff --git a/nfclib/iso15693.c b/nfclib/iso15693.c new file mode 100644 index 0000000..dc32578 --- /dev/null +++ b/nfclib/iso15693.c @@ -0,0 +1,694 @@ +//*****************************************************************************
+//
+// iso15693.c - The top level API used to communicate with ISO15063 cards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "nfclib/iso15693.h"
+
+extern struct
+{
+ //
+ // The actual string of bytes in the UID.
+ //
+ unsigned char pucUID[UID_SIZE];
+
+ //
+ // The number of valid bytes in the pucUID variable.
+ //
+ unsigned long ulUIDSize;
+
+ //
+ // The ASCII string that is used to display the UID on the screen.
+ //
+ char pcUIDStr[CARD_LABEL_SIZE];
+
+ unsigned char ucSlot;
+}g_sCard_15693[16];
+
+//*****************************************************************************
+//
+// Command/Response and transmit/receive buffer.
+//
+//*****************************************************************************
+static unsigned char g_pucCmd[16];
+
+//*****************************************************************************
+//
+// The value that is written to the block if the "Erase" button is pressed.
+// This will invalidate the block.
+//
+//*****************************************************************************
+static const unsigned char g_pucValueEmpty[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char ucCardFound = 0;
+
+//*****************************************************************************
+//
+// Set up registers for ISO 15693 operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0Command() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO15963 functions.
+//
+//*****************************************************************************
+void
+ISO15693SetupRegisters(void)
+{
+ // actually, we can just use the default setting
+#if 0
+ //
+ // Set the TX pulse to 9.44us (0x80 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x80);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 293us (0x20 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x20);
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_C424);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+#endif
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation Depth to OOK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ (TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ |
+ TRF79X0_MOD_CTRL_MOD_ASK_10));
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ TRF79X0_STATUS_CTRL_RF_ON | TRF79X0_STATUS_CTRL_RF_PWR_FULL
+ | TRF79X0_STATUS_CTRL_5V_OPERATION);
+
+ //
+ // Set the ISO format to ISO15693 high bit rate, 26.48 kbps, one subcarrier, 1 out of 4
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT4);
+}
+
+//*****************************************************************************
+//
+//! Initializes the ISO15693 utility functions.
+//!
+//! This function prepares the ISO1593 utility functions so that they are
+//! prepared for the remaining ISO1593 calls. This function must be called once
+//! before calling any other ISO1593 functions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISO15693Init(void)
+{
+ //
+ // Initialize RFID hardware.
+ //
+ TRF79x0Init();
+
+ //
+ // Set up ISO 15693 operation.
+ //
+ ISO15693SetupRegisters();
+}
+
+void
+ISO15693NextSlot(void)
+{
+ TRF79x0Command(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0Command(TRF79X0_RUN_DECODERS_CMD);
+ TRF79x0Command(TRF79X0_RESET_FIFO_CMD);
+ TRF79x0Command(TRF79X0_TRANSMIT_NEXT_SLOT_CMD);
+}
+
+//
+// \ucSubCarrier,
+// 0 A single sub-carrier frequency shall be used by the VICC
+// 1 Two sub-carriers shall be used by the VICC
+// \ucDataRate
+// 0 Low data rate shall be used
+// 1 High data rate shall be used
+// \ucNbSlots
+// 0 16 slots
+// 1 1 slot
+//
+int
+ISO15693InventoryAFI(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucAfi, unsigned char ucNbSlots,
+ unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10];
+ unsigned int uiRxSize, i, slot;
+
+ uiRxSize = 10;
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (ucNbSlots << 5) | (0x1 << 4) | (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[2] = ucAfi;
+ g_pucCmd[3] = ucMaskLen;
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 4, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((uiRxSize != 10) && (slot < 16))
+ {
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ if(uiRxSize == 10 )
+ {
+ //
+ // Valid answer to Inventory command received, return it as an char, uiRxSize NOT including two CRC bytes
+ // the first 2 byte in pucResponse is Flags & DSFI, the last 8 bytes is UID
+ //
+ if(pucMask != NULL)
+ {
+ for(i = 0; i < 8; i++)
+ pucMask[i] = pucResponse[2 + i];
+ }
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+//
+// \ucSubCarrier,
+// 0 A single sub-carrier frequency shall be used by the VICC
+// 1 Two sub-carriers shall be used by the VICC
+// \ucDataRate
+// 0 Low data rate shall be used
+// 1 High data rate shall be used
+// \ucNbSlots
+// 0 16 slots
+// 1 1 slot
+//
+int
+ISO15693Inventory(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucNbSlots, unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10];
+ unsigned char uiRxSize, i, slot;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (ucNbSlots << 5) | (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[3] = ucMaskLen;
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 3, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((uiRxSize != 10) && (slot < 16))
+ {
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ if(uiRxSize == 10 )
+ {
+ //
+ // Valid answer to Inventory command received, return it as an char, uiRxSize NOT including two CRC bytes
+ //
+ if(pucMask != NULL)
+ {
+ for(i = 0; i < uiRxSize; i++)
+ pucMask[i] = pucResponse[i];
+ }
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+int
+ISO15693Anticollision16Slots(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10], ucMaskNew[8];
+ unsigned int uiRxSize, uiTxSize, i, slot = 0;
+ unsigned int uiFlagCollision = 0, uiSlotCollision = 0;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[2] = ucMaskLen;
+
+ uiTxSize = 3 + (((ucMaskLen >> 2) + 1) >> 1);
+
+ if(uiTxSize > 3)
+ {
+ for(i = 0; i < (uiTxSize - 3); i++)
+ g_pucCmd[3 + i] = pucMask[i];
+ }
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, uiTxSize, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ while(slot < 16)
+ {
+ if(TRF79x0IsCollision() == 1)
+ {
+ uiFlagCollision = 1;
+ uiSlotCollision = slot -1;
+ }
+ else if(uiRxSize == 10)
+ {
+ for(i = 0; i < 8; i++)
+ g_sCard_15693[ucCardFound + 1].pucUID[i] = pucResponse[2 + i];
+ g_sCard_15693[ucCardFound + 1].ucSlot = slot;
+ ucCardFound++;
+ }
+
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ //
+ // only do ones cascade
+ // TODO: NEED refer to the msp430 version to make more cascade anticollision function
+ //
+ if(uiFlagCollision && (ucMaskLen < 4))
+ {
+ uiFlagCollision = 0;
+ ucMaskNew[0] = uiSlotCollision;
+ ISO15693Anticollision16Slots(0, 1, &ucMaskNew[0], ucMaskLen + 4);
+ }
+
+ if(ucCardFound)
+ {
+ ucCardFound = 0;
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+int
+ISO15693StayQuiet(unsigned char *pucUID)
+{
+ int i;
+
+ //
+ // Prepare Stay Quiet command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ g_pucCmd[0] = (1 << 5) | (1 << 1);
+ // Command Code = 0x02 ---> Stay Quiet
+ g_pucCmd[1] = 0x02;
+ for(i = 0; i < 8; i++)
+ g_pucCmd[2 + i] = pucUID[i];
+
+ //
+ // Transmit Stay Quiet command, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 10, 0, 0, 0, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+}
+
+//*****************************************************************************
+//
+// ! Reads a single block data from the selected card.
+// !
+// ! \param uiBlock is the address of the block to read.
+// ! \param pucBuf is the output buffer to store the raw block contents into.
+// ! This buffer must be able to store at least 32 bytes.
+// !
+// ! This function reads a ISO15693 block and returns the full contents
+// ! of the block with no interpretation of the bytes. The function will
+// ! return the number of valid bytes stored in the \e pucBuf parameter.
+// !
+//
+//*****************************************************************************
+int
+BlockReadSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[11];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 32;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ // b7 Option_flag
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) |(1 << 5) | (1 << 1);
+ // Command Code = 0x20 ---> Read Single Block
+ pucCmd[1] = 0x20;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0Transceive(pucCmd, sizeof(pucCmd), 0, pucBuf, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockReadSingle(unsigned int uiBlock, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[3];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 32;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b7 Option_flag
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x20 ---> Read Single Block
+ pucCmd[1] = 0x20;
+ pucCmd[2] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0Transceive(pucCmd, sizeof(pucCmd), 0, pucBuf, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+//*****************************************************************************
+//
+// ! Write a single block data to the selected card.
+// !
+// ! \param uiBlock is the address of the block to write.
+// ! \param pucBuf is the input buffer to store the raw block contents into.
+// ! This buffer must be able to store at least 32 bytes.
+// !
+// ! This function write a ISO15693 block
+// !
+//
+//*****************************************************************************
+int
+BlockWriteSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[43];
+ unsigned char pucResponse[2];
+ unsigned int uiRxBytes;
+ int i;
+
+ //
+ // transmit bytes as most
+ //
+ uiRxBytes = 2;
+
+ //
+ // Prepare Write Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 5) | (1 << 1);
+ // Command Code = 0x21 ---> Write Single Block
+ pucCmd[1] = 0x21;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+ for(i = 0; i < ucValueLen; i++)
+ pucCmd[11 + i] = pucBuf[i];
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, 11 + ucValueLen, 0, pucResponse, &uiRxBytes, 0, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockWriteSingle(unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[7];
+ unsigned char pucResponse[2];
+ unsigned int uiRxBytes;
+ int i;
+
+ //
+ // transmit bytes as most
+ //
+ uiRxBytes = 2;
+
+ //
+ // Prepare Write Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x21 ---> Write Single Block
+ pucCmd[1] = 0x21;
+ pucCmd[2] = uiBlock;
+ for(i = 0; i < ucValueLen; i++)
+ pucCmd[3 + i] = pucBuf[i];
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, 3 + ucValueLen, 0, pucResponse, &uiRxBytes, 0, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockLockSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucResponse)
+{
+ unsigned char pucCmd[11];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 2;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 5) | (1 << 1);
+ // Command Code = 0x22 ---> Lock Single Block
+ pucCmd[1] = 0x22;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, sizeof(pucCmd), 0, pucResponse, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockLockSingle(unsigned int uiBlock, unsigned char *pucResponse)
+{
+ unsigned char pucCmd[3];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 2;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x22 ---> Lock Single Block
+ pucCmd[1] = 0x22;
+ pucCmd[2] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, sizeof(pucCmd), 0, pucResponse, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
diff --git a/nfclib/iso15693.h b/nfclib/iso15693.h new file mode 100644 index 0000000..574b199 --- /dev/null +++ b/nfclib/iso15693.h @@ -0,0 +1,62 @@ +//*****************************************************************************
+//
+// iso15693.h - The top level API used to communicate with MIFARE cards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#ifndef __ISO15693_H__
+#define __ISO15693_H__
+
+//*****************************************************************************
+//
+// The maximum size in bytes of a card's UID in ASCII.
+//
+//*****************************************************************************
+#define UID_SIZE 8
+
+
+//*****************************************************************************
+//
+// The size in card label string for the card's UID. Two characters per byte
+// and a spot for a null terminator.
+//
+//*****************************************************************************
+#define CARD_LABEL_SIZE (6 + (UID_SIZE * 2) + 1)
+
+extern void ISO15693Init(void);
+extern int ISO15693InventoryAFI(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucAfi, unsigned char ucNbSlots,
+ unsigned char *pucMask, unsigned char ucMaskLen);
+extern int ISO15693Inventory(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucNbSlots, unsigned char *pucMask, unsigned char ucMaskLen);
+extern int ISO15693Anticollision16Slots(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char *pucMask, unsigned char ucMaskLen);
+
+extern int BlockReadSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucBuf);
+extern int BlockWriteSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf);
+extern int BlockLockSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucResponse);
+
+extern int BlockReadSingle(unsigned int uiBlock, unsigned char *pucBuf);
+extern int BlockWriteSingle(unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf);
+extern int BlockLockSingle(unsigned int uiBlock, unsigned char *pucResponse);
+
+extern int ISO15693StayQuiet(unsigned char *pucUID);
+
+#endif
+
diff --git a/nfclib/llcp.c b/nfclib/llcp.c new file mode 100644 index 0000000..9a878ea --- /dev/null +++ b/nfclib/llcp.c @@ -0,0 +1,1051 @@ +//*****************************************************************************
+//
+// llcp.c - Logic Link Control Protocol : used to send packets via NPP or SNEP
+// NPP: NDEF Push Protocol
+// SNEP: Simple NDEF Exchange protocol
+// NOTE: currently only SNEP is Supported
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "utils/uartstdio.h"
+#include "nfclib/llcp.h"
+#include "nfclib/snep.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_llcp_api NFC LLCP API Functions
+//! @{
+//! Logical Link Control Protocol is the NFC transport layer used to open and
+//! close a virtual link used to transfer NDEFs between two devices in
+//! peer-to-peer mode via the Simple NDEF Exchange Protocol.
+//! For more information on LLCP, please read the Logical Link Control Protocol
+//! Specification Version 1.1.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The next PDU to be sent to the destination device - updated based on
+// incoming packets or by LLCPSetNextPDU().
+//
+//*****************************************************************************
+tLLCPPduPtype g_eNextPduQueue = LLCP_SYMM_PDU;
+
+//*****************************************************************************
+//
+// Connection Status
+//
+//*****************************************************************************
+tLLCPConnectionStatus g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+
+//*****************************************************************************
+//
+// Destination Service Access Point Address
+//
+//*****************************************************************************
+uint8_t g_ui8dsapValue;
+
+//*****************************************************************************
+//
+// Source Service Access Point Address
+//
+//*****************************************************************************
+uint8_t g_ui8ssapValue;
+
+//*****************************************************************************
+//
+// Service Name - SNEP by default
+//
+//*****************************************************************************
+tServiceName g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+//*****************************************************************************
+//
+// Acknowledged packets
+//
+//*****************************************************************************
+uint8_t g_ui8NSNR = 0x00;
+
+//*****************************************************************************
+//
+// Disconnected Mode Reason
+//
+//*****************************************************************************
+tDisconnectModeReason g_eDMReason;
+
+//*****************************************************************************
+//
+// LLCP Link Time Out
+//
+//*****************************************************************************
+uint16_t g_ui16LLCPlto = 0x00;
+
+//*****************************************************************************
+//
+// LLCP MIUX of the initiator / target communicating with the TRF7970A.
+// 248 by default.
+//
+//*****************************************************************************
+uint8_t g_ui8LLCPmiu = 248;
+
+//*****************************************************************************
+//
+//! Initializes the Logical Link Control Protocol layer.
+//!
+//! This function must be called prior to any other function offer by the LLCP
+//! driver. This function initializes the acknowledge packets, the current
+//! service enabled, and the next PDU for the LLCP_stateMachine(), and also
+//! initializes the SNEP layer with SNEP_init().
+//!
+//! \return None
+//!
+//
+//*****************************************************************************
+void LLCP_init(void)
+{
+ //
+ // Reset NS and NR
+ //
+ g_ui8NSNR = 0x00;
+ g_ui8LLCPmiu = 128;
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ SNEP_init();
+ SNEP_setMaxPayload(g_ui8LLCPmiu);
+}
+
+//*****************************************************************************
+//
+//! Gets link timeout
+//!
+//! This function returns the Link Timeout, which may be modified if the
+//! LLCP_processTLV() function processes a LLCP_LTO TLV.
+//!
+//! \return \e \b g_ui16LLCPlto the link timeout.
+//
+//*****************************************************************************
+uint16_t LLCP_getLinkTimeOut(void)
+{
+ return g_ui16LLCPlto;
+}
+
+//*****************************************************************************
+//
+//! Adds a LLCP parameter to the LLCP PDU with the Type Length
+//! Value (TLV) format.
+//!
+//! \param eLLCPparam is the LLCP type that will be added.
+//! \param pui8TLVBufferPtr is the pointer where the TLV is written
+//!
+//! The \e \b eLLCPparam parameter can be any of the following:
+//!
+//! - \b LLCP_VERSION - Version Number
+//! - \b LLCP_MIUX - Maximum Information Unit Extension
+//! - \b LLCP_WKS - Well-Known Service List
+//! - \b LLCP_LTO - Link Timeout
+//! - \b LLCP_RW - Receive Window Size
+//! - \b LLCP_SN - Service Name
+//! - \b LLCP_OPT - Option
+//! - \b LLCP_SDREQ - Service Discovery Request
+//! - \b LLCP_SDRES - Service Discovery Response
+//! - \b LLCP_ERROR - Reserved (used ro return length of 0)
+//!
+//! This function is used to add a LLCP Parameter to the LLCP PDU to include
+//! more information about the LLCP layer. This function must be called inside
+//! LLCP_sendCONNECT(), LLCP_sendCC(), NFCDEP_sendATR_REQ() and
+//! NFCDEP_sendATR_RES().
+//!
+//! \return ui8PacketLength Length of the LLCP Parameter added to the LLCP.
+//
+//*****************************************************************************
+uint8_t LLCP_addTLV(tLLCPParamaeter eLLCPparam, uint8_t * pui8TLVBufferPtr)
+{
+ uint8_t ui8PacketLength = 0;
+
+ switch(eLLCPparam)
+ {
+ case LLCP_VERSION:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_VERSION;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x11; // Version 1.1
+ break;
+ case LLCP_MIUX:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_MIUX;
+ // Length
+ pui8TLVBufferPtr[1] = 0x02;
+ // Value
+ // 128 + MIUX (120) = MIU (248)
+ pui8TLVBufferPtr[2] = (LLCP_MIUX_SIZE >> 8) & 0xFF; // MIUX 15:8
+ pui8TLVBufferPtr[3] = (uint8_t) LLCP_MIUX_SIZE; // MIUX 7:0
+ break;
+ case LLCP_WKS:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_WKS;
+ // Length
+ pui8TLVBufferPtr[1] = 0x02;
+ // Value
+ pui8TLVBufferPtr[2] = 0x00;
+ pui8TLVBufferPtr[3] = 0x03;
+ break;
+ case LLCP_LTO:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_LTO;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x64; // (100 (0x64) * 10 mS = 1000 mS timeout, Figure 22, LLP)
+ break;
+ case LLCP_RW:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_RW;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ // Section 5.6.2.2 LLP
+ // A receive window size of zero indicates that the local LLC will not
+ // accept I PDUs on that data link connection. A receive window size of
+ // one indicates that the local LLC will acknowledge every I PDU before
+ // accepting additional I PDUs.
+ //
+ pui8TLVBufferPtr[2] = 0x04;
+ break;
+ case LLCP_SN:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_SN;
+ if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // Length
+ pui8TLVBufferPtr[1] = 0x0F;
+ // Value
+ pui8TLVBufferPtr[2] = 'c';
+ pui8TLVBufferPtr[3] = 'o';
+ pui8TLVBufferPtr[4] = 'm';
+ pui8TLVBufferPtr[5] = '.';
+ pui8TLVBufferPtr[6] = 'a';
+ pui8TLVBufferPtr[7] = 'n';
+ pui8TLVBufferPtr[8] = 'd';
+ pui8TLVBufferPtr[9] = 'r';
+ pui8TLVBufferPtr[10] = 'o';
+ pui8TLVBufferPtr[11] = 'i';
+ pui8TLVBufferPtr[12] = 'd';
+ pui8TLVBufferPtr[13] = '.';
+ pui8TLVBufferPtr[14] = 'n';
+ pui8TLVBufferPtr[15] = 'p';
+ pui8TLVBufferPtr[16] = 'p';
+ }
+ else if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ // Length
+ pui8TLVBufferPtr[1] = 0x0F;
+ // Value
+ pui8TLVBufferPtr[2] = 'u';
+ pui8TLVBufferPtr[3] = 'r';
+ pui8TLVBufferPtr[4] = 'n';
+ pui8TLVBufferPtr[5] = ':';
+ pui8TLVBufferPtr[6] = 'n';
+ pui8TLVBufferPtr[7] = 'f';
+ pui8TLVBufferPtr[8] = 'c';
+ pui8TLVBufferPtr[9] = ':';
+ pui8TLVBufferPtr[10] = 's';
+ pui8TLVBufferPtr[11] = 'n';
+ pui8TLVBufferPtr[12] = ':';
+ pui8TLVBufferPtr[13] = 's';
+ pui8TLVBufferPtr[14] = 'n';
+ pui8TLVBufferPtr[15] = 'e';
+ pui8TLVBufferPtr[16] = 'p';
+
+ }
+ break;
+ case LLCP_OPT:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_OPT;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x03; // (Class 3) (Table 7, LLP)
+ break;
+ case LLCP_SDREQ:
+ break;
+ case LLCP_SDRES:
+ break;
+ default:
+ pui8TLVBufferPtr[0] = LLCP_ERROR;
+ break;
+ }
+
+ if(pui8TLVBufferPtr[0] == LLCP_ERROR)
+ ui8PacketLength = 0x00;
+ else
+ ui8PacketLength = pui8TLVBufferPtr[1] + 2;
+
+ return ui8PacketLength;
+}
+
+//*****************************************************************************
+//
+//! Processes the LLCP Parameter TLV.
+//!
+//! \param pui8TLVBufferPtr is the pointer to the Type value of the TLV.
+//!
+//! This function processes the LLCP Parameters included in the ATR_RES. This
+//! function must be called inside the NFCDEP_processReceivedData(), to
+//! initialize the g_ui8LLCPmiu and g_ui16LLCPlto if they are included as part
+//! of ATR_RES.
+//!
+//! \return None
+//
+//*****************************************************************************
+void LLCP_processTLV(uint8_t * pui8TLVBufferPtr)
+{
+ uint16_t ui16Miu;
+ switch(pui8TLVBufferPtr[0])
+ {
+ case LLCP_VERSION:
+ break;
+ case LLCP_MIUX:
+ // MIU = 128 + MIUX
+ ui16Miu = (pui8TLVBufferPtr[2] << 8)+pui8TLVBufferPtr[3]+128;
+ // Check if the received MIU is less than 248, the modify the current MIU to it
+ if(ui16Miu < 248)
+ {
+ // Modify MIU to be less
+ g_ui8LLCPmiu = (uint8_t) ui16Miu;
+
+ }
+ else
+ {
+ // Maximum supported MIU is 248
+ g_ui8LLCPmiu = 248;
+ }
+
+ SNEP_setMaxPayload(g_ui8LLCPmiu);
+ break;
+ case LLCP_WKS:
+ break;
+ case LLCP_LTO:
+ g_ui16LLCPlto = pui8TLVBufferPtr[2] * 10;
+ break;
+ case LLCP_RW:
+ break;
+ case LLCP_SN:
+ break;
+ case LLCP_OPT:
+ break;
+ case LLCP_SDREQ:
+ break;
+ case LLCP_SDRES:
+ break;
+ default:
+ break;
+ }
+}
+
+//*****************************************************************************
+//
+//! Prepares the LLCP packet to be transmitted.
+//!
+//! \param pui8PduBufferPtr is the start pointer to add the LLCP PDU.
+//!
+//! This function is used to add the LLCP portion of the DEP_REQ / DEP_RES PDU.
+//! This function must be called inside NFCDEP_sendDEP_REQ() and
+//! NFCDEP_sendDEP_RES(). It currently does not support sending the following
+//! PDUs : LLCP_PAX_PDU, LLCP_AGF_PDU, LLCP_UI_PDU, LLCP_FRMR_PDU, LLCP_SNL_PDU,
+//! LLCP_RNR_PDU, and LLCP_RESERVED_PDU.
+//!
+//! \return ui8PacketLength is the length of the LLCP PDU added to the
+//! pui8PduBufferPtr.
+//
+//*****************************************************************************
+uint8_t LLCP_stateMachine(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8PacketLength=0;
+
+ switch(g_eNextPduQueue)
+ {
+ case LLCP_SYMM_PDU:
+ {
+ //UARTprintf("TX: SYMM\n");
+ ui8PacketLength = LLCP_sendSYMM(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_PAX_PDU:
+ {
+ break;
+ }
+ case LLCP_AGF_PDU:
+ {
+ break;
+ }
+ case LLCP_UI_PDU:
+ {
+ break;
+ }
+ case LLCP_CONNECT_PDU:
+ {
+ //UARTprintf("TX: CONNECT\n");
+ ui8PacketLength = LLCP_sendCONNECT(pui8PduBufferPtr);
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ case LLCP_DISC_PDU:
+ {
+ if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ //UARTprintf("TX: DISC\n");
+ ui8PacketLength = LLCP_sendDISC(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_CC_PDU:
+ {
+ //UARTprintf("TX: CC\n");
+ ui8PacketLength = LLCP_sendCC(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_DM_PDU:
+ {
+ //UARTprintf("TX: DM\n");
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ ui8PacketLength = LLCP_sendDM(pui8PduBufferPtr,g_eDMReason);
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ case LLCP_FRMR_PDU:
+ {
+ break;
+ }
+ case LLCP_SNL_PDU:
+ {
+ break;
+ }
+ case LLCP_I_PDU:
+ {
+ //UARTprintf("TX: I\n");
+ ui8PacketLength = LLCP_sendI(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_RR_PDU:
+ {
+ //UARTprintf("TX: RR\n");
+ if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ }
+ ui8PacketLength = LLCP_sendRR(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_RNR_PDU:
+ {
+ break;
+ }
+ case LLCP_RESERVED_PDU:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return ui8PacketLength;
+}
+
+//*****************************************************************************
+//
+//! Processes LLCP Data Received.
+//!
+//! \param pui8RxBuffer is the start pointer of the LLCP data received.
+//! \param ui8PduLength is the length of the LLCP PDU received.
+//!
+//! This function is used to handle the LLCP portion of the DEP_REQ / DEP_RES PDU.
+//! This function must be called inside NFCDEP_processReceivedRequest() and
+//! NFCDEP_processReceivedData().It currently does not support to handle the
+//! following PDUs : LLCP_PAX_PDU, LLCP_AGF_PDU, LLCP_UI_PDU, LLCP_FRMR_PDU,
+//! LLCP_SNL_PDU, LLCP_RNR_PDU, and LLCP_RESERVED_PDU.
+//!
+//! \return \b eLLCPStatus is the boolean status if the command was processed
+//! (1) or not (0).
+//
+//*****************************************************************************
+tStatus LLCP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8PduLength)
+{
+ tLLCPPduPtype ePduType;
+ tStatus eLLCPStatus = STATUS_SUCCESS;
+ tSNEPConnectionStatus eSnepProtocolStatus;
+
+ ePduType = (tLLCPPduPtype) ( ((pui8RxBuffer[0] & 0x03) << 2) +
+ ((pui8RxBuffer[1] & 0xC0) >> 6));
+
+ switch(ePduType)
+ {
+ case LLCP_SYMM_PDU:
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if((g_eNextPduQueue == LLCP_CONNECT_PDU) ||
+ (g_eNextPduQueue == LLCP_I_PDU))
+ {
+ //
+ // Do no modify the next PDU
+ //
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_SEND_COMPLETE)
+ {
+ SNEP_setProtocolStatus(SNEP_CONNECTION_IDLE);
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ else if((eSnepProtocolStatus ==
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_RECEIVE_COMPLETE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_EXCESS_SIZE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS))
+ {
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_I_PDU;
+ }
+ else
+ {
+ if(g_eLLCPConnectionStatus != LLCP_CONNECTION_IDLE)
+ {
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ }
+ }
+ else if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_IDLE)
+ {
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ else
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ else
+ {
+ if(g_eLLCPConnectionStatus != LLCP_CONNECTION_IDLE)
+ {
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ }
+ break;
+ case LLCP_PAX_PDU:
+ // Not Supported
+ break;
+ case LLCP_AGF_PDU:
+ // Not Supported
+ break;
+ case LLCP_UI_PDU:
+ // Not Supported
+ break;
+ case LLCP_CONNECT_PDU:
+ g_ui8dsapValue = (pui8RxBuffer[1] & 0x3F);
+
+ // Check Service Name TLV
+ if(pui8RxBuffer[2] == 0x06)
+ {
+ if (pui8RxBuffer[3] == 0x0F && pui8RxBuffer[4] == 'u'
+ && pui8RxBuffer[5] == 'r' && pui8RxBuffer[6] == 'n'
+ && pui8RxBuffer[7] == ':' && pui8RxBuffer[8] == 'n'
+ && pui8RxBuffer[9] == 'f' && pui8RxBuffer[10] == 'c'
+ && pui8RxBuffer[11] == ':' && pui8RxBuffer[12] == 's'
+ && pui8RxBuffer[13] == 'n' && pui8RxBuffer[14] == ':'
+ && pui8RxBuffer[15] == 's' && pui8RxBuffer[16] == 'n'
+ && pui8RxBuffer[17] == 'e' && pui8RxBuffer[18] == 'p')
+ {
+ // SNEP
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ else if (pui8RxBuffer[3] == 0x0F && pui8RxBuffer[4] == 'c'
+ && pui8RxBuffer[5] == 'o' && pui8RxBuffer[6] == 'm'
+ && pui8RxBuffer[7] == '.' && pui8RxBuffer[8] == 'a'
+ && pui8RxBuffer[9] == 'n' && pui8RxBuffer[10] == 'd'
+ && pui8RxBuffer[11] == 'r' && pui8RxBuffer[12] == 'o'
+ && pui8RxBuffer[13] == 'i' && pui8RxBuffer[14] == 'd'
+ && pui8RxBuffer[15] == '.' && pui8RxBuffer[16] == 'n'
+ && pui8RxBuffer[17] == 'p' && pui8RxBuffer[18] == 'p')
+ {
+ // NPP
+ g_eCurrentServiceEnabled = NPP_SERVICE;
+ }
+ else if (pui8RxBuffer[3] == 0x13 && pui8RxBuffer[4] == 'u'
+ && pui8RxBuffer[5] == 'r' && pui8RxBuffer[6] == 'n'
+ && pui8RxBuffer[7] == ':' && pui8RxBuffer[8] == 'n'
+ && pui8RxBuffer[9] == 'f' && pui8RxBuffer[10] == 'c'
+ && pui8RxBuffer[11] == ':' && pui8RxBuffer[12] == 's'
+ && pui8RxBuffer[13] == 'n' && pui8RxBuffer[14] == ':'
+ && pui8RxBuffer[15] == 'h' && pui8RxBuffer[16] == 'a'
+ && pui8RxBuffer[17] == 'n' && pui8RxBuffer[18] == 'd'
+ && pui8RxBuffer[19] == 'o' && pui8RxBuffer[20] == 'v'
+ && pui8RxBuffer[21] == 'e' && pui8RxBuffer[22] == 'r')
+ {
+ // Handover
+ g_eCurrentServiceEnabled = HANDOVER_SERVICE;
+ }
+ else if(ui8PduLength == 2)
+ {
+ // SNEP
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ else
+ {
+ // // Debug Incoming Request
+ // while(1);
+ // Ignore the command
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ }
+ else
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+ g_eNextPduQueue = LLCP_CC_PDU;
+ break;
+ case LLCP_DISC_PDU:
+ //UARTprintf("RX: DISC ");
+ g_eDMReason = DM_REASON_LLCP_RECEIVED_DISC_PDU;
+ g_eNextPduQueue = LLCP_DM_PDU;
+ break;
+ case LLCP_CC_PDU:
+ //UARTprintf("RX: CC ");
+ g_ui8dsapValue = (pui8RxBuffer[1] & 0x3F);
+ g_eNextPduQueue = LLCP_I_PDU;
+ break;
+ case LLCP_DM_PDU:
+ //UARTprintf("RX: DM ");
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ // Reset the snep communication
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ case LLCP_FRMR_PDU:
+ //UARTprintf("RX: FRMR ");
+ break;
+ case LLCP_SNL_PDU:
+ //UARTprintf("RX: SNL ");
+ break;
+ case LLCP_I_PDU:
+ //UARTprintf("RX: I ");
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ SNEP_processReceivedData(&pui8RxBuffer[3],ui8PduLength-3);
+ else if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // Not Supported
+ }
+ else if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ // Not Supported
+ }
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_RECEIVING;
+ }
+ g_eNextPduQueue = LLCP_RR_PDU;
+ break;
+ case LLCP_RR_PDU:
+ //UARTprintf("RX: RR \n");
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_SENDING)
+ {
+ if(
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS))
+ {
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ else if(eSnepProtocolStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS)
+ {
+ g_eNextPduQueue = LLCP_I_PDU;
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_SEND_COMPLETE)
+ {
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ }
+ else
+ {
+ //
+ // Used for debugging
+ //
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ break;
+ case LLCP_RNR_PDU:
+ //UARTprintf("RX: RNR ");
+ break;
+ case LLCP_RESERVED_PDU:
+ //UARTprintf("RX: RESERVED ");
+ break;
+ default:
+ //UARTprintf("RX: UNKNOWN LLCP ");
+ eLLCPStatus = STATUS_FAIL;
+ break;
+ }
+
+ return eLLCPStatus;
+}
+
+//*****************************************************************************
+//
+//! Set next PDU, return SUCCESS or FAIL
+//!
+//! \param eNextPdu is the LLCP PDU to set next.
+//!
+//! The \e eNextPdu parameter can be any of the following:
+//!
+//! - \b LLCP_SYMM_PDU - See LLCP standard document section 4.3.1
+//! - \b LLCP_PAX_PDU - See LLCP standard document section 4.3.2
+//! - \b LLCP_AGF_PDU - See LLCP standard document section 4.3.3
+//! - \b LLCP_UI_PDU - See LLCP standard document section 4.3.4
+//! - \b LLCP_CONNECT_PDU - See LLCP standard document section 4.3.5
+//! - \b LLCP_DISC_PDU - See LLCP standard document section 4.3.6
+//! - \b LLCP_CC_PDU - See LLCP standard document section 4.3.7
+//! - \b LLCP_DM_PDU - See LLCP standard document section 4.3.8
+//! - \b LLCP_FRMR_PDU - See LLCP standard document section 4.3.9
+//! - \b LLCP_SNL_PDU - See LLCP standard document section 4.3.10
+//! - \b LLCP_I_PDU - See LLCP standard document section 4.3.11
+//! - \b LLCP_RR_PDU - See LLCP standard document section 4.3.12
+//! - \b LLCP_RNR_PDU - See LLCP standard document section 4.3.13
+//! - \b LLCP_RESERVED_PDU - See LLCP standard document section 4.3.14
+//! - \b LLCP_ERROR_PDU - Unknown PDU
+//!
+//! This function is used to modify the next LLCP PDU. For example
+//! when we need to set the next PDU to be LLCP_CONNECT_PDU, to initiate
+//! a transfer. For more information please see the LLCP document from the
+//! NFC Forum.
+//!
+//! \return eSetNextPduStatus SUCCESS if g_eNextPduQueue was modified, else
+//! return FAIL
+//
+//*****************************************************************************
+tStatus LLCP_setNextPDU(tLLCPPduPtype eNextPdu)
+{
+ tStatus eSetNextPduStatus;
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_IDLE ||
+ g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eNextPduQueue = eNextPdu;
+ if(eNextPdu == LLCP_CONNECT_PDU)
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ eSetNextPduStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ eSetNextPduStatus = STATUS_FAIL;
+ }
+ return eSetNextPduStatus;
+}
+
+//*****************************************************************************
+//
+//! Send SYMM message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the SYMM PDU.
+//!
+//! This function adds a SYMM PDU starting at pui8PduBufferPtr.For more
+//! details on this PDU read LLCP V1.1 Section 4.3.1.
+//!
+//! \return ui8IndexTemp is the length of the SYMM PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendSYMM(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_SYMM_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_SYMM_PDU & 0x03) << 6);
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send CONNECT message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the CONNECT PDU.
+//!
+//! This function adds a CONNECT PDU starting at pui8PduBufferPtr.For more
+//! details on this PDU read LLCP V1.1 Section 4.3.5.
+//!
+//! \return ui8IndexTemp is the length of the CONNECT PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendCONNECT(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+ //
+ // Reset NR and NS
+ //
+ g_ui8NSNR = 0x00;
+
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_SENDING;
+
+ g_ui8ssapValue = LLCP_SSAP_CONNECT_SEND;
+ g_ui8dsapValue = DSAP_SERVICE_DISCOVERY_PROTOCOL;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_CONNECT_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_CONNECT_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ //
+ // TLV Fields
+ //
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_SN, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_MIUX, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_RW, &pui8PduBufferPtr[ui8IndexTemp]);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send DISC message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the DISC PDU.
+//!
+//! This function adds a DISC PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.6.
+//!
+//! \return ui8IndexTemp is the length of the DISC PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendDISC(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ //
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ //
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_DISC_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_DISC_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send CC message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the CC PDU.
+//!
+//! This function adds a CC PDU starting at pui8PduBufferPtr. For more details
+//! on this PDU, read LLCP V1.1 Section 4.3.7.
+//!
+//! \return \b ui8IndexTemp is the length of the CC PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendCC(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_ESTABLISHED;
+
+ //
+ // Reset NR and NS
+ //
+ g_ui8NSNR = 0x00;
+
+ g_ui8ssapValue = LLCP_SSAP_CONNECT_RECEIVED;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_CC_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_CC_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ //
+ // TLV Fields
+ //
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_MIUX, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_RW, &pui8PduBufferPtr[ui8IndexTemp]);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send DM message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the DM PDU.
+//! \param eDmReason is the enumeration of the disconnection reason.
+//!
+//! The \e eDmReason parameter can be any of the following:
+//!
+//! - \b DM_REASON_LLCP_RECEIVED_DISC_PDU
+//! - \b DM_REASON_LLCP_RECEIVED_CONNECTION_ORIENTED_PDU
+//! - \b DM_REASON_LLCP_RECEIVED_CONNECT_PDU_NO_SERVICE
+//! - \b DM_REASON_LLCP_PROCESSED_CONNECT_PDU_REQ_REJECTED
+//! - \b DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_SAME_SSAP
+//! - \b DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_ANY_SSAP
+//! - \b DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_SAME_SSSAPT
+//! - \b DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_ANY_SSSAPT
+//!
+//! This function adds a DM PDU starting at pui8PduBufferPtr with a dm_reason.
+//! For more details on this PDU read LLCP V1.1 Section 4.3.8.
+//!
+//! \return ui8IndexTemp is the length of the DM PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendDM(uint8_t * pui8PduBufferPtr,tDisconnectModeReason eDmReason)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_DM_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_DM_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ pui8PduBufferPtr[ui8IndexTemp++] = (uint8_t) eDmReason;
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send I message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the I PDU.
+//!
+//! This function adds a I PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.10.
+//!
+//! \return ui8IndexTemp is the length of the I PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendI(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+ tSNEPConnectionStatus eSnepProtocolStatus;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) | ( (LLCP_I_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_I_PDU & 0x03) << 6) | g_ui8ssapValue;
+
+ pui8PduBufferPtr[ui8IndexTemp++] = g_ui8NSNR;
+
+ g_ui8NSNR = (g_ui8NSNR & 0x0F) | (((g_ui8NSNR >> 4) + 0x01) << 4); // Increment N(S)
+
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_SENDING;
+ }
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_SENDING)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendRequest(&pui8PduBufferPtr[ui8IndexTemp],SNEP_REQUEST_PUT);
+ }
+ else if(g_eLLCPConnectionStatus == LLCP_CONNECTION_RECEIVING)
+ {
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if(eSnepProtocolStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_CONTINUE);
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_RECEIVE_COMPLETE)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_SUCCESS);
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_EXCESS_SIZE)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_REJECT);
+ }
+ }
+ }
+ else if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // RFU
+ }
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send RR message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the RR PDU.
+//!
+//! This function adds a RR PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.11.
+//!
+//! \return ui8IndexTemp is the length of the RR PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendRR(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) | \
+ ((LLCP_RR_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_RR_PDU & 0x03) << 6) | \
+ g_ui8ssapValue;
+
+ // Increment N(R)
+ g_ui8NSNR = (g_ui8NSNR & 0xF0) | ((g_ui8NSNR + 0x01) & 0x0F);
+
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8NSNR & 0x0F);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/nfclib/llcp.h b/nfclib/llcp.h new file mode 100644 index 0000000..7e419e0 --- /dev/null +++ b/nfclib/llcp.h @@ -0,0 +1,248 @@ +//*****************************************************************************
+//
+// llcp.h - Logic Link Control Protocol header file
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_LLCP_H__
+#define __NFC_LLCP_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_llcp_api NFC LLCP API Functions
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+
+//
+// ! LLCP Magic Number is constant 0x46666D
+//
+#define LLCP_MAGIC_NUMBER_HIGH 0x46
+#define LLCP_MAGIC_NUMBER_MIDDLE 0x66
+#define LLCP_MAGIC_NUMBER_LOW 0x6D
+
+//*****************************************************************************
+//
+// Service in local service Environment and is NOT advertised by local SDP
+//
+//*****************************************************************************
+
+//
+//! Source Service Access Point when sending
+//
+#define LLCP_SSAP_CONNECT_SEND 0x20
+
+//
+//! Source Service Access Point when receiving
+//
+#define LLCP_SSAP_CONNECT_RECEIVED 0x04
+
+//
+//! Destination Service Access Point for discovery
+//
+#define DSAP_SERVICE_DISCOVERY_PROTOCOL 0x01
+
+//
+//! The LLCP_MIU is the maximum information unit supported by the LLCP layer.
+//! This information unit may be included in each LLCP packet depending on the
+//! PDU type. The minimum must be 128.
+//
+#define LLCP_MIU 248
+
+//
+//! The LLCP_MIUX_SIZE is the value for the LLCP_MIUX TLV used in LLCP_addTLV().
+//
+#define LLCP_MIUX_SIZE (LLCP_MIU - 128)
+
+//*****************************************************************************
+//
+//! LLCP Parameter Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP V1.1 Section 4.5.1
+ LLCP_VERSION = 0x01,
+ //! See LLCP V1.1 Section 4.5.2
+ LLCP_MIUX = 0x02,
+ //! See LLCP V1.1 Section 4.5.3
+ LLCP_WKS = 0x03,
+ //! See LLCP V1.1 Section 4.5.4
+ LLCP_LTO = 0x04,
+ //! See LLCP V1.1 Section 4.5.5
+ LLCP_RW = 0x05,
+ //! See LLCP V1.1 Section 4.5.6
+ LLCP_SN = 0x06,
+ //! See LLCP V1.1 Section 4.5.7
+ LLCP_OPT = 0x07,
+ //! See LLCP V1.1 Section 4.5.8
+ LLCP_SDREQ = 0x08,
+ //! See LLCP V1.1 Section 4.5.9
+ LLCP_SDRES = 0x09,
+ LLCP_ERROR
+}tLLCPParamaeter;
+
+//*****************************************************************************
+//
+//! PDU Type Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP V1.1 Section 4.3.1
+ LLCP_SYMM_PDU = 0x00,
+ //! See LLCP V1.1 Section 4.3.2
+ LLCP_PAX_PDU= 0x01,
+ //! See LLCP V1.1 Section 4.3.3
+ LLCP_AGF_PDU= 0x02,
+ //! See LLCP V1.1 Section 4.3.4
+ LLCP_UI_PDU = 0x03,
+ //! See LLCP V1.1 Section 4.3.5
+ LLCP_CONNECT_PDU = 0x04,
+ //! See LLCP V1.1 Section 4.3.6
+ LLCP_DISC_PDU = 0x05,
+ //! See LLCP V1.1 Section 4.3.7
+ LLCP_CC_PDU = 0x06,
+ //! See LLCP V1.1 Section 4.3.8
+ LLCP_DM_PDU = 0x07,
+ //! See LLCP V1.1 Section 4.3.9
+ LLCP_FRMR_PDU = 0x08,
+ //! See LLCP V1.1 Section 4.3.10
+ LLCP_SNL_PDU = 0x09,
+ //! See LLCP V1.1 Section 4.3.11
+ LLCP_I_PDU = 0x0C,
+ //! See LLCP V1.1 Section 4.3.12
+ LLCP_RR_PDU = 0x0D,
+ //! See LLCP V1.1 Section 4.3.13
+ LLCP_RNR_PDU = 0x0E,
+ //! See LLCP V1.1 Section 4.3.14
+ LLCP_RESERVED_PDU = 0x0F
+}tLLCPPduPtype;
+
+//*****************************************************************************
+//
+//! LLCP Connection Status Enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! No Tx/Rx ongoing.
+ LLCP_CONNECTION_IDLE = 0x00,
+
+ //! When a virtual link is created either when we send a CONNECT PDU and
+ //! receive a CC PDU, or when we receive a CONNECT PDU and respond a CC PDU.
+ LLCP_CONNECTION_ESTABLISHED,
+
+ //! When sending data via SNEP
+ LLCP_CONNECTION_SENDING,
+
+ //! When receiving data via SNEP
+ LLCP_CONNECTION_RECEIVING
+
+}tLLCPConnectionStatus;
+
+//*****************************************************************************
+//
+//! Service Name Enumerations - Only support SNEP_SERVICE
+//
+//*****************************************************************************
+typedef enum
+{
+ NPP_SERVICE = 0,
+ SNEP_SERVICE,
+ HANDOVER_SERVICE
+}tServiceName;
+
+
+//*****************************************************************************
+//
+//! Disconnected Mode Reasons Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_DISC_PDU = 0x00,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_CONNECTION_ORIENTED_PDU = 0x01,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_CONNECT_PDU_NO_SERVICE = 0x02,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PROCESSED_CONNECT_PDU_REQ_REJECTED = 0x03,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_SAME_SSAP = 0x10,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_ANY_SSAP = 0x11,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_SAME_SSSAPT = 0x20,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_ANY_SSSAPT = 0x21
+}tDisconnectModeReason;
+
+
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void LLCP_init(void);
+
+uint8_t LLCP_stateMachine(uint8_t * pui8PduBufferPtr);
+
+tStatus LLCP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8PduLength);
+
+uint16_t LLCP_getLinkTimeOut(void);
+uint8_t LLCP_addTLV(tLLCPParamaeter eLLCPparam, uint8_t * pui8TLVBufferPtr);
+void LLCP_processTLV(uint8_t * pui8TLVBufferPtr);
+
+tStatus LLCP_setNextPDU(tLLCPPduPtype eNextPdu);
+void LLCP_setConnectionStatus(tLLCPConnectionStatus eConnectionState);
+
+uint8_t LLCP_sendSYMM(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendCONNECT(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendDISC(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendCC(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendDM(uint8_t * pui8PduBufferPtr,tDisconnectModeReason eDmReason);
+uint8_t LLCP_sendI(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendRR(uint8_t * pui8PduBufferPtr);
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif //__NFC_LLCP_H__
diff --git a/nfclib/nfc.c b/nfclib/nfc.c new file mode 100644 index 0000000..30bc104 --- /dev/null +++ b/nfclib/nfc.c @@ -0,0 +1,241 @@ +//*****************************************************************************
+//
+// nfc.c - NFC implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443b.h"
+
+unsigned char g_ucNFCID[11] = "\x80\x12\x34\x56"; //NFC ID (PUPI = 80123456)
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 B 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+NfcTagType4BSetupRegisters(void)
+{
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // TODO:check why have to set as this?
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ TRF79X0_MOD_CTRL_MOD_OOK_100);
+
+ //
+ // Set the ISO format to NFC Card Emulation, Type B
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x25);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_VRS_2_8V);
+
+ //
+ // RX Special Settings for ISO14443B
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x3C);
+
+ //
+ // Set the Target Detection Level to Max; use SDD
+ //
+// TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x27);
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Set the NFCID to be sent during SDD
+ //
+ TRF79x0WriteRegisterContinuous(TRF79X0_NFC_ID_REG, g_ucNFCID, 4);
+
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x03);
+
+ //
+ // ISO14443B TX Options
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x00);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x21);
+
+ TRF79x0ResetFifoCommand();
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+}
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 A 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+NfcTagType4ASetupRegisters(void)
+{
+ unsigned char Data[11] = "\x08\x12\x34\x56";
+
+ //Examples of start byte of Type A UID Values and MFGs seen by Nexus S.
+ //These are just a few found by using the TagInfo app
+ //0x01, 0x05, 0x07, 0x09, 0x19 = Infineon
+ //0x02, 0x03, 0x04, 0x06, 0x0A = NXP
+ //0x08 = Unknown, considered to be for random ID
+ //0x1C, 0xC2, 0x3E, 0x80 = NXP
+
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // TODO:check why have to set as this?
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ TRF79X0_MOD_CTRL_MOD_OOK_100);
+
+ //
+ // Set the ISO format to NFC Card Emulation, Type A
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x24);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+
+ //
+ // RX Special Settings for ISO14443A
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x30);
+
+ //
+ // Set the Target Detection Level to Max; use SDD
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x27);
+
+ //
+ // Set the NFCID to be sent during SDD
+ //
+ TRF79x0WriteRegisterContinuous(TRF79X0_NFC_ID_REG, Data, 4);
+
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ // SDD need this
+ TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x01);
+
+ //
+ // ISO14443B TX Options
+ //
+// TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x01);
+ TRF79x0WriteRegister(TRF79X0_ISO14443A_OPTIONS_REG, 0x00);
+
+// //
+// // Set the TX pulse to 106ns (0x20 * 73.7ns).
+// //
+// TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+//
+// //
+// // Set the RX No response wait time to 529us (0xe * 37.76us).
+// //
+// TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+//
+// //
+// // Set the RX wait time to 66us (7 * 9.44us).
+// //
+// TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x40);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x21);
+
+ TRF79x0ResetFifoCommand();
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+
+ //
+ // Delay 5ms before initializing the TRF79x0.
+ //
+ SysCtlDelay((SysCtlClockGet()/3000) * 2);
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+int
+ISO14443BATQB(unsigned char *pucPUPI,unsigned char ucAFI, unsigned char ucBitRate,
+ unsigned char ucMaxFrameSize, unsigned char ucProtocolType,
+ unsigned char ucFWI, unsigned char ucADC, unsigned char ucFO)
+{
+ unsigned char pucATQB[12];
+
+//
+// // Protocol Info Bytes
+// buffer[10] = 0x80; // Date Rate Capability ( Only Support 106 kbps)
+// // Max Frame/Protocol type (128 bytes / PICC compliant to -4)
+// buffer[11] = 0x71;
+// // (FWI/ADC/FO) ( FWT = 77.3mSec, ADC = coded according to AFI, CID supported)
+// buffer[12] = 0x85;
+
+ //
+ // ATQB response.
+ //
+ pucATQB[0] = 0x50;
+ pucATQB[1] = pucPUPI[0];
+ pucATQB[2] = pucPUPI[1];
+ pucATQB[3] = pucPUPI[2];
+ pucATQB[4] = pucPUPI[3];
+ pucATQB[5] = ucAFI;
+ pucATQB[6] = 0xE2; // CRC_B
+ pucATQB[7] = 0xAF; // CRC_B
+ pucATQB[8] = 0x11; // # of applications (1)
+ pucATQB[9] = ucBitRate;
+ pucATQB[10] = (ucMaxFrameSize << 4) | ucProtocolType;
+ pucATQB[11] = (ucFWI << 4) | (ucADC << 2) | ucFO;
+
+ //
+ // Transmit w/o receive
+ //
+ TRF79x0Transceive(pucATQB, sizeof(pucATQB), 0, 0, 0, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+
+ //
+ // Return true
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// NFC P2P Functions
+//
+//*****************************************************************************
diff --git a/nfclib/nfc.h b/nfclib/nfc.h new file mode 100644 index 0000000..6f349ce --- /dev/null +++ b/nfclib/nfc.h @@ -0,0 +1,42 @@ +//*****************************************************************************
+//
+// nfc.h - NFC implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __NFC_H__
+#define __NFC_H__
+
+//*****************************************************************************
+//
+// General NFC Function Prototypes
+//
+//*****************************************************************************
+extern unsigned char g_ucNFCID[4];
+
+extern void NfcTagType4BSetupRegisters(void);
+extern void NfcTagType4ASetupRegisters(void);
+extern int ISO14443BATQB(unsigned char *pucPUPI,unsigned char ucAFI,
+ unsigned char ucBitRate,unsigned char ucMaxFrameSize,
+ unsigned char ucProtocolType,unsigned char ucFWI,
+ unsigned char ucADC, unsigned char ucFO);
+
+#endif //__NFC_H__
diff --git a/nfclib/nfc_dep.c b/nfclib/nfc_dep.c new file mode 100644 index 0000000..3c30910 --- /dev/null +++ b/nfclib/nfc_dep.c @@ -0,0 +1,597 @@ +//*****************************************************************************
+//
+// nfc_dep.c - used to send packets of P2P
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "nfclib/nfc_dep.h"
+#include "nfclib/llcp.h"
+#include "nfclib/trf79x0.h"
+
+//*****************************************************************************
+//
+// Globals
+//
+//*****************************************************************************
+
+uint8_t g_pui8NFCID3t[10] = {0x01, 0xFE, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09};
+
+uint8_t g_ui8NfcDepPni = 0x00;
+
+uint8_t g_ui8RtoxTransportData;
+
+tPDUBlock tNextPduType = INFORMATION_PDU;
+
+uint8_t * g_pui8DEPBufferPtr;
+
+//*****************************************************************************
+//
+// NFCDEP_SendATR_REQ -
+//
+//*****************************************************************************
+void NFCDEP_SendATR_REQ(uint8_t * pui8NFCID2_Ptr)
+{
+ uint8_t ui8Counter = 0;
+ uint8_t ui8Offset = 0;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = 0x25;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((ATR_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (ATR_REQ_CMD & 0x00FF);
+
+ //
+ // NFCID3i
+ //
+ for(ui8Counter=0;ui8Counter<8;ui8Counter++)
+ {
+ g_pui8DEPBufferPtr[3+ui8Counter] = pui8NFCID2_Ptr[ui8Counter];
+ }
+ g_pui8DEPBufferPtr[11] = 0x00;
+ g_pui8DEPBufferPtr[12] = 0x00;
+
+ g_pui8DEPBufferPtr[13] = DIDi;
+ g_pui8DEPBufferPtr[14] = BSi;
+ g_pui8DEPBufferPtr[15] = BRi;
+ g_pui8DEPBufferPtr[16] = PPi; // Max Payload 64 bytes
+
+ //
+ // LLCP Magic Number
+ //
+ g_pui8DEPBufferPtr[17] = LLCP_MAGIC_NUMBER_HIGH;
+ g_pui8DEPBufferPtr[18] = LLCP_MAGIC_NUMBER_MIDDLE;
+ g_pui8DEPBufferPtr[19] = LLCP_MAGIC_NUMBER_LOW;
+
+ ui8Offset = 20;
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_VERSION,
+ &g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_MIUX,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_WKS,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_LTO,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_OPT,&g_pui8DEPBufferPtr[ui8Offset]);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendPSL_REQ -
+//
+//*****************************************************************************
+void NFCDEP_SendPSL_REQ(void)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((PSL_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (PSL_REQ_CMD & 0x00FF);
+
+ //
+ // DID
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x00;
+
+ //
+ // BRS -
+ // B5 B4 B3 (DSI) Initiator to Target
+ // B2 B1 B0 (DRI) Target to Initiator
+ // 0 0 0 106kbaud
+ // 0 0 1 212kbaud
+ // 0 1 0 424kbaud (default)
+ // 0 1 1 848kbaud
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x12;
+
+ //
+ // FSL
+ // B1-B0 Max Payload Size (11b: Max payload size is 254 bytes)
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x03;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendATR_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendATR_RES(void)
+{
+ uint8_t ui8Counter = 0;
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((ATR_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (ATR_RES_CMD & 0x00FF);
+
+ //
+ // NFCID3t
+ //
+ for(ui8Counter=0;ui8Counter<10;ui8Counter++)
+ {
+ g_pui8DEPBufferPtr[ui8Offset++] = g_pui8NFCID3t[ui8Counter];
+ }
+
+ g_pui8DEPBufferPtr[ui8Offset++] = DIDt;
+ g_pui8DEPBufferPtr[ui8Offset++] = BSt;
+ g_pui8DEPBufferPtr[ui8Offset++] = BRt;
+ g_pui8DEPBufferPtr[ui8Offset++] = TO;
+ g_pui8DEPBufferPtr[ui8Offset++] = PPt; // Max Payload 64 bytes
+
+ //
+ // LLCP Magic Number
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_HIGH;
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_MIDDLE;
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_LOW;
+
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_VERSION,
+ &g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_MIUX,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_WKS,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_LTO,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_OPT,&g_pui8DEPBufferPtr[ui8Offset]);
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendRSL_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendRSL_RES(void)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((RSL_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (RSL_RES_CMD & 0x00FF);
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendPSL_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendPSL_RES(uint8_t did_value)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((PSL_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (PSL_RES_CMD & 0x00FF);
+
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x00;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_ProcessReceivedRequest -
+//
+//*****************************************************************************
+tStatus NFCDEP_ProcessReceivedRequest(uint8_t * pui8RxBuffer , \
+ uint8_t * pui8NFCID2_Ptr,
+ bool bActiveResponse)
+{
+ volatile uint8_t ui8CommandLength;
+ uint16_t ui16Command;
+ tStatus eNfcDepStatus = STATUS_SUCCESS;
+ uint8_t ui8PFBValue;
+ uint8_t ui8Counter;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui16Command = pui8RxBuffer[2] + (pui8RxBuffer[1] << 8);
+
+ ui8PFBValue = pui8RxBuffer[3];
+
+ // Check if chaining is enabled
+ if((ui8PFBValue & 0xF0) == 0x00)
+ {
+ tNextPduType = INFORMATION_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x10)
+ {
+ tNextPduType = ACK_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x90)
+ {
+ tNextPduType = RTOX_REQ_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x80)
+ {
+ tNextPduType = ATN_PDU;
+ }
+
+
+ if(ui16Command == ATR_REQ_CMD)
+ {
+ if((pui8NFCID2_Ptr[0] == pui8RxBuffer[3] && \
+ pui8NFCID2_Ptr[1] == pui8RxBuffer[4] && \
+ pui8NFCID2_Ptr[2] == pui8RxBuffer[5] && \
+ pui8NFCID2_Ptr[3] == pui8RxBuffer[6] && \
+ pui8NFCID2_Ptr[4] == pui8RxBuffer[7] && \
+ pui8NFCID2_Ptr[5] == pui8RxBuffer[8] && \
+ pui8NFCID2_Ptr[6] == pui8RxBuffer[9] && \
+ pui8NFCID2_Ptr[7] == pui8RxBuffer[10]) || bActiveResponse == true)
+ {
+ ui8Counter = 0;
+ while(ui8CommandLength > (ui8Counter+20))
+ {
+ //
+ // Process the TLV - pass the starting address of the TLV
+ //
+ LLCP_processTLV(&pui8RxBuffer[ui8Counter+20]);
+
+ //
+ // Increment ui8Counter by the length+ 2 (type and length) of
+ // the current TLV
+ //
+ ui8Counter = ui8Counter+ pui8RxBuffer[ui8Counter+21] + 2;
+ }
+ NFCDEP_SendATR_RES();
+ // Reset the PNI
+ g_ui8NfcDepPni = 0x00;
+ //UARTprintf("CMD : D400\n");
+ }
+ else
+ eNfcDepStatus = STATUS_FAIL;
+ }
+ else if(ui16Command == PSL_REQ_CMD)
+ {
+ // Check if the DSI (Bits 5-3) == 010b => 424kbaud (Init. to Target)
+ // if the DRI (2-0) == 010b => 424kbaud (Target to Initiator)
+ if(((pui8RxBuffer[4] & 0x38) == 0x10) && \
+ ((pui8RxBuffer[4] & 0x07) == 0x02))
+ {
+ NFCDEP_SendPSL_RES(pui8RxBuffer[3]);
+ TRF79x0SetMode(P2P_PASSIVE_TARGET_MODE,FREQ_424_KBPS);
+ }
+
+ }
+ else if(ui16Command == DEP_REQ_CMD)
+ {
+ //
+ // LLCP Packet Handler
+ //
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ LLCP_processReceivedData(&pui8RxBuffer[4], (ui8CommandLength-4));
+ }
+
+ NFCDEP_SendDEP_RES();
+ }
+ else if(ui16Command == DSL_REQ_CMD)
+ {
+ //
+ // Debug
+ //
+ while(1);
+ }
+ else if(ui16Command == RSL_REQ_CMD)
+ {
+ //UARTprintf("CMD : D40A\n");
+ if(ui8CommandLength == 0x03)
+ NFCDEP_SendRSL_RES();
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+
+ }
+ return eNfcDepStatus;
+}
+
+//*****************************************************************************
+//
+// NFCDEP_ProcessReceivedData -
+//
+//*****************************************************************************
+tStatus NFCDEP_ProcessReceivedData(uint8_t * pui8RxBuffer)
+{
+ volatile uint8_t ui8CommandLength;
+ uint16_t ui16Command;
+ uint8_t ui8Counter;
+ tStatus eNfcDepStatus = STATUS_SUCCESS;
+ uint8_t ui8PFBValue;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui16Command = pui8RxBuffer[2] + (pui8RxBuffer[1] << 8);
+
+ if(ui16Command == ATR_RES_CMD)
+ {
+ //
+ // Store the g_pui8NFCID3t
+ //
+ for(ui8Counter = 0; ui8Counter < 10; ui8Counter++)
+ {
+ g_pui8NFCID3t[ui8Counter] = pui8RxBuffer[3+ui8Counter];
+ }
+ //
+ // LLCP Decoding - RFU
+ //
+ if(pui8RxBuffer[18] == LLCP_MAGIC_NUMBER_HIGH && \
+ pui8RxBuffer[19] == LLCP_MAGIC_NUMBER_MIDDLE && \
+ pui8RxBuffer[20] == LLCP_MAGIC_NUMBER_LOW)
+ {
+ ui8Counter = 0;
+ while(ui8CommandLength > (ui8Counter+21))
+ {
+ //
+ // Process the TLV - pass the starting address of the TLV
+ //
+ LLCP_processTLV(&pui8RxBuffer[ui8Counter+21]);
+
+ //
+ // Increment ui8Counter by the length+ 2 (type and length) of
+ // the current TLV
+ //
+ ui8Counter = ui8Counter+ pui8RxBuffer[ui8Counter+22] + 2;
+ }
+ //
+ // Set the next PDU for LLCP - SYMM PDU
+ //
+ LLCP_setNextPDU(LLCP_SYMM_PDU);
+
+ //
+ // Reset the PNI
+ //
+ g_ui8NfcDepPni = 0x00;
+ tNextPduType = INFORMATION_PDU;
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+ }
+ }
+ else if(ui16Command == PSL_RES_CMD)
+ {
+ //
+ // Check if DID is correct
+ //
+ if(pui8RxBuffer[3] != 0x00)
+ eNfcDepStatus = STATUS_FAIL;
+
+ }
+ else if(ui16Command == DEP_RES_CMD)
+ {
+ ui8PFBValue = pui8RxBuffer[3];
+
+ if((ui8PFBValue & 0xF0) == 0x00)
+ {
+ tNextPduType = INFORMATION_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x10)
+ {
+ //
+ // Check if chaining is enabled
+ //
+ tNextPduType = ACK_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x90)
+ {
+ tNextPduType = RTOX_REQ_PDU;
+ g_ui8RtoxTransportData = (0x3F & pui8RxBuffer[4]);
+ }
+
+ if(tNextPduType == INFORMATION_PDU)
+ //
+ // LLCP Packet Handler
+ //
+ eNfcDepStatus = LLCP_processReceivedData(&pui8RxBuffer[4],
+ (ui8CommandLength-4));
+
+ }
+ else if(ui16Command == DSL_RES_CMD)
+ {
+
+ }
+ else if(ui16Command == RSL_RES_CMD)
+ {
+
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+ }
+
+ return eNfcDepStatus;
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendDEP_REQ - Send DEP_REQ to TRF79x0
+//
+//*****************************************************************************
+void NFCDEP_SendDEP_REQ(uint8_t * pui8RxBuffer)
+{
+ uint8_t ui8TotalLength = 0;
+
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ //
+ // Total = 1 byte Length + 2 bytes Command + 1 byte PFB + n PDU
+ //
+ ui8TotalLength = 4 + LLCP_stateMachine(&g_pui8DEPBufferPtr[4]);
+
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+ }
+ else if(tNextPduType == RTOX_REQ_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = (tNextPduType);
+
+ g_pui8DEPBufferPtr[4] = g_ui8RtoxTransportData;
+ ui8TotalLength = 5;
+ }
+ else if(tNextPduType == ACK_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+
+ ui8TotalLength = 4;
+ }
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8TotalLength;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((DEP_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (DEP_REQ_CMD & 0x00FF);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8TotalLength);
+
+ if(tNextPduType == RTOX_REQ_PDU)
+ if(TRF79x0IRQHandler(((2<<g_ui8RtoxTransportData)/3)) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ NFCDEP_ProcessReceivedData(pui8RxBuffer);
+ NFCDEP_SendDEP_REQ(pui8RxBuffer);
+ }
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendDEP_RES -Send DEP_RES to TRF79x0
+//
+//*****************************************************************************
+void NFCDEP_SendDEP_RES(void)
+{
+ uint8_t ui8TotalLength = 0;
+
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+
+ //
+ // Total = 1 byte Length + 2 bytes Command + 1 byte PFB + n PDU
+ //
+ ui8TotalLength = 4 + LLCP_stateMachine(&g_pui8DEPBufferPtr[4]);
+ }
+ else if(tNextPduType == ATN_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = (tNextPduType);
+
+ ui8TotalLength = 4;
+ }
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8TotalLength;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((DEP_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (DEP_RES_CMD & 0x00FF);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8TotalLength);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SetBufferPtr - set global buffer pointer to input pointer value
+//
+//*****************************************************************************
+void NFCDEP_SetBufferPtr(uint8_t * buffer_ptr)
+{
+ g_pui8DEPBufferPtr = buffer_ptr;
+}
+
diff --git a/nfclib/nfc_dep.h b/nfclib/nfc_dep.h new file mode 100644 index 0000000..4581ebe --- /dev/null +++ b/nfclib/nfc_dep.h @@ -0,0 +1,109 @@ +//*****************************************************************************
+//
+// nfc_dep.h - Defines for sending packets of P2P
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_DEP_H__
+#define __NFC_DEP_H__
+#include "types.h"
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+// REQUESTS //
+#define ATR_REQ_CMD 0xD400
+#define PSL_REQ_CMD 0xD404
+#define DEP_REQ_CMD 0xD406
+#define DSL_REQ_CMD 0xD408
+#define RSL_REQ_CMD 0xD40A
+
+// RESPONSES //
+#define ATR_RES_CMD 0xD501
+#define PSL_RES_CMD 0xD505
+#define DEP_RES_CMD 0xD507
+#define DSL_RES_CMD 0xD509
+#define RSL_RES_CMD 0xD50B
+
+
+#define DIDi 0x00
+#define BSi 0x00
+#define BRi 0x00
+//*****************************************************************************
+//
+// Initiator Maximum payload size + General bytes available (BIT1)
+// B6 B5 - '00' Max Payload 64 bytes
+// B6 B5 - '01' Max Payload 128 bytes
+// B6 B5 - '10' Max Payload 192 bytes
+// B6 B5 - '11' Max Payload 254 bytes (default)
+//
+//*****************************************************************************
+#define PPi 0x32
+
+#define DIDt 0x00
+#define BSt 0x00
+#define BRt 0x00
+#define TO 0x07
+//*****************************************************************************
+//
+// Target Maximum payload size + General bytes available (BIT1)
+// B6 B5 - '00' Max Payload 64 bytes
+// B6 B5 - '01' Max Payload 128 bytes
+// B6 B5 - '10' Max Payload 192 bytes
+// B6 B5 - '11' Max Payload 254 bytes (default)
+//
+//*****************************************************************************
+#define PPt 0x32
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+typedef enum
+{
+ ACK_PDU = 0x40,
+ INFORMATION_PDU = 0x00,
+ NACK_PDU = 0x50,
+ ATN_PDU = 0x80,
+ RTOX_REQ_PDU = 0x90,
+
+}tPDUBlock;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCDEP_SendATR_REQ(uint8_t * pui8NFCID2_Ptr);
+void NFCDEP_SendPSL_REQ(void);
+void NFCDEP_SendATR_RES(void);
+void NFCDEP_SendRSL_RES(void);
+void NFCDEP_SendPSL_RES(uint8_t did_value);
+
+tStatus NFCDEP_ProcessReceivedRequest(uint8_t * rx_buffer ,uint8_t * pui8NFCID2_Ptr, bool bActiveResponse);
+tStatus NFCDEP_ProcessReceivedData(uint8_t * rx_buffer);
+void NFCDEP_SendDEP_REQ(uint8_t * rx_buffer);
+void NFCDEP_SendDEP_RES(void);
+void NFCDEP_SetBufferPtr(uint8_t * buffer_ptr);
+
+#endif //__NFC_DEP_H__
diff --git a/nfclib/nfc_f.c b/nfclib/nfc_f.c new file mode 100644 index 0000000..c27ef22 --- /dev/null +++ b/nfclib/nfc_f.c @@ -0,0 +1,166 @@ +//*****************************************************************************
+//
+// nfc_f.c - contains implementation of NFC Type F (Felica) protocol
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "nfclib/nfc_f.h"
+#include "nfclib/trf79x0.h"
+
+//*****************************************************************************
+//
+// NFC ID for TYPE F cards
+//
+//*****************************************************************************
+uint8_t g_ui8NFCID2[8] = {0x01 , 0xFE, 0x88 , 0x77, 0x66 , 0x55, 0x44 , 0x33};
+
+//*****************************************************************************
+//
+// Pointer to buffer
+//
+//*****************************************************************************
+uint8_t * g_pui8NFC_F_BufferPtr;
+
+//*****************************************************************************
+//
+// Sens SENSF_REQ (request)
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_REQ(void)
+{
+ uint8_t ui8NFC_F_Packet[6];
+ //
+ // Length
+ //
+ ui8NFC_F_Packet[0] = 0x06;
+ //
+ // Command
+ //
+ ui8NFC_F_Packet[1] = SENSF_REQ_CMD;
+
+ ui8NFC_F_Packet[2] = 0xFF; // System Code (SC) 7:0
+ ui8NFC_F_Packet[3] = 0xFF; // System Code (SC) 15:8
+
+ ui8NFC_F_Packet[4] = 0x00; // Request Code (RC)
+
+ ui8NFC_F_Packet[5] = 0x03; // Time Slot Number (TSN) (DP, Table 42, 4 time slots)
+ TRF79x0WriteFIFO(ui8NFC_F_Packet,CRC_BIT_ENABLE,6);
+}
+
+//*****************************************************************************
+//
+// Send SENSF_RES (response)
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_RES(void)
+{
+ uint8_t ui8NFC_F_Packet[18];
+ uint8_t ui8Offset = 0;
+ uint8_t ui8Counter = 0;
+ //
+ // Length
+ //
+ ui8NFC_F_Packet[ui8Offset++] = 0x12;
+ //
+ // Command
+ //
+ ui8NFC_F_Packet[ui8Offset++] = SENSF_RES_CMD;
+
+ for(ui8Counter = 0; ui8Counter < 8; ui8Counter++)
+ {
+ ui8NFC_F_Packet[ui8Offset++] = g_ui8NFCID2[ui8Counter];
+ }
+
+ // PAD 0
+ ui8NFC_F_Packet[ui8Offset++] = 0xC0;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC1;
+ // PAD 1
+ ui8NFC_F_Packet[ui8Offset++] = 0xC2;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC3;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC4;
+ // MRTI CHECK
+ ui8NFC_F_Packet[ui8Offset++] = 0xC5;
+ // MRTI UPDATE
+ ui8NFC_F_Packet[ui8Offset++] = 0xC6;
+ // PAD2
+ ui8NFC_F_Packet[ui8Offset++] = 0xC7;
+
+ TRF79x0WriteFIFO(ui8NFC_F_Packet,CRC_BIT_ENABLE,ui8Offset);
+}
+//*****************************************************************************
+//
+// Process data received in buffer
+//
+//*****************************************************************************
+tStatus NFCTypeF_ProcessReceivedData(uint8_t * pui8RxBuffer)
+{
+ volatile uint8_t ui8CommandLength;
+ uint8_t ui8Command;
+ uint8_t ui8Counter;
+ tStatus eNFCFStatus = STATUS_SUCCESS;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui8Command = pui8RxBuffer[1];
+
+// //UARTprintf("NFC_F CMD: %d \n",ui8Command);
+
+ if(ui8Command == SENSF_RES_CMD)
+ {
+ //
+ // Store the g_ui8NFCID2
+ //
+ for(ui8Counter = 0; ui8Counter < 8; ui8Counter++)
+ {
+ g_ui8NFCID2[ui8Counter] = pui8RxBuffer[2+ui8Counter];
+ }
+ }
+ else if(ui8Command == SENSF_REQ_CMD && ui8CommandLength == 0x06 )
+ {
+ if(pui8RxBuffer[2] == 0xFF && pui8RxBuffer[3] == 0xFF)
+ {
+ // Valid SENSF_REQ received - thus send a SENSF Response
+ NFCTypeF_SendSENSF_RES();
+ }
+ else
+ eNFCFStatus = STATUS_FAIL;
+ }
+ else
+ {
+ eNFCFStatus = STATUS_FAIL;
+ }
+ return eNFCFStatus;
+}
+
+//*****************************************************************************
+//
+// Return the NFCID
+//
+//*****************************************************************************
+uint8_t * NFCTypeF_GetNFCID2(void)
+{
+ return g_ui8NFCID2;
+}
+
+
+
+
diff --git a/nfclib/nfc_f.h b/nfclib/nfc_f.h new file mode 100644 index 0000000..9292731 --- /dev/null +++ b/nfclib/nfc_f.h @@ -0,0 +1,48 @@ +//*****************************************************************************
+//
+// nfc_f.h - Type F (Felica) NFC Header
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_F_H__
+#define __NFC_F_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+#define SENSF_REQ_CMD 0x00
+#define SENSF_RES_CMD 0x01
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_REQ(void);
+void NFCTypeF_SendSENSF_RES(void);
+tStatus NFCTypeF_ProcessReceivedData(uint8_t * pui8RxBuffer);
+uint8_t * NFCTypeF_GetNFCID2(void);
+void NFCTypeF_SetBufferPtr(uint8_t * buffer_ptr);
+
+#endif //__NFC_F_H__
diff --git a/nfclib/nfc_p2p.c b/nfclib/nfc_p2p.c new file mode 100644 index 0000000..7f1638a --- /dev/null +++ b/nfclib/nfc_p2p.c @@ -0,0 +1,1993 @@ +//*****************************************************************************
+//
+// nfc_p2p.c - contains implementation of p2p over NFC
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include "nfclib/nfc_p2p.h"
+#include "nfclib/nfc_f.h"
+#include "nfclib/nfc_dep.h"
+#include "nfclib/llcp.h"
+#include "nfclib/snep.h"
+#include "nfclib/debug.h"
+
+//*****************************************************************************
+//! \addtogroup nfc_p2p_api NFC P2P API Functions
+//! @{
+//! This module implements the encoding and decoding of NFC P2P messages
+//! and records.
+//!
+//! It is assumed that users of this module have a functional knowledge of NFC
+//! P2P messages and record types as defined by the NFC specification at
+//! <a href="http://www.nfc-forum.org/specs/spec_list/">
+//! http://www.nfc-forum.org/specs/spec_list</a> .
+//!
+//! The functions in this module assume that the NFCP2P_proccessStateMachine()
+//! is being called every 77ms or less as defined by the Digital
+//! Protocol Technical Specification requirement 197. Before any of the
+//! functions in this module are called, TRF79x0Init() and NFCP2P_init() must be
+//! called to initialize the transceiver and the NFCP2P state machine.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Globals
+//
+//*****************************************************************************
+
+//
+// Global pointer to recieve data, used by NFCP2PStateMachine().
+//
+uint8_t *g_ui8RxDataPtr;
+
+//
+// Flag to keep track of when to transmit data. Used by NFCP2PStateMachine().
+//
+bool g_bTxDataAvailable = false;
+
+//
+// Timout value aquired from lower level in NFC Stack, used by
+// NFCP2PStateMachine()
+//
+uint16_t g_ui16TargetTimeout = 0;
+
+//*****************************************************************************
+//
+// State used by NFCP2PStateMachine.
+//
+// Options are:
+// - NFC_P2P_PROTOCOL_ACTIVATION
+// - NFC_P2P_PARAMETER_SELECTION
+// - NFC_P2P_DATA_EXCHANGE_PROTOCOL
+// - NFC_P2P_DEACTIVATION
+//
+//*****************************************************************************
+tNFCP2PState g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+
+//*****************************************************************************
+//
+// Global for what mode the TRF79x0 operates in.
+//
+// Options are:
+// - BOARD_INIT
+// - P2P_INITATIOR_MODE
+// - P2P_PASSIVE_TARGET_MODE
+// - P2P_ACTIVE_TARGET_MODE
+// - CARD_EMULATION_TYPE_A
+// - CARD_EMULATION_TYPE_B
+//
+//*****************************************************************************
+tTRF79x0TRFMode g_eP2PMode;
+
+//*****************************************************************************
+//
+// Global for TRF79x0 operating frequency.
+//
+// Options are:
+// - FREQ_STAND_BY
+// - FREQ_106_KBPS
+// - FREQ_212_KBPS
+// - FREQ_424_KBPS
+//
+//*****************************************************************************
+tTRF79x0Frequency g_eP2PFrequency;
+
+//*****************************************************************************
+//! Initialize the variables used by the NFC Stack.
+//!
+//! \param eMode is the mode which to initialize the TRF79x0
+//! \param eFrequency is the frequency which to initialize the TRF79x0
+//!
+//! This function must be called before any other NFCP2P function is called.
+//! It can be called at any point to change the mode or frequency of the
+//! TRF79x0 transceiver. This function initializes either the initiator or the
+//! target mode.
+//!
+//! The \e eMode parameter can be any of the following:
+//!
+//! - \b BOARD_INIT - Initial Mode.
+//! - \b P2P_INITATIOR_MODE - P2P Initiator Mode.
+//! - \b P2P_PASSIVE_TARGET_MODE - P2P Passive Target Mode.
+//! - \b P2P_ACTIVE_TARGET_MODE - P2P Active Target Mode.
+//! - \b CARD_EMULATION_TYPE_A - Card Emulation for Type A cards.
+//! - \b CARD_EMULATION_TYPE_B - Card Emulation for Type B cards.
+//!
+//! The \e eFrequency parameter can be any of the following:
+//!
+//! - \b FREQ_STAND_BY - Used for Board Initialization.
+//! - \b FREQ_106_KBPS - Frequency of 106 kB per second.
+//! - \b FREQ_212_KBPS - Frequency of 212 kB per second.
+//! - \b FREQ_424_KBPS - Frequency of 424 kB per second.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+NFCP2P_init(tTRF79x0TRFMode eMode,tTRF79x0Frequency eFrequency)
+{
+ //
+ // Reset Default Values
+ //
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ g_eP2PMode = eMode;
+ g_eP2PFrequency = eFrequency;
+ g_bTxDataAvailable = false;
+ g_ui16TargetTimeout = 0;
+
+ //
+ // Store the nfc_buffer ptr in g_ui8RxDataPtr
+ //
+ g_ui8RxDataPtr = TRF79x0GetNFCBuffer();
+
+ //
+ // Initialize NFC DEP Global Pointer to use the g_ui8RxDataPtr pointer -
+ // the pointer is used to send responses/commands to the other Peer to
+ // Peer device. This implementation allows to reduce the RAM consumption.
+ //
+ NFCDEP_SetBufferPtr(g_ui8RxDataPtr);
+}
+
+//*****************************************************************************
+//
+//!
+//! Processes low level stack.
+//!
+//! \return This function returns the current NFCP2P state.
+//!
+//! The \e \b tNFCP2PState return parameter can be any of the following
+//! - \b NFC_P2P_PROTOCOL_ACTIVATION - Polling/Listening for SENSF_REQ / SENSF_RES.
+//! - \b NFC_P2P_PARAMETER_SELECTION - Setting the NFCIDs and bit rate
+//! - \b NFC_P2P_DATA_EXCHANGE_PROTOCOL - Data exchange using the LLCP layer
+//! - \b NFC_P2P_DEACTIVATION - Technology deactivation.
+//!
+//! This function must be executed every 77 ms or less as
+//! defined by requirement 197 inside the Digital Protocol Technical
+//! Specification. When the g_eP2PMode is set to P2P_INITATIOR_MODE, this
+//! function sends a SENSF_REQ to check if there is a Target in the field,
+//! while blocking the main application. If there is no target in the field,
+//! it exits. When the g_eP2PMode is set to P2P_PASSIVE_TARGET_MODE, this
+//! function waits for command for 495 ms, while blocking the main
+//! application. If no commands are received or if any errors occurred, this
+//! function exits. Once a technology is activated for either
+//! P2P_INITATIOR_MODE or P2P_PASSIVE_TARGET_MODE, the main application can use
+//! g_eNFCP2PState when equal to NFC_P2P_DATA_EXCHANGE_PROTOCOL, to then call
+//! NFCP2P_sendPacket() to send data from the TRF7970A to a target/initiator.
+//! Furthermore when g_eNFCP2PState is NFC_P2P_DATA_EXCHANGE_PROTOCOL,
+//! the main application must check the receive state with the function
+//! NFCP2P_getReceiveState() each time NFCP2P_proccessStateMachine() is
+//! executed to ensure it handles the data as it is received.
+//!
+//! \return g_eNFCP2PState, which is the current P2P state.
+//
+//*****************************************************************************
+tNFCP2PState
+NFCP2P_proccessStateMachine(void)
+{
+ uint8_t *pui8NFCID2_Ptr=0;
+
+ tTRF79x0IRQFlag eIRQStatus = IRQ_STATUS_IDLE;
+
+ switch(g_eNFCP2PState)
+ {
+ case NFC_P2P_PROTOCOL_ACTIVATION:
+ {
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ //
+ // Initialize the TRF7970A Registers for P2P Initiator Mode -
+ // in the case there is an external field enabled, the function
+ // will return STATUS_FAIL, the TRF7970 field will be disabled,
+ // and the program should switch to Target Mode.
+ //
+ if(TRF79x0Init2(P2P_INITATIOR_MODE, g_eP2PFrequency) ==
+ STATUS_FAIL)
+ break;
+
+ //
+ // Send SENSF_REQ
+ //
+ NFCTypeF_SendSENSF_REQ();
+
+ //
+ // Check if IRQ is triggered - timeout of 20 mS
+ //
+ if(TRF79x0IRQHandler(20) == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid SENSF_RES
+ //
+ if (NFCTypeF_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_SUCCESS)
+ {
+ g_eNFCP2PState = NFC_P2P_PARAMETER_SELECTION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nInitiator Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+ break;
+ }
+ else
+ {
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else
+ {
+ TRF79x0DisableTransmitter();
+ break;
+ }
+
+ }
+ else if (g_eP2PMode == P2P_PASSIVE_TARGET_MODE)
+ {
+ TRF79x0Init2(P2P_PASSIVE_TARGET_MODE, g_eP2PFrequency);
+
+ //
+ // Poll the IRQ flag for 495 mS.
+ //
+ while(eIRQStatus != IRQ_STATUS_TIME_OUT)
+ {
+ eIRQStatus = TRF79x0IRQHandler(495);
+
+ //
+ // Process the received data - check for valid SENSF_REQ
+ //
+ if((eIRQStatus == IRQ_STATUS_RX_COMPLETE) &&
+ (NFCTypeF_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_SUCCESS))
+ {
+ g_eNFCP2PState = NFC_P2P_PARAMETER_SELECTION;
+ break;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nTarget Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+ }
+ }
+ break;
+
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ TRF79x0Init2(P2P_ACTIVE_TARGET_MODE, g_eP2PFrequency);
+
+ //
+ // Poll the IRQ flag for 495 mS.
+ //
+ while(eIRQStatus != IRQ_STATUS_TIME_OUT)
+ {
+ eIRQStatus = TRF79x0IRQHandler(495);
+
+ //
+ // Process the received data - check for valid ATR_REQ
+ //
+ if((eIRQStatus == IRQ_STATUS_RX_COMPLETE) &&
+ (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,0,true) ==
+ STATUS_SUCCESS))
+ {
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ break;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nTarget Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+
+ }
+ }
+ break;
+ }
+ }
+ case NFC_P2P_PARAMETER_SELECTION:
+ {
+ //
+ // Reset the LLCP Parameters
+ //
+ LLCP_init();
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ pui8NFCID2_Ptr = NFCTypeF_GetNFCID2();
+ NFCDEP_SendATR_REQ(pui8NFCID2_Ptr);
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(1000) == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid ATR_RES
+ //
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr)
+ == STATUS_SUCCESS)
+ {
+ //
+ // If Current Frequency is 212 request to go to a higher
+ // baud rate
+ //
+ if(g_eP2PFrequency == FREQ_212_KBPS)
+ {
+ NFCDEP_SendPSL_REQ();
+
+ if (TRF79x0IRQHandler(1000) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr)==
+ STATUS_SUCCESS)
+ {
+ //
+ // If the function returns successful then
+ // the returned DID was correct.
+ //
+ TRF79x0SetMode(g_eP2PMode,FREQ_424_KBPS);
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+
+ g_ui16TargetTimeout = LLCP_getLinkTimeOut();
+
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Time out is: %d",g_ui16TargetTimeout);
+ #endif
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else if (g_eP2PMode == P2P_PASSIVE_TARGET_MODE)
+ {
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(1000) == IRQ_STATUS_RX_COMPLETE)
+ {
+ pui8NFCID2_Ptr = NFCTypeF_GetNFCID2();
+ //
+ // Process the received data - check for valid ATR_REQ
+ //
+ if (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,
+ pui8NFCID2_Ptr,false)
+ == STATUS_SUCCESS)
+ {
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Invalid ATR REQ\n");
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+ break;
+ }
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ break;
+ //TRF79x0DisableTransmitter();
+ }
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //TODO
+ break;
+ }
+ }
+ case NFC_P2P_DATA_EXCHANGE_PROTOCOL:
+ {
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ NFCDEP_SendDEP_REQ(g_ui8RxDataPtr);
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(g_ui16TargetTimeout) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid DEP_RES
+ //
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_FAIL)
+ {
+ //DebugPrintf("Exit DATA EXCHANGE\n");
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ break;
+ }
+
+ //
+ // Check if there is data to send to the Target.
+ //
+ if (g_bTxDataAvailable == true)
+ {
+ //
+ // Set the Connect PDU as the next command to the Target
+ //
+ if (LLCP_setNextPDU(LLCP_CONNECT_PDU) == STATUS_SUCCESS)
+ {
+ //
+ // If there was no ongoing connection, then clear
+ // the g_data_available flag
+ //
+ g_bTxDataAvailable = false;
+ }
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out \n");
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else if ((g_eP2PMode == P2P_PASSIVE_TARGET_MODE) ||
+ (g_eP2PMode == P2P_ACTIVE_TARGET_MODE))
+ {
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ eIRQStatus = IRQ_STATUS_IDLE;
+ while((eIRQStatus == IRQ_STATUS_IDLE) ||
+ (eIRQStatus == IRQ_STATUS_RF_FIELD_CHANGE) )
+ {
+ eIRQStatus = TRF79x0IRQHandler(1000);
+ }
+
+ if (eIRQStatus == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Check if there is data to send to the Target.
+ //
+ if (g_bTxDataAvailable == true)
+ {
+ //
+ // Set the Connect PDU as the next command to the Target
+ //
+ if (LLCP_setNextPDU(LLCP_CONNECT_PDU) == STATUS_SUCCESS)
+ {
+ //
+ // If there was no ongoing connection, then clear
+ //the g_data_available flag
+ //
+ g_bTxDataAvailable = false;
+ }
+ }
+
+ //
+ // Process the received data - check for valid DEP_REQ
+ //
+ if (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,
+ pui8NFCID2_Ptr,false)
+ == STATUS_FAIL)
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+ break;
+ }
+ }
+ else if (eIRQStatus
+ == (IRQ_STATUS_RX_COMPLETE | IRQ_STATUS_FIFO_HIGH_OR_LOW))
+ {
+ // Wait to receive the complete payload
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out \n");
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+
+ break;
+ }
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //TODO
+ break;
+ }
+ }
+ case NFC_P2P_DEACTIVATION:
+ {
+ break;
+ }
+ }
+
+ return g_eNFCP2PState;
+
+}
+
+//*****************************************************************************
+//
+//! Sends a raw buffer of data to the SNEP stack to be transmitted.
+//!
+//! \param pui8DataPtr is a pointer to the raw data to be sent.
+//! \param ui32DataLength is the length of the raw data.
+//!
+//! This function is used to send a data stream over NFC. The buffer resulting
+//! from a call to NFCP2P_NDEFMessageEncoder() should be fed to this function.
+//!
+//! \return Status of sent packet.
+//!
+//! The \e \b tStatus parameter can be any of the following:
+//!
+//! - \b STATUS_FAIL - The function exited with a failure.
+//! - \b STATUS_SUCCESS - The function ended in succes.
+//
+//*****************************************************************************
+tStatus
+NFCP2P_sendPacket(uint8_t *pui8DataPtr, uint32_t ui32DataLength)
+{
+ g_bTxDataAvailable = true;
+ return SNEP_setupPacket(pui8DataPtr,ui32DataLength);
+}
+
+//*****************************************************************************
+//
+//! NFCP2P_getReceiveState - Gets the receive state from the low level SNEP
+//! stack.
+//!
+//! Description: This function is used to get the receive payload status
+//! from the SNEP layer.
+//!
+//! \return This function returns the receive state.
+//
+//*****************************************************************************
+sNFCP2PRxStatus
+NFCP2P_getReceiveState(void)
+{
+ sNFCP2PRxStatus eReceiveStatus;
+
+ SNEP_getReceiveStatus(&eReceiveStatus.eDataReceivedStatus,
+ &eReceiveStatus.ui8DataReceivedLength,
+ &eReceiveStatus.pui8RxDataPtr);
+
+ return eReceiveStatus;
+}
+
+//*****************************************************************************
+//
+//! Encodes NFC Message meta-data and payload information.
+//!
+//! \param sNDEFDataToSend is a sNDEFMessageData structure filled out with the
+//! NDEF message to send.
+//! \param pui8Buffer is a pointer to the buffer where the raw encoded data will
+//! be stored
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to an integer that is filled with
+//! the length of the raw data encoded to the \b pui8Buffer.
+//!
+//! This function takes a filled sNDEFMessageData structure and encodes it to
+//! the provided buffer. The length, in bytes, of the data encoded to the buffer
+//! is stored into the integer pointer provided.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//!
+//
+// Note: for an explanation of the fields please see the Programmers Note in
+// nfc_p2p.h
+//*****************************************************************************
+bool
+NFCP2P_NDEFMessageEncoder(sNDEFMessageData sNDEFDataToSend,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint32_t ui32HeaderSize = 0;
+ uint32_t x;
+ sNDEFMessageData sMessage = sNDEFDataToSend;
+
+ //
+ // Check Arguements, ASSERT / return STATUS_FAIL as appropriate
+ //
+ ASSERT(ui16BufferMaxLength > 0);
+ ASSERT(pui8Buffer != 0);
+ ASSERT(sNDEFDataToSend.ui8TypeLength > 0);
+ ASSERT(sNDEFDataToSend.ui32PayloadLength > 0);
+ ASSERT(sNDEFDataToSend.pui8PayloadPtr != 0);
+ ASSERT(sNDEFDataToSend.ui32PayloadLength < ui16BufferMaxLength);
+ if(
+ (ui16BufferMaxLength == 0) ||
+ (pui8Buffer == 0) ||
+ (sNDEFDataToSend.ui8TypeLength == 0) ||
+ (sNDEFDataToSend.ui32PayloadLength == 0 ) ||
+ (sNDEFDataToSend.pui8PayloadPtr == 0) ||
+ (sNDEFDataToSend.ui32PayloadLength > ui16BufferMaxLength)
+ )
+ {
+ DebugPrintf(" ERR: NDEFMessageEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+ if(ui16BufferMaxLength < 25)
+ {
+ DebugPrintf("Warning: NDEFMessageEncoder : You need a bigger buffer\n");
+ }
+
+ //
+ // Fill STATUS_BYTE field
+ //
+ pui8Buffer[ui32HeaderSize] = (
+ NDEF_STATUSBYTE_SET_MB(sMessage.sStatusByte.MB) |
+ NDEF_STATUSBYTE_SET_ME(sMessage.sStatusByte.ME) |
+ NDEF_STATUSBYTE_SET_CF(sMessage.sStatusByte.CF) |
+ NDEF_STATUSBYTE_SET_SR(sMessage.sStatusByte.SR) |
+ NDEF_STATUSBYTE_SET_IL(sMessage.sStatusByte.IL) |
+ NDEF_STATUSBYTE_SET_TNF(sMessage.sStatusByte.TNF)
+ );
+ ui32HeaderSize++;
+
+ //
+ // Fill TYPE_LENGTH field
+ //
+ pui8Buffer[ui32HeaderSize] = sMessage.ui8TypeLength;
+ ui32HeaderSize++;
+
+ //
+ // Fill PAYLOAD_LENGTH field.
+ // based on StatusByte.SR field. May truncate if improperly set.
+ //
+ switch(sMessage.sStatusByte.SR)
+ {
+ //
+ // PAYLOAD_LENGTH is 1 byte long
+ //
+ case NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE:
+ {
+ pui8Buffer[ui32HeaderSize] = (sMessage.ui32PayloadLength & 0xFF);
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // PAYLOAD_LENGTH is 4 bytes long, inverted order (NFC Standard)
+ //
+ case NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE:
+ {
+ pui8Buffer[ui32HeaderSize+0] = ((sMessage.ui32PayloadLength >> 3*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+1] = ((sMessage.ui32PayloadLength >> 2*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+2] = ((sMessage.ui32PayloadLength >> 1*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+3] = ((sMessage.ui32PayloadLength >> 0*8)
+ & 0xFF);
+ ui32HeaderSize = ui32HeaderSize + 4;
+ break;
+ }
+
+ //
+ // default case, should never get here, if you do its an error
+ //
+ default:
+ {
+ DebugPrintf("ERR: NFC Header Encoder fn PAYLOAD_LENGTH field\n");
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Fill ID_LENGTH field.
+ // depends on Statusbyte.IL, if IL not set but data given in ui8IDLength
+ // the data will be ignored.
+ //
+ switch(sMessage.sStatusByte.IL)
+ {
+ //
+ // No ID_LENGTH field included
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:
+ {
+ // do nothing
+ break;
+ }
+
+ //
+ // ID_LENGTH field present, fill data, incriment buffer pointer
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.ui8IDLength;
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // default case, should never get here, if you do its an error.
+ //
+ default:
+ {
+ DebugPrintf("ERR: NFC Header Encoder fn ID_LENGTH field\n");
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Fill TYPE field. If TYPE_LENGTH > NDEF_TYPE_MAXSIZE then TYPE will be
+ // truncated to MAXSIZE
+ //
+ if(0 == sMessage.ui8TypeLength)
+ {
+ //
+ // do nothing
+ // TYPE_LENGTH = 0, so there is nothing to put in the TYPE field
+ //
+ }
+ else
+ {
+ for(x = 0;(x < sMessage.ui8TypeLength) && (x < NDEF_TYPE_MAXSIZE); x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8Type[x];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Fill ID field. If ID_LENGTH > NDEF_ID_MAXSIZE then ID will be truncated
+ // to MAXSIZE.
+ //
+ switch(sMessage.sStatusByte.IL)
+ {
+ //
+ // StatusByte.IL says no ID_LENGTH field, thus no ID field.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:{
+ //do nothing.
+ break;
+ }
+
+ //
+ // StatusByte.IL says ID_LENGTH Exists, so add the ID.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ if(0 == sMessage.ui8IDLength)
+ {
+ //
+ // Do nothing. ID_LENGTH = 0 so there is no ID to add.
+ //
+ }
+ else
+ {
+ for(x = 0;(x < sMessage.ui8IDLength) && (x < NDEF_ID_MAXSIZE);
+ x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8ID[x];
+ ui32HeaderSize++;
+ }
+ }
+ break;
+ }
+ }
+
+ //
+ // Make sure we wont overflow the buffer with the payload in the next step.
+ //
+ if((ui32HeaderSize + sMessage.ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR:NDEFMessageEncoder: BufferOverflow Payload too big\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill PAYLOAD buffer.
+ //
+ if(sMessage.sStatusByte.SR == NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE)
+ {
+ //
+ // 1 byte PAYLOAD_LENGTH.
+ //
+ for(x = 0;x < (sMessage.ui32PayloadLength & 0xFF);x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8PayloadPtr[x];
+ ui32HeaderSize++;
+ }
+ }
+ else
+ {
+ //
+ // 4 byte PAYLOAD_LENGTH.
+ // (treat Payload length as a 32bit number)
+ //
+ for(x = 0;x < sMessage.ui32PayloadLength; x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8PayloadPtr[x];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Fill BufferLength variable.
+ //
+ *pui32BufferLength = ui32HeaderSize;
+
+
+ return STATUS_SUCCESS;
+
+}
+
+//*****************************************************************************
+//
+//! Decodes NFC Message meta-data and payload information.
+//!
+//! \param psNDEFDataDecoded is a pointer to the sNDEFMessageData structure to
+//! be filled.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer from which to
+//! decode the data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent reading past the end of the
+//! buffer.
+//!
+//! This function takes in a buffer of raw NFC data and fills up an
+//! sNDEFMessageData structure. This function is the first step to decoding an
+//! NFC Message. The next step is to decode the Message Payload, which is the record.
+//! The decoded sNDEFMessageData structure has a field named \b pui8Type. The
+//! \b pui8Type field defines the record type and therefore indicates which
+//! RecordDecoder function to use on the Message Payload.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+// Note: local variables are used to break out fields from the header for
+// clarity. ui32HeaderSize is used to keep track of how large the header
+// is in bytes. It is used to computer the size of the payload at the end.
+// (length of Buffer - HeaderSize = Payload length)
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFMessageDecoder(sNDEFMessageData *psNDEFDataDecoded,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength)
+{
+ sNDEFMessageData *psMessage;
+ uint8_t ui8StatusByte,ui8TypeLength,ui8IDLength;
+ uint8_t *pui8PayloadPtr;
+ uint32_t ui32HeaderSize = 0;
+ uint32_t ui32PayloadLength=0;
+ uint32_t x;
+
+ //
+ // Check Input for Validity
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength > 0);
+
+ //
+ // Minimum length of header is 5 bytes.
+ //
+ if(ui16BufferMaxLength <= 5)
+ {
+ DebugPrintf("ERR: NDEFMessageDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ psMessage = psNDEFDataDecoded;
+
+ //
+ // Load Status Byte into NDEF Structure.
+ //
+ ui8StatusByte = pui8Buffer[ui32HeaderSize];
+ psMessage->sStatusByte.MB = NDEF_STATUSBYTE_GET_MB(ui8StatusByte);
+ psMessage->sStatusByte.ME = NDEF_STATUSBYTE_GET_ME(ui8StatusByte);
+ psMessage->sStatusByte.CF = NDEF_STATUSBYTE_GET_CF(ui8StatusByte);
+ psMessage->sStatusByte.SR = NDEF_STATUSBYTE_GET_SR(ui8StatusByte);
+ psMessage->sStatusByte.IL = NDEF_STATUSBYTE_GET_IL(ui8StatusByte);
+ psMessage->sStatusByte.TNF = NDEF_STATUSBYTE_GET_TNF(ui8StatusByte);
+
+ //
+ // Increment size of header (+1 for the size of the Status Byte).
+ //
+ ui32HeaderSize++;
+
+ //
+ // Load TypeLength byte into NDEF Structure.
+ //
+ ui8TypeLength = pui8Buffer[ui32HeaderSize];
+ psMessage->ui8TypeLength = ui8TypeLength;
+
+ //
+ // Increment size of header (+1 for the size of the Status Byte).
+ //
+ ui32HeaderSize++;
+
+ //
+ // Determine the payload size based upon the SR field in the header.
+ //
+ switch (psMessage->sStatusByte.SR)
+ {
+ //
+ // Short Record (PAYLOAD_LENGTH field is 1 byte).
+ //
+ case NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE:
+ {
+ ui32PayloadLength = pui8Buffer[ui32HeaderSize];
+
+ //
+ // Validate Data
+ //
+ if((ui32HeaderSize + ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf(
+ "ERR: NFCP2P_NDEFMessageDecoder: ui32PayloadLength > ui16BufferMaxLength\n");
+ DebugPrintf("\tYou Need a bigger buffer to hold this message.\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Set Payload Length
+ //
+ psMessage->ui32PayloadLength = ui32PayloadLength;
+ ui32HeaderSize++;
+ }
+ break;
+ }
+
+ //
+ // Normal Record (PAYLOAD_LENGTH field is 4 bytes).
+ //
+ case NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE:
+ {
+ ui32PayloadLength =
+ (
+ (pui8Buffer[ui32HeaderSize + 3] << 0*8) |
+ (pui8Buffer[ui32HeaderSize + 2] << 1*8) |
+ (pui8Buffer[ui32HeaderSize + 1] << 2*8) |
+ (pui8Buffer[ui32HeaderSize + 0] << 3*8)
+ );
+
+ //
+ // Validate Data
+ //
+ if((ui32HeaderSize + ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf(
+ "ERR: NFCP2P_NDEFMessageDecoder: ui32PayloadLength > ui16BufferMaxLength\n");
+ DebugPrintf("\tYou Need a bigger buffer to hold this message.\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Set Payload Length
+ //
+ psMessage->ui32PayloadLength = ui32PayloadLength;
+ ui32HeaderSize = ui32HeaderSize + 4;
+ }
+ break;
+ }
+
+ //
+ // This should never happen. return error.
+ //
+ default:
+ {
+ DebugPrintf("NDEFMessageDecoder: ERR decoding SR bit \n");
+ ASSERT(0);
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Load ID_LENGTH field, if it exists. Depends on StatusByte.IL.
+ //
+ switch (psMessage->sStatusByte.IL)
+ {
+ //
+ // ID_LENGTH field exists. Load it to the NDEF structure.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ ui8IDLength = pui8Buffer[ui32HeaderSize];
+ psMessage->ui8IDLength = ui8IDLength;
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // ID_LENGTH field does not exist and thus the ID field doesnt exists.
+ // Load 0 to NDEF structure to express this
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:
+ {
+ psMessage->ui8IDLength = 0;
+ break;
+ }
+
+ //
+ // This should never happen. return error.
+ //
+ default:
+ {
+ DebugPrintf(
+ "ERR: Invalid ID_LENGTH field Detected in NDEFMessageDecoder\n");
+ ASSERT(0);
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Load TYPE field based on length in TYPE_LENGTH field
+ //
+ // If TYPE_LENGTH value is larger than NDEF_TYPE_MAXSIZE truncate to MAXSIZE
+ // and adjust index in buffer to end of TYPE so as to not lose data / skew
+ // pointer.
+ //
+ if(psMessage->ui8TypeLength > NDEF_TYPE_MAXSIZE)
+ {
+ #ifdef DEBUG_PRINT
+ ASSERT(0);
+ UARTprintf("ERR: MessageDecode: TYPE > NDEF_TYPE_MAXSIZE, truncating to %d bytes\n",
+ NDEF_TYPE_MAXSIZE);
+ UARTprintf(" Orig Type = ");
+ for(x = 0;x < psMessage->ui8TypeLength;x++)
+ {
+ UARTprintf("%c",pui8Buffer[ui32HeaderSize + x]);
+ }
+ UARTprintf("\n");
+ #endif
+
+ //
+ // Copy across truncated TYPE
+ //
+ for(x = 0;x < NDEF_TYPE_MAXSIZE;x++)
+ {
+ psMessage->pui8Type[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+
+ //
+ // Adjust index appropriately.
+ //
+ ui32HeaderSize = ui32HeaderSize +
+ (psMessage->ui8TypeLength - NDEF_TYPE_MAXSIZE);
+ psMessage->ui8TypeLength = NDEF_TYPE_MAXSIZE;
+ }
+ else
+ {
+ //
+ // No problem
+ // Load Type field into NDEF structure
+ //
+ for(x = 0;x < psMessage->ui8TypeLength;x++)
+ {
+ psMessage->pui8Type[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Load ID field into NDEF structure. Depends on length in ID_LENGTH field.
+ // if ID field is > NDEF_ID_MAXSIZE truncate to MAXSIZE
+ //
+ if(psMessage->ui8IDLength > NDEF_ID_MAXSIZE)
+ {
+ #ifdef DEBUG_PRINT
+ ASSERT(0);
+ UARTprintf("ERR: ID_LENGTH > NDEF_ID_MAXSIZE, trucating to %d bytes\n",
+ NDEF_ID_MAXSIZE);
+ UARTprintf(" Orig ID = ");
+ for(x = 0;x < psMessage->ui8IDLength;x++)
+ {
+ UARTprintf("%c",pui8Buffer[ui32HeaderSize + x]);
+ }
+ UARTprintf("\n");
+ #endif
+
+ //
+ // Copy across truncated ID
+ //
+ for(x = 0;x < NDEF_ID_MAXSIZE;x++)
+ {
+ psMessage->pui8ID[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+
+ //
+ // adjust index appropriately
+ //
+ ui32HeaderSize = ui32HeaderSize + (psMessage->ui8IDLength -
+ NDEF_ID_MAXSIZE);
+ psMessage->ui8IDLength = NDEF_ID_MAXSIZE;
+ }
+ else
+ {
+ //
+ // No problem
+ // Load ID field into NDEF structure
+ //
+ for(x = 0;x < psMessage->ui8IDLength;x++)
+ {
+ psMessage->pui8ID[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Error Check
+ // Check to make sure we didnt overrun the buffer / read beyond its bounds.
+ //
+ if((ui32HeaderSize + psMessage->ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFMessageDecode: Buffer OverRun / OverRead\n");
+
+ //
+ // Clear all data out of datastrucutre, dont return invalid data.
+ //
+ psMessage->ui32PayloadLength=0;
+ psMessage->pui8PayloadPtr=0;
+
+ return STATUS_FAIL;
+ }
+
+ //
+ // Calculate Payload Pointer (payload is located after the header)
+ //
+ pui8PayloadPtr = pui8Buffer + ui32HeaderSize;
+
+ //
+ // Set the Message Payload Pointer
+ //
+ psMessage->pui8PayloadPtr = pui8PayloadPtr;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF Text Records.
+//!
+//! \param sTextRecord is the Text Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a TextRecord structure and encodes it into a provided
+//! buffer in the raw NFC data format. The length of the data stored in the
+//! buffer is stored in \e ui32BufferLength.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFTextRecordEncoder(sNDEFTextRecord sTextRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint8_t x;
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength > 0);
+ ASSERT(pui32BufferLength != 0);
+ ASSERT(sTextRecord.pui8Text != 0);
+ ASSERT(sTextRecord.ui32TextLength > 0);
+ ASSERT(sTextRecord.ui32TextLength < ui16BufferMaxLength);
+ if( (pui8Buffer == 0) ||
+ (ui16BufferMaxLength == 0) ||
+ (pui32BufferLength == 0) ||
+ (sTextRecord.pui8Text == 0) ||
+ (sTextRecord.ui32TextLength == 0) ||
+ (sTextRecord.ui32TextLength > ui16BufferMaxLength))
+ {
+ DebugPrintf("ERR: NDEFTextRecordEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill StatusByte in buffer
+ //
+ pui8Buffer[ui32RecordIndex] =
+ (
+ NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(sTextRecord.sStatusByte.bUTFcode) |
+ NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(sTextRecord.sStatusByte.bRFU ) |
+ NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(
+ sTextRecord.sStatusByte.ui5LengthLangCode)
+ );
+ ui32RecordIndex++;
+
+ //
+ // Validate LanguageCode Length
+ //
+ if(sTextRecord.sStatusByte.ui5LengthLangCode >
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ ASSERT(0);
+ DebugPrintf("Err: TextRecordEncoder: ui5LengthLanguageCode > ");
+ DebugPrintf("NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE\n");
+ DebugPrintf("\t Truncating from %d to MaxSize of %d.\n",
+ sTextRecord.sStatusByte.ui5LengthLangCode,
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE);
+ }
+
+ //
+ // Fill LanguageCode in buffer
+ //
+ for(x = 0;x < sTextRecord.sStatusByte.ui5LengthLangCode;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sTextRecord.pui8LanguageCode[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Error Check
+ //
+ if((ui32RecordIndex + sTextRecord.ui32TextLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFTextRecordEncode: Buffer Overflow Immenant\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill Text in buffer
+ //
+ for(x = 0;x < sTextRecord.ui32TextLength;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sTextRecord.pui8Text[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Set buffer length
+ //
+ *pui32BufferLength = ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF Text Records.
+//!
+//! \param psTextDataDecoded is a pointer to the TextRecord structure to decode
+//! the data into.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a Text
+//! record data structure. It is assumed that the raw data buffer contains a
+//! text record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFTextRecordDecoder(sNDEFTextRecord *psTextDataDecoded,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength)
+{
+ sNDEFTextRecord *psTextRecord;
+ uint8_t ui8StatusByte, ui8LengthLangCode, x = 0;
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(psTextDataDecoded != 0);
+ if(
+ (pui8Buffer == 0) ||
+ (psTextDataDecoded == 0)
+ )
+ {
+ DebugPrintf("ERR: TextRecordDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Initialize (done to insure 0 as sentinel in language Code)
+ //
+ psTextRecord = psTextDataDecoded;
+ for(x = 0;x < NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE;x++)
+ {
+ psTextRecord->pui8LanguageCode[x] = 0;
+ }
+ psTextRecord->ui32TextLength = 0;
+
+ //
+ // Load STATUSBYTE field
+ //
+ ui8StatusByte = pui8Buffer[ui32RecordIndex];
+ psTextRecord->sStatusByte.bUTFcode =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(ui8StatusByte);
+ psTextRecord->sStatusByte.bRFU =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(ui8StatusByte);
+ ui8LengthLangCode =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8StatusByte);
+ psTextRecord->sStatusByte.ui5LengthLangCode = ui8LengthLangCode;
+ ui32RecordIndex++;
+
+ //
+ // The StatusByte.RFU should always be 0, if this is not the case return
+ // failure
+ //
+ if(psTextRecord->sStatusByte.bRFU != 0)
+ {
+ ASSERT(0);
+ DebugPrintf("Err: NDEF TextRecord Decoder: StatusByte.RFU !=0\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // LengthLangCode must be > 0
+ //
+ if(ui8LengthLangCode <= 0)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFTextRecordDecoder: LengthLangCode <= 0\n");
+ return STATUS_FAIL;
+
+ }
+
+ //
+ // Load LANGUAGE_CODE field
+ //
+ for(x = 0;x < ui8LengthLangCode;x++)
+ {
+ //
+ // If space left in LanguageCode field put character in, otherwise
+ // truncate. (dont copy across, but do incriment through raw buffer)
+ //
+ if(x < NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ psTextRecord->pui8LanguageCode[x] = pui8Buffer[ui32RecordIndex];
+ ui32RecordIndex++;
+ }
+ else
+ {
+ ui32RecordIndex++;
+ }
+ }
+
+ //
+ // Validate Data
+ //
+ if(ui8LengthLangCode > NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ DebugPrintf("ERR: TextRecordDecoder: LengthLangCode > ");
+ DebugPrintf("NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE, truncating %d to %d",
+ ui8LengthLangCode,NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE);
+ DebugPrintf("\n");
+ psTextRecord->sStatusByte.ui5LengthLangCode =
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE;
+ }
+
+ //
+ // Load pointer to Text
+ //
+ psTextRecord->pui8Text = pui8Buffer + ui32RecordIndex;
+
+ //
+ // Validate Data - make sure we dont overrun the buffer
+ //
+ if(ui32RecordIndex > ui32BufferLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: TextRecordDecoder: Text Length longer than payload.");
+ DebugPrintf("\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Calculate Length of Text
+ // Length of text = Length of Record - RecordIndex to this point.
+ //
+ psTextRecord->ui32TextLength = ui32BufferLength-ui32RecordIndex;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF URI Records.
+//!
+//! \param sURIRecord is the URI Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a URI Record structure and encodes it into a provided
+//! buffer in a raw NFC data format. The length of the data stored in the buffer
+//! is stored in \e \b pui32BufferLength.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFURIRecordEncoder(sNDEFURIRecord sURIRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint32_t ui32RecordIndex = 0;
+ uint8_t x = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength !=0);
+ ASSERT((sURIRecord.ui32URILength +1) < ui16BufferMaxLength);
+ if(
+ (pui8Buffer == 0) ||
+ (ui16BufferMaxLength ==0) ||
+ ((sURIRecord.ui32URILength +1) > ui16BufferMaxLength)
+ )
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: URIRecordEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill IDCode field in buffer
+ //
+ pui8Buffer[ui32RecordIndex] = sURIRecord.eIDCode;
+ ui32RecordIndex++;
+
+ //
+ // Fill UTF8 string into buffer
+ //
+ for(x = 0;x < sURIRecord.ui32URILength;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sURIRecord.puiUTF8String[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Set Buffer Length
+ //
+ *pui32BufferLength = ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF URI Records.
+//!
+//! \param sURIRecord is a pointer to the URIRecord structure into which to
+//! decode the data.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a URI
+//! record data structure. It is assumed that the raw data buffer contains a
+//! URI record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFURIRecordDecoder(sNDEFURIRecord *sURIRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength)
+{
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(sURIRecord != 0);
+ if(
+ (pui8Buffer == 0) ||
+ (sURIRecord == 0)
+ )
+ {
+ DebugPrintf("ERR: URIRecordDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Load eIDCode field into struct
+ // error check that the ID code is valid.
+ //
+ if(pui8Buffer[ui32RecordIndex] >= NDEF_URIRECORD_IDCODE_RFU)
+ {
+ //
+ // IDCode not recognized, skip it.
+ // (can add codes in nfc_p2p.h eNDEF_URIRecord_IDCode enumeration)
+ //
+ DebugPrintf("ERR: URI Record Decoder: URI ID Code Not Recognized: 0x%x\n"
+ ,pui8Buffer[ui32RecordIndex]);
+ sURIRecord->eIDCode = RFU;
+ ui32RecordIndex++;
+ //return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // ID Code is Valid, set it.
+ //
+ sURIRecord->eIDCode = pui8Buffer[ui32RecordIndex];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Load UTF8 String Pointer into struct
+ //
+ sURIRecord->puiUTF8String = pui8Buffer + ui32RecordIndex;
+
+ //
+ // Load URI string Length into struct
+ //
+ sURIRecord->ui32URILength = ui32BufferLength-ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF SmartPoster Records.
+//!
+//! \param sSmartPoster is the SmartPoster Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a SmartPoster record structure and encodes it into a
+//! provided buffer in a raw NFC data format. The length of the data stored in
+//! the buffer is stored in \e \b pui32BufferLength.
+//!
+//! \note It is assumed that all smart poster messages have a Text record and a
+//! URI record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+// Note: This function works by first encoding the Record, then the Header.
+// The Header comes before the Record. Thus space is allocated in the
+// buffer for the Header before the buffer is passed to the encoder. The
+// extra space will be taken care of by the Header encoder function
+// (aka NDEFMessageEncoder).
+//
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFSmartPosterRecordEncoder(sNDEFSmartPosterRecord sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ //
+ // RECORD_OFFSET is the max size of the header. The magic number 7 comes
+ // from the size of the Statusbyte[1]+PayloadLength[4]+IDLength[1]+
+ // TypeLength[1]. This is done to ensure that there is space
+ // left in the buffer for the header while the record is encoding.
+ //
+ #define RECORD_OFFSET (NDEF_TYPE_MAXSIZE+NDEF_ID_MAXSIZE+7)
+
+ bool bStatus = STATUS_SUCCESS;
+
+ uint32_t ui32TotalLength = 0;
+ uint32_t ui32RecordLength = 0;
+
+ uint8_t *pui8CurrHeaderPt = pui8Buffer;
+ uint8_t *pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+
+ //
+ // Validate Data
+ //
+ ASSERT(ui16BufferMaxLength != 0);
+ ASSERT(pui8Buffer != 0);
+
+ //
+ // Encode TextMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode TextHeader (included TextPayload)
+ //
+ bStatus = NFCP2P_NDEFTextRecordEncoder(sSmartPoster.sTextPayload,
+ pui8CurrRecordPt,
+ (ui16BufferMaxLength -
+ (pui8CurrRecordPt - pui8Buffer)),
+ &ui32RecordLength);
+ sSmartPoster.sTextHeader.ui32PayloadLength = ui32RecordLength;
+ sSmartPoster.sTextHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster TextRecord Encode FAIL.\n");
+ return bStatus;
+ }
+
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sTextHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster TextRecord Header Encode FAIL.\n");
+ return bStatus;
+ }
+ ui32TotalLength += ui32RecordLength;
+
+ //
+ // Encode URIMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode URIHeader (included URIPayload)
+ //
+ bStatus = NFCP2P_NDEFURIRecordEncoder(sSmartPoster.sURIPayload,
+ pui8CurrRecordPt,
+ (ui16BufferMaxLength -
+ (pui8CurrRecordPt - pui8Buffer)),
+ &ui32RecordLength);
+ sSmartPoster.sURIHeader.ui32PayloadLength = ui32RecordLength;
+ sSmartPoster.sURIHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster URIRecord Encode FAIL.\n");
+ return bStatus;
+ }
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sURIHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ ui32TotalLength += ui32RecordLength;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster URIRecord Header Encode FAIL.\n");
+ return bStatus;
+ }
+
+ //
+ // Encode ActionMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode ActionHeader (included ActionPayload)
+ //
+ if(sSmartPoster.bActionExists)
+ {
+ //
+ // The Action Record has no Encoder / Decoder because it is just 1 byte
+ // of data. So it is hard coded into the Smart Poster Encoder / Decoder
+ //
+ pui8CurrRecordPt[0] = sSmartPoster.sActionPayload.eAction;
+ sSmartPoster.sActionHeader.ui32PayloadLength = 1;
+ sSmartPoster.sActionHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sActionHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ ui32TotalLength += ui32RecordLength;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster ActionRecord Encode FAIL.\n");
+ return bStatus;
+ }
+ }
+
+ //
+ // Check for buffer overflow. This should be caught in the lower level
+ // encode functions, but just to be safe we check for it here as well.
+ //
+ if(ui32TotalLength > ui16BufferMaxLength)
+ {
+ DebugPrintf(" ERR: SmartPosterRecordEncoder : Buffer Overflow.\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Return Buffer Length
+ //
+ *pui32BufferLength = ui32TotalLength;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF SmartPoster Records.
+//!
+//! \param sSmartPoster is a pointer to the SmartPosterRecord structure into
+//! which to decode the data.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent reading past the end of the
+//! buffer.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a
+//! SmartPoster record data structure. It is assumed that the raw data buffer
+//! contains a SmartPoster record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//!
+//! \note Currently only Title, Action and URI records are supported.
+//! Other records are skipped and ignored.
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFSmartPosterRecordDecoder(sNDEFSmartPosterRecord *sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t ui32BufferLength)
+{
+ sNDEFMessageData sCurrentHeader; //temp Header Info
+ uint32_t ui32RecordIndex = 0;
+ uint8_t *pui8CurrHeaderPt;
+ uint8_t x = 0;
+ bool bCheck = STATUS_SUCCESS;
+ uint64_t TypeID = 0;
+
+ //
+ // Initialize
+ //
+ sSmartPoster->bActionExists = false;
+
+ //
+ // Process through Payload for Smart Poster.
+ // Assume first header at pui8Buffer[0]
+ // Process and fill
+ //
+ while(ui32RecordIndex < ui32BufferLength)
+ {
+ //
+ // Pointer to Header
+ //
+ pui8CurrHeaderPt = pui8Buffer+ui32RecordIndex;
+
+ //
+ // Decode Current Header, in this case the
+ //
+ bCheck = NFCP2P_NDEFMessageDecoder(&sCurrentHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf("ERR: SPDecoder: SP NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ //
+ // Check for buffer read overrun. This would be caused by bad data.
+ // This goes off when you try to read past the end of the buffer.
+ //
+ if((sCurrentHeader.ui32PayloadLength +
+ (sCurrentHeader.pui8PayloadPtr - pui8Buffer))
+ > ui16BufferMaxLength)
+ {
+ DebugPrintf("ERR: SPDecoder: BufferRead Overrun. Bad Data.");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Calculate Record Type
+ //
+ for(x = 0,TypeID = 0;x < sCurrentHeader.ui8TypeLength;x++)
+ {
+ TypeID = (TypeID << 8) + sCurrentHeader.pui8Type[x];
+ }
+
+ //
+ // Decode Header into appropriate part of SmartPoster struct
+ // Call decoder function for each header type
+ //
+ switch(TypeID)
+ {
+ //
+ // Text Record
+ //
+ case NDEF_TYPE_TEXT:
+ {
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sTextHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: Text NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ bCheck = NFCP2P_NDEFTextRecordDecoder(
+ &sSmartPoster->sTextPayload,
+ sSmartPoster->sTextHeader.pui8PayloadPtr,
+ sSmartPoster->sTextHeader.ui32PayloadLength
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: NDEFTextRecordDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ break;
+ }
+
+ //
+ // URI Record
+ //
+ case NDEF_TYPE_URI:
+ {
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sURIHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: URI NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ bCheck = NFCP2P_NDEFURIRecordDecoder(
+ &sSmartPoster->sURIPayload,
+ sSmartPoster->sURIHeader.pui8PayloadPtr,
+ sSmartPoster->sURIHeader.ui32PayloadLength
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(\
+ " ERR: SPDecoder: NDEFURIMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ break;
+ }
+
+ //
+ // Action Record (built in type to SmartPoster, no need for external
+ // functions)
+ //
+ case NDEF_TYPE_ACTION:
+ {
+ sSmartPoster->bActionExists = true;
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sActionHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: Action NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ sSmartPoster->sActionPayload.eAction =
+ sSmartPoster->sActionHeader.pui8PayloadPtr[0];
+ break;
+ }
+
+ //
+ // Other record type, not supported, so skip it.
+ //
+ default:
+ {
+ DebugPrintf("NDEFSmartPosterDecode: Record Not recognized: 0x%x\n"
+ ,TypeID);
+ break;
+ }
+ }
+
+ //
+ // Incriment ui32RecordIndex
+ // (sCurrentHeader.pui8PayloadPtr-pui8CurrHeaderPt) = size of header
+ // when added to payload length this gives the total record size
+ //
+ ui32RecordIndex += (sCurrentHeader.pui8PayloadPtr-pui8CurrHeaderPt)
+ + sCurrentHeader.ui32PayloadLength;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/nfclib/nfc_p2p.h b/nfclib/nfc_p2p.h new file mode 100644 index 0000000..d0a7136 --- /dev/null +++ b/nfclib/nfc_p2p.h @@ -0,0 +1,1536 @@ +//*****************************************************************************
+//
+// nfc_p2p.h - contains P2P State Machine NDEF P2P Record Type Structures
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_P2P_H__
+#define __NFC_P2P_H__
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_p2p_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// NFC Protocol Headers
+//
+//*****************************************************************************
+#include "nfc_f.h"
+#include "nfc_dep.h"
+#include "llcp.h"
+#include "snep.h"
+
+//*****************************************************************************
+//
+// TRF7970 Header
+//
+//*****************************************************************************
+#include "trf79x0.h"
+
+//*****************************************************************************
+//
+//! Enumeration for 4 possible states for NFC P2P State Machine.
+//
+//*****************************************************************************
+typedef enum {
+ //
+ //! Polling/Listening for SENSF_REQ / SENSF_RES.
+ //
+ NFC_P2P_PROTOCOL_ACTIVATION = 0,
+
+ //
+ //! Setting the NFCIDs and bit rate
+ //
+ NFC_P2P_PARAMETER_SELECTION,
+
+ //
+ //! Data exchange using the LLCP layer
+ //
+ NFC_P2P_DATA_EXCHANGE_PROTOCOL,
+
+ //
+ //! Technology deactivation
+ //
+ NFC_P2P_DEACTIVATION
+
+} tNFCP2PState;
+
+//*****************************************************************************
+//
+//! This structure defines the status of the received payload.
+//
+//*****************************************************************************
+typedef struct{
+
+ //
+ //! SNEP RX Packet Status
+ //
+ tPacketStatus eDataReceivedStatus;
+
+ //
+ //! SNEP Number of bytes received
+ //
+ uint8_t ui8DataReceivedLength;
+
+ //
+ //! Pointer to data received
+ //
+ uint8_t *pui8RxDataPtr;
+
+}sNFCP2PRxStatus;
+
+//*****************************************************************************
+//
+// Programmers Note: NDEF message layout
+//
+// The fields in an NDEF header are as follows:
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0| Notes:
+// |------------------------------|
+// | MB| ME| CF| SR| IL| TNF | NDEF StatusByte
+// |------------------------------|
+// | TYPE_LENGTH | 1 byte, hex value
+// |------------------------------|
+// | PAYLOAD_LENGTH | 1 or 4 bytes (determined by SR) (LSB first)
+// |------------------------------|
+// | ID_LENGTH | 0 or 1 bytes (determined by IL)
+// |------------------------------|
+// | TYPE | 2 or 5 bytes (determined by TYPE_LENGTH)
+// |------------------------------|
+// | ID | 0 or 1 byte (determined by IL & ID_LENGTH)
+// |------------------------------|
+// | PAYLOAD | X bytes (determined by PAYLOAD_LENGTH)
+// |------------------------------|
+// NDEF messages NDEF messages can be considered as two parts:
+// The Header (everything except the last field), and the Payload.
+//
+// **********
+// HEADER
+// **********
+// The Header encompases Everything in the above diagram except the PAYLOAD
+// The Header can vary in length from 5-13 bytes.
+// The PAYLOAD_LENGTH, ID_LENGTH, ID, and TYPE fields can all very in length.
+//
+// Field Name | Length Depends On | Length
+// ------------------------------------------------
+// PAYLOAD LENGTH | SR | SR = 1 => 1 byte , SR = 0 => 4 bytes
+// ID_LENGTH | IL | IL = 0 (if IL = 0 Both ID_LENGTH and
+// ID fields are excluded.
+// If IL = 1 then ID_LENGTH
+// exists. If ID_LENGTH = 0x0
+// then the ID field is
+// not included)
+// TYPE | TYPE_LENGTH | 2-5 bytes (hex value of TYPE_LENGTH)
+// (In special cases there can be
+// a TYPE_LENGTH of 0, in which
+// case there is no TYPE field.)
+//
+// Note: PAYLOAD_LENGTH only gives the length of the PAYLOAD in its message.
+// The PAYLOAD_LENGTH does NOT give the length of the record across
+// multiple messages..
+//
+// ***********
+// PAYLOAD
+// ***********
+// The Payload can have a wide range of formats depending on the TNF and TYPE
+// specified. (IE a TNF of 0x01 aka WELL_KNOWN_TYPE and a TYPE of 'T' would
+// indicate a plain text payload, which has its own syntax). The user can even
+// implement their own PAYLOAD type, providing handlers are provided on both the
+// sending and receiving devices.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// NDEF message header definitions
+// SET macros are used to set the bit (encoder)
+// GET macros are used to read the bit (decoder)
+//
+//*****************************************************************************
+
+//
+//! This macro is used to set the MB field in the StatusByte of the NFC message header by
+//! shifting a bit into position. This define should be ORed together with other StatusByte
+//! Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the MB field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_MB(0x1) </tt>
+//!
+//! \b Example: Clear the MB field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_MB(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_MB(ui8x) ((ui8x & 0x01) << 7)
+
+//
+//! This macro is used to set the ME field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the ME field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_ME(0x1) </tt>
+//!
+//! \b Example: Clear the ME field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_ME(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_ME(ui8x) ((ui8x & 0x01) << 6)
+
+//
+//! This Macro is used to set the CF field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the CF field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_CF(0x1) </tt>
+//!
+//! \b Example: Clear the CF field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_CF(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_CF(ui8x) ((ui8x & 0x01) << 5)
+
+//
+//! This macro is used to set the SR field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the SR field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_SR(0x1) </tt>
+//!
+//! \b Example: Clear the SR field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_SR(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_SR(ui8x) ((ui8x & 0x01) << 4)
+
+//
+//! This macro is used to set the IL field in the StatusByte of the NFC message header by
+//! shifting a bit into position. This define should be ORed together with other StatusByte
+//! Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the IL field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_IL(0x1) </tt>
+//!
+//! \b Example: Clear the IL field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_IL(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_IL(ui8x) ((ui8x & 0x01) << 3)
+
+//
+//! This macro is used to set the TNF field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the 3-bit value to be shifted into place
+//!
+//! \b Example: Set the TNF field to Well Known Type in a StatusByte
+//!
+//! <tt>NsNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_TNF(0x1) </tt>
+//!
+//! \b Example: Set the TNF field to Unknown Type in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_TNF(0x5) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_TNF(ui8x) ((ui8x & 0x07) << 0)
+
+//
+//! Macro used to get the MB field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the MB field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_MB(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_MB(ui8x) ((ui8x >> 7) & 0x01)
+
+//
+//! Macro used to get the ME field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the ME field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_ME(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_ME(ui8x) ((ui8x >> 6) & 0x01)
+
+//
+//! Macro used to get the CF field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the CF field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_CF(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_CF(ui8x) ((ui8x >> 5) & 0x01)
+
+//
+//! Macro used to get the SR field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the SR field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_SR(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_SR(ui8x) ((ui8x >> 4) & 0x01)
+
+//
+//! Macro used to get the IL field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the IL field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_IL(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_IL(ui8x) ((ui8x >> 3) & 0x01)
+
+//
+//! Macro used to get the TNF field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the TNF field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_TNF(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_TNF(ui8x) ((ui8x >> 0) & 0x07)
+
+//*****************************************************************************
+//
+// Defines to check Header StatusByte field meaning. Some cases left out
+// because they are irrelevant (ie only care when MB is 1 or not 1, dont care
+// about 0)
+//
+//*****************************************************************************
+
+//
+//! Flag used to check the MB field in the StatusByte. If MB is set then this is
+//! the first Record.
+//!
+//! \b Example: Check for Message Begin flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_MB(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_MB_FIRSTBYTE){} </tt>
+//
+#define NDEF_STATUSBYTE_MB_FIRSTBYTE 1
+
+//
+//! Flag used to check the ME field in the StatusByte. If ME is set, then this
+//! is the last Record.
+//!
+//! \b Example: Check for Message End flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_ME(ui8StatusByte) == NDEF_STATUSBYTE_ME_LASTBYTE)
+//! {} </tt>
+//
+#define NDEF_STATUSBYTE_ME_LASTBYTE 1
+
+//
+//! Flag used to check the CF field in the StatusByte. If CF is set, then the
+//! message is a chunked message spread out across multiple transactions.
+//!
+//! \b Example: Check for Chunked Flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_CF(ui8StatusByte) == NDEF_STATUSBYTE_CF_CHUNK)
+//! {} </tt>
+//
+#define NDEF_STATUSBYTE_CF_CHUNK 1
+
+//
+//! Flag used to check the SR field in the StatusByte. If SR is set, then
+//! the message is a short record with a payload length field of 1 byte instead
+//! of 4 bytes.
+//!
+//! \b Example: Check the Short Record flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE){} </tt>
+//
+#define NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE 1
+
+//
+//! Flag used to check the SR field in the StatusByte. If SR is not set, then
+//! the message is a normal record with a payload length field of 4 bytes
+//! instead of 1 byte.
+//!
+//! \b Example: Check the Short Record flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE){} </tt>
+//
+#define NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE 0
+
+//
+//! Flag used to check the IL field in the StatusByte. If IL is set, then the ID
+//! and IDLength fields are present in the message.
+//!
+//! \b Example: Check for the presence of the ID Length and ID name field
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_IL_IDLENGTHPRESENT) {} </tt>
+//
+#define NDEF_STATUSBYTE_IL_IDLENGTHPRESENT 1
+
+//
+//! Flag used to check the IL field in the StatusByte. If IL is not set, then
+//! there is no ID or IDLength fields included in the message.
+//!
+//! \b Example: Check for the presence of the ID Length and ID name field
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_IL_IDLENGTHABSENT) {} </tt>
+//
+#define NDEF_STATUSBYTE_IL_IDLENGTHABSENT 0
+
+//*****************************************************************************
+//
+// Defines to set maximum field lengths in bytes
+//
+//*****************************************************************************
+
+//
+//! Maximum size of Type field in StatusByte. This define is used to declare the
+//! length of the buffer in the structure and thus can be changed to allow
+//! larger Type names.
+//!
+//! \b Example: Copy the Type from raw buffer to structure using
+//! NDEF_TYPE_MAXSIZE to prevent overflowing buffer in the
+//! structure
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume that TypeLength is already decoded from the raw buffer and is
+//! // stored in sNDEFMessageData.ui8TypeLength. Assume ui8RawBuffer is a
+//! // pointer to the beginning of the Type field in the raw data stream.
+//! //
+//! int x = 0;
+//! for(x = 0; (x<NDEF_TYPE_MAXSIZE) & (x<sNDEFMessageData.ui8TypeLength); x++)
+//! {
+//! sNDEFMessageData.pui8Type[x]=ui8RawBuffer[x];
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_MAXSIZE 10 // can be changed
+
+//
+//! Maximum size of the ID field in StatusByte, which can be modified to support
+//! larger ID names.
+//!
+//! \b Example: Copy the ID from the raw buffer to the structure using
+//! NDEF_ID_MAXSIZE to prevent overflowing buffer in the structure
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume IDLength already decoded from the raw buffer is stored in
+//! // sNDEFMessageData.ui8IDLength. Assume ui8RawBuffer is a pointer to
+//! // the beginning of the ID field in the raw data stream.
+//! //
+//! int x = 0;
+//! for(x = 0; (x<NDEF_ID_MAXSIZE) & (x<sNDEFMessageData.ui8IDLength); x++)
+//! {
+//! sNDEFMessageData.pui8pui8ID[x] = ui8RawBuffer[x];
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_ID_MAXSIZE 10 // can be changed
+
+//*****************************************************************************
+//
+// Defines to check NDEF ID type
+//
+//*****************************************************************************
+
+//
+//! NFC Message TypeID hex representation for TEXT records.
+//! 0x54 == 'T' in UTF-8
+//!
+//! \b Example: Check if tag type is TEXT
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_TEXT)
+//! {
+//! // The Tag is a TEXT record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_TEXT 0x54 // 'T' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for URI records.
+//! 0x55 == 'U' in UTF-8
+//!
+//! \b Example: Check if tag type is URI
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_URI)
+//! {
+//! // The Tag is a URI record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_URI 0x55 // 'U' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SMARTPOSTER records.
+//! 0x5370 == "Sp" in UTF-8
+//!
+//! \b Example: Check if tag type is SMARTPOSTER
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SMARTPOSTER)
+//! {
+//! // The Tag is a SMARTPOSTER record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SMARTPOSTER 0x5370 //"Sp" in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SIGNATURE records.
+//! 0x536967 == "Sig" in UTF-8
+//!
+//! \b Example: Check if tag type is SIGNATURE
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SIGNATURE)
+//! {
+//! // The Tag is a SIGNATURE record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SIGNATURE 0x536967 //"Sig" in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SIZE records.
+//! 0x73 == 's' in UTF-8
+//!
+//! \b Example: Check if tag type is SIZE
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SIZE)
+//! {
+//! // The Tag is a SIZE record. Handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SIZE 0x73 // 's' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for ACTION records.
+//! 0x616374 == "act" in UTF-8
+//!
+//! \b Example: Check if tag type is ACTION
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_ACTION)
+//! {
+//! // The Tag is a ACTION record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_ACTION 0x616374 //"act" in UTF-8
+
+
+
+//*****************************************************************************
+//
+//! Enumeration for Type Name Format (TNF) field in NDEF header StatusByte.
+//! TNF values are 3 bits. Most records are of the Well Known Type format
+//! (0x01).
+//
+// TNF = Type Name Format: 3bit field, indicates structure of TYPE field
+// Acceptable Values are:
+// 0x00 Empty
+// 0x01 NFC Forum well-known type [NFC RTD]
+// NDEF Record Type Description Full URI Reference
+// 'Sp' Smart Poster urn:nfc:wkt:Sp
+// 'T' Text urn:nfc:wkt:T
+// 'U' URI urn:nfc:wkt:U
+// 'Hr' Handover Request urn:nfc:wkt:Hr
+// 'Hs' Handover Select urn:nfc:wkt:Hs
+// 'Hc' Handover Carrier urn:nfc:wkt:Hc
+// 'Sig' Signature urn:nfc:wkt:Sig
+// 0x02 Media-type as defined in RFC 2046 [RFC 2046]
+// 0x03 Absolute URI as defined in RFC 3986 [RFC 3986]
+// 0x04 NFC Forum external type [NFC RTD]
+// 0x05 Unknown
+// 0x06 Unchanged (used with single message across multiple chunks)
+// 0x07 Reserved
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! Empty Format
+ //
+ TNF_EMPTY = 0x00,
+
+ //
+ //! NFC Forum Well Known Type [NFC RTD]
+ //
+ TNF_WELLKNOWNTYPE = 0x01,
+
+ //
+ //! Media-type as defined in RFC 2046 [RFC 2046]
+ //
+ TNF_MEDIA_TYPE = 0x02,
+
+ //
+ //! Absolute URI as defined in RFC 3986 [RFC 3986]
+ //
+ TNF_ABSOLUTE_URI = 0x03,
+
+ //
+ //! NFC Forum external type [NFC RTD]
+ //
+ TNF_EXTERNAL_TYPE = 0x04,
+
+ //
+ //! Unknown
+ //
+ TNF_UNKNOWN = 0x05,
+
+ //
+ //! Unchanged (used with single message across multiple chunks)
+ //
+ TNF_UNCHANGED = 0x06,
+
+ //
+ //! Reserved
+ //
+ TNF_RESERVED = 0x07
+} tTNF;
+
+//*****************************************************************************
+//
+//! NFC NDEF message header StatusByte structure. Included in this structure
+//! are fields for Message Begin (MB), Message End (ME), Chunk Flag (CF), Short
+//! Record (SR), IDLength (IL) and Type Name Format (TNF). The purpose of this
+//! structure is to make the fields readily available for message processing.
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0|
+// |------------------------------|
+// | MB| ME| CF| SR| IL| TNF |
+// |------------------------------|
+//
+// MB = Message Begin : marks start of NDEF message
+// ME = Message End : marks end of NDEF message
+// CF = Chunk Flag : indicate first or middle record chunk of chunked payload
+// SR = Short Record : if == 1 PAYLOAD_LENGTH is 1 byte, else it is 4 bytes
+// IL = ID Length : indicate presence of ID_LENGTH byte
+// (1 =included, 0 = not)
+// TNF = Type Name Format: 3bit field, indicates structure of TYPE field
+//
+// Note: for a record that only takes up 1 NDEF message both the MB and ME
+// fields would be set on the same message. It is likely that the SR
+// field would be set as well to save space, but not required.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Message Begin flag
+ //
+ bool MB;
+
+ //
+ //! Message End flag
+ //
+ bool ME;
+
+ //
+ //! Chunk Flag
+ //
+ bool CF;
+
+ //
+ //! Short Record flag
+ //
+ bool SR;
+
+ //
+ //! ID Length flag
+ //
+ bool IL;
+
+ //
+ //! Type Name Field. An enumeration specifying the general tag type.
+ //
+ tTNF TNF;
+
+} sNDEFStatusByte;
+
+//*****************************************************************************
+//
+//! Structure to hold NDEF Message header data. The message header encapsulates
+//! and contains metadata about the payload message. This structure is used
+//! with the NFCP2P_NDEFMessageEncoder and NFCP2P_NDEFMessageDecoder functions.
+//! For detailed information on the NDEF message header data, please see the NFC
+//! specification.
+//
+// NDEF Record Layout
+// _________________
+// | StatusByte | 1 byte
+// |-----------------|
+// | TYPE_LENGTH | 1 byte, hex value
+// |---------------- |
+// | PAYLOAD_LENGTH | 1 or 4 bytes
+// |---------------- |
+// | ID_LENGTH | 0 or 1 bytes
+// |---------------- |
+// | TYPE | 2 or 5 bytes
+// |---------------- |
+// | ID | 0 or 1 byte
+// |---------------- |
+// | |
+// | PAYLOAD | Multiple Bytes
+// | |
+// |-----------------|
+//
+// Note: The Type and ID field lengths are arbitrarily set and can be expanded
+// if desired. The PayloadLength field is set to the standard maximum.
+// The Payload is set as a pointer into the received buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Metadata about the message
+ //
+ sNDEFStatusByte sStatusByte;
+
+ //
+ //! Length of the Type field in bytes
+ //
+ uint8_t ui8TypeLength;
+
+ //
+ //! Length of the payload in bytes
+ //
+ uint32_t ui32PayloadLength;
+
+ //
+ //! Length of ID field in bytes. Optional field
+ //
+ uint8_t ui8IDLength;
+
+ //
+ //! Contains message type
+ //
+ uint8_t pui8Type[NDEF_TYPE_MAXSIZE];
+
+ //
+ //! Contains message ID. Optional field
+ //
+ uint8_t pui8ID[NDEF_ID_MAXSIZE];
+
+ //
+ //! Pointer to the encoded payload buffer
+ //
+ uint8_t *pui8PayloadPtr;
+
+} sNDEFMessageData;
+
+//*****************************************************************************
+//
+// General defines used to interpret data / set limits on buffer sizes
+//
+//*****************************************************************************
+//
+//! Check text record bit in the StatusByte to determine if text record is UTF8
+//! format.
+//!
+//! \b Example: Check Text Record for UTF8 format
+//!
+//! <tt> if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF8){}</tt>
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_UTF8 0 // DO NOT CHANGE
+
+//
+//! Check text record bit in the StatusByte to determine if text record is UTF16
+//! format.
+//!
+//! \b Example: Check Text Record for UTF16 format
+//!
+//! <tt> if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF16){}</tt>
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_UTF16 1 // DO NOT CHANGE
+
+//
+//! Define the size of the Text Record Language Code Buffer. This can be changed
+//! by the user to fit larger language codes that may develop in the future.
+//! Current language codes are 2 or 5 bits, but users can use larger sizes
+//! if they are adopted in the future.
+//
+#define NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE 5 // can be changed
+
+//*****************************************************************************
+//
+// Set Values into Raw StatusByte by | together
+//
+//*****************************************************************************
+
+//
+//! Set UTF bit field in TextRecord StatusByte field. This define should be ORed
+//! together with other StatusByte fields and set into StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Set UTF bit field to UTF8
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(
+//! NDEF_TEXTRECORD_STATUSBYTE_UTF8) |
+//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(ui8x) ((ui8x & 0x01) << 7)
+
+//
+//! Set the RFU bit field in the TextRecord StatusByte field. Should be ORed
+//! together with other StatusByte fields and set into StatusByte. The RFU field
+//! is reserved for future use by the NFC specification and should not be used
+//! by normal applications.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(0)|
+//! (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...)))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(ui8x) ((ui8x & 0x01) << 6)
+
+//
+//! Set the Language Code Length field in the TextRecord StatusByte field.
+//! This define should be ORed together with other StatusByte fields and set
+//! into StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(5) |
+//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(ui8x) ((ui8x & 0x3F) << 0)
+
+//*****************************************************************************
+//
+// Get values from Raw StatusByte
+//
+//*****************************************************************************
+
+//
+//! This macro extracts the UTF bit value from the raw StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the UTF boolean value in the data structure from the raw
+//! buffer byte
+//!
+//! <tt> sNDEFTextRecord.bUTFcode = NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(
+//! ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(ui8x) ((ui8x >> 7) & 0x01)
+
+//
+//! This macro extracts the RFU bit value from raw StatusByte. According to the
+//! NFC specification, this value must be zero.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the RFU boolean value in the data structure from the raw
+//! buffer byte
+//!
+//! <tt> sNDEFTextRecord.bRFU = NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(
+//! ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(ui8x) ((ui8x >> 6) & 0x01)
+
+//
+//! This macro extracts the Language Code Length field from the raw StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the Language Code Length field in the data structure from
+//! the raw buffer byte
+//!
+//! <tt>
+//! sNDEFTextRecord.ui5LengthLangCode =
+//! NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8x) ((ui8x >> 0) & 0x3F)
+
+//*****************************************************************************
+//
+//! This structure defines the text record status byte.
+//! bUTFcode determines if the Text Record is encoded with UTF8 (0) or
+//! UTF16 (1). bRFU is reserved for future use by the NFC specification.
+//! ui5LengthLangCode holds the length of the language code. Currently
+//! language code lengths are either 2 or 5 bytes.
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0|
+// |------------------------------|
+// |UTF|RFU| Length of Lang Code | = StatusByte
+// |------------------------------|
+//
+// UTF = UTF8 or UTF16 text string formatting (0 = UTF8, 1 = UTF16)
+// RFU = 0, no exceptions, its reserved for future use
+// LenLangCode = 6 bytes to determine the Length of Language Code (next field)
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Flag for UTF Code. 0 = UTF8, 1 = UTF16
+ //
+ bool bUTFcode;
+
+ //
+ //! Reserved for future use by NFC specification
+ //
+ bool bRFU;
+
+ //
+ //! Length of Text Record language code
+ //
+ uint8_t ui5LengthLangCode;
+
+} sNDEFTextRecordStatusByte;
+
+//*****************************************************************************
+//
+//! This structure defines the text record. sStatusByte contains the length of
+//! the language code and the formatting for the Text (UTF8/UTF16).
+//! pui8LanguageCode is a buffer that contains the language code; the buffer
+//! size can be changed at compile time by modifying the
+//! NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE define. pui8Text is a pointer to the
+//! text payload of the Text Record. These three fields are defined in the
+//! NFC specification. In addition, ui32TextLength has been added for
+//! convenience to keep track of the Text buffer length. For example, a
+//! text record with the Text "hello world" would have a StatusByte of 0x02
+//! (UTF = 0 (UTF8), LenLangCode = 0x2), a Language Code of "en"
+//! (for English, note that it is 2 bytes long just as the ui5LengthLangCode
+//! field of the Text Record StatusByte denoted), pui8Text points to
+//! a buffer holding "hello world", and ui32TextLength has a value of 11,
+//! which is the number of chars in "hello world".
+//
+// NDEF message Text Record Payload Layout
+// _________________
+// | StatusByte | = 1 byte
+// |-----------------|
+// | Language Code | = 2-5 bytes
+// |-----------------|
+// | |
+// | Text | = Multiple Bytes
+// | |
+// |-----------------|
+//
+// Note: the contents of a text record are freeform plain text in either
+// UTF8 or UTF16 format.
+//
+// Note: the TextRecordLength is used in lieu of a terminiating sentinel on
+// the puiText buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Structure to hold StatusByte information
+ //
+ sNDEFTextRecordStatusByte sStatusByte;
+
+ //
+ //! Buffer that holds the Language Code
+ //
+ uint8_t pui8LanguageCode[NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE];
+
+ //
+ //! Pointer to the Text Buffer
+ //
+ uint8_t *pui8Text;
+
+ //
+ //! Length of text in Text Buffer
+ //
+ uint32_t ui32TextLength;
+
+} sNDEFTextRecord;
+
+//*****************************************************************************
+//
+//! Define used to mark end of well-defined URI Record ID Codes. Any code
+//! greater than this value is not defined by the NFC specification.
+//!
+//! \b Example: Check if ID Code of Tag is known defined value
+//!
+//! <tt>
+//! \verbatim
+//! if(sNDEFURIRecord.eIDCode < NDEF_URIRECORD_IDCODE_RFU)
+//! {
+//! //process tag
+//! }
+//! \endverbatim
+//! </tt>
+//
+//*****************************************************************************
+#define NDEF_URIRECORD_IDCODE_RFU 0x24
+
+//*****************************************************************************
+//
+//! Enumeration of all possible URI Record ID Codes defined by the NFC
+//! specification.
+//! For the complete list, please see the enumeration definition in nfc_p2p.h.
+//! Defined values range from 0x00 (no prepending) to 0x23 ('urn:nfc:').
+//! Values 0x24 and above are reserved for future use.
+//
+// Acceptable Prepending values are:
+// 0x00 N/A. No prepending is done
+// 0x01 http://www.
+// 0x02 https://www.
+// 0x03 http://
+// 0x04 https://
+// 0x05 tel:
+// 0x06 mailto:
+// 0x07 ftp://anonymous:anonymous@
+// 0x08 ftp://ftp.
+// 0x09 ftps://
+// 0x0A sftp://
+// 0x0B smb://
+// 0x0C nfs://
+// 0x0D ftp://
+// 0x0E dav://
+// 0x0F news:
+// 0x10 telnet://
+// 0x11 imap:
+// 0x12 rtsp://
+// 0x13 urn:
+// 0x14 pop:
+// 0x15 sip:
+// 0x16 sips:
+// 0x17 tftp:
+// 0x18 btspp://
+// 0x19 btl2cap://
+// 0x1A btgoep://
+// 0x1B tcpobex://
+// 0x1C irdaobex://
+// 0x1D file://
+// 0x1E urn:epc:id:
+// 0x1F urn:epc:tag:
+// 0x20 urn:epc:pat:
+// 0x21 urn:epc:raw:
+// 0x22 urn:epc:
+// 0x23 urn:nfc:
+//
+// 0x24-0xFF RFU Reserved for Future Use, Not Valid Inputs
+//
+//*****************************************************************************
+typedef enum
+{
+
+ //
+ //! Nothing is prepended to puiUTF8String
+ //
+ unabridged = 0x00,
+
+ //
+ //! 'http://www.' is prepended to puiUTF8String
+ //
+ http_www = 0x01,
+
+ //
+ //! 'https://www.' is prepended to puiUTF8String
+ //
+ https_www = 0x02,
+
+ //
+ //! 'http://' is prepended to puiUTF8String
+ //
+ http = 0x03,
+
+ //
+ //! 'https://' is prepended to puiUTF8String
+ //
+ https = 0x04,
+
+ //
+ //! 'tel:' is prepended to puiUTF8String
+ //
+ tel = 0x05,
+
+ //
+ //! 'mailto:' is prepended to puiUTF8String
+ //
+ mailto = 0x06,
+
+ //
+ //! 'ftp://anonymous:anonymous@' is prepended to puiUTF8String
+ //
+ ftp_anonymous = 0x07,
+
+ //
+ //! 'ftp://ftp.' is prepended to puiUTF8String
+ //
+ ftp_ftp = 0x08,
+
+ //
+ //! 'ftps://' is prepended to puiUTF8String
+ //
+ ftps = 0x09,
+
+ //
+ //! 'sftp://' is prepended to puiUTF8String
+ //
+ sftp = 0x0A,
+
+ //
+ //! 'smb://' is prepended to puiUTF8String
+ //
+ smb = 0x0B,
+
+ //
+ //! 'nfs://' is prepended to puiUTF8String
+ //
+ nfs = 0x0C,
+
+ //
+ //! 'ftp://' is prepended to puiUTF8String
+ //
+ ftp = 0x0D,
+
+ //
+ //! 'dav://' is prepended to puiUTF8String
+ //
+ dav = 0x0E,
+
+ //
+ //! 'news:' is prepended to puiUTF8String
+ //
+ news = 0x0F,
+
+ //
+ //! 'telnet://' is prepended to puiUTF8String
+ //
+ telnet = 0x10,
+
+ //
+ //! 'imap:' is prepended to puiUTF8String
+ //
+ imap = 0x11,
+
+ //
+ //! 'rtsp://' is prepended to puiUTF8String
+ //
+ rtsp = 0x12,
+
+ //
+ //! 'urn:' is prepended to puiUTF8String
+ //
+ urn = 0x13,
+
+ //
+ //! 'pop:' is prepended to puiUTF8String
+ //
+ pop = 0x14,
+
+ //
+ //! 'sip:' is prepended to puiUTF8String
+ //
+ sip = 0x15,
+
+ //
+ //! 'sips:' is prepended to puiUTF8String
+ //
+ sips = 0x16,
+
+ //
+ //! 'tftp:' is prepended to puiUTF8String
+ //
+ tftp = 0x17,
+
+ //
+ //! 'btspp://' is prepended to puiUTF8String
+ //
+ btspp = 0x18,
+
+ //
+ //! 'btl2cap://' is prepended to puiUTF8String
+ //
+ btl2cap = 0x19,
+
+ //
+ //! 'btgoep://' is prepended to puiUTF8String
+ //
+ btgoep = 0x1A,
+
+ //
+ //! 'tcpobex://' is prepended to puiUTF8String
+ //
+ tcpobex = 0x1B,
+
+ //
+ //! 'irdaobex://' is prepended to puiUTF8String
+ //
+ irdaobex = 0x1C,
+
+ //
+ //! 'file://' is prepended to puiUTF8String
+ //
+ file = 0x1D,
+
+ //
+ //! 'urn:epc:id:' is prepended to puiUTF8String
+ //
+ urn_epc_id = 0x1E,
+
+ //
+ //! 'urn:epc:tag:' is prepended to puiUTF8String
+ //
+ urn_epc_tag = 0x1F,
+
+ //
+ //! 'urn:epc:pat:' is prepended to puiUTF8String
+ //
+ urn_epc_pat = 0x20,
+
+ //
+ //! 'urn:epc:raw:' is prepended to puiUTF8String
+ //
+ urn_epc_raw = 0x21,
+
+ //
+ //! 'urn:epc:' is prepended to puiUTF8String
+ //
+ urn_epc = 0x22,
+
+ //
+ //! 'urn:nfc:' is prepended to puiUTF8String
+ //
+ urn_nfc = 0x23,
+
+ //
+ //! Values equal to and above this are reserved for future use (RFU)
+ //
+ RFU = 0x24
+
+} eNDEF_URIRecord_IDCode;
+
+//*****************************************************************************
+//
+//! This structure defines the URI record type. The URI Record Type has two
+//! fields; the ID code and the UTF8 URI string. The IDCode is used to
+//! determine the URI type. For example, IDcode of 0x06 is 'mailto:'
+//! and usually triggers an email event. IDcode 0x01 is 'http://www.' and
+//! usually triggers a webpage to open. The IDcode values are prepended to
+//! the UTF8 string. ui32URILength is used to determine the length of the
+//! puiUTF8String buffer. For example, to direct a user to 'http://www.ti.com'
+//! the IDcode is 0x01, the UTF8 string is 'ti.com', and the ui32URILength is
+//! 0x6.
+//
+// NDEF message URI Record Payload Layout
+// _________________
+// | ID Code | 1 byte
+// |-----------------|
+// | |
+// | UTF8 String | Multiple Bytes
+// | |
+// |-----------------|
+//
+// The URI string is multiple bytes of UTF8 format text with a possible
+// prepended value depending on the ID Code
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Enumeration of all possible ID codes
+ //
+ eNDEF_URIRecord_IDCode eIDCode;
+
+ //
+ //! Buffer that holds the URI character string
+ //
+ uint8_t *puiUTF8String;
+
+ //
+ //! Length of URI Character String
+ //
+ uint32_t ui32URILength;
+
+} sNDEFURIRecord;
+
+//*****************************************************************************
+//
+//! Enumeration of the three actions that can be associated with an Action
+//! Record.
+//
+//*****************************************************************************
+typedef enum
+{
+
+ //
+ //! Do Action on Record
+ //
+ DO_ACTION = 0x00,
+
+ //
+ //! Save Record for Later
+ //
+ SAVE_FOR_LATER = 0x01,
+
+ //
+ //! Open Record for Editing
+ //
+ OPEN_FOR_EDITING = 0x02
+
+} tAction;
+
+//*****************************************************************************
+//
+//! This structure defines an Action Record
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Action Record type enumeration
+ //
+ tAction eAction;
+
+} sNDEFActionRecord;
+
+//*****************************************************************************
+//
+//! This structure defines the SmartPoster record type.
+//! The SmartPoster Record is essentially
+//! a URI Record with other records included for metadata. Thus
+//! the SmartPoster must include at least a URI Record and may also include a
+//! Text Record for a Title record, an Action record to do actions on the URI,
+//! an Icon Record with a small icon, a Size record that holds the size of the
+//! externally referenced entity, and a Type record that denotes the type of the
+//! externally referenced entity. It should be noted that while the SmartPoster
+//! specification can include all these records, this library only provides
+//! support for Title, URI and Action records. All other records are ignored
+//! by the default handler.
+//
+// NDEF message SmartPoster Record Payload consists of multiple fully wrapped
+// NDEF records. The basic layout is a URI record with subsequent records as
+// metadata on size, type, icon, title, and action associated with record.
+//
+// The possible record types are :
+// Title Record : multiple possible in different languages (Text Record)
+// URI Record : 1 and only 1, core of Smart Poster record
+// Action Record : how to treat the URI (Do, Save for later, Open for edit)
+// Icon Record : MIME type image record [optional]
+// Size Record : size of external referenced entity (web link) [optional]
+// Type Record : MIME type of external referenced entity [optional
+//
+//
+// Note: Currently only Title,URI, and Action records are supported.
+// Image, Type and size records are not implemented.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! message header for Text Record
+ //
+ sNDEFMessageData sTextHeader;
+
+ //
+ //! Text Record payload structure
+ //
+ sNDEFTextRecord sTextPayload;
+
+ //
+ //! message header for URI Record
+ //
+ sNDEFMessageData sURIHeader;
+
+ //
+ //! URI Record payload strucutre
+ //
+ sNDEFURIRecord sURIPayload;
+
+ //
+ //! Flag to signal if Action Record is part of Smart Poster
+ //
+ bool bActionExists;
+
+ //
+ //! message header for Action Record
+ //
+ sNDEFMessageData sActionHeader;
+
+ //
+ //! Action Record payload strucutre
+ //
+ sNDEFActionRecord sActionPayload;
+
+} sNDEFSmartPosterRecord;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCP2P_init(tTRF79x0TRFMode eMode,tTRF79x0Frequency eFrequency);
+tNFCP2PState NFCP2P_proccessStateMachine(void);
+tStatus NFCP2P_sendPacket(uint8_t *pui8DataPtr, uint32_t ui32DataLength);
+sNFCP2PRxStatus NFCP2P_getReceiveState(void);
+
+bool NFCP2P_NDEFMessageEncoder(sNDEFMessageData sNDEFDataToSend,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength);
+bool NFCP2P_NDEFMessageDecoder(sNDEFMessageData *psNDEFDataDecoded,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength);
+bool NFCP2P_NDEFTextRecordEncoder(sNDEFTextRecord sTextRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFTextRecordDecoder(sNDEFTextRecord *sTextRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength);
+bool NFCP2P_NDEFURIRecordEncoder(sNDEFURIRecord sURIRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFURIRecordDecoder(sNDEFURIRecord *sURIRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength);
+bool NFCP2P_NDEFSmartPosterRecordEncoder(sNDEFSmartPosterRecord sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFSmartPosterRecordDecoder(sNDEFSmartPosterRecord *sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t ui32BufferLength);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif //__NFC_P2P_H__
diff --git a/nfclib/snep.c b/nfclib/snep.c new file mode 100644 index 0000000..dc0bd95 --- /dev/null +++ b/nfclib/snep.c @@ -0,0 +1,760 @@ +//*****************************************************************************
+//
+// snep.c - implementation of Simple NDEF Exchange Protocol, uses LLCP
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "nfclib/snep.h"
+#include "nfclib/debug.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_snep_api NFC SNEP API Functions
+//! @{
+//! Simple NDEF Exchange Protocol is an application protocol used by the LLCP
+//! layer to send / receive NDEFs between two NFC Forum Devices operating
+//! in Peer-to-Peer Mode (1 Target and 1 Initiator). For more information
+//! on SNEP, please read the NFC Simple NDEF Exchange Protocol Specification
+//! Version 1.0.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Stores the length of the Tx/Rx packet.
+//
+//****************************************************************************
+uint32_t g_ui32SNEPPacketLength;
+
+//*****************************************************************************
+//
+// g_pui8SNEPTxPacketPtr points to the first location of the data to be
+// transferred
+//
+//*****************************************************************************
+uint8_t * g_pui8SNEPTxPacketPtr;
+uint8_t * g_pui8SNEPRxPacketPtr;
+
+//*****************************************************************************
+//
+// Stores the remaining rx byte count
+//
+//*****************************************************************************
+uint32_t g_ui32SNEPRemainingRxPayloadBytes = 0;
+
+//*****************************************************************************
+//
+// Stores the bytes received in the current I-PDU transaction
+//
+//*****************************************************************************
+uint8_t g_ui8SNEPReceivedBytes = 0;
+
+//*****************************************************************************
+//
+// Stores the status of the incoming packet
+//
+//*****************************************************************************
+tPacketStatus g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+
+//*****************************************************************************
+//
+// Stores the status of the SNEP communication
+//
+//*****************************************************************************
+tSNEPConnectionStatus g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+//*****************************************************************************
+//
+// Stores the maximum size of each SNEP packet.
+//
+//*****************************************************************************
+uint8_t g_ui8MaxPayload = SNEP_MAX_BUFFER;
+
+//*****************************************************************************
+//
+// Stores the index of the current transaction
+//
+//*****************************************************************************
+uint32_t g_ui32TxIndex = 0;
+
+//*****************************************************************************
+//
+//! Initialize the Simple NDEF Exchange Protocol driver.
+//!
+//! This function must be called prior to any other function offered by the
+//! SNEP driver. This function initializes the SNEP status, Tx/Rx packet length
+//! and maximum payload size. This function must be called by the LLCP_init().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void SNEP_init(void)
+{
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+ g_ui32SNEPRemainingRxPayloadBytes = 0;
+ g_ui8SNEPReceivedBytes = 0;
+ g_ui8MaxPayload = SNEP_MAX_BUFFER;
+ g_ui32TxIndex = 0;
+}
+
+//*****************************************************************************
+//
+//! Set the Maximum size of each fragment.
+//!
+//! \param ui8MaxPayload is the maximum size of each fragment.
+//!
+//! This function must be called inside LLCP_processTLV() to define the maxium
+//! size of each fragment based on the Maximum Information Unit (MIU) supported
+//! by the target/initiator.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void SNEP_setMaxPayload(uint8_t ui8MaxPayload)
+{
+ if(ui8MaxPayload <= SNEP_MAX_BUFFER)
+ {
+ g_ui8MaxPayload = ui8MaxPayload;
+ if(g_ui8MaxPayload == 0x80)
+ {
+ ui8MaxPayload = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Set the global SNEP Packet Pointer and Length
+//!
+//! \param pui8PacketPtr is the pointer to the first payload to be transmitted.
+//! \param ui32PacketLength is the length of the total packet.
+//!
+//! This function must be called by the main application to initialize the
+//! packet to be sent to the SNEP server.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) if the packet was
+//! queued, else it returns \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+tStatus SNEP_setupPacket(uint8_t * pui8PacketPtr, uint32_t ui32PacketLength)
+{
+ tStatus ePacketSetupStatus;
+
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE )
+ {
+ g_pui8SNEPTxPacketPtr = pui8PacketPtr;
+ // Reset TX Index
+ g_ui32TxIndex = 0;
+ g_ui32SNEPPacketLength = ui32PacketLength;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+
+ ePacketSetupStatus = STATUS_SUCCESS;
+ }
+ else
+ ePacketSetupStatus = STATUS_FAIL;
+
+ return ePacketSetupStatus;
+}
+
+
+//*****************************************************************************
+//
+//! Sends request to the server.
+//!
+//! \param pui8DataPtr is the start pointer where the request is written.
+//! \param eRequestCmd is the request command to be sent.
+//!
+//! The \e eRequestCmd parameter can be any of the following:
+//!
+//! - \b SNEP_REQUEST_CONTINUE - Send remaining fragments
+//! - \b SNEP_REQUEST_GET - Return an NDEF message
+//! - \b SNEP_REQUEST_PUT - Accept an NDEF message
+//! - \b SNEP_REQUEST_REJECT - Do not send remaining fragments
+//!
+//! This function sends an SNEP request from the SNEP client to an SNEP server.
+//! It must be called from the LLCP_sendI() function.
+//!
+//! \return \b ui8offset, which is the length of the request written starting at
+//! \b pui8DataPtr.
+//
+//*****************************************************************************
+uint8_t SNEP_sendRequest(uint8_t * pui8DataPtr, tSNEPCommands eRequestCmd)
+{
+ uint8_t ui8PacketLength;
+ uint8_t ui8offset = 0;
+ static uint8_t * pui8SNEPPacketPtr;
+ volatile uint8_t ui8counter;
+
+ switch(eRequestCmd)
+ {
+ case SNEP_REQUEST_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE)
+ break;
+ }
+ case SNEP_REQUEST_GET:
+ {
+ break;
+ }
+ case SNEP_REQUEST_PUT:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE)
+ {
+ //
+ // Set sneP_packet_ptr to first address
+ //
+ pui8SNEPPacketPtr = g_pui8SNEPTxPacketPtr;
+
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Request Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_REQUEST_PUT;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0xFF000000) >> 24);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0x00FF0000) >> 16);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0x0000FF00) >> 8);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) (g_ui32SNEPPacketLength & 0x000000FF);
+
+ //
+ // The PUT Request has 6 bytes of overhead (Version (1) Request
+ // Field (1) Length (4)).
+ //
+ if( g_ui32SNEPPacketLength > (g_ui8MaxPayload - 6))
+ {
+ //
+ // Remaining bytes = Total Length - (SNEP_MAX_BUFFER - 13)
+ //
+ g_ui32SNEPPacketLength = g_ui32SNEPPacketLength -
+ (g_ui8MaxPayload - 6);
+ ui8PacketLength = (g_ui8MaxPayload - 6);
+
+ //
+ // Change connection status to waiting for continue
+ //
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE;
+ }
+ else
+ {
+ ui8PacketLength = g_ui32SNEPPacketLength;
+ g_ui32SNEPPacketLength = 0;
+
+ //
+ // Change connection status to waiting for success
+ //
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS;
+ }
+
+ //
+ // Copy the snep_packet buffer into the pui8DataPtr
+ //
+ for(ui8counter = 0; ui8counter < ui8PacketLength; ui8counter++)
+ {
+ pui8DataPtr[ui8offset++] = pui8SNEPPacketPtr[g_ui32TxIndex++];
+
+ }
+ }
+ else if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS)
+ {
+ if( g_ui32SNEPPacketLength > g_ui8MaxPayload)
+ {
+ //
+ // Remaining bytes = Total Length - SNEP_MAX_BUFFER
+ //
+ g_ui32SNEPPacketLength = g_ui32SNEPPacketLength -
+ g_ui8MaxPayload;
+ ui8PacketLength = g_ui8MaxPayload;
+ }
+ else
+ {
+ ui8PacketLength = g_ui32SNEPPacketLength;
+ //
+ // Remaining bytes = 0
+ //
+ g_ui32SNEPPacketLength = 0;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_WAITING_FOR_SUCCESS;
+ }
+
+ //
+ // Copy the snep_packet buffer into the pui8DataPtr
+ //
+ for(ui8counter = 0; ui8counter < ui8PacketLength; ui8counter++)
+ {
+ pui8DataPtr[ui8offset++] = pui8SNEPPacketPtr[g_ui32TxIndex++];
+ }
+
+ }
+ break;
+ }
+ case SNEP_REQUEST_REJECT:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return ui8offset;
+}
+
+//*****************************************************************************
+//
+//! Sends response to the client.
+//!
+//! \param pui8DataPtr is the start pointer where the response is written.
+//! \param eResponseCmd is the response command to be sent.
+//!
+//! The \e eResponseCmd parameter can be any of the following:
+//!
+//! - \b SNEP_RESPONSE_CONTINUE - Continue send remaining fragments
+//! - \b SNEP_RESPONSE_SUCCESS - Operation succeeded
+//! - \b SNEP_RESPONSE_NOT_FOUND - Resource not found
+//! - \b SNEP_RESPONSE_EXCESS_DATA - Resource exceeds data size limit
+//! - \b SNEP_RESPONSE_BAD_REQUEST - Malformed request not understood
+//! - \b SNEP_RESPONSE_NOT_IMPLEMENTED - Unsupported functionality requested
+//! - \b SNEP_RESPONSE_UNSUPPORTED_VER - Unsupported protocol version
+//! - \b SNEP_RESPONSE_REJECT - Do not send remaining fragments
+//!
+//! This function sends an SNEP response from the SNEP server to an SNEP client.
+//! It must be called from the LLCP_sendI() function.
+//!
+//! \return \b ui8offset is the length of the response written starting at
+//! \b pui8DataPtr.
+//
+//*****************************************************************************
+uint8_t SNEP_sendResponse(uint8_t * pui8DataPtr, tSNEPCommands eResponseCmd)
+{
+ uint8_t ui8offset = 0;
+
+ switch(eResponseCmd)
+ {
+ case SNEP_RESPONSE_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_CONTINUE;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVING_N_FRAGMENTS;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_SUCCESS:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVE_COMPLETE)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_SUCCESS;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_NOT_FOUND:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_EXCESS_DATA:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_BAD_REQUEST:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_NOT_IMPLEMENTED:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_UNSUPPORTED_VER:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_REJECT:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_EXCESS_SIZE)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_REJECT;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return ui8offset;
+}
+
+//*****************************************************************************
+//
+//! Processes the data received from a client/server.
+//!
+//! \param pui8RxBuffer is the starting pointer of the SNEP request/response
+//! received.
+//! \param ui8RxLength is the length of the SNEP request/response received.
+//!
+//! This function handles the requests/responses received inside an I-PDU
+//! in the LLCP layer. This function must be called inside
+//! LLCP_processReceivedData().
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8RxLength)
+{
+ volatile uint8_t ui8SNEPversion;
+ tSNEPCommands eCommandField;
+
+ eCommandField = (tSNEPCommands) pui8RxBuffer[1];
+
+ if((g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET) ||
+ (g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVING_N_FRAGMENTS))
+ {
+ if(g_ui32SNEPRemainingRxPayloadBytes > ui8RxLength)
+ {
+ g_ui8SNEPReceivedBytes = ui8RxLength;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVING_N_FRAGMENTS;
+ g_eRxPacketStatus = RECEIVED_N_FRAGMENT;
+ }
+ else
+ {
+ g_ui8SNEPReceivedBytes = (uint8_t)g_ui32SNEPRemainingRxPayloadBytes;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVE_COMPLETE;
+ g_eRxPacketStatus = RECEIVED_FRAGMENT_COMPLETED;
+ }
+ g_ui32SNEPRemainingRxPayloadBytes = g_ui32SNEPRemainingRxPayloadBytes -
+ g_ui8SNEPReceivedBytes;
+ g_pui8SNEPRxPacketPtr = &pui8RxBuffer[0];
+ }
+ else if(eCommandField >= 0x80)
+ {
+ //
+ // Process Responses
+ //
+ switch(eCommandField)
+ {
+ case SNEP_RESPONSE_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE)
+ {
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_SUCCESS:
+ {
+ if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS)
+ {
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_SEND_COMPLETE;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_NOT_FOUND:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_EXCESS_DATA:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_BAD_REQUEST:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_NOT_IMPLEMENTED:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_UNSUPPORTED_VER:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_REJECT:
+ {
+ break;
+ }
+ default :
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Process Requests
+ //
+ switch(eCommandField)
+ {
+ case SNEP_REQUEST_CONTINUE:
+ {
+ break;
+ }
+ case SNEP_REQUEST_GET:
+ {
+ break;
+ }
+ case SNEP_REQUEST_PUT:
+ {
+ ui8SNEPversion = pui8RxBuffer[0];
+ if(ui8SNEPversion == SNEP_VERSION)
+ {
+ //
+ // Update remaining payload bytes
+ //
+ g_ui32SNEPRemainingRxPayloadBytes =
+ (
+ (uint32_t) (pui8RxBuffer[5] & 0xFF) +
+ ((uint32_t) (pui8RxBuffer[4] & 0xFF) << 8) +
+ ((uint32_t) (pui8RxBuffer[3] & 0xFF) << 16) +
+ ((uint32_t) (pui8RxBuffer[2] & 0xFF) << 24)
+ );
+ if(g_ui32SNEPRemainingRxPayloadBytes > SNEP_MAX_PAYLOAD)
+ {
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_EXCESS_SIZE;
+ }
+ else
+ {
+ if (g_ui32SNEPRemainingRxPayloadBytes
+ > (ui8RxLength - 6)) {
+ g_ui8SNEPReceivedBytes = (ui8RxLength - 6);
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET;
+ g_eRxPacketStatus = RECEIVED_FIRST_FRAGMENT;
+ }
+ else
+ {
+ //
+ // Packet Length
+ //
+ g_ui8SNEPReceivedBytes =
+ (uint8_t) g_ui32SNEPRemainingRxPayloadBytes;
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_RECEIVE_COMPLETE;
+ g_eRxPacketStatus = RECEIVED_FRAGMENT_COMPLETED;
+ }
+ //
+ // Update remaining payload bytes
+ //
+ g_ui32SNEPRemainingRxPayloadBytes =
+ g_ui32SNEPRemainingRxPayloadBytes
+ - g_ui8SNEPReceivedBytes;
+
+ //
+ // Set the g_pui8SNEPRxPacketPtr to the start of payload
+ //
+ g_pui8SNEPRxPacketPtr = &pui8RxBuffer[6];
+
+ }
+ }
+ else
+ {
+ g_eSNEPConnectionStatus = SNEP_WRONG_VERSION_RECEIVED;
+ }
+ break;
+ }
+ case SNEP_REQUEST_REJECT:
+ {
+ break;
+ }
+ default :
+ {
+ break;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Get RxStatus flag, Clear packet status flag,retrieve length of data and
+//! retrieve data
+//!
+//! \param peReceiveFlag is a pointer to store the RX state status.
+//! \param pui8length is a pointer to store the number of received bytes.
+//! \param pui8DataPtr is a double pointer to store the pointer of data
+//! received.
+//!
+//! The \e peReceiveFlag parameter can be any of the following:
+//!
+//! - \b RECEIVED_NO_FRAGMENT - No Fragment has been received
+//! - \b RECEIVED_FIRST_FRAGMENT - First fragment has been received.
+//! - \b RECEIVED_N_FRAGMENT - N Fragment has been received.
+//! - \b RECEIVED_FRAGMENT_COMPLETED - End of the fragment has been received.
+//!
+//! This function must be called in the main application after the
+//! NFCP2P_proccessStateMachine() is called to ensure the data received is moved
+//! to another buffer and handled when a fragment is received.
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_getReceiveStatus(tPacketStatus * peReceiveFlag, uint8_t * pui8length,
+ uint8_t ** pui8DataPtr)
+{
+ //
+ // Save RX Packet Status Flag
+ //
+ *peReceiveFlag = g_eRxPacketStatus;
+
+ //
+ // Clear the packet status flag
+ //
+ g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+
+ //
+ // Save Number of Byted received
+ //
+ *pui8length = g_ui8SNEPReceivedBytes;
+
+ //
+ // Set Data = ReceivedPacket
+ //
+ *pui8DataPtr = g_pui8SNEPRxPacketPtr;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Returns current SNEP Connection Status enumeration
+//!
+//! This function returns the current SNEP status flag. It must be called inside
+//! LLCP_processReceivedData() to determine if further I-PDUs are required,
+//! which is when there are requests/responses queued.
+//!
+//! \return g_eSNEPConnectionStatus the current connection status flag.
+//
+//*****************************************************************************
+tSNEPConnectionStatus SNEP_getProtocolStatus(void)
+{
+ return g_eSNEPConnectionStatus;
+}
+
+//*****************************************************************************
+//
+//! Sets current SNEP Connection Status enumeration
+//!
+//! \param eProtocolStatus is the status flag used by the SNEP state machine
+//! SNEP_processReceivedData() to send request/response.
+//! New sent transactions are allowed only when eProtocolStatus is set
+//! to \b SNEP_CONNECTION_IDLE.
+//!
+//! The \e eProtocolStatus parameter can be any of the following:
+//!
+//! - \b SNEP_CONNECTION_IDLE - No ongoing Tx/Rx
+//! - \b SNEP_WRONG_VERSION_RECEIVED - Wrong Version Received
+//! - \b SNEP_CONNECTION_RECEIVED_FIRST_PACKET - Received First Fragment
+//! - \b SNEP_CONNECTION_RECEIVING_N_FRAGMENTS - Received N Fragment
+//! - \b SNEP_CONNECTION_WAITING_FOR_CONTINUE - Waiting for Continue response
+//! - \b SNEP_CONNECTION_WAITING_FOR_SUCCESS - Waiting for Success response
+//! - \b SNEP_CONNECTION_SENDING_N_FRAGMENTS - Sending N Fragment
+//! - \b SNEP_CONNECTION_SEND_COMPLETE - Send Completed
+//! - \b SNEP_CONNECTION_RECEIVE_COMPLETE - Receive Completed
+//! - \b SNEP_CONNECTION_EXCESS_SIZE - Received Excess Size request
+//!
+//! This function is called inside LLCP_processReceivedData(), to set the
+//! \e g_eSNEPConnectionStatus flag to \b SNEP_CONNECTION_IDLE after
+//! a send transaction is completed to allow for further send transactions.
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_setProtocolStatus(tSNEPConnectionStatus eProtocolStatus)
+{
+ g_eSNEPConnectionStatus = eProtocolStatus;
+ return;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/nfclib/snep.h b/nfclib/snep.h new file mode 100644 index 0000000..561c688 --- /dev/null +++ b/nfclib/snep.h @@ -0,0 +1,206 @@ +//*****************************************************************************
+//
+// snep.h - Simple NDEF Exchange Protocol deffinitions
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_SNEP_H__
+#define __NFC_SNEP_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_snep_api NFC SNEP API Functions
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This size is used to limit the maximum size of the incoming NDEF message.
+// The maximum is dependent on the Maximum Information Units (MIU) defined in
+// the LLCP layer.
+// For example for MIU = 248, SNEP_MAX_BUFFER = 248
+//
+//*****************************************************************************
+//
+//! This is the maximum size of a fragment that is sent/received.
+//
+#define SNEP_MAX_BUFFER 248
+
+//
+//! Maximum size of the incoming payload.
+//
+#define SNEP_MAX_PAYLOAD 20000
+
+//
+//! Simple NDEF protocol version specified in the specification.
+//
+#define SNEP_VERSION 0x10
+
+//*****************************************************************************
+//
+// List of SNEP Commands
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! SNEPCommand request / responses enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // SNEP request field value
+ //
+
+ //! See SNEP V1.0 Section 4.1
+ SNEP_REQUEST_CONTINUE = 0x00,
+
+ //! See SNEP V1.0 Section 4.2
+ SNEP_REQUEST_GET = 0x01,
+
+ //! See SNEP V1.0 Section 4.3
+ SNEP_REQUEST_PUT = 0x02,
+ // 03h-7Eh Reserved for future use
+
+ //! See SNEP V1.0 Section 4.4
+ SNEP_REQUEST_REJECT = 0x7F,
+ // 80h-FFh Reserved for response field values
+
+ //
+ // See SNEP Response Field Values
+ //
+ // 00h-7Fh Reserved for request field values
+
+ //! See SNEP V1.0 Section 5.1
+ SNEP_RESPONSE_CONTINUE = 0x80,
+
+ //! See SNEP V1.0 Section 5.2
+ SNEP_RESPONSE_SUCCESS = 0x81,
+
+ //! See SNEP V1.0 Section 5.3
+ SNEP_RESPONSE_NOT_FOUND = 0xC0,
+
+ //! See SNEP V1.0 Section 5.4
+ SNEP_RESPONSE_EXCESS_DATA = 0xC1,
+
+ //! See SNEP V1.0 Section 5.5
+ SNEP_RESPONSE_BAD_REQUEST = 0xC2,
+
+ //! See SNEP V1.0 Section 5.6
+ SNEP_RESPONSE_NOT_IMPLEMENTED = 0xE0,
+
+ //! See SNEP V1.0 Section 5.7
+ SNEP_RESPONSE_UNSUPPORTED_VER = 0xE1,
+
+ //! See SNEP V1.0 Section 5.8
+ SNEP_RESPONSE_REJECT = 0xFF
+}tSNEPCommands;
+
+//*****************************************************************************
+//
+//! SNEP Connection Status Enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! No ongoing transaction to/from the client
+ SNEP_CONNECTION_IDLE = 0x00,
+
+ //! Wrong version received
+ SNEP_WRONG_VERSION_RECEIVED,
+
+ //! Received first fragment
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET,
+
+ //! Received n fragment
+ SNEP_CONNECTION_RECEIVING_N_FRAGMENTS,
+
+ //! Waiting for continue response
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE,
+
+ //! Waiting for success response
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS,
+
+ //! Sending n fragment
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS,
+
+ //! Send completed
+ SNEP_CONNECTION_SEND_COMPLETE,
+
+ //! Receive completed
+ SNEP_CONNECTION_RECEIVE_COMPLETE,
+
+ //! Received excess size request.
+ SNEP_CONNECTION_EXCESS_SIZE
+}tSNEPConnectionStatus;
+
+//*****************************************************************************
+//
+//! RX packet status enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! No pending received data
+ //
+ RECEIVED_NO_FRAGMENT = 0,
+
+ //
+ //! First fragment received from the client
+ //
+ RECEIVED_FIRST_FRAGMENT,
+
+ //
+ //! N fragment received from the client
+ RECEIVED_N_FRAGMENT,
+
+ //! Last fragment received from the client - packet completed
+ RECEIVED_FRAGMENT_COMPLETED
+}tPacketStatus;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void SNEP_init(void);
+void SNEP_setMaxPayload(uint8_t ui8MaxPayload);
+tStatus SNEP_setupPacket(uint8_t * pui8PacketPtr, uint32_t ui32PacketLength);
+uint8_t SNEP_sendRequest(uint8_t * pui8DataPtr, tSNEPCommands eRequestCmd);
+uint8_t SNEP_sendResponse(uint8_t * pui8DataPtr, tSNEPCommands eResponseCmd);
+void SNEP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8RxLength);
+void SNEP_getReceiveStatus(tPacketStatus * peReceiveFlag, uint8_t * length,
+ uint8_t ** pui8DataPtr);
+tSNEPConnectionStatus SNEP_getProtocolStatus(void);
+void SNEP_setProtocolStatus(tSNEPConnectionStatus eProtocolStatus);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif // __NFC_SNEP_H__
diff --git a/nfclib/ssitrf79x0.c b/nfclib/ssitrf79x0.c new file mode 100644 index 0000000..b14a393 --- /dev/null +++ b/nfclib/ssitrf79x0.c @@ -0,0 +1,826 @@ +//*****************************************************************************
+//
+// ssitrf79x0.c - SSI Driver for the TI TRF79x0 on the dk-lm3s9b96 board.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/pin_map.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/ssi.h"
+#include "driverlib/sysctl.h"
+#include "ssitrf79x0.h"
+#include "trf79x0.h"
+#include "trf79x0_hw.h"
+
+//*****************************************************************************
+//
+// Raw SPI through SSI access API for the TRF79x0. Most user code will not and
+// should not call these functions but instead use the provided higher level
+// functions in trf79x0.c, directmode.c and iso14443a.c.
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+// Global that holds the clock speed of the MicroController in Hz.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SysClk;
+
+//*****************************************************************************
+//
+// The rate of the SSI clock and derived values.
+//
+//*****************************************************************************
+#define SSI_CLKS_PER_MS (SSI_CLK_RATE / 1000)
+#define STATUS_READS_PER_MS (SSI_CLKS_PER_MS / 16)
+#define SSI_NO_DATA 0
+
+//*****************************************************************************
+//
+// Internal helper function that sends a buffer of data to the TRF79x0, used
+// by all the functions that need to send bytes.
+//
+//*****************************************************************************
+void
+SSITRF79x0GenericWrite(unsigned char const *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulDummyData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write address/command/data and clear SSI register of dummy data.
+ //
+ MAP_SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)*pucBuffer);
+ //
+ // Wait until the SSI Module is completed sending uiLength bytes to the SSI module.
+ //
+ while(SSIBusy(TRF79X0_SSI_BASE) == true);
+ MAP_SSIDataGet(TRF79X0_SSI_BASE, &ulDummyData);
+
+ //
+ // Post increment counters.
+ //
+ pucBuffer++;
+ uiLength--;
+ }
+
+
+}
+
+//*****************************************************************************
+//
+// Internal helper function used by all the functions that need to send bytes.
+//
+//*****************************************************************************
+void
+SSITRF79x0DummyWrite(unsigned char const *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulDummyData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write address/command/data and clear SSI register of dummy data.
+ //
+ SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)*pucBuffer);
+ SSIDataGet(TRF79X0_SSI_BASE, &ulDummyData);
+
+ //
+ // Post increment counters.
+ //
+ pucBuffer++;
+ uiLength--;
+ }
+}
+
+//*****************************************************************************
+//
+// Internal helper function that receives a buffer of data from the TRF79x0,
+// used by all the functions that need to read bytes.
+//
+//*****************************************************************************
+static void
+SSITRF79x0GenericRead(unsigned char *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write dummy data for SSI clock and read data from SSI register.
+ //
+ MAP_SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)SSI_NO_DATA);
+ //
+ // Wait until the SSI Module is completed sending uiLength bytes to the SSI module.
+ //
+ while(SSIBusy(TRF79X0_SSI_BASE) == true);
+ MAP_SSIDataGet(TRF79X0_SSI_BASE, &ulData);
+// SSIDataGet(TRF79X0_SSI_BASE, &ulData);
+
+ //
+ // Read data into buffers and post increment counters.
+ //
+ *pucBuffer++ = (unsigned char)ulData;
+
+ uiLength--;
+ }
+
+}
+
+//*****************************************************************************
+//
+// Asserts the chip select for the TRF79x0.
+//
+//*****************************************************************************
+void
+SSITRF79x0ChipSelectAssert(void)
+{
+ //
+ // Disable the interrupt associated with the TRF79x0.
+ //
+ TRF79x0InterruptDisable();
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, 0);
+}
+
+//*****************************************************************************
+//
+// Deasserts the chip select for the TRF79x0
+//
+//*****************************************************************************
+void
+SSITRF79x0ChipSelectDeAssert(void)
+{
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, TRF79X0_CS_PIN);
+
+ //
+ // Enable interrupt associated with the TRF79x0.
+ //
+ TRF79x0InterruptEnable();
+}
+
+//*****************************************************************************
+//
+// Initializes the SSI port and determines if the TRF79x0 is available.
+//
+// This function must be called prior to any other function offered by the
+// TRF79x0. It configures the SSI port to run in Motorola/Freescale
+// mode.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0Init(void)
+{
+ //
+ // Enable the peripherals used to drive the TRF79x0 on SSI.
+ //
+ MAP_SysCtlPeripheralEnable(TRF79X0_SSI_PERIPH);
+
+ //
+ // Enable the GPIO peripherals associated with the SSI.
+ //
+ MAP_SysCtlPeripheralEnable(TRF79X0_CLK_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_RX_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_TX_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_CS_PERIPH);
+
+ //
+ // Configure the appropriate pins to be SSI instead of GPIO. The CS
+ // is configured as GPIO to support TRF79x0 SPI requirements for R/W
+ // access.
+ //
+ MAP_GPIOPinConfigure(TRF79X0_CLK_CONFIG);
+ MAP_GPIOPinConfigure(TRF79X0_RX_CONFIG);
+ MAP_GPIOPinConfigure(TRF79X0_TX_CONFIG);
+ MAP_GPIOPinTypeSSI(TRF79X0_CLK_BASE, TRF79X0_CLK_PIN);
+ MAP_GPIOPinTypeSSI(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+ MAP_GPIOPinTypeSSI(TRF79X0_TX_BASE, TRF79X0_TX_PIN);
+ MAP_GPIOPinTypeGPIOOutput(TRF79X0_CS_BASE, TRF79X0_CS_PIN);
+
+ MAP_GPIOPadConfigSet(TRF79X0_CLK_BASE, TRF79X0_CLK_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+ MAP_GPIOPadConfigSet(TRF79X0_RX_BASE, TRF79X0_RX_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+ MAP_GPIOPadConfigSet(TRF79X0_TX_BASE, TRF79X0_TX_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+
+ //
+ // Deassert the SSI chip selects TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, TRF79X0_CS_PIN);
+
+ //
+ // Configure the SSI port for 2MHz operation.
+ //
+ MAP_SSIConfigSetExpClk(TRF79X0_SSI_BASE, g_ui32SysClk,
+ SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, SSI_CLK_RATE,
+ 8);
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ //
+ // Switch from SPH=0 to SPH=1. Required for TRF7970.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+
+ //
+ // Enable the SSI controller.
+ //
+ MAP_SSIEnable(TRF79X0_SSI_BASE);
+}
+
+//*****************************************************************************
+//
+// Writes a single value to TRF79x0 for address provided.
+//
+// \param ucAddress is the register address to write and must be between 0
+// and 0x1f, inclusive.
+// \param ucData is the data byte to write.
+//
+// This function asserts the TRF79x0 chip select, sends a write command,
+// the single data value and then deasserts the chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteRegister(unsigned char ucAddress, unsigned char ucData)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 write single command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_WRITE | TRF79X0_REG_MODE_SINGLE;
+
+ //
+ // Put the address and data into the buffer.
+ //
+ pucCommand[0] = ucAddress;
+ pucCommand[1] = ucData;
+
+ //
+ // Start the write.
+ //
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Starts a continuous write operation to the given address.
+//
+// \param ucAddress is the register address to start this write command and
+// must be between 0 and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select and sends a write continuous
+// command. The chip select stays asserted when the function returns and must
+// be released with SSITRF79x0WriteContinuousStop().
+//
+// Typical usage for a write to multiple registers at once is: one call to
+// SSITRF79x0WriteContinuousStart(), one or more calls to
+// SSITRF79x0WriteContinuousData() and one call to
+// SSITRF79x0WriteContinuousStop().
+//
+// \sa SSITRF79x0WriteContinuousData()
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousStart(unsigned char ucAddress)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 write continuous command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_WRITE | TRF79X0_REG_MODE_CONTINUOUS;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ //
+ // Keep chip select asserted for follow-up calls to
+ // SSITRF79x0WriteContinuousData(). Calling code must ensure to finish
+ // with SSITRF79x0WriteContinuousStop().
+ //
+}
+
+//*****************************************************************************
+//
+// Starts a direct continous write operation
+//
+// This function asserts the chip select for the TRF79x0.
+//
+// \return None
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectContinuousStart(void)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+}
+
+//*****************************************************************************
+//
+// Sends data in continuous write mode.
+//
+// \param pucBuffer is a pointer to the data buffer to write.
+// \param uiLength is the length of the data to write in bytes.
+//
+// This function sends data from the buffer to the TRF79x0. The write must
+// have been previously set up with SSITRF79x0WriteContinuousStart().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousData(unsigned char const *pucBuffer,
+ unsigned int uiLength)
+{
+ SSITRF79x0GenericWrite(pucBuffer, uiLength);
+}
+
+//*****************************************************************************
+//
+// Stops a continuous write operation.
+//
+// This function deasserts the TRF79x0 chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousStop(void)
+{
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Reads a single value from TRF79x0 at the address provided.
+//
+// \param ucAddress is the register address to read and must be between 0
+// and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select, sends a read command,
+// reads a single byte and then deasserts the chip select.
+//
+// \return This function returns the value that was stored in the given
+// register.
+//
+//*****************************************************************************
+unsigned char
+SSITRF79x0ReadRegister(unsigned char ucAddress)
+{
+ unsigned char ucData = 0;
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 read single command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_READ | TRF79X0_REG_MODE_SINGLE;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=0 to SPH=1.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+
+ //
+ // Get the data.
+ //
+ SSITRF79x0GenericRead(&ucData, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=1 to SPH=0.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) &= ~SSI_CR0_SPH;
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+
+ return(ucData);
+}
+
+//*****************************************************************************
+//
+// Starts a continuous read operation from the given address.
+//
+// \param ucAddress is the register address to start this read command and must
+// be between 0 and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select and sends a read continuous
+// command. The chip select stays asserted when the function returns and must
+// be released with SSITRF79x0ReadContinuousStop().
+//
+// Typical usage for a read from multiple registers at once is: one call to
+// SSITRF79x0ReadContinuousStart(), one or more calls to
+// SSITRF79x0ReadContinuousData() and one call to
+// SSITRF79x0ReadContinuousStop().
+//
+// \sa SSITRF79x0ReadContinuousData()
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousStart(unsigned char ucAddress)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 read continuous command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_READ | TRF79X0_REG_MODE_CONTINUOUS;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=0 to SPH=1.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+}
+
+//*****************************************************************************
+//
+// Receives data in continuous read mode.
+//
+// \param pucBuffer is a pointer to the data buffer to receive data.
+// \param uiLength is the length of the data to read in bytes.
+//
+// This function reads data from the the TRF79x0 into the buffer. The read
+// must have been previously set up with SSITRF79x0ReadContinuousStart().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousData(unsigned char *pucBuffer, unsigned int uiLength)
+{
+ SSITRF79x0GenericRead(pucBuffer, uiLength);
+}
+
+//*****************************************************************************
+//
+// Stop a continuous read operation.
+//
+// This function deasserts the TRF79x0 chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousStop(void)
+{
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=1 to SPH=0.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) &= ~SSI_CR0_SPH;
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Reads IRQ status value from TRF79x0.
+//
+// This function reads the TRF79x0 IRQ status register 0x0c and returns its
+// contents. This will make the TRF79x0 release its interrupt request.
+//
+// \note You should use this function instead of a direct read from register
+// 0x0c if you want to retrieve the IRQ status since this function applies
+// a special workaround as indicated in SLOA140.
+//
+// \return Returns the IRQ status
+//
+//*****************************************************************************
+unsigned char
+SSITRF79x0ReadIRQStatus(void)
+{
+ unsigned char pucData[2];
+
+ //
+ // Workaround as per SLOA140: When reading the IRQ status register, do a
+ // continuous read with an additional register to ensure at least one
+ // additional SPI clock after reading the IRQ status. Ignore the second
+ // read result.
+ //
+
+ SSITRF79x0ReadContinuousStart(TRF79X0_IRQ_STATUS_REG);
+ SSITRF79x0ReadContinuousData(pucData, sizeof(pucData));
+ SSITRF79x0ReadContinuousStop();
+
+ return(pucData[0]);
+}
+
+//*****************************************************************************
+//
+// Executes a direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \note This function applies a special workaround as indicated in SLOA140.
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectCommand(unsigned char ucCommand)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF79x0 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+ pucCommand[1] = SSI_NO_DATA;
+
+ if(ucCommand == TRF79X0_RESET_FIFO_CMD)
+ {
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+ }
+ else
+ {
+ SSITRF79x0GenericWrite(pucCommand, 1);
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Write Direct Command Tailored for 7970 chip. Ported for redundancy
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h. A dummy command is sent after the direct command to handle
+// issues with the last command somtimes not processing.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectCommandWithDummy(unsigned char ucCommand)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF7970.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF7970 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+ pucCommand[1] = SSI_NO_DATA;
+
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF7970.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Executes a Reset direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \note This function applies a special workaround as indicated in SLOA140.
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteResetFifoDirectCommand(unsigned char ucCommand)
+{
+ unsigned char pucCommand[1];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF79x0 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Executes: writes a packet to the TRF79x0
+//
+// \param pui8Buffer
+// \param ui8CRCBit
+// \param ui8TotalLength
+// \param ui8PayloadLength
+// \param bHeaderEnable
+//
+// \note
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void SSITRF79x0WritePacket(uint8_t *pui8Buffer, uint8_t ui8CRCBit, \
+ uint8_t ui8TotalLength, uint8_t ui8PayloadLength, bool bHeaderEnable)
+{
+ uint8_t ui8LengthLowerNibble = (ui8TotalLength & 0x0F) << 4;
+ uint8_t ui8LengthHigherNibble = (ui8TotalLength & 0xF0) >> 4;
+ uint8_t pui8HeaderData[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ if(bHeaderEnable == true)
+ {
+ // RESET FIFO
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x8F; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // CRC COMMAND
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x90 | (ui8CRCBit & 0x01); // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // WRITE TO LENGTH REG
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x3D;
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // LENGTH HIGH Nibble
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = ui8LengthHigherNibble; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // LENGTH LOW Nibble
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = ui8LengthLowerNibble; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+ }
+ else
+ {
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x3F;
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+ }
+
+
+ SSITRF79x0GenericWrite(pui8Buffer,ui8PayloadLength);
+ //while(ui8PayloadLength > 0)
+ //{
+ // while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ // UCB0TXBUF = *pui8Buffer; // Previous data to TX, RX
+ // while(UCB0STAT & UCBUSY);
+ // pui8Buffer++;
+ // ui8PayloadLength--;
+ //}
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
diff --git a/nfclib/ssitrf79x0.h b/nfclib/ssitrf79x0.h new file mode 100644 index 0000000..5b9f8f3 --- /dev/null +++ b/nfclib/ssitrf79x0.h @@ -0,0 +1,62 @@ +//*****************************************************************************
+//
+// ssitrf79x0.h - Header file for the TI TRF79x0 SSI driver for the
+// dk-lm3s9b96 boards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SSITRF79X0_H__
+#define __SSITRF79X0_H__
+
+//*****************************************************************************
+//
+// Exported function prototypes.
+//
+//*****************************************************************************
+extern void SSITRF79x0Init(void);
+extern void SSITRF79x0WriteRegister(unsigned char ucAddress,
+ unsigned char ucData);
+extern void SSITRF79x0WriteContinuousStart(unsigned char ucAddress);
+extern void SSITRF79x0WriteContinuousData(unsigned char const *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0WriteContinuousStop(void);
+extern unsigned char SSITRF79x0ReadRegister(unsigned char ucAddress);
+extern void SSITRF79x0ReadContinuousStart(unsigned char ucAddress);
+extern void SSITRF79x0ReadContinuousData(unsigned char *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0ReadContinuousStop(void);
+extern unsigned char SSITRF79x0ReadIRQStatus(void);
+extern void SSITRF79x0WriteDirectCommand(unsigned char ucCommand);
+extern void SSITRF79x0WriteDirectContinuousStart(void);
+extern void SSITRF79x0WriteResetFifoDirectCommand(unsigned char ucCommand);
+extern void SSITRF79x0DummyWrite(unsigned char const *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0WriteDirectCommandWithDummy(unsigned char ucCommand);
+extern void SSITRF79x0WritePacket(uint8_t *pui8Buffer, uint8_t ui8CRCBit,
+ uint8_t ui8TotalLength, uint8_t ui8PayloadLength,
+ bool eHeaderEnable);
+
+extern void SSITRF79x0ChipSelectAssert(void);
+extern void SSITRF79x0GenericWrite(unsigned char const *pucBuffer, unsigned int uiLength);
+extern void SSITRF79x0ChipSelectDeAssert(void);
+
+
+#endif // __SSITRF79X0_H__
diff --git a/nfclib/trf79x0.c b/nfclib/trf79x0.c new file mode 100644 index 0000000..f0405e4 --- /dev/null +++ b/nfclib/trf79x0.c @@ -0,0 +1,1961 @@ +//*****************************************************************************
+//
+// trf79x0.c - Driver for the TI TRF79x0 on the dk-lm3s9b96 board.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_ints.h"
+#include "driverlib/gpio.h"
+#include "driverlib/ssi.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/timer.h"
+#include "utils/uartstdio.h"
+#include "ssitrf79x0.h"
+#include "trf79x0_hw.h"
+#include "trf79x0.h"
+#include "nfc.h"
+#include "nfclib/debug.h"
+
+//extern unsigned char g_ucNfcWorkMode = NFC_NONE;
+
+//*****************************************************************************
+//
+// Global Defines
+//
+//*****************************************************************************
+#define NFC_FIFO_SIZE 255
+// Fifo size depends on the maximum payload size defined in LLCP.h
+uint8_t g_fifo_buffer[NFC_FIFO_SIZE];
+uint8_t g_fifo_bytes_received = 0;
+volatile uint8_t g_irq_flag = 0x00;
+volatile uint8_t g_time_out_flag = 0x00;
+
+tTRF79x0TRFMode g_selected_mode = BOARD_INIT;
+tTRF79x0Frequency g_selected_frequency = FREQ_STAND_BY;
+
+// Used for debugging
+#define OUTPUT_FIFO_ENABLE 0
+
+#define TRF7970A_5V_OPERATION 0x01
+
+//*****************************************************************************
+//
+// A global variable indicating which RF daughter board, if any, is currently
+// connected to the development board.
+//
+//*****************************************************************************
+tRFDaughterBoard g_eRFDaughterType = RF_DAUGHTER_NONE;
+
+//*****************************************************************************
+//
+// API for the TRF79x0. Provides register read/write access, command
+// execution, abstracted access to IRQ results and comprehensive transceiver
+// functionality for higher-layer frame transmission and reception.
+//
+// Most user code will only need TRF79x0Init() from this module to set up
+// and initialize the TRF79x0 and will then use the functions defined by
+// some higher layer protocol, such as from iso14443a.c.
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+// The number of counts to pass to SysCtlDelay() to get approximately 1ms
+// delay.
+//
+//*****************************************************************************
+static unsigned long g_ulDelayms;
+
+//*****************************************************************************
+//
+// Global that holds the clock speed of the MicroController in Hz.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SysClk;
+
+//*****************************************************************************
+//
+// This structure holds information about encountered IRQs. The collision
+// position can be queried by TRF79x0GetCollisionPosition().
+// TRF79x0IRQWait() and TRF79x0IRQWaitTimeout() can be used to wait for
+// an interrupt cause to be asserted. TRF79x0IRQClearAll() and
+// TRF79x0IRQClearCauses() can be used to clear indicated causes from this
+// structure, since TRF79x0IRQWait()/TRF79x0IRQWaitTimeout() do not do
+// that.
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // This stores the contents of the IRQ status register at the most recent
+ // IRQ. However, the contents of this field are not reliable since IRQs
+ // may occur shortly after one another and a loop that simply queries state
+ // might miss all but the last of these.
+ //
+ unsigned char ucState;
+
+ //
+ // Indicates whether a collision was detected since the last call to
+ // TRF79x0GetCollisionPosition().
+ //
+ unsigned char ucCollisionDetected;
+
+ //
+ // Stores the last collision position as returned in registers
+ // 0xd and 0xe.
+ //
+ unsigned int uiCollisionPosition;
+
+ //
+ // Bitfield tracking the occurrence of abstract interrupt causes. The
+ // values of enum TRF79x0WaitCondition are used as indices into the
+ // bitfield, e.g. for a TRF79X0_WAIT_TXEND interrupt the bit at
+ // <tt>(1<<TRF79X0_WAIT_TXEND)</tt> is set.
+ //
+ unsigned int uiIrqCauses;
+}
+g_sIRQState;
+
+//*****************************************************************************
+//
+// Definitions for different interrupt status bits.
+//
+//*****************************************************************************
+#define TX_FIFO_ALMOST_EMPTY 0xA0
+#define TX_COMPLETE 0x80
+#define RX_FIFO_ALMOST_FULL 0x60
+#define RX_COMPLETE 0x40
+#define COLLISION_DETECTED 0x02
+
+//*****************************************************************************
+//
+// Timeout to apply while waiting for reception, this is expressed in
+// milliseconds.
+//
+// For a more accurate timeout indication you can program the no-response
+// timer in the TRF79x0 and must enable the no-response interrupt.
+//
+//*****************************************************************************
+#define TRF79X0_RX_TIMEOUT 10
+
+//*****************************************************************************
+//
+// This structure holds information about the transmission state for use by
+// the FIFO refill algorithm in the IRQ handler. It is set up by
+// TRF79x0FIFOWrite().
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // Pointer to the next byte to be transmitted
+ //
+ unsigned char const *pucBuffer;
+
+ //
+ // Number of bytes left that need to be transmitted
+ //
+ unsigned int uiBytesRemaining;
+} g_sTXState;
+
+//*****************************************************************************
+//
+// This structure holds information about the reception state for use by the
+// FIFO read algorithm in the IRQ handler. It is set up by TRF79x0Receive().
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // Pointer to write the next received byte to.
+ //
+ unsigned char *pucBuffer;
+
+ //
+ // Pointer to the received length counter. This is the counter that is
+ // passed in to TRF79x0Receive(). The integer that this pointer points
+ // to contains the number of bytes that were received (and stored in
+ // pucBuffer).
+ //
+ unsigned int *puiLength;
+
+ //
+ // Length of the buffer that pucBuffer pointed to at the start of
+ // reception. No more bytes are received when *puiLength equals this
+ // value.
+ //
+ unsigned int uiMaxLength;
+} g_sRXState;
+
+//*****************************************************************************
+//
+// Initializes the TRF79x0 and its communication interface.
+//
+// This function must be called prior to any other function offered by the
+// TRF79x0. This function initializes the GPIO and pin settings, sets up the
+// communication interface by calling SSITRF79x0Init() and sets up the
+// interrupt handler by calling TRF79x0InterruptInit().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Init(void)
+{
+ //
+ // Set up GPIO resources for bit-banging output access to EN and MOD
+ // and input for IRQ.
+ //
+ SysCtlPeripheralEnable(TRF79X0_EN_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_IRQ_PERIPH);
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ SysCtlPeripheralEnable(TRF79X0_MOD_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_EN2_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_ASKOK_PERIPH);
+ }
+
+ //
+ // Set the IRQ pin as an input.
+ //
+ GPIOPinTypeGPIOInput(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set the EN, EN2, MOD, and ASKOK pins as outputs.
+ //
+ GPIOPinTypeGPIOOutput(TRF79X0_EN_BASE, TRF79X0_EN_PIN);
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ GPIOPinTypeGPIOOutput(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN);
+ GPIOPinTypeGPIOOutput(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN);
+ GPIOPinTypeGPIOOutput(TRF79X0_ASKOK_BASE, TRF79X0_ASKOK_PIN);
+ }
+
+ //
+ // Set the MOD and ASKOK pins to start with a low value.
+ //
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, 0);
+ GPIOPinWrite(TRF79X0_ASKOK_BASE, TRF79X0_ASKOK_PIN, 0);
+ }
+
+ //
+ // Set up the SSI communication interface.
+ //
+ SSITRF79x0Init();
+
+ //
+ // Calculate the number of units for a 1ms delay using SysCtlDelay().
+ //
+ // NOTE: the ifdef is necessary because of an API change
+ //
+#ifdef TARGET_IS_TM4C123_RA1
+ //
+ // Blizzard Silicon (and before)
+ //
+ g_ulDelayms=(SysCtlClockGet()/3000);
+#else
+ //
+ // Snowflake Silicon (and after)
+ //
+ g_ulDelayms = (g_ui32SysClk / 3000);
+#endif
+
+ //
+ // Force a toggle on the EN and EN2 pins.
+ //
+ GPIOPinWrite(TRF79X0_EN_BASE, TRF79X0_EN_PIN, 0);
+ GPIOPinWrite(TRF79X0_EN_BASE, TRF79X0_EN_PIN,
+ TRF79X0_EN_PIN);
+
+// //
+// // Delay 2ms between ENABLE.
+// //
+// SysCtlDelay(g_ulDelayms * 2);
+//
+// GPIOPinWrite(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN, 0);
+// GPIOPinWrite(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN,
+// TRF79X0_EN2_PIN);
+
+ //
+ // Delay 2ms before initializing the TRF79x0.
+ //
+ SysCtlDelay(g_ulDelayms * 2);
+
+ //
+ // Initialize the TRF7970 with a software initialization command, idle
+ // command, and set the modulator control register to
+ //
+ if(RF_DAUGHTER_TRF7970)
+ {
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+ }
+
+ //
+ // Get RF Daughter Board ID TRF7960/TRF7970 ATB
+ //
+ TRF79x0ReadRegister(TRF79X0_MODULATOR_CONTROL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Set up the interrupt handler and enable the RX timeout IRQ.
+ //
+ TRF79x0InterruptInit();
+ TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG,
+ TRF79x0ReadRegister(TRF79X0_IRQ_MASK_REG) | 1);
+
+ //
+ // Delay 4ms before leaving the initialization function.
+ //
+ SysCtlDelay(g_ulDelayms * 4);
+}
+
+//*****************************************************************************
+//
+// Set the Operating mode for the TRF79x0
+//
+// Set bits in ISO_CONTROL_REG based on mode given
+// Supported modes:
+// NFC_P2P_PASSIVE_TARGET_MODE
+// NFC_P2P_INITIATOR_MODE
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0SetMode(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency)
+{
+ g_selected_mode = eMode;
+ g_selected_frequency = eFrequency;
+
+ if(g_selected_mode == P2P_PASSIVE_TARGET_MODE)
+ {
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+ }
+ else if(g_selected_mode == P2P_INITATIOR_MODE)
+ {
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x32);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x33);
+ }
+ }
+
+}
+
+//*****************************************************************************
+//
+// Prepare the TRF79x0 interrupt handler.
+//
+// Sets up the GPIO for a level triggered interrupt on the TRF79x0 IRQ line
+// and calls TRF79x0InterruptEnable(). Processor interrupts need to be
+// enabled (IntMasterEnable() from DriverLib) for the interrupt handler to
+// to be actually called.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptInit(void)
+{
+ //
+ // Set GPIO Interrupt to level triggered active high.
+ //
+ GPIOIntTypeSet(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN, GPIO_RISING_EDGE);
+
+ //
+ // Clear out any pending interrupt.
+ //
+ GPIOIntClear(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set GPIO Interrupt Enable.
+ //
+ TRF79x0InterruptEnable();
+
+ //
+ // Enable the GPIO interrupt.
+ //
+ IntEnable(TRF79X0_IRQ_INT);
+}
+
+//*****************************************************************************
+//
+// IRQ pin Interrupt Handler. This function is triggered by the IRQ pin going
+// high. The g_irq_flag flag is set as a result.
+//
+//*****************************************************************************
+void TRF79x0IRQPinInterruptHandler(void)
+{
+ uint32_t ui32IRQGPIOBankIntStatus;
+
+ //
+ // Get the masked interrupt status.
+ //
+ ui32IRQGPIOBankIntStatus=GPIOIntStatus(TRF79X0_IRQ_BASE,true);
+
+
+ //
+ // check if IRQ pin is high
+ //
+ if(ui32IRQGPIOBankIntStatus & TRF79X0_IRQ_PIN)
+ {
+ //
+ // Clear the asserted interrupts.
+ //
+ GPIOIntClear(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set flag appropriately.
+ //
+ g_irq_flag = 0x01;
+ }
+
+}
+
+//*****************************************************************************
+//
+// Internal helper function to transmit up to uiMaxLength bytes from g_sTXState
+// to the FIFO.
+//
+//*****************************************************************************
+static void
+FIFOTransmitSomeBytes(unsigned int uiMaxLength)
+{
+ unsigned int uiLength;
+
+ if(g_sTXState.uiBytesRemaining > 0)
+ {
+ //
+ // There are some bytes in g_sTXState that still need to
+ // be sent.
+ //
+ uiLength = g_sTXState.uiBytesRemaining;
+
+ if(uiLength > uiMaxLength)
+ {
+ //
+ // Clamp number of bytes to be sent to parameter uiMaxLength,
+ // which is 12 for the initial call with an empty FIFO and
+ // 9 for subsequent calls from the IRQ.
+ //
+ uiLength = uiMaxLength;
+ }
+
+ //
+ // Send the data in a continuous write to the FIFO "register".
+ //
+ if(RF_DAUGHTER_TRF7960)
+ {
+ SSITRF79x0WriteContinuousStart(TRF79X0_FIFO_REG);
+ SSITRF79x0WriteContinuousData(g_sTXState.pucBuffer, uiLength);
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ SSITRF79x0WriteContinuousData(g_sTXState.pucBuffer, uiLength);
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ //
+ // Update g_sTXState to reflect what we just sent.
+ //
+ g_sTXState.pucBuffer += uiLength;
+ g_sTXState.uiBytesRemaining -= uiLength;
+ }
+}
+
+
+
+
+//*****************************************************************************
+//
+// Clears all IRQ causes from g_sIRQState.
+//
+// You will need to call either this function or TRF79x0IRQClearCauses()
+// before a call to TRF79x0IRQWait() or TRF79x0IRQWaitTimeout() in order to
+// clear sticky causes from the interrupt state. If a cause has been indicated
+// before and is not cleared from the state then the wait functions will
+// return immediately.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0IRQClearAll(void)
+{
+ //
+ // Clear the interrupt causes flags.
+ //
+ g_sIRQState.uiIrqCauses = 0;
+}
+
+//*****************************************************************************
+//
+// Clears all given IRQ causes from g_sIRQState.
+//
+// \param causes is a bitfield of clauses to clear. This is a logical or of
+// one or more terms of the form <tt>(1<<<i>x</i>)</tt> where <i>x</i>
+// is a value from enumeration TRF79x0WaitCondition.
+//
+// You will need to call either this function or TRF79x0IRQClearAll()
+// before a call to TRF79x0IRQWait() or TRF79x0IRQWaitTimeout().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0IRQClearCauses(unsigned int uiCauses)
+{
+ //
+ // Clear the requested interrupt causes.
+ //
+ g_sIRQState.uiIrqCauses &= ~uiCauses;
+}
+
+//*****************************************************************************
+//
+// Returns the last indicated collision position and clears the collision
+// position indicator.
+//
+// \return This function returns the collision position as returned by the
+// TRF79x0 in registers 0xd and 0xe, or -1 if no collision was indicated since
+// the last call to this function.
+//
+//*****************************************************************************
+int
+TRF79x0GetCollisionPosition(void)
+{
+ //
+ // If there were no collisions detected then just return.
+ //
+ if(!g_sIRQState.ucCollisionDetected)
+ {
+ return(-1);
+ }
+
+ //
+ // Clear the collisions detected flag and return the number of collisions
+ // detected.
+ //
+ g_sIRQState.ucCollisionDetected = 0;
+
+ return(g_sIRQState.uiCollisionPosition);
+}
+
+//*****************************************************************************
+//
+// Enables the TRF79x0 IRQ handler.
+//
+// The interrupt handler needs and the processor interrupt to be enabled
+// (IntMasterEnable() from DriverLib) in order for transmission and
+// reception to work.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptEnable(void)
+{
+ //
+ // Enable interrupts on the pin assigned to the IRQ signal.
+ //
+ GPIOIntEnable(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+}
+
+//*****************************************************************************
+//
+// Disables the TRF79x0 IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptDisable(void)
+{
+ //
+ // Disable interrupts on the pin assigned to the IRQ signal.
+ //
+ GPIOIntDisable(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+}
+
+//*****************************************************************************
+//
+// TRF79x0DisableTransmitter - Disable the TRF79x0 Transmitter and Reset Fifo
+//
+//*****************************************************************************
+void TRF79x0DisableTransmitter(void)
+{
+ //
+ // Register 00h. Chip Status Control
+ //
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,0x00 | TRF7970A_5V_OPERATION);
+
+ //
+ // Reset FIFO CMD + Dummy byte
+ //
+ TRF79x0ResetFifoCommand();
+}
+
+//*****************************************************************************
+//
+// stop, then start the decoders
+//
+//*****************************************************************************
+void TRF797x0ResetDecoders(void)
+{
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+uint8_t* TRF79x0GetNFCBuffer(void)
+{
+ return g_fifo_buffer;
+}
+
+//*****************************************************************************
+//
+// Waits for an abstract IRQ cause.
+//
+// \param eCondition is the IRQ cause to wait for.
+//
+// Waits until the IRQ handler indicates that the given abstract IRQ cause
+// has been met.
+//
+// \return Returns 1.
+//
+//*****************************************************************************
+int
+TRF79x0IRQWait(unsigned long ulCondition)
+{
+ //
+ // Wait with no timeout.
+ //
+ return(TRF79x0IRQWaitTimeout(ulCondition, 0));
+}
+
+//*****************************************************************************
+//
+// Waits for an abstract IRQ cause or timeout.
+//
+// \param ulCondition is the IRQ cause to wait for.
+// \param ulTimeout is the number of milliseconds to wait before a timeout
+// occurs.
+//
+// Waits until the IRQ handler indicates that the given abstract IRQ cause
+// has been met or the timeout occurs. If ulTimeout is 0 then this function
+// will wait forever.
+//
+// \return This function returns 1 if the condition was reached or 0 if the
+// function aborted due to the timeout being met.
+//
+//*****************************************************************************
+int
+TRF79x0IRQWaitTimeout(unsigned long ulCondition, unsigned long ulTimeout)
+{
+ unsigned long ulTime;
+
+ //
+ // If timeout was not set or not reached, return true.
+ //
+ if(ulTimeout == 0)
+ {
+ return(1);
+ }
+
+ ulTime = 0;
+
+ while((g_sIRQState.uiIrqCauses & ulCondition) == 0)
+ {
+ if(ulTimeout == ulTime)
+ {
+ //
+ // Abort if timeout is set and reached.
+ //
+ break;
+ }
+
+ //
+ // Delay 1ms and check again.
+ //
+ SysCtlDelay(g_ulDelayms);
+
+ //
+ // Increment the loop count.
+ //
+ ulTime++;
+ }
+
+ //
+ // If timeout was set and reached: return false.
+ //
+ if(ulTimeout == ulTime)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Issues a direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed. Must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0DirectCommand(unsigned char ucCommand)
+{
+ SSITRF79x0WriteDirectCommand(ucCommand);
+}
+
+//*****************************************************************************
+//
+// Issues a direct Reset FIFO command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed. Must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ResetFifoCommand(void)
+{
+ SSITRF79x0WriteResetFifoDirectCommand(TRF79X0_RESET_FIFO_CMD);
+}
+
+//*****************************************************************************
+//
+//! Writes a single value to the TRF79x0 for address provided.
+//!
+//! \param ucAddress is the register address to write to. Must be between 0
+//! and 0x1f, inclusive.
+//! \param ucData is the data byte to be written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TRF79x0WriteRegister(unsigned char ucAddress, unsigned char ucData)
+{
+ SSITRF79x0WriteRegister(ucAddress, ucData);
+}
+
+
+//*****************************************************************************
+//
+// Initialize the mode and frequecy for the TRF79x0.
+// Useful for hot switching modes
+//
+// \param eMode is the mode the TRF79x0 is operating in.
+// Implemented: Future Implementation:
+// BOARD_INIT P2P_ACTIVE_TARGET_MODE
+// P2P_INITATIOR_MODE CARD_EMULATION_TYPE_A
+// P2P_PASSIVE_TARGET_MODE CARD_EMULATION_TYPE_B
+//
+// \param eFrequency is the frequency to set the board to.
+// Valid values are:
+// FREQ_STAND_BY
+// FREQ_106_KBPS
+// FREQ_212_KBPS
+// FREQ_424_KBPS
+//
+//*****************************************************************************
+tStatus TRF79x0Init2(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency)
+{
+ uint8_t ui8RxVal;
+ uint8_t ui8RxValCont[2];
+
+ g_selected_mode = eMode;
+ g_selected_frequency = eFrequency;
+
+ if (eMode == BOARD_INIT) {
+
+ do {
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // Delay 1ms
+ // NOTE: Sysctl delay takes 3 clock ticks to complete,
+ // thus 1ms = (clock/1000)/3 or clock/3000
+ //
+ SysCtlDelay(g_ulDelayms * 1 );
+
+ //
+ // Register 09h. Modulator Control
+ //
+ ui8RxVal=TRF79x0ReadRegister(TRF79X0_MODULATOR_CONTROL_REG);
+
+ } while (ui8RxVal != 0x91);
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK (in this case 13.56 MHz) out optional, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x87);
+
+ //
+ // Reset FIFO CMD + Dummy byte
+ //
+ TRF79x0ResetFifoCommand();
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x00 | TRF7970A_5V_OPERATION);
+
+ //
+ // Register 0Dh. Interrupt Mask Register
+ //
+// TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG, 0x3F);//NO Response IRQEnable
+ TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG, 0x3E);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+ } else if (eMode == P2P_INITATIOR_MODE) {
+ // TODO - Understand why the SOFT Init at start up, does
+ // not allow to send packets to reader
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ // Register 00h. Chip Status Control
+ // RF output active, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x02 | TRF7970A_5V_OPERATION);
+
+ // Check if there an external RF Field
+ TRF79x0DirectCommand(TRF79X0_TEST_EXTERNAL_RF_CMD);
+
+ //
+ // Delay 50uS
+ //
+ SysCtlDelay((g_ulDelayms/1000) * 50);
+
+ ui8RxVal=TRF79x0ReadRegister(TRF79X0_RSSI_LEVEL_REG);
+
+ // If the External RF Field is 0x00, we continue else we return fail
+ if ((ui8RxVal & 0x3F) != 0x00) {
+ //UARTprintf("Initiator Mode field disabled. RSSI: 0x%x \n",
+ //ui8RxVal);
+
+ // Register 00h. Chip Status Control
+ // RF output de-activated, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x00 | TRF7970A_5V_OPERATION);
+ return STATUS_FAIL;
+ }
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK (in this case 13.56 MHz) out optional, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+
+ //
+ // Register 01h. Chip Status Control
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x1A);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x1B);
+ }
+
+ //
+ // Register 0Ah. RX Special Settings
+ //
+ // Turn off transmitter, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x2F);
+
+ //
+ // Register 16h. NFC Low Detection Level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ //
+ // Register 18h. NFC Target level
+ //
+// TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // Turn off transmitter, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x20 |TRF7970A_5V_OPERATION);
+
+ //
+ // Guard Time Delay (GT_F) - 20 mS - Incremented to 30 mS due to the GS3.
+ //
+ SysCtlDelay(g_ulDelayms * 30);
+
+ } else if (eMode == P2P_PASSIVE_TARGET_MODE || eMode == P2P_ACTIVE_TARGET_MODE) {
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // Disable Decoder Command
+ //
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK Disabled, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Ah. RX Special Settings
+ //
+// TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x30);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+
+ //
+ // Register 16h. NFC Low Detection Level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ //
+ // Register 18h. NFC Target level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // RF output active, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x20 | TRF7970A_5V_OPERATION);
+
+ //
+ // Read IRQ Register & Collision Register to clear data.
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, ui8RxValCont, 2);
+
+ //
+ // Enable Decoder Command
+ //
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+// Write Fifo - used for NFC
+//
+//*****************************************************************************
+tStatus TRF79x0WriteFIFO(uint8_t *pui8Buffer, tTRF79x0CRC eCRCBit,
+ uint8_t ui8Length)
+{
+ tStatus eStatus;
+ tTRF79x0IRQFlag irq_flag = IRQ_STATUS_IDLE;
+ uint8_t remaining_bytes = 0;
+ uint8_t ui8FifoStatusLength = 0;
+ uint8_t ui8PayloadLength = 0;
+ uint8_t pui8IRQBuffer[2];
+
+ if (ui8Length > 127) {
+ ui8PayloadLength = 127;
+ } else {
+ ui8PayloadLength = ui8Length;
+ }
+
+ remaining_bytes = ui8Length - ui8PayloadLength;
+
+ if(g_selected_mode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (g_selected_frequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (g_selected_frequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x32);
+ } else if (g_selected_frequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x33);
+ }
+ }
+
+ if (IRQ_IS_SET())
+ {
+ //
+ // Read IRQ Register
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, pui8IRQBuffer, 2);
+ }
+
+ SSITRF79x0WritePacket(pui8Buffer, eCRCBit, ui8Length, ui8PayloadLength, \
+ true);
+
+ while (irq_flag != IRQ_STATUS_TX_COMPLETE) {
+ // Workaround for Type A commands - check the IRQ within 10 mS to
+ // refill FIFO
+ if(g_selected_mode == CARD_EMULATION_TYPE_A)
+ irq_flag = TRF79x0IRQHandler(10);
+ else
+ {
+ // No workaround needed, implement a longer timeout, allowing for
+ // FIFO IRQ to handle the FIFO levels
+ irq_flag = TRF79x0IRQHandler(100);
+ }
+
+ if (irq_flag == IRQ_STATUS_PROTOCOL_ERROR) {
+ eStatus = STATUS_FAIL;
+ break;
+ } else if (irq_flag == IRQ_STATUS_TX_COMPLETE) {
+ if(g_selected_mode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //
+ // Delay 1uS
+ //
+ SysCtlDelay((g_ulDelayms/1000) * 1);
+
+ //
+ // Register 01h. ISO Control Register
+ //
+ if(g_selected_frequency == FREQ_106_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ else if(g_selected_frequency == FREQ_212_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ else if(g_selected_frequency == FREQ_424_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+ eStatus = STATUS_SUCCESS;
+ } else if ((irq_flag == IRQ_STATUS_FIFO_HIGH_OR_LOW
+ || irq_flag == IRQ_STATUS_TIME_OUT) && remaining_bytes > 0) {
+ // Modify the pointer to point to the next address of data for
+ // payload larger than 127 bytes
+ pui8Buffer = pui8Buffer + ui8PayloadLength;
+
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ // Check if there are more remaining bytes than available spots on
+ // the TRF7970
+ if (remaining_bytes > (127 - ui8FifoStatusLength)) {
+ // If there are more bytes than available then payload length
+ //is the (127 - ui8FifoStatusLength)
+ ui8PayloadLength = (127 - ui8FifoStatusLength);
+ } else {
+ ui8PayloadLength = remaining_bytes;
+ }
+
+ remaining_bytes = remaining_bytes - ui8PayloadLength;
+
+ SSITRF79x0WritePacket(pui8Buffer, eCRCBit, ui8Length, \
+ ui8PayloadLength, false);
+ }
+ }
+
+ return eStatus;
+}
+
+//*****************************************************************************
+//
+// IRQ Handler
+//
+// NOTE: currently TimerSet, TimerDisable, and TimerInteruptHandler must be
+// implemented by the user.
+//
+//*****************************************************************************
+extern void TimerSet(uint16_t timeout_ms, uint8_t * timeout_flag);
+
+tTRF79x0IRQFlag
+TRF79x0IRQHandler(uint16_t ui16TimeOut)
+{
+ tTRF79x0IRQFlag eIRQStatus = IRQ_STATUS_IDLE;
+ uint8_t pui8IRQBuffer[2];
+ uint8_t pui8TargetProtocol[2];
+ uint8_t ui8FifoStatusLength;
+ uint8_t ui8FifoIndex = 0;
+ uint8_t ui8PacketLength = 0;
+
+ //volatile uint8_t x;
+
+ if (IRQ_IS_SET())
+ {
+ g_irq_flag = 0x01;
+ }
+ else
+ {
+ g_irq_flag = 0x00;
+ //
+ // Initialize a ui16TimeOut timeout
+ //
+ TimerSet(ui16TimeOut, (uint8_t*) &g_time_out_flag);
+
+ }
+
+ //
+ // Check if the IRQ flag has been set
+ //
+ while (g_irq_flag == 0x00 && g_time_out_flag == 0x00) {
+ ;
+ //
+ // Enable Low Power Mode 0
+ //
+ //__bis_SR_register(LPM0_bits);
+ }
+
+ //
+ // Disable Timer
+ //
+ TimerDisable(TIMER0_BASE, TIMER_A);
+
+ if (g_time_out_flag == 0x01) {
+ //MCU_rssiDisplay(0);
+ eIRQStatus = IRQ_STATUS_TIME_OUT;
+ } else {
+
+ TRF79x0ReadRegisterContinuous(TRF79X0_NFC_TARGET_PROTOCOL_REG, \
+ pui8TargetProtocol, 2);
+
+ //
+ // Read IRQ Register
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, pui8IRQBuffer, 2);
+
+ if (pui8IRQBuffer[0] & IRQ_STATUS_FIFO_HIGH_OR_LOW) {
+ if (pui8IRQBuffer[0] & IRQ_STATUS_RX_COMPLETE) {
+ g_fifo_bytes_received = 0;
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ ui8FifoIndex = 0;
+
+ while ((ui8FifoStatusLength > 0) &&
+ (g_fifo_bytes_received < NFC_FIFO_SIZE))
+ {
+
+ //
+ // Update the received bytes
+ //
+ g_fifo_bytes_received += ui8FifoStatusLength;
+ #ifdef DEBUG
+ //DebugPrintf("%d\n",g_fifo_bytes_received);
+ #endif
+
+ //
+ // Read the FIFO Data
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_FIFO_REG,
+ &g_fifo_buffer[ui8FifoIndex], ui8FifoStatusLength);
+
+ ui8PacketLength = g_fifo_buffer[0];
+
+ //
+ // Update ui8FifoIndex
+ //
+ ui8FifoIndex = ui8FifoIndex + ui8FifoStatusLength;
+
+ if (!IRQ_IS_SET())
+ {
+ g_irq_flag = 0;
+ }
+
+ //
+ // Type F - P2P Workaround
+ //
+ if((g_selected_mode == P2P_PASSIVE_TARGET_MODE) ||
+ (g_selected_mode == P2P_INITATIOR_MODE))
+ {
+ //
+ // Check if we have received all the bytes defined in
+ // the first packet.
+ //
+ if(g_fifo_buffer[0] == g_fifo_bytes_received)
+ {
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ break;
+ }
+ //
+ // If we have not read all the bytes, then every 1 mS
+ // go read out the FIFO status register to ensure we do
+ // not get an overflow flag.
+ //
+ else
+ {
+ //
+ // Initialize a 1 mS timeout
+ //
+ ui16TimeOut = 0x01;
+ TimerSet(ui16TimeOut, (uint8_t*) &g_time_out_flag);
+
+ while(g_irq_flag == 0x00 && g_time_out_flag == 0x00)
+ {
+ //
+ // Enable Low Power Mode 0
+ //
+ // __bis_SR_register(LPM0_bits);
+ }
+
+ //
+ // Disable Timer
+ //
+ TimerDisable(TIMER0_BASE, TIMER_A);
+ }
+
+ }
+ else
+ {
+ while ((g_irq_flag == 0) && (
+ (uint8_t) g_fifo_bytes_received !=
+ ui8PacketLength))
+ {
+ //
+ // Enable Low Power Mode 0
+ //
+ //__bis_SR_register(LPM0_bits);
+ }
+ }
+
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG,
+ pui8IRQBuffer, 2);
+
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength =
+ TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+ //
+ // Mask off the lower 7 bits.
+ //
+ ui8FifoStatusLength &= 0x7F;
+ }
+
+ //TRF79x0ResetFifoCommand();
+
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+ eIRQStatus = IRQ_STATUS_FIFO_HIGH_OR_LOW;
+ }
+ }
+ else if (pui8IRQBuffer[0] == IRQ_STATUS_RX_COMPLETE)
+ {
+
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ if (ui8FifoStatusLength != 0) {
+ //
+ // Read the FIFO Data
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_FIFO_REG, g_fifo_buffer,
+ ui8FifoStatusLength);
+
+ g_fifo_bytes_received = ui8FifoStatusLength;
+ } else {
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ return IRQ_STATUS_IDLE;
+ }
+
+ // Check if the selected_mode corresponds to the command read in
+ // the command
+ if ((pui8TargetProtocol[0] == 0xC9
+ && g_selected_mode == CARD_EMULATION_TYPE_A)
+ || (pui8TargetProtocol[0] == 0xC5
+ && g_selected_mode == CARD_EMULATION_TYPE_B)
+ || (pui8TargetProtocol[0] == 0xD2
+ && g_selected_mode == P2P_PASSIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_212_KBPS)
+ || (pui8TargetProtocol[0] == 0xD3
+ && g_selected_mode == P2P_PASSIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_424_KBPS)
+ || (pui8TargetProtocol[0] == 0xD2
+ && g_selected_mode == P2P_ACTIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_212_KBPS)
+ || (pui8TargetProtocol[0] == 0xD3
+ && g_selected_mode == P2P_ACTIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_424_KBPS)
+ || (g_selected_mode == P2P_INITATIOR_MODE))
+ {
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ if(g_selected_mode == P2P_INITATIOR_MODE ||
+ g_selected_mode == P2P_PASSIVE_TARGET_MODE)
+ //
+ // 500 microsecond // TR0
+ //
+ SysCtlDelay(g_ulDelayms / 2);
+ }
+ else
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+
+ } else if (pui8IRQBuffer[0] & IRQ_STATUS_COLLISION_AVOID_FINISHED) {
+ eIRQStatus = IRQ_STATUS_COLLISION_AVOID_FINISHED;
+ } else if (pui8IRQBuffer[0] & IRQ_STATUS_RX_COMPLETE) {
+ // Handle the case for P2P Initiator Mode where IRQ is triggered
+ // with value 0xC0 - TODO
+ if(pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+
+ }
+ else if(pui8IRQBuffer[0] & IRQ_STATUS_PROTOCOL_ERROR)
+ {
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ }
+ else
+ {
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength =
+ TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ TRF79x0ResetFifoCommand();
+ }
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_PROTOCOL_ERROR
+ || pui8IRQBuffer[0] & IRQ_STATUS_COLLISION_ERROR)
+ {
+ eIRQStatus = IRQ_STATUS_PROTOCOL_ERROR;
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+
+ // Reset FIFO CMD + Dummy byte
+ TRF79x0ResetFifoCommand();
+
+ eIRQStatus = IRQ_STATUS_TX_COMPLETE;
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_RF_FIELD_CHANGE)
+ {
+
+ eIRQStatus = IRQ_STATUS_RF_FIELD_CHANGE;
+ }
+
+ }
+
+ //
+ // Reset Global Flags
+ //
+ g_irq_flag = 0x00;
+ g_time_out_flag = 0x00;
+
+ return eIRQStatus;
+}
+
+//*****************************************************************************
+//
+// Writes a sequence of values to the TRF79x0 starting at the address
+// provided.
+//
+// \param ucAddress is the register address to start the write at. Must be
+// between 0 and 0x1f, inclusive.
+// \param pucData is a pointer to the data buffer to be written.
+// \param uiLength is the length of the buffer and number of bytes to write.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0WriteRegisterContinuous(unsigned char ucAddress, unsigned char *pucData,
+ unsigned int uiLength)
+{
+ SSITRF79x0WriteContinuousStart(ucAddress);
+ SSITRF79x0WriteContinuousData(pucData, uiLength);
+ SSITRF79x0WriteContinuousStop();
+}
+
+//*****************************************************************************
+//
+// Reads IRQ status value from TRF79x0.
+//
+// This function reads the TRF79x0 IRQ status register 0x0c and returns its
+// contents. This will make the TRF79x0 release its interrupt request.
+//
+// \return Returns the IRQ status
+//
+//*****************************************************************************
+unsigned char
+TRF79x0ReadIRQStatus(void)
+{
+ return(SSITRF79x0ReadIRQStatus());
+}
+
+//*****************************************************************************
+//
+// Reads a single value from TRF79x0 at the address provided.
+//
+// \param ucAddress is the register address to read from. Must be between 0
+// and 0x1f, inclusive.
+//
+// \return Returns the value that was stored in the given register.
+//
+//*****************************************************************************
+unsigned char
+TRF79x0ReadRegister(unsigned char ucAddress)
+{
+ return(SSITRF79x0ReadRegister(ucAddress));
+}
+
+//*****************************************************************************
+//
+// Reads a sequence of values from the TRF79x0 starting at the address
+// provided.
+//
+// \param ucAddress is the register address to start the read at. Must be
+// between 0 and 0x1f, inclusive.
+// \param pucData is a pointer to the data buffer to store the read bytes into.
+// \param uiLength is the length of the buffer and number of bytes to read.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ReadRegisterContinuous(unsigned char ucAddress, unsigned char *pucData,
+ unsigned int uiLength)
+{
+ SSITRF79x0ReadContinuousStart(ucAddress);
+ SSITRF79x0ReadContinuousData(pucData, uiLength);
+ SSITRF79x0ReadContinuousStop();
+}
+
+//*****************************************************************************
+//
+// Writes a sequence of values to the FIFO of the TRF79x0.
+//
+// \param pucData is a pointer to the data buffer to be written.
+// \param length is the length of the buffer and number of bytes to write.
+//
+// This function sets up g_sTXState for the write operation to the FIFO and
+// sends the first chunk of up to 12 bytes. If more bytes need to be written
+// this will be handled by the IRQ handler, which therefore must be enabled.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0FIFOWrite(unsigned char const *pucData, unsigned int uiLength)
+{
+ //
+ // Set up TX state to send the buffer.
+ //
+ g_sTXState.pucBuffer = pucData;
+ g_sTXState.uiBytesRemaining = uiLength;
+
+ //
+ // This will start transmission and write the first couple byte (12 at
+ // most) to the FIFO. If more bytes are to be written then the IRQ handler
+ // will pick up and send the remainder.
+ //
+ FIFOTransmitSomeBytes(12);
+ return;
+}
+
+//*****************************************************************************
+//
+// Writes to the FIFO, starting a transmission by the RF front end.
+//
+// \param pucData is a pointer to the data buffer to be written.
+// \param uiLength is the number of bytes to send.
+// \param uiBits is the additional number of bits to send.
+//
+// This function sets up the TX length byte registers 0x1D and 0x1E with
+// the given bytes and bits and then calls TRF79x0FIFOWrite() to initiate the
+// write to the FIFO.
+// If the RF front end has been enabled for transmission with
+// TRF79x0DirectCommand() with parameter \b TRF79X0_TRANSMIT_NO_CRC_CMD or
+// \b TRF79X0_TRANSMIT_CRC_CMD this function call will start the radio
+// transmission.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Transmit(unsigned char const *pucData, unsigned int uiLength,
+ unsigned int uiBits)
+{
+ unsigned char pucLengthRegs[2];
+
+ //
+ // Prepare the length to be written into the FIFO for registers 0x1D and
+ // 0x1E.
+ //
+ pucLengthRegs[0] = (uiLength >> 4) & 0xff;
+ pucLengthRegs[1] = (uiLength & 0xf) << 4;
+
+ if(uiBits > 0)
+ {
+ //
+ // Last byte is incomplete.
+ //
+ pucLengthRegs[1] |= ((uiBits & 0x7) << 1) | 1;
+
+ //
+ // This is an additional byte, so increase the number of bytes for the
+ // purpose of SPI transmission below by 1.
+ //
+ uiLength++;
+ }
+
+ //
+ // The data from pucLengthRegs is written to registers 0x1D and 0x1E
+ // in continuous mode. In principle the continuous mode could simply
+ // be kept active in order to write to the FIFO (starts at 0x1F). However
+ // there is a necessary workaround when only one byte needs to be
+ // transmitted (see SLOA140). Also stopping the continuous write here and
+ // separately enabling it in TRF79x0WriteFIFO makes for more logical
+ // function separation.
+ //
+ if(RF_DAUGHTER_TRF7960)
+ {
+ SSITRF79x0WriteContinuousStart(TRF79X0_TX_LENGTH_BYTE1_REG);
+ SSITRF79x0WriteContinuousData(pucLengthRegs, sizeof(pucLengthRegs));
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ SSITRF79x0WriteContinuousData(pucLengthRegs, sizeof(pucLengthRegs));
+ }
+
+ TRF79x0FIFOWrite(pucData, uiLength);
+}
+
+//*****************************************************************************
+//
+// Sets up reception from the FIFO
+//
+// \param pucData is a pointer to the data buffer to receive the data.
+// \param puiLength is a pointer to the length of the \e pucData buffer in
+// bytes.
+//
+// This function sets up g_sRXState for the read operation from the FIFO. The
+// actual reading will be handled by the IRQ handler, which therefore must
+// be enabled. When the function returns the \e puiLength parameter will
+// contain the number of bytes that were actually received. These values are
+// updated asynchronously by the IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Receive(unsigned char *pucData, unsigned int *puiLength)
+{
+ unsigned int uiMaxLength;
+
+ uiMaxLength = *puiLength;
+
+ //
+ // Already received: 0 bytes.
+ //
+ *puiLength = 0;
+
+ //
+ // The uiMaxLength member is the ultimate deciding factor on whether the
+ // IRQ receiver is enabled. So set it to 0 first and only set it to its
+ // final value when the other members are set.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ g_sRXState.pucBuffer = pucData;
+ g_sRXState.puiLength = puiLength;
+ g_sRXState.uiMaxLength = uiMaxLength;
+}
+
+//*****************************************************************************
+//
+// Sets up reception from the FIFO with wait time out feature
+//
+// \param pucData is a pointer to the data buffer to receive the data.
+// \param puiLength is a pointer to the length of the \e pucData buffer in
+// bytes.
+//
+// This function sets up g_sRXState for the read operation from the FIFO. The
+// actual reading will be handled by the IRQ handler, which therefore must
+// be enabled. When the function returns the \e puiLength parameter will
+// contain the number of bytes that were actually received. These values are
+// updated asynchronously by the IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ReceiveAgain(unsigned char *pucRXBuf, unsigned int *puiRXLen)
+{
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+void
+TRF79x0ReceiveEnd(void)
+{
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ TRF79x0ResetFifoCommand();
+}
+
+//*****************************************************************************
+//
+// Coordinated transmission and reception function.
+//
+// \param pucTXBuf is a pointer to the data buffer.
+// \param uiTXLen is the number of full bytes to send.
+// \param uiTXBits is the number of additional bits to send
+// \param pucRXBuf is a pointer to a data buffer to receive data. If this is
+// \b 0 then no reception will take place.
+// \param puiRXLen is pointer that inputs the length of \e pucRXBuf and outputs
+// the number of bytes that were actually received.
+// \param puiRXBits is unused.
+// \param uiFlags is a bitfield of uiFlags to modify the transceiver operation.
+// Should contain at least \b TRF79X0_TRANSCEIVE_NO_CRC,
+// \b TRF79X0_TRANSCEIVE_RX_CRC, \b TRF79X0_TRANSCEIVE_TX_CRC or
+// \b TRF79X0_TRANSCEIVE_CRC. These values indicate whether a CRC should be
+// added when transmitting (\b TRF79X0_TRANSCEIVE_TX_CRC or
+// \b TRF79X0_TRANSCEIVE_CRC) and whether it should be checked when receiving
+// (\b TRF79X0_TRANSCEIVE_RX_CRC or \b TRF79X0_TRANSCEIVE_CRC).
+//
+// This function calls, in order:
+//
+// - TRF79x0WriteRegister() to set up reception with/without CRC (in
+// register 0x1),
+// - TRF79x0DirectCommand() with \b TRF79X0_RESET_FIFO_CMD to clear the FIFO,
+// - TRF79x0DirectCommand() with \b TRF79X0_TRANSMIT_CRC_CMD or
+// \b TRF79X0_TRANSMIT_NO_CRC_CMD to prepare transmission with/without CRC,
+// - TRF79x0IRQClearAll() to clear the IRQ state,
+// - TRF79x0GetCollisionPosition() to clear the stored collision position,
+// - TRF79x0Receive() to set up reception (if enabled),
+// - TRF79x0Transmit() to set up transmission,
+// - TRF79x0IRQWaitTimeout() with \b TRF79X0_WAIT_TXEND to wait for the
+// end of transmission and
+// - TRF79x0IRQWaitTimeout() with \b TRF79X0_WAIT_RXEND to wait for the
+// end of reception (if enabled).
+//
+// The uiFlags and puiRXBits parameters offer for future, source-compatible
+// extensions such as integrated collision handling (which would result in
+// incomplete byte reception).
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Transceive(unsigned char const *pucTXBuf, unsigned int uiTXLen,
+ unsigned int uiTXBits, unsigned char *pucRXBuf,
+ unsigned int *puiRXLen, unsigned int *puiRXBits,
+ unsigned int uiFlags)
+{
+ int iRXEnabled;
+ unsigned char ucISOState;
+ unsigned char ucBuf[30];
+
+ ucISOState = TRF79x0ReadRegister(TRF79X0_ISO_CONTROL_REG);
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_RX_CRC)
+ {
+ //
+ // Receive with CRC.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ ucISOState & ~TRF79X0_ISO_CONTROL_RX_CRC_N);
+ }
+ else
+ {
+ //
+ // Receive without CRC.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ ucISOState | TRF79X0_ISO_CONTROL_RX_CRC_N);
+ }
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ TRF79x0DirectCommand(TRF79X0_RESET_FIFO_CMD);
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_TX_CRC)
+ {
+ //
+ // Transmit with CRC.
+ //
+ TRF79x0DirectCommand(TRF79X0_TRANSMIT_CRC_CMD);
+ }
+ else
+ {
+ //
+ // Transmit without CRC.
+ //
+ TRF79x0DirectCommand(TRF79X0_TRANSMIT_NO_CRC_CMD);
+ }
+
+ //
+ // Disable any possible old receive job.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ //
+ // Clear all IRQ causes.
+ //
+ TRF79x0IRQClearAll();
+
+ //
+ // Clear stored collision position.
+ //
+ TRF79x0GetCollisionPosition();
+
+ //
+ // If receive is enabled, set up receive job.
+ //
+ iRXEnabled = 0;
+
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ {
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+ iRXEnabled = 1;
+ }
+
+ //
+ // Writing the FIFO starts the transmission. This function will return
+ // after writing up to 12 bytes with the remaining bytes to be written
+ // by the interrupt handler.
+ //
+ TRF79x0Transmit(pucTXBuf, uiTXLen, uiTXBits);
+
+ //
+ // Wait for the interrupt handler to signal the end of transmission
+ // with no further FIFO loading. This IRQ should always happen, so
+ // no timeout necessary. However, for robustness reasons: Use the RX
+ // timeout.
+ //
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_TXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // If receive is enabled, wait for receive end.
+ //
+ if(iRXEnabled)
+ {
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+ }
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ //
+ // Prepare SELECT command
+ //
+ ucBuf[0] = TRF79X0_CONTROL_CMD | TRF79X0_RESET_FIFO_CMD;
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_TX_CRC)
+ {
+ //
+ // Transmit with CRC.
+ //
+ ucBuf[1] = TRF79X0_CONTROL_CMD | TRF79X0_TRANSMIT_CRC_CMD;
+ }
+ else
+ {
+ //
+ // Transmit without CRC.
+ //
+ ucBuf[1] = TRF79X0_CONTROL_CMD | TRF79X0_TRANSMIT_NO_CRC_CMD;
+ }
+
+ //
+ // Disable any possible old receive job.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ //
+ // Clear all IRQ causes.
+ //
+ TRF79x0IRQClearAll();
+
+ //
+ // Clear stored collision position.
+ //
+ TRF79x0GetCollisionPosition();
+
+ //
+ // If receive is enabled, set up receive job.
+ //
+ iRXEnabled = 0;
+
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ {
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+ iRXEnabled = 1;
+ }
+
+ //
+ // Writing the FIFO starts the transmission. This function will return
+ // after writing up to 12 bytes with the remaining bytes to be written
+ // by the interrupt handler.
+ //
+
+ //
+ // Look into what is ucBuf being used for.
+ //
+ ucBuf[2] = 0x3D;
+
+ //
+ // Send the data in a continuous write to the FIFO "register".
+ //
+ SSITRF79x0WriteDirectContinuousStart();
+ SSITRF79x0WriteContinuousData(ucBuf, 3);
+ TRF79x0Transmit(pucTXBuf, uiTXLen, uiTXBits);
+
+ //
+ // Wait for the interrupt handler to signal the end of transmission
+ // with no further FIFO loading. This IRQ should always happen, so
+ // no timeout necessary. However, for robustness reasons: Use the RX
+ // timeout.
+ //
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_TXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // If receive is enabled, wait for receive end.
+ //
+ if(iRXEnabled)
+ {
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+ }
+ }
+}
diff --git a/nfclib/trf79x0.h b/nfclib/trf79x0.h new file mode 100644 index 0000000..159bec7 --- /dev/null +++ b/nfclib/trf79x0.h @@ -0,0 +1,400 @@ +//*****************************************************************************
+//
+// trf79x0.h - Header file for the TI TRF79X0 driver
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __TRF79X0_H__
+#define __TRF79X0_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+// Definitions for different interrupt status bits.
+//
+//*****************************************************************************
+#define TX_FIFO_ALMOST_EMPTY 0xA0
+#define TX_COMPLETE 0x80
+#define RX_FIFO_ALMOST_FULL 0x60
+#define RX_COMPLETE 0x40
+#define COLLISION_DETECTED 0x02
+
+//*****************************************************************************
+//
+// Timeout to apply while waiting for reception, this is expressed in
+// milliseconds.
+//
+// For a more accurate timeout indication you can program the no-response
+// timer in the TRF7960 and must enable the no-response interrupt.
+//
+//*****************************************************************************
+#define TRF7960_RX_TIMEOUT 10
+
+//*****************************************************************************
+//
+// An enum defining the various daughter boards that can be attached to the
+// development board.
+//
+//*****************************************************************************
+typedef enum
+{
+ RF_DAUGHTER_NONE = 0,
+ RF_DAUGHTER_TRF7960ATB = 1,
+ RF_DAUGHTER_TRF7970ATB = 2,
+ RF_DAUGHTER_TRF7970ABP = 3,
+ RF_DAUGHTER_UNKNOWN = 0xFFFF
+}
+tRFDaughterBoard;
+
+extern tRFDaughterBoard g_eRFDaughterType;
+#define NFC_NONE 0
+#define NFC_CARD_EMU_TAG4A 1
+#define NFC_CARD_EMU_TAG4B 2
+
+extern unsigned char g_ucNfcWorkMode;
+
+//*****************************************************************************
+//
+// IRQ Status Register (0x0C) for NFC and Card Emulation Operation
+//
+//*****************************************************************************
+#define RF_FIELD_CHANGE 0x04
+#define SDD_COMPLETED 0x08
+
+//*****************************************************************************
+//
+// TRF79X0 Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_CHIP_STATUS_CTRL_REG 0x00
+#define TRF79X0_ISO_CONTROL_REG 0x01
+#define TRF79X0_ISO14443B_OPTIONS_REG 0x02
+#define TRF79X0_ISO14443A_OPTIONS_REG 0x03
+#define TRF79X0_TX_TIMER_EPC_HIGH 0x04
+#define TRF79X0_TX_TIMER_EPC_LOW 0x05
+#define TRF79X0_TX_PULSE_LENGTH_CTRL_REG 0x06
+#define TRF79X0_RX_NO_RESPONSE_WAIT_REG 0x07
+#define TRF79X0_RX_WAIT_TIME_REG 0x08
+#define TRF79X0_MODULATOR_CONTROL_REG 0x09
+#define TRF79X0_RX_SPECIAL_SETTINGS_REG 0x0A
+#define TRF79X0_REGULATOR_CONTROL_REG 0x0B
+#define TRF79X0_IRQ_STATUS_REG 0x0C
+#define TRF79X0_IRQ_MASK_REG 0x0D
+#define TRF79X0_COLLISION_POSITION_REG 0x0E
+#define TRF79X0_RSSI_LEVEL_REG 0x0F
+#define TRF79X0_RAM_START_ADDRESS_REG 0x10
+#define TRF797X0_SPECIAL_FUNC_1_REG 0x10
+#define TRF797X0_SPECIAL_FUNC_2_REG 0x11
+#define TRF79X0_FIFO_IRQ_LEVEL_REG 0x14
+#define TRF79X0_NFC_LO_FIELD_LEVEL_REG 0x16
+#define TRF79X0_NFC_ID_REG 0x17
+#define TRF79X0_NFC_TARGET_LEVEL_REG 0x18
+#define TRF79X0_NFC_TARGET_PROTOCOL_REG 0x19
+#define TRF79X0_TEST_SETTING1_REG 0x1A
+#define TRF79X0_TEST_SETTING2_REG 0x1B
+#define TRF79X0_FIFO_STATUS_REG 0x1C
+#define TRF79X0_TX_LENGTH_BYTE1_REG 0x1D
+#define TRF79X0_TX_LENGTH_BYTE2_REG 0x1E
+#define TRF79X0_FIFO_REG 0x1F
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_CHIP_STATUS_CTRL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_STATUS_CTRL_DIRECT 0x40
+#define TRF79X0_STATUS_CTRL_RF_ON 0x20
+#define TRF79X0_STATUS_CTRL_RF_PWR_HALF 0x10
+#define TRF79X0_STATUS_CTRL_RF_PWR_FULL 0x00
+#define TRF79X0_STATUS_CTRL_5V_OPERATION 0x01
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_ISO_CONTROL Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_ISO_CONTROL_RX_CRC_N 0x80
+#define TRF79X0_ISO_CONTROL_DIR_MODE 0x40
+#define TRF79X0_ISO_NFC_TARGET 0x00
+#define TRF79X0_ISO_NFC_INITIATOR 0x10
+#define TRF79X0_NFC_PASSIVE_MODE 0x00
+#define TRF79X0_NFC_ACTIVE_MODE 0x08
+#define TRF79X0_NFC_NORMAL_MODE 0x00
+#define TRF79X0_NFC_CARD_EMULATION_MODE 0x40
+#define TRF79X0_ISO_CONTROL_14443A_106K 0x08
+#define TRF79X0_ISO_CONTROL_14443A_106K 0x08
+#define TRF79X0_ISO_CONTROL_14443B_106K 0x0C
+#define TRF79X0_ISO_CONTROL_15693_LOW_1SUB_1OUT4 0x00
+#define TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT4 0x02
+#define TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT256 0x03
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_MODULATOR_CONTROL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_MOD_CTRL_SYS_CLK_13_56MHZ 0x30
+#define TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ 0x20
+#define TRF79X0_MOD_CTRL_SYS_CLK_3_3MHZ 0x10
+#define TRF79X0_MOD_CTRL_SYS_CLK_DISABLE 0x00
+#define TRF79X0_MOD_CTRL_MOD_ASK_30 0x07
+#define TRF79X0_MOD_CTRL_MOD_ASK_22 0x06
+#define TRF79X0_MOD_CTRL_MOD_ASK_16 0x05
+#define TRF79X0_MOD_CTRL_MOD_ASK_13 0x04
+#define TRF79X0_MOD_CTRL_MOD_ASK_8_5 0x03
+#define TRF79X0_MOD_CTRL_MOD_ASK_7 0x02
+#define TRF79X0_MOD_CTRL_MOD_OOK_100 0x01
+#define TRF79X0_MOD_CTRL_MOD_ASK_10 0x00
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_RX_SPECIAL_SETTINGS_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_RX_SP_SET_M848 0x20
+#define TRF79X0_RX_SP_SET_C424 0x40
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_REGULATOR_CONTROL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_REGULATOR_CTRL_AUTO_REG 0x80
+#define TRF79X0_REGULATOR_CTRL_VRS_2_7V 0x00
+#define TRF79X0_REGULATOR_CTRL_VRS_2_8V 0x01
+#define TRF79X0_REGULATOR_CTRL_VRS_2_9V 0x02
+#define TRF79X0_REGULATOR_CTRL_VRS_3_0V 0x03
+#define TRF79X0_REGULATOR_CTRL_VRS_3_1V 0x04
+#define TRF79X0_REGULATOR_CTRL_VRS_3_2V 0x05
+#define TRF79X0_REGULATOR_CTRL_VRS_3_3V 0x06
+#define TRF79X0_REGULATOR_CTRL_VRS_3_4V 0x07
+
+//*****************************************************************************
+//
+// TRF79x0 Command Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_IDLE_CMD 0x00
+#define TRF79X0_SOFT_INIT_CMD 0x03
+#define TRF79X0_INITIAL_RF_COLLISION_AVOID_CMD 0x04
+#define TRF79X0_PERFORM_RES_RF_COLLISION_AVOID_CMD 0x05
+#define TRF79X0_PERFORM_RES_RF_COLLISION_AVOID_N0_CMD 0x06
+#define TRF79X0_RESET_FIFO_CMD 0x0F
+#define TRF79X0_TRANSMIT_NO_CRC_CMD 0x10
+#define TRF79X0_TRANSMIT_CRC_CMD 0x11
+#define TRF79X0_DELAY_TRANSMIT_NO_CRC_CMD 0x12
+#define TRF79X0_DELAY_TRANSMIT_CRC_CMD 0x13
+#define TRF79X0_TRANSMIT_NEXT_SLOT_CMD 0x14
+#define TRF79X0_CLOSE_SLOT_SEQUENCE_CMD 0x15
+#define TRF79X0_STOP_DECODERS_CMD 0x16
+#define TRF79X0_RUN_DECODERS_CMD 0x17
+#define TRF79X0_TEST_INTERNAL_RF_CMD 0x18
+#define TRF79X0_TEST_EXTERNAL_RF_CMD 0x19
+#define TRF79X0_RX_ADJUST_GAIN_CMD 0x1A
+
+//*****************************************************************************
+//
+// TRF79x0 Command/Address mode definitions.
+//
+//*****************************************************************************
+#define TRF79X0_ADDRESS_MASK 0x1F
+#define TRF79X0_CONTROL_CMD 0x80
+#define TRF79X0_CONTROL_REG_READ 0x40
+#define TRF79X0_CONTROL_REG_WRITE 0x00
+#define TRF79X0_REG_MODE_SINGLE 0x00
+#define TRF79X0_REG_MODE_CONTINUOUS 0x20
+
+//*****************************************************************************
+//
+// TRF7960/7970 Modulator control register mode default values to
+// determine RF Daughter Board.
+//
+//*****************************************************************************
+#define TRF7960_DEFAULT_ID 0x11
+#define TRF7970_DEFAULT_ID 0x91
+
+//*****************************************************************************
+//
+// The following defines are used with the TRF79x0Transceive() function with
+// the uiFlags parameter.
+//
+//*****************************************************************************
+
+//
+// Transmit without CRC, receive without CRC check.
+//
+#define TRF79X0_TRANSCEIVE_NO_CRC 0
+//
+// Transmit without CRC, receive with CRC check.
+//
+#define TRF79X0_TRANSCEIVE_RX_CRC 1
+//
+// Transmit with CRC, receive without CRC check.
+//
+#define TRF79X0_TRANSCEIVE_TX_CRC 2
+//
+// Transmit with CRC, receive with CRC check.
+//
+#define TRF79X0_TRANSCEIVE_CRC (TRF79X0_TRANSCEIVE_TX_CRC | \
+ TRF79X0_TRANSCEIVE_RX_CRC)
+
+//*****************************************************************************
+//
+// These defines specify abstract IRQ causes to wait for. Since the IRQ
+// state register does not lend itself to easy cumulative storage (for
+// example just because bit 0x80 was set at least once does not mean that the
+// transmission is complete) these are defined to have an abstract way to
+// express certain conditions that one would want to wait for.
+//
+//*****************************************************************************
+
+//
+// Wait for any IRQ to occur.
+//
+#define TRF79X0_WAIT_ANY 0x00000001
+
+//
+// Wait for an IRQ that signifies the end of transmission to occur.
+//
+#define TRF79X0_WAIT_TXEND 0x00000002
+
+//
+// Wait for an IRQ that signifies the end of reception to occur, this
+// will either be 0x40 with no other flags set, or 0x01 for RX timeout.
+//
+#define TRF79X0_WAIT_RXEND 0x00000004
+
+//*****************************************************************************
+//
+// These enumerations are used as part of the state machine layout for NFC P2P
+//
+//*****************************************************************************
+
+//
+// States for the TRF79x0 State Machine
+//
+typedef enum
+{
+ BOARD_INIT = 0,
+ P2P_INITATIOR_MODE,
+ P2P_PASSIVE_TARGET_MODE,
+ P2P_ACTIVE_TARGET_MODE,
+ CARD_EMULATION_TYPE_A,
+ CARD_EMULATION_TYPE_B
+} tTRF79x0TRFMode;
+
+//
+// Frequency Settings for TRF79x0
+//
+typedef enum
+{
+ FREQ_STAND_BY= 0, // Used for Board Initialization
+ FREQ_106_KBPS,
+ FREQ_212_KBPS,
+ FREQ_424_KBPS
+} tTRF79x0Frequency;
+
+//
+// CRC Settings for TRF79x0
+//
+typedef enum
+{
+ CRC_BIT_DISABLE = 0,
+ CRC_BIT_ENABLE
+} tTRF79x0CRC;
+
+//
+// IRQ Flag deffinitions. Defined in datasheet, provided for ease of use
+//
+typedef enum
+{
+ IRQ_STATUS_IDLE = 0x00,
+ IRQ_STATUS_COLLISION_ERROR = 0x01,
+ IRQ_STATUS_COLLISION_AVOID_FINISHED = 0x02,
+ IRQ_STATUS_RF_FIELD_CHANGE = 0x04,
+ IRQ_STATUS_SDD_COMPLETE = 0x08,
+ IRQ_STATUS_PROTOCOL_ERROR = 0x10,
+ IRQ_STATUS_FIFO_HIGH_OR_LOW = 0x20,
+ IRQ_STATUS_RX_COMPLETE = 0x40,
+ IRQ_STATUS_TX_COMPLETE = 0x80,
+ IRQ_STATUS_TIME_OUT = 0xFF
+} tTRF79x0IRQFlag;
+
+//*****************************************************************************
+//
+// Exported function prototypes.
+//
+//*****************************************************************************
+extern void TRF79x0Init(void);
+extern void TRF79x0SetMode(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency);
+extern void TRF79x0Interrupt(void);
+extern void TRF79x0InterruptInit(void);
+extern void TRF79x0InterruptEnable(void);
+extern void TRF79x0InterruptDisable(void);
+extern void TRF79x0DisableTransmitter(void);
+extern void TRF797x0ResetDecoders(void);
+extern uint8_t* TRF79x0GetNFCBuffer(void);
+extern void TRF79x0DirectCommand(uint8_t ucCommand);
+extern void TRF79x0ResetFifoCommand(void);
+extern tStatus TRF79x0Init2(tTRF79x0TRFMode eMode,
+ tTRF79x0Frequency eFrequency);
+tStatus TRF79x0WriteFIFO(uint8_t *pui8Buffer, tTRF79x0CRC eCRCBit,
+ uint8_t ui8Length);
+tTRF79x0IRQFlag TRF79x0IRQHandler(uint16_t ui16TimeOut);
+extern void TRF79x0WriteRegister(unsigned char ucAddress,
+ unsigned char ucData);
+extern void TRF79x0WriteRegisterContinuous(unsigned char ucAddress,
+ unsigned char *pucData,
+ unsigned int uiLength);
+extern unsigned char TRF79x0ReadIRQStatus(void);
+extern unsigned char TRF79x0ReadRegister(unsigned char ucAddress);
+extern void TRF79x0ReadRegisterContinuous(unsigned char ucAddress,
+ unsigned char *pucData,
+ unsigned int uiLength);
+extern void TRF79x0FIFOWrite(unsigned char const *pucData,
+ unsigned int uiLength);
+extern void TRF79x0Receive(unsigned char *pucData, unsigned int *puiLength);
+extern void TRF79x0Transmit(unsigned char const *pucData,
+ unsigned int uiLength, unsigned int uiBits);
+extern void TRF79x0Transceive(unsigned char const *pucTXBuf,
+ unsigned int uiTXLen, unsigned int uiTXBits,
+ unsigned char *pucRXBuf, unsigned int *puiRXLen,
+ unsigned int *puiRXBits, unsigned int uiFlags);
+extern void TRF79x0IRQClearAll(void);
+extern void TRF79x0IRQClearCauses(unsigned int uiCauses);
+extern int TRF79x0IRQWait(unsigned long ulCondition);
+extern int TRF79x0IRQWaitTimeout(unsigned long ulCondition,
+ unsigned long ulTimeout);
+extern int TRF79x0GetCollisionPosition(void);
+extern int TRF79x0IsCollision(void);
+extern void TRF79x0InitialSettings(void);
+extern void TRF79x0ReceiveAgain(unsigned char *pucRXBuf,
+ unsigned int *puiRXLen);
+extern void TRF79x0ReceiveEnd(void);
+extern void TRF79x0TransceiveISO15693(unsigned char const *pucTXBuf,
+ unsigned int uiTXLen,
+ unsigned int uiTXBits, unsigned char *pucRXBuf,
+ unsigned int *puiRXLen, unsigned int *puiRXBits,
+ unsigned int uiFlags);
+extern int SendResponse(int Something, int DataLength, char *DataPtr);
+extern int SendResponse_w_o_CRC(int Something, int DataLength, char *DataPtr);
+#endif
diff --git a/nfclib/trf79x0_hw_example.h b/nfclib/trf79x0_hw_example.h new file mode 100644 index 0000000..c73e882 --- /dev/null +++ b/nfclib/trf79x0_hw_example.h @@ -0,0 +1,489 @@ +//*****************************************************************************
+//
+// trf79x0_hw_example.h - Hardware Pin configuration for TRF79x0 ATB on
+// Tiva C Series Snowflake Class silicon. Tailored for DK-tm4c129x, but will
+// work for any board with a Snowflake chip with RF Headers.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __TRF79X0_HW_H__
+#define __TRF79X0_HW_H__
+
+//*****************************************************************************
+//
+// Enable the TRF79x0 that will be used with the TM4C129X board
+// Enabled = 1, Disabled = 0
+//
+//*****************************************************************************
+#define RF_DAUGHTER_TRF7960 0
+#define RF_DAUGHTER_TRF7970 1
+
+//*****************************************************************************
+//
+// Check for correct definition of RF_DAUGTHER_TRF79X0
+//
+//*****************************************************************************
+#if (RF_DAUGHTER_TRF7960 && RF_DAUGHTER_TRF7970)
+#error "Only one TRF79X0 can be defined at the same time."
+#elif (!(RF_DAUGHTER_TRF7960 || RF_DAUGHTER_TRF7970))
+#error "Define the TRF79X0 to be used, none currently defined."
+#endif
+
+//*****************************************************************************
+//
+// Pin definitions for the DK-TM4C129X development board connections to the
+// BoosterPack board.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_hw NFC Hardware Definitions
+//! @{
+//! This section covers the definitions that control which hardware is used to
+//! communicate with the TRF79x0 EM module. These defines configure which SSI
+//! peripheral is used as well as which pins are assigned to the other
+//! connections to the TRF79x0 EM module. The \b TRF79X0_SSI_* defines are
+//! used to specify the SSI peripheral that is used by the application. The
+//! remaining defines specify the pins used by the NFC APIs. The TRF79x0
+//! EM module requires the following signal connections: CLK, RX, TX, CS, ASKOK,
+//! EN, EN2, IRQ, MOD. To configure these signals, three defines must be set
+//! for each. For example, for the CS signal, the \ref TRF79X0_CS_BASE,
+//! \ref TRF79X0_CS_PERIPH and \ref TRF79X0_CS_PIN defines must be set.
+//!
+//! \b Example: CS pin is on GPIO port E pin 1.
+//! \verbatim
+//!
+//! #define TRF79X0_CS_BASE GPIO_PORTA_BASE
+//! #define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA
+//! #define TRF79X0_CS_PIN GPIO_PIN_4
+//! \endverbatim
+//!
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The clock rate of the SSI clock specified in Hz.
+//!
+//! \b Example: 2-MHz SSI data clock.
+//!
+//! <tt>\#define SSI_CLK_RATE 2000000</tt>
+//!
+//*****************************************************************************
+#define SSI_CLK_RATE 2000000
+#define SSI_CLKS_PER_MS (SSI_CLK_RATE / 1000)
+#define STATUS_READS_PER_MS (SSI_CLKS_PER_MS / 16)
+#define SSI_NO_DATA 0
+
+//*****************************************************************************
+//
+//! Specifies the SSI peripheral for the SSI port that is connected to the
+//! TRF79x0 EM board. The value should be set to SYSCTL_PERIPH_SSIn, where n is
+//! the number of the SSI port being used.
+//!
+//! \b Example: Uses SSI0 peripheral
+//!
+//! <tt>\#define TRF79X0_SSI_PERIPH SYSCTL_PERIPH_SSI0</tt>
+//!
+//*****************************************************************************
+#define TRF79X0_SSI_PERIPH SYSCTL_PERIPH_SSI0
+
+//*****************************************************************************
+//
+//! Specifies the SSI @a base address for the SSI port that is connected to the
+//! TRF79x0 EM board. The value should be set to SYSCTL_PERIPH_SSIn, where n is
+//! the number of the SSI port being used.
+//!
+//! \b Example: Uses SSI0 peripheral
+//!
+//! <tt>\#define TRF79X0_SSI_BASE SSI0_BASE</tt>
+//!
+//*****************************************************************************
+#define TRF79X0_SSI_BASE SSI0_BASE
+
+//*****************************************************************************
+//
+// GPIO pin deffinitions for TRF79x0 SSI signals
+//
+//*****************************************************************************
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CLK_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_CLK_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CLK_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_CLK_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO pin 2.
+//!
+//! <tt>\#define TRF79X0_CLK_PIN GPIO_PIN_2</tt>
+//
+#define TRF79X0_CLK_PIN GPIO_PIN_2
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSI Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI Clock signal is on GPIO port A pin 2.
+//!
+//! <tt>\#define TRF79X0_CLK_CONFIG GPIO_PA2_SSI0CLK</tt>
+//
+#define TRF79X0_CLK_CONFIG GPIO_PA2_SSI0CLK
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_TX_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_TX_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_TX_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_TX_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_TX_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_TX_PIN GPIO_PIN_4
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSITX (DAT0) signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI 1 TX signal is on GPIO port A pin 4.
+//!
+//! <tt>\#define TRF79X0_TX_CONFIG GPIO_PA4_SSI0XDAT0</tt>
+//
+#define TRF79X0_TX_CONFIG GPIO_PA4_SSI0XDAT0
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_RX_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_RX_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_RX_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_RX_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO pin 5.
+//!
+//! <tt>\#define TRF79X0_RX_PIN GPIO_PIN_5</tt>
+//
+#define TRF79X0_RX_PIN GPIO_PIN_5
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSIRX (DAT1) signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI 1 RX signal is on GPIO port A pin 5.
+//!
+//! <tt>\#define TRF79X0_RX_CONFIG GPIO_PA5_SSI0XDAT1</tt>
+//
+#define TRF79X0_RX_CONFIG GPIO_PA5_SSI0XDAT1
+
+//*****************************************************************************
+//
+// Hardware connection definitions for the TRF79x0 board.
+//
+//*****************************************************************************
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI CS signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CS_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_CS_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI CS signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CS signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_CS_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_CS_PIN GPIO_PIN_3
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the EN
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN_BASE GPIO_PORTD_BASE</tt>
+//
+#define TRF79X0_EN_BASE GPIO_PORTD_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the EN
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN_PERIPH SYSCTL_PERIPH_GPIOD</tt>
+//
+#define TRF79X0_EN_PERIPH SYSCTL_PERIPH_GPIOD
+
+//
+//! Specifies the GPIO pin that is connected to the EN pin on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO pin 2.
+//!
+//! <tt>\#define TRF79X0_EN_PIN GPIO_PIN_2</tt>
+//
+#define TRF79X0_EN_PIN GPIO_PIN_2
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the EN2
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN2_BASE GPIO_PORTD_BASE</tt>
+//
+#define TRF79X0_EN2_BASE GPIO_PORTD_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the EN2
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN2_PERIPH SYSCTL_PERIPH_GPIOD</tt>
+//
+#define TRF79X0_EN2_PERIPH SYSCTL_PERIPH_GPIOD
+
+//
+//! Specifies the GPIO pin that is connected to the EN2 signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO pin 3.
+//!
+//! <tt>\#define TRF79X0_EN2_PIN GPIO_PIN_3</tt>
+//
+#define TRF79X0_EN2_PIN GPIO_PIN_3
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the
+//! ASKOK signal on the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_ASKOK_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_ASKOK_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the ASKOK
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_ASKOK_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_ASKOK_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the ASKOK signal on
+//! the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO pin 5.
+//!
+//! <tt>\#define TRF79X0_ASKOK_PIN GPIO_PIN_5</tt>
+//
+#define TRF79X0_ASKOK_PIN GPIO_PIN_5
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the MOD
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_MOD_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_MOD_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the MOD
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_MOD_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_MOD_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the MOD signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_MOD_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_MOD_PIN GPIO_PIN_4
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the IRQ
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_IRQ_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_IRQ_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the IRQ
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_IRQ_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_IRQ_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the IRQ signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO pin 1.
+//!
+//! <tt>\#define TRF79X0_IRQ_PIN GPIO_PIN_1</tt>
+//
+#define TRF79X0_IRQ_PIN GPIO_PIN_1
+
+//
+//! Specifies GPIO interrupt that is tied to the GPIO port that the IRQ signal
+//! is connected to TRF79x0 EM board.
+//!
+//! \b Example: SSI GPIO interrupt is on GPIO port C.
+//!
+//! <tt>\#define TRF79X0_IRQ_INT INT_GPIOC</tt>
+//
+#define TRF79X0_IRQ_INT INT_GPIOJ
+
+//
+// Uses Blue LED part of RGB tricolor LED (arbitrary color choice)
+//
+#define ENABLE_LED_PERIPHERAL SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_4 );
+#define TURN_ON_LED GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, GPIO_PIN_4);
+#define TURN_OFF_LED GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, 0);
+
+//*****************************************************************************
+//
+// Optional LED Defines, useful for boards that have tricolor LED's
+//
+//*****************************************************************************
+#define BOARD_HAS_TRICOLOR_LED 1
+
+#define ENABLE_LED_TRICOLOR_RED_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
+#define SET_LED_TRICOLOR_RED_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_5 );
+#define TURN_ON_LED_TRICOLOR_RED GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
+#define TURN_OFF_LED_TRICOLOR_RED GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, 0);
+
+#define ENABLE_LED_TRICOLOR_BLUE_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_TRICOLOR_BLUE_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_4 );
+#define TURN_ON_LED_TRICOLOR_BLUE GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, GPIO_PIN_4);
+#define TURN_OFF_LED_TRICOLOR_BLUE GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, 0);
+
+#define ENABLE_LED_TRICOLOR_GREEN_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_TRICOLOR_GREEN_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_7 );
+#define TURN_ON_LED_TRICOLOR_GREEN GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_7, GPIO_PIN_7);
+#define TURN_OFF_LED_TRICOLOR_GREEN GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_7, 0);
+
+//*****************************************************************************
+//
+// Macro for IRQ signal from TRF79x0 -> Board
+// left in this format for cross platform compatibility.
+//
+//*****************************************************************************
+#define IRQ_IS_SET() GPIOPinRead(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif // __TRF79X0_HW_H__
diff --git a/nfclib/types.h b/nfclib/types.h new file mode 100644 index 0000000..b1a655a --- /dev/null +++ b/nfclib/types.h @@ -0,0 +1,36 @@ +//*****************************************************************************
+// types.h - typedefs used for cross architecture code porting / ease of use.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+//
+// Boolean Status type. Provided for Cross Compatibility with other chipsets.
+// Not necessary, but useful for porting code between architectures.
+//
+typedef enum
+{
+ STATUS_FAIL = 0,
+ STATUS_SUCCESS
+}tStatus;
+
+#endif //_TYPES_H_
|
