From 4085ae3ddfbbf10c8ccbd3dccd43452c40a1fe40 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Fri, 13 Mar 2015 12:24:52 +0200 Subject: Add bootloader, nfclib and sensorlib --- nfclib/debug.h | 74 ++ nfclib/directmode.c | 1059 +++++++++++++++++++++++ nfclib/directmode.h | 78 ++ nfclib/iso14443-4.c | 164 ++++ nfclib/iso14443-4.h | 33 + nfclib/iso14443a.c | 1141 +++++++++++++++++++++++++ nfclib/iso14443a.h | 65 ++ nfclib/iso14443b.c | 339 ++++++++ nfclib/iso14443b.h | 51 ++ nfclib/iso15693.c | 694 +++++++++++++++ nfclib/iso15693.h | 62 ++ nfclib/llcp.c | 1051 +++++++++++++++++++++++ nfclib/llcp.h | 248 ++++++ nfclib/nfc.c | 241 ++++++ nfclib/nfc.h | 42 + nfclib/nfc_dep.c | 597 +++++++++++++ nfclib/nfc_dep.h | 109 +++ nfclib/nfc_f.c | 166 ++++ nfclib/nfc_f.h | 48 ++ nfclib/nfc_p2p.c | 1993 +++++++++++++++++++++++++++++++++++++++++++ nfclib/nfc_p2p.h | 1536 +++++++++++++++++++++++++++++++++ nfclib/snep.c | 760 +++++++++++++++++ nfclib/snep.h | 206 +++++ nfclib/ssitrf79x0.c | 826 ++++++++++++++++++ nfclib/ssitrf79x0.h | 62 ++ nfclib/trf79x0.c | 1961 ++++++++++++++++++++++++++++++++++++++++++ nfclib/trf79x0.h | 400 +++++++++ nfclib/trf79x0_hw_example.h | 489 +++++++++++ nfclib/types.h | 36 + 29 files changed, 14531 insertions(+) create mode 100644 nfclib/debug.h create mode 100644 nfclib/directmode.c create mode 100644 nfclib/directmode.h create mode 100644 nfclib/iso14443-4.c create mode 100644 nfclib/iso14443-4.h create mode 100644 nfclib/iso14443a.c create mode 100644 nfclib/iso14443a.h create mode 100644 nfclib/iso14443b.c create mode 100644 nfclib/iso14443b.h create mode 100644 nfclib/iso15693.c create mode 100644 nfclib/iso15693.h create mode 100644 nfclib/llcp.c create mode 100644 nfclib/llcp.h create mode 100644 nfclib/nfc.c create mode 100644 nfclib/nfc.h create mode 100644 nfclib/nfc_dep.c create mode 100644 nfclib/nfc_dep.h create mode 100644 nfclib/nfc_f.c create mode 100644 nfclib/nfc_f.h create mode 100644 nfclib/nfc_p2p.c create mode 100644 nfclib/nfc_p2p.h create mode 100644 nfclib/snep.c create mode 100644 nfclib/snep.h create mode 100644 nfclib/ssitrf79x0.c create mode 100644 nfclib/ssitrf79x0.h create mode 100644 nfclib/trf79x0.c create mode 100644 nfclib/trf79x0.h create mode 100644 nfclib/trf79x0_hw_example.h create mode 100644 nfclib/types.h (limited to 'nfclib') 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 +#include +#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 + +#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 +#include +#include +#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: +//

A: Detect only new cards

    +//
  • Keep field enabled at all times +//
  • 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(). +//
  • 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. +//
  • 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 +//
+// Pseudo C:
+//  while(1) {
+//      ISO14443APowerOn();
+//      if(ISO14443ASelectFirst(ISO14443A_REQA, ...)) {
+//
+//          Do something with the card
+//
+//          ISO14443AHalt();
+//      }
+//
+//      Do NOT power off the field
+//  }
+// 
+// +//

B: List all cards in the field

    +//
  • Optionally disable the field or do other things, but enable the +// field at least for 5ms (e.g. with ISO14443APowerOn()) +//
  • 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. +//
  • 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. +//
