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/nfc_p2p.c | 1993 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1993 insertions(+) create mode 100644 nfclib/nfc_p2p.c (limited to 'nfclib/nfc_p2p.c') 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. +//! @} +// +//***************************************************************************** -- cgit v1.3.1