+// Pseudo C:
+//  while(1) {
+//      ISO14443APowerOn();
+//      if(ISO14443ASelectFirst(ISO14443A_WUPA, ...)) {
+//          do {
+//
+//              Do something with the card
+//
+//              ISO14443AHalt();
+//          } while(ISO14443ASelectNext(ISO14443A_WUPA, ...));
+//      }
+//
+//      You may power off the field here
+//  }
+// 
+// +// 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 +#include +#include +#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 +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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<> 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 +#include +#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 +#include +#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 +//! +//! http://www.nfc-forum.org/specs/spec_list . +//! +//! 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 +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_MB(0x1) +//! +//! \b Example: Clear the MB field in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_MB(0x0) +//! +// +#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 +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_ME(0x1) +//! +//! \b Example: Clear the ME field in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_ME(0x0) +//! +// +#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 +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_CF(0x1) +//! +//! \b Example: Clear the CF field in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_CF(0x0) +//! +// +#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 +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_SR(0x1) +//! +//! \b Example: Clear the SR field in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_SR(0x0) +//! +// +#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 +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_IL(0x1) +//! +//! \b Example: Clear the IL field in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_IL(0x0) +//! +// +#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 +//! +//! NsNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte | +//! NDEF_STATUSBYTE_SET_TNF(0x1) +//! +//! \b Example: Set the TNF field to Unknown Type in a StatusByte +//! +//! sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte & +//! NDEF_STATUSBYTE_SET_TNF(0x5) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_MB(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_ME(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_CF(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_SR(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_IL(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! x = NDEF_STATUSBYTE_GET_TNF(sNDEFMessageData.sStatusByte) +//! +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_MB(ui8StatusByte) == +//! NDEF_STATUSBYTE_MB_FIRSTBYTE){} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_ME(ui8StatusByte) == NDEF_STATUSBYTE_ME_LASTBYTE) +//! {} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_CF(ui8StatusByte) == NDEF_STATUSBYTE_CF_CHUNK) +//! {} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) == +//! NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE){} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) == +//! NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE){} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) == +//! NDEF_STATUSBYTE_IL_IDLENGTHPRESENT) {} +// +#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 +//! +//! if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) == +//! NDEF_STATUSBYTE_IL_IDLENGTHABSENT) {} +// +#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 +//! +//! +//! \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 +// +#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 +//! +//! +//! \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 +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! +//! \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 +//! +// +#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 +//! +//! if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF8){} +// +#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 +//! +//! if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF16){} +// +#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 +//! +//! ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_UTF( +//! NDEF_TEXTRECORD_STATUSBYTE_UTF8) | +//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...)) +//! +//! +// +#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 +//! +//! ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(0)| +//! (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...))) +//! +//! +// +#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 +//! +//! ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(5) | +//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...)) +//! +//! +// +#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 +//! +//! sNDEFTextRecord.bUTFcode = NDEF_TEXTRECORD_STATUSBYTE_GET_UTF( +//! ui8StatusByte) +//! +//! +// +#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 +//! +//! sNDEFTextRecord.bRFU = NDEF_TEXTRECORD_STATUSBYTE_GET_RFU( +//! ui8StatusByte) +//! +//! +// +#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 +//! +//! +//! sNDEFTextRecord.ui5LengthLangCode = +//! NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8StatusByte) +//! +//! +// +#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 +//! +//! +//! \verbatim +//! if(sNDEFURIRecord.eIDCode < NDEF_URIRECORD_IDCODE_RFU) +//! { +//! //process tag +//! } +//! \endverbatim +//! +// +//***************************************************************************** +#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 +#include +#include +#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 +#include +#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 +#include +#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 + // (1< 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 (1<<x) where x +// 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. +//! +//! \#define SSI_CLK_RATE 2000000 +//! +//***************************************************************************** +#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 +//! +//! \#define TRF79X0_SSI_PERIPH SYSCTL_PERIPH_SSI0 +//! +//***************************************************************************** +#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 +//! +//! \#define TRF79X0_SSI_BASE SSI0_BASE +//! +//***************************************************************************** +#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. +//! +//! \#define TRF79X0_CLK_BASE GPIO_PORTA_BASE +// +#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. +//! +//! \#define TRF79X0_CLK_PERIPH SYSCTL_PERIPH_GPIOA +// +#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. +//! +//! \#define TRF79X0_CLK_PIN GPIO_PIN_2 +// +#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. +//! +//! \#define TRF79X0_CLK_CONFIG GPIO_PA2_SSI0CLK +// +#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. +//! +//! \#define TRF79X0_TX_BASE GPIO_PORTA_BASE +// +#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. +//! +//! \#define TRF79X0_TX_PERIPH SYSCTL_PERIPH_GPIOA +// +#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. +//! +//! \#define TRF79X0_TX_PIN GPIO_PIN_4 +// +#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. +//! +//! \#define TRF79X0_TX_CONFIG GPIO_PA4_SSI0XDAT0 +// +#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. +//! +//! \#define TRF79X0_RX_BASE GPIO_PORTA_BASE +// +#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. +//! +//! \#define TRF79X0_RX_PERIPH SYSCTL_PERIPH_GPIOA +// +#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. +//! +//! \#define TRF79X0_RX_PIN GPIO_PIN_5 +// +#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. +//! +//! \#define TRF79X0_RX_CONFIG GPIO_PA5_SSI0XDAT1 +// +#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. +//! +//! \#define TRF79X0_CS_BASE GPIO_PORTA_BASE +// +#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. +//! +//! \#define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA +// +#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. +//! +//! \#define TRF79X0_CS_PIN GPIO_PIN_4 +// +#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. +//! +//! \#define TRF79X0_EN_BASE GPIO_PORTD_BASE +// +#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. +//! +//! \#define TRF79X0_EN_PERIPH SYSCTL_PERIPH_GPIOD +// +#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. +//! +//! \#define TRF79X0_EN_PIN GPIO_PIN_2 +// +#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. +//! +//! \#define TRF79X0_EN2_BASE GPIO_PORTD_BASE +// +#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. +//! +//! \#define TRF79X0_EN2_PERIPH SYSCTL_PERIPH_GPIOD +// +#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. +//! +//! \#define TRF79X0_EN2_PIN GPIO_PIN_3 +// +#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. +//! +//! \#define TRF79X0_ASKOK_BASE GPIO_PORTJ_BASE +// +#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. +//! +//! \#define TRF79X0_ASKOK_PERIPH SYSCTL_PERIPH_GPIOJ +// +#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. +//! +//! \#define TRF79X0_ASKOK_PIN GPIO_PIN_5 +// +#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. +//! +//! \#define TRF79X0_MOD_BASE GPIO_PORTJ_BASE +// +#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. +//! +//! \#define TRF79X0_MOD_PERIPH SYSCTL_PERIPH_GPIOJ +// +#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. +//! +//! \#define TRF79X0_MOD_PIN GPIO_PIN_4 +// +#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. +//! +//! \#define TRF79X0_IRQ_BASE GPIO_PORTJ_BASE +// +#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. +//! +//! \#define TRF79X0_IRQ_PERIPH SYSCTL_PERIPH_GPIOJ +// +#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. +//! +//! \#define TRF79X0_IRQ_PIN GPIO_PIN_1 +// +#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. +//! +//! \#define TRF79X0_IRQ_INT INT_GPIOC +// +#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_ -- cgit v1.3.1