diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 6c6a61c..b5b92e0 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -4,149 +4,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/README.md b/README.md index 29b9b36..4ddf4b0 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Some source code is licensed separately, please check the following table for de | components/pax-keyboard | | MIT | Julian Scheffers | | components/sdcard | | MIT | Nicolai Electronics | | components/spi-ili9341 | | MIT | Nicolai Electronics | +| components/spi-st25r3911b/en.STSW-ST25RFAL001 | 2.10.0 | SLA0051 MyLiberty | STMicroelectronics | | components/ws2812 | | MIT | Unlicense / Public domain | | tools/[libusb-1.0.dll] | | GNU LGPL 2.1 | See the [AUTHORS](https://github.com/libusb/libusb/blob/master/AUTHORS) document of the project | diff --git a/components/keyboard b/components/keyboard index 76cf073..8a3ae33 160000 --- a/components/keyboard +++ b/components/keyboard @@ -1 +1 @@ -Subproject commit 76cf073ad933a19c8e2c88d69a073e7555653a67 +Subproject commit 8a3ae33cc14326433202a22544119cb0977943cd diff --git a/components/spi-st25r3911b/CMakeLists.txt b/components/spi-st25r3911b/CMakeLists.txt new file mode 100644 index 0000000..af55a97 --- /dev/null +++ b/components/spi-st25r3911b/CMakeLists.txt @@ -0,0 +1,36 @@ +idf_component_register( + SRCS + "st25r3911b.c" + "en.STSW-ST25RFAL001/source/rfal_nfc.c" + "en.STSW-ST25RFAL001/source/rfal_analogConfig.c" + "en.STSW-ST25RFAL001/source/rfal_cd.c" + "en.STSW-ST25RFAL001/source/rfal_crc.c" + "en.STSW-ST25RFAL001/source/rfal_crc.h" + "en.STSW-ST25RFAL001/source/rfal_dpo.c" + "en.STSW-ST25RFAL001/source/rfal_iso15693_2.c" + "en.STSW-ST25RFAL001/source/rfal_iso15693_2.h" + "en.STSW-ST25RFAL001/source/rfal_isoDep.c" + "en.STSW-ST25RFAL001/source/rfal_nfca.c" + "en.STSW-ST25RFAL001/source/rfal_nfcb.c" + "en.STSW-ST25RFAL001/source/rfal_nfcDep.c" + "en.STSW-ST25RFAL001/source/rfal_nfcf.c" + "en.STSW-ST25RFAL001/source/rfal_nfcv.c" + "en.STSW-ST25RFAL001/source/rfal_st25tb.c" + "en.STSW-ST25RFAL001/source/rfal_st25xv.c" + "en.STSW-ST25RFAL001/source/rfal_t1t.c" + "en.STSW-ST25RFAL001/source/rfal_t2t.c" + "en.STSW-ST25RFAL001/source/rfal_t4t.c" + "en.STSW-ST25RFAL001/source/st25r3911/rfal_rfst25r3911.c" + "en.STSW-ST25RFAL001/source/st25r3911/st25r3911.c" + "en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.c" + "en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.c" + "NDEF/source" + INCLUDE_DIRS + "include" + "en.STSW-ST25RFAL001" + "en.STSW-ST25RFAL001/include" + "en.STSW-ST25RFAL001/source/st25r3911" + "NDEF/include" + "NDEF/include/message" + "NDEF/include/poller" +) diff --git a/components/spi-st25r3911b/NDEF/.gitattributes b/components/spi-st25r3911b/NDEF/.gitattributes new file mode 100644 index 0000000..88961fc --- /dev/null +++ b/components/spi-st25r3911b/NDEF/.gitattributes @@ -0,0 +1,6 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Declare files that will always have LF line endings on checkout. +*.uvprojx text eol=lf +*.uvoptx text eol=lf diff --git a/components/spi-st25r3911b/NDEF/LICENCE b/components/spi-st25r3911b/NDEF/LICENCE new file mode 100644 index 0000000..d5b35a4 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/LICENCE @@ -0,0 +1,54 @@ +SLA0051 +SOFTWARE LICENSE AGREEMENT (“Agreement”) +BY CLICKING ON THE "I ACCEPT" BUTTON OR BY UNZIPPING, INSTALLING, COPYING, DOWNLOADING, ACCESSING +OR OTHERWISE USING THIS SOFTWARE (HEREINAFTER “SOFTWARE” MEANS THE RELATED SOFTWARE, +DOCUMENTATION, OTHER MATERIALS, AND ANY PARTS, PERMITTED MODIFICATIONS, AND PERMITTED +DERIVATIVES THEREOF) FROM STMICROELECTRONICS INTERNATIONAL N.V, SWISS BRANCH AND/OR ITS +AFFILIATED COMPANIES (“STMICROELECTRONICS”), THE RECIPIENT, ON BEHALF OF HIMSELF OR HERSELF, OR ON +BEHALF OF ANY ENTITY BY WHICH SUCH RECIPIENT IS EMPLOYED AND/OR ENGAGED (“YOU”) AGREES TO BE +BOUND BY THIS AGREEMENT. +You represent that you have the authority to enter into this Agreement. You will comply with all laws, including export laws. +STMicroelectronics’s failure or delay to enforce this Agreement does not waive STMicroelectronics’s rights. Swiss law, except +conflict of laws, governs this Agreement, and the parties consent to exclusive jurisdiction of courts in Switzerland for litigation of +this Agreement. +Subject to the below disclaimer, the redistribution, reproduction and use in source and binary forms of the software or any part +thereof, with or without modification, are permitted provided that the following conditions are met: +1. Redistribution of source code (modified or not) must retain any copyright notice, this list of conditions and the following +disclaimer. +2. Redistributions in binary form, except as embedded into a microcontroller or microprocessor device or a software update +for such device, must reproduce any copyright notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. Neither the name of STMicroelectronics nor the names of other contributors to this software may be used to endorse or +promote products using or derived from this software or part thereof without specific written permission. +4. This software or any part thereof, including modifications and/or derivative works of this software, must be used and +execute solely and exclusively in combination with an integrated circuit that is manufactured by or for STMicroelectronics +and is an NFC tag, NFC dynamic tag, NFC reader, or UHF reader. +5. No use, reproduction or redistribution of this software may be done in any manner that would subject this software to any +Open Source Terms. “Open Source Terms” shall mean any open source license which requires as part of distribution of +software that the source code of such software is distributed therewith or otherwise made available, or open source license +that substantially complies with the Open Source definition specified at www.opensource.org and any other comparable +open source license such as for example GNU General Public License (GPL), Eclipse Public License (EPL), Apache +Software License, BSD license and MIT license. +6. STMicroelectronics has no obligation to provide any maintenance, support or updates for the software. +7. The software is and will remain the exclusive property of STMicroelectronics and its licensors. The recipient will not take +any action that jeopardizes STMicroelectronics and its licensors' proprietary rights or acquire any rights in the software, +except the limited rights specified hereunder. +8. Redistribution and use of this software partially or any part thereof other than as permitted under this license is void and +will automatically terminate your rights under this license. +DISCLAIMER +THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS, +IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY +INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT +SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +EXCEPT AS EXPRESSLY PERMITTED HEREUNDER, NO LICENSE OR OTHER RIGHTS, WHETHER EXPRESS OR +IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF +STMICROELECTRONICS OR ANY THIRD PARTY. + + diff --git a/components/spi-st25r3911b/NDEF/doc/ndef.chm b/components/spi-st25r3911b/NDEF/doc/ndef.chm new file mode 100644 index 0000000..e5c791a Binary files /dev/null and b/components/spi-st25r3911b/NDEF/doc/ndef.chm differ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_buffer.h b/components/spi-st25r3911b/NDEF/include/message/ndef_buffer.h new file mode 100644 index 0000000..78ef6cd --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_buffer.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF buffer type structures + * + */ + +#ifndef NDEF_BUFFER_H +#define NDEF_BUFFER_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! NDEF structure to handle const buffers */ +typedef struct +{ + const uint8_t* buffer; /*!< Pointer to const buffer */ + uint32_t length; /*!< buffer length */ +} ndefConstBuffer; + + +/*! NDEF structure to handle buffers */ +typedef struct +{ + uint8_t* buffer; /*!< Pointer to buffer */ + uint32_t length; /*!< buffer length */ +} ndefBuffer; + + +/*! NDEF structure to handle const buffers limited to 256 bytes */ +typedef struct +{ + const uint8_t* buffer; /*!< Pointer to const buffer */ + uint8_t length; /*!< buffer length */ +} ndefConstBuffer8; + + +/*! NDEF structure to handle buffers limited to 256 bytes */ +typedef struct +{ + uint8_t* buffer; /*!< Pointer to buffer */ + uint8_t length; /*!< buffer length */ +} ndefBuffer8; + + +#endif /* NDEF_BUFFER_H */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_message.h b/components/spi-st25r3911b/NDEF/include/message/ndef_message.h new file mode 100644 index 0000000..4cb6976 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_message.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF message header file + * + * NDEF Message provides functionalities required to perform message management. + * A message is a list of records. + * + * The most common interfaces are: + *
  ndefMessageReset() + *
  ndefMessageAppend() + *
  ndefMessageEncode() + *
  ndefMessageDecode() + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_MESSAGE_H +#define NDEF_MESSAGE_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_config.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/*! Message scanning macros */ +#define ndefMessageGetFirstRecord(message) (((message) == NULL) ? NULL : (message)->record) /*!< Get first record */ +#define ndefMessageGetNextRecord(record) (((record) == NULL) ? NULL : (record)->next) /*!< Get next record */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! Message information */ +typedef struct +{ + uint32_t length; /*!< Message length in bytes */ + uint32_t recordCount; /*!< Number of records in the message */ +} ndefMessageInfo; + + +/*! NDEF message */ +struct ndefMessageStruct +{ + ndefRecord* record; /*!< Pointer to a record */ + ndefMessageInfo info; /*!< Message information, e.g. length in bytes, record count */ +}; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * Initialize an empty NDEF message + * + * \param[in,out] message to initialize + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMessageInit(ndefMessage* message); + + +/*! + ***************************************************************************** + * Get NDEF message information + * + * Return the message information + * + * \param[in] message to get info from + * \param[out] info: e.g. message length in bytes, number of records + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMessageGetInfo(const ndefMessage* message, ndefMessageInfo* info); + + +/*! + ***************************************************************************** + * Get the number of NDEF message records + * + * Return the number of records in the given message + * + * \param[in] message + * + * \return number of records + ***************************************************************************** + */ +uint32_t ndefMessageGetRecordCount(const ndefMessage* message); + + +/*! + ***************************************************************************** + * Append a record to an NDEF message + * + * \param[in] record: Record to append + * \param[in,out] message: Message to be appended with the given record + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMessageAppend(ndefMessage* message, ndefRecord* record); + + +/*! + ***************************************************************************** + * Decode a raw buffer to an NDEF message + * + * Convert a raw buffer to a message + * + * \param[in] bufPayload: Payload buffer to convert into message + * \param[out] message: Message created from the raw buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMessageDecode(const ndefConstBuffer* bufPayload, ndefMessage* message); + + +#if NDEF_FEATURE_FULL_API +/*! + ***************************************************************************** + * Encode an NDEF message to a raw buffer + * + * Convert a message to a raw buffer + * + * \param[in] message: Message to convert + * \param[in,out] bufPayload: Output buffer to store the converted message + * The input length provides the output buffer allocated + * length, used for parameter check to avoid overflow. + * In case the buffer provided is too short, it is + * updated with the required buffer length. + * On success, it is updated with the actual buffer + * length used to contain the converted message. + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMessageEncode(const ndefMessage* message, ndefBuffer* bufPayload); +#endif + + +#if NDEF_FEATURE_FULL_API +/*! + ***************************************************************************** + * Look for a given record type in an NDEF message + * + * Parses an NDEF message, looking for a record of given type + * + * \param[in] message: Message to parse + * \param[in] tnf: TNF type to match + * \param[in] bufType: Type buffer to match + * + * \return the record matching the type if successful or NULL + ***************************************************************************** + */ +ndefRecord* ndefMessageFindRecordType(ndefMessage* message, uint8_t tnf, const ndefConstBuffer8* bufType); +#endif + + +#endif /* NDEF_MESSAGE_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_record.h b/components/spi-st25r3911b/NDEF/include/message/ndef_record.h new file mode 100644 index 0000000..82f3837 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_record.h @@ -0,0 +1,409 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF record header file + * + * + * NDEF record provides functionalities required to perform record management. + * + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_RECORD_H +#define NDEF_RECORD_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_config.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_RECORD_HEADER_LEN 7U /*!< Record header length (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) */ + +#define NDEF_SHORT_RECORD_LENGTH_MAX 255U /*!< Short record maximum length */ + + +/*! Type Name Format aka TNF types */ +#define NDEF_TNF_EMPTY 0U /*!< TNF Empty */ +#define NDEF_TNF_RTD_WELL_KNOWN_TYPE 1U /*!< TNF Well-known Type */ +#define NDEF_TNF_MEDIA_TYPE 2U /*!< TNF Media Type */ +#define NDEF_TNF_URI 3U /*!< TNF URI */ +#define NDEF_TNF_RTD_EXTERNAL_TYPE 4U /*!< TNF External Type */ +#define NDEF_TNF_UNKNOWN 5U /*!< TNF Unknown */ +#define NDEF_TNF_UNCHANGED 6U /*!< TNF Unchanged */ +#define NDEF_TNF_RESERVED 7U /*!< TNF Reserved */ + +#define NDEF_TNF_MASK 7U /*!< Type Name Format mask */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! Build the record header byte, made of MB, ME, CF, SR, IL bits and TNF type */ +#define ndefHeader(MB, ME, CF, SR, IL, TNF) ((((MB) & 1U) << 7U) | (((ME) & 1U) << 6U) | (((CF) & 1U) << 5U) | (((SR) & 1U) << 4U) | (((IL) & 1U) << 3U) | ((uint8_t)(TNF) & NDEF_TNF_MASK) ) /*< Build the record header byte, made of MB, ME, CF, SR, IL bits and TNF type */ + +/*! Read bits in header byte */ +#define ndefHeaderMB(record) ( ((record)->header & 0x80U) >> 7 ) /*!< Return the MB bit from the record header byte */ +#define ndefHeaderME(record) ( ((record)->header & 0x40U) >> 6 ) /*!< Return the ME bit from the record header byte */ +#define ndefHeaderCF(record) ( ((record)->header & 0x20U) >> 5 ) /*!< Return the CF bit from the record header byte */ +#define ndefHeaderSR(record) ( ((record)->header & 0x10U) >> 4 ) /*!< Return the SR bit from the record header byte */ +#define ndefHeaderIL(record) ( ((record)->header & 0x08U) >> 3 ) /*!< Return the IL bit from the record header byte */ +#define ndefHeaderTNF(record) ( (record)->header & NDEF_TNF_MASK ) /*!< Return the TNF type from the record header byte */ + +/*! Set bits in header byte */ +#define ndefHeaderSetMB(record) ( (record)->header |= (1U << 7) ) /*!< Set the MB bit in the record header byte */ +#define ndefHeaderSetME(record) ( (record)->header |= (1U << 6) ) /*!< Set the ME bit in the record header byte */ +#define ndefHeaderSetCF(record) ( (record)->header |= (1U << 5) ) /*!< Set the CF bit in the record header byte */ +#define ndefHeaderSetSR(record) ( (record)->header |= (1U << 4) ) /*!< Set the SR bit in the record header byte */ +#define ndefHeaderSetIL(record) ( (record)->header |= (1U << 3) ) /*!< Set the IL bit in the record header byte */ +#define ndefHeaderSetTNF(record, value) ( (record)->header |= (uint8_t)(value) & NDEF_TNF_MASK ) /*!< Set the TNF type in the record header byte */ + +/*! Clear bits in header byte */ +#define ndefHeaderClearMB(record) ( (record)->header &= 0x7FU ) /*!< Clear the MB bit in the record header byte */ +#define ndefHeaderClearME(record) ( (record)->header &= 0xBFU ) /*!< Clear the ME bit in the record header byte */ +#define ndefHeaderClearCF(record) ( (record)->header &= 0xDFU ) /*!< Clear the CF bit in the record header byte */ +#define ndefHeaderClearSR(record) ( (record)->header &= 0xEFU ) /*!< Clear the SR bit in the record header byte */ +#define ndefHeaderClearIL(record) ( (record)->header &= 0xF7U ) /*!< Clear the IL bit in the record header byte */ +#define ndefHeaderClearTNF(record, value) ( (record)->header &= 0xF8U ) /*!< Clear the TNF type in the record header byte */ + +/*! Set or Clear the MB/ME bit in header byte */ +#define ndefHeaderSetValueMB(record, value) do{ (record)->header &= 0x7FU; (record)->header |= (((uint8_t)(value)) & 1U) << 7; }while(0) /*!< Write the value to the MB bit in the record header byte */ +#define ndefHeaderSetValueME(record, value) do{ (record)->header &= 0xBFU; (record)->header |= (((uint8_t)(value)) & 1U) << 6; }while(0) /*!< Write the value to the ME bit in the record header byte */ +#define ndefHeaderSetValueSR(record, value) do{ (record)->header &= 0xEFU; (record)->header |= (((uint8_t)(value)) & 1U) << 4; }while(0) /*!< Write the value to the SR bit in the record header byte */ + +/*! Test bit in header byte */ +#define ndefHeaderIsSetMB(record) ( ndefHeaderMB(record) == 1U ) /*!< Return true if the Message Begin bit is set */ +#define ndefHeaderIsSetSR(record) ( ndefHeaderSR(record) == 1U ) /*!< Return true if the Short Record bit is set */ +#define ndefHeaderIsSetIL(record) ( ndefHeaderIL(record) == 1U ) /*!< Return true if the Id Length bit is set */ + + +typedef struct ndefTypeStruct ndefType; /*!< Forward declaration */ +typedef struct ndefMessageStruct ndefMessage; /*!< Forward declaration */ + +/*! Record type */ +typedef struct ndefRecordStruct +{ + uint8_t header; /*!< Header byte made of MB:1 ME:1 CF:1 SR:1 IL:1 TNF:3 => 8 bits */ + uint8_t typeLength; /*!< Type length in bytes */ + uint8_t idLength; /*!< Id Length, presence depends on the IL bit */ + const uint8_t* type; /*!< Type follows the structure implied by the value of the TNF field */ + const uint8_t* id; /*!< Id (middle and terminating record chunks MUST NOT have an ID field) */ + ndefConstBuffer bufPayload; /*!< Payload buffer. Payload length depends on the SR bit (either coded on 1 or 4 bytes) */ + + const ndefType* ndeftype; /*!< Well-known type data */ + + struct ndefRecordStruct* next; /*!< Pointer to the next record, if any */ +} ndefRecord; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/*! + ***************************************************************************** + * Reset an NDEF record + * + * This function clears every record field + * + * \param[in,out] record to reset + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordReset(ndefRecord* record); + + +/*! + ***************************************************************************** + * Initialize an NDEF record + * + * This function initializes all record fields + * + * \param[in,out] record: Record to initialize + * \param[in] tnf: TNF type + * \param[in] bufType: Type buffer + * \param[in] bufId: Id buffer + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordInit(ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType, const ndefConstBuffer8* bufId, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Get NDEF record header length + * + * Return the length of header for the given record + * + * \param[in] record + * + * \return header length in bytes + ***************************************************************************** + */ +uint32_t ndefRecordGetHeaderLength(const ndefRecord* record); + + +/*! + ***************************************************************************** + * Get NDEF record length + * + * Return the length of the given record, needed to store it as a raw buffer. + * It includes the header length. + * + * \param[in] record + * + * \return record length in bytes + ***************************************************************************** + */ +uint32_t ndefRecordGetLength(const ndefRecord* record); + + +/*! + ***************************************************************************** + * Set NDEF record type + * + * Set the type for the given record + * + * \param[in,out] record: Record to set the type + * \param[in] tnf: TNF type + * \param[in] bufType: Type buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordSetType(ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType); + + +/*! + ***************************************************************************** + * Get NDEF record type + * + * Return the type for the given record + * + * \param[in] record: Record to get the type from + * \param[out] tnf: Pointer to the TNF type + * \param[out] bufType: Type string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordGetType(const ndefRecord* record, uint8_t* tnf, ndefConstBuffer8* bufType); + + +/*! + ***************************************************************************** + * Check the record type matches a given type + * + * \param[in] record: Record to get the type from + * \param[out] tnf: the TNF type to compare with + * \param[out] bufType: Type string buffer to compare with + * + * \return true or false + ***************************************************************************** + */ +bool ndefRecordTypeMatch(const ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType); + + +/*! + ***************************************************************************** + * Set NDEF record Id + * + * Set the Id for the given NDEF record + * + * \param[in] record: Record to set the Id + * \param[out] bufId: Id buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordSetId(ndefRecord* record, const ndefConstBuffer8* bufId); + + +/*! + ***************************************************************************** + * Get NDEF record Id + * + * Return the Id for the given NDEF record + * + * \param[in] record: Record to get the Id from + * \param[out] bufId: Id buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordGetId(const ndefRecord* record, ndefConstBuffer8* bufId); + + +/*! + ***************************************************************************** + * Set NDEF record payload + * + * Set the payload for the given record, update the SR bit accordingly + * + * \param[in,out] record: Record to set the payload + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordSetPayload(ndefRecord* record, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Get NDEF record payload + * + * Return the payload for the given record + * + * \param[in] record: Record to get the payload from + * \param[out] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordGetPayload(const ndefRecord* record, ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Decode a raw buffer to create an NDEF record + * + * Convert a raw buffer to a record + * + * \param[in] bufPayload: Payload buffer to convert into record + * \param[out] record: Record created from the raw buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordDecode(const ndefConstBuffer* bufPayload, ndefRecord* record); + + +#if NDEF_FEATURE_FULL_API +/*! + ***************************************************************************** + * Encode an NDEF record header to a raw buffer + * + * Convert a record header to a raw buffer. It is made of: + * "header byte" (1 byte), type length (1 byte), + * payload length (4 bytes), Id length (1 byte). + * Total 7 bytes. + * + * \param[in] record: Record header to convert + * \param[in,out] bufHeader: Output buffer to store the converted record header + * The input length provides the output buffer allocated + * length, used for parameter check to avoid overflow. + * In case the buffer provided is too short, it is + * updated with the required buffer length. + * On success, it is updated with the actual buffer + * length used to contain the converted record. + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordEncodeHeader(const ndefRecord* record, ndefBuffer* bufHeader); + + +/*! + ***************************************************************************** + * Encode an NDEF record to a raw buffer + * + * Convert a record to a raw buffer + * + * \param[in] record: Record to convert + * \param[in,out] bufRecord: Output buffer to store the converted record + * The input length provides the output buffer allocated + * length, used for parameter check to avoid overflow. + * In case the buffer provided is too short, it is + * updated with the required buffer length. + * On success, it is updated with the actual buffer + * length used to contain the converted record. + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordEncode(const ndefRecord* record, ndefBuffer* bufRecord); +#endif + + +/*! + ***************************************************************************** + * Get NDEF record payload length + * + * Return the length of payload for the given record + * + * \param[in] record + * + * \return payload length in bytes + ***************************************************************************** + */ +uint32_t ndefRecordGetPayloadLength(const ndefRecord* record); + + +/*! + ***************************************************************************** + * Return a payload elementary item needed to build the complete record payload + * + * Call this function to get either the first payload item, or the next one. + * Returns the next payload item, call it until it returns NULL. + * + * \param[in] record: Record + * \param[out] bufPayloadItem: The payload item returned + * \param[in] begin: Tell to return the first payload item or the next one + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +const uint8_t* ndefRecordGetPayloadItem(const ndefRecord* record, ndefConstBuffer* bufPayloadItem, bool begin); + + +#endif /* NDEF_RECORD_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_aar.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_aar.h new file mode 100644 index 0000000..03a1d92 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_aar.h @@ -0,0 +1,143 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Android Application Record (AAR) type header file + * + * NDEF RTD provides functionalities to handle RTD AAR records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_AAR_H +#define NDEF_TYPE_AAR_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! RTD Record Type buffers */ +extern const ndefConstBuffer8 bufRtdTypeAar; /*! AAR (Android Application Record) Record Type buffer */ + + +/*! RTD Android Application Record External Type */ +typedef struct +{ + ndefConstBuffer8 bufType; /*!< AAR type */ + ndefConstBuffer bufPayload; /*!< AAR payload */ +} ndefTypeRtdAar; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/******************* + * AAR External Type + ******************* + */ + +/*! + ***************************************************************************** + * Initialize an RTD Android Application Record External type + * + * \param[out] aar: Type to initialize + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdAarInit(ndefType* aar, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Get RTD Android Application Record type content + * + * \param[in] aar: Type to get information from + * \param[out] bufAarString: AAR string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdAar(const ndefType* aar, ndefConstBuffer* bufAarString); + + +/*! + ***************************************************************************** + * Convert an NDEF record to an RTD Android Application Record External type + * + * \param[in] record: Record to convert + * \param[out] aar: The converted AAR external type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdAar(const ndefRecord* record, ndefType* aar); + + +/*! + ***************************************************************************** + * Convert an RTD Android Application Record External type to an NDEF record + * + * \param[in] aar: AAR External type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdAarToRecord(const ndefType* aar, ndefRecord* record); + + +#endif /* NDEF_TYPE_AAR_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_bluetooth.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_bluetooth.h new file mode 100644 index 0000000..6e57077 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_bluetooth.h @@ -0,0 +1,425 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Bluetooth type header file + * + * It provides functionalities to handle Bluetooth Out-Of-Band NDEF records, + * to start a communication based on Bluetooth. + * + * The Bluetooth OOB format is described by the Bluetooth v4.0 core specification. + * It consists in a list of Extended Inquiry Responses (EIRs) formated as length-type-value. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_BLUETOOTH_H +#define NDEF_TYPE_BLUETOOTH_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_BT_EIR_DEVICE_ADDRESS_TYPE_OFFSET 6U /*!< Device Address Type (Public, Random) offset */ + + +/*!< Number of EIRs that can be decoded simultaneously + Allow to control the number of allocated memory space to store decoded EIRs + Should be lower or equal to the number of known EIRs (currently 26) +*/ +#define NDEF_BT_EIR_COUNT 8U /*!< Number of EIRs that can be decoded */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! Bluetooth LE address types */ +typedef enum +{ + NDEF_BLE_PUBLIC_ADDRESS_TYPE = 0x0U, /*!< Public Device Address */ + NDEF_BLE_RANDOM_ADDRESS_TYPE = 0x1U, /*!< Random Device Address */ + NDEF_BLE_UNDEF_ADDRESS_TYPE = 0xFFU /*!< Device Address is undefined */ +} ndefBluetoothLEAddressType; + + +/*! Bluetooth LE roles */ +typedef enum +{ + NDEF_BLE_ROLE_PERIPH_ONLY = 0x0U, /*!< Only Peripheral Role supported */ + NDEF_BLE_ROLE_CENTRAL_ONLY = 0x1U, /*!< Only Central Role supported */ + NDEF_BLE_ROLE_PERIPH_PREFERRED = 0x2U, /*!< Peripheral and Central Role supported, Peripheral Role preferred for connection establishment */ + NDEF_BLE_ROLE_CENTRAL_PREFERRED = 0x3U, /*!< Peripheral and Central Role supported, Central Role preferred for connection establishment */ + NDEF_BLE_ROLE_UNDEF = 0xFFU /*!< LE Role is undefined */ +} ndefBluetoothLERole; + + +/*! Extended Inquiry Responses, as defined in the Bluetooth v4.0 Core Specification */ +#define NDEF_BT_EIR_FLAGS 0x01U /*!< Bluetooth flags:\n + b0: LE limited Discoverable Mode, + b1: LE general Discoverable Mode, + b2: BR/EDR not supported, + b3: Simultaneous LE & BR/EDR Conroller, + b4: Simultaneous LE & BR/EDR Host */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_16 0x02U /*!< Bluetooth service UUID on 16-bits (partial list) */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_16 0x03U /*!< Bluetooth service UUID on 16-bits (complete list) */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_32 0x04U /*!< Bluetooth service UUID on 32-bits (partial list) */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_32 0x05U /*!< Bluetooth service UUID on 32-bits (complete list) */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_128 0x06U /*!< Bluetooth service UUID on 128-bits (partial list) */ +#define NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_128 0x07U /*!< Bluetooth service UUID on 128-bits (complete list) */ +#define NDEF_BT_EIR_SHORT_LOCAL_NAME 0x08U /*!< Shortened local name */ +#define NDEF_BT_EIR_COMPLETE_LOCAL_NAME 0x09U /*!< Complete local name */ +#define NDEF_BT_EIR_TX_POWER_LEVEL 0x0AU /*!< TX Power Level (1 byte): 0xXX:-127 to +127dBm */ +#define NDEF_BT_EIR_DEVICE_CLASS 0x0DU /*!< Class of device, Format defined in Assigned Numbers */ +#define NDEF_BT_EIR_SIMPLE_PAIRING_HASH 0x0EU /*!< Simple Pairing Hash C (16 octets), Format defined in [Vol. 2], Part H Section 7.2.2 */ +#define NDEF_BT_EIR_SIMPLE_PAIRING_RANDOMIZER 0x0FU /*!< Simple Pairing Randomizer R (16 octets), Format defined in[Vol. 2], Part H Section 7.2.2 */ +#define NDEF_BT_EIR_SECURITY_MANAGER_TK_VALUE 0x10U /*!< TK Value: Value as used in pairing over LE Physical channel. Format defined in [Vol. 3], Part H Section 2.3 */ +#define NDEF_BT_EIR_SECURITY_MANAGER_FLAGS 0x11U /*!< Flags (1 octet):\n + b0: OOB Flags Field (0 = OOB data not present, 1 = OOB data present), + b1: LE supported (Host) (i.e. bit 65 of LMP Extended Feature bits Page 1), + b2: Simultaneous LE and BR/EDR to Same Device Capable (Host) (i.e. bit 66 of LMP Extended Feature bits Page 1) + b3: Address type (0 = Public Address, 1 = Random Address) */ +#define NDEF_BT_EIR_SLAVE_CONNECTION_INTERVAL_RANGE 0x12U /*!< Slave Connection Interval Range: The first 2 octets define the minimum value for the connection interval, The second 2 octets define the maximum value for the connection interval */ +#define NDEF_BT_EIR_SERVICE_SOLICITATION_16 0x14U /*!< Service UUIDs: List of 16 bit Service UUIDs */ +#define NDEF_BT_EIR_SERVICE_SOLICITATION_128 0x15U /*!< Service UUIDs: List of 128 bit Service UUIDs */ +#define NDEF_BT_EIR_SERVICE_DATA 0x16U /*!< Service Data (2 or more octets): The first 2 octets contain the 16 bit Service UUID followed by additional service data */ +#define NDEF_BT_EIR_APPEARANCE 0x19U /*!< UUID for `Appearance`: The Appearance characteristic value shall be the enumerated value as defined by Bluetooth Assigned Numbers document */ +#define NDEF_BT_EIR_LE_DEVICE_ADDRESS 0x1BU /*!< 6 LSB bytes: Device address, 7th byte: Address type (Public/Random) */ +#define NDEF_BT_EIR_LE_ROLE 0x1CU /*!< Device Role: Periph only, Central only, Periph prefered, Central prefered */ +#define NDEF_BT_EIR_LE_SECURE_CONN_CONFIRMATION_VALUE 0x22U /*!< Secure Connection Confirmation value */ +#define NDEF_BT_EIR_LE_SECURE_CONN_RANDOM_VALUE 0x23U /*!< Secure Connection Random value */ +#define NDEF_BT_EIR_MANUFACTURER_DATA 0xFFU /*!< Manufacturer Specific Data (2 or more octets): The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data */ + + +/*! Bluetooth Out-Of-Band data structure + * Some fields are shared by both Br/Edr & LE Bluetooth, some are specific. + */ +typedef struct +{ + /* Mandatory fields: + bufDeviceAddress + Optional common fields: + NDEF_BT_EIR_FLAGS + NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_16 + NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_16 + NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_32 + NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_32 + NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_128 + NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_128 + NDEF_BT_EIR_SHORT_LOCAL_NAME + NDEF_BT_EIR_COMPLETE_LOCAL_NAME + NDEF_BT_EIR_TX_POWER_LEVEL + NDEF_BT_EIR_DEVICE_CLASS + NDEF_BT_EIR_SECURITY_MANAGER_FLAGS + NDEF_BT_EIR_SLAVE_CONNECTION_INTERVAL_RANGE + NDEF_BT_EIR_SERVICE_SOLICITATION_16 + NDEF_BT_EIR_SERVICE_SOLICITATION_128 + NDEF_BT_EIR_SERVICE_DATA + For Br/Edr only: + NDEF_BT_EIR_SIMPLE_PAIRING_HASH + NDEF_BT_EIR_SIMPLE_PAIRING_RANDOMIZER + BLE mandatory fields: + NDEF_BT_EIR_LE_ROLE + BLE optional fields: + NDEF_BT_EIR_LE_SECURE_CONN_CONFIRMATION_VALUE + NDEF_BT_EIR_LE_SECURE_CONN_RANDOM_VALUE + NDEF_BT_EIR_SECURITY_MANAGER_TK_VALUE + NDEF_BT_EIR_APPEARANCE + NDEF_BT_EIR_MANUFACTURER_DATA */ + + ndefConstBuffer bufDeviceAddress; /*!< Device address, for BR/EDR only */ + + const uint8_t* eir[NDEF_BT_EIR_COUNT]; /*!< Array containg pointer to each EIR */ + +} ndefTypeBluetooth; + + +/*! Bluetooth Record Type buffers */ +extern const ndefConstBuffer8 bufMediaTypeBluetoothBrEdr; /*! Bluetooth BR/EDR Out-Of-Band Record Type buffer */ +extern const ndefConstBuffer8 bufMediaTypeBluetoothLe; /*! Bluetooth Low Energy Record Type buffer */ +extern const ndefConstBuffer8 bufMediaTypeBluetoothSecureBrEdr; /*! Bluetooth Secure BR/EDR Record Type buffer */ +extern const ndefConstBuffer8 bufMediaTypeBluetoothSecureLe; /*! Bluetooth Secure Low Energy Record Type buffer */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * Bluetooth + *************** + */ + + +/*! + ***************************************************************************** + * Get Bluetooth EIR length + * + * \param[in] eir: Extended Inquiry Response + * + * \return the length of the EIR passed as parameter + ***************************************************************************** + */ +uint8_t ndefBluetoothEirLength(const uint8_t* eir); + + +/*! + ***************************************************************************** + * Get Bluetooth EIR data length + * + * \param[in] eir: Extended Inquiry Response + * + * \return the length of the data contained in the EIR passed as parameter + ***************************************************************************** + */ +uint8_t ndefBluetoothEirDataLength(const uint8_t* eir); + + +/*! + ***************************************************************************** + * Get Bluetooth EIR type + * + * \param[in] eir: Extended Inquiry Response + * + * \return the type of the EIR passed as parameter + ***************************************************************************** + */ +uint8_t ndefBluetoothEirType(const uint8_t* eir); + +/*! + ***************************************************************************** + * Get a pointer to a Bluetooth EIR data + * + * \param[in] eir: Extended Inquiry Response + * + * \return a pointer to the data of the EIR passed as parameter + ***************************************************************************** + */ +const uint8_t* ndefBluetoothEirData(const uint8_t* eir); + + +/*! + ***************************************************************************** + * Convert a Bluetooth EIR to an ndefBuffer structure + * + * \param[in] eir: Extended Inquiry Response + * \param[in,out] bufEir: pointer to the Extended Inquiry Response data + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothEirDataToBuffer(const uint8_t* eir, ndefConstBuffer* bufEir); + + +/*! + ***************************************************************************** + * Add a Bluetooth EIR to the bluetooth type + * + * \param[in] bluetooth: Bluetooth type + * \param[in] eir: EIR type to add + * + * Add eir after any EIR already listed in the bluetooth type, + * or replace in case an EIR with matching type is already there. + * + * \return ERR_NONE if successful, ERR_NOMEM or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothSetEir(ndefTypeBluetooth* bluetooth, const uint8_t* eir); + + +/*! + ***************************************************************************** + * Get a pointer to a Bluetooth EIR + * + * \param[in] bluetooth: Bluetooth type + * \param[in] eirType: EIR type to find + * + * \return a pointer to the EIR matching the type, or NULL + ***************************************************************************** + */ +const uint8_t* ndefBluetoothGetEir(const ndefTypeBluetooth* bluetooth, uint8_t eirType); + + +/*! + ***************************************************************************** + * Return an EIR content + * + * \param[in] bluetooth: Bluetooth type + * \param[in] eirType: EIR type to retrieve + * \param[out] bufData: NDEF buffer pointing to the EIR data + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothGetEirData(const ndefTypeBluetooth* bluetooth, uint8_t eirType, ndefConstBuffer* bufData); + + +/*! + ***************************************************************************** + * Copy an EIR content with bytes in reversed order in the ndefBuffer + * + * \param[in] bluetooth: Bluetooth type + * \param[in] eirType: EIR type to retrieve + * \param[out] bufDataReversed: NDEF buffer to store the reversed EIR + * + * In case the NDEF buffer is not long enough, its length is updated with + * the actual length required and the function returns ERR_NOMEM. + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothGetEirDataReversed(const ndefTypeBluetooth* bluetooth, uint8_t eirType, ndefBuffer* bufDataReversed); + + +/*! + ***************************************************************************** + * Reset a Bluetooth type + * + * \param[in] bluetooth: Bluetooth type + * + * This function resets each field of the ndefTypeBluetooth structure + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothReset(ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Initialize a Bluetooth Basic Rate/Enhanced Data Rate type + * + * \param[out] type: Type to initialize + * \param[in] bluetooth: Bluetooth type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothBrEdrInit(ndefType* type, const ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Initialize a Bluetooth Low Energy type + * + * \param[out] type: Type to initialize + * \param[in] bluetooth: Bluetooth type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothLeInit(ndefType* type, const ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Initialize a Bluetooth Secure BR/EDR type + * + * \param[out] type: Type to initialize + * \param[in] bluetooth: Bluetooth type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothSecureBrEdrInit(ndefType* type, const ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Initialize a Bluetooth Secure Low Energy type + * + * \param[out] type: Type to initialize + * \param[in] bluetooth: Bluetooth type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothSecureLeInit(ndefType* type, const ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Get Bluetooth type content + * + * \param[in] type: Type to get information from + * \param[out] bluetooth: Bluetooth type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetBluetooth(const ndefType* type, ndefTypeBluetooth* bluetooth); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a Bluetooth type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToBluetooth(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a Bluetooth type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefBluetoothToRecord(const ndefType* type, ndefRecord* record); + + +#endif /* NDEF_TYPE_BLUETOOTH_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_deviceinfo.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_deviceinfo.h new file mode 100644 index 0000000..82f8de3 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_deviceinfo.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Device Information type header file + * + * NDEF RTD provides functionalities to handle RTD Device Information records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_RTD_DEVICE_INFO_H +#define NDEF_TYPE_RTD_DEVICE_INFO_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! Device Information defines */ +#define NDEF_UUID_LENGTH 16U /*!< Device Information UUID length */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! RTD Device Information Record Type buffer */ +extern const ndefConstBuffer8 bufRtdTypeDeviceInfo; /*! Device Information Record Type buffer */ + + +/*! RTD Device Information types */ +#define NDEF_DEVICE_INFO_MANUFACTURER_NAME 0U /*!< Manufacturer name */ +#define NDEF_DEVICE_INFO_MODEL_NAME 1U /*!< Model name */ +#define NDEF_DEVICE_INFO_DEVICE_UNIQUE_NAME 2U /*!< Device Unique Name aka "Friendly Name" */ +#define NDEF_DEVICE_INFO_UUID 3U /*!< UUID */ +#define NDEF_DEVICE_INFO_FIRMWARE_VERSION 4U /*!< Firmware Version */ +#define NDEF_DEVICE_INFO_TYPE_COUNT 5U /*!< Maximum Device Information types */ + + +/*! RTD Device Information Entry */ +typedef struct +{ + uint8_t type; /*!< Device Information Type */ + uint8_t length; /*!< Device Information length */ + const uint8_t* buffer; /*!< Device Information pointer to buffer */ +} ndefDeviceInfoEntry; + + +/*! RTD Type Device Information */ +typedef struct +{ + ndefDeviceInfoEntry devInfo[NDEF_DEVICE_INFO_TYPE_COUNT]; /*!< Device Information entries */ +} ndefTypeRtdDeviceInfo; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/********************* + * Device Information + ********************* + */ + + +/*! + ***************************************************************************** + * Initialize a RTD Device Information type + * + * \param[out] devInfo: Type to initialize + * \param[in] devInfoData: Device Information data + * \param[in] devInfoDataCount: Number of Device Information data + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdDeviceInfoInit(ndefType* devInfo, const ndefDeviceInfoEntry* devInfoData, uint8_t devInfoDataCount); + + +/*! + ***************************************************************************** + * Get RTD Device Information type content + * + * \param[in] devInfo: Type to get information from + * \param[out] devInfoData: Device Information data + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdDeviceInfo(const ndefType* devInfo, ndefTypeRtdDeviceInfo* devInfoData); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a Device Information RTD type + * + * \param[in] record: Record to convert + * \param[out] devInfo: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdDeviceInfo(const ndefRecord* record, ndefType* devInfo); + + +/*! + ***************************************************************************** + * Convert a Device Information RTD type to an NDEF record + * + * \param[in] devInfo: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdDeviceInfoToRecord(const ndefType* devInfo, ndefRecord* record); + + +#endif /* NDEF_TYPE_RTD_DEVICE_INFO_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_empty.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_empty.h new file mode 100644 index 0000000..237a5db --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_empty.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Empty type header file + * + * NDEF RTD provides functionalities to handle empty records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_EMPTY_H +#define NDEF_TYPE_EMPTY_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * Empty type + *************** + */ + +/*! + ***************************************************************************** + * Initialize an Empty type + * + * \param[out] empty: Type to initialize + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefEmptyTypeInit(ndefType* empty); + + +/*! + ***************************************************************************** + * Convert an NDEF record to an Empty type + * + * \param[in] record: Record to convert + * \param[out] empty: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToEmptyType(const ndefRecord* record, ndefType* empty); + + +/*! + ***************************************************************************** + * Convert an Empty type to an NDEF record + * + * \param[in] empty: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefEmptyTypeToRecord(const ndefType* empty, ndefRecord* record); + + +#endif /* NDEF_TYPE_EMPTY_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_flat.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_flat.h new file mode 100644 index 0000000..1e0ca73 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_flat.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Flat payload type header file + * + * NDEF RTD provides functionalities to handle flat payload records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_FLAT_H +#define NDEF_TYPE_FLAT_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * Flat type + *************** + */ + +/*! + ***************************************************************************** + * Initialize a flat payload type + * + * \param[out] type: Type to initialize + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefFlatPayloadTypeInit(ndefType* type, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Initialize a flat payload type + * + * \param[out] type: Type to get data from + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetFlatPayloadType(const ndefType* type, ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a flat payload type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToFlatPayloadType(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a flat payload type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefFlatPayloadTypeToRecord(const ndefType* type, ndefRecord* record); + + +#endif /* NDEF_TYPE_FLAT_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_media.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_media.h new file mode 100644 index 0000000..1f86fc1 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_media.h @@ -0,0 +1,142 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF MIME Media type header file + * + * NDEF MIME type provides functionalities to handle generic MIME Media records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_MEDIA_H +#define NDEF_TYPE_MEDIA_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! Media Type */ +typedef struct +{ + ndefConstBuffer8 bufType; /*!< Media type */ + ndefConstBuffer bufPayload; /*!< Media payload */ +} ndefTypeMedia; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * Media + *************** + */ + +/*! + ***************************************************************************** + * Initialize a Media type + * + * \param[out] media: Media type to initialize + * \param[in] bufType: Type buffer + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMediaInit(ndefType* media, const ndefConstBuffer8* bufType, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Get Media type content + * + * \param[in] media: Media type to get information from + * \param[out] bufType: Type buffer + * \param[out] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetMedia(const ndefType* media, ndefConstBuffer8* bufType, ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a Media type + * + * \param[in] record: Record to convert + * \param[out] media: The converted Media type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToMedia(const ndefRecord* record, ndefType* media); + + +/*! + ***************************************************************************** + * Convert a Media type to an NDEF record + * + * \param[in] media: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefMediaToRecord(const ndefType* media, ndefRecord* record); + + +#endif /* NDEF_TYPE_MEDIA_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_text.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_text.h new file mode 100644 index 0000000..814e796 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_text.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Text type header file + * + * NDEF RTD provides functionalities to handle RTD Text records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_RTD_TEXT_H +#define NDEF_TYPE_RTD_TEXT_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! RTD Text Record Type buffer */ +extern const ndefConstBuffer8 bufRtdTypeText; /*! Text Record Type buffer */ + + +/*! RTD Type Text Encoding */ +#define TEXT_ENCODING_UTF8 0U /*!< UTF8 text encoding */ +#define TEXT_ENCODING_UTF16 1U /*!< UTF16 text encoding */ + +#define NDEF_TEXT_ENCODING_MASK 0x80U /*!< Text encoding mask */ +#define NDEF_TEXT_ENCODING_SHIFT 7U /*!< Text encoding bit shift */ + + +/*! RTD Type Text */ +typedef struct +{ + uint8_t status; /*!< Status byte */ + ndefConstBuffer8 bufLanguageCode; /*!< ISO/IANA language code buffer */ + ndefConstBuffer bufSentence; /*!< Sentence buffer */ +} ndefTypeRtdText; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * Text + *************** + */ + + +/*! + ***************************************************************************** + * Initialize a Text RTD type + * + * \param[out] text: Type to initialize + * \param[out] utfEncoding: UTF-8/UTF-16 + * \param[in] bufLanguageCode: ISO/IANA language code buffer + * \param[in] bufSentence: Actual text buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTextInit(ndefType* text, uint8_t utfEncoding, const ndefConstBuffer8* bufLanguageCode, const ndefConstBuffer* bufSentence); + + +/*! + ***************************************************************************** + * Get RTD Text type content + * + * \param[in] text: Type to get information from + * \param[out] utfEncoding: UTF-8/UTF-16 + * \param[out] bufLanguageCode: ISO/IANA language code buffer + * \param[out] bufSentence: Actual text buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdText(const ndefType* text, uint8_t* utfEncoding, ndefConstBuffer8* bufLanguageCode, ndefConstBuffer* bufSentence); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a Text type + * + * \param[in] record: Record to convert + * \param[out] text: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdText(const ndefRecord* record, ndefType* text); + + +/*! + ***************************************************************************** + * Convert a Text RTD type to an NDEF record + * + * \param[in] text: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTextToRecord(const ndefType* text, ndefRecord* record); + + +#endif /* NDEF_TYPE_RTD_TEXT_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_tnep.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_tnep.h new file mode 100644 index 0000000..b49f6c1 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_tnep.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF TNEP (Tag NDEF Exchange Protocol record) types header file + * + * NDEF TNEP provides functionalities to handle TNEP records: Service Parameter, Service Select and Status. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPES_TNEP_H +#define NDEF_TYPES_TNEP_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! RTD TNEP defines */ +#define TNEP_VERSION_V1_0 0x10U /*!< TNEP version */ +#define TNEP_COMMUNICATION_MODE_SINGLE_RESPONSE 0x00U /*!< Single Response Communication mode */ +#define TNEP_COMMUNICATION_MODE_SPECIFIC 0xFEU /*!< Specific Communication mode */ +#define TNEP_STATUS_TYPE_SUCCESS 0U /*!< Status type Success */ +#define TNEP_STATUS_TYPE_PROTOCOL_ERROR 1U /*!< Status type Protocol Error */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! RTD TNEP Service Parameter */ +typedef struct +{ + ndefConstBuffer bufServiceNameUri; /*!< Service Name URI string buffer */ + uint8_t tnepVersion; /*!< TNEP version */ + uint8_t communicationMode; /*!< TNEP communication mode */ + uint8_t minimumWaitingTime; /*!< Minimum Waiting Time WT_INT */ + uint8_t maximumWaitingTimeExtensions; /*!< Maximum number of waiting time extensions */ + uint8_t maximumNdefMessageSize[2]; /*!< Maximum NDEF message size (Big Endian) */ +} ndefTypeRtdTnepServiceParameter; + + +/*! RTD TNEP Service Select */ +typedef struct +{ + ndefConstBuffer bufServiceNameUri; /*!< Service Name URI string buffer */ +} ndefTypeRtdTnepServiceSelect; + + +/*! RTD TNEP Status */ +typedef struct +{ + uint8_t statusType; /*!< Status type */ +} ndefTypeRtdTnepStatus; + + +/*! RTD TNEP Record Type buffers */ +extern const ndefConstBuffer8 bufRtdTypeTnepServiceParameter; /*! TNEP Service Parameter buffer */ +extern const ndefConstBuffer8 bufRtdTypeTnepServiceSelect; /*! TNEP Service Select buffer */ +extern const ndefConstBuffer8 bufRtdTypeTnepStatus; /*! TNEP Status buffer */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/************************* + * TNEP Service Parameter + ************************* + */ + + +/*! + ***************************************************************************** + * Computes the TNEP Service Parameter WT_INT from the Twait value (in ms) + * + * \param[in] twait: minimum waiting time between last TNEP write and next TNEP read + * + * \return WT_INT value corresponding to the Twait + ***************************************************************************** + */ +uint8_t ndefRtdTnepServiceParameterComputeWtInt(float twait); + + +/*! + ***************************************************************************** + * Computes the TNEP Service Parameter Twait (in ms) from the WT_INT value + * + * \param[in] wtInt: NDEF Record field WT_INT defining the Twait + * + * \return Twait minimum waiting time between last TNEP write and next TNEP read + ***************************************************************************** + */ +float ndefRtdTnepServiceParameterComputeTwait(uint8_t wtInt); + + +/*! + ***************************************************************************** + * Initialize a TNEP Service Parameter RTD type + * + * \param[out] type: Type to initialize + * \param[in] tnepVersion: TNEP version + * \param[in] bufServiceUri: TNEP Service Name URI string buffer + * \param[in] comMode: TNEP Communication Mode + * \param[in] minWaitingTime: Minimum Waiting Time + * \param[in] maxExtensions: Maximum Waiting Time Extensions + * \param[in] maxMessageSize: Maximum NDEF Message Size (in bytes) + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepServiceParameterInit(ndefType* type, uint8_t tnepVersion, const ndefConstBuffer* bufServiceUri, uint8_t comMode, uint8_t minWaitingTime, uint8_t maxExtensions, uint16_t maxMessageSize); + + +/*! + ***************************************************************************** + * Get TNEP Service Parameter RTD type content + * + * \param[in] type: Type to get information from + * \param[out] tnepVersion: TNEP version + * \param[out] bufServiceUri: TNEP Service Name URI string buffer + * \param[out] comMode: TNEP Communication Mode + * \param[out] minWaitingTime: Minimum Waiting Time + * \param[out] maxExtensions: Maximum Waiting Time Extensions + * \param[out] maxMessageSize: Maximum NDEF Message Size (in bytes) + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdTnepServiceParameter(const ndefType* type, uint8_t* tnepVersion, ndefConstBuffer* bufServiceUri, uint8_t* comMode, uint8_t* minWaitingTime, uint8_t* maxExtensions, uint16_t* maxMessageSize); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a TNEP Service Parameter RTD type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdTnepServiceParameter(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a TNEP Service Parameter RTD type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepServiceParameterToRecord(const ndefType* type, ndefRecord* record); + + +/********************** + * TNEP Service Select + ********************** + */ + + +/*! + ***************************************************************************** + * Initialize a TNEP Service Select RTD type + * + * \param[out] type: Type to initialize + * \param[in] bufServiceUri: TNEP Service Name URI string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepServiceSelectInit(ndefType* type, const ndefConstBuffer* bufServiceUri); + + +/*! + ***************************************************************************** + * Get TNEP Service Select RTD type content + * + * \param[in] type: Type to get information from + * \param[out] bufServiceUri: TNEP Service Name URI string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdTnepServiceSelect(const ndefType* type, ndefConstBuffer* bufServiceUri); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a TNEP Service Select RTD type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdTnepServiceSelect(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a TNEP Service Select RTD type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepServiceSelectToRecord(const ndefType* type, ndefRecord* record); + + +/*************** + * TNEP Status + *************** + */ + + +/*! + ***************************************************************************** + * Initialize a TNEP Status RTD type + * + * \param[out] type: Type to initialize + * \param[in] statusType: TNEP status type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepStatusInit(ndefType* type, uint8_t statusType); + + +/*! + ***************************************************************************** + * Get TNEP Status RTD type content + * + * \param[in] type: Type to get information from + * \param[out] statusType: TNEP status type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdTnepStatus(const ndefType* type, uint8_t* statusType); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a TNEP Status RTD type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdTnepStatus(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a TNEP Status RTD type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdTnepStatusToRecord(const ndefType* type, ndefRecord* record); + + +#endif /* NDEF_TYPES_TNEP_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_uri.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_uri.h new file mode 100644 index 0000000..a261cad --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_uri.h @@ -0,0 +1,184 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD (well-known and external) types header file + * + * NDEF RTD provides functionalities to handle RTD records, such as Text or URI. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_URI_H +#define NDEF_TYPE_URI_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! RTD Type URI Protocols */ +#define NDEF_URI_PREFIX_NONE 0x00U /*!< No URI Protocol */ +#define NDEF_URI_PREFIX_HTTP_WWW 0x01U /*!< URI Protocol http://www. */ +#define NDEF_URI_PREFIX_HTTPS_WWW 0x02U /*!< URI Protocol https://www. */ +#define NDEF_URI_PREFIX_HTTP 0x03U /*!< URI Protocol http:// */ +#define NDEF_URI_PREFIX_HTTPS 0x04U /*!< URI Protocol https:// */ +#define NDEF_URI_PREFIX_TEL 0x05U /*!< URI Protocol tel: */ +#define NDEF_URI_PREFIX_MAILTO 0x06U /*!< URI Protocol mailto: */ +#define NDEF_URI_PREFIX_FTP_ANONYMOUS 0x07U /*!< URI Protocol ftp://anonymous@ */ +#define NDEF_URI_PREFIX_FTP_FTP 0x08U /*!< URI Protocol ftp://ftp. */ +#define NDEF_URI_PREFIX_FTPS 0x09U /*!< URI Protocol ftps:// */ +#define NDEF_URI_PREFIX_SFTP 0x0AU /*!< URI Protocol sftp:// */ +#define NDEF_URI_PREFIX_SMB 0x0BU /*!< URI Protocol smb:// */ +#define NDEF_URI_PREFIX_NFS 0x0CU /*!< URI Protocol nfs:// */ +#define NDEF_URI_PREFIX_FTP 0x0DU /*!< URI Protocol ftp:// */ +#define NDEF_URI_PREFIX_DAV 0x0EU /*!< URI Protocol dav:// */ +#define NDEF_URI_PREFIX_NEWS 0x0FU /*!< URI Protocol news: */ +#define NDEF_URI_PREFIX_TELNET 0x10U /*!< URI Protocol telnet:// */ +#define NDEF_URI_PREFIX_IMAP 0x11U /*!< URI Protocol imap: */ +#define NDEF_URI_PREFIX_RTSP 0x12U /*!< URI Protocol rtsp:// */ +#define NDEF_URI_PREFIX_URN 0x13U /*!< URI Protocol urn: */ +#define NDEF_URI_PREFIX_POP 0x14U /*!< URI Protocol pop: */ +#define NDEF_URI_PREFIX_SIP 0x15U /*!< URI Protocol sip: */ +#define NDEF_URI_PREFIX_SIPS 0x16U /*!< URI Protocol sips: */ +#define NDEF_URI_PREFIX_TFTP 0x17U /*!< URI Protocol tftp: */ +#define NDEF_URI_PREFIX_BTSPP 0x18U /*!< URI Protocol btspp:// */ +#define NDEF_URI_PREFIX_BTL2CAP 0x19U /*!< URI Protocol btl2cap:// */ +#define NDEF_URI_PREFIX_BTGOEP 0x1AU /*!< URI Protocol btgoep:// */ +#define NDEF_URI_PREFIX_TCPOBEX 0x1BU /*!< URI Protocol tcpobex:// */ +#define NDEF_URI_PREFIX_IRDAOBEX 0x1CU /*!< URI Protocol irdaobex:// */ +#define NDEF_URI_PREFIX_FILE 0x1DU /*!< URI Protocol file:// */ +#define NDEF_URI_PREFIX_URN_EPC_ID 0x1EU /*!< URI Protocol urn:epc:id: */ +#define NDEF_URI_PREFIX_URN_EPC_TAG 0x1FU /*!< URI Protocol urn:epc:tag */ +#define NDEF_URI_PREFIX_URN_EPC_PAT 0x20U /*!< URI Protocol urn:epc:pat: */ +#define NDEF_URI_PREFIX_URN_EPC_RAW 0x21U /*!< URI Protocol urn:epc:raw: */ +#define NDEF_URI_PREFIX_URN_EPC 0x22U /*!< URI Protocol urn:epc: */ +#define NDEF_URI_PREFIX_URN_NFC 0x23U /*!< URI Protocol urn:nfc: */ +#define NDEF_URI_PREFIX_AUTODETECT 0x24U /*!< ST Protocol Autodetect */ +#define NDEF_URI_PREFIX_COUNT 0x25U /*!< Number of URI protocols */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! RTD URI Record Type buffer */ +extern const ndefConstBuffer8 bufRtdTypeUri; /*! URI Record Type buffer */ + +/*! RTD Type URI */ +typedef struct +{ + uint8_t protocol; /*!< Protocol Idendifier */ + ndefConstBuffer bufUriString; /*!< URI string buffer */ +} ndefTypeRtdUri; + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************** + * URI + *************** + */ + +/*! + ***************************************************************************** + * Initialize a URI RTD type + * + * \param[out] uri: Type to initialize + * \param[in] protocol: URI protocol + * \param[in] bufUriString: URI string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdUriInit(ndefType* uri, uint8_t protocol, const ndefConstBuffer* bufUriString); + + +/*! + ***************************************************************************** + * Get URI RTD type content + * + * \param[in] uri: Type to get information from + * \param[out] bufProtocol: URI protocol buffer + * \param[out] bufUriString: URI string buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdUri(const ndefType* uri, ndefConstBuffer* bufProtocol, ndefConstBuffer* bufUriString); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a URI RTD type + * + * \param[in] record: Record to convert + * \param[out] uri: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdUri(const ndefRecord* record, ndefType* uri); + + +/*! + ***************************************************************************** + * Convert a URI RTD type to an NDEF record + * + * \param[in] uri: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdUriToRecord(const ndefType* uri, ndefRecord* record); + + +#endif /* NDEF_TYPE_URI_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_vcard.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_vcard.h new file mode 100644 index 0000000..5c352b1 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_vcard.h @@ -0,0 +1,216 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF MIME vCard type header file + * + * NDEF MIME type provides functionalities to handle vCard records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_VCARD_H +#define NDEF_TYPE_VCARD_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define NDEF_VCARD_PROPERTY_COUNT 16U /*!< Number of properties that can be decoded */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! vCard Record Type buffer */ +extern const ndefConstBuffer8 bufMediaTypeVCard; /*! vCard Record Type buffer */ + + +/*! NDEF Type vCard */ +typedef struct +{ + const uint8_t* propertyBuffer[NDEF_VCARD_PROPERTY_COUNT]; /*!< vCard property buffers */ + uint16_t propertyLength[NDEF_VCARD_PROPERTY_COUNT]; /*!< vCard property buffers length */ +} ndefTypeVCard; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * Compare two NDEF buffers + * + * \param[in] buf1: reference buffer + * \param[in] buf2: buffer to compare to the reference buffer + * + * \return true if both buffers content and length match + ***************************************************************************** + */ +bool ndefBufferMatch(const ndefConstBuffer* buf1, const ndefConstBuffer* buf2); + + +/*************** + * vCard + *************** + */ + + +/*! + ***************************************************************************** + * Parse a vCard property to get the type, subtype if any, and its value + * + * \param[in] bufProperty: vCard Property to parse + * \param[out] bufType: property type + * \param[out] bufSubtype: property subtype + * \param[out] bufValue: property value + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardParseProperty(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufType, ndefConstBuffer* bufSubtype, ndefConstBuffer* bufValue); + + +/*! + ***************************************************************************** + * Add a property to the vCard type + * + * \param[in] vCard: vCard type + * \param[in] bufProperty: vCard Property to add, contain the type, subtype if any and its value + * + * \return ERR_NONE if successful, ERR_NOMEM or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardSetProperty(ndefTypeVCard* vCard, const ndefConstBuffer* bufProperty); + + +/*! + ***************************************************************************** + * Get a pointer to a vCard property + * + * \param[in] vCard: vCard type + * \param[in] bufType: Type to find + * \param[out] bufProperty: The vCard property matching bufType: contain the type, subtype if any and the property value + * + * \return ERR_NONE if successful, ERR_NOTFOUND or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardGetProperty(const ndefTypeVCard* vCard, const ndefConstBuffer* bufType, ndefConstBuffer* bufProperty); + + +/*! + ***************************************************************************** + * Reset a vCard type + * + * \param[in] vCard: vCard type + * + * This function resets each field of the ndefTypeVCard structure + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardReset(ndefTypeVCard* vCard); + + +/*! + ***************************************************************************** + * Initialize a vCard + * + * \param[out] type: Type to initialize + * \param[in] vCard: vCard type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardInit(ndefType* type, const ndefTypeVCard* vCard); + + +/*! + ***************************************************************************** + * Get vCard content + * + * \param[in] type: vCard type to get information from + * \param[out] vCard: vCard type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetVCard(const ndefType* type, ndefTypeVCard* vCard); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a vCard + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToVCard(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a vCard type to an NDEF record + * + * \param[in] type: Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefVCardToRecord(const ndefType* type, ndefRecord* record); + + +#endif /* NDEF_TYPE_VCARD_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_wifi.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wifi.h new file mode 100644 index 0000000..2025b14 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wifi.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Wifi type header file + * + * NDEF Wifi type provides functionalities to handle Wifi records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_WIFI_H +#define NDEF_TYPE_WIFI_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define NDEF_WIFI_AUTHENTICATION_NONE 0U /*!< WPS No Authentication (Should be 1, but set to 0 for Android native support) */ +#define NDEF_WIFI_AUTHENTICATION_WPAPSK 2U /*!< WPS Authentication based on WPAPSK */ +#define NDEF_WIFI_AUTHENTICATION_SHARED 3U /*!< WPS Authentication */ +#define NDEF_WIFI_AUTHENTICATION_WPA 4U /*!< WPS Authentication based on WPA */ +#define NDEF_WIFI_AUTHENTICATION_WPA2 5U /*!< WPS Authentication based on WPA2 */ +#define NDEF_WIFI_AUTHENTICATION_WPA2PSK 6U /*!< WPS Authentication based on WPA2PSK */ + + +#define NDEF_WIFI_ENCRYPTION_NONE 0U /*!< WPS No Encryption (Should be 1, but set to 0 for Android native support) */ +#define NDEF_WIFI_ENCRYPTION_WEP 2U /*!< WPS Encryption based on WEP */ +#define NDEF_WIFI_ENCRYPTION_TKIP 3U /*!< WPS Encryption based on TKIP */ +#define NDEF_WIFI_ENCRYPTION_AES 4U /*!< WPS Encryption based on AES */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! Structure to store Network SSID, Authentication Type, Encryption Type and Network Key */ +typedef struct +{ + ndefConstBuffer bufNetworkSSID; /*!< Network SSID */ + ndefConstBuffer bufNetworkKey; /*!< Network Key */ + uint8_t authentication; /*!< Authentication type */ + uint8_t encryption; /*!< Encryption */ +} ndefTypeWifi; + + +/*! Wifi Record Type buffers */ +extern const ndefConstBuffer8 bufMediaTypeWifi; /*! Wifi Record Type buffer */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * Initialize a Wifi configuration + * + * \param[out] wifi: wifi type to initialize + * \param[in] wifiConfig: wifi configuration to use + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefWifiInit(ndefType* wifi, const ndefTypeWifi* wifiConfig); + + +/*! + ***************************************************************************** + * Get Wifi configuration + * + * \param[in] wifi: wifi type to get information from + * \param[out] wifiConfig: wifi configuration + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetWifi(const ndefType* wifi, ndefTypeWifi* wifiConfig); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a wifi type + * + * \param[in] record: Record to convert + * \param[out] wifi: The converted wifi type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToWifi(const ndefRecord* record, ndefType* wifi); + + +/*! + ***************************************************************************** + * Convert a wifi type to an NDEF record + * + * \param[in] wifi: wifi type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefWifiToRecord(const ndefType* wifi, ndefRecord* record); + + +#endif /* NDEF_TYPE_WIFI_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_wlc.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wlc.h new file mode 100644 index 0000000..db9de37 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wlc.h @@ -0,0 +1,392 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF WLC (Wireless Charging) types header file + * + * NDEF WLC provides functionalities to handle WLC records, such + * WLC Capability, WLC Status Information, WLC Poll Information and WLC Listen Control. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_WLC_H +#define NDEF_TYPE_WLC_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_BATTERY_LEVEL_MASK 0x01U /*!< WLC Status and Info Control byte 1: Battery Level mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_POWER_MASK 0x02U /*!< WLC Status and Info Control byte 1: Receive Power mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_VOLTAGE_MASK 0x04U /*!< WLC Status and Info Control byte 1: Receive Voltage mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_CURRENT_MASK 0x08U /*!< WLC Status and Info Control byte 1: Receive Current mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_BATTERY_MASK 0x10U /*!< WLC Status and Info Control byte 1: Temperature Battery mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_WLCL_MASK 0x20U /*!< WLC Status and Info Control byte 1: Temperature WLCL mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_RFU_MASK 0x40U /*!< WLC Status and Info Control byte 1: RFU mask */ +#define NDEF_WLC_STATUSINFO_CONTROLBYTE1_CONTROL_BYTE_2_MASK 0x80U /*!< WLC Status and Info Control byte 1: Control byte 2 mask */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! Structure to store WLC Capability */ +typedef struct +{ + uint8_t wlcProtocolVersion; /*!< WLC Protocol Version */ + uint8_t wlcConfigModeReq; /*!< WLC Config: MODE_REQ */ + uint8_t wlcConfigWaitTimeRetry; /*!< WLC Config: WaitTimeRetry */ + uint8_t wlcConfigNegoWait; /*!< WLC Config: NEGO_WAIT */ + uint8_t wlcConfigRdConf; /*!< WLC Config: RD_CONF */ + uint8_t capWtIntRfu; /*!< Cap Wt Int RFU */ + uint8_t capWtInt; /*!< Cap Wt Int */ + uint8_t ndefRdWt; /*!< NDEF Rd Wt */ + uint8_t ndefWriteToInt; /*!< NDEF Write To Int */ + uint8_t ndefWriteWtInt; /*!< NDEF Write Wt Int */ +} ndefTypeRtdWlcCapability; + + +/*! Structure to store WLC Status and Info */ +typedef struct +{ + uint8_t controlByte1; /*!< Control byte 1 */ + uint8_t batteryLevel; /*!< Battery level */ + uint8_t receivePower; /*!< Receive power */ + uint8_t receiveVoltage; /*!< Receive voltage */ + uint8_t receiveCurrent; /*!< Receive current */ + uint8_t temperatureBattery; /*!< Battery temperature */ + uint8_t temperatureWlcl; /*!< WLCL temperature */ + uint8_t rfu; /*!< RFU */ + uint8_t controlByte2; /*!< Control byte 2 */ +} ndefTypeRtdWlcStatusInfo; + + +/*! Structure to store WLC Poll Information */ +typedef struct +{ + uint8_t pTx; /*!< P Tx, Transmit Power Level */ + uint8_t wlcPCap; /*!< WLC_P Capability */ + uint8_t powerClass; /*!< Power Class */ + uint8_t totPowerSteps; /*!< Tot Power Steps */ + uint8_t curPowerStep; /*!< Current Power Step */ + uint8_t nextMinStepInc; /*!< Next Min Step Inc */ + uint8_t nextMinStepDec; /*!< Next Min Step Dec */ +} ndefTypeRtdWlcPollInfo; + + +/*! Structure to store WLC Listen Control */ +typedef struct +{ + uint8_t statusInfoErrorFlag; /*!< Status information: ERROR_FLG */ + uint8_t statusInfoBatteryStatus; /*!< Status information: BATTERY_STATUS */ + uint8_t statusInfoCnt; /*!< Status information: CNT */ + uint8_t wptConfigWptReq; /*!< WPT Config: WPT_REQ */ + uint8_t wptConfigWptDuration; /*!< WPT Config: WPT_DURATION */ + uint8_t wptConfigInfoReq; /*!< WPT Config: INFO_REQ */ + uint8_t powerAdjReq; /*!< Power Adjust Req */ + uint8_t batteryLevel; /*!< Battery level */ + uint8_t drvInfoFlag; /*!< Drv info: DRV_FLAG */ + uint8_t drvInfoInt; /*!< Drv info: DRV_INT */ + uint8_t holdOffWtInt; /*!< Hold off Wt Int */ + uint8_t errorInfoError; /*!< [Error info]* if ERROR_FLG set: WLC_INFO_ERROR */ + uint8_t errorInfoTemperature; /*!< [Error info]* if ERROR_FLG set: TEMPERATURE_ERROR */ +} ndefTypeRtdWlcListenCtl; + + +/*! WLC Record Type buffers */ +extern const ndefConstBuffer8 bufTypeRtdWlcCapability; /*!< WLC Capability Type Record buffer */ +extern const ndefConstBuffer8 bufTypeRtdWlcStatusInfo; /*!< WLC Status and Information Type Record buffer */ +extern const ndefConstBuffer8 bufTypeRtdWlcPollInfo; /*!< WLC Poll Information Type Record buffer */ +extern const ndefConstBuffer8 bufTypeRtdWlcListenCtl; /*!< WLC Listen Control Type Record buffer */ + + +/*! WLC MODE_REQ */ +typedef enum +{ + NDEF_RTD_WLC_CAPABILITY_MODE_STATIC, + NDEF_RTD_WLC_CAPABILITY_MODE_NEGOTIATED, + NDEF_RTD_WLC_CAPABILITY_MODE_BATTERY_FULL, + NDEF_RTD_WLC_CAPABILITY_MODE_RFU +} ndefRtdWlcReqMode; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*************************** + * WLC - Wireless Charging + *************************** + */ + + +/* WLC Capability */ + + +/*! + ***************************************************************************** + * Initialize a WLC Capability type + * + * \param[out] type: NDEF type to initialize + * \param[in] wlcCapability: WLC Capability + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcCapabilityInit(ndefType* type, const ndefTypeRtdWlcCapability* wlcCapability); + + +/*! + ***************************************************************************** + * Get WLC Capability type content + * + * \param[in] type: NDEF type to get information from + * \param[out] wlcCapability: WLC Capability + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdWlcCapability(const ndefType* type, ndefTypeRtdWlcCapability* wlcCapability); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a WLC Capability type + * + * \param[in] record: Record to convert + * \param[out] type: The converted NDEF type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdWlcCapability(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a WLC Capability type to an NDEF record + * + * \param[in] type: NDEF type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcCapabilityToRecord(const ndefType* type, ndefRecord* record); + + +/* WLC Status and Information */ + + +/*! + ***************************************************************************** + * Initialize a WLC Status and Information type + * + * \param[out] type: NDEF type to initialize + * \param[in] wlcStatusInfo: WLC Status and Information + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcStatusInfoInit(ndefType* type, const ndefTypeRtdWlcStatusInfo* wlcStatusInfo); + + +/*! + ***************************************************************************** + * Get WLC Status and Information type content + * + * \param[in] type: NDEF type to get information from + * \param[out] wlcStatusInfo: WLC Status and Information + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdWlcStatusInfo(const ndefType* type, ndefTypeRtdWlcStatusInfo* wlcStatusInfo); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a WLC Status and Information type + * + * \param[in] record: Record to convert + * \param[out] type: The converted NDEF type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdWlcStatusInfo(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a WLC Status and Information type to an NDEF record + * + * \param[in] type: NDEF type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcStatusInfoToRecord(const ndefType* type, ndefRecord* record); + + +/* WLC Poll Information */ + + +/*! + ***************************************************************************** + * Initialize a WLC Poll Information type + * + * \param[out] type: NDEF type to initialize + * \param[in] wlcPollInfo: WLC Poll Info + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcPollInfoInit(ndefType* type, const ndefTypeRtdWlcPollInfo* wlcPollInfo); + + +/*! + ***************************************************************************** + * Get WLC Poll type content + * + * \param[in] type: NDEF type to get information from + * \param[out] wlcPollInfo: WLC Poll Info + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdWlcPollInfo(const ndefType* type, ndefTypeRtdWlcPollInfo* wlcPollInfo); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a WLC Poll Info type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdWlcPollInfo(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a WLC Poll Info type to an NDEF record + * + * \param[in] type: NDEF Type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcPollInfoToRecord(const ndefType* type, ndefRecord* record); + + +/* WLC Listen Control */ + + +/*! + ***************************************************************************** + * Initialize a WLC Listen Control type + * + * \param[out] type: NDEF Type to initialize + * \param[in] wlcListenCtl: WLC Listen Control + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcListenCtlInit(ndefType* type, const ndefTypeRtdWlcListenCtl* wlcListenCtl); + + +/*! + ***************************************************************************** + * Get WLC Listen Control type content + * + * \param[in] type: NDEF type to get information from + * \param[out] wlcListenCtl: WLC Listen Control + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdWlcListenCtl(const ndefType* type, ndefTypeRtdWlcListenCtl* wlcListenCtl); + + +/*! + ***************************************************************************** + * Convert an NDEF record to a WLC Listen Control type + * + * \param[in] record: Record to convert + * \param[out] type: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdWlcListenCtl(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a WLC Listen Control type to an NDEF record + * + * \param[in] type: NDEF type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWlcListenCtlToRecord(const ndefType* type, ndefRecord* record); + + +#endif + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_type_wpcwlc.h b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wpcwlc.h new file mode 100644 index 0000000..22367dc --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_type_wpcwlc.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Wireless Power Consortium WLC Record (WPCWLC) type header file + * + * NDEF RTD provides functionalities to handle RTD WPCWLC records. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPE_WPCWLC_H +#define NDEF_TYPE_WPCWLC_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_buffer.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_KI_APPLICATION_PROFILE 03U /*!< Ki Application Profile */ + +#define NDEF_KI_V10_PAYLOAD_LENGTH 16U /*!< Ki v1.0 Payload length */ + +#define NDEF_KI_APPLICATION_PROFILE_OFFSET 0x00U /*!< Ki Application Profile offset */ +#define NDEF_KI_VERSION_OFFSET 0x01U /*!< Ki Major|Minor Version Offset */ +#define NDEF_KI_ALIVE_FDT_OFFSET 0x02U /*!< Ki Alive FDT Offset */ +#define NDEF_KI_READ_ADDRESS_OFFSET 0x03U /*!< Ki Read Data Buffer Start Address Offset */ +#define NDEF_KI_WRITE_ADDRESS_OFFSET 0x04U /*!< Ki Write Data Buffer Start Address Offset */ +#define NDEF_KI_READ_SIZE_OFFSET 0x05U /*!< Ki Read Data Buffer Size Offset */ +#define NDEF_KI_WRITE_SIZE_OFFSET 0x06U /*!< Ki Write Data Buffer Size Offset */ +#define NDEF_KI_READ_CMD_OFFSET 0x07U /*!< Ki Read Command Code Offset */ +#define NDEF_KI_WRITE_CMD_OFFSET 0x08U /*!< Ki Write Commande Code Offset */ +#define NDEF_KI_MAX_T_SLOT_FOD_OFFSET 0x09U /*!< Ki Maximum T_SLOT FOD Offset */ +#define NDEF_KI_MIN_T_POWER_OFFSET 0x0AU /*!< Ki Minimum T_POWER Offset */ +#define NDEF_KI_T_SUSPEND_OFFSET 0x0BU /*!< Ki T_SUSPEND Offset */ +#define NDEF_KI_COMM_LAG_MAX_OFFSET 0x0CU /*!< Ki T_COMM_LAG,MAX Offset */ +#define NDEF_KI_WRITE_SEQ_LENGTH_OFFSET 0x0DU /*!< Ki Write Sequence Length Offset */ +#define NDEF_KI_MIN_POWER_OFFSET 0x0EU /*!< Ki Minimum Power Offset */ +#define NDEF_KI_MAX_POWER_OFFSET 0x0FU /*!< Ki Maximum Power Offset */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! RTD Record Type buffers */ +extern const ndefConstBuffer8 bufRtdTypeWpcWlc; /*! WPCWLC (Wireless Power Consortium WLC) Record Type buffer */ + + +/*! RTD Wireless Power Consortium WLC Record External Type */ +typedef struct +{ + ndefConstBuffer bufPayload; /*!< WPCWLC payload */ +} ndefTypeRtdWpcWlc; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/********************** + * WPCWLC External Type + ********************** + */ + +/*! + ***************************************************************************** + * Initialize an RTD Wireless Power Consortium WLC Record External type + * + * \param[out] wpcWlc: Type to initialize + * \param[in] bufPayload: Payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWpcWlcInit(ndefType* wpcWlc, const ndefConstBuffer* bufPayload); + + +/*! + ***************************************************************************** + * Get RTD Wireless Power Consortium WLC Record type content + * + * \param[in] wpcWlc: Type to get information from + * \param[out] bufWpcWlc: WPCWLC payload buffer + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefGetRtdWpcWlc(const ndefType* wpcWlc, ndefConstBuffer* bufWpcWlc); + + +/*! + ***************************************************************************** + * Convert an NDEF record to an RTD Wireless Power Consortium WLC Record External type + * + * \param[in] record: Record to convert + * \param[out] wpcWlc: The converted WPCWLC type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToRtdWpcWlc(const ndefRecord* record, ndefType* wpcWlc); + + +/*! + ***************************************************************************** + * Convert an RTD Wireless Power Consortium WLC Record External type to an NDEF record + * + * \param[in] wpcWlc: WPCWLC type to convert + * \param[out] record: The converted type + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRtdWpcWlcToRecord(const ndefType* wpcWlc, ndefRecord* record); + + +#endif /* NDEF_TYPE_WPCWLC_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/message/ndef_types.h b/components/spi-st25r3911b/NDEF/include/message/ndef_types.h new file mode 100644 index 0000000..c259fd9 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/message/ndef_types.h @@ -0,0 +1,259 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Common NDEF RTD (well-known and external) and Media types header file + * + * NDEF types provides an abstraction layer gathering both the RTD and MIME types + * in a single generic ndefType interface. + * See ndefTypeStruct and ndefType + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_TYPES_H +#define NDEF_TYPES_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_config.h" +#include "ndef_record.h" +#include "ndef_buffer.h" + +/* RTD types */ +#if NDEF_TYPE_EMPTY_SUPPORT +#include "ndef_type_empty.h" +#endif +#if NDEF_TYPE_FLAT_SUPPORT +#include "ndef_type_flat.h" +#endif +#if NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT +#include "ndef_type_deviceinfo.h" +#endif +#if NDEF_TYPE_RTD_TEXT_SUPPORT +#include "ndef_type_text.h" +#endif +#if NDEF_TYPE_RTD_URI_SUPPORT +#include "ndef_type_uri.h" +#endif +#if NDEF_TYPE_RTD_AAR_SUPPORT +#include "ndef_type_aar.h" +#endif +#if NDEF_TYPE_RTD_WLC_SUPPORT +#include "ndef_type_wlc.h" +#endif +#if NDEF_TYPE_RTD_WPCWLC_SUPPORT +#include "ndef_type_wpcwlc.h" +#endif +#if NDEF_TYPE_RTD_TNEP_SUPPORT +#include "ndef_type_tnep.h" +#endif + +/* MIME types */ +#if NDEF_TYPE_MEDIA_SUPPORT +#include "ndef_type_media.h" +#endif +#if NDEF_TYPE_BLUETOOTH_SUPPORT +#include "ndef_type_bluetooth.h" +#endif +#if NDEF_TYPE_VCARD_SUPPORT +#include "ndef_type_vcard.h" +#endif +#if NDEF_TYPE_WIFI_SUPPORT +#include "ndef_type_wifi.h" +#endif + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*****************************************************************************/ + +/*! NDEF Type Id enum */ +typedef enum +{ + NDEF_TYPE_ID_NONE = 0, + NDEF_TYPE_ID_FLAT, + NDEF_TYPE_ID_EMPTY, + NDEF_TYPE_ID_RTD_DEVICE_INFO, + NDEF_TYPE_ID_RTD_TEXT, + NDEF_TYPE_ID_RTD_URI, + NDEF_TYPE_ID_RTD_AAR, + NDEF_TYPE_ID_RTD_WLCCAP, + NDEF_TYPE_ID_RTD_WLCSTAI, + NDEF_TYPE_ID_RTD_WLCINFO, + NDEF_TYPE_ID_RTD_WLCCTL, + NDEF_TYPE_ID_RTD_WPCWLC, + NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER, + NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT, + NDEF_TYPE_ID_RTD_TNEP_STATUS, + NDEF_TYPE_ID_MEDIA, + NDEF_TYPE_ID_BLUETOOTH_BREDR, + NDEF_TYPE_ID_BLUETOOTH_LE, + NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR, + NDEF_TYPE_ID_BLUETOOTH_SECURE_LE, + NDEF_TYPE_ID_MEDIA_VCARD, + NDEF_TYPE_ID_MEDIA_WIFI, + NDEF_TYPE_ID_COUNT /* Keep this one last */ +} ndefTypeId; + + +/*! NDEF abstraction Struct */ +struct ndefTypeStruct +{ + ndefTypeId id; /*!< Type Id */ + uint32_t (*getPayloadLength)(const ndefType* type); /*!< Return payload length, specific to each type */ + const uint8_t* (*getPayloadItem)(const ndefType* type, ndefConstBuffer* item, bool begin); /*!< Payload Encoder, specific to each type */ + ndefStatus (*typeToRecord)(const ndefType* type, ndefRecord* record); /*!< Type to Record convert function */ + union + { +#if NDEF_TYPE_FLAT_SUPPORT + ndefConstBuffer bufPayload; /*!< Flat/unknown type */ +#endif +#if NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT + ndefTypeRtdDeviceInfo deviceInfo; /*!< Device Information */ +#endif +#if NDEF_TYPE_RTD_TEXT_SUPPORT + ndefTypeRtdText text; /*!< Text */ +#endif +#if NDEF_TYPE_RTD_URI_SUPPORT + ndefTypeRtdUri uri; /*!< URI */ +#endif +#if NDEF_TYPE_RTD_AAR_SUPPORT + ndefTypeRtdAar aar; /*!< AAR */ +#endif +#if NDEF_TYPE_RTD_WLC_SUPPORT + ndefTypeRtdWlcCapability wlcCapability; /*!< WLC Capability */ + ndefTypeRtdWlcStatusInfo wlcStatusInfo; /*!< WLC Status and Info */ + ndefTypeRtdWlcPollInfo wlcPollInfo; /*!< WLC Poll Information */ + ndefTypeRtdWlcListenCtl wlcListenCtl; /*!< WLC Listen Control */ +#endif +#if NDEF_TYPE_RTD_WPCWLC_SUPPORT + ndefTypeRtdWpcWlc wpcWlc; /*!< WPC WLC */ +#endif +#if NDEF_TYPE_RTD_TNEP_SUPPORT + ndefTypeRtdTnepServiceParameter tnepServiceParameter; /*!< TNEP Service Parameter */ + ndefTypeRtdTnepServiceSelect tnepServiceSelect; /*!< TNEP Service Select */ + ndefTypeRtdTnepStatus tnepStatus; /*!< TNEP Status */ +#endif +#if NDEF_TYPE_MEDIA_SUPPORT + ndefTypeMedia media; /*!< Media */ +#endif +#if NDEF_TYPE_BLUETOOTH_SUPPORT + ndefTypeBluetooth bluetooth; /*!< Bluetooth */ +#endif +#if NDEF_TYPE_VCARD_SUPPORT + ndefTypeVCard vCard; /*!< vCard */ +#endif +#if NDEF_TYPE_WIFI_SUPPORT + ndefTypeWifi wifi; /*!< Wifi */ +#endif + uint8_t reserved; /*!< Non-conditional field to avoid empty union when all types are disabled */ + } data; /*!< Type data union */ +}; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + + +/*! + ***************************************************************************** + * Convert a record to a supported type + * + * \param[in] record: Record to read + * \param[out] type: Type to store the converted record + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordToType(const ndefRecord* record, ndefType* type); + + +/*! + ***************************************************************************** + * Convert a supported type to a record + * + * \param[in] type: Pointer to the type to read data from + * \param[out] record: Record to fill + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefTypeToRecord(const ndefType* type, ndefRecord* record); + + +/*! + ***************************************************************************** + * Set the NDEF specific structure to process NDEF types + * + * \param[in] record: Record + * \param[out] type: NDEF type structure + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +ndefStatus ndefRecordSetNdefType(ndefRecord* record, const ndefType* type); + + +/*! + ***************************************************************************** + * Get the NDEF type structure of this record + * + * \param[in] record: Record + * + * \return ERR_NONE if successful or a standard error code + ***************************************************************************** + */ +const ndefType* ndefRecordGetNdefType(const ndefRecord* record); + + +#endif /* NDEF_TYPES_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/ndef_config.h b/components/spi-st25r3911b/NDEF/include/ndef_config.h new file mode 100644 index 0000000..4b94274 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/ndef_config.h @@ -0,0 +1,168 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF config header file + * + * This file allows to select which NDEF features to use. + * + * \addtogroup NDEF + * @{ + * + */ + +#ifndef NDEF_CONFIG_H +#define NDEF_CONFIG_H + + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include +#include +#include "st_errno.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define ndefStatus stError /*!< NDEF error type */ + +/* + ****************************************************************************** + * NDEF FEATURES CONFIGURATION + ****************************************************************************** + */ + +#ifdef NDEF_CONFIG_CUSTOM + +#include "ndef_config_custom.h" + +/* Define default configuration when not set in ndef_config_custom.h */ +#ifndef ndefDevice +#include "rfal_nfc.h" +#include "rfal_t4t.h" +#define ndefDevice rfalNfcDevice /*!< NDEF Device */ +#endif +#ifndef NDEF_FEATURE_T1T +#define NDEF_FEATURE_T1T RFAL_FEATURE_T1T /*!< T1T Support control */ +#endif +#ifndef NDEF_FEATURE_T2T +#define NDEF_FEATURE_T2T RFAL_FEATURE_T2T /*!< T2T Support control */ +#endif +#ifndef NDEF_FEATURE_T3T +#define NDEF_FEATURE_T3T RFAL_FEATURE_NFCF /*!< T3T Support control */ +#endif +#ifndef NDEF_FEATURE_T4T +#define NDEF_FEATURE_T4T RFAL_FEATURE_T4T /*!< T4T Support control */ +#endif +#ifndef NDEF_FEATURE_T5T +#define NDEF_FEATURE_T5T RFAL_FEATURE_NFCV /*!< T5T Support control */ +#endif + + +#ifndef NDEF_FEATURE_FULL_API +#define NDEF_FEATURE_FULL_API false /*!< Support Write, Format, Check Presence, set Read-only in addition to the Read feature */ +#endif + +#ifndef NDEF_TYPE_EMPTY_SUPPORT +#define NDEF_TYPE_EMPTY_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_FLAT_SUPPORT +#define NDEF_TYPE_FLAT_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_AAR_SUPPORT +#define NDEF_TYPE_RTD_AAR_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT +#define NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_URI_SUPPORT +#define NDEF_TYPE_RTD_URI_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_TEXT_SUPPORT +#define NDEF_TYPE_RTD_TEXT_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_WLC_SUPPORT +#define NDEF_TYPE_RTD_WLC_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_RTD_TNEP_SUPPORT +#define NDEF_TYPE_RTD_TNEP_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_MEDIA_SUPPORT +#define NDEF_TYPE_MEDIA_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_BLUETOOTH_SUPPORT +#define NDEF_TYPE_BLUETOOTH_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_VCARD_SUPPORT +#define NDEF_TYPE_VCARD_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif +#ifndef NDEF_TYPE_WIFI_SUPPORT +#define NDEF_TYPE_WIFI_SUPPORT false /* NDEF library configuration missing. Disabled by default */ +#endif + +#else /* NDEF_CONFIG_CUSTOM */ + +#include "rfal_nfc.h" +#include "rfal_t4t.h" + +#define ndefDevice rfalNfcDevice /*!< NDEF Device */ +#define NDEF_FEATURE_T1T RFAL_FEATURE_T1T /*!< T1T Support control */ +#define NDEF_FEATURE_T2T RFAL_FEATURE_T2T /*!< T2T Support control */ +#define NDEF_FEATURE_T3T RFAL_FEATURE_NFCF /*!< T3T Support control */ +#define NDEF_FEATURE_T4T RFAL_FEATURE_T4T /*!< T4T Support control */ +#define NDEF_FEATURE_T5T RFAL_FEATURE_NFCV /*!< T5T Support control */ + + +#define NDEF_FEATURE_FULL_API true /*!< Support Write, Format, Check Presence, set Read-only in addition to the Read feature */ + +#define NDEF_TYPE_EMPTY_SUPPORT true /*!< Support Empty type */ +#define NDEF_TYPE_FLAT_SUPPORT true /*!< Support Flat type */ +#define NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT true /*!< Support RTD Device Information type */ +#define NDEF_TYPE_RTD_TEXT_SUPPORT true /*!< Support RTD Text type */ +#define NDEF_TYPE_RTD_URI_SUPPORT true /*!< Support RTD URI type */ +#define NDEF_TYPE_RTD_AAR_SUPPORT true /*!< Support RTD Android Application Record type */ +#define NDEF_TYPE_RTD_WLC_SUPPORT true /*!< Support RTD WLC Types */ +#define NDEF_TYPE_RTD_WPCWLC_SUPPORT true /*!< Support RTD WPC WLC type */ +#define NDEF_TYPE_RTD_TNEP_SUPPORT true /*!< Support RTD TNEP Types */ +#define NDEF_TYPE_MEDIA_SUPPORT true /*!< Support Media type */ +#define NDEF_TYPE_BLUETOOTH_SUPPORT true /*!< Support Bluetooth types */ +#define NDEF_TYPE_VCARD_SUPPORT true /*!< Support vCard type */ +#define NDEF_TYPE_WIFI_SUPPORT true /*!< Support Wifi type */ + +#endif /* NDEF_CONFIG_CUSTOM */ + +#endif /* NDEF_CONFIG_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_poller.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_poller.h new file mode 100644 index 0000000..d0eded6 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_poller.h @@ -0,0 +1,671 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum Tags + * + * NDEF provides several functionalities required to perform NFC NDEF activities. + *
The NDEF encapsulates the different tag technologies (T2T, T3T, T4AT, T4BT, T5T) + * into a common and easy to use interface. + * + * It provides interfaces to Detect, Read, Write and Format NDEF. + * + * The most common interfaces are: + * + *
  ndefGetDeviceType() + *
  ndefPollerContextInitialization() + *
  ndefPollerNdefDetect() + *
  ndefPollerReadBytes() + *
  ndefPollerWriteBytes() + *
  ndefPollerReadRawMessage() + *
  ndefPollerWriteRawMessage() + *
  ndefPollerTagFormat() + *
  ndefPollerWriteMessage() + *
  ndefPollerCheckPresence() + *
  ndefPollerCheckAvailableSpace() + *
  ndefPollerSetReadOnly() + * + * + * An NDEF read usage example is provided here: \ref ndef_example_read.c + * \example ndef_example_read.c + * + * An NDEF write usage example is provided here: \ref ndef_example_write.c + * \example ndef_example_write.c + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_POLLER_H +#define NDEF_POLLER_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_message.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_CC_BUF_LEN 17U /*!< CC buffer len. Max length = 17 in case of T4T v3 */ +#define NDEF_NFCV_SUPPORTED_CMD_LEN 4U /*!< Ext sys info supported commands list length */ +#define NDEF_NFCV_UID_LEN 8U /*!< NFC-V UID length */ + +#define NDEF_SHORT_VFIELD_MAX_LEN 254U /*!< Max V-field length for 1-byte Lengh encoding */ +#define NDEF_TERMINATOR_TLV_LEN 1U /*!< Terminator TLV size */ +#define NDEF_TERMINATOR_TLV_T 0xFEU /*!< Terminator TLV T=FEh */ + +#define NDEF_T2T_READ_RESP_SIZE 16U /*!< Size of the READ response i.e. four blocks */ +#define NDEF_T2T_MAX_RSVD_AREAS 3U /*!< Number of reserved areas including 1 Dyn Lock area */ + +#define NDEF_T3T_BLOCK_SIZE 16U /*!< size for a block in t3t */ +#define NDEF_T3T_MAX_NB_BLOCKS 4U /*!< size for a block in t3t */ +#define NDEF_T3T_BLOCK_NUM_MAX_SIZE 3U /*!< Maximun size for a block number */ +#define NDEF_T3T_MAX_RX_SIZE ((NDEF_T3T_BLOCK_SIZE*NDEF_T3T_MAX_NB_BLOCKS) + 13U) /*!< size for a CHECK Response 13 bytes (LEN+07h+NFCID2+Status+Nos) + (block size x Max Nob) */ +#define NDEF_T3T_MAX_TX_SIZE (((NDEF_T3T_BLOCK_SIZE + NDEF_T3T_BLOCK_NUM_MAX_SIZE) * NDEF_T3T_MAX_NB_BLOCKS) + 14U) \ + /*!< size for an UPDATE command, 11 bytes (LEN+08h+NFCID2+Nos) + 2 bytes for 1 SC + 1 byte for NoB + (block size + block num Len) x Max NoB */ + +#define NDEF_T5T_TxRx_BUFF_HEADER_SIZE 1U /*!< Request Flags/Responses Flags size */ +#define NDEF_T5T_TxRx_BUFF_FOOTER_SIZE 2U /*!< CRC size */ + +#define NDEF_T5T_TxRx_BUFF_SIZE \ + (32U + NDEF_T5T_TxRx_BUFF_HEADER_SIZE + NDEF_T5T_TxRx_BUFF_FOOTER_SIZE) /*!< T5T working buffer size */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define ndefBytes2Uint16(hiB, loB) ((uint16_t)((((uint32_t)(hiB)) << 8U) | ((uint32_t)(loB)))) /*!< convert 2 bytes to a u16 */ + +#define ndefMajorVersion(V) ((uint8_t)((V) >> 4U)) /*!< Get major version */ +#define ndefMinorVersion(V) ((uint8_t)((V) & 0xFU)) /*!< Get minor version */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/*! NDEF device type */ +typedef enum { + NDEF_DEV_NONE = 0x00U, /*!< Device type undef */ + NDEF_DEV_T1T = 0x01U, /*!< Device type T1T */ + NDEF_DEV_T2T = 0x02U, /*!< Device type T2T */ + NDEF_DEV_T3T = 0x03U, /*!< Device type T3T */ + NDEF_DEV_T4T = 0x04U, /*!< Device type T4AT/T4BT */ + NDEF_DEV_T5T = 0x05U, /*!< Device type T5T */ +} ndefDeviceType; + +/*! NDEF states */ +typedef enum { + NDEF_STATE_INVALID = 0x00U, /*!< Invalid state (e.g. no CC) */ + NDEF_STATE_INITIALIZED = 0x01U, /*!< State Initialized (no NDEF message) */ + NDEF_STATE_READWRITE = 0x02U, /*!< Valid NDEF found. Read/Write capability */ + NDEF_STATE_READONLY = 0x03U, /*!< Valid NDEF found. Read only */ +} ndefState; + +/*! NDEF Information */ +typedef struct { + uint8_t majorVersion; /*!< Major version */ + uint8_t minorVersion; /*!< Minor version */ + uint32_t areaLen; /*!< Area Length for NDEF storage */ + uint32_t areaAvalableSpaceLen; /*!< Remaining Space in case a propTLV is present */ + uint32_t messageLen; /*!< NDEF message Length */ + ndefState state; /*!< Tag state e.g. NDEF_STATE_INITIALIZED */ +} ndefInfo; + +#if NDEF_FEATURE_T1T +/*! T1T Capability Container */ +typedef struct { + uint8_t magicNumber; /*!< Magic number e.g. E1h */ + uint8_t majorVersion; /*!< Major version i.e. 1 */ + uint8_t minorVersion; /*!< Minor version i.e. 2 */ + uint16_t tagMemorySize; /*!< Tag Memory Size (TMS) */ + uint8_t readAccess; /*!< NDEF READ access condition */ + uint8_t writeAccess; /*!< NDEF WRITE access condition */ +} ndefCapabilityContainerT1T; +#endif + +#if NDEF_FEATURE_T2T +/*! T2T Capability Container */ +typedef struct { + uint8_t magicNumber; /*!< Magic number e.g. E1h */ + uint8_t majorVersion; /*!< Major version i.e. 1 */ + uint8_t minorVersion; /*!< Minor version i.e. 2 */ + uint8_t size; /*!< Size. T2T_Area_Size = Size * 8 */ + uint8_t readAccess; /*!< NDEF READ access condition */ + uint8_t writeAccess; /*!< NDEF WRITE access condition */ +} ndefCapabilityContainerT2T; +#endif + +#if NDEF_FEATURE_T3T +/*! T3T Attribute info block */ +typedef struct { + uint8_t majorVersion; /*!< Major version i.e. 1 */ + uint8_t minorVersion; /*!< Minor version i.e. 2 */ + uint8_t nbR; /*!< Nbr: number of blocks read in one CHECK cmd */ + uint8_t nbW; /*!< Nbr: number of blocks written in one UPDATE cmd */ + uint16_t nMaxB; /*!< NmaxB: max number of blocks for NDEF data */ + uint8_t writeFlag; /*!< WriteFlag indicates completion of previous NDEF */ + uint8_t rwFlag; /*!< RWFlag indicates whether the NDEF can be updated */ + uint32_t Ln; /*!< Ln size of the actual stored NDEF data in bytes */ +} ndefAttribInfoBlockT3T; +#endif + +#if NDEF_FEATURE_T4T +/*! T4T Capability Container */ +typedef struct { + uint16_t ccLen; /*!< CCFILE Length */ + uint8_t vNo; /*!< Mapping version */ + uint16_t mLe; /*!< Max data size that can be read using a ReadBinary */ + uint16_t mLc; /*!< Max data size that can be sent using a single cmd */ + uint8_t fileId[2]; /*!< NDEF File Identifier */ + uint32_t fileSize; /*!< NDEF File Size */ + uint8_t readAccess; /*!< NDEF File READ access condition */ + uint8_t writeAccess; /*!< NDEF File WRITE access condition */ +} ndefCapabilityContainerT4T; +#endif + +#if NDEF_FEATURE_T5T +/*! T5T Capability Container */ +typedef struct { + uint8_t ccLen; /*!< CC Length */ + uint8_t magicNumber; /*!< Magic number i.e. E1h or E2h */ + uint8_t majorVersion; /*!< Major version i.e. 1 */ + uint8_t minorVersion; /*!< Minor version i.e. 0 */ + uint8_t readAccess; /*!< NDEF READ access condition */ + uint8_t writeAccess; /*!< NDEF WRITE access condition */ + uint16_t memoryLen; /*!< MLEN (Memory Len). T5T_Area size = 8 * MLEN (bytes)*/ + bool specialFrame; /*!< Use Special Frames for Write-alike commands */ + bool lockBlock; /*!< (EXTENDED_)LOCK_SINGLE_BLOCK supported */ + bool mlenOverflow; /*!< memory size exceeds 2040 bytes (Android) */ + bool multipleBlockRead; /*!< (EXTENDED_)READ_MULTIPLE_BLOCK supported */ +} ndefCapabilityContainerT5T; +#endif + +/*! Generic Capability Container */ +typedef union { +#if NDEF_FEATURE_T1T + ndefCapabilityContainerT1T t1t; /*!< T1T Capability Container */ +#endif +#if NDEF_FEATURE_T2T + ndefCapabilityContainerT2T t2t; /*!< T2T Capability Container */ +#endif +#if NDEF_FEATURE_T3T + ndefAttribInfoBlockT3T t3t; /*!< T3T Attribute Information Block */ +#endif +#if NDEF_FEATURE_T4T + ndefCapabilityContainerT4T t4t; /*!< T4T Capability Container */ +#endif +#if NDEF_FEATURE_T5T + ndefCapabilityContainerT5T t5t; /*!< T5T Capability Container */ +#endif +} ndefCapabilityContainer; + +#if NDEF_FEATURE_T1T +/*! NDEF T1T sub context structure */ +typedef struct { + void * rfu; /*!< RFU */ +} ndefT1TContext; +#endif + +#if NDEF_FEATURE_T2T +/*! NDEF T2T sub context structure */ +typedef struct { + uint8_t currentSecNo; /*!< Current sector number */ + uint8_t cacheBuf[NDEF_T2T_READ_RESP_SIZE]; /*!< Cache buffer */ + uint8_t nbrRsvdAreas; /*!< Number of reseved Areas */ + uint16_t dynLockNbrLockBits; /*!< Number of bits inside the DynLock_Area */ + uint16_t dynLockBytesLockedPerBit; /*!< Number of bytes locked by one Dynamic Lock bit */ + uint16_t dynLockNbrBytes; /*!< Number of bytes inside the DynLock_Area */ + uint16_t rsvdAreaSize[NDEF_T2T_MAX_RSVD_AREAS]; /*!< Sizes of reserved areas */ + uint32_t cacheAddr; /*!< Address of cached data */ + uint32_t offsetNdefTLV; /*!< NDEF TLV message offset */ + uint32_t dynLockFirstByteAddr; /*!< Address of the first byte of the DynLock_Area */ + uint32_t rsvdAreaFirstByteAddr[NDEF_T2T_MAX_RSVD_AREAS]; /*!< Addresses of reserved areas */ +} ndefT2TContext; +#endif + +#if NDEF_FEATURE_T3T +/*! NDEF T3T sub context structure */ +typedef struct { + uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2 */ + uint8_t txbuf[NDEF_T3T_MAX_TX_SIZE]; /*!< Tx buffer dedicated for T3T internal operations */ + uint8_t rxbuf[NDEF_T3T_MAX_RX_SIZE]; /*!< Rx buffer dedicated for T3T internal operations */ + rfalNfcfBlockListElem listBlocks[NDEF_T3T_MAX_NB_BLOCKS]; /*!< block number list for T3T internal operations */ +} ndefT3TContext; +#endif + +#if NDEF_FEATURE_T4T +/*! NDEF T4T sub context structure */ +typedef struct { + uint8_t curMLe; /*!< Current MLe. Default Fh until CC file is read */ + uint8_t curMLc; /*!< Current MLc. Default Dh until CC file is read */ + bool mv1Flag; /*!< Mapping version 1 flag */ + rfalIsoDepApduBufFormat cApduBuf; /*!< Command-APDU buffer */ + rfalIsoDepApduBufFormat rApduBuf; /*!< Response-APDU buffer */ + rfalT4tRApduParam respAPDU; /*!< Response-APDU params */ + rfalIsoDepBufFormat tmpBuf; /*!< I-Block temporary buffer */ + uint16_t rApduBodyLen; /*!< Response Body Length */ + uint32_t FWT; /*!< Frame Waiting Time (1/fc) */ + uint32_t dFWT; /*!< Delta Frame Waiting Time (1/fc) */ + uint16_t FSx; /*!< Frame Size Device/Card (FSD or FSC) */ + uint8_t DID; /*!< Device ID */ +} ndefT4TContext; +#endif + +#if NDEF_FEATURE_T5T +/*! NFCV (Extended) System Information */ +typedef struct { + uint16_t numberOfBlock; /*!< Number of block */ + uint8_t UID[NDEF_NFCV_UID_LEN]; /*!< UID Value */ + uint8_t supportedCmd[NDEF_NFCV_SUPPORTED_CMD_LEN];/*!< Supported Commands list */ + uint8_t infoFlags; /*!< Information flags */ + uint8_t DFSID; /*!< DFSID Value */ + uint8_t AFI; /*!< AFI Value */ + uint8_t blockSize; /*!< Block Size Value */ + uint8_t ICRef; /*!< IC Reference */ +} ndefSystemInformation; + +/*! NDEF T5T sub context structure */ +typedef struct { + const uint8_t* uid; /*!< UID in Addressed mode, NULL: Non-addr/Selected mode*/ + uint8_t flags; /*!< Command flags */ + uint32_t TlvNDEFOffset; /*!< NDEF TLV message offset */ + uint8_t blockLen; /*!< T5T BLEN parameter */ + ndefSystemInformation sysInfo; /*!< System Information (when supported) */ + bool sysInfoSupported; /*!< System Information Supported flag */ + bool legacySTHighDensity; /*!< Legacy ST High Density flag */ + uint8_t txrxBuf[NDEF_T5T_TxRx_BUFF_SIZE];/*!< Tx Rx Buffer */ + uint8_t cacheBuf[NDEF_T5T_TxRx_BUFF_SIZE];/*!< Cache buffer */ + uint32_t cacheBlock; /*!< Block number of cached buffer */ + bool useMultipleBlockRead; /*!< Access multiple block read */ + bool stDevice; /*!< ST device */ +} ndefT5TContext; +#endif + +/*! NDEF context structure */ +typedef struct { + ndefDeviceType type; /*!< NDEF Device type */ + ndefDevice device; /*!< NDEF Device */ + ndefState state; /*!< Tag state e.g. NDEF_STATE_INITIALIZED */ + ndefCapabilityContainer cc; /*!< Capability Container */ + uint32_t messageLen; /*!< NDEF message length */ + uint32_t messageOffset; /*!< NDEF message offset */ + uint32_t areaLen; /*!< Area Length for NDEF storage */ + uint8_t ccBuf[NDEF_CC_BUF_LEN]; /*!< buffer for CC */ + const struct ndefPollerWrapperStruct* + ndefPollWrapper; /*!< pointer to array of function for wrapper */ + union { +#if NDEF_FEATURE_T1T + ndefT1TContext t1t; /*!< T1T context */ +#endif +#if NDEF_FEATURE_T2T + ndefT2TContext t2t; /*!< T2T context */ +#endif +#if NDEF_FEATURE_T3T + ndefT3TContext t3t; /*!< T3T context */ +#endif +#if NDEF_FEATURE_T4T + ndefT4TContext t4t; /*!< T4T context */ +#endif +#if NDEF_FEATURE_T5T + ndefT5TContext t5t; /*!< T5T context */ +#endif + } subCtx; /*!< Sub-context union */ +} ndefContext; + +/*! Wrapper structure to hold the function pointers on each tag type */ +typedef struct ndefPollerWrapperStruct +{ + ndefStatus (* pollerContextInitialization)(ndefContext *ctx, const ndefDevice *dev); /*!< ContextInitialization function pointer */ + ndefStatus (* pollerNdefDetect)(ndefContext *ctx, ndefInfo *info); /*!< NdefDetect function pointer */ + ndefStatus (* pollerReadBytes)(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); /*!< Read function pointer */ + ndefStatus (* pollerReadRawMessage)(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); /*!< ReadRawMessage function pointer */ +#if NDEF_FEATURE_FULL_API + ndefStatus (* pollerWriteBytes)(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator); /*!< Write function pointer */ + ndefStatus (* pollerWriteRawMessage)(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); /*!< WriteRawMessage function pointer */ + ndefStatus (* pollerTagFormat)(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); /*!< TagFormat function pointer */ + ndefStatus (* pollerWriteRawMessageLen)(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator); /*!< WriteRawMessageLen function pointer */ + ndefStatus (* pollerCheckPresence)(ndefContext *ctx); /*!< CheckPresence function pointer */ + ndefStatus (* pollerCheckAvailableSpace)(const ndefContext *ctx, uint32_t messageLen); /*!< CheckAvailableSpace function pointer */ + ndefStatus (* pollerBeginWriteMessage)(ndefContext *ctx, uint32_t messageLen); /*!< BeginWriteMessage function pointer */ + ndefStatus (* pollerEndWriteMessage)(ndefContext *ctx, uint32_t messageLen, bool writeTerminator); /*!< EndWriteMessage function pointer */ + ndefStatus (* pollerSetReadOnly)(ndefContext *ctx); /*!< SetReadOnly function pointer */ +#endif /* NDEF_FEATURE_FULL_API */ +} ndefPollerWrapper; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * \brief Return the device type + * + * This funtion returns the device type from the context + * + * \param[in] dev: ndef Device + * + * \return the device type + ***************************************************************************** + */ +ndefDeviceType ndefGetDeviceType(const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief Handle NDEF context activation + * + * This method performs the initialization of the NDEF context. + * It must be called after a successful + * anti-collision procedure and prior to any NDEF procedures such as NDEF + * detection procedure. + * + * \param[in] ctx : ndef Context + * \param[in] dev : ndef Device + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief NDEF Detection procedure + * + * This method performs the NDEF Detection procedure + * + * \param[in] ctx : ndef Context + * \param[out] info : ndef Information (optional parameter, NULL may be used when no NDEF Information is needed) + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : Detection failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerNdefDetect(ndefContext *ctx, ndefInfo *info); + + +/*! + ***************************************************************************** + * \brief Read data + * + * This method reads arbitrary length data + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start reading data + * \param[in] len : requested length + * \param[out] buf : buffer to place the data read from the tag + * \param[out] rcvdLen: received length + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); + + +/*! + ***************************************************************************** + * \brief Write data + * + * This method writes arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start writing data + * \param[in] buf : data to write + * \param[in] len : buf length + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len); + + +/*! + ***************************************************************************** + * \brief Read raw NDEF message + * + * This method reads a raw NDEF message. + * Prior to NDEF Read procedure, a successful ndefPollerNdefDetect() + * has to be performed. + * + * + * \param[in] ctx : ndef Context + * \param[out] buf : buffer to place the NDEF message + * \param[in] bufLen : buffer length + * \param[out] rcvdLen: received length + * \param[in] single : performs the procedure as part of a single NDEF read operation. "true" can be used when migrating from previous version of this API as only SINGLE NDEF READ was supported. "false" can be used to force the reading of the NDEF length (e.g. for TNEP). + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); + + +/*! + ***************************************************************************** + * \brief Write raw NDEF message + * + * This method writes a raw NDEF message. + * Prior to NDEF Write procedure, a successful ndefPollerNdefDetect() + * has to be performed. + * + * \param[in] ctx : ndef Context + * \param[in] buf : raw message buffer + * \param[in] bufLen : buffer length + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); + + +/*! + ***************************************************************************** + * \brief Format Tag + * + * This method formats a tag to make it ready for NDEF storage. + * cc and options parameters usage is described in each technology method + * (ndefT[2345]TPollerTagFormat) + * + * \param[in] ctx : ndef Context + * \param[in] cc : Capability Container + * \param[in] options : specific flags + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); + + +/*! + ***************************************************************************** + * \brief Write NDEF message length + * + * This method writes the NLEN field + * + * \param[in] ctx : ndef Context + * \param[in] rawMessageLen: len + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen); + + + /*! + ***************************************************************************** + * \brief Write an NDEF message + * + * Write the NDEF message to the tag + * + * \param[in] ctx: NDEF Context + * \param[in] message: Message to write + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerWriteMessage(ndefContext *ctx, const ndefMessage *message); + + +/*! + ***************************************************************************** + * \brief Check Presence + * + * This method checks whether an NFC tag is still present in the operating field + * + * \param[in] ctx : ndef Context + + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerCheckPresence(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief Check Available Space + * + * This method checks whether a NFC tag has enough space to write a message of a given length + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief Begin Write Message + * + * This method sets the L-field to 0 (T1T, T2T, T4T, T5T) or set the WriteFlag (T3T) and sets the message offset to the proper value according to messageLen + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief End Write Message + * + * This method updates the L-field value after the message has been written and resets the WriteFlag (for T3T only) + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief Set Read Only + * + * This method performs the transition from the READ/WRITE state to the READ-ONLY state + * + * \param[in] ctx : ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefPollerSetReadOnly(ndefContext *ctx); + + +#endif /* NDEF_POLLER_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_t2t.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_t2t.h new file mode 100644 index 0000000..b209fcd --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_t2t.h @@ -0,0 +1,351 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T2T + * + * NDEF T2T provides several functionalities required to + * perform NDEF message management with T2T tags. + * + * The most common interfaces are + *
  ndefT2TPollerContextInitialization() + *
  ndefT2TPollerNdefDetect() + *
  ndefT2TPollerReadRawMessage() + *
  ndefT2TPollerWriteRawMessage() + *
  ndefT2TPollerTagFormat() + * + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_T2T_H +#define NDEF_T2T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + /* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/*! + ***************************************************************************** + * \brief Handle T2T NDEF context activation + * + * This method performs the initialization of the NDEF context and handles + * the activation of the ISO-DEP layer. It must be called after a successful + * anti-collision procedure and prior to any NDEF procedures such as NDEF + * detection procedure. + * + * \param[in] ctx : ndef Context + * \param[in] dev : ndef Device + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief T2T NDEF Detection procedure + * + * This method performs the T2T NDEF Detection procedure + * + * + * \param[in] ctx : ndef Context + * \param[out] info : ndef Information (optional parameter, NULL may be used when no NDEF Information is needed) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : Detection failed (application or ccfile not found) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerNdefDetect(ndefContext *ctx, ndefInfo *info); + + +/*! + ***************************************************************************** + * \brief T2T Read data from tag memory + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] len : requested length + * \param[in] offset : file offset of where to start reading data + * \param[out] buf : buffer to place the data read from the tag + * \param[out] rcvdLen: received length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); + + +/*! + ***************************************************************************** + * \brief T2T write data to tag memory + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start writing data + * \param[in] buf : data to write + * \param[in] len : buf length + * \param[in] pad : pad remaining bytes of last modified block with 0s + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T2T Read raw NDEF message + * + * This method reads a raw NDEF message from the current selected file. + * Prior to NDEF Read procedure, a successful ndefT2TPollerNdefDetect() + * has to be performed. + * + * \param[in] ctx : ndef Context + * \param[out] buf : buffer to place the NDEF message + * \param[in] bufLen : buffer length + * \param[out] rcvdLen: received length + * \param[in] single : performs the procedure as part of a single NDEF read operation + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); + + +/*! + ***************************************************************************** + * \brief T2T Write raw NDEF message + * + * This method writes a raw NDEF message in the current selected file. + * Prior to NDEF Write procedure, a successful ndefT2TPollerNdefDetect() + * has to be performed. + * + * \warning Current selected file must not be changed between NDEF Detect + * procedure and NDEF Write procedure. If another file is selected before + * NDEF Write procedure, it is user responsibility to re-select NDEF file + * or to call ndefT2TPollerNdefDetect() to restore proper context. + * + * \param[in] ctx : ndef Context + * \param[in] buf : raw message buffer + * \param[in] bufLen : buffer length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); + + +/*! + ***************************************************************************** + * \brief T2T Write NDEF message length + * + * This method writes the NLEN field (V2 mapping) or the ENLEN (V3 mapping). + * + * \param[in] ctx : ndef Context + * \param[in] rawMessageLen : len + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T2T Format Tag + * + * This method formats a tag to make it ready for NDEF storage. + * The Capability Container block is written only for virgin tags. + * If the cc parameter is not provided (i.e. NULL), a default one is used + * with T2T_AreaSize = 48 bytes. + * Beware that formatting is on most tags a one time operation (OTP bits!!!!) + * Doing a wrong format may render your tag unusable. + * options parameter is not used for T2T Tag Format method + * + * \param[in] ctx : ndef Context + * \param[in] cc : Capability Container + * \param[in] options: specific flags + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); + + +/*! + ***************************************************************************** + * \brief T2T Check Presence + * + * This method checks whether a T2T tag is still present in the operating field + * + * \param[in] ctx : ndef Context + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerCheckPresence(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief T2T Check Available Space + * + * This method checks whether a T2T tag has enough space to write a message of a given length + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT2TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T2T Begin Write Message + * + * This method sets the L-field to 0 and sets the message offset to the proper value according to messageLen + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT2TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T2T End Write Message + * + * This method updates the L-field value after the message has been written + * + * \param[in] ctx : ndef Context + * \param[in] messageLen : message length + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT2TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T2T Set Read Only + * + * This method perform the transition from the READ/WRITE state to the READ-ONLY state + * + * \param[in] ctx : ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT2TPollerSetReadOnly(ndefContext *ctx); + + +#endif /* NDEF_T2T_H */ + +/** + * @} + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_t3t.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_t3t.h new file mode 100644 index 0000000..7201a6b --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_t3t.h @@ -0,0 +1,351 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T3T + * + * NDEF T3T provides several functionalities required to + * perform NDEF message management with T3T tags. + * + * The most common interfaces are + *
  ndefT3TPollerContextInitialization() + *
  ndefT3TPollerNdefDetect() + *
  ndefT3TPollerReadRawMessage() + *
  ndefT3TPollerWriteRawMessage() + *
  ndefT3TPollerTagFormat() + * + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_T3T_H +#define NDEF_T3T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + /* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/*! + ***************************************************************************** + * \brief Handle T3T NDEF context activation + * + * This method performs the initialization of the NDEF context and handles + * the activation of the ISO-DEP layer. It must be called after a successful + * anti-collision procedure and prior to any NDEF procedures such as NDEF + * detection procedure. + * + * \param[in] ctx : ndef Context + * \param[in] dev : ndef Device + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief T3T NDEF Detection procedure + * + * This method performs the T3T NDEF Detection procedure + * + * + * \param[in] ctx : ndef Context + * \param[out] info : ndef Information (optional parameter, NULL may be used when no NDEF Information is needed) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : Detection failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerNdefDetect(ndefContext *ctx, ndefInfo *info); + + +/*! + ***************************************************************************** + * \brief T3T Read data from file + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] len : requested length + * \param[in] offset : file offset of where to start reading data + * \param[out] buf : buffer to place the data read from the tag + * \param[out] rcvdLen: received length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); + + +/*! + ***************************************************************************** + * \brief T3T write data to file + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start writing data + * \param[in] buf : data to write + * \param[in] len : buf length + * \param[in] pad : pad remaining bytes of last modified block with 0s + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T3T Read raw NDEF message + * + * This method reads a raw NDEF message from the current selected file. + * Prior to NDEF Read procedure, a successful ndefT3TPollerNdefDetect() + * has to be performed. + * + * \param[in] ctx : ndef Context + * \param[out] buf : buffer to place the NDEF message + * \param[in] bufLen : buffer length + * \param[out] rcvdLen: received length + * \param[in] single : performs the procedure as part of a single NDEF read operation + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); + + +/*! + ***************************************************************************** + * \brief T3T Write raw NDEF message + * + * This method writes a raw NDEF message in the current selected file. + * Prior to NDEF Write procedure, a successful ndefT3TPollerNdefDetect() + * has to be performed. + * + * \warning Current selected file must not be changed between NDEF Detect + * procedure and NDEF Write procedure. If another file is selected before + * NDEF Write procedure, it is user responsibility to re-select NDEF file + * or to call ndefT3TPollerNdefDetect() to restore proper context. + * + * \param[in] ctx : ndef Context + * \param[in] buf : raw message buffer + * \param[in] bufLen : buffer length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); + + +/*! + ***************************************************************************** + * \brief T3T Write NDEF message length + * + * This method writes the NLEN field (V2 mapping) or the ENLEN (V3 mapping). + * + * \param[in] ctx : ndef Context + * \param[in] rawMessageLen : len + * \param[in] writeTerminator: unused + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T3T Format Tag + * + * This method formats a tag to make it ready for NDEF storage. + * cc parameter contains the Attribute Information Block fields + * If cc parameter is not provided (i.e. NULL), this method assumes + * that the AIB is already present. + * options parameter is not used for T3T Tag Format method + * + * + * \param[in] ctx : ndef Context + * \param[in] cc : Capability Container + * \param[in] options: specific flags + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); + + +/*! + ***************************************************************************** + * \brief T3T Check Presence + * + * This method checks whether a T3T tag is still present in the operating field + * + * \param[in] ctx : ndef Context + + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerCheckPresence(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief T3T Check Available Space + * + * This method checks whether a T3T tag has enough space to write a message of a given length + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT3TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T3T Begin Write Message + * + * This method sets the WriteFlag to the appropriate value before starting to write the NDEF message + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT3TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T3T End Write Message + * + * This method updates the Ln field of the AIB and resets the WriteFlag + * + * \param[in] ctx : ndef Context + * \param[in] messageLen : message length + * \param[in] writeTerminator: unused + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT3TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T3T Set Read Only + * + * This method perform the transition from the READ/WRITE state to the READ-ONLY state + * + * \param[in] ctx : ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT3TPollerSetReadOnly(ndefContext *ctx); + + +#endif /* NDEF_T3T_H */ + +/** + * @} + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_t4t.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_t4t.h new file mode 100644 index 0000000..2f70511 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_t4t.h @@ -0,0 +1,501 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T4T + * + * NDEF T4T provides several functionalities required to + * perform NDEF message management with T4T tags. + * + * The most common interfaces are + *
  ndefT4TPollerContextInitialization() + *
  ndefT4TPollerNdefDetect() + *
  ndefT4TPollerReadRawMessage() + *
  ndefT4TPollerWriteRawMessage() + *
  ndefT4TPollerTagFormat() + * + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_T4T_H +#define NDEF_T4T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T4T_MAPPING_VERSION_2_0 0x20U /*!< Mapping version 2.0 */ +#define NDEF_T4T_MAPPING_VERSION_3_0 0x30U /*!< Mapping version 3.0 */ + +/*! Minimun size for an APDU (corresponding to Select NDEF App) */ +#define NDEF_T4T_MIN_APDU_LEN 13U + +/*! Maximun Response-APDU response body length (short field coding) */ +#if RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN > (256 + RFAL_T4T_MAX_RAPDU_SW1SW2_LEN) +#define NDEF_T4T_MAX_RAPDU_BODY_LEN 256U +#else +#define NDEF_T4T_MAX_RAPDU_BODY_LEN (RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_MAX_RAPDU_SW1SW2_LEN) +#endif + +/*! Maximun Command-APDU data length (short field coding) */ +#if RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN > (255 + RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN + RFAL_T4T_LE_LEN) +#define NDEF_T4T_MAX_CAPDU_BODY_LEN 255U +#else +#define NDEF_T4T_MAX_CAPDU_BODY_LEN (RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - (RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN + RFAL_T4T_LE_LEN)) +#endif + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ +#define ndefT4TIsReadAccessGranted(r) ( ((r) == 0x00U) || (((r) >= 0x80U) && ((r) <= 0xFEU)) ) /*!< Read access status */ +#define ndefT4TIsWriteAccessGranted(w) ( ((w) == 0x00U) || (((w) >= 0x80U) && ((w) <= 0xFEU)) ) /*!< Write access status */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Handle T4T NDEF context activation + * + * This method performs the initialization of the NDEF context and handles + * the activation of the ISO-DEP layer. It must be called after a successful + * anti-collision procedure and prior to any NDEF procedures such as NDEF + * detection procedure. + * + * \param[in] ctx : ndef Context + * \param[in] dev : ndef Device + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief T4T NDEF Detection procedure + * + * This method performs the T4T NDEF Detection procedure + * + * + * \param[in] ctx : ndef Context + * \param[out] info : ndef Information (optional parameter, NULL may be used when no NDEF Information is needed) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : Detection failed (application or ccfile not found) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info); + + +/*! + ***************************************************************************** + * \brief T4T Select NDEF Tag Application + * + * This method sends the Select NDEF tag application. If V2 Tag Application + * is not found, a Select NDEF tag V1 application is sent/ + * + * \param[in] ctx : ndef Context + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : Application not found + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerSelectNdefTagApplication(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief T4T Select File + * + * This method sends a Select File Command-APDU. + * + * The following fields of the ndef Context must be filled up before calling + * this method: + * - devType: device type + * - subCtx.t4t.mv1Flag: Mapping version 1 flag + * + * \param[in] ctx : ndef Context + * \param[in] fileId : file identifier + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : File not found + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerSelectFile(ndefContext *ctx, const uint8_t *fileId); + + +/*! + ***************************************************************************** + * \brief T4T ReadBinary + * + * This method reads the data from the tag using a single + * ReadBinary command + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to star reading data; valid range 0000h-7FFFh + * \param[in] len : requested length (short field coding) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerReadBinary(ndefContext *ctx, uint16_t offset, uint8_t len); + + +/*! + ***************************************************************************** + * \brief T4T ReadBinary with ODO + * + * This method reads the data from the tag using a single + * ReadBinary ODO command + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to star reading data; valid range 0000h-7FFFh + * \param[in] len : requested length (short field coding) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerReadBinaryODO(ndefContext *ctx, uint32_t offset, uint8_t len); + + +/*! + ***************************************************************************** + * \brief T4T Read data from file + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] len : requested length + * \param[in] offset : file offset of where to start reading data + * \param[out] buf : buffer to place the data read from the tag + * \param[out] rcvdLen: received length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); + +/*! + ***************************************************************************** + * \brief T4T WriteBinary + * + * This method writes the data to the tag using a single + * WriteBinary command + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to star reading data; valid range 0000h-7FFFh + * \param[in] data : data to be written + * \param[in] len : data length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerWriteBinary(ndefContext *ctx, uint16_t offset, const uint8_t *data, uint8_t len); + + +/*! + ***************************************************************************** + * \brief T4T WriteBinary with ODO + * + * This method writes the data to the tag using a single + * WriteBinary ODO command + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to star reading data; valid range 0000h-7FFFh + * \param[in] data : data to be written + * \param[in] len : data length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerWriteBinaryODO(ndefContext *ctx, uint32_t offset, const uint8_t *data, uint8_t len); + +/*! + ***************************************************************************** + * \brief T4T write data to file + * + * This method reads arbitrary length data from the current selected file + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start writing data + * \param[in] buf : data to write + * \param[in] len : buf length + * \param[in] pad : unused + * \param[in] writeTerminator: unused + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T4T Read raw NDEF message + * + * This method reads a raw NDEF message from the current selected file. + * Prior to NDEF Read procedure, a successfull ndefT4TPollerNdefDetect() + * has to be performed. + * + * \warning Current selected file must not be changed between NDEF Detect + * procedure and NDEF Read procedure. If another file is selected before + * NDEF Read procedure, it is user responsibility to re-select NDEF file + * or to call ndefT4TPollerNdefDetect() to restore proper context. + * + * \param[in] ctx : ndef Context + * \param[out] buf : buffer to place the NDEF message + * \param[in] bufLen : buffer length + * \param[out] rcvdLen: received length + * \param[in] single : performs the procedure as part of a single NDEF read operation + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); + + +/*! + ***************************************************************************** + * \brief T4T Write raw NDEF message + * + * This method writes a raw NDEF message in the current selected file. + * Prior to NDEF Write procedure, a successfull ndefT4TPollerNdefDetect() + * has to be performed. + * + * \warning Current selected file must not be changed between NDEF Detect + * procedure and NDEF Write procedure. If another file is selected before + * NDEF Write procedure, it is user responsibility to re-select NDEF file + * or to call ndefT4TPollerNdefDetect() to restore proper context. + * + * \param[in] ctx : ndef Context + * \param[in] buf : raw message buffer + * \param[in] bufLen : buffer length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); + + +/*! + ***************************************************************************** + * \brief T4T Write NDEF message length + * + * This method writes the NLEN field (V2 mapping) or the ENLEN (V3 mapping). + * + * \param[in] ctx : ndef Context + * \param[in] rawMessageLen : len + * \param[in] writeTerminator: unused + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T4T Format Tag + * + * This method formats a tag to make it ready for NDEF storage. In case of T4T, + * it writes NLEN/ENLEN=0 to the NDEF File. + * cc and options parameters are not used for T4T Tag Format method. + * + * \param[in] ctx : ndef Context + * \param[in] cc : Capability Container + * \param[in] options: specific flags + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed (SW1SW2 <> 9000h) + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); + + +/*! + ***************************************************************************** + * \brief T4T Check Presence + * + * This method checks whether a T4T tag is still present in the operating field + * + * \param[in] ctx : ndef Context + + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerCheckPresence(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief T4T Check Available Space + * + * This method checks whether a T4T tag has enough space to write a message of a given length + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT4TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T4T Begin Write Message + * + * This method sets the L-field to 0 + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT4TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T4T End Write Message + * + * This method updates the L-field value after the message has been written + * + * \param[in] ctx : ndef Context + * \param[in] messageLen : message length + * \param[in] writeTerminator: unused + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT4TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T4T Set Read Only + * + * This method perform the transition from the READ/WRITE state to the READ-ONLY state + * + * \param[in] ctx : ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT4TPollerSetReadOnly(ndefContext *ctx); + + +#endif /* NDEF_T4T_H */ + +/** + * @} + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t.h new file mode 100644 index 0000000..4600375 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t.h @@ -0,0 +1,482 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T5T + * + * NDEF T5T provides several functionalities required to + * perform NDEF message management with T5T tags. + * + * The most common interfaces are: + * + *
  ndefT5TPollerContextInitialization() + *
  ndefT5TPollerNdefDetect() + *
  ndefT5TPollerReadBytes() + *
  ndefT5TPollerWriteBytes() + *
  ndefT5TPollerReadRawMessage() + *
  ndefT5TPollerWriteRawMessage() + *
  ndefT5TPollerTagFormat() + *
  ndefT5TPollerCheckPresence() + *
  ndefT5TPollerCheckAvailableSpace() + *
  ndefT5TPollerSetReadOnly() + * + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_T5T_H +#define NDEF_T5T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T5T_MAPPING_VERSION_1_0 (1U << 6) /*!< T5T Version 1.0 */ + +#define NDEF_SYSINFO_FLAG_DFSID_POS (0U) /*!< Info flags DFSID flag position */ +#define NDEF_SYSINFO_FLAG_AFI_POS (1U) /*!< Info flags AFI flag position */ +#define NDEF_SYSINFO_FLAG_MEMSIZE_POS (2U) /*!< Info flags Memory Size flag position */ +#define NDEF_SYSINFO_FLAG_ICREF_POS (3U) /*!< Info flags IC reference flag position */ +#define NDEF_SYSINFO_FLAG_MOI_POS (4U) /*!< Info flags MOI flag position */ +#define NDEF_SYSINFO_FLAG_CMDLIST_POS (5U) /*!< Info flags Command List flag position */ +#define NDEF_SYSINFO_FLAG_CSI_POS (6U) /*!< Info flags CSI flag position */ +#define NDEF_SYSINFO_FLAG_LEN_POS (7U) /*!< Info flags Length position */ + +#define NDEF_CMDLIST_READSINGLEBLOCK_POS (0U) /*!< Cmd List: ReadSingleBlock position */ +#define NDEF_CMDLIST_WRITESINGLEBLOCK_POS (1U) /*!< Cmd List: WriteSingleBlock position */ +#define NDEF_CMDLIST_LOCKSINGLEBLOCK_POS (2U) /*!< Cmd List: LockSingleBlock position */ +#define NDEF_CMDLIST_READMULTIPLEBLOCKS_POS (3U) /*!< Cmd List: ReadMultipleBlocks position */ +#define NDEF_CMDLIST_WRITEMULTIPLEBLOCKS_POS (4U) /*!< Cmd List: WriteMultipleBlocks position */ +#define NDEF_CMDLIST_SELECT_POS (5U) /*!< Cmd List: SelectSupported position */ +#define NDEF_CMDLIST_RESETTOREADY_POS (6U) /*!< Cmd List: ResetToReady position */ +#define NDEF_CMDLIST_GETMULTIPLEBLOCKSECSTATUS_POS (7U) /*!< Cmd List: GetMultipleBlockSecStatus position */ + +#define NDEF_CMDLIST_WRITEAFI_POS (0U) /*!< Cmd List: WriteAFI position */ +#define NDEF_CMDLIST_LOCKAFI_POS (1U) /*!< Cmd List: LockAFI position */ +#define NDEF_CMDLIST_WRITEDSFID_POS (2U) /*!< Cmd List: WriteDSFID position */ +#define NDEF_CMDLIST_LOCKDSFID_POS (3U) /*!< Cmd List: LockDSFID position */ +#define NDEF_CMDLIST_GETSYSTEMINFORMATION_POS (4U) /*!< Cmd List: GetSystemInformation position */ +#define NDEF_CMDLIST_CUSTOMCMDS_POS (5U) /*!< Cmd List: CustomCmds position */ +#define NDEF_CMDLIST_FASTREADMULTIPLEBLOCKS_POS (6U) /*!< Cmd List: FastReadMultipleBlocks position */ + +#define NDEF_CMDLIST_EXTREADSINGLEBLOCK_POS (0U) /*!< Cmd List: ExtReadSingleBlock position */ +#define NDEF_CMDLIST_EXTWRITESINGLEBLOCK_POS (1U) /*!< Cmd List: ExtWriteSingleBlock position */ +#define NDEF_CMDLIST_EXTLOCKSINGLEBLOCK_POS (2U) /*!< Cmd List: ExtLockSingleBlock position */ +#define NDEF_CMDLIST_EXTREADMULTIPLEBLOCKS_POS (3U) /*!< Cmd List: ExtReadMultipleBlocks position */ +#define NDEF_CMDLIST_EXTWRITEMULTIPLEBLOCKS_POS (4U) /*!< Cmd List: ExtWriteMultipleBlocks position */ +#define NDEF_CMDLIST_EXTGETMULTIPLEBLOCKSECSTATUS_POS (5U) /*!< Cmd List: ExtGetMultipleBlockSecStatus position */ +#define NDEF_CMDLIST_FASTEXTENDEDREADMULTIPLEBLOCKS_POS (6U) /*!< Cmd List: FastExtendedReadMultipleBlocks position */ + +#define NDEF_T5T_CC_MAGIC_1_BYTE_ADDR_MODE 0xE1U /*!< T5T CC Magic Number (1-byte Addres Mode) */ +#define NDEF_T5T_CC_MAGIC_2_BYTE_ADDR_MODE 0xE2U /*!< T5T CC Magic Number (2-byte Addres Mode) */ +#define NDEF_T5T_CC_LEN_4_BYTES 4U /*!< T5T CC Length (4 bytes) */ +#define NDEF_T5T_CC_LEN_8_BYTES 8U /*!< T5T CC Length (8 bytes) */ +#define NDEF_T5T_FORMAT_OPTION_NFC_FORUM 1U /*!< Format tag according to NFC Forum MLEN computation */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ +#define ndefT5TMajorVersion(V) ((uint8_t)( (V) >> 6U)) /*!< Get major version */ +#define ndefT5TMinorVersion(V) ((uint8_t)(((V) >> 4U) & 3U)) /*!< Get minor version */ + +#define ndefT5TSysInfoDFSIDPresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_DFSID_POS) & 0x01U) /*!< Returns DFSID presence flag */ +#define ndefT5TSysInfoAFIPresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_AFI_POS) & 0x01U) /*!< Returns AFI presence flag */ +#define ndefT5TSysInfoMemSizePresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_MEMSIZE_POS) & 0x01U) /*!< Returns Memory size presence flag */ +#define ndefT5TSysInfoICRefPresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_ICREF_POS) & 0x01U) /*!< Returns IC Reference presence flag */ +#define ndefT5TSysInfoMOIValue(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_MOI_POS) & 0x01U) /*!< Returns MOI value */ +#define ndefT5TSysInfoCmdListPresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_CMDLIST_POS) & 0x01U) /*!< Returns Command List presence flag */ +#define ndefT5TSysInfoCSIPresent(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_CSI_POS) & 0x01U) /*!< Returns CSI presence flag */ +#define ndefT5TSysInfoLenValue(infoFlags) (((infoFlags) >> NDEF_SYSINFO_FLAG_LEN_POS) & 0x01U) /*!< Returns Info flag length value */ + +#define ndefT5TSysInfoReadSingleBlockSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_READSINGLEBLOCK_POS) & 0x01U) /*!< Returns ReadSingleBlock support flag */ +#define ndefT5TSysInfoWriteSingleBlockSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_WRITESINGLEBLOCK_POS) & 0x01U) /*!< Returns WriteSingleBlock support flag */ +#define ndefT5TSysInfoLockSingleBlockSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_LOCKSINGLEBLOCK_POS) & 0x01U) /*!< Returns LockSingleBlock support flag */ +#define ndefT5TSysInfoReadMultipleBlocksSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_READMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns ReadMultipleBlocks support flag */ +#define ndefT5TSysInfoWriteMultipleBlocksSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_WRITEMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns WriteMultipleBlocks support flag */ +#define ndefT5TSysInfoSelectSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_SELECT_POS) & 0x01U) /*!< Returns SelectSupported support flag */ +#define ndefT5TSysInfoResetToReadySupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_RESETTOREADY_POS) & 0x01U) /*!< Returns ResetToReady support flag */ +#define ndefT5TSysInfoGetMultipleBlockSecStatusSupported(cmdList) (((cmdList)[0] >> NDEF_CMDLIST_GETMULTIPLEBLOCKSECSTATUS_POS) & 0x01U) /*!< Returns GetMultipleBlockSecStatus support flag */ + +#define ndefT5TSysInfoWriteAFISupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_WRITEAFI_POS) & 0x01U) /*!< Returns WriteAFI support flag */ +#define ndefT5TSysInfoLockAFISupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_LOCKAFI_POS) & 0x01U) /*!< Returns LockAFI support flag */ +#define ndefT5TSysInfoWriteDSFIDSupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_WRITEDSFID_POS) & 0x01U) /*!< Returns WriteDSFID support flag */ +#define ndefT5TSysInfoLockDSFIDSupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_LOCKDSFID_POS) & 0x01U) /*!< Returns LockDSFID support flag */ +#define ndefT5TSysInfoGetSystemInformationSupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_GETSYSTEMINFORMATION_POS) & 0x01U) /*!< Returns GetSystemInformation support flag */ +#define ndefT5TSysInfoCustomCmdsSupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_CUSTOMCMDS_POS) & 0x01U) /*!< Returns CustomCmds support flag */ +#define ndefT5TSysInfoFastReadMultipleBlocksSupported(cmdList) (((cmdList)[1] >> NDEF_CMDLIST_FASTREADMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns FastReadMultipleBlocks support flag */ + +#define ndefT5TSysInfoExtReadSingleBlockSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTREADSINGLEBLOCK_POS) & 0x01U) /*!< Returns ExtReadSingleBlock support flag */ +#define ndefT5TSysInfoExtWriteSingleBlockSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTWRITESINGLEBLOCK_POS) & 0x01U) /*!< Returns ExtWriteSingleBlock support flag */ +#define ndefT5TSysInfoExtLockSingleBlockSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTLOCKSINGLEBLOCK_POS) & 0x01U) /*!< Returns ExtLockSingleBlock support flag */ +#define ndefT5TSysInfoExtReadMultipleBlocksSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTREADMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns ExtReadMultipleBlocks support flag */ +#define ndefT5TSysInfoExtWriteMultipleBlocksSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTWRITEMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns ExtWriteMultipleBlocks support flag */ +#define ndefT5TSysInfoExtGetMultipleBlockSecStatusSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_EXTGETMULTIPLEBLOCKSECSTATUS_POS) & 0x01U) /*!< Returns ExtGetMultipleBlockSecStatus support flag */ +#define ndefT5TSysInfoFastExtendedReadMultipleBlocksSupported(cmdList) (((cmdList)[2] >> NDEF_CMDLIST_FASTEXTENDEDREADMULTIPLEBLOCKS_POS) & 0x01U) /*!< Returns FastExtendedReadMultipleBlocks support flag */ + +#define ndefT5TInvalidateCache(ctx) { (ctx)->subCtx.t5t.cacheBlock = 0xFFFFFFFFU; } /*!< Invalidate the internal cache, before reading a buffer */ +#define ndefT5TIsValidCache(ctx, block) ( (ctx)->subCtx.t5t.cacheBlock == (block) ) /*!< Check the internal cache is valid to avoid useless read */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! T5T Access mode */ +typedef enum { + NDEF_T5T_ACCESS_MODE_SELECTED, + NDEF_T5T_ACCESS_MODE_ADDRESSED, + NDEF_T5T_ACCESS_MODE_NON_ADDRESSED, +} ndefT5TAccessMode; + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * \brief Set T5T access mode + * + * This method allows to set the access mode, among addressed, non-addressed + * and selected modes. + * It must be called before calling ndefT5TPollerContextInitialization(). + * + * \param[in] mode : access mode + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerSetAccessMode(ndefT5TAccessMode mode); + + +#ifdef TEST_NDEF +/*! + ***************************************************************************** + * \brief Control the Multiple Read Block mode + * + * This method allows to turn on of off the Read Multiple Block feature. + * It will be enabled when the MBREAD bit is set in the CC file. + * It must be called after calling ndefT5TPollerContextInitialization() and + * before ndefT5TPollerNdefDetect(). + * + * \param[in] ctx : ndef Context + * \param[in] enable : enable the feature or not + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerMultipleBlockRead(ndefContext *ctx, bool enable); +#endif + + +/*! + ***************************************************************************** + * \brief Handle T5T NDEF context activation + * + * This method performs the initialisation of the NDEF context. + * It must be called after a successfull + * anticollision procedure and prior to any NDEF procedures such as NDEF + * detection procedure. + * + * \param[in] ctx : ndef Context + * \param[in] dev : ndef Device + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief T5T NDEF Detection procedure + * + * This method performs the T5T NDEF Detection procedure + * + * + * \param[in] ctx : ndef Context + * \param[out] info : ndef Information (optional parameter, NULL may be used when no NDEF Information is needed) + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : Detection failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerNdefDetect(ndefContext *ctx, ndefInfo *info); + + +/*! + ***************************************************************************** + * \brief T5T Read data from tag memory + * + * This method reads arbitrary length data from tag memory + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset of where to start reading data + * \param[in] len : requested length + * \param[out] buf : buffer to place the data read from the tag + * \param[out] rcvdLen: received length + * + * \return ERR_WRONG_STATE: Library not initialized or mode not set + * \return ERR_REQUEST : Read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen); + + +/*! + ***************************************************************************** + * \brief T5T Write data to tag memory + * + * This method writes arbitrary length data to tag memory + * + * \param[in] ctx : ndef Context + * \param[in] offset : file offset where to start writing data + * \param[in] buf : data to write + * \param[in] len : buf length + * \param[in] pad : pad remaining bytes of last modified block with 0s + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_WRONG_STATE: Library not initialized or mode not set + * \return ERR_REQUEST : Write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T5T Read raw NDEF message + * + * This method reads a raw NDEF message from the current selected file. + * Prior to NDEF Read procedure, a successfull ndefT5TPollerNdefDetect() + * has to be performed. + * + * \param[in] ctx : ndef Context + * \param[out] buf : buffer to place the NDEF message + * \param[in] bufLen : buffer length + * \param[out] rcvdLen: received length + * \param[in] single : performs the procedure as part of a single NDEF read operation + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : read failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single); + + +/*! + ***************************************************************************** + * \brief T5T Write raw NDEF message + * + * This method writes a raw NDEF message in the current selected file. + * Prior to NDEF Write procedure, a successfull ndefT5TPollerNdefDetect() + * has to be performed. + * + * \param[in] ctx : ndef Context + * \param[in] buf : raw message buffer + * \param[in] bufLen : buffer length + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen); + + +/*! + ***************************************************************************** + * \brief T5T Write NDEF message length + * + * This method writes the L field to the tag memory + * + * \param[in] ctx : ndef Context + * \param[in] rawMessageLen : len + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T5T Format Tag + * + * This method formats a tag to make it ready for NDEF storage. + * When the cc parameter is provided, the Capability Container is initialized + * with the value provided by the user. + * When the cc parameter is not provided (i.e. NULL), this method + * retrieves the appropriate CC field from (Extended) Get System Information + * or returns ERR_REQUEST if (Extended) Get System Information is not supported. + * The option parameter is used in case of NULL cc parameter to choose + * between Android CC format (default when option = 0) + * or NFC Forum Format (option = NDEF_T5T_FORMAT_OPTION_NFC_FORUM) + * + * + * \param[in] ctx : ndef Context + * \param[in] cc : Capability Container + * \param[in] options : specific flags + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_REQUEST : write failed + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options); + + +/*! + ***************************************************************************** + * \brief T5T Check Presence + * + * This method checks whether a T5T tag is still present in the operating field + * + * \param[in] ctx : ndef Context + + * + * \return ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerCheckPresence(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief T5T Check Available Space + * + * This method checks whether a T5T tag has enough space to write a message of a given length + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT5TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T5T Begin Write Message + * + * This method sets the L-field to 0 and sets the message offset to the proper value according to messageLen + * + * \param[in] ctx : ndef Context + * \param[in] messageLen: message length + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT5TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen); + + +/*! + ***************************************************************************** + * \brief T5T End Write Message + * + * This method updates the L-field value after the message has been written + * + * \param[in] ctx : ndef Context + * \param[in] messageLen : message length + * \param[in] writeTerminator: write Terminator TLV after data + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NOMEM : not enough space + * \return ERR_NONE : Enough space for message of messageLen length + ***************************************************************************** + */ +ndefStatus ndefT5TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator); + + +/*! + ***************************************************************************** + * \brief T5T Set Read Only + * + * This method performs the transition from the READ/WRITE state to the READ-ONLY state + * + * \param[in] ctx : ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerSetReadOnly(ndefContext *ctx); + + +#endif /* NDEF_T5T_H */ + +/** + * @} + */ diff --git a/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t_hal.h b/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t_hal.h new file mode 100644 index 0000000..435fda6 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/include/poller/ndef_t5t_hal.h @@ -0,0 +1,209 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum Tags + * + * NDEF provides several functionalities required to perform NFC NDEF activities. + *
The NDEF encapsulates the different tag technologies (T2T, T3T, T4AT, T4BT, T5T) + * into a common and easy to use interface. + * + * This file provides the hardware-dependent API to adapt to a given platform + * to benefit from the NDEF generic functionalities. + * The main functions are: + * + *
  ndefT5TisSTDevice() + *
  ndefT5TisT5TDeviceType() + *
  ndefT5TPollerAccessMode() + *
  ndefT5TGetBlockLength() + *
  ndefT5TGetMemoryConfig() + *
  ndefT5TIsMultipleBlockReadSupported() + *
  ndefT5TIsDevicePresent() + *
  ndefT5TLockDevice() + * + * \addtogroup NDEF + * @{ + * + */ + + +#ifndef NDEF_T5T_HAL_H +#define NDEF_T5T_HAL_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_config.h" +#include "ndef_poller.h" +#include "ndef_t5t.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ***************************************************************************** + * \brief Return whether the device type is a STMicroelectronics device + * + * \param[in] dev: ndef Device + * + * \return true if it is a STMicroelectronics device + ***************************************************************************** + */ +bool ndefT5TisSTDevice(const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief Return whether the device type is a T5T device + * + * \param[in] dev: ndef Device + * + * \return true if it is a T5T device + ***************************************************************************** + */ +bool ndefT5TisT5TDevice(const ndefDevice *dev); + + +/*! + ***************************************************************************** + * \brief Set T5T device access mode + * + * \param[in] ctx: ndef Context + * \param[in] dev: ndef Device + * \param[in] mode: Acces mode + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TPollerAccessMode(ndefContext *ctx, const ndefDevice *dev, ndefT5TAccessMode mode); + + +/*! + ***************************************************************************** + * \brief Get Block length + * + * This function returns the block length, in bytes + * + * \param[in] ctx: ndef Context + * + * \return 0 if invalid parameter or the block length + ***************************************************************************** + */ +uint8_t ndefT5TGetBlockLength(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief Get the memory configuration + * + * This function provides the number of blocks and the block size in the + * T5T system information structure. + * + * \param[in] ctx: ndef Context + * + * \return ERR_PARAM: Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TGetMemoryConfig(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief Return whether the device supports Multiple block read + * + * \param[in] ctx: ndef Context + * + * \return true or false + ***************************************************************************** + */ +bool ndefT5TIsMultipleBlockReadSupported(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief Check Presence + * + * This method checks whether an NFC tag is still present in the operating field + * + * \param[in] ctx : ndef Context + * + * \return ERR_WRONG_STATE : Library not initialized or mode not set + * \return ERR_PARAM : Invalid parameter + * \return ERR_PROTO : Protocol error + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TIsDevicePresent(ndefContext *ctx); + + +/*! + ***************************************************************************** + * \brief This function locks the device + * + * \param[in] ctx: ndef Context + * + * \return ERR_PARAM : Invalid parameter + * \return ERR_NONE : No error + ***************************************************************************** + */ +ndefStatus ndefT5TLockDevice(ndefContext *ctx); + + +#endif /* NDEF_T5T_HAL_H */ + +/** + * @} + * + */ diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_message.c b/components/spi-st25r3911b/NDEF/source/message/ndef_message.c new file mode 100644 index 0000000..390059f --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_message.c @@ -0,0 +1,317 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF message + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_message.h" +#include "utils.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_MAX_RECORD 10U /*!< Maximum number of records */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ +static uint8_t ndefRecordPoolIndex = 0; + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*****************************************************************************/ +static ndefRecord* ndefAllocRecord(void) +{ + static ndefRecord ndefRecordPool[NDEF_MAX_RECORD]; + + if (ndefRecordPoolIndex >= NDEF_MAX_RECORD) + { + return NULL; + } + + return &ndefRecordPool[ndefRecordPoolIndex++]; +} + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ +/*****************************************************************************/ + + +ndefStatus ndefMessageInit(ndefMessage* message) +{ + if (message == NULL) + { + return ERR_PARAM; + } + + message->record = NULL; + message->info.length = 0; + message->info.recordCount = 0; + + ndefRecordPoolIndex = 0; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefMessageGetInfo(const ndefMessage* message, ndefMessageInfo* info) +{ + ndefRecord* record; + uint32_t length = 0; + uint32_t recordCount = 0; + + if ( (message == NULL) || (info == NULL) ) + { + return ERR_PARAM; + } + + record = message->record; + + while (record != NULL) + { + length += ndefRecordGetLength(record); + recordCount++; + + record = record->next; + } + + info->length = length; + info->recordCount = recordCount; + + return ERR_NONE; +} + + +/*****************************************************************************/ +uint32_t ndefMessageGetRecordCount(const ndefMessage* message) +{ + ndefMessageInfo info; + + if (ndefMessageGetInfo(message, &info) == ERR_NONE) + { + return info.recordCount; + } + + return 0; +} + + +/*****************************************************************************/ +ndefStatus ndefMessageAppend(ndefMessage* message, ndefRecord* record) +{ + if ( (message == NULL) || (record == NULL) ) + { + return ERR_PARAM; + } + + record->next = NULL; + + if (message->record == NULL) + { + message->record = record; + + /* Set both Message Begin and Message End bits */ + ndefHeaderSetMB(record); + /* Record is appended so it is the last in the list, set the Message End bit */ + ndefHeaderSetME(record); + } + else + { + ndefRecord* current = message->record; + + /* Go through the list of records */ + while (current->next != NULL) + { + current = current->next; + } + + /* Clear the Message End bit to the record before the one being appended */ + ndefHeaderClearME(current); + + /* Append to the last record */ + current->next = record; + + /* Clear the Message Begin bit of appended record */ + ndefHeaderClearMB(record); + /* Record is appended so it is the last in the list, set the Message End bit */ + ndefHeaderSetME(record); + } + + message->info.length += ndefRecordGetLength(record); + message->info.recordCount += 1U; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefMessageDecode(const ndefConstBuffer* bufPayload, ndefMessage* message) +{ + ndefStatus err; + uint32_t offset; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) ) + { + return ERR_PARAM; + } + + err = ndefMessageInit(message); + if (err != ERR_NONE) + { + return err; + } + + offset = 0; + while (offset < bufPayload->length) + { + ndefConstBuffer bufRecord; + ndefRecord* record = ndefAllocRecord(); + if (record == NULL) + { + return ERR_NOMEM; + } + bufRecord.buffer = &bufPayload->buffer[offset]; + bufRecord.length = bufPayload->length - offset; + err = ndefRecordDecode(&bufRecord, record); + if (err != ERR_NONE) + { + return err; + } + offset += ndefRecordGetLength(record); + + err = ndefMessageAppend(message, record); + if (err != ERR_NONE) + { + return err; + } + } + + return ERR_NONE; +} + + +#if NDEF_FEATURE_FULL_API +/*****************************************************************************/ +ndefStatus ndefMessageEncode(const ndefMessage* message, ndefBuffer* bufPayload) +{ + ndefStatus err; + ndefMessageInfo info = {.length = 0U}; + ndefRecord* record; + uint32_t offset; + uint32_t remainingLength; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) ) + { + return ERR_PARAM; + } + + err = ndefMessageGetInfo(message, &info); + if ( (err != ERR_NONE) || (bufPayload->length < info.length) ) + { + bufPayload->length = info.length; + return ERR_NOMEM; + } + + /* Get the first record */ + record = ndefMessageGetFirstRecord(message); + offset = 0; + remainingLength = bufPayload->length; + + while (record != NULL) + { + ndefBuffer bufRecord; + bufRecord.buffer = &bufPayload->buffer[offset]; + bufRecord.length = remainingLength; + err = ndefRecordEncode(record, &bufRecord); + if (err != ERR_NONE) + { + bufPayload->length = info.length; + return err; + } + offset += bufRecord.length; + remainingLength -= bufRecord.length; + + record = ndefMessageGetNextRecord(record); + } + + bufPayload->length = offset; + return ERR_NONE; +} +#endif + + +#if NDEF_FEATURE_FULL_API +/*****************************************************************************/ +ndefRecord* ndefMessageFindRecordType(ndefMessage* message, uint8_t tnf, const ndefConstBuffer8* bufType) +{ + ndefRecord* record; + + record = ndefMessageGetFirstRecord(message); + + while (record != NULL) + { + if (ndefRecordTypeMatch(record, tnf, bufType) == true) + { + return record; + } + + record = ndefMessageGetNextRecord(record); + } + + return record; +} +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_record.c b/components/spi-st25r3911b/NDEF/source/message/ndef_record.c new file mode 100644 index 0000000..1c900a7 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_record.c @@ -0,0 +1,623 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF record + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_message.h" +#include "ndef_types.h" +#include "utils.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define ndefBufferIsInvalid(buf) (((buf)->buffer == NULL) && ((buf)->length != 0U)) + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*****************************************************************************/ +ndefStatus ndefRecordReset(ndefRecord* record) +{ + ndefConstBuffer8 bufEmpty8 = { NULL , 0 }; + ndefConstBuffer bufEmpty = { NULL , 0 }; + + if (record == NULL) + { + return ERR_PARAM; + } + + /* Set the MB and ME bits */ + record->header = ndefHeader(1U, 1U, 0U, 0U, 0U, NDEF_TNF_EMPTY); + + (void)ndefRecordSetType(record, NDEF_TNF_EMPTY, &bufEmpty8); + + (void)ndefRecordSetId(record, &bufEmpty8); + + /* Set the SR bit */ + (void)ndefRecordSetPayload(record, &bufEmpty); + + record->ndeftype = NULL; + + record->next = NULL; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordInit(ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType, const ndefConstBuffer8* bufId, const ndefConstBuffer* bufPayload) +{ + if (record == NULL) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + (void)ndefRecordSetType(record, tnf, bufType); + + (void)ndefRecordSetId(record, bufId); + + (void)ndefRecordSetPayload(record, bufPayload); + + return ERR_NONE; +} + + +/*****************************************************************************/ +uint32_t ndefRecordGetHeaderLength(const ndefRecord* record) +{ + uint32_t length; + + if (record == NULL) + { + return 0; + } + + length = sizeof(uint8_t); /* header (MB:1 + ME:1 + CF:1 + SR:1 + IL:1 + TNF:3 => 8 bits) */ + length += sizeof(uint8_t); /* Type length */ + if (ndefHeaderIsSetSR(record)) + { + length += sizeof(uint8_t); /* Short record */ + } + else + { + length += sizeof(uint32_t); /* Standard record */ + } + if (ndefHeaderIsSetIL(record)) + { + length += sizeof(uint8_t); /* Id length */ + } + length += record->typeLength; /* Type */ + length += record->idLength; /* Id */ + + return length; +} + + +/*****************************************************************************/ +uint32_t ndefRecordGetLength(const ndefRecord* record) +{ + uint32_t length; + + length = ndefRecordGetHeaderLength(record); /* Header */ + length += ndefRecordGetPayloadLength(record); /* Payload */ + + return length; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordSetType(ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType) +{ + if ( (record == NULL) || + (bufType == NULL) || ndefBufferIsInvalid(bufType) ) + { + return ERR_PARAM; + } + + ndefHeaderSetTNF(record, tnf); + + record->typeLength = bufType->length; + record->type = bufType->buffer; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordGetType(const ndefRecord* record, uint8_t* tnf, ndefConstBuffer8* bufType) +{ + /* Allow to get either tnf or bufType */ + if ( (record == NULL) || ((tnf == NULL) && (bufType == NULL)) ) + { + return ERR_PARAM; + } + + if (tnf != NULL) + { + *tnf = ndefHeaderTNF(record); + } + + if (bufType != NULL) + { + bufType->buffer = record->type; + bufType->length = record->typeLength; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +bool ndefRecordTypeMatch(const ndefRecord* record, uint8_t tnf, const ndefConstBuffer8* bufType) +{ + if ( (record == NULL) || (bufType == NULL) ) + { + return false; + } + + if ( (ndefHeaderTNF(record) == tnf) && + (record->typeLength == bufType->length) && + (ST_BYTECMP(record->type, bufType->buffer, bufType->length) == 0) ) + { + return true; + } + + return false; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordSetId(ndefRecord* record, const ndefConstBuffer8* bufId) +{ + if ( (record == NULL) || + (bufId == NULL) || ndefBufferIsInvalid(bufId) ) + { + return ERR_PARAM; + } + + if (bufId->buffer != NULL) + { + ndefHeaderSetIL(record); + } + else + { + ndefHeaderClearIL(record); + } + + record->id = bufId->buffer; + record->idLength = bufId->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordGetId(const ndefRecord* record, ndefConstBuffer8* bufId) +{ + if ( (record == NULL) || (bufId == NULL) ) + { + return ERR_PARAM; + } + + bufId->buffer = record->id; + bufId->length = record->idLength; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordSetPayload(ndefRecord* record, const ndefConstBuffer* bufPayload) +{ + if ( (record == NULL) || + (bufPayload == NULL) || ndefBufferIsInvalid(bufPayload) ) + { + return ERR_PARAM; + } + + ndefHeaderSetValueSR(record, (bufPayload->length <= NDEF_SHORT_RECORD_LENGTH_MAX) ? 1 : 0); + + record->bufPayload.buffer = bufPayload->buffer; + record->bufPayload.length = bufPayload->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordGetPayload(const ndefRecord* record, ndefConstBuffer* bufPayload) +{ + if ( (record == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + bufPayload->buffer = record->bufPayload.buffer; + bufPayload->length = record->bufPayload.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordDecode(const ndefConstBuffer* bufPayload, ndefRecord* record) +{ + uint32_t offset; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || (record == NULL) ) + { + return ERR_PARAM; + } + + if (ndefRecordReset(record) != ERR_NONE) + { + return ERR_INTERNAL; + } + + /* Get "header" byte */ + offset = 0; + if ((offset + sizeof(uint8_t)) > bufPayload->length) + { + return ERR_PROTO; + } + record->header = bufPayload->buffer[offset]; + offset++; + + /* Get Type length */ + if ((offset + sizeof(uint8_t)) > bufPayload->length) + { + return ERR_PROTO; + } + record->typeLength = bufPayload->buffer[offset]; + offset++; + + /* Decode Payload length */ + if (ndefHeaderIsSetSR(record)) + { + /* Short record */ + if ((offset + sizeof(uint8_t)) > bufPayload->length) + { + return ERR_PROTO; + } + record->bufPayload.length = bufPayload->buffer[offset]; /* length stored on a single byte for Short Record */ + offset++; + } + else + { + /* Standard record */ + if ((offset + sizeof(uint32_t)) > bufPayload->length) + { + return ERR_PROTO; + } + record->bufPayload.length = GETU32(&bufPayload->buffer[offset]); + offset += sizeof(uint32_t); + } + + /* Get Id length */ + if (ndefHeaderIsSetIL(record)) + { + if ((offset + sizeof(uint8_t)) > bufPayload->length) + { + return ERR_PROTO; + } + record->idLength = bufPayload->buffer[offset]; + offset++; + } + else + { + record->idLength = 0; + } + + /* Get Type */ + if (record->typeLength > 0U) + { + if ((offset + record->typeLength) > bufPayload->length) + { + return ERR_PROTO; + } + record->type = &bufPayload->buffer[offset]; + offset += record->typeLength; + } + else + { + record->type = NULL; + } + + /* Get Id */ + if (record->idLength > 0U) + { + if ((offset + record->idLength) > bufPayload->length) + { + return ERR_PROTO; + } + record->id = &bufPayload->buffer[offset]; + offset += record->idLength; + } + else + { + record->id = NULL; + } + + /* Get Payload */ + if (record->bufPayload.length > 0U) + { + if ((offset + record->bufPayload.length) > bufPayload->length) + { + return ERR_PROTO; + } + record->bufPayload.buffer = &bufPayload->buffer[offset]; + } + else + { + record->bufPayload.buffer = NULL; + } + + record->next = NULL; + + return ERR_NONE; +} + + +#if NDEF_FEATURE_FULL_API +/*****************************************************************************/ +ndefStatus ndefRecordEncodeHeader(const ndefRecord* record, ndefBuffer* bufHeader) +{ + uint32_t offset; + uint32_t payloadLength; + + if ( (record == NULL) || (bufHeader == NULL) || (bufHeader->buffer == NULL) ) + { + return ERR_PARAM; + } + + if (bufHeader->length < NDEF_RECORD_HEADER_LEN) + { + bufHeader->length = NDEF_RECORD_HEADER_LEN; + return ERR_NOMEM; + } + + /* Start encoding the record */ + offset = 0; + bufHeader->buffer[offset] = record->header; + offset++; + + /* Set Type length */ + bufHeader->buffer[offset] = record->typeLength; + offset++; + + /* Encode Payload length */ + payloadLength = ndefRecordGetPayloadLength(record); + + if (payloadLength <= NDEF_SHORT_RECORD_LENGTH_MAX) + { + /* Short record */ + bufHeader->buffer[offset] = (uint8_t)payloadLength; + offset++; + } + else + { + /* Standard record */ + bufHeader->buffer[offset] = (uint8_t)(payloadLength >> 24); + offset++; + bufHeader->buffer[offset] = (uint8_t)(payloadLength >> 16); + offset++; + bufHeader->buffer[offset] = (uint8_t)(payloadLength >> 8); + offset++; + bufHeader->buffer[offset] = (uint8_t)(payloadLength); + offset++; + } + + /* Encode Id length */ + if (ndefHeaderIsSetIL(record)) + { + bufHeader->buffer[offset] = record->idLength; + offset++; + } + + bufHeader->length = offset; + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefRecordEncodePayload(const ndefRecord* record, ndefBuffer* bufPayload) +{ + uint32_t payloadLength; + uint32_t offset; + bool begin; + ndefConstBuffer bufPayloadItem; + + if (bufPayload == NULL) + { + return ERR_PARAM; + } + + payloadLength = ndefRecordGetPayloadLength(record); + if (payloadLength > bufPayload->length) + { + return ERR_NOMEM; + } + + begin = true; + offset = 0; + while (ndefRecordGetPayloadItem(record, &bufPayloadItem, begin) != NULL) + { + begin = false; + if (bufPayloadItem.length > 0U) + { + ST_MEMCPY(&bufPayload->buffer[offset], bufPayloadItem.buffer, bufPayloadItem.length); + } + offset += bufPayloadItem.length; + } + + bufPayload->length = offset; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordEncode(const ndefRecord* record, ndefBuffer* bufRecord) +{ + ndefStatus err; + ndefBuffer bufHeader; + ndefBuffer bufPayload; + uint32_t offset; + + if ( (record == NULL) || (bufRecord == NULL) || (bufRecord->buffer == NULL) ) + { + return ERR_PARAM; + } + + if (bufRecord->length < ndefRecordGetLength(record)) + { + bufRecord->length = ndefRecordGetLength(record); + return ERR_NOMEM; + } + + /* Encode header at the beginning of buffer provided */ + bufHeader = *bufRecord; /* Copy ndefBuffer fields */ + err = ndefRecordEncodeHeader(record, &bufHeader); + if (err != ERR_NONE) + { + return err; + } + + offset = bufHeader.length; + + /* Set Type */ + if (record->typeLength > 0U) + { + (void)ST_MEMCPY(&bufRecord->buffer[offset], record->type, record->typeLength); + offset += record->typeLength; + } + + /* Set Id */ + if (record->idLength > 0U) + { + (void)ST_MEMCPY(&bufRecord->buffer[offset], record->id, record->idLength); + offset += record->idLength; + } + + /* Set Payload */ + bufPayload.buffer = &bufRecord->buffer[offset]; + bufPayload.length = bufRecord->length - offset; + err = ndefRecordEncodePayload(record, &bufPayload); + if (err != ERR_NONE) + { + return err; + } + + bufRecord->length = offset + bufPayload.length; + + return ERR_NONE; +} +#endif + + +/*****************************************************************************/ +uint32_t ndefRecordGetPayloadLength(const ndefRecord* record) +{ + uint32_t payloadLength; + + if (record == NULL) + { + return 0; + } + + if ( (record->ndeftype != NULL) && (record->ndeftype->getPayloadLength != NULL) ) + { + payloadLength = record->ndeftype->getPayloadLength(record->ndeftype); + } + else + { + payloadLength = record->bufPayload.length; + } + + return payloadLength; +} + + +/*****************************************************************************/ +const uint8_t* ndefRecordGetPayloadItem(const ndefRecord* record, ndefConstBuffer* bufPayloadItem, bool begin) +{ + if ( (record == NULL) || (bufPayloadItem == NULL) ) + { + return NULL; + } + + bufPayloadItem->buffer = NULL; + bufPayloadItem->length = 0; + + if ( (record->ndeftype != NULL) && (record->ndeftype->getPayloadItem != NULL) ) + { + record->ndeftype->getPayloadItem(record->ndeftype, bufPayloadItem, begin); + } + else + { + if (begin == true) + { + (void)ndefRecordGetPayload(record, bufPayloadItem); + } + } + + return bufPayloadItem->buffer; +} diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_aar.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_aar.c new file mode 100644 index 0000000..9c742f2 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_aar.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Android Application Record (AAR) type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_aar.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_AAR_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD Type strings */ +static const uint8_t ndefRtdTypeAar[] = "android.com:pkg"; /*!< External Type (Android Application Record) */ + +const ndefConstBuffer8 bufRtdTypeAar = { ndefRtdTypeAar, sizeof(ndefRtdTypeAar) - 1U }; /*!< AAR External Type Record buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * NFC Forum External Type (Android Application Record) + */ + + +/*****************************************************************************/ +ndefStatus ndefRtdAarInit(ndefType* aar, const ndefConstBuffer* bufPayload) +{ + ndefTypeRtdAar* rtdAar; + + if ( (aar == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + aar->id = NDEF_TYPE_ID_RTD_AAR; + aar->getPayloadLength = NULL; + aar->getPayloadItem = NULL; + aar->typeToRecord = ndefRtdAarToRecord; + rtdAar = &aar->data.aar; + + rtdAar->bufType.buffer = bufRtdTypeAar.buffer; + rtdAar->bufType.length = bufRtdTypeAar.length; + rtdAar->bufPayload.buffer = bufPayload->buffer; + rtdAar->bufPayload.length = bufPayload->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdAar(const ndefType* aar, ndefConstBuffer* bufAarString) +{ + const ndefTypeRtdAar* rtdAar; + + if ( (aar == NULL) || (aar->id != NDEF_TYPE_ID_RTD_AAR) || + (bufAarString == NULL) ) + { + return ERR_PARAM; + } + + rtdAar = &aar->data.aar; + + bufAarString->buffer = rtdAar->bufPayload.buffer; + bufAarString->length = rtdAar->bufPayload.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdAar(const ndefRecord* record, ndefType* aar) +{ + if ( (record == NULL) || (aar == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeAar)) /* "android.com:pkg" */ + { + return ERR_PROTO; + } + + /* No constraint on payload length */ + + return ndefRtdAarInit(aar, &record->bufPayload); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdAarToRecord(const ndefType* aar, ndefRecord* record) +{ + const ndefTypeRtdAar* rtdAar; + + if ( (aar == NULL) || (aar->id != NDEF_TYPE_ID_RTD_AAR) || + (record == NULL) ) + { + return ERR_PARAM; + } + + rtdAar = &aar->data.aar; + + (void)ndefRecordReset(record); + + /* "android.com:pkg" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeAar); + + (void)ndefRecordSetPayload(record, &rtdAar->bufPayload); + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_bluetooth.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_bluetooth.c new file mode 100644 index 0000000..ee9bb2e --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_bluetooth.c @@ -0,0 +1,808 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Bluetooth type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_bluetooth.h" +#include "utils.h" + + +#if NDEF_TYPE_BLUETOOTH_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/*! Bluetooth Payload minimal length */ +#define NDEF_BLUETOOTH_BREDR_PAYLOAD_LENGTH_MIN 8U +#define NDEF_BLUETOOTH_SECURE_LE_PAYLOAD_LENGTH_MIN 2U +#define NDEF_BLUETOOTH_PAYLOAD_LENGTH_MIN (MIN(NDEF_BLUETOOTH_BREDR_PAYLOAD_LENGTH_MIN, NDEF_BLUETOOTH_SECURE_LE_PAYLOAD_LENGTH_MIN)) + + +/*! EIR length */ +#define NDEF_BT_EIR_DEVICE_ADDRESS_SIZE 6U +#define NDEF_BT_EIR_BLE_DEVICE_ADDRESS_SIZE 6U +#define NDEF_BT_EIR_DEVICE_CLASS_SIZE 3U +#define NDEF_BT_EIR_SIMPLE_PAIRING_HASH_SIZE 16U +#define NDEF_BT_EIR_SIMPLE_PAIRING_RANDOMIZER_SIZE 16U +#define NDEF_BT_EIR_SECURE_CO_CONFIRMATION_VALUE_SIZE 16U +#define NDEF_BT_EIR_SECURE_CO_RANDOM_VALUE_SIZE 16U +#define NDEF_BT_EIR_SECURITY_MANAGER_TK_SIZE 16U +#define NDEF_BT_EIR_SLAVE_CONNECTION_INTERVAL_RANGE_SIZE (2U * sizeof(uint16_t)) + + +/*! Enable EIR length check while decoding payload */ +#define NDEF_BLUETOOTH_CHECK_REFERENCE_LENGTH + +/*! Encode 0-length data EIRs */ +#define NDEF_BLUETOOTH_ENCODE_EMPTY_DATA_EIR + +/*! EIR Length-Type-Data fields offsets */ +#define NDEF_BT_EIR_LENGTH_OFFSET 0U +#define NDEF_BT_EIR_TYPE_OFFSET 1U +#define NDEF_BT_EIR_DATA_OFFSET 2U + + +/* + ****************************************************************************** + * LOCAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! Bluetooth Type strings */ +static const uint8_t ndefTypeBluetoothBrEdr[] = "application/vnd.bluetooth.ep.oob"; /*!< Bluetooth BR/EDR Out-Of-Band Record Type */ +static const uint8_t ndefTypeBluetoothLe[] = "application/vnd.bluetooth.le.oob"; /*!< Bluetooth Low Energy Out-Of-Band Record Type */ +static const uint8_t ndefTypeBluetoothSecureBrEdr[] = "application/vnd.bluetooth.secure.ep.oob"; /*!< Bluetooth Secure BR/EDR Out-Of-Band Record Type */ +static const uint8_t ndefTypeBluetoothSecureLe[] = "application/vnd.bluetooth.secure.le.oob"; /*!< Bluetooth Secure Low Energy Out-Of-Band Record type */ + +const ndefConstBuffer8 bufMediaTypeBluetoothBrEdr = { ndefTypeBluetoothBrEdr, sizeof(ndefTypeBluetoothBrEdr) - 1U }; /*!< Bluetooth BR/EDR Record Type buffer */ +const ndefConstBuffer8 bufMediaTypeBluetoothLe = { ndefTypeBluetoothLe, sizeof(ndefTypeBluetoothLe) - 1U }; /*!< Bluetooth Low Energy Record Type buffer */ +const ndefConstBuffer8 bufMediaTypeBluetoothSecureBrEdr = { ndefTypeBluetoothSecureBrEdr, sizeof(ndefTypeBluetoothSecureBrEdr) - 1U }; /*!< Bluetooth Secure BR/EDR Record Type buffer */ +const ndefConstBuffer8 bufMediaTypeBluetoothSecureLe = { ndefTypeBluetoothSecureLe, sizeof(ndefTypeBluetoothSecureLe) - 1U }; /*!< Bluetooth Secure Low Energy Record Type buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Bluetooth OOB + */ + + +/* EIR Helper functions */ + + +/*****************************************************************************/ +uint8_t ndefBluetoothEirLength(const uint8_t* eir) +{ + if (eir == NULL) + { + return 0; + } + + uint8_t length = eir[NDEF_BT_EIR_LENGTH_OFFSET]; + /* Check the EIR contains something */ + if (length != 0U) + { + /* Add the Length byte that is not included in the EIR length */ + length += (uint8_t)sizeof(uint8_t); + } + + return length; +} + + +/*****************************************************************************/ +uint8_t ndefBluetoothEirDataLength(const uint8_t* eir) +{ + if (eir == NULL) + { + return 0; + } + + uint8_t dataLength = eir[NDEF_BT_EIR_LENGTH_OFFSET]; + /* Check the EIR contains a type */ + if (dataLength > 0U) + { + dataLength -= (uint8_t)sizeof(uint8_t); /* Remove the EIR Type byte */ + } + + return dataLength; +} + + +/*****************************************************************************/ +uint8_t ndefBluetoothEirType(const uint8_t* eir) +{ + uint8_t type = 0; + + if (ndefBluetoothEirLength(eir) != 0U) + { + type = eir[NDEF_BT_EIR_TYPE_OFFSET]; + } + + return type; +} + + +/*****************************************************************************/ +const uint8_t* ndefBluetoothEirData(const uint8_t* eir) +{ + const uint8_t* data = NULL; + + if (ndefBluetoothEirDataLength(eir) != 0U) + { + data = &eir[NDEF_BT_EIR_DATA_OFFSET]; + } + + return data; +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothEirDataToBuffer(const uint8_t* eir, ndefConstBuffer* bufEir) +{ + if ( (eir == NULL) || (bufEir == NULL) ) + { + return ERR_PARAM; + } + + bufEir->buffer = ndefBluetoothEirData(eir); + bufEir->length = ndefBluetoothEirDataLength(eir); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothSetEir(ndefTypeBluetooth* bluetooth, const uint8_t* eir) +{ + if ( (bluetooth == NULL) || (eir == NULL) ) + { + return ERR_PARAM; + } + + /* Find first free EIR */ + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(bluetooth->eir); i++) + { + /* Append it */ + if (bluetooth->eir[i] == NULL) + { + bluetooth->eir[i] = eir; + return ERR_NONE; + } + /* Or update existing one */ + else if (ndefBluetoothEirType(bluetooth->eir[i]) == ndefBluetoothEirType(eir)) + { + bluetooth->eir[i] = eir; + return ERR_NONE; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + + return ERR_NOMEM; +} + + +/*****************************************************************************/ +const uint8_t* ndefBluetoothGetEir(const ndefTypeBluetooth* bluetooth, uint8_t eirType) +{ + if (bluetooth == NULL) + { + return NULL; + } + + /* Find EIR with this type */ + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(bluetooth->eir); i++) + { + if (ndefBluetoothEirType(bluetooth->eir[i]) == eirType) + { + return bluetooth->eir[i]; + } + } + + return NULL; +} + + +/*****************************************************************************/ +/* This function copies an array, changing its endianness, useful to convert data to BLE endianess */ +static uint8_t* NDEF_BluetoothReverse(uint8_t* dst, const uint8_t* src, uint32_t length) +{ + if ( (dst == NULL) || (src == NULL) ) + { + return NULL; + } + + for(uint32_t i = 0; i < length; i++) + { + dst[i] = src[length - i - 1U]; + } + + return dst; +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothGetEirData(const ndefTypeBluetooth* bluetooth, uint8_t eirType, ndefConstBuffer* bufData) +{ + if ( (bluetooth == NULL) || (bufData == NULL) ) + { + return ERR_PARAM; + } + + const uint8_t* eir = ndefBluetoothGetEir(bluetooth, eirType); + + return ndefBluetoothEirDataToBuffer(eir, bufData); +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothGetEirDataReversed(const ndefTypeBluetooth* bluetooth, uint8_t eirType, ndefBuffer* bufDataReversed) +{ + if ( (bluetooth == NULL) || (bufDataReversed == NULL) ) + { + return ERR_PARAM; + } + + const uint8_t* eir = ndefBluetoothGetEir(bluetooth, eirType); + + uint32_t data_length = ndefBluetoothEirDataLength(eir); + if (data_length > bufDataReversed->length) + { + bufDataReversed->length = data_length; + return ERR_NOMEM; + } + bufDataReversed->length = data_length; + + const uint8_t* eir_data = ndefBluetoothEirData(eir); + (void)NDEF_BluetoothReverse(bufDataReversed->buffer, eir_data, data_length); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static uint32_t ndefBluetoothPayloadGetLength(const ndefType* type) +{ + const ndefTypeBluetooth* ndefData; + uint32_t length = 0; + + if ( (type == NULL) || + ( (type->id != NDEF_TYPE_ID_BLUETOOTH_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_LE) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) ) + { + return 0; + } + + ndefData = &type->data.bluetooth; + + /* For both BR/EDR and Secure LE */ + if ( (type->id == NDEF_TYPE_ID_BLUETOOTH_BREDR) || + (type->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) + { + length = sizeof(uint16_t); /* 2 bytes for length */ + } + + /* For BR/EDR only, but no test needed because length is 0 in that case */ + length += ndefData->bufDeviceAddress.length; + + /* Go through all EIRs */ + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(ndefData->eir); i++) + { +#ifdef NDEF_BLUETOOTH_ENCODE_EMPTY_DATA_EIR + /* Send all/valid EIRs (even EIRs with data length == 0) */ +#else + /* Send EIRs with data length != 0U only */ + if (ndefBluetoothGetEirDataLength(ndefDtata->eir[i]) != 0U) +#endif + { + length += ndefBluetoothEirLength(ndefData->eir[i]); + } + } + + return length; +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothReset(ndefTypeBluetooth* bluetooth) +{ + ndefConstBuffer bufEmpty = { NULL, 0 }; + + if (bluetooth == NULL) + { + return ERR_PARAM; + } + + /* Initialize ndefBuffer */ + bluetooth->bufDeviceAddress = bufEmpty; + + /* Initialize all EIRs */ + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(bluetooth->eir); i++) + { + bluetooth->eir[i] = NULL; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static const uint8_t* ndefBluetoothToPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + static uint32_t eirId = 0; + + const ndefTypeBluetooth* ndefData; + + if ( (type == NULL) || (bufItem == NULL) || + ( (type->id != NDEF_TYPE_ID_BLUETOOTH_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_LE) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) ) + { + return NULL; + } + + ndefData = &type->data.bluetooth; + + bufItem->buffer = NULL; + bufItem->length = 0; + + /* Initialization */ + if (begin == true) + { + item = 0; + eirId = 0; + } + + /* BR/EDR or Secure Low Energy */ + if ( (type->id == NDEF_TYPE_ID_BLUETOOTH_BREDR) || + (type->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) + { + if (item == 0U) + { + /* for BR-EDR and Secure LE, Device address & length are managed outside EIR */ + /* First item for NDEF_TYPE_ID_BLUETOOTH_BREDR: Payload length */ + static uint16_t len; + len = (uint16_t)ndefBluetoothPayloadGetLength(type); + bufItem->buffer = (const uint8_t*)&len; + bufItem->length = sizeof(uint16_t); + + item++; + return bufItem->buffer; + } + } + if (type->id == NDEF_TYPE_ID_BLUETOOTH_BREDR) + { + if (item == 1U) + { + /* for BR-EDR Device address & length are managed outside EIR */ + /* Second item for NDEF_TYPE_ID_BLUETOOTH_BREDR: Device Address */ + bufItem->buffer = ndefData->bufDeviceAddress.buffer; + bufItem->length = ndefData->bufDeviceAddress.length; + + item++; + return bufItem->buffer; + } + } + + /* Go through all EIRs */ + while (eirId < (uint32_t)SIZEOF_ARRAY(ndefData->eir)) + { +#ifdef NDEF_BLUETOOTH_ENCODE_EMPTY_DATA_EIR + /* Send all/valid EIRs (even EIRs with data length == 0) */ + if (ndefBluetoothEirLength(ndefData->eir[eirId]) != 0U) +#else + /* Send EIRs with data length != 0U only */ + if (ndefBluetoothEirDataLength(ndefData->eir[eirId]) != 0U) +#endif + { + bufItem->buffer = (const uint8_t*)ndefData->eir[eirId]; + bufItem->length = ndefBluetoothEirLength(ndefData->eir[eirId]); + + eirId++; + return bufItem->buffer; + } + eirId++; + } + + return bufItem->buffer; +} + + +/*****************************************************************************/ +static ndefStatus ndefBluetoothInit(ndefType* type, const ndefTypeBluetooth* bluetooth) +{ + ndefTypeBluetooth* ndefData; + + if ( (type == NULL) || (bluetooth == NULL) ) + { + return ERR_PARAM; + } + + /* type->id set by the caller */ + type->getPayloadLength = ndefBluetoothPayloadGetLength; + type->getPayloadItem = ndefBluetoothToPayloadItem; + type->typeToRecord = ndefBluetoothToRecord; + ndefData = &type->data.bluetooth; + + /* Copy in a bulk */ + (void)ST_MEMCPY(ndefData, bluetooth, sizeof(ndefTypeBluetooth)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothBrEdrInit(ndefType* type, const ndefTypeBluetooth* bluetooth) +{ + if (type == NULL) + { + return ERR_PARAM; + } + + /* Initialize a Basic Rate/Enhanced Data Rate type */ + type->id = NDEF_TYPE_ID_BLUETOOTH_BREDR; + + return ndefBluetoothInit(type, bluetooth); +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothLeInit(ndefType* type, const ndefTypeBluetooth* bluetooth) +{ + if (type == NULL) + { + return ERR_PARAM; + } + + /* Initialize a Bluetooth Low Energy type */ + type->id = NDEF_TYPE_ID_BLUETOOTH_LE; + + return ndefBluetoothInit(type, bluetooth); +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothSecureBrEdrInit(ndefType* type, const ndefTypeBluetooth* bluetooth) +{ + if (type == NULL) + { + return ERR_PARAM; + } + + /* Initialize a Secure BR/EDR type */ + type->id = NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR; + + return ndefBluetoothInit(type, bluetooth); +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothSecureLeInit(ndefType* type, const ndefTypeBluetooth* bluetooth) +{ + if (type == NULL) + { + return ERR_PARAM; + } + + /* Initialize a Secure Low Energy type */ + type->id = NDEF_TYPE_ID_BLUETOOTH_SECURE_LE; + + return ndefBluetoothInit(type, bluetooth); +} + + +/*****************************************************************************/ +ndefStatus ndefGetBluetooth(const ndefType* type, ndefTypeBluetooth* bluetooth) +{ + const ndefTypeBluetooth* ndefData; + + if ( (type == NULL) || (bluetooth == NULL) || + ( (type->id != NDEF_TYPE_ID_BLUETOOTH_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_LE) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR) && + (type->id != NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.bluetooth; + + /* Copy in a bulk */ + (void)ST_MEMCPY(bluetooth, ndefData, sizeof(ndefTypeBluetooth)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +#ifdef NDEF_BLUETOOTH_CHECK_REFERENCE_LENGTH +static uint32_t ndefBluetoothEirRefLength(uint8_t eirType) +{ + uint32_t length; + switch (eirType) + { + case NDEF_BT_EIR_FLAGS : length = sizeof(uint8_t) ; break; + case NDEF_BT_EIR_TX_POWER_LEVEL : length = sizeof(uint8_t) ; break; + case NDEF_BT_EIR_DEVICE_CLASS : length = NDEF_BT_EIR_DEVICE_CLASS_SIZE ; break; + case NDEF_BT_EIR_SIMPLE_PAIRING_HASH : length = NDEF_BT_EIR_SIMPLE_PAIRING_HASH_SIZE ; break; + case NDEF_BT_EIR_SIMPLE_PAIRING_RANDOMIZER : length = NDEF_BT_EIR_SIMPLE_PAIRING_RANDOMIZER_SIZE ; break; + case NDEF_BT_EIR_SECURITY_MANAGER_TK_VALUE : length = NDEF_BT_EIR_SECURITY_MANAGER_TK_SIZE ; break; + case NDEF_BT_EIR_SECURITY_MANAGER_FLAGS : length = sizeof(uint8_t) ; break; + case NDEF_BT_EIR_SLAVE_CONNECTION_INTERVAL_RANGE : length = NDEF_BT_EIR_SLAVE_CONNECTION_INTERVAL_RANGE_SIZE ; break; + case NDEF_BT_EIR_LE_DEVICE_ADDRESS : length = NDEF_BT_EIR_BLE_DEVICE_ADDRESS_SIZE + sizeof(uint8_t); break; + case NDEF_BT_EIR_LE_ROLE : length = sizeof(uint8_t) ; break; + case NDEF_BT_EIR_LE_SECURE_CONN_CONFIRMATION_VALUE: length = NDEF_BT_EIR_SECURE_CO_CONFIRMATION_VALUE_SIZE ; break; + case NDEF_BT_EIR_LE_SECURE_CONN_RANDOM_VALUE : length = NDEF_BT_EIR_SECURE_CO_RANDOM_VALUE_SIZE ; break; + default: + /* No length constraint on the following EIRs: */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_16 */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_16 */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_32 */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_32 */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_PARTIAL_128 */ + /* NDEF_BT_EIR_SERVICE_CLASS_UUID_COMPLETE_128 */ + /* NDEF_BT_EIR_SHORT_LOCAL_NAME */ + /* NDEF_BT_EIR_COMPLETE_LOCAL_NAME */ + /* NDEF_BT_EIR_SERVICE_SOLICITATION_16 */ + /* NDEF_BT_EIR_SERVICE_SOLICITATION_128 */ + /* NDEF_BT_EIR_SERVICE_DATA */ + /* NDEF_BT_EIR_APPEARANCE */ + /* NDEF_BT_EIR_MANUFACTURER_DATA */ + length = 0; + break; + } + + return length; +} +#endif + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToBluetooth(const ndefConstBuffer* bufPayload, ndefTypeId typeId, ndefType* type) +{ + ndefTypeBluetooth* ndefData; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + if (bufPayload->length < NDEF_BLUETOOTH_PAYLOAD_LENGTH_MIN) /* Bluetooth Payload Min */ + { + return ERR_PROTO; + } + + /* MISRA complains that this conditional expression is always false, so comment it out */ + /* if ( (typeId != NDEF_TYPE_ID_BLUETOOTH_BREDR) && + (typeId != NDEF_TYPE_ID_BLUETOOTH_BLE) && + (typeId != NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) + { + return ERR_PARAM; + } */ + + type->id = typeId; + type->getPayloadLength = ndefBluetoothPayloadGetLength; + type->getPayloadItem = ndefBluetoothToPayloadItem; + type->typeToRecord = ndefBluetoothToRecord; + ndefData = &type->data.bluetooth; + + /* Reset every field */ + if (ndefBluetoothReset(ndefData) != ERR_NONE) + { + return ERR_PARAM; + } + + uint32_t offset = 0; + + /* Extract data from the payload */ + if ( (typeId == NDEF_TYPE_ID_BLUETOOTH_BREDR) || + (typeId == NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) + { + uint16_t length = bufPayload->buffer[offset]; + NO_WARNING(length); + offset += sizeof(uint16_t); + + /* Could check length and bufPayload->length match */ + } + if (typeId == NDEF_TYPE_ID_BLUETOOTH_BREDR) + { + ndefData->bufDeviceAddress.buffer = &bufPayload->buffer[offset]; + ndefData->bufDeviceAddress.length = NDEF_BT_EIR_DEVICE_ADDRESS_SIZE; + offset += NDEF_BT_EIR_DEVICE_ADDRESS_SIZE; + } + + while (offset < bufPayload->length) + { + const uint8_t* eir = &bufPayload->buffer[offset]; + uint8_t eir_length = ndefBluetoothEirLength(eir); + + if (eir_length == 0U) + { + break; /* Leave when find an empty EIR */ + } + + offset += eir_length; + +#ifdef NDEF_BLUETOOTH_CHECK_REFERENCE_LENGTH + uint8_t eir_data_length = ndefBluetoothEirDataLength(eir); + uint8_t eir_type = ndefBluetoothEirType(eir); + uint32_t refLength = ndefBluetoothEirRefLength(eir_type); + /* Check length match */ + if ( (refLength != 0U) && + (refLength != eir_data_length) ) + { + return ERR_PROTO; + } +#endif + ndefStatus err = ndefBluetoothSetEir(ndefData, eir); + if (err != ERR_NONE) + { + return err; + } + } + + /* The client is in charge to check that the mandatory fields are there */ + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToBluetooth(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + ndefTypeId typeId; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + /* "application/vnd.bluetooth.ep.oob" */ + if (ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothBrEdr)) + { + typeId = NDEF_TYPE_ID_BLUETOOTH_BREDR; + } + /* "application/vnd.bluetooth.le.oob" */ + else if (ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothLe)) + { + typeId = NDEF_TYPE_ID_BLUETOOTH_LE; + } + /* "application/vnd.bluetooth.secure.ep.oob" */ + else if (ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureBrEdr)) + { + typeId = NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR; + } + /* "application/vnd.bluetooth.secure.le.oob" */ + else if (ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureLe)) + { + typeId = NDEF_TYPE_ID_BLUETOOTH_SECURE_LE; + } + else + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && ( (ndefData->id == NDEF_TYPE_ID_BLUETOOTH_BREDR) || + (ndefData->id == NDEF_TYPE_ID_BLUETOOTH_LE) || + (ndefData->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR) || + (ndefData->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) ) + ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToBluetooth(&record->bufPayload, typeId, type); +} + + +/*****************************************************************************/ +ndefStatus ndefBluetoothToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + if (type->id == NDEF_TYPE_ID_BLUETOOTH_BREDR) + { + /* "application/vnd.bluetooth.ep.oob" */ + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothBrEdr); + } + else if (type->id == NDEF_TYPE_ID_BLUETOOTH_LE) + { + /* "application/vnd.bluetooth.le.oob" */ + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothLe); + } + else if (type->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_BREDR) + { + /* "application/vnd.bluetooth.secure.ep.oob" */ + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureBrEdr); + } + else if (type->id == NDEF_TYPE_ID_BLUETOOTH_SECURE_LE) + { + /* "application/vnd.bluetooth.secure.le.oob" */ + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureLe); + } + else + { + return ERR_PROTO; + } + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_deviceinfo.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_deviceinfo.c new file mode 100644 index 0000000..8f8f04a --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_deviceinfo.c @@ -0,0 +1,416 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Device Information type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_deviceinfo.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! Device Information payload defines */ +#define NDEF_RTD_DEVICE_INFO_PAYLOAD_MIN (2U * (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t))) /*!< Device Information minimum length (2 required TLV structures) */ +#define NDEF_RTD_DEVICE_INFO_PAYLOAD_MAX ((4U * (sizeof(uint8_t) + sizeof(uint8_t) + 255U)) + (sizeof(uint8_t) + sizeof(uint8_t) + 16U)) /*!< Device Information maximum length */ +#define NDEF_RTD_DEVICE_INFO_TLV_LENGTH_MIN (sizeof(uint8_t) + sizeof(uint8_t)) /*!< Device Information minimum TLV length */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD Device Information Type string */ +static const uint8_t ndefRtdTypeDeviceInfo[] = "Di"; /*!< Device Information Record Type {0x44, 0x69} */ + +const ndefConstBuffer8 bufRtdTypeDeviceInfo = { ndefRtdTypeDeviceInfo, sizeof(ndefRtdTypeDeviceInfo) - 1U }; /*!< Device Information Record Type buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Device Information + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdDeviceInfoPayloadGetLength(const ndefType* devInfo) +{ + const ndefTypeRtdDeviceInfo* rtdDevInfo; + uint32_t payloadLength = 0; + + if ( (devInfo == NULL) || (devInfo->id != NDEF_TYPE_ID_RTD_DEVICE_INFO) ) + { + return 0; + } + + rtdDevInfo = &devInfo->data.deviceInfo; + + for (uint32_t i = 0; i < NDEF_DEVICE_INFO_TYPE_COUNT; i++) + { + if (rtdDevInfo->devInfo[i].length != 0U) + { + /* sizeof(type) + sizeof(length) + actual length */ + payloadLength += sizeof(rtdDevInfo->devInfo[i].type) + sizeof(rtdDevInfo->devInfo[i].length) + (uint32_t)rtdDevInfo->devInfo[i].length; + } + } + + return payloadLength; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdDeviceInfoToPayloadItem(const ndefType* devInfo, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdDeviceInfo* rtdDevInfo; + uint32_t index; + + if ( (devInfo == NULL) || (devInfo->id != NDEF_TYPE_ID_RTD_DEVICE_INFO) || + (bufItem == NULL) ) + { + return NULL; + } + + rtdDevInfo = &devInfo->data.deviceInfo; + + if (begin == true) + { + item = 0; + } + + bufItem->buffer = NULL; + bufItem->length = 0; + + index = item / 3U; + + /* Stop streaming on first empty entry */ + if (rtdDevInfo->devInfo[index].length > 0U) + { + switch (item % 3U) + { + case 0: + bufItem->buffer = &rtdDevInfo->devInfo[index].type; + bufItem->length = sizeof(rtdDevInfo->devInfo[index].type); + break; + case 1: + bufItem->buffer = &rtdDevInfo->devInfo[index].length; + bufItem->length = sizeof(rtdDevInfo->devInfo[index].length); + break; + case 2: + bufItem->buffer = rtdDevInfo->devInfo[index].buffer; + bufItem->length = rtdDevInfo->devInfo[index].length; + break; + /*NOTREACHED*/ + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdDeviceInfoInit(ndefType* devInfo, const ndefDeviceInfoEntry* devInfoData, uint8_t devInfoDataCount) +{ + ndefTypeRtdDeviceInfo* rtdDevInfo; + uint8_t count; + uint8_t manufacturerNameIndex; + uint8_t modelNameIndex; + + if ( (devInfo == NULL) || + (devInfoData == NULL) || (devInfoData->length == 0U) || + (devInfoDataCount == 0U) || (devInfoDataCount > NDEF_DEVICE_INFO_TYPE_COUNT) ) + { + return ERR_PARAM; + } + + devInfo->id = NDEF_TYPE_ID_RTD_DEVICE_INFO; + devInfo->getPayloadLength = ndefRtdDeviceInfoPayloadGetLength; + devInfo->getPayloadItem = ndefRtdDeviceInfoToPayloadItem; + devInfo->typeToRecord = ndefRtdDeviceInfoToRecord; + rtdDevInfo = &devInfo->data.deviceInfo; + + /* Clear the Device Information structure before parsing */ + for (uint32_t i = 0; i < NDEF_DEVICE_INFO_TYPE_COUNT; i++) + { + rtdDevInfo->devInfo[i].type = 0; + rtdDevInfo->devInfo[i].length = 0; + rtdDevInfo->devInfo[i].buffer = NULL; + } + + /* Read Type, Length and Value fields */ + /* Not checking multiple occurences of a given field, use the last one */ + count = 0; + manufacturerNameIndex = 0; + modelNameIndex = 0; + + while (count < devInfoDataCount) + { + uint8_t type = devInfoData[count].type; + uint8_t length = devInfoData[count].length; + if ((type == NDEF_DEVICE_INFO_UUID) && (length != NDEF_UUID_LENGTH)) + { + return ERR_PROTO; + } + if ( (type > NDEF_DEVICE_INFO_TYPE_COUNT) || (length == 0U) ) + { + return ERR_PROTO; + } + if (type == NDEF_DEVICE_INFO_MANUFACTURER_NAME) + { + manufacturerNameIndex = count; + } + else + { + if (type == NDEF_DEVICE_INFO_MODEL_NAME) + { + modelNameIndex = count; + } + } + + rtdDevInfo->devInfo[count].type = type; + rtdDevInfo->devInfo[count].length = length; + rtdDevInfo->devInfo[count].buffer = devInfoData[count].buffer; + count++; + } + + /* Check that both required fields are there */ + if ( (manufacturerNameIndex != modelNameIndex) && + (rtdDevInfo->devInfo[manufacturerNameIndex].buffer != NULL) && + (rtdDevInfo->devInfo[modelNameIndex].buffer != NULL) ) + { + return ERR_NONE; + } + else + { + return ERR_PARAM; + } +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdDeviceInfo(const ndefType* devInfo, ndefTypeRtdDeviceInfo* devInfoData) +{ + const ndefTypeRtdDeviceInfo* rtdDevInfo; + + if ( (devInfo == NULL) || (devInfo->id != NDEF_TYPE_ID_RTD_DEVICE_INFO) || + (devInfoData == NULL) ) + { + return ERR_PARAM; + } + + rtdDevInfo = &devInfo->data.deviceInfo; + + for (uint32_t i = 0; i < NDEF_DEVICE_INFO_TYPE_COUNT; i++) + { + devInfoData->devInfo[i].type = rtdDevInfo->devInfo[i].type; + devInfoData->devInfo[i].length = rtdDevInfo->devInfo[i].length; + devInfoData->devInfo[i].buffer = rtdDevInfo->devInfo[i].buffer; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdDeviceInfo(const ndefConstBuffer* bufDevInfo, ndefType* devInfo) +{ + ndefTypeRtdDeviceInfo* rtdDevInfo; + uint32_t offset; + uint8_t count; + uint8_t manufacturerNameIndex; + uint8_t modelNameIndex; + + if ( (bufDevInfo == NULL) || (bufDevInfo->buffer == NULL) || + (devInfo == NULL) ) + { + return ERR_PARAM; + } + + devInfo->id = NDEF_TYPE_ID_RTD_DEVICE_INFO; + devInfo->getPayloadLength = ndefRtdDeviceInfoPayloadGetLength; + devInfo->getPayloadItem = ndefRtdDeviceInfoToPayloadItem; + devInfo->typeToRecord = ndefRtdDeviceInfoToRecord; + rtdDevInfo = &devInfo->data.deviceInfo; + + if ( (bufDevInfo->length < NDEF_RTD_DEVICE_INFO_PAYLOAD_MIN) || + (bufDevInfo->length > NDEF_RTD_DEVICE_INFO_PAYLOAD_MAX) ) + { + return ERR_PROTO; + } + + /* Extract device information from the buffer */ + + /* Clear the Device Information structure before parsing */ + for (uint32_t i = 0; i < NDEF_DEVICE_INFO_TYPE_COUNT; i++) + { + rtdDevInfo->devInfo[i].type = 0; + rtdDevInfo->devInfo[i].length = 0; + rtdDevInfo->devInfo[i].buffer = NULL; + } + + /* Read Type, Length and Value fields */ + /* Not checking multiple occurences of a given field, use the last one */ + offset = 0; + count = 0; + manufacturerNameIndex = 0; + modelNameIndex = 0; + + while ( ((offset + NDEF_RTD_DEVICE_INFO_TLV_LENGTH_MIN) < bufDevInfo->length) + && (count < NDEF_DEVICE_INFO_TYPE_COUNT) ) + { + uint8_t type = bufDevInfo->buffer[offset]; + uint8_t length = bufDevInfo->buffer[offset + 1U]; + if ((type == NDEF_DEVICE_INFO_UUID) && (length != NDEF_UUID_LENGTH)) + { + return ERR_PROTO; + } + if ( (type > NDEF_DEVICE_INFO_TYPE_COUNT) || (length == 0U) ) + { + return ERR_PROTO; + } + if (type == NDEF_DEVICE_INFO_MANUFACTURER_NAME) + { + manufacturerNameIndex = count; + } + else + { + if (type == NDEF_DEVICE_INFO_MODEL_NAME) + { + modelNameIndex = count; + } + } + + rtdDevInfo->devInfo[count].type = type; + rtdDevInfo->devInfo[count].length = length; + rtdDevInfo->devInfo[count].buffer = &bufDevInfo->buffer[offset + 2U]; + count++; + + /* Next entry */ + offset += sizeof(uint8_t) + sizeof(uint8_t) + (uint32_t)length; + } + + /* Check both required fields are there */ + if ( (manufacturerNameIndex != modelNameIndex) && + (rtdDevInfo->devInfo[manufacturerNameIndex].buffer != NULL) && + (rtdDevInfo->devInfo[modelNameIndex].buffer != NULL) ) + { + return ERR_NONE; + } + else + { + return ERR_PARAM; + } +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdDeviceInfo(const ndefRecord* record, ndefType* devInfo) +{ + const ndefType* type; + + if ( (record == NULL) || (devInfo == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeDeviceInfo)) /* "Di" */ + { + return ERR_PROTO; + } + + type = ndefRecordGetNdefType(record); + if ( (type != NULL) && (type->id == NDEF_TYPE_ID_RTD_DEVICE_INFO) ) + { + (void)ST_MEMCPY(devInfo, type, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdDeviceInfo(&record->bufPayload, devInfo); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdDeviceInfoToRecord(const ndefType* devInfo, ndefRecord* record) +{ + if ( (devInfo == NULL) || (devInfo->id != NDEF_TYPE_ID_RTD_DEVICE_INFO) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "Di" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeDeviceInfo); + + if (ndefRecordSetNdefType(record, devInfo) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_empty.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_empty.c new file mode 100644 index 0000000..66b79a0 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_empty.c @@ -0,0 +1,168 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Empty type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_empty.h" +#include "utils.h" + + +#if NDEF_TYPE_EMPTY_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Empty record + */ + + +/*****************************************************************************/ +static uint32_t ndefEmptyTypePayloadGetLength(const ndefType* empty) +{ + NO_WARNING(empty); + + return 0; +} + + +/*****************************************************************************/ +static const uint8_t* ndefEmptyTypePayloadItem(const ndefType* empty, ndefConstBuffer* bufItem, bool begin) +{ + NO_WARNING(begin); + + if ( (empty == NULL) || (empty->id != NDEF_TYPE_ID_EMPTY) ) + { + return NULL; + } + + if (bufItem != NULL) + { + bufItem->buffer = NULL; + bufItem->length = 0; + } + + return NULL; +} + + +/*****************************************************************************/ +ndefStatus ndefEmptyTypeInit(ndefType* empty) +{ + if (empty == NULL) + { + return ERR_PARAM; + } + + empty->id = NDEF_TYPE_ID_EMPTY; + empty->getPayloadLength = ndefEmptyTypePayloadGetLength; + empty->getPayloadItem = ndefEmptyTypePayloadItem; + empty->typeToRecord = ndefEmptyTypeToRecord; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToEmptyType(const ndefRecord* record, ndefType* empty) +{ + ndefConstBuffer8 bufEmpty = { NULL, 0 }; + + if ( (record == NULL) || (empty == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_EMPTY, &bufEmpty)) + { + return ERR_PARAM; + } + + if ( (record->idLength != 0U) || (record->id != NULL) || + (record->bufPayload.length != 0U) || (record->bufPayload.buffer != NULL) ) + { + return ERR_PARAM; + } + + return ndefEmptyTypeInit(empty); +} + + +/*****************************************************************************/ +ndefStatus ndefEmptyTypeToRecord(const ndefType* empty, ndefRecord* record) +{ + if ( (empty == NULL) || (empty->id != NDEF_TYPE_ID_EMPTY) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + if (ndefRecordSetNdefType(record, empty) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_flat.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_flat.c new file mode 100644 index 0000000..7a99110 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_flat.c @@ -0,0 +1,195 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Empty type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_flat.h" +#include "utils.h" + + +#if NDEF_TYPE_FLAT_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Flat payload record + */ + + +/*****************************************************************************/ +static uint32_t ndefFlatPayloadTypePayloadGetLength(const ndefType* type) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_FLAT) ) + { + return 0; + } + + return type->data.bufPayload.length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefFlatPayloadTypePayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_FLAT) ) + { + return NULL; + } + + if ( (begin == true) && (bufItem != NULL) ) + { + bufItem->buffer = type->data.bufPayload.buffer; + bufItem->length = type->data.bufPayload.length; + + return bufItem->buffer; + } + + return NULL; +} + + +/*****************************************************************************/ +ndefStatus ndefFlatPayloadTypeInit(ndefType* type, const ndefConstBuffer* bufPayload) +{ + if ( (type == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_FLAT; + type->getPayloadLength = ndefFlatPayloadTypePayloadGetLength; + type->getPayloadItem = ndefFlatPayloadTypePayloadItem; + type->typeToRecord = ndefFlatPayloadTypeToRecord; + + type->data.bufPayload.buffer = bufPayload->buffer; + type->data.bufPayload.length = bufPayload->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetFlatPayloadType(const ndefType* type, ndefConstBuffer* bufPayload) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_FLAT) || + (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + bufPayload->buffer = type->data.bufPayload.buffer ; + bufPayload->length = type->data.bufPayload.length ; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToFlatPayloadType(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_FLAT) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + ndefConstBuffer bufPayload; + ndefStatus err = ndefRecordGetPayload(record, &bufPayload); + if (err != ERR_NONE) + { + return err; + } + + return ndefFlatPayloadTypeInit(type, &bufPayload); +} + + +/*****************************************************************************/ +ndefStatus ndefFlatPayloadTypeToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_FLAT) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* Do not initialize Type string */ + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_media.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_media.c new file mode 100644 index 0000000..651552e --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_media.c @@ -0,0 +1,178 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF MIME types + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_media.h" +#include "utils.h" + + +#if NDEF_TYPE_MEDIA_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Media + */ + + +/*****************************************************************************/ +ndefStatus ndefMediaInit(ndefType* media, const ndefConstBuffer8* bufType, const ndefConstBuffer* bufPayload) +{ + ndefTypeMedia* typeMedia; + + if ( (media == NULL) || (bufType == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + media->id = NDEF_TYPE_ID_MEDIA; + media->getPayloadLength = NULL; + media->getPayloadItem = NULL; + media->typeToRecord = ndefMediaToRecord; + typeMedia = &media->data.media; + + typeMedia->bufType.buffer = bufType->buffer; + typeMedia->bufType.length = bufType->length; + typeMedia->bufPayload.buffer = bufPayload->buffer; + typeMedia->bufPayload.length = bufPayload->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetMedia(const ndefType* media, ndefConstBuffer8* bufType, ndefConstBuffer* bufPayload) +{ + const ndefTypeMedia* typeMedia; + + if ( (media == NULL) || (media->id != NDEF_TYPE_ID_MEDIA) || + (bufType == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + typeMedia = &media->data.media; + + bufType->buffer = typeMedia->bufType.buffer; + bufType->length = typeMedia->bufType.length; + + bufPayload->buffer = typeMedia->bufPayload.buffer; + bufPayload->length = typeMedia->bufPayload.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToMedia(const ndefRecord* record, ndefType* media) +{ + const ndefType* type; + ndefConstBuffer8 bufType; + + if ( (record == NULL) || (media == NULL) ) + { + return ERR_PARAM; + } + + if (ndefHeaderTNF(record) != NDEF_TNF_MEDIA_TYPE) + { + return ERR_PROTO; + } + + type = ndefRecordGetNdefType(record); + if ( (type != NULL) && (type->id == NDEF_TYPE_ID_MEDIA) ) + { + (void)ST_MEMCPY(media, type, sizeof(ndefType)); + return ERR_NONE; + } + + bufType.buffer = record->type; + bufType.length = record->typeLength; + + return ndefMediaInit(media, &bufType, &record->bufPayload); +} + + +/*****************************************************************************/ +ndefStatus ndefMediaToRecord(const ndefType* media, ndefRecord* record) +{ + const ndefTypeMedia* typeMedia; + + if ( (media == NULL) || (media->id != NDEF_TYPE_ID_MEDIA) || + (record == NULL) ) + { + return ERR_PARAM; + } + + typeMedia = &media->data.media; + + (void)ndefRecordReset(record); + + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &typeMedia->bufType); + + (void)ndefRecordSetPayload(record, &typeMedia->bufPayload); + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_text.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_text.c new file mode 100644 index 0000000..211b0c3 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_text.c @@ -0,0 +1,317 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD Text type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_text.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_TEXT_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! Text defines */ +#define NDEF_RTD_TEXT_STATUS_OFFSET 0U /*!< Text status offset */ +#define NDEF_RTD_TEXT_LANGUAGE_OFFSET 1U /*!< Text language offset */ + +#define NDEF_RTD_TEXT_LANGUAGE_CODE_LEN_MASK 0x3FU /*!< IANA language code mask (length coded on 6 bits) */ + +#define NDEF_RTD_TEXT_PAYLOAD_LENGTH_MIN (sizeof(uint8_t) + sizeof(uint8_t)) /*!< Minimum Text Payload length */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD Text Type string */ +static const uint8_t ndefRtdTypeText[] = "T"; /*!< Text Record Type {0x54} */ + +const ndefConstBuffer8 bufRtdTypeText = { ndefRtdTypeText, sizeof(ndefRtdTypeText) - 1U }; /*!< Text Record Type buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * Text + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdTextPayloadGetLength(const ndefType* text) +{ + const ndefTypeRtdText* rtdText; + + if ( (text == NULL) || (text->id != NDEF_TYPE_ID_RTD_TEXT) ) + { + return 0; + } + + rtdText = &text->data.text; + + return sizeof(rtdText->status) + rtdText->bufLanguageCode.length + rtdText->bufSentence.length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdTextToPayloadItem(const ndefType* text, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdText* rtdText; + + if ( (text == NULL) || (text->id != NDEF_TYPE_ID_RTD_TEXT) || + (bufItem == NULL) ) + { + return NULL; + } + + rtdText = &text->data.text; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* Status byte */ + bufItem->buffer = &rtdText->status; + bufItem->length = sizeof(rtdText->status); + break; + + case 1: + /* Language Code */ + bufItem->buffer = rtdText->bufLanguageCode.buffer; + bufItem->length = rtdText->bufLanguageCode.length; + break; + + case 2: + /* Actual text */ + bufItem->buffer = rtdText->bufSentence.buffer; + bufItem->length = rtdText->bufSentence.length; + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTextInit(ndefType* text, uint8_t utfEncoding, const ndefConstBuffer8* bufLanguageCode, const ndefConstBuffer* bufSentence) +{ + ndefTypeRtdText* rtdText; + + if ( (text == NULL) || + (bufLanguageCode == NULL) || (bufLanguageCode->buffer == NULL) || (bufLanguageCode->length == 0U) || + (bufSentence == NULL) || (bufSentence->buffer == NULL) || (bufSentence->length == 0U) ) + { + return ERR_PARAM; + } + + if (bufLanguageCode->length > NDEF_RTD_TEXT_LANGUAGE_CODE_LEN_MASK) + { + return ERR_PROTO; + } + + if ( (utfEncoding != TEXT_ENCODING_UTF8) && (utfEncoding != TEXT_ENCODING_UTF16) ) + { + return ERR_PARAM; + } + + text->id = NDEF_TYPE_ID_RTD_TEXT; + text->getPayloadLength = ndefRtdTextPayloadGetLength; + text->getPayloadItem = ndefRtdTextToPayloadItem; + text->typeToRecord = ndefRtdTextToRecord; + rtdText = &text->data.text; + + rtdText->status = (utfEncoding << NDEF_TEXT_ENCODING_SHIFT) | (bufLanguageCode->length & NDEF_RTD_TEXT_LANGUAGE_CODE_LEN_MASK); + + rtdText->bufLanguageCode.buffer = bufLanguageCode->buffer; + rtdText->bufLanguageCode.length = bufLanguageCode->length; + + rtdText->bufSentence.buffer = bufSentence->buffer; + rtdText->bufSentence.length = bufSentence->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdText(const ndefType* text, uint8_t* utfEncoding, ndefConstBuffer8* bufLanguageCode, ndefConstBuffer* bufSentence) +{ + const ndefTypeRtdText* rtdText; + + if ( (text == NULL) || (text->id != NDEF_TYPE_ID_RTD_TEXT) || + (utfEncoding == NULL) || (bufLanguageCode == NULL) || (bufSentence == NULL) ) + { + return ERR_PARAM; + } + + rtdText = &text->data.text; + + *utfEncoding = (rtdText->status >> NDEF_TEXT_ENCODING_SHIFT) & 1U; + + bufLanguageCode->buffer = rtdText->bufLanguageCode.buffer; + bufLanguageCode->length = rtdText->bufLanguageCode.length; + + bufSentence->buffer = rtdText->bufSentence.buffer; + bufSentence->length = rtdText->bufSentence.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdText(const ndefConstBuffer* bufText, ndefType* text) +{ + ndefTypeRtdText* rtdText; + uint8_t status; + uint8_t languageCodeLength; + + if ( (bufText == NULL) || (bufText->buffer == NULL) || (bufText->length == 0U) || + (text == NULL) ) + { + return ERR_PARAM; + } + + if (bufText->length < NDEF_RTD_TEXT_PAYLOAD_LENGTH_MIN) /* Text Payload Min */ + { + return ERR_PROTO; + } + + text->id = NDEF_TYPE_ID_RTD_TEXT; + text->getPayloadLength = ndefRtdTextPayloadGetLength; + text->getPayloadItem = ndefRtdTextToPayloadItem; + text->typeToRecord = ndefRtdTextToRecord; + rtdText = &text->data.text; + + /* Extract info from the payload */ + status = bufText->buffer[NDEF_RTD_TEXT_STATUS_OFFSET]; + + rtdText->status = status; + + /* Extract info from the status byte */ + //uint8_t textUtfEncoding = (status & NDEF_TEXT_ENCODING_MASK) >> NDEF_TEXT_ENCODING_SHIFT; + languageCodeLength = (status & NDEF_RTD_TEXT_LANGUAGE_CODE_LEN_MASK); + + rtdText->bufLanguageCode.buffer = &(bufText->buffer[NDEF_RTD_TEXT_LANGUAGE_OFFSET]); + rtdText->bufLanguageCode.length = languageCodeLength; + + rtdText->bufSentence.buffer = &(bufText->buffer[NDEF_RTD_TEXT_LANGUAGE_OFFSET + languageCodeLength]); + rtdText->bufSentence.length = bufText->length - sizeof(status) - languageCodeLength; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdText(const ndefRecord* record, ndefType* text) +{ + const ndefType* type; + + if ( (record == NULL) || (text == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeText)) /* "T" */ + { + return ERR_PROTO; + } + + type = ndefRecordGetNdefType(record); + if ( (type != NULL) && (type->id == NDEF_TYPE_ID_RTD_TEXT) ) + { + (void)ST_MEMCPY(text, type, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdText(&record->bufPayload, text); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTextToRecord(const ndefType* text, ndefRecord* record) +{ + if ( (text == NULL) || (text->id != NDEF_TYPE_ID_RTD_TEXT) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "T" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeText); + + if (ndefRecordSetNdefType(record, text) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_tnep.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_tnep.c new file mode 100644 index 0000000..90f9992 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_tnep.c @@ -0,0 +1,711 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF TNEP (Tag NDEF Exchange Protocol record) types + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_tnep.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_TNEP_SUPPORT + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! TNEP defines */ +#define NDEF_TNEP_SERVICE_NAME_URI_LENGTH_LENGTH sizeof(uint8_t) /*!< Service Name URI length's length */ + +/*! TNEP Service Parameter defines */ +#define NDEF_RTD_TNEP_SP_VERSION_OFFSET 0U /*!< TNEP Service Parameter TNEP Version offset */ +#define NDEF_RTD_TNEP_SP_SERVICE_URI_LENGTH_OFFSET 1U /*!< TNEP Service Parameter URI length offset */ +#define NDEF_RTD_TNEP_SP_SERVICE_URI_OFFSET 2U /*!< TNEP Service Parameter URI offset */ +#define NDEF_RTD_TNEP_SP_SERVICE_URI_LENGTH_MAX 255U /*!< TNEP Service Parameter URI max length (bytes) */ +#define NDEF_RTD_TNEP_SP_COMMUNICATION_MODE_OFFSET 2U /*!< TNEP Service Parameter Communication Mode offset */ +#define NDEF_RTD_TNEP_SP_MIN_WAITING_TIME_OFFSET 3U /*!< TNEP Service Parameter Minimum Waiting Time offset */ +#define NDEF_RTD_TNEP_SP_MAX_WT_EXTENSIONS_OFFSET 4U /*!< TNEP Service Parameter Maximum Waiting Time Extensions offset */ +#define NDEF_RTD_TNEP_SP_MAX_MESSAGE_SIZE_OFFSET 5U /*!< TNEP Service Parameter Maximum NDEF Message Size (bytes) offset */ +#define NDEF_RTD_TNEP_SP_MINIMUM_LENGTH 8U /*!< TNEP Service Parameter minimum length (bytes) */ + +/*! TNEP Service Select defines */ +#define NDEF_RTD_TNEP_SS_SERVICE_URI_LENGTH_OFFSET 0U /*!< TNEP Service Select URI length offset */ +#define NDEF_RTD_TNEP_SS_SERVICE_URI_OFFSET 1U /*!< TNEP Service Select URI offset */ +#define NDEF_RTD_TNEP_SS_MINIMUM_LENGTH 2U /*!< TNEP Service Select minimum length (bytes) */ + +/*! TNEP Service Select defines */ +#define NDEF_RTD_TNEP_STATUS_TYPE_OFFSET 0U /*!< TNEP Status Type offset */ +#define NDEF_RTD_TNEP_STATUS_MINIMUM_LENGTH 1U /*!< TNEP Status minimum length (bytes) */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD TNEP Type strings */ +static const uint8_t ndefRtdTypeTnepServiceParameter[] = "Tp"; /*!< Tnep Service Parameter Record Type */ +static const uint8_t ndefRtdTypeTnepServiceSelect[] = "Ts"; /*!< Tnep Service Select Record Type */ +static const uint8_t ndefRtdTypeTnepStatus[] = "Te"; /*!< Tnep Status Record Type */ + +const ndefConstBuffer8 bufRtdTypeTnepServiceParameter = { ndefRtdTypeTnepServiceParameter, sizeof(ndefRtdTypeTnepServiceParameter) - 1U }; /*!< TNEP Service Parameter Type Record buffer */ +const ndefConstBuffer8 bufRtdTypeTnepServiceSelect = { ndefRtdTypeTnepServiceSelect, sizeof(ndefRtdTypeTnepServiceSelect) - 1U }; /*!< TNEP Service Select Type Record buffer */ +const ndefConstBuffer8 bufRtdTypeTnepStatus = { ndefRtdTypeTnepStatus, sizeof(ndefRtdTypeTnepStatus) - 1U }; /*!< TNEP Status Type Record buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * TNEP Service Parameter + */ + +/*****************************************************************************/ +static uint32_t ndefRtdTnepServiceParameterGetPayloadLength(const ndefType* type) +{ + const ndefTypeRtdTnepServiceParameter* rtdServiceParameter; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER) ) + { + return 0; + } + + rtdServiceParameter = &type->data.tnepServiceParameter; + + return sizeof(rtdServiceParameter->tnepVersion) + + NDEF_TNEP_SERVICE_NAME_URI_LENGTH_LENGTH + + rtdServiceParameter->bufServiceNameUri.length + + sizeof(rtdServiceParameter->communicationMode) + + sizeof(rtdServiceParameter->minimumWaitingTime) + + sizeof(rtdServiceParameter->maximumWaitingTimeExtensions) + + sizeof(rtdServiceParameter->maximumNdefMessageSize); +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdTnepServiceParameterToPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdTnepServiceParameter* rtdServiceParameter; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER) + || (bufItem == NULL) ) + { + return NULL; + } + + rtdServiceParameter = &type->data.tnepServiceParameter; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* TNEP version byte */ + bufItem->buffer = &rtdServiceParameter->tnepVersion; + bufItem->length = sizeof(rtdServiceParameter->tnepVersion); + break; + + case 1: + /* Service URI length byte */ + bufItem->buffer = (const uint8_t*)&(rtdServiceParameter->bufServiceNameUri.length); + bufItem->length = NDEF_TNEP_SERVICE_NAME_URI_LENGTH_LENGTH; + break; + + case 2: + /* Service URI string */ + bufItem->buffer = rtdServiceParameter->bufServiceNameUri.buffer; + bufItem->length = rtdServiceParameter->bufServiceNameUri.length; + break; + + case 3: + /* TNEP communication Mode byte */ + bufItem->buffer = &rtdServiceParameter->communicationMode; + bufItem->length = sizeof(rtdServiceParameter->communicationMode); + break; + + case 4: + /* Minimum waiting time byte */ + bufItem->buffer = &rtdServiceParameter->minimumWaitingTime; + bufItem->length = sizeof(rtdServiceParameter->minimumWaitingTime); + break; + + case 5: + /* Maximum waiting time extensions byte */ + bufItem->buffer = &rtdServiceParameter->maximumWaitingTimeExtensions; + bufItem->length = sizeof(rtdServiceParameter->maximumWaitingTimeExtensions); + break; + + case 6: + /* Maximum NDEF message size */ + bufItem->buffer = rtdServiceParameter->maximumNdefMessageSize; + bufItem->length = sizeof(rtdServiceParameter->maximumNdefMessageSize); + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +#ifdef NDEF_PROVIDE_HELPER_FUNCTIONS +/*****************************************************************************/ +uint8_t ndefRtdTnepServiceParameterComputeWtInt(float twait) +{ + return ceil(4 * ((log(twait)/0.69314) + 1)); +} + + +/*****************************************************************************/ +float ndefRtdTnepServiceParameterComputeTwait(uint8_t wtInt) +{ + return powf(2, (((float)wtInt/4) - 1)); +} +#endif + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepServiceParameterInit(ndefType* type, uint8_t tnepVersion, const ndefConstBuffer* bufServiceUri, uint8_t comMode, uint8_t minWaitingTime, uint8_t maxExtensions, uint16_t maxMessageSize) +{ + ndefTypeRtdTnepServiceParameter* rtdServiceParameter; + + if ( (type == NULL) || (bufServiceUri == NULL) + || (bufServiceUri->buffer == NULL) || (bufServiceUri->length == 0U) + || (bufServiceUri->length > (NDEF_RTD_TNEP_SP_SERVICE_URI_LENGTH_MAX)) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER; + type->getPayloadLength = ndefRtdTnepServiceParameterGetPayloadLength; + type->getPayloadItem = ndefRtdTnepServiceParameterToPayloadItem; + type->typeToRecord = ndefRtdTnepServiceParameterToRecord; + rtdServiceParameter = &type->data.tnepServiceParameter; + + rtdServiceParameter->tnepVersion = tnepVersion; + rtdServiceParameter->bufServiceNameUri.length = bufServiceUri->length; + rtdServiceParameter->bufServiceNameUri.buffer = bufServiceUri->buffer; + rtdServiceParameter->communicationMode = comMode; + rtdServiceParameter->minimumWaitingTime = minWaitingTime; + rtdServiceParameter->maximumWaitingTimeExtensions = maxExtensions; + rtdServiceParameter->maximumNdefMessageSize[0] = (uint8_t)(maxMessageSize >> 8U); + rtdServiceParameter->maximumNdefMessageSize[1] = (uint8_t)(maxMessageSize & 0xFFU); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdTnepServiceParameter(const ndefType* type, uint8_t* tnepVersion, ndefConstBuffer* bufServiceUri, uint8_t* comMode, uint8_t* minWaitingTime, uint8_t* maxExtensions, uint16_t* maxMessageSize) +{ + const ndefTypeRtdTnepServiceParameter* rtdServiceParameter; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER) + || (bufServiceUri == NULL) || (tnepVersion == NULL) || (comMode == NULL) + || (minWaitingTime == NULL) || (maxExtensions == NULL) || (maxMessageSize == NULL) ) + { + return ERR_PARAM; + } + + rtdServiceParameter = &type->data.tnepServiceParameter; + + *tnepVersion = rtdServiceParameter->tnepVersion; + bufServiceUri->buffer = rtdServiceParameter->bufServiceNameUri.buffer; + bufServiceUri->length = rtdServiceParameter->bufServiceNameUri.length; + *comMode = rtdServiceParameter->communicationMode; + *minWaitingTime = rtdServiceParameter->minimumWaitingTime; + *maxExtensions = rtdServiceParameter->maximumWaitingTimeExtensions; + *maxMessageSize = GETU16(rtdServiceParameter->maximumNdefMessageSize); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdTnepServiceParameter(const ndefConstBuffer* bufTnepServiceParameter, ndefType* type) +{ + uint8_t tnepVersion; + ndefConstBuffer bufServiceUri; + uint8_t commMode; + uint8_t minWaitingTime; + uint8_t maxWaitingTimeExtensions; + uint16_t maxNdefMessageSize; + uint32_t maxNdefMessageSizeOffset; + + if ( (bufTnepServiceParameter == NULL) || (bufTnepServiceParameter->buffer == NULL) || (bufTnepServiceParameter->length < (NDEF_RTD_TNEP_SP_MINIMUM_LENGTH)) || + (type == NULL)) + { + return ERR_PARAM; + } + + /* Extract info from the payload */ + tnepVersion = bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_VERSION_OFFSET]; + bufServiceUri.buffer = &bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_SERVICE_URI_OFFSET]; + bufServiceUri.length = bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_SERVICE_URI_LENGTH_OFFSET]; + commMode = bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_COMMUNICATION_MODE_OFFSET + bufServiceUri.length]; + minWaitingTime = bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_MIN_WAITING_TIME_OFFSET + bufServiceUri.length]; + maxWaitingTimeExtensions = bufTnepServiceParameter->buffer[NDEF_RTD_TNEP_SP_MAX_WT_EXTENSIONS_OFFSET + bufServiceUri.length]; + maxNdefMessageSizeOffset = NDEF_RTD_TNEP_SP_MAX_MESSAGE_SIZE_OFFSET + bufServiceUri.length; + maxNdefMessageSize = GETU16(&bufTnepServiceParameter->buffer[maxNdefMessageSizeOffset]); + + return ndefRtdTnepServiceParameterInit(type, tnepVersion, &bufServiceUri, commMode, minWaitingTime, maxWaitingTimeExtensions, maxNdefMessageSize); +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdTnepServiceParameter(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceParameter)) /* "Tp" */ + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + if (record->bufPayload.length < NDEF_RTD_TNEP_SP_MINIMUM_LENGTH) + { + return ERR_PROTO; + } + + return ndefPayloadToRtdTnepServiceParameter(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepServiceParameterToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_PARAMETER) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "Tp" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceParameter); + + (void)ndefRecordSetNdefType(record, type); + + return ERR_NONE; +} + + +/* + * TNEP Service Select + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdTnepServiceSelectGetPayloadLength(const ndefType* type) +{ + const ndefTypeRtdTnepServiceSelect* rtdServiceSelect; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT) ) + { + return 0; + } + + rtdServiceSelect = &type->data.tnepServiceSelect; + + return NDEF_TNEP_SERVICE_NAME_URI_LENGTH_LENGTH + rtdServiceSelect->bufServiceNameUri.length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdTnepServiceSelectToPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdTnepServiceSelect* rtdServiceSelect; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT) + || (bufItem == NULL) ) + { + return NULL; + } + + rtdServiceSelect = &type->data.tnepServiceSelect; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* Service URI length byte */ + bufItem->buffer = (const uint8_t*)&rtdServiceSelect->bufServiceNameUri.length; + bufItem->length = NDEF_TNEP_SERVICE_NAME_URI_LENGTH_LENGTH; + break; + + case 1: + /* Service URI string */ + bufItem->buffer = rtdServiceSelect->bufServiceNameUri.buffer; + bufItem->length = rtdServiceSelect->bufServiceNameUri.length; + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepServiceSelectInit(ndefType* type, const ndefConstBuffer* bufServiceUri) +{ + ndefTypeRtdTnepServiceSelect* rtdServiceSelect; + + if ( (type == NULL) || (bufServiceUri == NULL) + || (bufServiceUri->buffer == NULL) || (bufServiceUri->length == 0U) + || (bufServiceUri->length > (NDEF_RTD_TNEP_SP_SERVICE_URI_LENGTH_MAX))) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT; + type->getPayloadLength = ndefRtdTnepServiceSelectGetPayloadLength; + type->getPayloadItem = ndefRtdTnepServiceSelectToPayloadItem; + type->typeToRecord = ndefRtdTnepServiceSelectToRecord; + rtdServiceSelect = &type->data.tnepServiceSelect; + + rtdServiceSelect->bufServiceNameUri.length = bufServiceUri->length; + rtdServiceSelect->bufServiceNameUri.buffer = bufServiceUri->buffer; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdTnepServiceSelect(const ndefType* type, ndefConstBuffer* bufServiceUri) +{ + const ndefTypeRtdTnepServiceSelect* rtdServiceSelect; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT) || + (bufServiceUri == NULL) ) + { + return ERR_PARAM; + } + + rtdServiceSelect = &type->data.tnepServiceSelect; + + bufServiceUri->buffer = rtdServiceSelect->bufServiceNameUri.buffer; + bufServiceUri->length = rtdServiceSelect->bufServiceNameUri.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdTnepServiceSelect(const ndefConstBuffer* bufTnepServiceSelect, ndefType* type) +{ + ndefConstBuffer bufServiceUri; + + if ( (bufTnepServiceSelect == NULL) || (bufTnepServiceSelect->buffer == NULL) || (bufTnepServiceSelect->length < (NDEF_RTD_TNEP_SS_MINIMUM_LENGTH)) || + (type == NULL)) + { + return ERR_PARAM; + } + + /* Extract info from the payload */ + bufServiceUri.buffer = &bufTnepServiceSelect->buffer[NDEF_RTD_TNEP_SS_SERVICE_URI_OFFSET]; + bufServiceUri.length = bufTnepServiceSelect->buffer[NDEF_RTD_TNEP_SS_SERVICE_URI_LENGTH_OFFSET]; + + return ndefRtdTnepServiceSelectInit(type, &bufServiceUri); +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdTnepServiceSelect(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceSelect)) /* "Ts" */ + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + if (record->bufPayload.length < NDEF_RTD_TNEP_SS_MINIMUM_LENGTH) + { + return ERR_PROTO; + } + + return ndefPayloadToRtdTnepServiceSelect(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepServiceSelectToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_SERVICE_SELECT) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "Ts" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceSelect); + + (void)ndefRecordSetNdefType(record, type); + + return ERR_NONE; +} + + +/* + * TNEP Status + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdTnepStatusGetPayloadLength(const ndefType* type) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_STATUS) ) + { + return 0; + } + + return sizeof(type->data.tnepStatus.statusType); +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdTnepStatusToPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdTnepStatus* rtdStatus; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_STATUS) + || (bufItem == NULL) ) + { + return NULL; + } + + rtdStatus = &type->data.tnepStatus; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* Status type byte */ + bufItem->buffer = &rtdStatus->statusType; + bufItem->length = sizeof(rtdStatus->statusType); + break; + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepStatusInit(ndefType* type, uint8_t statusType) +{ + ndefTypeRtdTnepStatus* rtdStatus; + + if (type == NULL) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_TNEP_STATUS; + type->getPayloadLength = ndefRtdTnepStatusGetPayloadLength; + type->getPayloadItem = ndefRtdTnepStatusToPayloadItem; + type->typeToRecord = ndefRtdTnepStatusToRecord; + rtdStatus = &type->data.tnepStatus; + + rtdStatus->statusType = statusType; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdTnepStatus(const ndefType* type, uint8_t* statusType) +{ + const ndefTypeRtdTnepStatus* rtdStatus; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_STATUS) || + (statusType == NULL) ) + { + return ERR_PARAM; + } + + rtdStatus = &type->data.tnepStatus; + + *statusType = rtdStatus->statusType; + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdTnepStatus(const ndefConstBuffer* bufTnepStatus, ndefType* type) +{ + uint8_t statusType; + + if ( (bufTnepStatus == NULL) || (bufTnepStatus->buffer == NULL) || (bufTnepStatus->length < (NDEF_RTD_TNEP_STATUS_MINIMUM_LENGTH)) || + (type == NULL)) + { + return ERR_PARAM; + } + + /* Extract info from the payload */ + statusType = bufTnepStatus->buffer[NDEF_RTD_TNEP_STATUS_TYPE_OFFSET]; + + return ndefRtdTnepStatusInit(type, statusType); +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdTnepStatus(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepStatus)) /* "Te" */ + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_TNEP_STATUS) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + if (record->bufPayload.length < NDEF_RTD_TNEP_STATUS_MINIMUM_LENGTH) + { + return ERR_PROTO; + } + + return ndefPayloadToRtdTnepStatus(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdTnepStatusToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_TNEP_STATUS) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "Te" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepStatus); + + (void)ndefRecordSetNdefType(record, type); + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_uri.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_uri.c new file mode 100644 index 0000000..1401c9e --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_uri.c @@ -0,0 +1,400 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD URI type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_uri.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_URI_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/*! URI defines */ +#define NDEF_RTD_URI_PROTOCOL_LEN 1U /*!< URI protocol length */ +#define NDEF_RTD_URI_PAYLOAD_LENGTH_MIN (NDEF_RTD_URI_PROTOCOL_LEN + sizeof(uint8_t)) /*!< URI minimum payload length */ + +/*! URI defines */ +#define NDEF_RTD_URI_ID_CODE_OFFSET 0U /*!< URI Id code offset */ +#define NDEF_RTD_URI_FIELD_OFFSET 1U /*!< URI field offset */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD URI Type string */ +static const uint8_t ndefRtdTypeUri[] = "U"; /*!< URI Record Type {0x55} */ + +const ndefConstBuffer8 bufRtdTypeUri = { ndefRtdTypeUri, sizeof(ndefRtdTypeUri) - 1U }; /*!< URI Record Type buffer */ + + +/*! URI Type strings */ +static const uint8_t ndefUriPrefixNone[] = ""; +static const uint8_t ndefUriPrefixHttpWww[] = "http://www."; +static const uint8_t ndefUriPrefixHttpsWww[] = "https://www."; +static const uint8_t ndefUriPrefixHttp[] = "http://"; +static const uint8_t ndefUriPrefixHttps[] = "https://"; +static const uint8_t ndefUriPrefixTel[] = "tel:"; +static const uint8_t ndefUriPrefixMailto[] = "mailto:"; +static const uint8_t ndefUriPrefixFtpAnonymous[] = "ftp://anonymous:anonymous@"; +static const uint8_t ndefUriPrefixFtpFtp[] = "ftp://ftp."; +static const uint8_t ndefUriPrefixFtps[] = "ftps://"; +static const uint8_t ndefUriPrefixSftp[] = "sftp://"; +static const uint8_t ndefUriPrefixSmb[] = "smb://"; +static const uint8_t ndefUriPrefixNfs[] = "nfs://"; +static const uint8_t ndefUriPrefixFtp[] = "ftp://"; +static const uint8_t ndefUriPrefixDav[] = "dav://"; +static const uint8_t ndefUriPrefixNews[] = "news:"; +static const uint8_t ndefUriPrefixTelnet[] = "telnet://"; +static const uint8_t ndefUriPrefixImap[] = "imap:"; +static const uint8_t ndefUriPrefixRtsp[] = "rtsp://"; +static const uint8_t ndefUriPrefixUrn[] = "urn:"; +static const uint8_t ndefUriPrefixPop[] = "pop:"; +static const uint8_t ndefUriPrefixSip[] = "sip:"; +static const uint8_t ndefUriPrefixSips[] = "sips:"; +static const uint8_t ndefUriPrefixTftp[] = "tftp:"; +static const uint8_t ndefUriPrefixBtspp[] = "btspp://"; +static const uint8_t ndefUriPrefixBtl2cap[] = "btl2cap://"; +static const uint8_t ndefUriPrefixBtgoep[] = "btgoep://"; +static const uint8_t ndefUriPrefixTcpobex[] = "tcpobex://"; +static const uint8_t ndefUriPrefixIrdaobex[] = "irdaobex://"; +static const uint8_t ndefUriPrefixFile[] = "file://"; +static const uint8_t ndefUriPrefixUrnEpcId[] = "urn:epc:id:"; +static const uint8_t ndefUriPrefixUrnEpcTag[] = "urn:epc:tag"; +static const uint8_t ndefUriPrefixUrnEpcPat[] = "urn:epc:pat:"; +static const uint8_t ndefUriPrefixUrnEpcRaw[] = "urn:epc:raw:"; +static const uint8_t ndefUriPrefixUrnEpe[] = "urn:epc:"; +static const uint8_t ndefUriPrefixUrnNfc[] = "urn:nfc:"; +static const uint8_t ndefUriPrefixEmpty[] = ""; /* Autodetect filler */ + +static const ndefConstBuffer ndefUriPrefix[NDEF_URI_PREFIX_COUNT] = +{ + { ndefUriPrefixNone , sizeof(ndefUriPrefixNone ) - 1U }, + { ndefUriPrefixHttpWww , sizeof(ndefUriPrefixHttpWww ) - 1U }, + { ndefUriPrefixHttpsWww , sizeof(ndefUriPrefixHttpsWww ) - 1U }, + { ndefUriPrefixHttp , sizeof(ndefUriPrefixHttp ) - 1U }, + { ndefUriPrefixHttps , sizeof(ndefUriPrefixHttps ) - 1U }, + { ndefUriPrefixTel , sizeof(ndefUriPrefixTel ) - 1U }, + { ndefUriPrefixMailto , sizeof(ndefUriPrefixMailto ) - 1U }, + { ndefUriPrefixFtpAnonymous, sizeof(ndefUriPrefixFtpAnonymous) - 1U }, + { ndefUriPrefixFtpFtp , sizeof(ndefUriPrefixFtpFtp ) - 1U }, + { ndefUriPrefixFtps , sizeof(ndefUriPrefixFtps ) - 1U }, + { ndefUriPrefixSftp , sizeof(ndefUriPrefixSftp ) - 1U }, + { ndefUriPrefixSmb , sizeof(ndefUriPrefixSmb ) - 1U }, + { ndefUriPrefixNfs , sizeof(ndefUriPrefixNfs ) - 1U }, + { ndefUriPrefixFtp , sizeof(ndefUriPrefixFtp ) - 1U }, + { ndefUriPrefixDav , sizeof(ndefUriPrefixDav ) - 1U }, + { ndefUriPrefixNews , sizeof(ndefUriPrefixNews ) - 1U }, + { ndefUriPrefixTelnet , sizeof(ndefUriPrefixTelnet ) - 1U }, + { ndefUriPrefixImap , sizeof(ndefUriPrefixImap ) - 1U }, + { ndefUriPrefixRtsp , sizeof(ndefUriPrefixRtsp ) - 1U }, + { ndefUriPrefixUrn , sizeof(ndefUriPrefixUrn ) - 1U }, + { ndefUriPrefixPop , sizeof(ndefUriPrefixPop ) - 1U }, + { ndefUriPrefixSip , sizeof(ndefUriPrefixSip ) - 1U }, + { ndefUriPrefixSips , sizeof(ndefUriPrefixSips ) - 1U }, + { ndefUriPrefixTftp , sizeof(ndefUriPrefixTftp ) - 1U }, + { ndefUriPrefixBtspp , sizeof(ndefUriPrefixBtspp ) - 1U }, + { ndefUriPrefixBtl2cap , sizeof(ndefUriPrefixBtl2cap ) - 1U }, + { ndefUriPrefixBtgoep , sizeof(ndefUriPrefixBtgoep ) - 1U }, + { ndefUriPrefixTcpobex , sizeof(ndefUriPrefixTcpobex ) - 1U }, + { ndefUriPrefixIrdaobex , sizeof(ndefUriPrefixIrdaobex ) - 1U }, + { ndefUriPrefixFile , sizeof(ndefUriPrefixFile ) - 1U }, + { ndefUriPrefixUrnEpcId , sizeof(ndefUriPrefixUrnEpcId ) - 1U }, + { ndefUriPrefixUrnEpcTag , sizeof(ndefUriPrefixUrnEpcTag ) - 1U }, + { ndefUriPrefixUrnEpcPat , sizeof(ndefUriPrefixUrnEpcPat ) - 1U }, + { ndefUriPrefixUrnEpcRaw , sizeof(ndefUriPrefixUrnEpcRaw ) - 1U }, + { ndefUriPrefixUrnEpe , sizeof(ndefUriPrefixUrnEpe ) - 1U }, + { ndefUriPrefixUrnNfc , sizeof(ndefUriPrefixUrnNfc ) - 1U }, + { ndefUriPrefixEmpty , sizeof(ndefUriPrefixEmpty ) - 1U } +}; + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * URI + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdUriPayloadGetLength(const ndefType* uri) +{ + const ndefTypeRtdUri* rtdUri; + + if ( (uri == NULL) || (uri->id != NDEF_TYPE_ID_RTD_URI) ) + { + return 0; + } + + rtdUri = &uri->data.uri; + + return sizeof(rtdUri->protocol) + rtdUri->bufUriString.length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdUriToPayloadItem(const ndefType* uri, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdUri* rtdUri; + + if ( (uri == NULL) || (uri->id != NDEF_TYPE_ID_RTD_URI) || + (bufItem == NULL) ) + { + return NULL; + } + + rtdUri = &uri->data.uri; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* Protocol byte */ + bufItem->buffer = &rtdUri->protocol; + bufItem->length = sizeof(rtdUri->protocol); + break; + + case 1: + /* URI string */ + bufItem->buffer = rtdUri->bufUriString.buffer; + bufItem->length = rtdUri->bufUriString.length; + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +static ndefStatus ndefRtdUriProtocolAutodetect(uint8_t* protocol, ndefConstBuffer* bufUriString) +{ + if ( (protocol == NULL) || + (*protocol != NDEF_URI_PREFIX_AUTODETECT) || + (bufUriString == NULL) ) + { + return ERR_PARAM; + } + + for (uint8_t i = 0; i < NDEF_URI_PREFIX_COUNT; i++) /* Protocol fits in 1 byte => uint8_t */ + { + if (ndefUriPrefix[i].length > 0U) + { + if (ST_BYTECMP(bufUriString->buffer, ndefUriPrefix[i].buffer, ndefUriPrefix[i].length) == 0) + { + *protocol = i; + /* Move after the protocol string */ + bufUriString->buffer = &bufUriString->buffer[ndefUriPrefix[i].length]; + bufUriString->length -= ndefUriPrefix[i].length; + return ERR_NONE; + } + } + } + + *protocol = NDEF_URI_PREFIX_NONE; + + return ERR_NOTFOUND; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdUriInit(ndefType* uri, uint8_t protocol, const ndefConstBuffer* bufUriString) +{ + ndefTypeRtdUri* rtdUri; + ndefConstBuffer bufUri; + uint8_t protocolDetect; + + if ( (uri == NULL) || (protocol >= NDEF_URI_PREFIX_COUNT) || + (bufUriString == NULL) || (bufUriString->buffer == NULL) || (bufUriString->length == 0U) ) + { + return ERR_PARAM; + } + + uri->id = NDEF_TYPE_ID_RTD_URI; + uri->getPayloadLength = ndefRtdUriPayloadGetLength; + uri->getPayloadItem = ndefRtdUriToPayloadItem; + uri->typeToRecord = ndefRtdUriToRecord; + rtdUri = &uri->data.uri; + + bufUri.buffer = bufUriString->buffer; + bufUri.length = bufUriString->length; + protocolDetect = protocol; + if (protocol == NDEF_URI_PREFIX_AUTODETECT) + { + /* Update protocol and URI buffer */ + (void)ndefRtdUriProtocolAutodetect(&protocolDetect, &bufUri); + } + rtdUri->protocol = protocolDetect; + + rtdUri->bufUriString.buffer = bufUri.buffer; + rtdUri->bufUriString.length = bufUri.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdUri(const ndefType* uri, ndefConstBuffer* bufProtocol, ndefConstBuffer* bufUriString) +{ + const ndefTypeRtdUri* rtdUri; + + if ( (uri == NULL) || (uri->id != NDEF_TYPE_ID_RTD_URI) || + (bufProtocol == NULL) || (bufUriString == NULL) ) + { + return ERR_PARAM; + } + + rtdUri = &uri->data.uri; + + bufProtocol->buffer = ndefUriPrefix[rtdUri->protocol].buffer; + bufProtocol->length = ndefUriPrefix[rtdUri->protocol].length; + + bufUriString->buffer = rtdUri->bufUriString.buffer; + bufUriString->length = rtdUri->bufUriString.length; + + return ERR_NONE; +} + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdUri(const ndefConstBuffer* bufUri, ndefType* uri) +{ + uint8_t protocol; + + if ( (bufUri == NULL) || (bufUri->buffer == NULL) || + (uri == NULL) ) + { + return ERR_PARAM; + } + + if (bufUri->length < NDEF_RTD_URI_PAYLOAD_LENGTH_MIN) + { + return ERR_PROTO; + } + + /* Extract info from the payload */ + protocol = bufUri->buffer[NDEF_RTD_URI_ID_CODE_OFFSET]; + + ndefConstBuffer bufStringUri; + bufStringUri.buffer = &bufUri->buffer[NDEF_RTD_URI_FIELD_OFFSET]; + bufStringUri.length = bufUri->length - sizeof(protocol); + + return ndefRtdUriInit(uri, protocol, &bufStringUri); +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdUri(const ndefRecord* record, ndefType* uri) +{ + const ndefType* type; + + if ( (record == NULL) || (uri == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeUri)) /* "U" */ + { + return ERR_PROTO; + } + + type = ndefRecordGetNdefType(record); + if ( (type != NULL) && (type->id == NDEF_TYPE_ID_RTD_URI) ) + { + (void)ST_MEMCPY(uri, type, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdUri(&record->bufPayload, uri); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdUriToRecord(const ndefType* uri, ndefRecord* record) +{ + if ( (uri == NULL) || (uri->id != NDEF_TYPE_ID_RTD_URI) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "U" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeUri); + + if (ndefRecordSetNdefType(record, uri) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_vcard.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_vcard.c new file mode 100644 index 0000000..0c87450 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_vcard.c @@ -0,0 +1,723 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF MIME vCard type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_vcard.h" +#include "utils.h" + + +#if NDEF_TYPE_VCARD_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! vCard Type strings */ +static const uint8_t ndefMediaTypeVCard[] = "text/x-vCard"; /*!< vCard Type */ + +const ndefConstBuffer8 bufMediaTypeVCard = { ndefMediaTypeVCard, sizeof(ndefMediaTypeVCard) - 1U }; /*!< vCard Type buffer */ + + +/*! vCard delimiters */ +static const uint8_t COLON[] = ":"; +static const uint8_t SEMICOLON[] = ";"; +static const uint8_t NEWLINE[] = "\r\n"; +static const uint8_t LINEFEED[] = "\n"; + +static const ndefConstBuffer bufColon = { COLON, sizeof(COLON) - 1U }; /*!< ":" */ +static const ndefConstBuffer bufSemicolon = { SEMICOLON, sizeof(SEMICOLON) - 1U }; /*!< ";" */ +static const ndefConstBuffer bufNewLine = { NEWLINE, sizeof(NEWLINE) - 1U }; /*!< "\r\n" */ +static const ndefConstBuffer bufLineFeed = { LINEFEED, sizeof(LINEFEED) - 1U }; /*!< "\n" */ + +/*! vCard Payload minimal length (BEGIN:VCARD + VERSION:2.1 + END:VCARD) */ +#define NDEF_VCARD_PAYLOAD_LENGTH_MIN ( sizeof("BEGIN:VCARD") - 1U + sizeof("VERSION:2.1") - 1U + sizeof("END:VCARD") - 1U ) + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * VCard + */ + + +/* vCard Helper functions */ + + +/*****************************************************************************/ +bool ndefBufferMatch(const ndefConstBuffer* buf1, const ndefConstBuffer* buf2) +{ + if ( (buf1 == NULL) || (buf2 == NULL) ) + { + return false; + } + else if ( (buf1->buffer == buf2->buffer) && + (buf1->length == buf2->length) ) + { + return true; + } + else + { + if ( (buf1->length != 0U) && + (buf1->length == buf2->length) && + (ST_BYTECMP(buf1->buffer, buf2->buffer, buf1->length) == 0) ) + { + return true; + } + } + + return false; +} + + +/*****************************************************************************/ +static ndefStatus ndefBufferFind(const ndefConstBuffer* bufPayload, const ndefConstBuffer* bufMarker, uint32_t* offset) +{ + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (bufMarker == NULL) || (bufMarker->buffer == NULL) ) + { + return ERR_PARAM; + } + + uint32_t i = 0; + while ((i + bufMarker->length) <= bufPayload->length) + { + ndefConstBuffer bufOffset; + bufOffset.buffer = &bufPayload->buffer[i]; + bufOffset.length = bufMarker->length; + + if (ndefBufferMatch(&bufOffset, bufMarker) == true) + { + if (offset != NULL) + { + *offset = i; + } + return ERR_NONE; + } + i++; + } + + return ERR_NOTFOUND; +} + + +/*****************************************************************************/ +static ndefStatus ndefVCardGetPropertyType(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufType) +{ + ndefStatus err; + + if ( (bufProperty == NULL) || (bufType == NULL) ) + { + return ERR_PARAM; + } + + /* Look for the type delimiter semicolon ":" */ + uint32_t colonOffset; + err = ndefBufferFind(bufProperty, &bufColon, &colonOffset); + if (err != ERR_NONE) + { + return err; + } + + bufType->buffer = bufProperty->buffer; + bufType->length = colonOffset; + + /* Look for the subtype delimiter semicolon ";", if any */ + uint32_t semicolonOffset; + err = ndefBufferFind(bufProperty, &bufSemicolon, &semicolonOffset); + if (err == ERR_NONE) + { + bufType->length = MIN(semicolonOffset, colonOffset); /* Type is ahead ";" or ":" */ + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefVCardGetPropertySubtype(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufSubtype) +{ + ndefStatus err; + + ///* These parameters check are not needed as long as this function is only + // called internally (being static) because these parameters are checked by the caller */ + //if ( (bufProperty == NULL) || (bufSubtype == NULL) ) + //{ + // return ERR_PARAM; + //} + + /* Look for the type delimiter colon ":" */ + uint32_t colonOffset; + err = ndefBufferFind(bufProperty, &bufColon, &colonOffset); + if (err != ERR_NONE) + { + return err; + } + + /* Look for the subtype delimiter semicolon ";" */ + uint32_t semicolonOffset; + err = ndefBufferFind(bufProperty, &bufSemicolon, &semicolonOffset); + if (err != ERR_NONE) + { + return err; + } + + /* The subtype is between the first semicolon ";" delimiter and ":" delimiter */ + if (semicolonOffset < colonOffset) + { + bufSubtype->buffer = &bufProperty->buffer[semicolonOffset + bufSemicolon.length]; + bufSubtype->length = colonOffset - (semicolonOffset + bufSemicolon.length); + return ERR_NONE; + } + + return ERR_NOTFOUND; +} + + +/*****************************************************************************/ +static ndefStatus ndefVCardGetPropertyEOL(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufEOL) +{ + ndefStatus err; + uint32_t offset; + + if ( (bufProperty == NULL) || (bufEOL == NULL) ) + { + return ERR_PARAM; + } + + /* Look for "\r\n" */ + err = ndefBufferFind(bufProperty, &bufNewLine, &offset); /* "\r\n" */ + if (err == ERR_NONE) + { + bufEOL->buffer = bufNewLine.buffer; + bufEOL->length = bufNewLine.length; + } + else + { + /* Look for "\n" */ + err = ndefBufferFind(bufProperty, &bufLineFeed, &offset); /* "\n" */ + if (err == ERR_NONE) + { + bufEOL->buffer = bufLineFeed.buffer; + bufEOL->length = bufLineFeed.length; + } + else + { + bufEOL->buffer = NULL; + bufEOL->length = 0; + } + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefVCardGetPropertyValue(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufValue) +{ + ndefStatus err; + + if ( (bufProperty == NULL) || (bufProperty->buffer == NULL) || + (bufValue == NULL) ) + { + return ERR_PARAM; + } + + /* Look for the type delimiter colon ":" */ + uint32_t colonOffset; + err = ndefBufferFind(bufProperty, &bufColon, &colonOffset); + if (err != ERR_NONE) + { + return err; + } + + /* Look for the End-Of-Line */ + ndefConstBuffer bufEOL; + err = ndefVCardGetPropertyEOL(bufProperty, &bufEOL); + if (err != ERR_NONE) + { + return err; + } + + /* Value between ":" and End-Of-Line */ + bufValue->buffer = &bufProperty->buffer[colonOffset + bufColon.length]; + bufValue->length = bufProperty->length - (colonOffset + bufColon.length + bufEOL.length); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefVCardParseProperty(const ndefConstBuffer* bufProperty, ndefConstBuffer* bufType, ndefConstBuffer* bufSubtype, ndefConstBuffer* bufValue) +{ + ndefStatus err; + + if ( (bufProperty == NULL) || + (bufType == NULL) || (bufSubtype == NULL) || (bufValue == NULL) ) + { + return ERR_PARAM; + } + + err = ndefVCardGetPropertyType(bufProperty, bufType); + if (err != ERR_NONE) + { + return err; + } + + err = ndefVCardGetPropertySubtype(bufProperty, bufSubtype); + if (err != ERR_NONE) + { + /* Not all properties have a subtype */ + bufSubtype->buffer = NULL; + bufSubtype->length = 0; + } + + err = ndefVCardGetPropertyValue(bufProperty, bufValue); + if (err != ERR_NONE) + { + return err; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefVCardSetProperty(ndefTypeVCard* vCard, const ndefConstBuffer* bufProperty) +{ + ndefStatus err; + + if ( (vCard == NULL) || (bufProperty == NULL) ) + { + return ERR_PARAM; + } + + /* Check the property contains a type */ + ndefConstBuffer bufPropertyType; + err = ndefVCardGetPropertyType(bufProperty, &bufPropertyType); + if (err != ERR_NONE) + { + return err; + } + + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(vCard->propertyBuffer); i++) + { + /* Find first free property */ + if (vCard->propertyBuffer[i] == NULL) + { + /* Append it */ + vCard->propertyBuffer[i] = bufProperty->buffer; + vCard->propertyLength[i] = (uint16_t)bufProperty->length; + return ERR_NONE; + } + else + { + /* Or update existing one */ + ndefConstBuffer vCardProperty; + vCardProperty.buffer = vCard->propertyBuffer[i]; + vCardProperty.length = (uint16_t)vCard->propertyLength[i]; + + ndefConstBuffer vCardPropertyType; + err = ndefVCardGetPropertyType(&vCardProperty, &vCardPropertyType); + if (err != ERR_NONE) + { + return err; + } + + if (ndefBufferMatch(&vCardPropertyType, &bufPropertyType) == true) + { + vCard->propertyBuffer[i] = bufProperty->buffer; + vCard->propertyLength[i] = (uint16_t)bufProperty->length; + return ERR_NONE; + } + } + } + + return ERR_NOMEM; +} + + +/*****************************************************************************/ +ndefStatus ndefVCardGetProperty(const ndefTypeVCard* vCard, const ndefConstBuffer* bufType, ndefConstBuffer* bufProperty) +{ + ndefStatus err; + + if ( (vCard == NULL) || + (bufType == NULL) || (bufType->buffer == NULL) ) + { + return ERR_PARAM; + } + + for (uint32_t i = 0; i < SIZEOF_ARRAY(vCard->propertyBuffer); i++) + { + ndefConstBuffer bufLine; + bufLine.buffer = vCard->propertyBuffer[i]; + bufLine.length = vCard->propertyLength[i]; + + ndefConstBuffer bufLineType; + err = ndefVCardGetPropertyType(&bufLine, &bufLineType); + if (err != ERR_NONE) + { + return ERR_NOTFOUND; + } + + if (ndefBufferMatch(&bufLineType, bufType) == true) + { + if (bufProperty != NULL) + { + bufProperty->buffer = bufLine.buffer; + bufProperty->length = bufLine.length; + } + return ERR_NONE; + } + } + + return ERR_NOTFOUND; +} + + +/*****************************************************************************/ +static uint32_t ndefVCardPayloadGetLength(const ndefType* type) +{ + const ndefTypeVCard* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_MEDIA_VCARD) ) + { + return 0; + } + + ndefData = &type->data.vCard; + + uint32_t payloadLength = 0; + for (uint32_t i = 0; i < SIZEOF_ARRAY(ndefData->propertyBuffer); i++) + { + payloadLength += ndefData->propertyLength[i]; + } + + return payloadLength; +} + + +/*****************************************************************************/ +ndefStatus ndefVCardReset(ndefTypeVCard* vCard) +{ + if (vCard == NULL) + { + return ERR_PARAM; + } + + /* Initialize every property */ + for (uint32_t i = 0; i < (uint32_t)SIZEOF_ARRAY(vCard->propertyBuffer); i++) + { + vCard->propertyBuffer[i] = NULL; + vCard->propertyLength[i] = 0; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static const uint8_t* ndefVCardToPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeVCard* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_MEDIA_VCARD) || + (bufItem == NULL) ) + { + return NULL; + } + + ndefData = &type->data.vCard; + + bufItem->buffer = NULL; + bufItem->length = 0; + + /* Initialization */ + if (begin == true) + { + item = 0; + } + + while (item < (uint32_t)SIZEOF_ARRAY(ndefData->propertyBuffer)) + { + bufItem->buffer = ndefData->propertyBuffer[item]; + bufItem->length = ndefData->propertyLength[item]; + + item++; + return bufItem->buffer; + } + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefVCardInit(ndefType* type, const ndefTypeVCard* vCard) +{ + ndefTypeVCard* ndefData; + + if ( (type == NULL) || (vCard == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_MEDIA_VCARD; + type->getPayloadLength = ndefVCardPayloadGetLength; + type->getPayloadItem = ndefVCardToPayloadItem; + type->typeToRecord = ndefVCardToRecord; + ndefData = &type->data.vCard; + + /* Copy in a bulk */ + (void)ST_MEMCPY(ndefData, vCard, sizeof(ndefTypeVCard)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetVCard(const ndefType* type, ndefTypeVCard* vCard) +{ + const ndefTypeVCard* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_MEDIA_VCARD) || + (vCard == NULL) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.vCard; + + /* Copy in a bulk */ + (void)ST_MEMCPY(vCard, ndefData, sizeof(ndefTypeVCard)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefVCardGetLine(const ndefConstBuffer* bufPayload, ndefConstBuffer* bufLine) +{ + ndefStatus err; + uint32_t offset; + + if ( (bufPayload == NULL) || (bufLine == NULL) ) + { + return ERR_PARAM; + } + + /* Look for "\r\n" */ + err = ndefBufferFind(bufPayload, &bufNewLine, &offset); /* "\r\n" */ + if (err == ERR_NONE) + { + /* Return up to the marker */ + bufLine->buffer = bufPayload->buffer; + bufLine->length = offset + bufNewLine.length; + } + else + { + /* Look for "\n" */ + err = ndefBufferFind(bufPayload, &bufLineFeed, &offset); /* "\n" */ + if (err == ERR_NONE) + { + /* Return up to the marker */ + bufLine->buffer = bufPayload->buffer; + bufLine->length = offset + bufLineFeed.length; + } + else + { + /* Return up to the end of the payload */ + bufLine->buffer = bufPayload->buffer; + bufLine->length = bufPayload->length; + } + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToVcard(const ndefConstBuffer* bufPayload, ndefType* type) +{ + /*! vCard keyword types */ + static const uint8_t TYPE_BEGIN[] = "BEGIN"; + static const uint8_t TYPE_END[] = "END"; + static const uint8_t TYPE_VERSION[] = "VERSION"; + /*static const uint8_t VALUE_VCARD[] = "VCARD";*/ + /*static const uint8_t VALUE_2_1[] = "2.1";*/ + + static const ndefConstBuffer bufTypeBegin = { TYPE_BEGIN, sizeof(TYPE_BEGIN) - 1U }; /*!< "BEGIN" */ + static const ndefConstBuffer bufTypeEnd = { TYPE_END, sizeof(TYPE_END) - 1U }; /*!< "END" */ + static const ndefConstBuffer bufTypeVersion = { TYPE_VERSION, sizeof(TYPE_VERSION) - 1U }; /*!< "VERSION" */ + /*static const ndefConstBuffer bufValueVCard = { VALUE_VCARD, sizeof(VALUE_VCARD) - 1U }; *//*!< "VCARD" */ + /*static const ndefConstBuffer bufValue_2_1 = { VALUE_2_1, sizeof(VALUE_2_1) - 1U }; *//*!< "2.1" */ + + ndefStatus err; + ndefTypeVCard* ndefData; + + ndefConstBuffer bufRemaining; + ndefConstBuffer bufLine; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + if (bufPayload->length < NDEF_VCARD_PAYLOAD_LENGTH_MIN) /* vCard Payload Min */ + { + return ERR_PROTO; + } + + type->id = NDEF_TYPE_ID_MEDIA_VCARD; + type->getPayloadLength = ndefVCardPayloadGetLength; + type->getPayloadItem = ndefVCardToPayloadItem; + type->typeToRecord = ndefVCardToRecord; + ndefData = &type->data.vCard; + + /* Reset the vCard before parsing the payload */ + if (ndefVCardReset(ndefData) != ERR_NONE) + { + return ERR_PARAM; + } + + uint32_t offset = 0; + while (offset < bufPayload->length) + { + /* Parse the remaining to find an "end of line" or reach the end of payload */ + bufRemaining.buffer = &bufPayload->buffer[offset]; + bufRemaining.length = bufPayload->length - offset; + + err = ndefVCardGetLine(&bufRemaining, &bufLine); + if (err != ERR_NONE) + { + return err; + } + + err = ndefVCardSetProperty(ndefData, &bufLine); + if (err != ERR_NONE) + { + return err; + } + + /* Move to the next line */ + offset += bufLine.length; + } + + /* Check BEGIN, VERSION and END types were found */ + ndefStatus err_begin = ndefVCardGetProperty(ndefData, &bufTypeBegin, NULL); + ndefStatus err_version = ndefVCardGetProperty(ndefData, &bufTypeVersion, NULL); + ndefStatus err_end = ndefVCardGetProperty(ndefData, &bufTypeEnd, NULL); + if ( (err_begin != ERR_NONE) || (err_version != ERR_NONE) || (err_end != ERR_NONE) ) + { + return ERR_SYNTAX; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToVCard(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeVCard)) /* "text/x-vCard" */ + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (type->id == NDEF_TYPE_ID_MEDIA_VCARD) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToVcard(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefVCardToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_MEDIA_VCARD) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeVCard); + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_wifi.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wifi.c new file mode 100644 index 0000000..eb9a896 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wifi.c @@ -0,0 +1,513 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF Wifi type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_wifi.h" +#include "utils.h" + + +#if NDEF_TYPE_WIFI_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! Wifi Type strings */ +static const uint8_t ndefMediaTypeWifi[] = "application/vnd.wfa.wsc"; /*!< Wi-Fi Simple Configuration Type */ + +const ndefConstBuffer8 bufMediaTypeWifi = { ndefMediaTypeWifi, sizeof(ndefMediaTypeWifi) - 1U }; /*!< Wifi Type buffer */ + + +/*! Wifi OBB (WPS) */ + +#define NDEF_WIFI_DEFAULT_NETWORK_KEY "00000000" /*! Network key to be used when the Authentication is set to None. + Althought WPS defines a 0-length network key in such case, + a 8 digit value is required with tested phones. */ + +#define NDEF_WIFI_NETWORK_SSID_LENGTH 32U /*!< Network SSID length */ +#define NDEF_WIFI_NETWORK_KEY_LENGTH 32U /*!< Network Key length */ + +#define NDEF_WIFI_ENCRYPTION_TYPE_LENGTH 2U /*!< Encryption type length */ +#define NDEF_WIFI_AUTHENTICATION_TYPE_LENGTH 2U /*!< Authentication type length */ +#define WIFI_SSID_TYPE_LENGTH 2U /*!< SSID type length */ +#define WIFI_SSID_KEY_TYPE_LENGTH 2U /*!< SSID key type length */ + +#define NDEF_WIFI_ATTRIBUTE_ID_SSID_LSB 0x10U /*!< SSID Attribute ID LSB */ +#define NDEF_WIFI_ATTRIBUTE_ID_SSID_MSB 0x45U /*!< SSID Attribute ID MSB */ + +#define NDEF_WIFI_ATTRIBUTE_ID_NETWORK_LSB 0x10U /*!< Network Attribute ID LSB */ +#define NDEF_WIFI_ATTRIBUTE_ID_NETWORK_MSB 0x27U /*!< Network Attribute ID MSB */ + +#define NDEF_WIFI_ATTRIBUTE_ENCRYPTION 0x0FU /*!< Encryption attribute */ +#define NDEF_WIFI_ATTRIBUTE_AUTHENTICATION 0x03U /*!< Authentication attribute */ + +#define NDEF_WIFI_ATTRIBUTE_ID_OFFSET 0x01U /*!< Attribute Id offset */ +#define NDEF_WIFI_ATTRIBUTE_LENGTH_MSB_OFFSET 0x02U /*!< Attribute length MSB offset */ +#define NDEF_WIFI_ATTRIBUTE_LENGTH_LSB_OFFSET 0x03U /*!< Attribute length LSB offset */ +#define NDEF_WIFI_ATTRIBUTE_DATA_OFFSET 0x04U /*!< Attribute data offset */ +#define NDEF_WIFI_ATTRIBUTE_ENCRYPTION_LSB_OFFSET 0x05U /*!< Attribute encryption offset */ +#define NDEF_WIFI_ATTRIBUTE_AUTHENTICATION_LSB_OFFSET 0x05U /*!< Attribute authentication offset */ + + +static uint8_t wifiConfigToken1[] = { + 0x10, 0x4A, /* Attribute ID: Version */ + 0x00, 0x01, /* Attribute ID Length */ + 0x10, /* Version 1.0 */ + 0x10, 0x0E, /* Attribute ID Credential */ + 0x00, 0x48, /* Attribute ID Length */ + 0x10, 0x26, /* Attribute ID: Network Index */ + 0x00, 0x01, /* Attribute Length */ + 0x01, /* Index */ + 0x10, 0x45 /* Attribute ID: SSID */ +}; + +static uint8_t wifiConfigToken3[] = { + 0x10, 0x03, /* Attribute ID:Authentication Type */ + 0x00, 0x02, /* Attribute Length */ + 0x00, 0x01, /* Attribute Type: Open */ + 0x10, 0x0F, /* Attribute ID: Encryption Type */ + 0x00, 0x02, /* Attribute Length */ + 0x00, 0x01, /* Encryption Type: None */ + 0x10, 0x27 /* Attribute ID: Network Key */ +}; + +static uint8_t wifiConfigToken5[] = { + 0x10, 0x20, /* Attribute ID: MAC Address */ + 0x00, 0x06, /* Attribute Length */ + 0, /* MAC-ADDRESS */ + 0, /* MAC-ADDRESS */ + 0, /* MAC-ADDRESS */ + 0, /* MAC-ADDRESS */ + 0, /* MAC-ADDRESS */ + 0, /* MAC-ADDRESS */ + 0x10, 0x49, /* Attribute ID: Vendor Extension */ + 0x00, 0x06, /* Attribute Length */ + 0x00, 0x37, 0x2A, /* Vendor ID: WFA */ + 0x02, /* Subelement ID:Network Key Shareable */ + 0x01, /* Subelement Length */ + 0x01, /* Network Key Shareable: TRUE */ + 0x10, 0x49, /* Attribute ID: Vendor Extension */ + 0x00, 0x06, /* Attribute Length */ + 0x00, 0x37, 0x2A, /* Vendor ID: WFA */ + 0x00, /* Subelement ID: Version2 */ + 0x01, /* Subelement Length: 1 */ + 0x20 /* Version 2 */ +}; + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*****************************************************************************/ +/*! Manage a Wifi Out-Of-Band NDEF message, to start a communication based on Wifi. + * The Wifi OOB format is described by the Wifi Protected Setup specification. + * It consists in a list of data elements formated as type-length-value. + + The Wifi OOB in a NDEF record has the following structure: + - Version + - Credential + - Network index + - SSID + - Authentication Type + - Encryption Type + - Network Key + - MAC Address + - Vendor Extension + - Network Key Shareable + - Vendor Extension + - Version2 + + Note: If the `Network key` is set to an empty buffer, the library sets it to "0x00000000" + Even if 0-length Network Key is supposed to be supported, smartphones dont necessarily accept it. + */ + + +/*****************************************************************************/ +static uint32_t ndefWifiPayloadGetLength(const ndefType* wifi) +{ + const ndefTypeWifi* wifiData; + uint32_t payloadLength; + + if ( (wifi == NULL) || (wifi->id != NDEF_TYPE_ID_MEDIA_WIFI) ) + { + return 0; + } + + wifiData = &wifi->data.wifi; + + payloadLength = sizeof(wifiConfigToken1) + + WIFI_SSID_TYPE_LENGTH + wifiData->bufNetworkSSID.length + + sizeof(wifiConfigToken3) + + WIFI_SSID_KEY_TYPE_LENGTH + wifiData->bufNetworkKey.length + + sizeof(wifiConfigToken5); + + return payloadLength; +} + + +/*****************************************************************************/ +static const uint8_t* ndefWifiToPayloadItem(const ndefType* wifi, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeWifi* wifiData; + uint16_t credentialLength; + + static const uint8_t defaultKey[4] = {0, 0, 0, 0}; + ndefConstBuffer8 bufDefaultNetworkKey = { defaultKey, sizeof(defaultKey) }; + + const uint8_t CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX = 7U; + const uint8_t CONFIG_TOKEN_3_AUTHENTICATION_TYPE_INDEX = 5U; + const uint8_t CONFIG_TOKEN_3_ENCRYPTION_TYPE_INDEX = 11U; + + static uint8_t zero[] = { 0 }; + static ndefConstBuffer8 bufZero = { zero, sizeof(zero) }; + + if ( (wifi == NULL) || (wifi->id != NDEF_TYPE_ID_MEDIA_WIFI) || + (bufItem == NULL) ) + { + return NULL; + } + + wifiData = &wifi->data.wifi; + + if (begin == true) + { + item = 0; + } + + bufItem->buffer = NULL; + bufItem->length = 0; + + switch (item) + { + case 0: + /* Config Token1 */ + + /* Update Token1 with credential length */ + credentialLength = (uint16_t)(5U + /* Network index */ + 2U + /* SSID type */ + 2U + /* SSID key length */ + wifiData->bufNetworkSSID.length + /* SSID key */ + sizeof(wifiConfigToken3) + /* Token3 length */ + 2U + /* Network key length */ + wifiData->bufNetworkKey.length + /* Network key */ + sizeof(wifiConfigToken5)); /* Token5 length */ + + wifiConfigToken1[CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX] = (uint8_t)(credentialLength >> 8U); + wifiConfigToken1[CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX + 1U] = (uint8_t)(credentialLength & 0xFFU); + + bufItem->buffer = wifiConfigToken1; + bufItem->length = sizeof(wifiConfigToken1); + break; + + case 1: + /* SSID Length (1st byte) */ + bufItem->buffer = bufZero.buffer; + bufItem->length = bufZero.length; + break; + + case 2: + /* SSID Length (2nd byte) */ + bufItem->buffer = (const uint8_t*)&wifiData->bufNetworkSSID.length; + bufItem->length = 1U; + break; + + case 3: + /* SSID Value */ + bufItem->buffer = wifiData->bufNetworkSSID.buffer; + bufItem->length = wifiData->bufNetworkSSID.length; + break; + + case 4: + /* Config Token3 */ + + /* Update Token3 with Autentication and Encryption Types */ + wifiConfigToken3[CONFIG_TOKEN_3_AUTHENTICATION_TYPE_INDEX] = wifiData->authentication; + wifiConfigToken3[CONFIG_TOKEN_3_ENCRYPTION_TYPE_INDEX] = wifiData->encryption; + + bufItem->buffer = wifiConfigToken3; + bufItem->length = sizeof(wifiConfigToken3); + break; + + case 5: + /* SSID Key Length (1st byte) */ + bufItem->buffer = bufZero.buffer; + bufItem->length = bufZero.length; + break; + + case 6: + /* SSID Key Length (2 bytes) */ + bufItem->buffer = (const uint8_t*)&wifiData->bufNetworkKey.length; + bufItem->length = 1U; + break; + + case 7: + /* SSID Key Value */ + if(wifiData->bufNetworkKey.length == 0U) + { + /* Empty network key is not supported by Phones */ + bufItem->buffer = bufDefaultNetworkKey.buffer; + bufItem->length = bufDefaultNetworkKey.length; + } + else + { + bufItem->buffer = wifiData->bufNetworkKey.buffer; + bufItem->length = wifiData->bufNetworkKey.length; + } + break; + + case 8: + /* Config Token5 */ + bufItem->buffer = wifiConfigToken5; + bufItem->length = sizeof(wifiConfigToken5); + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefWifiInit(ndefType* wifi, const ndefTypeWifi* wifiConfig) +{ + ndefTypeWifi* wifiData; + + if ( (wifi == NULL) || (wifiConfig == NULL) ) + { + return ERR_PARAM; + } + + wifi->id = NDEF_TYPE_ID_MEDIA_WIFI; + wifi->getPayloadLength = ndefWifiPayloadGetLength; + wifi->getPayloadItem = ndefWifiToPayloadItem; + wifi->typeToRecord = ndefWifiToRecord; + wifiData = &wifi->data.wifi; + + wifiData->bufNetworkSSID = wifiConfig->bufNetworkSSID; + wifiData->bufNetworkKey = wifiConfig->bufNetworkKey; + wifiData->authentication = wifiConfig->authentication; + wifiData->encryption = wifiConfig->encryption; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetWifi(const ndefType* wifi, ndefTypeWifi* wifiConfig) +{ + const ndefTypeWifi* wifiData; + + if ( (wifi == NULL) || (wifi->id != NDEF_TYPE_ID_MEDIA_WIFI) || + (wifiConfig == NULL) ) + { + return ERR_PARAM; + } + + wifiData = &wifi->data.wifi; + + wifiConfig->bufNetworkSSID.buffer = wifiData->bufNetworkSSID.buffer; + wifiConfig->bufNetworkSSID.length = wifiData->bufNetworkSSID.length; + wifiConfig->bufNetworkKey.buffer = wifiData->bufNetworkKey.buffer; + wifiConfig->bufNetworkKey.length = wifiData->bufNetworkKey.length; + wifiConfig->authentication = wifiData->authentication; + wifiConfig->encryption = wifiData->encryption; + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToWifi(const ndefConstBuffer* bufPayload, ndefType* wifi) +{ + ndefTypeWifi wifiConfig; + uint32_t offset; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (wifi == NULL) ) + { + return ERR_PARAM; + } + + wifiConfig.bufNetworkSSID.buffer = NULL; + wifiConfig.bufNetworkSSID.length = 0; + wifiConfig.bufNetworkKey.buffer = NULL; + wifiConfig.bufNetworkKey.length = 0; + wifiConfig.authentication = 0; + wifiConfig.encryption = 0; + + offset = 0; + while (offset < bufPayload->length) + { + uint8_t attribute = bufPayload->buffer[offset]; + if (attribute == NDEF_WIFI_ATTRIBUTE_ID_SSID_LSB) + { + uint8_t data1 = bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_LENGTH_MSB_OFFSET]; + uint8_t data2 = bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_LENGTH_LSB_OFFSET]; + uint32_t length = ((uint32_t)data1 << 8U) | data2; + + switch (bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_ID_OFFSET]) + { + case NDEF_WIFI_ATTRIBUTE_ID_SSID_MSB: + /* Network SSID */ + if (length > NDEF_WIFI_NETWORK_SSID_LENGTH) + { + return ERR_PROTO; + } + wifiConfig.bufNetworkSSID.buffer = &bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_DATA_OFFSET]; + wifiConfig.bufNetworkSSID.length = length; + offset += (NDEF_WIFI_ATTRIBUTE_DATA_OFFSET + length); + break; + case NDEF_WIFI_ATTRIBUTE_ID_NETWORK_MSB: + /* Network key */ + if (length > NDEF_WIFI_NETWORK_KEY_LENGTH) + { + return ERR_PROTO; + } + wifiConfig.bufNetworkKey.buffer = &bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_DATA_OFFSET]; + wifiConfig.bufNetworkKey.length = length; + offset += (NDEF_WIFI_ATTRIBUTE_DATA_OFFSET + length); + break; + case NDEF_WIFI_ATTRIBUTE_AUTHENTICATION: + /* Authentication */ + if (length != NDEF_WIFI_AUTHENTICATION_TYPE_LENGTH) + { + return ERR_PROTO; + } + wifiConfig.authentication = bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_AUTHENTICATION_LSB_OFFSET]; + offset += (NDEF_WIFI_ATTRIBUTE_DATA_OFFSET + length); + break; + case NDEF_WIFI_ATTRIBUTE_ENCRYPTION: + /* Encryption */ + if (length != NDEF_WIFI_ENCRYPTION_TYPE_LENGTH) + { + return ERR_PROTO; + } + wifiConfig.encryption = bufPayload->buffer[offset + NDEF_WIFI_ATTRIBUTE_ENCRYPTION_LSB_OFFSET]; + offset += (NDEF_WIFI_ATTRIBUTE_DATA_OFFSET + length); + break; + default: + offset++; + break; + } + } + else + { + offset++; + } + } + + return ndefWifiInit(wifi, &wifiConfig); +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToWifi(const ndefRecord* record, ndefType* wifi) +{ + const ndefType* type; + + if ( (record == NULL) || (wifi == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeWifi)) /* "application/vnd.wfa.wsc" */ + { + return ERR_PROTO; + } + + type = ndefRecordGetNdefType(record); + if ( (type != NULL) && (type->id == NDEF_TYPE_ID_MEDIA_WIFI) ) + { + (void)ST_MEMCPY(wifi, type, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToWifi(&record->bufPayload, wifi); +} + + +/*****************************************************************************/ +ndefStatus ndefWifiToRecord(const ndefType* wifi, ndefRecord* record) +{ + if ( (wifi == NULL) || (wifi->id != NDEF_TYPE_ID_MEDIA_WIFI) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + (void)ndefRecordSetType(record, NDEF_TNF_MEDIA_TYPE, &bufMediaTypeWifi); + + if (ndefRecordSetNdefType(record, wifi) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_wlc.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wlc.c new file mode 100644 index 0000000..b506c02 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wlc.c @@ -0,0 +1,1205 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF WLC (Wireless Charging) types + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_wlc.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_WLC_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH 6U /*!< WLC Capability/Poll Info/Listen Control Records Payload Length */ + +#define NDEF_TYPE_RTD_WLC_STATUS_INFO_MIN_PAYLOAD_LENGTH 1U /*!< WLC Status Info Record Payload min length */ +#define NDEF_TYPE_RTD_WLC_STATUS_INFO_MAX_PAYLOAD_LENGTH 9U /*!< WLC Status Info Record Payload max length */ + + +/* WLC Capability */ +#define NDEF_WLC_CAPABILITY_PROTOCOL_VERSION_OFFSET 0U /*!< WLC Capability Protocol Version Offset */ +#define NDEF_WLC_CAPABILITY_CONFIG_OFFSET 1U /*!< WLC Capability Config Offset */ +#define NDEF_WLC_CAPABILITY_WT_INT_OFFSET 2U /*!< WLC Capability WT INT Offset */ +#define NDEF_WLC_CAPABILITY_NDEF_RD_WT_OFFSET 3U /*!< WLC Capability NDEF RD WT Offset */ +#define NDEF_WLC_CAPABILITY_NDEF_WR_TO_INT_OFFSET 4U /*!< WLC Capability NDEF WR TO INT Offset */ +#define NDEF_WLC_CAPABILITY_NDEF_WR_WT_INT_OFFSET 5U /*!< WLC Capability NDEF WR WT INT Offset */ + +/* WLC Config: Protocol Version */ +//#define NDEF_WLC_CAPABILITY_PROTOCOL_MAJOR_VERSION_SHIFT 4U /*!< WLC Capability Protocol Major Version bit shift */ +//#define NDEF_WLC_CAPABILITY_PROTOCOL_VERSION_MASK 0xFU /*!< WLC Capability Protocol Major Version mask */ + +/* WLC Config: Mode Req */ +#define NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_SHIFT 6U /*! WLC Capability Config Req Mode bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_MASK 3U /*! WLC Capability Config Req Mode mask */ + +/* WLC Config: Nego Wait Retry */ +#define NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_SHIFT 2U /*! WLC Capability config Nego Wait Retry bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_MASK 0xFU /*! WLC Capability config Nego Wait Retry mask */ + +/* WLC Config: Nego Wait Retry flag */ +#define NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_SHIFT 1U /*! WLC Capability config Nego Wait bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_MASK 1U /*! WLC Capability config Nego Wait mask */ + +/* WLC Config: Rd Conf flag */ +#define NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_SHIFT 0U /*! WLC Capability config Rd Conf bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_MASK 1U /*! WLC Capability config Rd Conf mask */ + +/* WLC Config: CapWtInt RFU */ +#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_SHIFT 5U /*! WLC Capability config CapWtInt RFU bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_MASK 0x7U /*! WLC Capability config CapWtInt RFU mask */ + +/* WLC Config: CapWtInt */ +#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_SHIFT 0U /*! WLC Capability config CapWtInt bit shift */ +#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_MASK 0x1FU /*! WLC Capability config CapWtInt mask */ + +//#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_MAX 0x13U /*! WLC Capability config CapWtInt max value */ +//#define NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_MASK 0x1FU /*! WLC Capability config CapWtInt mask */ + +//#define NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_MASK 1U /*! WLC Capability config Rd Conf mask */ + +/* WLC Status and Information */ +#define NDEF_WLC_STATUSINFO_CONTROL_BYTE_1_OFFSET 0U /*! WLC Status and Info Control byte 1 offset */ + +/* WLC Poll Info */ +#define NDEF_WLC_POLL_INFO_PTX_OFFSET 0U /*!< WLC Poll Info P Tx Offset */ +#define NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_OFFSET 1U /*!< WLC Poll Info WLC-P Capability Offset */ +#define NDEF_WLC_POLL_INFO_POWER_CLASS_OFFSET 1U /*!< WLC Poll Info Power Class Offset */ +#define NDEF_WLC_POLL_INFO_TOT_POWER_STEPS_OFFSET 2U /*!< WLC Poll Info Total Power Steps Offset */ +#define NDEF_WLC_POLL_INFO_CUR_POWER_STEP_OFFSET 3U /*!< WLC Poll Info Current Power Step Offset */ +#define NDEF_WLC_POLL_INFO_NEXT_MIN_STEP_INC_OFFSET 4U /*!< WLC Poll Info Next Min Step Inc Offset */ +#define NDEF_WLC_POLL_INFO_NEXT_MIN_STEP_DEC_OFFSET 5U /*!< WLC Poll Info Next Min Step Dec Offset */ + +#define NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_SHIFT 4U /*!< WLC Poll Info WLC-P Capability bit shift */ +#define NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_MASK 0xFU /*!< WLC Poll Info WLC-P Capability mask */ + +/* WLC Listen Ctl */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_OFFSET 0U /*!< WLC Listen Control Status Info Offset */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_OFFSET 1U /*!< WLC Listen Control WPT Config Offset */ +#define NDEF_WLC_LISTEN_CTL_POWER_ADJ_REQ_OFFSET 2U /*!< WLC Listen Control Power Adjust Request Offset */ +#define NDEF_WLC_LISTEN_CTL_BATTERY_LEVEL_OFFSET 3U /*!< WLC Listen Control Battery Level Offset */ +#define NDEF_WLC_LISTEN_CTL_DRV_INFO_OFFSET 4U /*!< WLC Listen Control Drv Info Offset */ +#define NDEF_WLC_LISTEN_CTL_HOLD_OFF_WT_INT_OFFSET 5U /*!< WLC Listen Control Hold Off WT INT Offset */ +#define NDEF_WLC_LISTEN_CTL_ERROR_INFO_OFFSET 5U /*!< WLC Listen Control Error Info Offset */ + +/* WLC Listen Ctl: Status Info */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_SHIFT 7U /*! WLC Listen Control Status Error Flag bit shift */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_MASK 1U /*! WLC Listen Control Status Error Flag mask */ + +/* WLC Listen Ctl: Battery Status */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_SHIFT 3U /*! WLC Listen Control Battery Status bit shift */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_MASK 3U /*! WLC Listen Control Battery Status mask */ + +/* WLC Listen Ctl: Status Counter */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_SHIFT 0U /*! WLC Listen Control Status Counter bit shift */ +#define NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_MASK 0x7U /*! WLC Listen Control Status Counter Status mask */ + +/* WLC Listen Ctl: WPT Config Req */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_SHIFT 6U /*! WLC Listen Control WPT Config Req bit shift */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_MASK 3U /*! WLC Listen Control WPT Config Req mask */ + +/* WLC Listen Ctl: WPT Config Duration */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_SHIFT 1U /*! WLC Listen Control WPT Config Duration bit shift */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_MASK 0x1FU /*! WLC Listen Control WPT Config Duration mask */ + +/* WLC Listen Ctl: WPT Config Info Request */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_SHIFT 0U /*! WLC Listen Control WPT Config Info Request bit shift */ +#define NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_MASK 1U /*! WLC Listen Control WPT Config Info Request mask */ + +/* WLC Listen Ctl: DRV Info Flag */ +#define NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_SHIFT 6U /*! WLC Listen Control Drv Info Flag bit shift */ +#define NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_MASK 3U /*! WLC Listen Control Drv Info Flag mask */ + +/* WLC Listen Ctl: DRV Info Int */ +#define NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_SHIFT 0U /*! WLC Listen Control Drv Info Int bit shift */ +#define NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_MASK 0x3FU /*! WLC Listen Control Drv Info Int mask */ + +/* WLC Listen Ctl: Error Info/WLC Protocol Error */ +#define NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_SHIFT 1U /*! WLC Listen Control Error Info Protocol bit shift */ +#define NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_MASK 1U /*! WLC Listen Control Error Info Protocol mask */ + +/* WLC Listen Ctl: Error Info/Temperature */ +#define NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_SHIFT 0U /*! WLC Listen Control Error Info Temperature bit shift */ +#define NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_MASK 1U /*! WLC Listen Control Error Info Temperature mask */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD WLC Type strings */ +static const uint8_t ndefRtdTypeWlcCapability[] = "WLCCAP"; /*!< WLC Capability Record Type */ +static const uint8_t ndefRtdTypeWlcStatusInfo[] = "WLCSTAI"; /*!< WLC Status and Information Record Type */ +static const uint8_t ndefRtdTypeWlcPollInfo[] = "WLCINF"; /*!< WLC Poll Info Record Type */ +static const uint8_t ndefRtdTypeWlcListenCtl[] = "WLCCTL"; /*!< WLC Listen Control Record Type */ + +const ndefConstBuffer8 bufTypeRtdWlcCapability = { ndefRtdTypeWlcCapability, sizeof(ndefRtdTypeWlcCapability) - 1U }; /*!< WLC Capabiilty Type Record buffer */ +const ndefConstBuffer8 bufTypeRtdWlcStatusInfo = { ndefRtdTypeWlcStatusInfo, sizeof(ndefRtdTypeWlcStatusInfo) - 1U }; /*!< WLC Capabiilty Type Record buffer */ +const ndefConstBuffer8 bufTypeRtdWlcPollInfo = { ndefRtdTypeWlcPollInfo, sizeof(ndefRtdTypeWlcPollInfo) - 1U }; /*!< WLC Poll Information Type Record buffer */ +const ndefConstBuffer8 bufTypeRtdWlcListenCtl = { ndefRtdTypeWlcListenCtl, sizeof(ndefRtdTypeWlcListenCtl) - 1U }; /*!< WLC Listen Control Type Record buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*****************************************************************************/ +/* + * WLC Capability + */ +/*****************************************************************************/ + + +/*****************************************************************************/ +static uint32_t ndefRtdWlcCapabilityGetPayloadLength(const ndefType* type) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCCAP) ) + { + return 0; + } + + return NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdWlcCapabilityGetPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + static uint8_t temp = 0; + const ndefTypeRtdWlcCapability* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCCAP) || + (bufItem == NULL) ) + { + return NULL; + } + + ndefData = &type->data.wlcCapability; + + if (begin == true) + { + item = 0; + } + + /* Prepare bufItem->length: Each field is 1 byte, except when complete */ + bufItem->length = sizeof(uint8_t); + + switch (item) + { + case 0: /* WLC Protocol Version */ + bufItem->buffer = &ndefData->wlcProtocolVersion; + break; + case 1: /* WLC Config */ + { + temp = + ((ndefData->wlcConfigModeReq & NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_MASK) << NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_SHIFT) + | ((ndefData->wlcConfigWaitTimeRetry & NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_MASK) << NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_SHIFT) + | ((ndefData->wlcConfigNegoWait & NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_MASK) << NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_SHIFT) + | ((ndefData->wlcConfigRdConf & NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_MASK) << NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_SHIFT); + + bufItem->buffer = &temp; + break; + } + case 2: /* Cap Wt Int */ + temp = + ((ndefData->capWtIntRfu & NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_MASK) << NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_SHIFT) + | ((ndefData->capWtInt & NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_MASK) << NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_SHIFT); + + bufItem->buffer = &temp; + break; + case 3: /* NDEF Rd Wt */ + bufItem->buffer = &ndefData->ndefRdWt; + break; + case 4: /* NDEF Write To Int */ + bufItem->buffer = &ndefData->ndefWriteToInt; + break; + case 5: /* NDEF Write Wt Int */ + bufItem->buffer = &ndefData->ndefWriteWtInt; + break; + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcCapabilityInit(ndefType* type, const ndefTypeRtdWlcCapability* param) +{ + ndefTypeRtdWlcCapability* ndefData; + + if ( (type == NULL) || (param == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_WLCCAP; + type->getPayloadLength = ndefRtdWlcCapabilityGetPayloadLength; + type->getPayloadItem = ndefRtdWlcCapabilityGetPayloadItem; + type->typeToRecord = ndefRtdWlcCapabilityToRecord; + ndefData = &type->data.wlcCapability; + + (void)ST_MEMCPY(ndefData, param, sizeof(ndefTypeRtdWlcCapability)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdWlcCapability(const ndefType* type, ndefTypeRtdWlcCapability* param) +{ + const ndefTypeRtdWlcCapability* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCCAP) || + (param == NULL) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.wlcCapability; + + (void)ST_MEMCPY(param, ndefData, sizeof(ndefTypeRtdWlcCapability)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdWlcCapability(const ndefConstBuffer* bufPayload, ndefType* type) +{ + ndefTypeRtdWlcCapability* ndefData; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + /* WLC TS v2.0 11.1.1.1 Any additional bytes inside an NDEF Record defined in this specification SHALL be ignored by the receiver.*/ + if (bufPayload->length < NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH) + { + return ERR_PROTO; + } + + type->id = NDEF_TYPE_ID_RTD_WLCCAP; + type->getPayloadLength = ndefRtdWlcCapabilityGetPayloadLength; + type->getPayloadItem = ndefRtdWlcCapabilityGetPayloadItem; + type->typeToRecord = ndefRtdWlcCapabilityToRecord; + ndefData = &type->data.wlcCapability; + + ndefData->wlcProtocolVersion = bufPayload->buffer[NDEF_WLC_CAPABILITY_PROTOCOL_VERSION_OFFSET]; + + uint8_t config = bufPayload->buffer[NDEF_WLC_CAPABILITY_CONFIG_OFFSET]; + ndefData->wlcConfigModeReq = (config >> NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_MODE_REQ_MASK; + ndefData->wlcConfigWaitTimeRetry = (config >> NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_WAIT_TIME_RETRY_MASK; + ndefData->wlcConfigNegoWait = (config >> NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_NEGO_WAIT_MASK; + ndefData->wlcConfigRdConf = (config >> NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_RD_CONF_MASK; + + uint8_t capWtInt = bufPayload->buffer[NDEF_WLC_CAPABILITY_WT_INT_OFFSET]; + ndefData->capWtIntRfu = (capWtInt >> NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_RFU_MASK; + ndefData->capWtInt = (capWtInt >> NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_SHIFT) & NDEF_WLC_CAPABILITY_CONFIG_CAP_WT_INT_MASK; + ndefData->ndefRdWt = bufPayload->buffer[NDEF_WLC_CAPABILITY_NDEF_RD_WT_OFFSET]; + ndefData->ndefWriteToInt = bufPayload->buffer[NDEF_WLC_CAPABILITY_NDEF_WR_TO_INT_OFFSET]; + ndefData->ndefWriteWtInt = bufPayload->buffer[NDEF_WLC_CAPABILITY_NDEF_WR_WT_INT_OFFSET]; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdWlcCapability(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + /* NDEF TNF and String type */ + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcCapability)) + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_WLCCAP) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdWlcCapability(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcCapabilityToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCCAP) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* String type */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcCapability); + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +/* + * WLC Status and Information + */ +/*****************************************************************************/ + + +/*****************************************************************************/ +static uint32_t ndefRtdWlcStatusInfoGetPayloadLength(const ndefType* type) +{ + uint32_t length; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCSTAI) ) + { + return 0; + } + + const ndefTypeRtdWlcStatusInfo* ndefData = &type->data.wlcStatusInfo; + + length = sizeof(uint8_t); /* Control byte 1 */ + + /* Count the number of bits set in the Control byte 1 to get the number of following bytes */ + for (uint32_t i = 0; i < 8U; i++) + { + if ( (ndefData->controlByte1 & (1U << i) ) != 0U) + { + length += sizeof(uint8_t); + } + } + + return length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdWlcStatusInfoGetPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdWlcStatusInfo* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCSTAI) || + (bufItem == NULL) ) + { + return NULL; + } + + ndefData = &type->data.wlcStatusInfo; + + if (begin == true) + { + item = 0; + } + + /* Prepare bufItem->length: Each field is 1 byte, except when complete */ + bufItem->length = sizeof(uint8_t); + + switch (item) + { + case 0: /* Control Byte 1 */ + bufItem->buffer = &ndefData->controlByte1; + item++; + break; + case 1: /* Battery Level */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_BATTERY_LEVEL_MASK) != 0U) + { + bufItem->buffer = &ndefData->batteryLevel; + item = 2; + break; + } + /* fall through */ + case 2: /* Receive Power */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_POWER_MASK) != 0U) + { + bufItem->buffer = &ndefData->receivePower; + item = 3; + break; + } + /* fall through */ + case 3: /* Receive Voltage */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_VOLTAGE_MASK) != 0U) + { + bufItem->buffer = &ndefData->receiveVoltage; + item = 4; + break; + } + /* fall through */ + case 4: /* Receive Current */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_CURRENT_MASK) != 0U) + { + bufItem->buffer = &ndefData->receiveCurrent; + item = 5; + break; + } + /* fall through */ + case 5: /* Receive Current */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_BATTERY_MASK) != 0U) + { + bufItem->buffer = &ndefData->temperatureBattery; + item = 6; + break; + } + /* fall through */ + case 6: /* Receive Current */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_WLCL_MASK) != 0U) + { + bufItem->buffer = &ndefData->temperatureWlcl; + item = 7; + break; + } + /* fall through */ + case 7: /* Receive Current */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RFU_MASK) != 0U) + { + bufItem->buffer = &ndefData->rfu; + item = 8; + break; + } + /* fall through */ + case 8: /* Receive Current */ + if ( (ndefData->controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_CONTROL_BYTE_2_MASK) != 0U) + { + bufItem->buffer = &ndefData->controlByte2; + item = 9; + break; + } + /* fall through */ + default: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcStatusInfoInit(ndefType* type, const ndefTypeRtdWlcStatusInfo* param) +{ + ndefTypeRtdWlcStatusInfo* ndefData; + + if ( (type == NULL) || (param == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_WLCSTAI; + type->getPayloadLength = ndefRtdWlcStatusInfoGetPayloadLength; + type->getPayloadItem = ndefRtdWlcStatusInfoGetPayloadItem; + type->typeToRecord = ndefRtdWlcStatusInfoToRecord; + ndefData = &type->data.wlcStatusInfo; + + (void)ST_MEMCPY(ndefData, param, sizeof(ndefTypeRtdWlcStatusInfo)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdWlcStatusInfo(const ndefType* type, ndefTypeRtdWlcStatusInfo* param) +{ + const ndefTypeRtdWlcStatusInfo* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCSTAI) || + (param == NULL) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.wlcStatusInfo; + + (void)ST_MEMCPY(param, ndefData, sizeof(ndefTypeRtdWlcStatusInfo)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdWlcStatusInfo(const ndefConstBuffer* bufPayload, ndefType* type) +{ + ndefTypeRtdWlcStatusInfo* ndefData; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + /* WLC TS v2.0 11.1.1.1 Any additional bytes inside an NDEF Record defined in this specification SHALL be ignored by the receiver.*/ + if ( (bufPayload->length < NDEF_TYPE_RTD_WLC_STATUS_INFO_MIN_PAYLOAD_LENGTH) ) + { + return ERR_PROTO; + } + + type->id = NDEF_TYPE_ID_RTD_WLCSTAI; + type->getPayloadLength = ndefRtdWlcStatusInfoGetPayloadLength; + type->getPayloadItem = ndefRtdWlcStatusInfoGetPayloadItem; + type->typeToRecord = ndefRtdWlcStatusInfoToRecord; + ndefData = &type->data.wlcStatusInfo; + + uint32_t offset = NDEF_WLC_STATUSINFO_CONTROL_BYTE_1_OFFSET; + + uint8_t controlByte1 = bufPayload->buffer[offset]; + offset++; + + /* Initialize each field */ + ndefData->controlByte1 = controlByte1; + ndefData->batteryLevel = 0; + ndefData->receivePower = 0; + ndefData->receiveVoltage = 0; + ndefData->receiveCurrent = 0; + ndefData->temperatureBattery = 0; + ndefData->temperatureWlcl = 0; + ndefData->rfu = 0; + ndefData->controlByte2 = 0; + + /* Check each bit in Control byte 1 and read the appropriate byte */ + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_BATTERY_LEVEL_MASK) != 0U) + { + ndefData->batteryLevel = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_POWER_MASK) != 0U) + { + ndefData->receivePower = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_VOLTAGE_MASK) != 0U) + { + ndefData->receiveVoltage = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RECEIVE_CURRENT_MASK) != 0U) + { + ndefData->receiveCurrent = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_BATTERY_MASK) != 0U) + { + ndefData->temperatureBattery = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_TEMPERATURE_WLCL_MASK) != 0U) + { + ndefData->temperatureWlcl = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_RFU_MASK) != 0U) + { + ndefData->rfu = bufPayload->buffer[offset]; + offset++; + } + + if ( (controlByte1 & NDEF_WLC_STATUSINFO_CONTROLBYTE1_CONTROL_BYTE_2_MASK) != 0U) + { + ndefData->controlByte2 = bufPayload->buffer[offset]; + /*offset++;*/ + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdWlcStatusInfo(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + /* NDEF TNF and String type */ + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcStatusInfo)) + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_WLCSTAI) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdWlcStatusInfo(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcStatusInfoToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCSTAI) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* String type */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcStatusInfo); + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +/* + * WLC Poll Information + */ +/*****************************************************************************/ + + +/*****************************************************************************/ +static uint32_t ndefRtdWlcPollInfoGetPayloadLength(const ndefType* type) +{ + if ( (type == NULL) || ((type)->id != NDEF_TYPE_ID_RTD_WLCINFO) ) + { + return 0; + } + + return NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdWlcPollInfoGetPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdWlcPollInfo* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCINFO) || + (bufItem == NULL) ) + { + return NULL; + } + + ndefData = &type->data.wlcPollInfo; + + if (begin == true) + { + item = 0; + } + + /* Prepare bufItem->length: Each field is 1 byte, except when complete */ + bufItem->length = sizeof(uint8_t); + + switch (item) + { + case 0: /* P Tx */ + bufItem->buffer = &ndefData->pTx; + break; + case 1: /* WLC-P Capability | Power class */ + { + static uint8_t temp; + temp = + ((ndefData->wlcPCap << NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_SHIFT) + | ((ndefData->powerClass & NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_MASK))); + + bufItem->buffer = &temp; + break; + } + case 2: /* Total Power Steps */ + bufItem->buffer = &ndefData->totPowerSteps; + break; + case 3: /* Current Power Steps */ + bufItem->buffer = &ndefData->curPowerStep; + break; + case 4: /* Next min step increment */ + bufItem->buffer = &ndefData->nextMinStepInc; + break; + case 5: /* Next min step decrement */ + bufItem->buffer = &ndefData->nextMinStepDec; + break; + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcPollInfoInit(ndefType* type, const ndefTypeRtdWlcPollInfo* param) +{ + ndefTypeRtdWlcPollInfo* ndefData; + + if ( (type == NULL) || (param == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_WLCINFO; + type->getPayloadLength = ndefRtdWlcPollInfoGetPayloadLength; + type->getPayloadItem = ndefRtdWlcPollInfoGetPayloadItem; + type->typeToRecord = ndefRtdWlcPollInfoToRecord; + ndefData = &type->data.wlcPollInfo; + + (void)ST_MEMCPY(ndefData, param, sizeof(ndefTypeRtdWlcPollInfo)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdWlcPollInfo(const ndefType* type, ndefTypeRtdWlcPollInfo* param) +{ + const ndefTypeRtdWlcPollInfo* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCINFO) || + (param == NULL) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.wlcPollInfo; + + (void)ST_MEMCPY(param, ndefData, sizeof(ndefTypeRtdWlcPollInfo)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdWlcPollInfo(const ndefConstBuffer* bufPayload, ndefType* type) +{ + ndefTypeRtdWlcPollInfo* ndefData; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + /* WLC TS v2.0 11.1.1.1 Any additional bytes inside an NDEF Record defined in this specification SHALL be ignored by the receiver.*/ + if (bufPayload->length < NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH) + { + return ERR_PROTO; + } + + type->id = NDEF_TYPE_ID_RTD_WLCINFO; + type->getPayloadLength = ndefRtdWlcPollInfoGetPayloadLength; + type->getPayloadItem = ndefRtdWlcPollInfoGetPayloadItem; + type->typeToRecord = ndefRtdWlcPollInfoToRecord; + ndefData = &type->data.wlcPollInfo; + + ndefData->pTx = bufPayload->buffer[NDEF_WLC_POLL_INFO_PTX_OFFSET]; + ndefData->wlcPCap = bufPayload->buffer[NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_OFFSET] >> NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_SHIFT; + ndefData->powerClass = bufPayload->buffer[NDEF_WLC_POLL_INFO_POWER_CLASS_OFFSET] & NDEF_WLC_POLL_INFO_WLC_P_CAPABILITY_MASK; + ndefData->totPowerSteps = bufPayload->buffer[NDEF_WLC_POLL_INFO_TOT_POWER_STEPS_OFFSET]; + ndefData->curPowerStep = bufPayload->buffer[NDEF_WLC_POLL_INFO_CUR_POWER_STEP_OFFSET]; + ndefData->nextMinStepInc = bufPayload->buffer[NDEF_WLC_POLL_INFO_NEXT_MIN_STEP_INC_OFFSET]; + ndefData->nextMinStepDec = bufPayload->buffer[NDEF_WLC_POLL_INFO_NEXT_MIN_STEP_DEC_OFFSET]; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdWlcPollInfo(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + /* NDEF TNF and String type */ + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcPollInfo)) + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_WLCINFO) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdWlcPollInfo(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcPollInfoToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || ((type)->id != NDEF_TYPE_ID_RTD_WLCINFO) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* String type */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcPollInfo); + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + + +/*****************************************************************************/ +/* + * WLC Listen Control + */ +/*****************************************************************************/ + + +/*****************************************************************************/ +static uint32_t ndefRtdWlcListenCtlGetPayloadLength(const ndefType* type) +{ + const ndefTypeRtdWlcListenCtl* ndefData; + uint32_t payloadLength; + + if ( (type == NULL) || ((type)->id != NDEF_TYPE_ID_RTD_WLCCTL) ) + { + return 0; + } + + ndefData = &type->data.wlcListenCtl; + + payloadLength = NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH; + /* Check for optional last ERROR_INFO byte */ + payloadLength += ((ndefData->statusInfoErrorFlag != 0U) ? 1U : 0U); + + return payloadLength; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdWlcListenCtlGetPayloadItem(const ndefType* type, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + static uint8_t temp = 0; + const ndefTypeRtdWlcListenCtl* ndefData; + + if ( (type == NULL) || ((type)->id != NDEF_TYPE_ID_RTD_WLCCTL) || + (bufItem == NULL) ) + { + return NULL; + } + + ndefData = &type->data.wlcListenCtl; + + if (begin == true) + { + item = 0; + } + + /* Prepare bufItem->length: Each field is 1 byte, except when complete */ + bufItem->length = sizeof(uint8_t); + + switch (item) + { + case 0: /* Status Info */ + { + temp = + ((ndefData->statusInfoErrorFlag & NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_MASK) << NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_SHIFT) + | ((ndefData->statusInfoBatteryStatus & NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_MASK) << NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_SHIFT) + | ((ndefData->statusInfoCnt & NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_MASK) << NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_SHIFT); + + bufItem->buffer = &temp; + break; + } + case 1: /* WPT Config */ + temp = + ((ndefData->wptConfigWptReq & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_MASK) << NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_SHIFT) + | ((ndefData->wptConfigWptDuration & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_MASK) << NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_SHIFT) + | ((ndefData->wptConfigInfoReq & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_MASK) << NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_SHIFT); + + bufItem->buffer = &temp; + break; + case 2: /* Power Adjust Request */ + bufItem->buffer = &ndefData->powerAdjReq; + break; + case 3: /* Battery Level */ + bufItem->buffer = &ndefData->batteryLevel; + break; + case 4: /* Drv Info */ + { + temp = + ((ndefData->drvInfoFlag & NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_MASK) << NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_SHIFT) + | ((ndefData->drvInfoInt & NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_MASK) << NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_SHIFT); + + bufItem->buffer = &temp; + break; + } + case 5: /* Hold Off Wt Int */ + bufItem->buffer = &ndefData->holdOffWtInt; + break; + case 6: /* Optional last ERROR_INFO byte */ + if (ndefData->statusInfoErrorFlag != 0U) + { + /* Send the ERROR_INFO byte */ + temp = + ((ndefData->errorInfoError & NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_MASK) << NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_SHIFT) + | ((ndefData->errorInfoTemperature & NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_MASK) << NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_SHIFT); + + bufItem->buffer = &temp; + break; + } + /* if no ERR_INFO byte to send */ + /* fall through */ + default: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcListenCtlInit(ndefType* type, const ndefTypeRtdWlcListenCtl* param) +{ + ndefTypeRtdWlcListenCtl* ndefData; + + if ( (type == NULL) || (param == NULL) ) + { + return ERR_PARAM; + } + + type->id = NDEF_TYPE_ID_RTD_WLCCTL; + type->getPayloadLength = ndefRtdWlcListenCtlGetPayloadLength; + type->getPayloadItem = ndefRtdWlcListenCtlGetPayloadItem; + type->typeToRecord = ndefRtdWlcListenCtlToRecord; + ndefData = &type->data.wlcListenCtl; + + (void)ST_MEMCPY(ndefData, param, sizeof(ndefTypeRtdWlcListenCtl)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdWlcListenCtl(const ndefType* type, ndefTypeRtdWlcListenCtl* param) +{ + const ndefTypeRtdWlcListenCtl* ndefData; + + if ( (type == NULL) || (type->id != NDEF_TYPE_ID_RTD_WLCCTL) || + (param == NULL) ) + { + return ERR_PARAM; + } + + ndefData = &type->data.wlcListenCtl; + + (void)ST_MEMCPY(param, ndefData, sizeof(ndefTypeRtdWlcListenCtl)); + + return ERR_NONE; +} + + +/*****************************************************************************/ +static ndefStatus ndefPayloadToRtdWlcListenCtl(const ndefConstBuffer* bufPayload, ndefType* type) +{ + ndefTypeRtdWlcListenCtl* ndefData; + + if ( (bufPayload == NULL) || (bufPayload->buffer == NULL) || + (type == NULL) ) + { + return ERR_PARAM; + } + + if (bufPayload->length < NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH) + { + return ERR_PROTO; + } + + type->id = NDEF_TYPE_ID_RTD_WLCCTL; + type->getPayloadLength = ndefRtdWlcListenCtlGetPayloadLength; + type->getPayloadItem = ndefRtdWlcListenCtlGetPayloadItem; + type->typeToRecord = ndefRtdWlcListenCtlToRecord; + ndefData = &type->data.wlcListenCtl; + + uint8_t status = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_STATUS_INFO_OFFSET]; + ndefData->statusInfoErrorFlag = (status >> NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_SHIFT) & NDEF_WLC_LISTEN_CTL_STATUS_INFO_ERROR_MASK; + ndefData->statusInfoBatteryStatus = (status >> NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_SHIFT) & NDEF_WLC_LISTEN_CTL_STATUS_INFO_BATTERY_MASK; + ndefData->statusInfoCnt = (status >> NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_SHIFT) & NDEF_WLC_LISTEN_CTL_STATUS_INFO_COUNTER_MASK; + + uint8_t config = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_WPT_CONFIG_OFFSET]; + ndefData->wptConfigWptReq = (config >> NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_SHIFT) & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_REQ_MASK; + ndefData->wptConfigWptDuration = (config >> NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_SHIFT) & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_DURATION_MASK; + ndefData->wptConfigInfoReq = (config >> NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_SHIFT) & NDEF_WLC_LISTEN_CTL_WPT_CONFIG_INFO_REQ_MASK; + + ndefData->powerAdjReq = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_POWER_ADJ_REQ_OFFSET]; + ndefData->batteryLevel = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_BATTERY_LEVEL_OFFSET]; + + uint8_t drvInfo = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_DRV_INFO_OFFSET]; + ndefData->drvInfoFlag = (drvInfo >> NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_SHIFT) & NDEF_WLC_LISTEN_CTL_DRV_INFO_FLAG_MASK; + ndefData->drvInfoInt = (drvInfo >> NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_SHIFT) & NDEF_WLC_LISTEN_CTL_DRV_INFO_INT_MASK; + + ndefData->holdOffWtInt = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_HOLD_OFF_WT_INT_OFFSET]; + + uint8_t error = 0; + if (ndefData->statusInfoErrorFlag != 0U) + { + if (bufPayload->length < (NDEF_TYPE_RTD_WLC_PAYLOAD_LENGTH + 1U)) + { + return ERR_PROTO; + } + error = bufPayload->buffer[NDEF_WLC_LISTEN_CTL_ERROR_INFO_OFFSET]; + } + ndefData->errorInfoError = (error >> NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_SHIFT) & NDEF_WLC_LISTEN_CTL_ERROR_INFO_PROTOCOL_MASK; + ndefData->errorInfoTemperature = (error >> NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_SHIFT) & NDEF_WLC_LISTEN_CTL_ERROR_INFO_TEMPERATURE_MASK; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdWlcListenCtl(const ndefRecord* record, ndefType* type) +{ + const ndefType* ndefData; + + if ( (record == NULL) || (type == NULL) ) + { + return ERR_PARAM; + } + + /* NDEF TNF and String type */ + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcListenCtl)) + { + return ERR_PROTO; + } + + ndefData = ndefRecordGetNdefType(record); + if ( (ndefData != NULL) && (ndefData->id == NDEF_TYPE_ID_RTD_WLCCTL) ) + { + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + return ndefPayloadToRtdWlcListenCtl(&record->bufPayload, type); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWlcListenCtlToRecord(const ndefType* type, ndefRecord* record) +{ + if ( (type == NULL) || ((type)->id != NDEF_TYPE_ID_RTD_WLCCTL) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* String type */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcListenCtl); + + if (ndefRecordSetNdefType(record, type) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_type_wpcwlc.c b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wpcwlc.c new file mode 100644 index 0000000..30109bb --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_type_wpcwlc.c @@ -0,0 +1,224 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD RTD Wireless Power Consortium WLC Record (WPCWLC) type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "ndef_type_wpcwlc.h" +#include "utils.h" + + +#if NDEF_TYPE_RTD_WPCWLC_SUPPORT + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/*! RTD Type strings */ +static const uint8_t ndefRtdTypeWptWlc[] = "www.wirelesspowerconsortium.com:wlc"; /*!< External Type (Wireless Power Consortium WLC Record) */ + +const ndefConstBuffer8 bufRtdTypeWpcWlc = { ndefRtdTypeWptWlc, sizeof(ndefRtdTypeWptWlc) - 1U }; /*!< WPCWLC External Type Record buffer */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/* + * NFC Forum External Type (Wireless Power Consortium WLC Record) + */ + + +/*****************************************************************************/ +static uint32_t ndefRtdWpcWlcPayloadGetLength(const ndefType* wpcWlc) +{ + const ndefTypeRtdWpcWlc* rtdWpcWlc; + + if ( (wpcWlc == NULL) || (wpcWlc->id != NDEF_TYPE_ID_RTD_WPCWLC) ) + { + return 0; + } + + rtdWpcWlc = &wpcWlc->data.wpcWlc; + + return rtdWpcWlc->bufPayload.length; +} + + +/*****************************************************************************/ +static const uint8_t* ndefRtdWpcWlcToPayloadItem(const ndefType* wpcWlc, ndefConstBuffer* bufItem, bool begin) +{ + static uint32_t item = 0; + const ndefTypeRtdWpcWlc* rtdWpcWlc; + + if ( (wpcWlc == NULL) || (wpcWlc->id != NDEF_TYPE_ID_RTD_WPCWLC) || + (bufItem == NULL) ) + { + return NULL; + } + + rtdWpcWlc = &wpcWlc->data.wpcWlc; + + if (begin == true) + { + item = 0; + } + + switch (item) + { + case 0: + /* Ki Payload */ + bufItem->buffer = rtdWpcWlc->bufPayload.buffer; + bufItem->length = rtdWpcWlc->bufPayload.length; + break; + + default: + bufItem->buffer = NULL; + bufItem->length = 0; + break; + } + + /* Move to next item for next call */ + item++; + + return bufItem->buffer; +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWpcWlcInit(ndefType* wpcWlc, const ndefConstBuffer* bufPayload) +{ + ndefTypeRtdWpcWlc* rtdWpcWlc; + + if ( (wpcWlc == NULL) || (bufPayload == NULL) ) + { + return ERR_PARAM; + } + + wpcWlc->id = NDEF_TYPE_ID_RTD_WPCWLC; + wpcWlc->getPayloadLength = ndefRtdWpcWlcPayloadGetLength; + wpcWlc->getPayloadItem = ndefRtdWpcWlcToPayloadItem; + wpcWlc->typeToRecord = ndefRtdWpcWlcToRecord; + rtdWpcWlc = &wpcWlc->data.wpcWlc; + + rtdWpcWlc->bufPayload.buffer = bufPayload->buffer; + rtdWpcWlc->bufPayload.length = bufPayload->length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefGetRtdWpcWlc(const ndefType* wpcWlc, ndefConstBuffer* bufWpcWlc) +{ + const ndefTypeRtdWpcWlc* rtdWpcWlc; + + if ( (wpcWlc == NULL) || (wpcWlc->id != NDEF_TYPE_ID_RTD_WPCWLC) || + (bufWpcWlc == NULL) ) + { + return ERR_PARAM; + } + + rtdWpcWlc = &wpcWlc->data.wpcWlc; + + bufWpcWlc->buffer = rtdWpcWlc->bufPayload.buffer; + bufWpcWlc->length = rtdWpcWlc->bufPayload.length; + + return ERR_NONE; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordToRtdWpcWlc(const ndefRecord* record, ndefType* wpcWlc) +{ + if ( (record == NULL) || (wpcWlc == NULL) ) + { + return ERR_PARAM; + } + + if ( ! ndefRecordTypeMatch(record, NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeWpcWlc)) /* "www.wirelesspowerconsortium.com:wlc" */ + { + return ERR_PROTO; + } + + /* No constraint on payload length */ + + return ndefRtdWpcWlcInit(wpcWlc, &record->bufPayload); +} + + +/*****************************************************************************/ +ndefStatus ndefRtdWpcWlcToRecord(const ndefType* wpcWlc, ndefRecord* record) +{ + if ( (wpcWlc == NULL) || (wpcWlc->id != NDEF_TYPE_ID_RTD_WPCWLC) || + (record == NULL) ) + { + return ERR_PARAM; + } + + (void)ndefRecordReset(record); + + /* "www.wirelesspowerconsortium.com:wlc" */ + (void)ndefRecordSetType(record, NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeWpcWlc); + + if (ndefRecordSetNdefType(record, wpcWlc) != ERR_NONE) + { + return ERR_PARAM; + } + + return ERR_NONE; +} + +#endif diff --git a/components/spi-st25r3911b/NDEF/source/message/ndef_types.c b/components/spi-st25r3911b/NDEF/source/message/ndef_types.c new file mode 100644 index 0000000..0187aa7 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/message/ndef_types.c @@ -0,0 +1,239 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief NDEF RTD and MIME types + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_record.h" +#include "ndef_types.h" +#include "utils.h" + + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/*! NDEF type table to associate a TNF, type and the recordToType function pointers */ +typedef struct +{ + uint8_t tnf; /*!< TNF */ + const ndefConstBuffer8* bufTypeString; /*!< Type String buffer */ + ndefStatus (*recordToType)(const ndefRecord* record, ndefType* type); /*!< Pointer to read function */ +} ndefTypeConverter; + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*****************************************************************************/ +ndefStatus ndefRecordToType(const ndefRecord* record, ndefType* type) +{ +#if NDEF_TYPE_EMPTY_SUPPORT + /*! Empty string */ + static const uint8_t ndefTypeEmpty[] = ""; /*!< Empty string */ + static ndefConstBuffer8 bufTypeEmpty = { ndefTypeEmpty, sizeof(ndefTypeEmpty) - 1U }; +#endif + + /*! Array to match RTD strings with Well-known types, and converting functions */ + static const ndefTypeConverter typeConverterTable[] = + { +#if NDEF_TYPE_EMPTY_SUPPORT + { NDEF_TNF_EMPTY, &bufTypeEmpty, ndefRecordToEmptyType }, +#endif +#if NDEF_TYPE_RTD_DEVICE_INFO_SUPPORT + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeDeviceInfo, ndefRecordToRtdDeviceInfo }, +#endif +#if NDEF_TYPE_RTD_TEXT_SUPPORT + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeText, ndefRecordToRtdText }, +#endif +#if NDEF_TYPE_RTD_URI_SUPPORT + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeUri, ndefRecordToRtdUri }, +#endif +#if NDEF_TYPE_RTD_AAR_SUPPORT + { NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeAar, ndefRecordToRtdAar }, +#endif +#if NDEF_TYPE_RTD_WLC_SUPPORT + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcCapability, ndefRecordToRtdWlcCapability }, + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcStatusInfo, ndefRecordToRtdWlcStatusInfo }, + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcPollInfo, ndefRecordToRtdWlcPollInfo }, + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufTypeRtdWlcListenCtl, ndefRecordToRtdWlcListenCtl }, +#endif +#if NDEF_TYPE_RTD_WPCWLC_SUPPORT + { NDEF_TNF_RTD_EXTERNAL_TYPE, &bufRtdTypeWpcWlc, ndefRecordToRtdWpcWlc }, +#endif +#if NDEF_TYPE_RTD_TNEP_SUPPORT + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceParameter, ndefRecordToRtdTnepServiceParameter }, + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepServiceSelect, ndefRecordToRtdTnepServiceSelect }, + { NDEF_TNF_RTD_WELL_KNOWN_TYPE, &bufRtdTypeTnepStatus, ndefRecordToRtdTnepStatus }, +#endif +#if NDEF_TYPE_BLUETOOTH_SUPPORT + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothBrEdr, ndefRecordToBluetooth }, + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothLe, ndefRecordToBluetooth }, + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureBrEdr, ndefRecordToBluetooth }, + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeBluetoothSecureLe, ndefRecordToBluetooth }, +#endif +#if NDEF_TYPE_VCARD_SUPPORT + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeVCard, ndefRecordToVCard }, +#endif +#if NDEF_TYPE_WIFI_SUPPORT + { NDEF_TNF_MEDIA_TYPE, &bufMediaTypeWifi, ndefRecordToWifi }, +#endif + /* Non-conditional field to avoid empty union when all types are disabled */ + { 0, NULL, NULL } + }; + + const ndefType* ndefData; + + if (type == NULL) + { + return ERR_PARAM; + } + + ndefData = ndefRecordGetNdefType(record); + if (ndefData != NULL) + { + /* Return the well-known type contained in the record */ + (void)ST_MEMCPY(type, ndefData, sizeof(ndefType)); + return ERR_NONE; + } + + for (int32_t i = 0; i < (int32_t)SIZEOF_ARRAY(typeConverterTable); i++) + { + if (ndefRecordTypeMatch(record, typeConverterTable[i].tnf, typeConverterTable[i].bufTypeString)) + { + /* Call the appropriate function to the matching type */ + if (typeConverterTable[i].recordToType != NULL) + { + return typeConverterTable[i].recordToType(record, type); + } + } + } + +#if NDEF_TYPE_FLAT_SUPPORT + return ndefRecordToFlatPayloadType(record, type); +#else + return ERR_NOT_IMPLEMENTED; +#endif +} + + +/*****************************************************************************/ +ndefStatus ndefTypeToRecord(const ndefType* type, ndefRecord* record) +{ + if (type == NULL) + { + return ERR_PARAM; + } + + if (type->typeToRecord != NULL) + { + return type->typeToRecord(type, record); + } + + return ERR_NOT_IMPLEMENTED; +} + + +/*****************************************************************************/ +ndefStatus ndefRecordSetNdefType(ndefRecord* record, const ndefType* type) +{ + uint32_t payloadLength; + + if ( (record == NULL) || + (type == NULL) || + (type->id == NDEF_TYPE_ID_NONE) || + (type->id > NDEF_TYPE_ID_COUNT) || + (type->getPayloadLength == NULL) || + (type->getPayloadItem == NULL) || + (type->typeToRecord == NULL) ) + { + return ERR_PARAM; + } + + record->ndeftype = type; + + /* Set Short Record bit accordingly */ + payloadLength = ndefRecordGetPayloadLength(record); + ndefHeaderSetValueSR(record, (payloadLength <= NDEF_SHORT_RECORD_LENGTH_MAX) ? 1 : 0); + + return ERR_NONE; +} + + +/*****************************************************************************/ +const ndefType* ndefRecordGetNdefType(const ndefRecord* record) +{ + if (record == NULL) + { + return NULL; + } + + /* Check whether it is a valid NDEF type */ + if ( (record->ndeftype != NULL) && + (record->ndeftype->id != NDEF_TYPE_ID_NONE) && + (record->ndeftype->id < NDEF_TYPE_ID_COUNT) && + (record->ndeftype->getPayloadItem != NULL) && + (record->ndeftype->getPayloadLength != NULL) && + (record->ndeftype->typeToRecord != NULL) ) + { + return record->ndeftype; + } + + return NULL; +} diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_poller.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller.c new file mode 100644 index 0000000..21bc1e7 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller.c @@ -0,0 +1,513 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum Tags + * + * This module provides an interface to handle NDEF message + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_poller.h" +#include "ndef_t2t.h" +#include "ndef_t3t.h" +#include "ndef_t4t.h" +#include "ndef_t5t_hal.h" +#include "ndef_t5t.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL VARIABLE DEFINITIONS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*******************************************************************************/ +ndefStatus ndefPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev) +{ + ndefDeviceType type; + +#if NDEF_FEATURE_T1T + static const ndefPollerWrapper ndefT1TWrapper = + { + NULL, /* ndefT1TPollerContextInitialization, */ + NULL, /* ndefT1TPollerNdefDetect, */ + NULL, /* ndefT1TPollerReadBytes, */ + NULL, /* ndefT1TPollerReadRawMessage, */ +#if NDEF_FEATURE_FULL_API + NULL, /* ndefT1TPollerWriteBytes, */ + NULL, /* ndefT1TPollerWriteRawMessage, */ + NULL, /* ndefT1TPollerTagFormat, */ + NULL, /* ndefT1TPollerWriteRawMessageLen */ + NULL, /* ndefT1TPollerCheckPresence */ + NULL, /* ndefT1TPollerCheckAvailableSpace */ + NULL, /* ndefT1TPollerBeginWriteMessage */ + NULL, /* ndefT1TPollerEndWriteMessage */ + NULL /* ndefT1TPollerSetReadOnly */ +#endif /* NDEF_FEATURE_FULL_API */ + }; +#endif /* NDEF_FEATURE_T1T */ + +#if NDEF_FEATURE_T2T + static const ndefPollerWrapper ndefT2TWrapper = + { + ndefT2TPollerContextInitialization, + ndefT2TPollerNdefDetect, + ndefT2TPollerReadBytes, + ndefT2TPollerReadRawMessage, +#if NDEF_FEATURE_FULL_API + ndefT2TPollerWriteBytes, + ndefT2TPollerWriteRawMessage, + ndefT2TPollerTagFormat, + ndefT2TPollerWriteRawMessageLen, + ndefT2TPollerCheckPresence, + ndefT2TPollerCheckAvailableSpace, + ndefT2TPollerBeginWriteMessage, + ndefT2TPollerEndWriteMessage, + ndefT2TPollerSetReadOnly +#endif /* NDEF_FEATURE_FULL_API */ + }; +#endif /* NDEF_FEATURE_T2T */ + +#if NDEF_FEATURE_T3T + static const ndefPollerWrapper ndefT3TWrapper = + { + ndefT3TPollerContextInitialization, + ndefT3TPollerNdefDetect, + ndefT3TPollerReadBytes, + ndefT3TPollerReadRawMessage, +#if NDEF_FEATURE_FULL_API + ndefT3TPollerWriteBytes, + ndefT3TPollerWriteRawMessage, + ndefT3TPollerTagFormat, + ndefT3TPollerWriteRawMessageLen, + ndefT3TPollerCheckPresence, + ndefT3TPollerCheckAvailableSpace, + ndefT3TPollerBeginWriteMessage, + ndefT3TPollerEndWriteMessage, + ndefT3TPollerSetReadOnly +#endif /* NDEF_FEATURE_FULL_API */ + }; +#endif /* NDEF_FEATURE_T3T */ + +#if NDEF_FEATURE_T4T + static const ndefPollerWrapper ndefT4TWrapper = + { + ndefT4TPollerContextInitialization, + ndefT4TPollerNdefDetect, + ndefT4TPollerReadBytes, + ndefT4TPollerReadRawMessage, +#if NDEF_FEATURE_FULL_API + ndefT4TPollerWriteBytes, + ndefT4TPollerWriteRawMessage, + ndefT4TPollerTagFormat, + ndefT4TPollerWriteRawMessageLen, + ndefT4TPollerCheckPresence, + ndefT4TPollerCheckAvailableSpace, + ndefT4TPollerBeginWriteMessage, + ndefT4TPollerEndWriteMessage, + ndefT4TPollerSetReadOnly +#endif /* NDEF_FEATURE_FULL_API */ + }; +#endif /* NDEF_FEATURE_T4T */ + +#if NDEF_FEATURE_T5T + static const ndefPollerWrapper ndefT5TWrapper = + { + ndefT5TPollerContextInitialization, + ndefT5TPollerNdefDetect, + ndefT5TPollerReadBytes, + ndefT5TPollerReadRawMessage, +#if NDEF_FEATURE_FULL_API + ndefT5TPollerWriteBytes, + ndefT5TPollerWriteRawMessage, + ndefT5TPollerTagFormat, + ndefT5TPollerWriteRawMessageLen, + ndefT5TPollerCheckPresence, + ndefT5TPollerCheckAvailableSpace, + ndefT5TPollerBeginWriteMessage, + ndefT5TPollerEndWriteMessage, + ndefT5TPollerSetReadOnly +#endif /* NDEF_FEATURE_FULL_API */ + }; +#endif /* NDEF_FEATURE_T5T */ + + static const ndefPollerWrapper *ndefPollerWrappers[] = + { + NULL, /* No device */ +#if NDEF_FEATURE_T1T + &ndefT1TWrapper, +#else + NULL, +#endif +#if NDEF_FEATURE_T2T + &ndefT2TWrapper, +#else + NULL, +#endif +#if NDEF_FEATURE_T3T + &ndefT3TWrapper, +#else + NULL, +#endif +#if NDEF_FEATURE_T4T + &ndefT4TWrapper, +#else + NULL, +#endif +#if NDEF_FEATURE_T5T + &ndefT5TWrapper, +#else + NULL, +#endif + }; + + if( (ctx == NULL) || (dev == NULL) ) + { + return ERR_PARAM; + } + + type = ndefGetDeviceType(dev); + + if( (type == NDEF_DEV_NONE) || ((uint32_t)type >= SIZEOF_ARRAY(ndefPollerWrappers)) ) + { + return ERR_PARAM; + } + + ctx->ndefPollWrapper = ndefPollerWrappers[type]; + + /* ndefPollWrapper is NULL when support of a given tag type is not enabled */ + if( (ctx->ndefPollWrapper == NULL) || (ctx->ndefPollWrapper->pollerContextInitialization == NULL) ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerContextInitialization)(ctx, dev); +} + +/*******************************************************************************/ +ndefStatus ndefPollerNdefDetect(ndefContext *ctx, ndefInfo *info) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerNdefDetect == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerNdefDetect)(ctx, info); +} + +/*******************************************************************************/ +ndefStatus ndefPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerReadRawMessage == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerReadRawMessage)(ctx, buf, bufLen, rcvdLen, single); +} + +/*******************************************************************************/ +ndefStatus ndefPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerReadBytes == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerReadBytes)(ctx, offset, len, buf, rcvdLen); +} + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +ndefStatus ndefPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerWriteRawMessage == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerWriteRawMessage)(ctx, buf, bufLen); +} + +/*******************************************************************************/ +ndefStatus ndefPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerTagFormat == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerTagFormat)(ctx, cc, options); +} + +/*******************************************************************************/ +ndefStatus ndefPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerWriteRawMessageLen == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerWriteRawMessageLen)(ctx, rawMessageLen, true); +} + +/*******************************************************************************/ +ndefStatus ndefPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerWriteBytes == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerWriteBytes)(ctx, offset, buf, len, false, false); +} + +/*******************************************************************************/ +ndefStatus ndefPollerCheckPresence(ndefContext *ctx) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerCheckPresence == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerCheckPresence)(ctx); +} + +/*******************************************************************************/ +ndefStatus ndefPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerCheckAvailableSpace == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerCheckAvailableSpace)(ctx, messageLen); +} + +/*******************************************************************************/ +ndefStatus ndefPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerBeginWriteMessage == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerBeginWriteMessage)(ctx, messageLen); +} + +/*******************************************************************************/ +ndefStatus ndefPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerEndWriteMessage == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerEndWriteMessage)(ctx, messageLen, true); +} + +/*******************************************************************************/ +ndefStatus ndefPollerSetReadOnly(ndefContext *ctx) +{ + if( ctx == NULL ) + { + return ERR_PARAM; + } + + if( ctx->ndefPollWrapper == NULL ) + { + return ERR_WRONG_STATE; + } + + if( ctx->ndefPollWrapper->pollerSetReadOnly == NULL ) + { + return ERR_NOTSUPP; + } + + return (ctx->ndefPollWrapper->pollerSetReadOnly)(ctx); +} + +#endif /* NDEF_FEATURE_FULL_API */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_message.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_message.c new file mode 100644 index 0000000..ffaf18a --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_message.c @@ -0,0 +1,240 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum Tags + * + * This module provides an interface between NDEF technology and technology-independant NDEF message + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "ndef_poller.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL VARIABLE DEFINITIONS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +static ndefStatus ndefPollerWriteRecord(ndefContext *ctx, const ndefRecord *record, uint32_t* recordOffset) +{ + ndefStatus err; + uint8_t recordHeaderBuf[NDEF_RECORD_HEADER_LEN]; + ndefBuffer bufHeader; + ndefConstBuffer bufPayloadItem; + uint32_t offset; + bool firstPayloadItem; + + if ( (ctx == NULL) || (record == NULL) || (recordOffset == NULL) ) + { + return ERR_PARAM; + } + + offset = *recordOffset; + + bufHeader.buffer = recordHeaderBuf; + bufHeader.length = sizeof(recordHeaderBuf); + (void)ndefRecordEncodeHeader(record, &bufHeader); + err = ndefPollerWriteBytes(ctx, offset, bufHeader.buffer, bufHeader.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + return err; + } + offset += bufHeader.length; + + ndefConstBuffer8 bufType; + ndefRecordGetType(record, NULL, &bufType); + if (bufType.length != 0U) + { + err = ndefPollerWriteBytes(ctx, offset, bufType.buffer, bufType.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + return err; + } + offset += record->typeLength; + } + + ndefConstBuffer8 bufId; + ndefRecordGetId(record, &bufId); + if (bufId.length != 0U) + { + err = ndefPollerWriteBytes(ctx, offset, bufId.buffer, bufId.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + return err; + } + offset += record->idLength; + } + if (ndefRecordGetPayloadLength(record) != 0U) + { + firstPayloadItem = true; + while (ndefRecordGetPayloadItem(record, &bufPayloadItem, firstPayloadItem) != NULL) + { + firstPayloadItem = false; + err = ndefPollerWriteBytes(ctx, offset, bufPayloadItem.buffer, bufPayloadItem.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + return err; + } + offset += bufPayloadItem.length; + } + } + + *recordOffset = offset; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefPollerWriteMessage(ndefContext *ctx, const ndefMessage *message) +{ + ndefStatus err; + ndefMessageInfo info; + ndefRecord* record; + uint32_t offset; + + if ( (ctx == NULL) || (message == NULL) ) + { + return ERR_PARAM; + } + + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + (void)ndefMessageGetInfo(message, &info); + + /* Verify length of the NDEF message */ + err = ndefPollerCheckAvailableSpace(ctx, info.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + return ERR_PARAM; + } + + /* Reset L-Field/NLEN field */ + err = ndefPollerBeginWriteMessage(ctx, info.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return err; + } + + if (info.length != 0U) + { + offset = ctx->messageOffset; + + record = ndefMessageGetFirstRecord(message); + while (record != NULL) + { + err = ndefPollerWriteRecord(ctx, record, &offset); + if (err != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return err; + } + + record = ndefMessageGetNextRecord(record); + } + + err = ndefPollerEndWriteMessage(ctx, info.length); + if (err != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return err; + } + + /* Procedure complete: Set Read/Write state */ + ctx->state = NDEF_STATE_READWRITE; + } + else + { + /* Procedure complete: Set Initialized state */ + ctx->state = NDEF_STATE_INITIALIZED; + } + + return ERR_NONE; +} + +#endif /* NDEF_FEATURE_FULL_API */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_rf.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_rf.c new file mode 100644 index 0000000..d7088f1 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_poller_rf.c @@ -0,0 +1,121 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum Tags + * + * This module provides an interface to handle the device type + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/* + ***************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +ndefDeviceType ndefGetDeviceType(const ndefDevice *dev) +{ + ndefDeviceType type = NDEF_DEV_NONE; + + if( dev != NULL ) + { + switch( dev->type ) + { + case RFAL_NFC_LISTEN_TYPE_NFCA: + switch( dev->dev.nfca.type ) + { + case RFAL_NFCA_T1T: + type = NDEF_DEV_T1T; + break; + case RFAL_NFCA_T2T: + type = NDEF_DEV_T2T; + break; + case RFAL_NFCA_T4T: + type = NDEF_DEV_T4T; + break; + default: + break; + } + break; + case RFAL_NFC_LISTEN_TYPE_NFCB: + type = NDEF_DEV_T4T; + break; + case RFAL_NFC_LISTEN_TYPE_NFCF: + type = NDEF_DEV_T3T; + break; + case RFAL_NFC_LISTEN_TYPE_NFCV: + type = NDEF_DEV_T5T; + break; + default: + break; + } + } + + return type; +} diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_t2t.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_t2t.c new file mode 100644 index 0000000..401de9e --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_t2t.c @@ -0,0 +1,1290 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T2T + * + * This module provides an interface to perform as a NFC Reader/Writer + * to handle a Type 2 Tag T2T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" +#include "ndef_t2t.h" +#include "rfal_t2t.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef NDEF_FEATURE_T2T + #error " NDEF: Module configuration missing. Please enable/disable T2T module by setting: NDEF_FEATURE_T2T" +#endif + +#if NDEF_FEATURE_T2T + +#ifndef NDEF_FEATURE_FULL_API + #error " NDEF: Module configuration missing. Please enable/disable Full API by setting: NDEF_FEATURE_FULL_API" +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T2T_BLOCK_SIZE 4U /*!< block size */ +#define NDEF_T2T_MAX_SECTOR 255U /*!< Max Number of Sector in Sector Select Command */ /* 00h -- FEh: 255 sectors */ +#define NDEF_T2T_BLOCKS_PER_SECTOR 256U /*!< Number of Block per Sector */ +#define NDEF_T2T_BYTES_PER_SECTOR (NDEF_T2T_BLOCKS_PER_SECTOR * NDEF_T2T_BLOCK_SIZE) /*!< Number of Bytes per Sector */ +#define NDEF_T2T_MAX_OFFSET (NDEF_T2T_BYTES_PER_SECTOR * NDEF_T2T_MAX_SECTOR) /*!< Maximum offset allowed */ +#define NDEF_T2T_3_BYTES_TLV_LEN 0xFFU /* FFh indicates the use of 3 bytes got the L field */ +#define NDEF_T2T_STATIC_MEM_SIZE 48U /* Static memory size */ + +#define NDEF_T2T_CC_OFFSET 12U /*!< CC offset */ +#define NDEF_T2T_CC_LEN 4U /*!< CC length */ +#define NDEF_T2T_AREA_OFFSET 16U /*!< T2T Area starts at block #4 */ + +#define NDEF_T2T_MAGIC 0xE1U /*!< CC Magic Number */ +#define NDEF_T2T_CC_0 0U /*!< CC_0: Magic Number */ +#define NDEF_T2T_CC_1 1U /*!< CC_1: Version */ +#define NDEF_T2T_CC_2 2U /*!< CC_2: Size */ +#define NDEF_T2T_CC_3 3U /*!< CC_3: Access conditions */ + +#define NDEF_T2T_VERSION_1_0 0x10U /*!< Version 1.0 */ + +#define NDEF_T2T_SIZE_DIVIDER 8U /*!< T2T_area size is measured in bytes is equal to 8 * Size */ + +#define NDEF_T2T_TLV_NULL 0x00U /*!< Null TLV */ +#define NDEF_T2T_TLV_LOCK_CTRL 0x01U /*!< Lock Control TLV */ +#define NDEF_T2T_TLV_MEMORY_CTRL 0x02U /*!< Memory Control TLV */ +#define NDEF_T2T_TLV_NDEF_MESSAGE 0x03U /*!< NDEF Message TLV */ +#define NDEF_T2T_TLV_PROPRIETRARY 0xFDU /*!< Proprietary TLV */ +#define NDEF_T2T_TLV_TERMINATOR 0xFEU /*!< Terminator TLV */ + +#define NDEF_T2T_TLV_L_3_BYTES_LEN 3U /*!< TLV L Length: 3 bytes */ +#define NDEF_T2T_TLV_L_1_BYTES_LEN 1U /*!< TLV L Length: 1 byte */ +#define NDEF_T2T_TLV_T_LEN 1U /*!< TLV T Length: 1 byte */ + +#define NDEF_T2T_LOCK_CTRL_LEN 3U /*!< Dyn Lock Control Length: 3 bytes */ +#define NDEF_T2T_MEM_CTRL_LEN 3U /*!< Memory Control Length: 3 bytes */ + +#define NDEF_T2T_DEF_BYTES_LCK_PER_BIT 8U /*!< Default nbr of bytes locked per bit for DynLock */ + +#define NDEF_T2T_WR_ACCESS_GRANTED 0x0U /*!< Write Accces 0h: Access granted w/o any security */ +#define NDEF_T2T_WR_ACCESS_NONE 0xFU /*!< Write Accces Fh: No access granted */ + +#define NDEF_T2T_STATLOCK_OFFSET 10U /*!< Static Lock offset */ + +#ifndef NDEF_T2T_N_RETRY_ERROR +#define NDEF_T2T_N_RETRY_ERROR 1U /*!< nT2T,RETRY,ERROR DP 2.2 B.7 */ +#endif /* NDEF_T2T_N_RETRY_ERROR */ + +#define NDEF_T2T_DYN_LOCK_BYTES_MAX 32U /*!< Max number of Dyn Lock Bytes */ + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define ndefT2TisT2TDevice(device) ((((device)->type == RFAL_NFC_LISTEN_TYPE_NFCA) && ((device)->dev.nfca.type == RFAL_NFCA_T2T))) +#define ndefT2TInvalidateCache(ctx) { (ctx)->subCtx.t2t.cacheAddr = 0xFFFFFFFFU; } + +#define ndefT2TIsReadOnlyAccessGranted(ctx) (((ctx)->cc.t2t.readAccess == 0x0U) && ((ctx)->cc.t2t.writeAccess == NDEF_T2T_WR_ACCESS_NONE)) +#define ndefT2TIsReadWriteAccessGranted(ctx) (((ctx)->cc.t2t.readAccess == 0x0U) && ((ctx)->cc.t2t.writeAccess == NDEF_T2T_WR_ACCESS_GRANTED)) + +#define rfalT2TIsTransmissionError(err) ( ((err) == RFAL_ERR_FRAMING) || ((err) == RFAL_ERR_CRC) || ((err) == RFAL_ERR_PAR) ) + +#define ndefT2TLogD(...) /*!< Macro for the debug log method */ +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static ndefStatus ndefT2TPollerReadBlock(ndefContext *ctx, uint16_t blockAddr, uint8_t *buf); + +#if NDEF_FEATURE_FULL_API +static ndefStatus ndefT2TPollerWriteBlock(ndefContext *ctx, uint16_t blockAddr, const uint8_t *buf); +#endif /* NDEF_FEATURE_FULL_API */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +static ndefStatus ndefT2TPollerReadBlock(ndefContext *ctx, uint16_t blockAddr, uint8_t *buf) +{ + ReturnCode ret; + uint8_t secNo; + uint8_t blNo; + uint16_t rcvdLen; + uint32_t retry; + + ndefT2TLogD("ndefT2TPollerReadBlock 0x%2.2x\r\n", blockAddr); + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + secNo = (uint8_t)(blockAddr >> 8U); + blNo = (uint8_t)blockAddr; + + if( secNo != ctx->subCtx.t2t.currentSecNo ) + { + ret = rfalT2TPollerSectorSelect(secNo); + if( ret != RFAL_ERR_NONE ) + { + return ERR_REQUEST; + } + ctx->subCtx.t2t.currentSecNo = secNo; + } + + retry = NDEF_T2T_N_RETRY_ERROR; + do + { + ret = rfalT2TPollerRead(blNo, buf, NDEF_T2T_READ_RESP_SIZE, &rcvdLen); + } + while ( (retry-- != 0U) && rfalT2TIsTransmissionError(ret) ); + + if( (ret == RFAL_ERR_NONE) && (rcvdLen != NDEF_T2T_READ_RESP_SIZE) ) + { + return ERR_REQUEST; + } + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + ndefStatus ret; + uint8_t le; + uint32_t lvOffset = offset; + uint32_t lvLen = len; + uint8_t* lvBuf = buf; + uint16_t blockAddr; + uint8_t byteNo; + uint8_t numOfValidBlocks; + + ndefT2TLogD("ndefT2TPollerReadBytes offset: %d, len %d\r\n", offset, len); + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (lvLen == 0U) || (offset > NDEF_T2T_MAX_OFFSET) ) + { + return ERR_PARAM; + } + + if( (offset >= ctx->subCtx.t2t.cacheAddr) && (offset < (ctx->subCtx.t2t.cacheAddr + NDEF_T2T_READ_RESP_SIZE)) && ((offset + len) < (ctx->subCtx.t2t.cacheAddr + NDEF_T2T_READ_RESP_SIZE)) ) + { + /* data in cache buffer */ + (void)ST_MEMCPY(lvBuf, &ctx->subCtx.t2t.cacheBuf[offset - ctx->subCtx.t2t.cacheAddr], len); + } + else + { + do { + blockAddr = (uint16_t)(lvOffset / NDEF_T2T_BLOCK_SIZE); + byteNo = (uint8_t)(lvOffset % NDEF_T2T_BLOCK_SIZE); + le = (lvLen < NDEF_T2T_READ_RESP_SIZE) ? (uint8_t)lvLen : (uint8_t)NDEF_T2T_READ_RESP_SIZE; + if( ((uint32_t)(uint8_t)blockAddr + (NDEF_T2T_READ_RESP_SIZE/NDEF_T2T_BLOCK_SIZE)) > NDEF_T2T_BLOCKS_PER_SECTOR ) + { + numOfValidBlocks = (uint8_t)(NDEF_T2T_BLOCKS_PER_SECTOR - (uint8_t)blockAddr); + le = MIN(le, numOfValidBlocks * NDEF_T2T_BLOCK_SIZE); + ndefT2TLogD("ndefT2TPollerReadBytes blockAddr: 0x%4.4x numofValidBlock: %d le: %d \r\n", blockAddr, numOfValidBlocks, le); + } + else + { + numOfValidBlocks = NDEF_T2T_READ_RESP_SIZE/NDEF_T2T_BLOCK_SIZE; + } + + if( (byteNo != 0U ) || (lvLen < NDEF_T2T_READ_RESP_SIZE) ) + { + ret = ndefT2TPollerReadBlock(ctx, blockAddr, ctx->subCtx.t2t.cacheBuf); + if( ret != ERR_NONE ) + { + ndefT2TInvalidateCache(ctx); + return ret; + } + ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE; + if( (NDEF_T2T_READ_RESP_SIZE - byteNo) < le ) + { + le = NDEF_T2T_READ_RESP_SIZE - byteNo; + } + if( le > 0U) + { + (void)ST_MEMCPY(lvBuf, &ctx->subCtx.t2t.cacheBuf[byteNo], le); + } + } + else + { + ret = ndefT2TPollerReadBlock(ctx, blockAddr, lvBuf); + if( ret != ERR_NONE ) + { + return ret; + } + if( (lvLen == le) && (numOfValidBlocks == (NDEF_T2T_READ_RESP_SIZE/NDEF_T2T_BLOCK_SIZE)) ) + { + /* cache the last read block */ + (void)ST_MEMCPY(&ctx->subCtx.t2t.cacheBuf[0], lvBuf, NDEF_T2T_READ_RESP_SIZE); + ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE; + } + } + lvBuf = &lvBuf[le]; + lvOffset += le; + lvLen -= le; + + } while( lvLen != 0U ); + } + + if( rcvdLen != NULL ) + { + *rcvdLen = len; + } + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT2TPollerSplitIntoAvailableAreas(ndefContext *ctx, uint32_t offset, uint32_t len, uint32_t *physOffset, uint32_t *maxLen) +{ + uint32_t updatedOffset; + uint32_t updatedLen; + uint32_t i; + + ndefT2TLogD("ndefT2TPollerSplitIntoAvailableAreas offset %d, len %d\r\n", offset, len); + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (physOffset == NULL) || (maxLen == NULL) ) + { + return ERR_PARAM; + } + + updatedOffset = offset; + updatedLen = len; + + for( i = 0; i < ctx->subCtx.t2t.nbrRsvdAreas; i++ ) + { + ndefT2TLogD("ndefT2TPollerSplitIntoAvailableAreas area #%d, start: %d Len: %d\r\n", i, ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i], ctx->subCtx.t2t.rsvdAreaSize[i]); + if( updatedOffset >= ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] ) + { + updatedOffset += ctx->subCtx.t2t.rsvdAreaSize[i]; + } + else + { + if( (updatedOffset + len) > ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] ) + { + updatedLen = ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] - updatedOffset; + } + break; + } + } + *physOffset = updatedOffset; + *maxLen = updatedLen; + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT2TPollerReadBytesFromAvailableAreas(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + ndefStatus ret; + uint32_t curOffset; + uint32_t curPhyOffset; + uint32_t remainingLen; + uint32_t curRcvdLen; + uint32_t maxLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + curOffset = offset; + remainingLen = len; + if( rcvdLen != NULL ) + { + *rcvdLen = 0U; + } + while( remainingLen > 0U ) + { + (void)ndefT2TPollerSplitIntoAvailableAreas(ctx, curOffset, remainingLen, &curPhyOffset, &maxLen); + ndefT2TLogD("ndefT2TPollerReadBytesFromAvailableAreas CurOffset: %d, curPhyOffset:%d Len :%d , buf offset: %d\r\n", curOffset, curPhyOffset, maxLen, len - remainingLen); + ret = ndefT2TPollerReadBytes(ctx, curPhyOffset, maxLen, &buf[len - remainingLen], &curRcvdLen); + if(ret != ERR_NONE ) + { + return ret; + } + if( rcvdLen != NULL ) + { + *rcvdLen += curRcvdLen; + } + remainingLen -= maxLen; + curOffset += maxLen; + } + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT2TReadLField(ndefContext *ctx) +{ + ndefStatus ret; + uint32_t offset; + uint8_t data[3]; + uint16_t lenTLV; + + ctx->state = NDEF_STATE_INVALID; + offset = ctx->subCtx.t2t.offsetNdefTLV; + offset++; + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, 1, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset++; + lenTLV = data[0]; + if( lenTLV == NDEF_T2T_3_BYTES_TLV_LEN ) + { + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, 2, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset += 2U; + lenTLV = GETU16(&data[0]); + } + ctx->messageLen = lenTLV; + ctx->messageOffset = offset; + + if( ctx->messageLen == 0U ) + { + if( !(ndefT2TIsReadWriteAccessGranted(ctx)) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + /* Empty message found TS T2T v1.0 7.5.1.6 & TS T2T v1.0 7.4.2.1 */ + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + if( (ndefT2TIsReadWriteAccessGranted(ctx)) ) + { + /* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.3.1 */ + ctx->state = NDEF_STATE_READWRITE; + } + else + { + if( !(ndefT2TIsReadOnlyAccessGranted(ctx)) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + /* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.4.1 */ + ctx->state = NDEF_STATE_READONLY; + } + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev) +{ + if( (ctx == NULL) || (dev == NULL) || !ndefT2TisT2TDevice(dev) ) + { + return ERR_PARAM; + } + + (void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device)); + + ctx->type = NDEF_DEV_T2T; + ctx->state = NDEF_STATE_INVALID; + ctx->subCtx.t2t.currentSecNo = 0U; + ndefT2TInvalidateCache(ctx); + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerNdefDetect(ndefContext *ctx, ndefInfo *info) +{ + ndefStatus ret; + uint8_t data[3]; + uint32_t offset; + uint16_t lenTLV; + uint8_t typeTLV; + uint8_t nbrMajorOffsets; + uint8_t nbrMinorOffsets; + uint8_t majorOffsetSize; + uint8_t blplb; + uint32_t rsvdAreaFirstByteAddr; + uint32_t i, j; + uint32_t maxAddr; + uint32_t rsvdAreasLen; + + if( info != NULL ) + { + info->state = NDEF_STATE_INVALID; + info->majorVersion = 0U; + info->minorVersion = 0U; + info->areaLen = 0U; + info->areaAvalableSpaceLen = 0U; + info->messageLen = 0U; + } + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + ctx->state = NDEF_STATE_INVALID; + + /* Read CC TS T2T v1.0 7.5.1.1 */ + ret = ndefT2TPollerReadBytes(ctx, NDEF_T2T_CC_OFFSET, NDEF_T2T_CC_LEN, ctx->ccBuf, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + ctx->cc.t2t.magicNumber = ctx->ccBuf[NDEF_T2T_CC_0]; + ctx->cc.t2t.majorVersion = ndefMajorVersion(ctx->ccBuf[NDEF_T2T_CC_1]); + ctx->cc.t2t.minorVersion = ndefMinorVersion(ctx->ccBuf[NDEF_T2T_CC_1]); + ctx->cc.t2t.size = ctx->ccBuf[NDEF_T2T_CC_2]; + ctx->cc.t2t.readAccess = (uint8_t)(ctx->ccBuf[NDEF_T2T_CC_3] >> 4U); + ctx->cc.t2t.writeAccess = (uint8_t)(ctx->ccBuf[NDEF_T2T_CC_3] & 0xFU); + ctx->areaLen = (uint32_t)ctx->cc.t2t.size * NDEF_T2T_SIZE_DIVIDER; + maxAddr = ctx->areaLen + NDEF_T2T_AREA_OFFSET; + rsvdAreasLen = 0U; + /* Default Dyn Lock settings TS T2T v1.0 4.7.1 */ + ctx->subCtx.t2t.dynLockFirstByteAddr = ctx->areaLen + NDEF_T2T_AREA_OFFSET; + ctx->subCtx.t2t.dynLockBytesLockedPerBit = NDEF_T2T_DEF_BYTES_LCK_PER_BIT; + ctx->subCtx.t2t.dynLockNbrLockBits = (uint16_t)(ctx->areaLen - NDEF_T2T_STATIC_MEM_SIZE + NDEF_T2T_DEF_BYTES_LCK_PER_BIT -1U) / NDEF_T2T_DEF_BYTES_LCK_PER_BIT; + ctx->subCtx.t2t.dynLockNbrBytes = (ctx->subCtx.t2t.dynLockNbrLockBits + 7U) / 8U; + ctx->subCtx.t2t.nbrRsvdAreas = 0U; + /* Check version number TS T2T v1.0 7.5.1.2 */ + if( (ctx->cc.t2t.magicNumber != NDEF_T2T_MAGIC) || (ctx->cc.t2t.majorVersion > ndefMajorVersion(NDEF_T2T_VERSION_1_0)) ) + { + /* Conclude procedure TS T2T v1.0 7.5.1.2 */ + return ERR_REQUEST; + } + /* Search for NDEF message TLV TS T2T v1.0 7.5.1.3 */ + offset = NDEF_T2T_AREA_OFFSET; + while ( (offset < (NDEF_T2T_AREA_OFFSET + ctx->areaLen)) ) + { + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, 1, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + typeTLV = data[0]; + if( typeTLV == NDEF_T2T_TLV_NDEF_MESSAGE ) + { + ctx->subCtx.t2t.offsetNdefTLV = offset; + } + offset++; + if( typeTLV == NDEF_T2T_TLV_TERMINATOR ) + { + break; + } + if( typeTLV == NDEF_T2T_TLV_NULL ) + { + continue; + } + /* read TLV Len */ + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, 1, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset++; + lenTLV = data[0]; + if( lenTLV == NDEF_T2T_3_BYTES_TLV_LEN ) + { + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, 2, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset += 2U; + lenTLV = GETU16(&data[0]); + } + if( typeTLV == NDEF_T2T_TLV_LOCK_CTRL ) + { + if( lenTLV != NDEF_T2T_LOCK_CTRL_LEN ) + { + return ERR_REQUEST; + } + if( ctx->subCtx.t2t.nbrRsvdAreas >= NDEF_T2T_MAX_RSVD_AREAS ) + { + return ERR_REQUEST; + } + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, NDEF_T2T_LOCK_CTRL_LEN, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + nbrMajorOffsets = (uint8_t)(data[0] >> 4U); + nbrMinorOffsets = (uint8_t)(data[0] & 0x0FU); + ctx->subCtx.t2t.dynLockNbrLockBits = (data[1] == 0U) ? 256U : (uint16_t)data[1]; + blplb = (uint8_t)(data[2] >> 4U); + majorOffsetSize = (uint8_t)(data[2] & 0x0FU); + if ( (blplb == 0U) || (majorOffsetSize == 0U) ) + { + /* values 0h are RFU */ + return ERR_REQUEST; + } + ctx->subCtx.t2t.dynLockBytesLockedPerBit = (uint16_t)1U << blplb; + ctx->subCtx.t2t.dynLockFirstByteAddr = (nbrMajorOffsets * ( (uint32_t)1U << majorOffsetSize) ) + nbrMinorOffsets; + ctx->subCtx.t2t.dynLockNbrBytes = (ctx->subCtx.t2t.dynLockNbrLockBits + 7U) / 8U; /* TS T2T v1.0 4.9.5 */ + rsvdAreaFirstByteAddr = ctx->subCtx.t2t.dynLockFirstByteAddr; + if( rsvdAreaFirstByteAddr < maxAddr) + { + for( i = 0; i < ctx->subCtx.t2t.nbrRsvdAreas; i++ ) + { + if( rsvdAreaFirstByteAddr < ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] ) + { + for(j = i; j < ctx->subCtx.t2t.nbrRsvdAreas; j++) + { + ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j + 1U] = ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j]; + ctx->subCtx.t2t.rsvdAreaSize[j + 1U] = ctx->subCtx.t2t.rsvdAreaSize[j]; + } + break; + } + } + ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] = rsvdAreaFirstByteAddr; + ctx->subCtx.t2t.rsvdAreaSize[i] = ((ctx->subCtx.t2t.dynLockNbrBytes + 3U)/ 4U) * 4U; + if( (rsvdAreaFirstByteAddr + ctx->subCtx.t2t.rsvdAreaSize[i]) > maxAddr ) + { + ctx->subCtx.t2t.rsvdAreaSize[i] = (uint16_t)(maxAddr - ctx->subCtx.t2t.rsvdAreaSize[i]); + } + rsvdAreasLen += ctx->subCtx.t2t.rsvdAreaSize[i]; + ctx->subCtx.t2t.nbrRsvdAreas++; + } + } + if( typeTLV == NDEF_T2T_TLV_MEMORY_CTRL ) + { + if( lenTLV != NDEF_T2T_MEM_CTRL_LEN ) + { + offset += lenTLV; + continue; + } + if( ctx->subCtx.t2t.nbrRsvdAreas >= NDEF_T2T_MAX_RSVD_AREAS ) + { + return ERR_REQUEST; + } + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, offset, NDEF_T2T_MEM_CTRL_LEN, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + nbrMajorOffsets = (uint8_t)(data[0] >> 4U); + nbrMinorOffsets = (uint8_t)(data[0] & 0x0FU); + majorOffsetSize = (uint8_t)(data[2] & 0x0FU); + if( majorOffsetSize == 0U ) + { + /* value 0h is RFU */ + return ERR_REQUEST; + } + rsvdAreaFirstByteAddr = (nbrMajorOffsets * ((uint32_t)1U << majorOffsetSize)) + nbrMinorOffsets; + if( rsvdAreaFirstByteAddr < maxAddr) + { + for( i = 0; i < ctx->subCtx.t2t.nbrRsvdAreas; i++ ) + { + if( rsvdAreaFirstByteAddr < ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] ) + { + for(j = i; j < ctx->subCtx.t2t.nbrRsvdAreas; j++) + { + ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j + 1U] = ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j]; + ctx->subCtx.t2t.rsvdAreaSize[j + 1U] = ctx->subCtx.t2t.rsvdAreaSize[j]; + } + break; + } + } + ctx->subCtx.t2t.rsvdAreaFirstByteAddr[i] = rsvdAreaFirstByteAddr; + ctx->subCtx.t2t.rsvdAreaSize[i] = (data[1] == 0U) ? 256U : (uint16_t)data[1]; + if( (rsvdAreaFirstByteAddr + ctx->subCtx.t2t.rsvdAreaSize[i]) > maxAddr ) + { + ctx->subCtx.t2t.rsvdAreaSize[i] = (uint16_t)(maxAddr - ctx->subCtx.t2t.rsvdAreaSize[i]); + } + rsvdAreasLen += ctx->subCtx.t2t.rsvdAreaSize[i]; + ctx->subCtx.t2t.nbrRsvdAreas++; + } + } + /* NDEF message present TLV TS T2T v1.0 7.5.1.4 */ + if( typeTLV == NDEF_T2T_TLV_NDEF_MESSAGE ) + { + /* Read length TS T2T v1.0 7.5.1.5 */ + ctx->messageLen = lenTLV; + ctx->messageOffset = offset; + if( ctx->messageLen == 0U ) + { + if( !(ndefT2TIsReadWriteAccessGranted(ctx)) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + /* Empty message found TS T2T v1.0 7.5.1.6 & TS T2T v1.0 7.4.2.1 */ + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + if( (ndefT2TIsReadWriteAccessGranted(ctx)) ) + { + /* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.3.1 */ + ctx->state = NDEF_STATE_READWRITE; + } + else + { + if( !(ndefT2TIsReadOnlyAccessGranted(ctx)) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + /* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.4.1 */ + ctx->state = NDEF_STATE_READONLY; + } + } + ctx->areaLen -= rsvdAreasLen; + if( info != NULL ) + { + info->state = ctx->state; + info->majorVersion = ctx->cc.t2t.majorVersion; + info->minorVersion = ctx->cc.t2t.minorVersion; + info->areaLen = ctx->areaLen; + info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset; + info->messageLen = ctx->messageLen; + } + return ERR_NONE; + } + offset += lenTLV; + } + return ERR_REQUEST; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + /* TS T2T v1.0 7.5.2.1: T2T NDEF Detect should have been called at least once before NDEF read procedure */ + + if( ! single ) + { + ndefT2TInvalidateCache(ctx); + ret = ndefT2TReadLField(ctx); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + } + + /* TS T2T v1.0 7.5.2.3: check presence of NDEF message */ + if ( ctx->state <= NDEF_STATE_INITIALIZED ) + { + /* Conclude procedure TS T4T v1.0 7.2.2.2 */ + return ERR_WRONG_STATE; + } + + if( ctx->messageLen > bufLen ) + { + return ERR_NOMEM; + } + + ret = ndefT2TPollerReadBytesFromAvailableAreas(ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + } + return ret; +} + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +static ndefStatus ndefT2TPollerWriteBlock(ndefContext *ctx, uint16_t blockAddr, const uint8_t *buf) +{ + ReturnCode ret; + uint8_t secNo; + uint8_t blNo; + uint32_t retry; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + secNo = (uint8_t)(blockAddr >> 8U); + blNo = (uint8_t)blockAddr; + + if( secNo != ctx->subCtx.t2t.currentSecNo ) + { + ret = rfalT2TPollerSectorSelect(secNo); + if( ret != RFAL_ERR_NONE ) + { + return ERR_REQUEST; + } + ctx->subCtx.t2t.currentSecNo = secNo; + } + + retry = NDEF_T2T_N_RETRY_ERROR; + do + { + ret = rfalT2TPollerWrite(blNo, buf); + } + while ( (retry-- != 0U) && rfalT2TIsTransmissionError(ret) ); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator) +{ + ndefStatus ret; + uint32_t lvOffset = offset; + uint32_t lvLen = len; + const uint8_t* lvBuf = buf; + uint16_t blockAddr; + uint8_t byteNo; + uint8_t le; + uint8_t tempBuf[NDEF_T2T_READ_RESP_SIZE]; + bool lvWriteTerminator = writeTerminator; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (lvLen == 0U) ) + { + return ERR_PARAM; + } + + ndefT2TInvalidateCache(ctx); + + do + { + blockAddr = (uint16_t)(lvOffset / NDEF_T2T_BLOCK_SIZE); + byteNo = (uint8_t)(lvOffset % NDEF_T2T_BLOCK_SIZE); + le = (lvLen < NDEF_T2T_BLOCK_SIZE) ? (uint8_t)lvLen : (uint8_t)NDEF_T2T_BLOCK_SIZE; + if( (byteNo != 0U ) || (lvLen < NDEF_T2T_BLOCK_SIZE) ) + { + if( (byteNo != 0U) || !pad ) + { + ret = ndefT2TPollerReadBlock(ctx, blockAddr, tempBuf); + if( ret != ERR_NONE ) + { + return ret; + } + } + if( (byteNo + lvLen) < NDEF_T2T_BLOCK_SIZE ) + { + if( pad ) + { + (void)ST_MEMSET(&tempBuf[byteNo + lvLen], 0x00, NDEF_T2T_BLOCK_SIZE - (byteNo + lvLen)); + } + if( lvWriteTerminator ) + { + tempBuf[byteNo + lvLen] = NDEF_T2T_TLV_TERMINATOR; + lvWriteTerminator = false; + } + } + if( (NDEF_T2T_BLOCK_SIZE - byteNo) < le ) + { + le = NDEF_T2T_BLOCK_SIZE - byteNo; + } + if( le > 0U ) + { + (void)ST_MEMCPY(&tempBuf[byteNo], lvBuf, le); + } + ret = ndefT2TPollerWriteBlock(ctx, blockAddr, tempBuf); + if( ret != ERR_NONE ) + { + return ret; + } + } + else + { + ret = ndefT2TPollerWriteBlock(ctx, blockAddr, lvBuf); + if( ret != ERR_NONE ) + { + return ret; + } + } + lvBuf = &lvBuf[le]; + lvOffset += le; + lvLen -= le; + + } while( lvLen != 0U ); + if( lvWriteTerminator ) + { + blockAddr++; + (void)ST_MEMSET(tempBuf, 0x00, NDEF_T2T_BLOCK_SIZE); + tempBuf[0] = NDEF_T2T_TLV_TERMINATOR; + (void)ndefT2TPollerWriteBlock(ctx, blockAddr, tempBuf); + } + + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT2TPollerWriteBytesToAvailableAreas(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator) +{ + ndefStatus ret; + uint32_t curOffset; + uint32_t curPhyOffset; + uint32_t remainingLen; + uint32_t maxLen = 0U; + uint32_t maxLenTerm = 0U; + bool term = false; + bool lvWriteTerminator = writeTerminator; + uint8_t termBuf[1]; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + curOffset = offset; + remainingLen = len; + + while( remainingLen > 0U ) + { + (void)ndefT2TPollerSplitIntoAvailableAreas(ctx, curOffset, remainingLen, &curPhyOffset, &maxLen); + if( (remainingLen == maxLen) && writeTerminator) /* last part */ + { + (void)ndefT2TPollerSplitIntoAvailableAreas(ctx, curOffset, remainingLen + 1U, &curPhyOffset, &maxLenTerm); + if( (remainingLen + 1U) == maxLenTerm ) /* check enough room for terminator in that area */ + { + term = true; + lvWriteTerminator = false; + } + } + ret = ndefT2TPollerWriteBytes(ctx, curPhyOffset, &buf[len - remainingLen], maxLen, (remainingLen == maxLen) && pad, term); + ndefT2TLogD("ndefT2TPollerWriteBytesToAvailableAreas CurOffset: %d, curPhyOffset: %d, Len :%d , buf offset: %d\r\n", curOffset, curPhyOffset, maxLen, len - remainingLen); + if(ret != ERR_NONE ) + { + return ret; + } + remainingLen -= maxLen; + curOffset += maxLen; + } + if( lvWriteTerminator ) + { + (void)ndefT2TPollerSplitIntoAvailableAreas(ctx, curOffset, 1U, &curPhyOffset, &maxLen); + termBuf[0] = NDEF_T2T_TLV_TERMINATOR; + (void)ndefT2TPollerWriteBytes(ctx, curPhyOffset, termBuf, 1U, pad, false); + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator) +{ + ndefStatus ret; + uint8_t buf[NDEF_T2T_BLOCK_SIZE]; + uint8_t dataIt; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + if( writeTerminator && (rawMessageLen != 0U) && ((ctx->messageOffset + rawMessageLen) < (ctx->areaLen + NDEF_T2T_AREA_OFFSET)) ) + { + /* Write Terminator TLV */ + dataIt = 0U; + buf[dataIt] = NDEF_T2T_TLV_TERMINATOR; + dataIt++; + ret = ndefT2TPollerWriteBytesToAvailableAreas(ctx, ctx->messageOffset + rawMessageLen, buf, dataIt, true, false); + if( ret != ERR_NONE ) + { + return ret; + } + } + + /* Prepare L buffer content - Don't need to write T byte so skip it */ + dataIt = 0U; + if( rawMessageLen <= NDEF_SHORT_VFIELD_MAX_LEN ) + { + buf[dataIt] = (uint8_t) rawMessageLen; + dataIt++; + if( (rawMessageLen == 0U) && writeTerminator ) + { + buf[dataIt] = NDEF_T2T_TLV_TERMINATOR; + dataIt++; + } + } + else + { + buf[dataIt] = (uint8_t)(NDEF_SHORT_VFIELD_MAX_LEN + 1U); + dataIt++; + buf[dataIt] = (uint8_t) (rawMessageLen >> 8U); + dataIt++; + buf[dataIt] = (uint8_t) rawMessageLen; + dataIt++; + } + + ret = ndefT2TPollerWriteBytesToAvailableAreas(ctx, ctx->subCtx.t2t.offsetNdefTLV + NDEF_T2T_TLV_T_LEN, buf, dataIt, writeTerminator && (rawMessageLen == 0U), false); + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || ((buf == NULL) && (bufLen != 0U)) ) + { + return ERR_PARAM; + } + + /* TS T2T v1.0 7.5.3.1/2: T4T NDEF Detect should have been called before NDEF write procedure */ + /* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF Write procedure*/ + + /* TS T2T v1.0 7.5.3.3: check write access condition */ + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + /* Conclude procedure */ + return ERR_WRONG_STATE; + } + + /* TS T2T v1.0 7.5.3.3: verify available space */ + ret = ndefT2TPollerCheckAvailableSpace(ctx, bufLen); + if( ret != ERR_NONE ) + { + /* Conclude procedures */ + return ERR_PARAM; + } + + /* TS T2T v1.0 7.5.3.4: reset L_Field to 0 */ + /* and update ctx->messageOffset according to L-field len */ + ret = ndefT2TPollerBeginWriteMessage(ctx, bufLen); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + /* Conclude procedure */ + return ret; + } + + if( bufLen != 0U ) + { + /* TS T2T v1.0 7.5.3.5: write new NDEF message */ + ret = ndefT2TPollerWriteBytesToAvailableAreas(ctx, ctx->messageOffset, buf, bufLen, true, ndefT2TPollerCheckAvailableSpace(ctx, bufLen + 1U) == ERR_NONE); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + + /* TS T2T v1.0 7.5.3.6 & 7.5.3.7: update L_Field and write Terminator TLV */ + ret = ndefT2TPollerEndWriteMessage(ctx, bufLen, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + } + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options) +{ + ndefStatus ret; + uint8_t dataIt; + static const uint8_t emptyNdef[] = {NDEF_T2T_TLV_NDEF_MESSAGE, 0x00U, NDEF_T2T_TLV_TERMINATOR, 0x00U}; + + NO_WARNING(options); + + /* Check parameters, ensure cc is provided */ + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) || (cc == NULL) ) + { + return ERR_PARAM; + } + + /* + * Read CC area + */ + ret = ndefT2TPollerReadBytes(ctx, NDEF_T2T_CC_OFFSET, NDEF_T2T_CC_LEN, ctx->ccBuf, NULL); + if( ret != ERR_NONE ) + { + return ret; + } + + ndefT2TInvalidateCache(ctx); + + /* + * Write CC only in case of virgin CC area + */ + if( (ctx->ccBuf[NDEF_T2T_CC_0] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_1] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_2] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_3] == 0U) ) + { + dataIt = 0U; + ctx->ccBuf[dataIt] = cc->t2t.magicNumber; + dataIt++; + ctx->ccBuf[dataIt] = (uint8_t)(cc->t2t.majorVersion << 4U) | cc->t2t.minorVersion; + dataIt++; + ctx->ccBuf[dataIt] = cc->t2t.size; + dataIt++; + ctx->ccBuf[dataIt] = (uint8_t)(cc->t2t.readAccess << 4U) | cc->t2t.writeAccess; + dataIt++; + ret = ndefT2TPollerWriteBlock(ctx, NDEF_T2T_CC_OFFSET/NDEF_T2T_BLOCK_SIZE, ctx->ccBuf); + if( ret != ERR_NONE ) + { + return ret; + } + } + + /* + * Write NDEF place holder + */ + ret = ndefT2TPollerWriteBlock(ctx, NDEF_T2T_AREA_OFFSET/NDEF_T2T_BLOCK_SIZE, emptyNdef); + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerCheckPresence(ndefContext *ctx) +{ + ndefStatus ret; + uint16_t blockAddr; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + blockAddr = 0U; + ret = ndefT2TPollerReadBlock(ctx, blockAddr, ctx->subCtx.t2t.cacheBuf); + if( ret != ERR_NONE ) + { + ndefT2TInvalidateCache(ctx); + return ret; + } + ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen) +{ + uint32_t lLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + if ( ctx->state == NDEF_STATE_INVALID ) + { + return ERR_WRONG_STATE; + } + + lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T2T_TLV_L_3_BYTES_LEN : NDEF_T2T_TLV_L_1_BYTES_LEN; + + if( (messageLen + ctx->subCtx.t2t.offsetNdefTLV + NDEF_T2T_TLV_T_LEN + lLen) > (ctx->areaLen + NDEF_T2T_AREA_OFFSET) ) + { + return ERR_NOMEM; + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + ndefStatus ret; + uint32_t lLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + /* TS T2T v1.0 7.5.3.4: reset L_Field to 0 */ + ret = ndefT2TPollerWriteRawMessageLen(ctx, 0U, true); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + + lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T2T_TLV_L_3_BYTES_LEN : NDEF_T2T_TLV_L_1_BYTES_LEN; + ctx->messageOffset = ctx->subCtx.t2t.offsetNdefTLV; + ctx->messageOffset += NDEF_T2T_TLV_T_LEN; /* T Len */ + ctx->messageOffset += lLen; /* L Len */ + + ctx->state = NDEF_STATE_INITIALIZED; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + + /* TS T2T v1.0 7.5.3.6 & 7.5.3.7: update L_Field and write Terminator TLV */ + ret = ndefT2TPollerWriteRawMessageLen(ctx, messageLen, writeTerminator); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + ctx->messageLen = messageLen; + ctx->state = (ctx->messageLen == 0U) ? NDEF_STATE_INITIALIZED : NDEF_STATE_READWRITE; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT2TPollerSetReadOnly(ndefContext *ctx) +{ + ndefStatus ret; + uint32_t nbrDynLockBits; + uint32_t nbrDynLockBitsInLastByte; + uint8_t dynLockBits[NDEF_T2T_DYN_LOCK_BYTES_MAX]; + uint32_t i, j; + uint32_t maxAddr; + uint32_t addr; + uint32_t bitPos; + uint32_t DynLockByteIndex; + + static const uint8_t staticBits[2] = {0xFF, 0xFF}; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T2T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_READWRITE ) + { + return ERR_WRONG_STATE; + } + + /* TS T2T v1.0 7.6.5.1: set the Access Conditions for Write (in the lower nibble) of CC_3 to Fh */ + ctx->cc.t2t.writeAccess = NDEF_T2T_WR_ACCESS_NONE; + ctx->ccBuf[NDEF_T2T_CC_3] |= ctx->cc.t2t.writeAccess; + ret = ndefT2TPollerWriteBlock(ctx, NDEF_T2T_CC_OFFSET/NDEF_T2T_BLOCK_SIZE, ctx->ccBuf); + if( ret != ERR_NONE ) + { + return ret; + } + /* TS T2T v1.0 7.6.5.1: set all Static Lock bits to 1b */ + ret = ndefT2TPollerWriteBytes(ctx, NDEF_T2T_STATLOCK_OFFSET, staticBits, sizeof(staticBits), false, false); + if( ret != ERR_NONE ) + { + return ret; + } + + /* TS T2T v1.0 7.6.5.1: set all Dynamic Lock bits that are associated with the TLVs_Area to 1b */ + if( ctx->areaLen > NDEF_T2T_STATIC_MEM_SIZE ) + { + nbrDynLockBits = (((uint32_t)ctx->cc.t2t.size * NDEF_T2T_SIZE_DIVIDER) - NDEF_T2T_STATIC_MEM_SIZE + ctx->subCtx.t2t.dynLockBytesLockedPerBit - 1U) / ctx->subCtx.t2t.dynLockBytesLockedPerBit; + for( i = 0; i < (nbrDynLockBits / 8U); i++ ) + { + dynLockBits[i] = 0xFFU; + } + nbrDynLockBitsInLastByte = nbrDynLockBits % 8U; + if( nbrDynLockBitsInLastByte != 0U ) + { + dynLockBits[i] = (1U << nbrDynLockBitsInLastByte) -1U; + i++; + } + + maxAddr = ((uint32_t)ctx->cc.t2t.size * NDEF_T2T_SIZE_DIVIDER) + NDEF_T2T_AREA_OFFSET; + /* clear dynLock bits for rsvd Areas */ + for( j = 0; (j < ctx->subCtx.t2t.nbrRsvdAreas) && (ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j] < maxAddr); j++ ) + { + for( addr = ((ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j] + ctx->subCtx.t2t.dynLockBytesLockedPerBit - 1U) / ctx->subCtx.t2t.dynLockBytesLockedPerBit) * ctx->subCtx.t2t.dynLockBytesLockedPerBit; + (addr < (ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j] + ctx->subCtx.t2t.rsvdAreaSize[j])) && ((addr + ctx->subCtx.t2t.dynLockBytesLockedPerBit)< (ctx->subCtx.t2t.rsvdAreaFirstByteAddr[j] + ctx->subCtx.t2t.rsvdAreaSize[j])); + addr += ctx->subCtx.t2t.dynLockBytesLockedPerBit) + { + bitPos = (addr - (NDEF_T2T_STATIC_MEM_SIZE + NDEF_T2T_AREA_OFFSET)) / ctx->subCtx.t2t.dynLockBytesLockedPerBit; + DynLockByteIndex = bitPos / 8U; + if( DynLockByteIndex < NDEF_T2T_DYN_LOCK_BYTES_MAX ) + { + dynLockBits[DynLockByteIndex] &= ~(1U << (bitPos % 8U)); + } + } + } + + ret = ndefT2TPollerWriteBytes(ctx, ctx->subCtx.t2t.dynLockFirstByteAddr, dynLockBits, i, false, false); + if( ret != ERR_NONE ) + { + return ret; + } + } + + return ERR_NONE; +} + +#endif /* NDEF_FEATURE_FULL_API */ + +#endif /* NDEF_FEATURE_T2T */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_t3t.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_t3t.c new file mode 100644 index 0000000..bc787e5 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_t3t.c @@ -0,0 +1,973 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T3T + * + * This module provides an interface to perform as a NFC Reader/Writer + * to handle a Type 3 Tag T3T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" +#include "ndef_t3t.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef NDEF_FEATURE_T3T + #error " NDEF: Module configuration missing. Please enable/disable T3T module by setting: NDEF_FEATURE_T3T" +#endif + +#if NDEF_FEATURE_T3T + +#ifndef NDEF_FEATURE_FULL_API + #error " NDEF: Module configuration missing. Please enable/disable Full API by setting: NDEF_FEATURE_FULL_API" +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ +#define NDEF_T3T_MAX_DEVICE 1U /*!< T3T maximum number of device for detection */ +#define NDEF_T3T_SYSTEMCODE 0x12FCU /*!< SENSF_RES System Code for T3T TS T3T 1.0 7.1.1.1 */ +#define NDEF_T3T_WRITEFLAG_ON 0xFU /*!< WriteFlag ON value TS T3T 1.0 7.2.2.16 */ +#define NDEF_T3T_WRITEFLAG_OFF 0x0U /*!< WriteFlag OFF value TS T3T 1.0 7.2.2.16 */ +#define NDEF_T3T_AREA_OFFSET 16U /*!< T3T Area starts at block #1 */ +#define NDEF_T3T_BLOCKLEN 16U /*!< T3T block length is always 16 */ +#define NDEF_T3T_FLAG_RW 1U /*!< T3T read/write flag value */ +#define NDEF_T3T_FLAG_RO 0U /*!< T3T read only flag value */ +#define NDEF_T3T_SENSFRES_NFCID2 2U /*!< T3T offset of UID in SENSFRES struct */ +#define NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN 0xEU /*!< T3T checksum length for attribute info to compute */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION 0x0U /*!< T3T attribute info offset of version */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_NBR 1U /*!< T3T attribute info offset of number of read */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_NBW 2U /*!< T3T attribute info offset of number of write */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB 3U /*!< T3T attribute info offset of MAXB */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_W 9U /*!< T3T attribute info offset of Write flag */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_RW 10U /*!< T3T attribute info offset of Read/Write flag */ +#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN 11U /*!< T3T attribute info offset of LN field */ +#define NDEF_T3T_ATTRIB_INFO_VERSION_1_0 0x10U /*!< T3T attribute info full version number */ +#define NDEF_T3T_ATTRIB_INFO_BLOCK_NB 0U /*!< T3T attribute info block number */ +#define NDEF_T3T_BLOCKNB_CONF 0x80U /*!< T3T TxRx config value for Read/Write block */ +#define NDEF_T3T_CHECK_NB_BLOCKS_LEN 1U /*!< T3T Length of the Nb of blocks in the CHECK reply */ + + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define ndefT3TisT3TDevice(device) ((device)->type == RFAL_NFC_LISTEN_TYPE_NFCF) +#define ndefT3TIsWriteFlagON(writeFlag) ((writeFlag) == NDEF_T3T_WRITEFLAG_ON) + +#define ndefT3TLogD(...) /*!< Macro for the debug log method */ + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static ndefStatus ndefT3TPollerReadBlocks (ndefContext *ctx, uint16_t blockNum, uint8_t nbBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen); +static ndefStatus ndefT3TPollerReadAttributeInformationBlock (ndefContext *ctx); + +#if NDEF_FEATURE_FULL_API +static ndefStatus ndefT3TPollerWriteBlocks (ndefContext *ctx, uint16_t blockNum, uint8_t nbBlocks, const uint8_t *dataBlocks); +static ndefStatus ndefT3TPollerWriteAttributeInformationBlock(ndefContext *ctx); +#endif /* NDEF_FEATURE_FULL_API */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +static ndefStatus ndefT3TPollerReadBlocks(ndefContext *ctx, uint16_t blockNum, uint8_t nbBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen) +{ + ReturnCode ret; + uint16_t requestedDataSize; + rfalNfcfServBlockListParam servBlock; + rfalNfcfBlockListElem* listBlocks; + uint8_t index; + uint16_t rcvdLen = 0U; + rfalNfcfServ serviceCodeLst = 0x000BU; /* serviceCodeLst */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + requestedDataSize = (uint16_t)nbBlocks * NDEF_T3T_BLOCK_SIZE; + if( rxBufLen < requestedDataSize ) + { + return ERR_PARAM; + } + + listBlocks = ctx->subCtx.t3t.listBlocks; + + for (index = 0U; index < nbBlocks; index++ ) + { + /* Write each block number (16 bits per block address) */ + listBlocks[index].blockNum = (uint16_t)( blockNum + (uint16_t) index); + listBlocks[index].conf = ((listBlocks[index].blockNum > 0xFFU) ? 0U : RFAL_NFCF_BLOCKLISTELEM_LEN_BIT); + } + + servBlock.numServ = 1U; + servBlock.servList = &serviceCodeLst; + servBlock.numBlock = nbBlocks; + servBlock.blockList = listBlocks; + + ret = rfalNfcfPollerCheck(ctx->subCtx.t3t.NFCID2, &servBlock, ctx->subCtx.t3t.rxbuf, (uint16_t)sizeof(ctx->subCtx.t3t.rxbuf), &rcvdLen); + if (ret != RFAL_ERR_NONE) + { + return ERR_REQUEST; + } + if( rcvdLen != (uint16_t)(NDEF_T3T_CHECK_NB_BLOCKS_LEN + requestedDataSize) ) + { + return ERR_REQUEST; + } + if( requestedDataSize > 0U ) + { + (void)ST_MEMMOVE( rxBuf, &ctx->subCtx.t3t.rxbuf[NDEF_T3T_CHECK_NB_BLOCKS_LEN], requestedDataSize ); + if (rcvLen != NULL) + { + *rcvLen = requestedDataSize; + } + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + ndefStatus res = ERR_NONE; + uint16_t nbRead = 0U; + uint32_t currentLen = len; + uint32_t lvRcvLen = 0U; + const uint16_t blockLen = (uint16_t) NDEF_T3T_BLOCKLEN; + uint16_t startBlock = (uint16_t) (offset / blockLen); + uint16_t startAddr = (uint16_t) (startBlock * blockLen); + uint16_t startOffset= (uint16_t) (offset - (uint32_t) startAddr); + uint16_t nbBlocks = (uint16_t) NDEF_T3T_MAX_NB_BLOCKS; + + ndefT3TLogD("ndefT3TPollerReadBytes offset: 0x%8.8x, Len %d\r\n", offset, len); + ndefT3TLogD("ndefT3TPollerReadBytes currentLen: %d, startBlock %d\r\n", currentLen, startBlock); + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) || (len == 0U) ) + { + return ERR_PARAM; + } + if (ctx->state != NDEF_STATE_INVALID) + { + nbBlocks = MIN(ctx->cc.t3t.nbR, NDEF_T3T_MAX_NB_BLOCKS); + } + + if ( startOffset != 0U ) + { + /* Unaligned read, need to use a tmp buffer */ + res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */ , ctx->subCtx.t3t.rxbuf, blockLen, &nbRead); + if (res != ERR_NONE) + { + /* Check result */ + return res; + } + if (nbRead != NDEF_T3T_BLOCKLEN) + { + /* Check length */ + return ERR_MEM_CORRUPT; + } + + nbRead = (uint16_t) (nbRead - (uint16_t)startOffset); + if ((uint32_t) nbRead > currentLen) + { + nbRead = (uint16_t) currentLen; + } + if (nbRead > 0U) + { + (void)ST_MEMCPY(buf, &ctx->subCtx.t3t.rxbuf[offset], (uint32_t)nbRead); + } + lvRcvLen += (uint32_t) nbRead; + currentLen -= (uint32_t) nbRead; + startBlock++; + ndefT3TLogD("ndefT3TPollerReadBytes currentLen: %d, startBlock %d\r\n", currentLen, startBlock); + } + + while ( currentLen >= (uint32_t)blockLen ) + { + if ( currentLen < ((uint32_t)blockLen * nbBlocks) ) + { + /* Reduce the nb of blocks to read */ + nbBlocks = (uint16_t) (currentLen / blockLen); + } + res = ndefT3TPollerReadBlocks(ctx, startBlock, (uint8_t)nbBlocks, ctx->subCtx.t3t.rxbuf, blockLen * nbBlocks, &nbRead); + if (res != ERR_NONE) + { + /* Check result */ + return res; + } + if (nbRead != (blockLen * nbBlocks)) + { + /* Check length */ + return ERR_MEM_CORRUPT; + } + (void)ST_MEMCPY(&buf[lvRcvLen], ctx->subCtx.t3t.rxbuf, (uint32_t)currentLen); + lvRcvLen += nbRead; + currentLen -= nbRead; + startBlock += nbBlocks; + ndefT3TLogD("ndefT3TPollerReadBytes currentLen: %d, startBlock %d\r\n", currentLen, startBlock); + } + + if( currentLen > 0U ) + { + /* Unaligned read, need to use a tmp buffer */ + res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */, ctx->subCtx.t3t.rxbuf, blockLen, &nbRead); + if (res != ERR_NONE) + { + /* Check result */ + return res; + } + if (nbRead != NDEF_T3T_BLOCKLEN) + { + /* Check length */ + return ERR_MEM_CORRUPT; + } + /* currentLen > 0U */ + (void)ST_MEMCPY(&buf[lvRcvLen], ctx->subCtx.t3t.rxbuf, (uint32_t)currentLen); + lvRcvLen += (uint32_t) currentLen; + currentLen -= (uint32_t) currentLen; + } + + if( currentLen != 0U ) + { + res = ERR_SYSTEM; + } + if( rcvdLen != NULL ) + { + *rcvdLen = lvRcvLen; + } + return res; +} + +/*******************************************************************************/ +static ndefStatus ndefT3TPollerReadAttributeInformationBlock(ndefContext *ctx) +{ + /* Follow 7.4.1 NDEF Detection Procedure */ + ndefStatus retcode; + uint8_t* rxbuf; + uint16_t checksum_received; + uint16_t checksum_computed = 0U; + uint16_t rcvLen = 0U; + uint8_t i; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + rxbuf = ctx->ccBuf; + retcode = ndefT3TPollerReadBlocks( ctx, NDEF_T3T_ATTRIB_INFO_BLOCK_NB, 1U /* One block */, rxbuf, NDEF_T3T_BLOCK_SIZE, &rcvLen ); + if ( (retcode != RFAL_ERR_NONE) && (rcvLen != NDEF_T3T_BLOCK_SIZE) ) + { + return retcode; + } + /* Now compute checksum */ + for(i = 0U; i < NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN; i++) + { + checksum_computed += (uint16_t) rxbuf[i]; + } + checksum_received = ((uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN] << 8U) + (uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN+ 1U]; + if (checksum_received != checksum_computed) + { + return ERR_REQUEST; + } + + /* Now copy the attribute struct */ + ctx->cc.t3t.majorVersion = ( rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION] >> 4U); + ctx->cc.t3t.minorVersion = ( rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION] & 0xFU); + ctx->cc.t3t.nbR = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_NBR]; + ctx->cc.t3t.nbW = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_NBW]; + ctx->cc.t3t.nMaxB = ((uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB] << 8U) + (uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB + 1U]; + ctx->cc.t3t.writeFlag = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_W]; + ctx->cc.t3t.rwFlag = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_RW]; + ctx->cc.t3t.Ln = ((uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 0U] << 0x10U) + | ((uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 1U] << 0x8U) + | (uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 2U]; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev) +{ + if( (ctx == NULL) || (dev == NULL) || !ndefT3TisT3TDevice(dev) ) + { + return ERR_PARAM; + } + + (void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device)); + + ST_MEMCPY(&ctx->subCtx.t3t.NFCID2, dev->dev.nfcf.sensfRes.NFCID2, sizeof(ctx->subCtx.t3t.NFCID2)); + + ctx->type = NDEF_DEV_T3T; + ctx->state = NDEF_STATE_INVALID; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerNdefDetect(ndefContext *ctx, ndefInfo *info) +{ + ndefStatus err; + ReturnCode retcode; + rfalFeliCaPollRes pollRes[NDEF_T3T_MAX_DEVICE]; + uint8_t devCnt = NDEF_T3T_MAX_DEVICE; + uint8_t collisions = 0U; + + if( info != NULL ) + { + info->state = NDEF_STATE_INVALID; + info->majorVersion = 0U; + info->minorVersion = 0U; + info->areaLen = 0U; + info->areaAvalableSpaceLen = 0U; + info->messageLen = 0U; + } + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + ctx->state = NDEF_STATE_INVALID; + + /* TS T3T v1.0 7.4.1.1 the Reader/Writer SHALL send a SENSF_REQ Command with System Code set to 12FCh. */ + retcode = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_NO_REQUEST, pollRes, &devCnt, &collisions ); + if( retcode != RFAL_ERR_NONE ) + { + /* TS T3T v1.0 7.4.1.2 Conclude procedure. */ + return ERR_REQUEST; + } + + /* Check if UID of the first card is the same */ + if( ST_BYTECMP(&(pollRes[0U][NDEF_T3T_SENSFRES_NFCID2]), ctx->subCtx.t3t.NFCID2, RFAL_NFCF_NFCID2_LEN ) != 0 ) + { + return ERR_REQUEST; /* Wrong UID */ + } + + /* TS T3T v1.0 7.4.1.3 The Reader/Writer SHALL read the Attribute Information Block using the CHECK Command. */ + /* TS T3T v1.0 7.4.1.4 The Reader/Writer SHALL verify the value of Checksum of the Attribute Information Block. */ + err = ndefT3TPollerReadAttributeInformationBlock(ctx); + if( err != ERR_NONE ) + { + return err; + } + + /* TS T3T v1.0 7.4.1.6 The Reader/Writer SHALL check if it supports the NDEF mapping version number based on the rules given in Section 7.3. */ + if( ctx->cc.t3t.majorVersion != ndefMajorVersion(NDEF_T3T_ATTRIB_INFO_VERSION_1_0) ) + { + return ERR_REQUEST; + } + + ctx->messageLen = ctx->cc.t3t.Ln; + ctx->messageOffset = NDEF_T3T_AREA_OFFSET; + ctx->areaLen = (uint32_t)ctx->cc.t3t.nMaxB * NDEF_T3T_BLOCK_SIZE; + if( ctx->messageLen == 0U ) + { + ctx->state = NDEF_STATE_INITIALIZED; + } + else /* ctx->messageLen > 0 */ + { + if( ctx->cc.t3t.rwFlag == NDEF_T3T_FLAG_RW ) + { + ctx->state = NDEF_STATE_READWRITE; + } + else /* NDEF_T3T_FLAG_RO or RFU */ + { + /* TS T3T v1.1 7.2.2.30 The Reader/Writer SHALL interpret an RFU value as Read-Only */ + ctx->state = NDEF_STATE_READONLY; + } + } + + if( info != NULL ) + { + info->state = ctx->state; + info->majorVersion = ctx->cc.t3t.majorVersion; + info->minorVersion = ctx->cc.t3t.minorVersion; + info->areaLen = ctx->areaLen; + info->areaAvalableSpaceLen = ctx->areaLen; + info->messageLen = ctx->messageLen; + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) || (buf == NULL) ) + { + return ERR_PARAM; + } + ndefT3TLogD("ndefT3TPollerReadRawMessage messageLen: %d\r\n", ctx->messageLen); + + /* TS T3T v1.0 7.4.2: This procedure assumes that the Reader/Writer has successfully performed the NDEF detection procedure at least once. */ + + if( !single ) + { + ctx->state = NDEF_STATE_INVALID; + ret = ndefT3TPollerReadAttributeInformationBlock(ctx); + if( ret != ERR_NONE ) + { + return ret; + } + ctx->messageLen = ctx->cc.t3t.Ln; + if( ctx->messageLen == 0U ) + { + if( ctx->cc.t3t.rwFlag != NDEF_T3T_FLAG_RW ) + { + return ERR_WRONG_STATE; + } + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + if( ctx->cc.t3t.rwFlag == NDEF_T3T_FLAG_RW ) + { + ctx->state = NDEF_STATE_READWRITE; + } + else /* NDEF_T3T_FLAG_RO or RFU */ + { + /* TS T3T v1.1 7.2.2.30 The Reader/Writer SHALL interpret an RFU value as Read-Only */ + ctx->state = NDEF_STATE_READONLY; + } + } + } + + if ( ctx->state <= NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + /* TS T3T v1.0 7.4.2.1: If the WriteFlag remembered during the NDEF detection procedure is set to ON, the NDEF data may be inconsistent ...*/ + if( ndefT3TIsWriteFlagON(ctx->cc.t3t.writeFlag) ) + { + /* TS T3T v1.0 7.4.2.1: ... the Reader/Writer SHALL conclude the NDEF read procedure */ + return ERR_WRONG_STATE; + } + + if( ctx->messageLen > bufLen ) + { + return ERR_NOMEM; + } + + /* TS T3T v1.0 7.4.2.2: Read NDEF data */ + ret = ndefT3TPollerReadBytes( ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen ); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + } + return ret; +} + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +static ndefStatus ndefT3TPollerWriteBlocks(ndefContext *ctx, uint16_t blockNum, uint8_t nbBlocks, const uint8_t* dataBlocks) +{ + ReturnCode ret; + rfalNfcfServBlockListParam servBlock; + rfalNfcfBlockListElem* listBlocks; + uint8_t index; + rfalNfcfServ serviceCodeLst = 0x0009U; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + listBlocks = ctx->subCtx.t3t.listBlocks; + + for (index = 0U; index < nbBlocks; index++) + { + /* Write each block number (16 bits per block address) */ + listBlocks[index].blockNum = (uint16_t)( blockNum + (uint16_t) index); + listBlocks[index].conf = ((listBlocks[index].blockNum > 0xFFU) ? 0U : RFAL_NFCF_BLOCKLISTELEM_LEN_BIT); + } + servBlock.numServ = 1U; + servBlock.servList = &serviceCodeLst; + servBlock.numBlock = nbBlocks; + servBlock.blockList = listBlocks; + + ret = rfalNfcfPollerUpdate( ctx->subCtx.t3t.NFCID2, &servBlock, ctx->subCtx.t3t.txbuf, (uint16_t)sizeof(ctx->subCtx.t3t.txbuf), dataBlocks, ctx->subCtx.t3t.rxbuf, (uint16_t)sizeof(ctx->subCtx.t3t.rxbuf)); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator) +{ + ndefStatus res; + uint16_t nbRead; + uint16_t nbWrite; + uint32_t currentLen = len; + uint32_t txtLen = 0U; + const uint16_t blockLen = (uint16_t) NDEF_T3T_BLOCKLEN; + uint16_t nbBlocks = (uint16_t) NDEF_T3T_MAX_NB_BLOCKS; + uint16_t startBlock = (uint16_t) (offset / blockLen); + uint16_t startAddr = (uint16_t) (startBlock * blockLen); + uint16_t startOffset= (uint16_t) (offset - (uint32_t) startAddr); + uint8_t tmpBuf[NDEF_T3T_BLOCKLEN]; + + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) || (len == 0U) ) + { + return ERR_PARAM; + } + if (ctx->state != NDEF_STATE_INVALID) + { + nbBlocks = MIN(ctx->cc.t3t.nbW, NDEF_T3T_MAX_NB_BLOCKS); + } + + if ( startOffset != 0U ) + { + /* Unaligned write, need to use a tmp buffer */ + res = ndefT3TPollerReadBlocks(ctx, startBlock, 1, tmpBuf, blockLen, &nbRead); + if (res != ERR_NONE) + { + /* Check result */ + return res; + } + if (nbRead != blockLen) + { + /* Check length */ + return ERR_REQUEST; + } + /* Fill the rest of the buffer with user data */ + nbWrite = NDEF_T3T_BLOCKLEN - startOffset; + if (nbWrite > len) + { + nbWrite = (uint16_t) len; + } + (void)ST_MEMCPY(&tmpBuf[startOffset], buf, nbWrite); + if ( pad ) + { + startOffset += nbWrite; + nbWrite = NDEF_T3T_BLOCKLEN - startOffset; + if( nbWrite > 0U ) + { + (void)ST_MEMSET(&tmpBuf[startOffset], 0x00, nbWrite); + } + } + res = ndefT3TPollerWriteBlocks(ctx, startBlock, 1U /* One block */, tmpBuf); + if (res != ERR_NONE) + { + return res; + } + txtLen += (uint32_t) nbWrite; + currentLen -= (uint32_t) nbWrite; + startBlock++; + } + while ( currentLen >= (uint32_t)blockLen ) + { + if ( currentLen < ((uint32_t)blockLen * nbBlocks) ) + { + /* Reduce the nb of blocks to read */ + nbBlocks = (uint16_t) (currentLen / blockLen); + } + nbWrite = blockLen * nbBlocks; + res = ndefT3TPollerWriteBlocks(ctx, startBlock, (uint8_t) nbBlocks, &buf[txtLen]); + if (res != ERR_NONE) + { + return res; + } + txtLen += nbWrite; + currentLen -= nbWrite; + startBlock += nbBlocks; + } + if ( currentLen > 0U ) + { + /* Unaligned write, need to use a tmp buffer */ + if( pad ) + { + (void)ST_MEMSET(tmpBuf, 0x00, NDEF_T3T_BLOCKLEN); + } + else + { + res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */, tmpBuf, blockLen, &nbRead); + if (res != ERR_NONE) + { + /* Check result */ + return res; + } + if (nbRead != blockLen) + { + /* Check length */ + return ERR_REQUEST; + } + } + /* Fill the beginning of the buffer with user data */ + (void)ST_MEMCPY( tmpBuf, &buf[txtLen], currentLen); + res = ndefT3TPollerWriteBlocks(ctx, startBlock, 1U /* One block */, tmpBuf); + if (res != ERR_NONE) + { + return res; + } + } + + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT3TPollerWriteAttributeInformationBlock(ndefContext *ctx) +{ + ndefStatus ret; + uint8_t dataIt; + uint16_t checksum; + uint8_t* buf; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + if ( ctx->state < NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + dataIt = 0U; + buf = ctx->ccBuf; + checksum = 0U; + buf[dataIt] = ((uint8_t)(ctx->cc.t3t.majorVersion << 4U)) | ctx->cc.t3t.minorVersion; /* Byte 0 Ver */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = ctx->cc.t3t.nbR; /* Byte 1 Nbr */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = ctx->cc.t3t.nbW; /* Byte 2 Nbw */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t3t.nMaxB >> 8U); /* Byte 3 NmaxB (MSB) */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t3t.nMaxB >> 0U); /* Byte 4 NmaxB (LSB) */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = 0U; /* Byte 5 RFU */ + dataIt++; + buf[dataIt] = 0U; /* Byte 6 RFU */ + dataIt++; + buf[dataIt] = 0U; /* Byte 7 RFU */ + dataIt++; + buf[dataIt] = 0U; /* Byte 8 RFU */ + dataIt++; + buf[dataIt] = ctx->cc.t3t.writeFlag; /* Byte 9 WriteFlag */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = ctx->cc.t3t.rwFlag; /* Byte 10 RWFlag */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 16U); /* Byte 11 Ln (MSB) */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 8U); /* Byte 12 Ln (middle) */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 0U); /* Byte 13 Ln (LSB) */ + checksum += buf[dataIt]; + dataIt++; + buf[dataIt] = (uint8_t)(checksum >> 8U); /* Byte 14 checksum MSB */ + dataIt++; + buf[dataIt] = (uint8_t)(checksum >> 0U); /* Byte 15 checksum LSB */ + dataIt++; + + ret = ndefT3TPollerWriteBlocks(ctx, NDEF_T3T_ATTRIB_INFO_BLOCK_NB, 1U /* One block */, buf); + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) || ((buf == NULL) && (bufLen != 0U)) ) + { + return ERR_PARAM; + } + /* TS T3T v1.0 7.4.3: This procedure assumes that the Reader/Writer has successfully performed the NDEF detection procedure... */ + /* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF read procedure*/ + + /* TS T3T v1.0 7.4.3: ... and that the RWFlag in the Attribute Information Block is set to 01h. */ + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + /* Conclude procedure */ + return ERR_WRONG_STATE; + } + + /* TS T3T v1.0 7.4.3.2: verify available space */ + ret = ndefT3TPollerCheckAvailableSpace(ctx, bufLen); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ERR_PARAM; + } + + /* TS T3T v1.0 7.4.3.3: update WriteFlag */ + ret = ndefT3TPollerBeginWriteMessage(ctx, bufLen); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + /* Conclude procedure */ + return ret; + } + + if( bufLen != 0U ) + { + /* TS T3T v1.0 7.4.3.4: write new NDEF message */ + ret = ndefT3TPollerWriteBytes(ctx, ctx->messageOffset, buf, bufLen, true, false); + if (ret != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + } + /* TS T3T v1.0 7.4.3.5: update Ln value and set WriteFlag to OFF */ + ret = ndefT3TPollerEndWriteMessage(ctx, bufLen, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options) +{ + ndefStatus err; + ReturnCode res; + rfalFeliCaPollRes buffOut[NDEF_T3T_MAX_DEVICE]; + uint8_t devCnt = NDEF_T3T_MAX_DEVICE; + uint8_t collisions = 0U; + NO_WARNING(options); /* options not used in T3T */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) || (cc == NULL) ) + { + return ERR_PARAM; + } + + /* 4.3.3 System Definition Information for SystemCode = 0x12FC (NDEF) */ + res = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_NO_REQUEST, buffOut, &devCnt, &collisions ); + if (res != RFAL_ERR_NONE) + { + return ERR_REQUEST; + } + res = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_SYSTEM_CODE, buffOut, &devCnt, &collisions ); + if (res != RFAL_ERR_NONE) + { + return ERR_REQUEST; + } + + (void)ST_MEMCPY(&ctx->cc, cc, sizeof(ndefCapabilityContainer)); + + ctx->state = NDEF_STATE_INITIALIZED; /* to be sure that the block will be written */ + ctx->cc.t3t.Ln = 0U; /* Force actual stored NDEF size to 0 */ + ctx->cc.t3t.writeFlag = NDEF_T3T_WRITEFLAG_OFF; /* Force WriteFlag to Off */ + + err = ndefT3TPollerWriteAttributeInformationBlock(ctx); + if (err != ERR_NONE) + { + ctx->state = NDEF_STATE_INVALID; + } + + return err; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerCheckPresence(ndefContext *ctx) +{ + ndefStatus retcode; + uint16_t nbRead; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + /* Perform a simple readblock */ + retcode = ndefT3TPollerReadBlocks(ctx, 0U /* First block */, 1U /* One Block */, ctx->subCtx.t3t.rxbuf, NDEF_T3T_BLOCKLEN, &nbRead); + return retcode; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen) +{ + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + if( ctx->state == NDEF_STATE_INVALID ) + { + return ERR_WRONG_STATE; + } + if( messageLen > ctx->areaLen ) + { + return ERR_NOMEM; + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + ndefStatus ret; + NO_WARNING(messageLen); + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + /* Update WriteFlag */ + ctx->cc.t3t.writeFlag = NDEF_T3T_WRITEFLAG_ON; + ret = ndefT3TPollerWriteAttributeInformationBlock(ctx); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + ctx->state = NDEF_STATE_INITIALIZED; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator) +{ + ndefStatus ret; + + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + if( ctx->state != NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + /* TS T3T v1.0 7.4.3.5 Update Attribute Information Block */ + ctx->cc.t3t.writeFlag = NDEF_T3T_WRITEFLAG_OFF; + ctx->cc.t3t.Ln = messageLen; + ret = ndefT3TPollerWriteAttributeInformationBlock(ctx); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + ctx->messageLen = messageLen; + ctx->state = (ctx->messageLen == 0U) ? NDEF_STATE_INITIALIZED : NDEF_STATE_READWRITE; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator) +{ + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + return ndefT3TPollerEndWriteMessage(ctx, rawMessageLen, false); +} + +/*******************************************************************************/ +ndefStatus ndefT3TPollerSetReadOnly(ndefContext *ctx) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T3T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_READWRITE ) + { + return ERR_WRONG_STATE; + } + + /* TS T3T v1.0 7.5.2.4 */ + if( ctx->cc.t3t.writeFlag != NDEF_T3T_WRITEFLAG_OFF ) + { + return ERR_WRONG_STATE; + } + + /* TS T3T v1.0 7.5.2.4 */ + ctx->cc.t3t.rwFlag = NDEF_T3T_FLAG_RO; + ret = ndefT3TPollerWriteAttributeInformationBlock(ctx); + if( ret != ERR_NONE ) + { + return ret; + } + + ctx->state = NDEF_STATE_READONLY; + return ERR_NONE; +} + +#endif /* NDEF_FEATURE_FULL_API */ + +#endif /* NDEF_FEATURE_T3T */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_t4t.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_t4t.c new file mode 100644 index 0000000..d81f560 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_t4t.c @@ -0,0 +1,964 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC Forum T4T + * + * This module provides an interface to perform as a NFC Reader/Writer + * to handle a Type 4 Tag T4T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" +#include "ndef_t4t.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef NDEF_FEATURE_T4T + #error " NDEF: Module configuration missing. Please enable/disable T4T module by setting: NDEF_FEATURE_T4T" +#endif + +#if NDEF_FEATURE_T4T + +#if RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN < NDEF_T4T_MIN_APDU_LEN + #error " RFAL: ISO-DEP APDU Max length must be greater than ISO7816 Command/Response-APDU length. Please increase RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN" +#endif + +#ifndef NDEF_FEATURE_FULL_API + #error " NDEF: Module configuration missing. Please enable/disable Full API by setting: NDEF_FEATURE_FULL_API" +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T4T_FID_SIZE 2U /*!< File Id size */ +#define NDEF_T4T_WRITE_ODO_PREFIX_SIZE 7U /*!< Size of ODO for Write Binary: 54 03 xxyyzz 53 Ld */ + +#define NDEF_T4T_DEFAULT_MLC 0x000DU /*!< Defauit Max Lc value before reading CCFILE values */ +#define NDEF_T4T_DEFAULT_MLE 0x000FU /*!< Defauit Max Le value before reading CCFILE values */ + +#define NDEF_T4T_OFFSET_MAX 0x7FFFU /*!< Maximum offset value for ReadBinary */ +#define NDEF_T4T_ODO_OFFSET_MAX 0xFFFFFEU /*!< Maximum offset value for ReadBinary with ODO */ + +#define NDEF_T4T_CCFILEV2_LEN 15U /*!< CCFILE Length mapping version V2 */ +#define NDEF_T4T_CCFILEV3_LEN 17U /*!< CCFILE Length mapping version V3 */ + +#define NDEF_T4T_NDEF_CTLV_T 0x04U /*!< NDEF-File_Ctrl_TLV T field value */ +#define NDEF_T4T_ENDEF_CTLV_T 0x06U /*!< ENDEF-File_Ctrl_TLV T field value */ + +#define NDEF_T4T_NDEF_CTLV_L 0x06U /*!< NDEF-File_Ctrl_TLV T field value */ +#define NDEF_T4T_ENDEF_CTLV_L 0x08U /*!< ENDEF-File_Ctrl_TLV T field value */ + +#define NDEF_T4T_MIN_VALID_MLE 0x000FU /*!< Min valid MLe. MLe valid range 000Fh-FFFFh */ +#define NDEF_T4T_MIN_VALID_MLC 0x000DU /*!< Min valid MLc. MLc valid range 000Dh-FFFFh */ + +#define NDEF_T4T_NLEN_LEN 2U /*!< NLEN LEN (mapping version v2.0): 2 bytes */ +#define NDEF_T4T_ENLEN_LEN 4U /*!< ENLEN LEN (mapping version v3.0): 4 bytes */ + +#define NDEF_T4T_MIN_NLEN 3U /*!< Minimun non null NLEN value. TS T4T v1.0 B */ + +#define NDEF_T4T_MV2_MAX_OFSSET 0x7FFFU /*!< ReadBinary maximum Offset (offset range 0000-7FFFh)*/ + +#if NDEF_T4T_MAX_RAPDU_BODY_LEN >= 255U +#define NDEF_T4T_MAX_MLE 255U /*!< Maximum MLe value supported in this implementation (short field coding). Le=0 (MLe=256) not supported by some tag. */ +#else +#define NDEF_T4T_MAX_MLE NDEF_T4T_MAX_RAPDU_BODY_LEN +#endif + +#if NDEF_T4T_MAX_CAPDU_BODY_LEN >= 255U +#define NDEF_T4T_MAX_MLC 255U /*!< Maximum MLc value supported in this implementation (short field coding). */ +#else +#define NDEF_T4T_MAX_MLC NDEF_T4T_MAX_CAPDU_BODY_LEN +#endif + +/* + ****************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define ndefT4TisT4TDevice(device) ((((device)->type == RFAL_NFC_LISTEN_TYPE_NFCA) && ((device)->dev.nfca.type == RFAL_NFCA_T4T)) || ((device)->type == RFAL_NFC_LISTEN_TYPE_NFCB)) + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static void ndefT4TInitializeIsoDepTxRxParam(ndefContext *ctx, rfalIsoDepApduTxRxParam *isoDepAPDU); +static ndefStatus ndefT4TTransceiveTxRx(ndefContext *ctx, rfalIsoDepApduTxRxParam *isoDepAPDU); +static ndefStatus ndefT4TReadAndParseCCFile(ndefContext *ctx); + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +static void ndefT4TInitializeIsoDepTxRxParam(ndefContext *ctx, rfalIsoDepApduTxRxParam *isoDepAPDU) +{ + /* Initialize the ISO-DEP protocol transceive context */ + isoDepAPDU->txBuf = &ctx->subCtx.t4t.cApduBuf; + isoDepAPDU->DID = ctx->subCtx.t4t.DID; + isoDepAPDU->FWT = ctx->subCtx.t4t.FWT; + isoDepAPDU->dFWT = ctx->subCtx.t4t.dFWT; + isoDepAPDU->FSx = ctx->subCtx.t4t.FSx; + isoDepAPDU->ourFSx = RFAL_ISODEP_FSX_KEEP; + isoDepAPDU->rxBuf = &ctx->subCtx.t4t.rApduBuf; + isoDepAPDU->tmpBuf = &ctx->subCtx.t4t.tmpBuf; +} + +/*******************************************************************************/ +static ndefStatus ndefT4TTransceiveTxRx(ndefContext *ctx, rfalIsoDepApduTxRxParam *isoDepAPDU) +{ + ReturnCode ret; + + /* Initialize respAPDU */ + ctx->subCtx.t4t.respAPDU.rApduBuf = &ctx->subCtx.t4t.rApduBuf; + isoDepAPDU->rxLen = &ctx->subCtx.t4t.respAPDU.rcvdLen; + + ret = rfalIsoDepStartApduTransceive(*isoDepAPDU); + if( ret == RFAL_ERR_NONE ) + { + do { + /* Blocking implementation, T4T may define rather long timeouts */ + rfalWorker(); + ret = rfalIsoDepGetApduTransceiveStatus(); + } while (ret == RFAL_ERR_BUSY); + } + + if (ret != RFAL_ERR_NONE) + { + return ERR_REQUEST; + } + + ret = rfalT4TPollerParseRAPDU(&ctx->subCtx.t4t.respAPDU); + ctx->subCtx.t4t.rApduBodyLen = ctx->subCtx.t4t.respAPDU.rApduBodyLen; + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + +/*******************************************************************************/ +static ndefStatus ndefT4TReadNlen(ndefContext *ctx) +{ + ndefStatus ret; + uint8_t nlenLen; + uint8_t* nLen; + + ctx->state = NDEF_STATE_INVALID; + nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN; + + /* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */ + ret = ndefT4TPollerReadBinary(ctx, 0U, nlenLen); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.11 */ + return ret; + } + nLen = ctx->subCtx.t4t.rApduBuf.apdu; + ctx->messageLen = (nlenLen == NDEF_T4T_ENLEN_LEN) ? GETU32(&nLen[0]) : (uint32_t)ndefBytes2Uint16(nLen[0], nLen[1]); + + if ( (ctx->messageLen > (ctx->cc.t4t.fileSize - nlenLen)) || ((ctx->messageLen > 0U) && (ctx->messageLen < NDEF_T4T_MIN_NLEN)) ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.11 */ + return ERR_REQUEST; + } + if( ctx->messageLen == 0U ) + { + if( !(ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.11 */ + return ERR_REQUEST; + } + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + ctx->state = (ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY; + } + + return ERR_NONE; +} + +/*******************************************************************************/ +static ndefStatus ndefT4TReadAndParseCCFile(ndefContext *ctx) +{ + static const uint8_t RFAL_T4T_FID_CC[] = {0xE1, 0x03}; /*!< FID_CC-File T4T 1.0 4.2 */ + + ndefStatus ret; + uint8_t dataIt; + + /* Select CCFILE TS T4T v1.0 7.2.1.3 */ + ret = ndefT4TPollerSelectFile(ctx, RFAL_T4T_FID_CC); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.4 */ + return ret; + } + + /* Read CCFILE TS T4T v1.0 7.2.1.5 */ + /* read CCFILE assuming at least 15 bytes are available. If V3 found will read the extra bytes in a second step */ + ret = ndefT4TPollerReadBinary(ctx, 0U, NDEF_T4T_CCFILEV2_LEN); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.6 */ + return ret; + } + (void)ST_MEMCPY(ctx->ccBuf, ctx->subCtx.t4t.rApduBuf.apdu, NDEF_T4T_CCFILEV2_LEN); + dataIt = 0; + ctx->cc.t4t.ccLen = GETU16(&ctx->ccBuf[dataIt]); + dataIt += (uint8_t)sizeof(uint16_t); + ctx->cc.t4t.vNo = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.mLe = GETU16(&ctx->ccBuf[dataIt]); + dataIt += (uint8_t)sizeof(uint16_t); + ctx->cc.t4t.mLc = GETU16(&ctx->ccBuf[dataIt]); + dataIt += (uint8_t)sizeof(uint16_t); + + /* TS T4T v1.0 7.2.1.7 verify MLe and MLc are within the valid range */ + if( (ctx->cc.t4t.mLe < NDEF_T4T_MIN_VALID_MLE) || (ctx->cc.t4t.mLc < NDEF_T4T_MIN_VALID_MLC) ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.8 */ + return ERR_REQUEST; + } + + ctx->subCtx.t4t.curMLe = (uint8_t)MIN(ctx->cc.t4t.mLe, NDEF_T4T_MAX_MLE); /* Only short field codind supported */ + ctx->subCtx.t4t.curMLc = (uint8_t)MIN(ctx->cc.t4t.mLc, NDEF_T4T_MAX_MLC); /* Only short field codind supported */ + + /* TS T4T v1.0 7.2.1.7 and 4.3.2.4 verify support of mapping version */ + if( ndefMajorVersion(ctx->cc.t4t.vNo) > ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.8 */ + return ERR_REQUEST; + } + if( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) + { + /* V3 found: read remainng bytes */ + ret = ndefT4TPollerReadBinary(ctx, NDEF_T4T_CCFILEV2_LEN, NDEF_T4T_CCFILEV3_LEN - NDEF_T4T_CCFILEV2_LEN); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.6 */ + return ret; + } + (void)ST_MEMCPY(&ctx->ccBuf[NDEF_T4T_CCFILEV2_LEN], ctx->subCtx.t4t.rApduBuf.apdu, NDEF_T4T_CCFILEV3_LEN - NDEF_T4T_CCFILEV2_LEN); + + /* TS T4T v1.0 7.2.1.7 verify coding as in table 5 */ + if( ctx->ccBuf[dataIt] != NDEF_T4T_ENDEF_CTLV_T ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.8 */ + return ERR_REQUEST; + } + dataIt++; + if( ctx->ccBuf[dataIt] < NDEF_T4T_ENDEF_CTLV_L ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.8 */ + return ERR_REQUEST; + } + dataIt++; + ctx->cc.t4t.fileId[0U] = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.fileId[1U] = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.fileSize = GETU32(&ctx->ccBuf[dataIt]); + dataIt += (uint8_t)sizeof(uint32_t); + ctx->cc.t4t.readAccess = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.writeAccess = ctx->ccBuf[dataIt]; + dataIt++; + } + else + { + if( ctx->ccBuf[dataIt] != NDEF_T4T_NDEF_CTLV_T ) + { + return ERR_REQUEST; + } + dataIt++; + if( ctx->ccBuf[dataIt] < NDEF_T4T_NDEF_CTLV_L ) + { + return ERR_REQUEST; + } + dataIt++; + ctx->cc.t4t.fileId[0U] = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.fileId[1U] = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.fileSize = ndefBytes2Uint16(ctx->ccBuf[dataIt], ctx->ccBuf[dataIt + 1U]); + dataIt += (uint8_t)sizeof(uint16_t); + ctx->cc.t4t.readAccess = ctx->ccBuf[dataIt]; + dataIt++; + ctx->cc.t4t.writeAccess = ctx->ccBuf[dataIt]; + dataIt++; + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerSelectNdefTagApplication(ndefContext *ctx) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + static const uint8_t NDEF_T4T_AID_NDEF[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01}; /*!< AID_NDEF v2.0 or higher T4T 1.0 4.3.3 */ + static const uint8_t NDEF_T4T_AID_NDEF_V1[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00}; /*!< AID_NDEF v1.0 T4T 1.0 4.3.3 */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeSelectAppl(isoDepAPDU.txBuf, NDEF_T4T_AID_NDEF, (uint8_t)sizeof(NDEF_T4T_AID_NDEF), &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + if( ret == ERR_NONE ) + { + /* application v2 or higher found */ + ctx->subCtx.t4t.mv1Flag = false; + return ret; + } + + if( ret != ERR_REQUEST ) + { + return ret; + } + + /* if v2 application not found, try v1 */ + (void)rfalT4TPollerComposeSelectAppl(isoDepAPDU.txBuf, NDEF_T4T_AID_NDEF_V1, (uint8_t)sizeof(NDEF_T4T_AID_NDEF_V1), &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + if( ret == ERR_NONE ) + { + /* application v1 found */ + ctx->subCtx.t4t.mv1Flag = true; + } + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerSelectFile(ndefContext *ctx, const uint8_t *fileId) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + + if (ctx->subCtx.t4t.mv1Flag) + { + (void)rfalT4TPollerComposeSelectFileV1Mapping(isoDepAPDU.txBuf, fileId, NDEF_T4T_FID_SIZE, &isoDepAPDU.txBufLen); + } + else + { + (void)rfalT4TPollerComposeSelectFile(isoDepAPDU.txBuf, fileId, NDEF_T4T_FID_SIZE, &isoDepAPDU.txBufLen); + } + + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + return ret; +} + + +/*******************************************************************************/ +ndefStatus ndefT4TPollerReadBinary(ndefContext *ctx, uint16_t offset, uint8_t len) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (len > ctx->subCtx.t4t.curMLe) || (offset > NDEF_T4T_OFFSET_MAX) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeReadData(isoDepAPDU.txBuf, offset, len, &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerReadBinaryODO(ndefContext *ctx, uint32_t offset, uint8_t len) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (len > ctx->subCtx.t4t.curMLe) || (offset > NDEF_T4T_ODO_OFFSET_MAX) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeReadDataODO(isoDepAPDU.txBuf, offset, len, &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + ndefStatus ret; + uint8_t le; + uint32_t lvOffset = offset; + uint32_t lvLen = len; + uint8_t* lvBuf = buf; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (lvLen == 0U) ) + { + return ERR_PARAM; + } + if( rcvdLen != NULL ) + { + *rcvdLen = 0U; + } + + do { + le = ( lvLen > ctx->subCtx.t4t.curMLe ) ? ctx->subCtx.t4t.curMLe : (uint8_t)lvLen; + if( lvOffset > NDEF_T4T_MV2_MAX_OFSSET ) + { + ret = ndefT4TPollerReadBinaryODO(ctx, lvOffset, le); + } + else + { + ret = ndefT4TPollerReadBinary(ctx, (uint16_t)lvOffset, le); + } + if( ret != ERR_NONE ) + { + return ret; + } + if( ctx->subCtx.t4t.rApduBodyLen == 0U ) + { + break; /* no more to read */ + } + if( ctx->subCtx.t4t.rApduBodyLen > lvLen ) + { + return ERR_SYSTEM; + } + (void)ST_MEMCPY(lvBuf, ctx->subCtx.t4t.rApduBuf.apdu, ctx->subCtx.t4t.rApduBodyLen); + lvBuf = &lvBuf[ctx->subCtx.t4t.rApduBodyLen]; + lvOffset += ctx->subCtx.t4t.rApduBodyLen; + lvLen -= ctx->subCtx.t4t.rApduBodyLen; + if( rcvdLen != NULL ) + { + *rcvdLen += ctx->subCtx.t4t.rApduBodyLen; + } + } while( lvLen != 0U ); + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev) +{ + if( (ctx == NULL) || (dev == NULL) || !ndefT4TisT4TDevice(dev) ) + { + return ERR_PARAM; + } + + (void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device)); + + ctx->type = NDEF_DEV_T4T; + ctx->state = NDEF_STATE_INVALID; + ctx->subCtx.t4t.curMLc = NDEF_T4T_DEFAULT_MLC; + ctx->subCtx.t4t.curMLe = NDEF_T4T_DEFAULT_MLE; + + ctx->subCtx.t4t.DID = dev->proto.isoDep.info.DID; + ctx->subCtx.t4t.FWT = dev->proto.isoDep.info.FWT; + ctx->subCtx.t4t.dFWT = dev->proto.isoDep.info.dFWT; + ctx->subCtx.t4t.FSx = dev->proto.isoDep.info.FSx; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info) +{ + ndefStatus ret; + uint8_t nlenLen; + + if( info != NULL ) + { + info->state = NDEF_STATE_INVALID; + info->majorVersion = 0U; + info->minorVersion = 0U; + info->areaLen = 0U; + info->areaAvalableSpaceLen = 0U; + info->messageLen = 0U; + } + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + ctx->state = NDEF_STATE_INVALID; + + /* Select NDEF Tag application TS T4T v1.0 7.2.1.1 */ + ret = ndefT4TPollerSelectNdefTagApplication(ctx); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.2 */ + return ret; + } + + /* TS T4T v1.0 7.2.1.3 and following */ + ret = ndefT4TReadAndParseCCFile(ctx); + if( ret != ERR_NONE ) + { + return ret; + } + nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN; + + /* TS T4T v1.0 7.2.1.7 verify file READ access */ + if( !(ndefT4TIsReadAccessGranted(ctx->cc.t4t.readAccess)) ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.8 */ + return ERR_REQUEST; + } + /* File size need at least be enough to store NLEN or ENLEN */ + if( ctx->cc.t4t.fileSize < nlenLen) + { + return ERR_REQUEST; + } + + /* Select NDEF File TS T4T v1.0 7.2.1.9 */ + ret = ndefT4TPollerSelectFile(ctx, ctx->cc.t4t.fileId); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.10 */ + return ret; + } + /* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */ + ret = ndefT4TReadNlen(ctx); /* Set ctx->state to NDEF_STATE_INITIALIZED, NDEF_STATE_READWRITE or NDEF_STATE_READONLY */ + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.1.11 */ + return ret; + } + ctx->messageOffset = nlenLen; + ctx->areaLen = ctx->cc.t4t.fileSize; + + if( info != NULL ) + { + info->state = ctx->state; + info->majorVersion = ndefMajorVersion(ctx->cc.t4t.vNo); + info->minorVersion = ndefMinorVersion(ctx->cc.t4t.vNo); + info->areaLen = ctx->areaLen; + info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset; + info->messageLen = ctx->messageLen; + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + /* TS T4T v1.0 7.2.2.1: T4T NDEF Detect should have been called at least once before NDEF read procedure */ + + if( !single ) + { + ret = ndefT4TReadNlen(ctx); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + } + + /* TS T4T v1.0 7.3.3.2: check presence of NDEF message */ + if ( ctx->state <= NDEF_STATE_INITIALIZED ) + { + /* Conclude procedure TS T4T v1.0 7.2.2.2 */ + return ERR_WRONG_STATE; + } + + if( ctx->messageLen > bufLen ) + { + return ERR_NOMEM; + } + + /* TS T4T v1.0 7.3.3.3: read the NDEF message */ + ret = ndefT4TPollerReadBytes(ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + } + + return ret; +} + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +ndefStatus ndefT4TPollerWriteBinary(ndefContext *ctx, uint16_t offset, const uint8_t *data, uint8_t len) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (len > ctx->subCtx.t4t.curMLc) || (offset > NDEF_T4T_OFFSET_MAX) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeWriteData(isoDepAPDU.txBuf, offset, data, len, &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerWriteBinaryODO(ndefContext *ctx, uint32_t offset, const uint8_t *data, uint8_t len) +{ + ndefStatus ret; + rfalIsoDepApduTxRxParam isoDepAPDU; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (len > ctx->subCtx.t4t.curMLc) || (offset > NDEF_T4T_ODO_OFFSET_MAX) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeWriteDataODO(isoDepAPDU.txBuf, offset, data, len, &isoDepAPDU.txBufLen); + ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator) +{ + ndefStatus ret; + uint8_t lc; + uint32_t lvOffset = offset; + uint32_t lvLen = len; + const uint8_t* lvBuf = buf; + + NO_WARNING(pad); /* Unused parameter */ + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || (lvLen == 0U) ) + { + return ERR_PARAM; + } + + do { + + if( lvOffset > NDEF_T4T_MV2_MAX_OFSSET ) + { + lc = ( lvLen > ((uint32_t)ctx->subCtx.t4t.curMLc - NDEF_T4T_WRITE_ODO_PREFIX_SIZE) ) ? (uint8_t)(ctx->subCtx.t4t.curMLc - NDEF_T4T_WRITE_ODO_PREFIX_SIZE) : (uint8_t)lvLen; + ret = ndefT4TPollerWriteBinaryODO(ctx, lvOffset, lvBuf, lc); + } + else + { + lc = ( lvLen > ctx->subCtx.t4t.curMLc ) ? ctx->subCtx.t4t.curMLc : (uint8_t)lvLen; + ret = ndefT4TPollerWriteBinary(ctx, (uint16_t)lvOffset, lvBuf, lc); + } + if( ret != ERR_NONE ) + { + return ret; + } + lvBuf = &lvBuf[lc]; + lvOffset += lc; + lvLen -= lc; + } while( lvLen != 0U ); + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator) +{ + ndefStatus ret; + uint8_t buf[NDEF_T4T_ENLEN_LEN]; + uint8_t dataIt; + + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + dataIt = 0U; + if( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) + { + buf[dataIt] = (uint8_t)(rawMessageLen >> 24U); + dataIt++; + buf[dataIt] = (uint8_t)(rawMessageLen >> 16U); + dataIt++; + buf[dataIt] = (uint8_t)(rawMessageLen >> 8U); + dataIt++; + buf[dataIt] = (uint8_t)(rawMessageLen); + dataIt++; + } + else + { + buf[dataIt] = (uint8_t)(rawMessageLen >> 8U); + dataIt++; + buf[dataIt] = (uint8_t)(rawMessageLen); + dataIt++; + } + + ret = ndefT4TPollerWriteBytes(ctx, 0U, buf, dataIt, false, false); + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) || ((buf == NULL) && (bufLen != 0U)) ) + { + return ERR_PARAM; + } + + /* TS T4T v1.0 7.2.3.1: T4T NDEF Detect should have been called before NDEF write procedure */ + /* Warning: current selected file must not be changed between NDEF Detect procedure and NDEF Write procedure*/ + + /* TS T4T v1.0 7.3.3.2: check write access condition */ + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + /* Conclude procedure TS T4T v1.0 7.2.3.2 */ + return ERR_WRONG_STATE; + } + + /* TS T4T v1.0 7.2.3.3: check Mapping Version */ + /* Done automatically inside underlying fucntions */ + + /* TS T4T v1.0 7.2.3.4/8 verify length of the NDEF message */ + ret = ndefT4TPollerCheckAvailableSpace(ctx, bufLen); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.3.4/8 */ + return ERR_PARAM; + } + + /* TS T4T v1.0 7.2.3.5/9 Write value 0000h in NLEN field (resp. 00000000h in ENLEN field) */ + ret = ndefT4TPollerBeginWriteMessage(ctx, bufLen); + if( ret != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + /* Conclude procedure TS T4T v1.0 7.2.3.5/9 */ + return ret; + } + + if( bufLen != 0U ) + { + /* TS T4T v1.0 7.2.3.6/10 Write NDEF message) */ + ret = ndefT4TPollerWriteBytes(ctx, ctx->messageOffset, buf, bufLen, false, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.3.6/10 */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + + /* TS T4T v1.0 7.2.3.7/11 Write value length in NLEN field (resp. in ENLEN field) */ + ret = ndefT4TPollerEndWriteMessage(ctx, bufLen, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure TS T4T v1.0 7.2.3.7/11 */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + } + + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options) +{ + NO_WARNING(ctx); + NO_WARNING(cc); + NO_WARNING(options); + + /* CC is not writable */ + return ERR_NOTSUPP; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerCheckPresence(ndefContext *ctx) +{ + rfalIsoDepApduTxRxParam isoDepAPDU; + ReturnCode ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU); + (void)rfalT4TPollerComposeReadData(isoDepAPDU.txBuf, 0, 1, &isoDepAPDU.txBufLen); + + /* Initialize respAPDU */ + ctx->subCtx.t4t.respAPDU.rApduBuf = &ctx->subCtx.t4t.rApduBuf; + isoDepAPDU.rxLen = &ctx->subCtx.t4t.respAPDU.rcvdLen; + + (void)rfalIsoDepStartApduTransceive(isoDepAPDU); + do { + /* Blocking implementation, T4T may define rather long timeouts */ + rfalWorker(); + ret = rfalIsoDepGetApduTransceiveStatus(); + } while (ret == RFAL_ERR_BUSY); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen) +{ + uint8_t nlenLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + if ( ctx->state == NDEF_STATE_INVALID ) + { + return ERR_WRONG_STATE; + } + + nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN; + if( (messageLen + (uint32_t)nlenLen) > ctx->cc.t4t.fileSize ) + { + return ERR_NOMEM; + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + ndefStatus ret; + NO_WARNING(messageLen); + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + /* TS T4T v1.0 7.2.3.5/9 Write value 0000h in NLEN field (resp. 00000000h in ENLEN field) */ + ret = ndefT4TPollerWriteRawMessageLen(ctx, 0U, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + + ctx->state = NDEF_STATE_INITIALIZED; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator) +{ + ndefStatus ret; + + NO_WARNING(writeTerminator); /* Unused parameter */ + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T4T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + + /* TS T4T v1.0 7.2.3.7/11 Write value length in NLEN field (resp. in ENLEN field) */ + ret = ndefT4TPollerWriteRawMessageLen(ctx, messageLen, false); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + ctx->messageLen = messageLen; + ctx->state = (ctx->messageLen == 0U) ? NDEF_STATE_INITIALIZED : NDEF_STATE_READWRITE; + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT4TPollerSetReadOnly(ndefContext *ctx) +{ + NO_WARNING(ctx); + return ERR_NOTSUPP; +} + +#endif /* NDEF_FEATURE_FULL_API */ + +#endif /* NDEF_FEATURE_T4T */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t.c new file mode 100644 index 0000000..82dafbb --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t.c @@ -0,0 +1,927 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC-V Forum T5T + * + * This module provides an interface to perform as a NFC-V Reader/Writer + * to handle a Type 5 Tag T5T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_poller.h" +#include "ndef_t5t_hal.h" +#include "ndef_t5t.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef NDEF_FEATURE_T5T + #error " NDEF: Module configuration missing. Please enable/disable T5T support by setting: NDEF_FEATURE_T5T" +#endif + +#if NDEF_FEATURE_T5T + +#ifndef NDEF_FEATURE_FULL_API + #error " NDEF: Module configuration missing. Please enable/disable Full API by setting: NDEF_FEATURE_FULL_API" +#endif + +#ifdef TEST_NDEF +#define NDEF_SKIP_T5T_SYS_INFO /* Must not call ndefT5TGetSystemInformation() in test mode */ +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T5T_MLEN_DIVIDER 8U /*!< T5T_area size is measured in bytes is equal to 8 * MLEN */ + +#define NDEF_T5T_TLV_T_LEN 1U /*!< TLV T Length: 1 bytes */ +#define NDEF_T5T_TLV_L_1_BYTES_LEN 1U /*!< TLV L Length: 1 bytes */ +#define NDEF_T5T_TLV_L_3_BYTES_LEN 3U /*!< TLV L Length: 3 bytes */ + +#define NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR 256U /*!< Max number of blocks for 1 byte addressing */ +#define NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING 256U /*!< MLEN max value for 1 byte encoding */ + +#define NDEF_T5T_TL_MIN_SIZE (NDEF_T5T_TLV_T_LEN \ + + NDEF_T5T_TLV_L_1_BYTES_LEN) /*!< Min TL size */ + +#define NDEF_T5T_TL_MAX_SIZE (NDEF_T5T_TLV_T_LEN \ + + NDEF_T5T_TLV_L_3_BYTES_LEN) /*!< Max TL size */ + +#define NDEF_T5T_TLV_NDEF 0x03U /*!< TLV flag NDEF value */ +#define NDEF_T5T_TLV_PROPRIETARY 0xFDU /*!< TLV flag PROPRIETARY value */ +#define NDEF_T5T_TLV_TERMINATOR 0xFEU /*!< TLV flag TERMINATOR value */ +#define NDEF_T5T_TLV_RFU 0x00U /*!< TLV flag RFU value */ + +#define NDEF_T5T_ACCESS_ALWAYS 0x0U /*!< Read/Write Accces. 00b: Always */ +#define NDEF_T5T_ACCESS_RFU 0x1U /*!< Read/Write Accces. 01b: RFU */ +#define NDEF_T5T_ACCESS_PROPRIETARY 0x2U /*!< Read/Write Accces. 00b: Proprietary */ +#define NDEF_T5T_ACCESS_NEVER 0x3U /*!< Read/Write Accces. 00b: Never */ + + +/* + ***************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ +/*! Default T5T Access mode */ +static ndefT5TAccessMode gAccessMode = NDEF_T5T_ACCESS_MODE_SELECTED; + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +#if NDEF_FEATURE_FULL_API +static ndefStatus ndefT5TWriteCC(ndefContext *ctx); +#endif /* NDEF_FEATURE_FULL_API */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +ndefStatus ndefT5TPollerSetAccessMode(ndefT5TAccessMode mode) +{ + gAccessMode = mode; + + return ERR_NONE; +} + +#ifdef TEST_NDEF +/*******************************************************************************/ +ndefStatus ndefT5TPollerMultipleBlockRead(ndefContext *ctx, bool enable) +{ + if ( (ctx == NULL) || (ctx->state != NDEF_STATE_INVALID) ) + { + return ERR_PARAM; + } + + ctx->subCtx.t5t.useMultipleBlockRead = enable; + + return ERR_NONE; +} +#endif /* TEST_NDEF */ + +/*******************************************************************************/ +static ndefStatus ndefT5TReadLField(ndefContext *ctx) +{ + ndefStatus ret; + uint32_t offset; + uint8_t data[3]; + uint16_t lenTLV; + + ctx->state = NDEF_STATE_INVALID; + offset = ctx->subCtx.t5t.TlvNDEFOffset; + offset++; + ret = ndefT5TPollerReadBytes(ctx, offset, 1, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset++; + lenTLV = data[0]; + if( lenTLV == (NDEF_SHORT_VFIELD_MAX_LEN + 1U) ) + { + ret = ndefT5TPollerReadBytes(ctx, offset, 2, data, NULL); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + return ret; + } + offset += 2U; + lenTLV = GETU16(&data[0]); + } + ctx->messageLen = lenTLV; + ctx->messageOffset = offset; + + if (lenTLV == 0U) + { + if ( !((ctx->cc.t5t.readAccess == NDEF_T5T_ACCESS_ALWAYS) && (ctx->cc.t5t.writeAccess == NDEF_T5T_ACCESS_ALWAYS)) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + if( !(ctx->cc.t5t.readAccess == NDEF_T5T_ACCESS_ALWAYS) ) + { + /* Conclude procedure */ + return ERR_REQUEST; + } + ctx->state = (ctx->cc.t5t.writeAccess == NDEF_T5T_ACCESS_ALWAYS) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY; + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerContextInitialization(ndefContext *ctx, const ndefDevice *dev) +{ +#if !defined NDEF_SKIP_T5T_SYS_INFO + ndefStatus result; +#endif + + if( (ctx == NULL) || (dev == NULL) ) + { + return ERR_PARAM; + } + if( !ndefT5TisT5TDevice(dev) ) + { + return ERR_PARAM; + } + + (void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device)); + + ndefT5TInvalidateCache(ctx); + + /* Reset info about the card */ + ctx->type = NDEF_DEV_T5T; + ctx->state = NDEF_STATE_INVALID; + + /* Initialize CC fields, used in NDEF detect */ + ctx->cc.t5t.ccLen = 0U; + ctx->cc.t5t.magicNumber = 0U; + ctx->cc.t5t.majorVersion = 0U; + ctx->cc.t5t.minorVersion = 0U; + ctx->cc.t5t.readAccess = 0U; + ctx->cc.t5t.writeAccess = 0U; + ctx->cc.t5t.memoryLen = 0U; + ctx->cc.t5t.specialFrame = false; + ctx->cc.t5t.lockBlock = false; + ctx->cc.t5t.mlenOverflow = false; + ctx->cc.t5t.multipleBlockRead = false; + + ctx->subCtx.t5t.blockLen = 0U; + ctx->subCtx.t5t.TlvNDEFOffset = 0U; /* Offset for TLV */ + ctx->subCtx.t5t.useMultipleBlockRead = false; + + ndefT5TPollerAccessMode(ctx, dev, gAccessMode); + + ctx->subCtx.t5t.stDevice = ndefT5TisSTDevice(dev); + + /* Get block length, and set subCtx.t5t.legacySTHighDensity */ + ctx->subCtx.t5t.blockLen = ndefT5TGetBlockLength(ctx); + if( ctx->subCtx.t5t.blockLen == 0U ) + { + return ERR_PROTO; + } + + ctx->subCtx.t5t.sysInfoSupported = false; + +#if !defined NDEF_SKIP_T5T_SYS_INFO + result = ndefT5TGetMemoryConfig(ctx); + if( result != ERR_NONE ) + { + return result; + } +#endif + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerNdefDetect(ndefContext *ctx, ndefInfo *info) +{ + ndefStatus result; + uint8_t tmpBuf[NDEF_T5T_TL_MAX_SIZE]; + ndefStatus returnCode = ERR_REQUEST; /* Default return code */ + uint16_t offset; + uint16_t length; + uint32_t TlvOffset; + bool exit; + uint32_t rcvLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + ctx->state = NDEF_STATE_INVALID; + ctx->cc.t5t.ccLen = 0U; + ctx->cc.t5t.memoryLen = 0U; + ctx->cc.t5t.multipleBlockRead = false; + ctx->messageLen = 0U; + ctx->messageOffset = 0U; + ctx->areaLen = 0U; + + if( info != NULL ) + { + info->state = NDEF_STATE_INVALID; + info->majorVersion = 0U; + info->minorVersion = 0U; + info->areaLen = 0U; + info->areaAvalableSpaceLen = 0U; + info->messageLen = 0U; + } + + /* Read the CC with Single Block Read command(s) first and update multipleBlockRead flag later */ + result = ndefT5TPollerReadBytes(ctx, 0U, 4U, ctx->ccBuf, &rcvLen); + if ( (result == ERR_NONE) && (rcvLen == 4U) && ( (ctx->ccBuf[0] == (uint8_t)0xE1U) || (ctx->ccBuf[0] == (uint8_t)0xE2U) ) ) + { + ctx->cc.t5t.magicNumber = ctx->ccBuf[0U]; + ctx->cc.t5t.majorVersion = (ctx->ccBuf[1U] >> 6U ) & 0x03U; + ctx->cc.t5t.minorVersion = (ctx->ccBuf[1U] >> 4U ) & 0x03U; + ctx->cc.t5t.readAccess = (ctx->ccBuf[1U] >> 2U ) & 0x03U; + ctx->cc.t5t.writeAccess = (ctx->ccBuf[1U] >> 0U ) & 0x03U; + ctx->cc.t5t.memoryLen = ctx->ccBuf[2U]; + ctx->cc.t5t.specialFrame = (((ctx->ccBuf[3U] >> 4U ) & 0x01U) != 0U); + ctx->cc.t5t.lockBlock = (((ctx->ccBuf[3U] >> 3U ) & 0x01U) != 0U); + ctx->cc.t5t.mlenOverflow = (((ctx->ccBuf[3U] >> 2U ) & 0x01U) != 0U); + + /* Check Magic Number TS T5T v1.0 - 7.5.1.2 */ + if( (ctx->cc.t5t.magicNumber != NDEF_T5T_CC_MAGIC_1_BYTE_ADDR_MODE) && + (ctx->cc.t5t.magicNumber != NDEF_T5T_CC_MAGIC_2_BYTE_ADDR_MODE) ) + { + return ERR_REQUEST; + } + + /* Check version - 7.5.1.2 */ + if( ctx->cc.t5t.majorVersion > ndefT5TMajorVersion(NDEF_T5T_MAPPING_VERSION_1_0) ) + { + return ERR_REQUEST; + } + + /* Check read access - 7.5.1.2 */ + if( ctx->cc.t5t.readAccess != NDEF_T5T_ACCESS_ALWAYS ) + { + return ERR_REQUEST; + } + + if( ctx->cc.t5t.memoryLen != 0U ) + { + /* 4-byte CC */ + ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_4_BYTES; + if( (ctx->cc.t5t.memoryLen == 0xFFU) && ctx->cc.t5t.mlenOverflow ) + { + if( (ctx->subCtx.t5t.sysInfoSupported == true) && (ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) ) + { + ctx->cc.t5t.memoryLen = (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER); + } + } + } + else + { + /* 8-byte CC */ + result = ndefT5TPollerReadBytes(ctx, 4U, 4U, &ctx->ccBuf[4U], &rcvLen); + if ( (result == ERR_NONE) && (rcvLen == 4U) ) + { + ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_8_BYTES; + ctx->cc.t5t.memoryLen = ((uint16_t)ctx->ccBuf[6U] << 8U) + (uint16_t)ctx->ccBuf[7U]; + } + } + + /* Update multipleBlockRead flag after having read the second half of 8-byte CC */ + ctx->cc.t5t.multipleBlockRead = (((ctx->ccBuf[3U] >> 0U ) & 0x01U) != 0U); + + if( (ctx->subCtx.t5t.sysInfoSupported == true) && + (ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) && + (ctx->cc.t5t.memoryLen == (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER)) && + (ctx->cc.t5t.memoryLen > 0U) ) + { + ctx->cc.t5t.memoryLen--; /* remove CC area from memory length */ + } + + ctx->messageLen = 0U; + ctx->messageOffset = ctx->cc.t5t.ccLen; + /* TS T5T v1.0 4.3.1.17 T5T_Area size is measured in bytes, is equal to MLEN * 8 */ + ctx->areaLen = (uint32_t)ctx->cc.t5t.memoryLen * NDEF_T5T_MLEN_DIVIDER; + + TlvOffset = ctx->cc.t5t.ccLen; + exit = false; + while( (exit == false) && (TlvOffset < (ctx->cc.t5t.ccLen + ctx->areaLen)) ) + { + result = ndefT5TPollerReadBytes(ctx, TlvOffset, NDEF_T5T_TL_MIN_SIZE, tmpBuf, &rcvLen); + if ( (result != ERR_NONE) || ( rcvLen != NDEF_T5T_TL_MIN_SIZE) ) + { + return result; + } + offset = NDEF_T5T_TLV_T_LEN + NDEF_T5T_TLV_L_1_BYTES_LEN; + length = tmpBuf[1U]; + if ( length == (NDEF_SHORT_VFIELD_MAX_LEN + 1U) ) + { + /* Size is encoded in 1 + 2 bytes */ + result = ndefT5TPollerReadBytes(ctx, TlvOffset, NDEF_T5T_TL_MAX_SIZE, tmpBuf, &rcvLen); + if ( (result != ERR_NONE) || ( rcvLen != NDEF_T5T_TL_MAX_SIZE) ) + { + return result; + } + length = (((uint16_t)tmpBuf[2U]) << 8U) + (uint16_t)tmpBuf[3U]; + offset += 2U; + } + if (tmpBuf[0U] == (uint8_t)NDEF_T5T_TLV_NDEF) + { + /* NDEF record return it */ + returnCode = ERR_NONE; /* Default */ + ctx->subCtx.t5t.TlvNDEFOffset = TlvOffset; /* Offset for TLV */ + ctx->messageOffset = TlvOffset + offset; + ctx->messageLen = length; + if (length == 0U) + { + /* Req 40 7.5.1.6 */ + if ( (ctx->cc.t5t.readAccess == NDEF_T5T_ACCESS_ALWAYS) && + (ctx->cc.t5t.writeAccess == NDEF_T5T_ACCESS_ALWAYS) ) + { + ctx->state = NDEF_STATE_INITIALIZED; + } + else + { + ctx->state = NDEF_STATE_INVALID; + returnCode = ERR_REQUEST; /* Default */ + } + exit = true; + } + else + { + if (ctx->cc.t5t.readAccess == NDEF_T5T_ACCESS_ALWAYS) + { + if (ctx->cc.t5t.writeAccess == NDEF_T5T_ACCESS_ALWAYS) + { + ctx->state = NDEF_STATE_READWRITE; + } + else + { + ctx->state = NDEF_STATE_READONLY; + } + } + exit = true; + } + } + else if (tmpBuf[0U]== (uint8_t) NDEF_T5T_TLV_TERMINATOR) + { + /* NDEF end */ + exit = true; + } + else + { + /* Skip Proprietary and RFU too */ + TlvOffset += (uint32_t)offset + (uint32_t)length; + } + } + } + else + { + /* No CC File */ + returnCode = ERR_REQUEST; + if (result != ERR_NONE) + { + returnCode = result; + } + } + + if( info != NULL ) + { + info->state = ctx->state; + info->majorVersion = ctx->cc.t5t.majorVersion; + info->minorVersion = ctx->cc.t5t.minorVersion; + info->areaLen = ctx->areaLen; + info->areaAvalableSpaceLen = (uint32_t)ctx->cc.t5t.ccLen + ctx->areaLen - ctx->messageOffset; + info->messageLen = ctx->messageLen; + } + return returnCode; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen, bool single) +{ + ndefStatus result; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + if( !single ) + { + ndefT5TInvalidateCache(ctx); + result = ndefT5TReadLField(ctx); + if( result != ERR_NONE ) + { + /* Conclude procedure */ + return result; + } + } + + if ( ctx->state <= NDEF_STATE_INITIALIZED ) + { + /* Conclude procedure */ + return ERR_WRONG_STATE; + } + + if( ctx->messageLen > bufLen ) + { + return ERR_NOMEM; + } + + result = ndefT5TPollerReadBytes(ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen); + if( result != ERR_NONE ) + { + ctx->state = NDEF_STATE_INVALID; + } + return result; +} + +#if NDEF_FEATURE_FULL_API + +/*******************************************************************************/ +ndefStatus ndefT5TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen, bool writeTerminator) +{ + uint8_t TLV[8U]; + ndefStatus result; + uint8_t len; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + if( writeTerminator && (rawMessageLen != 0U) && ((ctx->messageOffset + rawMessageLen) < ctx->areaLen) ) + { + /* Write T5T TLV terminator */ + len = 0U; + TLV[len] = NDEF_TERMINATOR_TLV_T; /* TLV terminator */ + len++; + result = ndefT5TPollerWriteBytes(ctx, ctx->messageOffset + rawMessageLen, TLV, len, true, false); + if (result != ERR_NONE) + { + return result; + } + } + + /* Prepare L buffer content - Don't need to write T byte so skip it */ + len = 0U; + if( rawMessageLen <= NDEF_SHORT_VFIELD_MAX_LEN ) + { + TLV[len] = (uint8_t) rawMessageLen; + len++; + } + else + { + TLV[len] = (uint8_t)(NDEF_SHORT_VFIELD_MAX_LEN + 1U); + len++; + TLV[len] = (uint8_t) (rawMessageLen >> 8U); + len++; + TLV[len] = (uint8_t) rawMessageLen; + len++; + } + if( writeTerminator && (rawMessageLen == 0U) ) + { + TLV[len] = NDEF_TERMINATOR_TLV_T; /* TLV terminator */ + len++; + } + + result = ndefT5TPollerWriteBytes(ctx, ctx->subCtx.t5t.TlvNDEFOffset + NDEF_T5T_TLV_T_LEN, TLV, len, writeTerminator && (rawMessageLen == 0U), false); + + return result; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen) +{ + uint32_t len = bufLen; + ndefStatus result; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + /* TS T5T v1.0 7.5.3.1/2: T5T NDEF Detect should have been called before NDEF write procedure */ + /* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF Write procedure*/ + + /* TS T5T v1.0 7.5.3.3: check write access condition */ + if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + /* Conclude procedure */ + return ERR_WRONG_STATE; + } + + /* TS T5T v1.0 7.5.3.3: verify available space */ + result = ndefT5TPollerCheckAvailableSpace(ctx, bufLen); + if( result != ERR_NONE ) + { + /* Conclude procedure */ + return ERR_PARAM; + } + /* TS T5T v1.0 7.5.3.4: reset L-Field to 0 */ + /* and update ctx->messageOffset according to L-field len */ + result = ndefT5TPollerBeginWriteMessage(ctx, bufLen); + if (result != ERR_NONE) + { + ctx->state = NDEF_STATE_INVALID; + /* Conclude procedure */ + return result; + } + if( bufLen != 0U ) + { + /* TS T5T v1.0 7.5.3.5: write new NDEF message and write terminator TLV is enough space for it*/ + result = ndefT5TPollerWriteBytes(ctx, ctx->messageOffset, buf, len, true, ndefT5TPollerCheckAvailableSpace(ctx, bufLen + 1U) == ERR_NONE); + if (result != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return result; + } + /* TS T5T v1.0 7.5.3.6 & 7.5.3.7: update L-Field and write Terminator TLV */ + result = ndefT5TPollerEndWriteMessage(ctx, len, false); + if (result != ERR_NONE) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return result; + } + } + return result; +} + +/*******************************************************************************/ +static ndefStatus ndefT5TWriteCC(ndefContext *ctx) +{ + ndefStatus ret; + uint8_t* buf; + uint8_t dataIt; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + buf = ctx->ccBuf; + dataIt = 0U; + /* Encode CC */ + buf[dataIt] = ctx->cc.t5t.magicNumber; /* Byte 0 */ + dataIt++; + buf[dataIt] = (uint8_t)(((ctx->cc.t5t.majorVersion & 0x03U) << 6) | /* Byte 1 */ + ((ctx->cc.t5t.minorVersion & 0x03U) << 4) | /* */ + ((ctx->cc.t5t.readAccess & 0x03U) << 2) | /* */ + ((ctx->cc.t5t.writeAccess & 0x03U) << 0)); /* */ + dataIt++; + buf[dataIt] = (ctx->cc.t5t.ccLen == NDEF_T5T_CC_LEN_8_BYTES) ? 0U : (uint8_t)ctx->cc.t5t.memoryLen; /* Byte 2 */ + dataIt++; + buf[dataIt] = 0U; /* Byte 3 */ + if( ctx->cc.t5t.multipleBlockRead ) { buf[dataIt] |= 0x01U; } /* Byte 3 b0 MBREAD */ + if( ctx->cc.t5t.mlenOverflow ) { buf[dataIt] |= 0x04U; } /* Byte 3 b2 Android MLEN overflow */ + if( ctx->cc.t5t.lockBlock ) { buf[dataIt] |= 0x08U; } /* Byte 3 b3 Lock Block */ + if( ctx->cc.t5t.specialFrame ) { buf[dataIt] |= 0x10U; } /* Byte 3 b4 Special Frame */ + dataIt++; + if( ctx->cc.t5t.ccLen == NDEF_T5T_CC_LEN_8_BYTES ) + { + buf[dataIt] = 0U; /* Byte 4 */ + dataIt++; + buf[dataIt] = 0U; /* Byte 5 */ + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t5t.memoryLen >> 8); /* Byte 6 */ + dataIt++; + buf[dataIt] = (uint8_t)(ctx->cc.t5t.memoryLen >> 0); /* Byte 7 */ + dataIt++; + } + + ret = ndefT5TPollerWriteBytes(ctx, 0U, buf, ctx->cc.t5t.ccLen, false, false); + return ret; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options) +{ + ndefStatus result; + static const uint8_t emptyNDEF[] = { 0x03U, 0x00U }; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + /* Reset previous potential info about NDEF messages */ + ctx->messageLen = 0U; + ctx->messageOffset = 0U; + ctx->subCtx.t5t.TlvNDEFOffset = 0U; + + if( cc != NULL ) + { + if( (cc->t5t.ccLen != NDEF_T5T_CC_LEN_8_BYTES) && (cc->t5t.ccLen != NDEF_T5T_CC_LEN_4_BYTES) ) + { + return ERR_PARAM; + } + (void)ST_MEMCPY(&ctx->cc, cc, sizeof(ndefCapabilityContainer)); + } + else + { + /* Try to find the appropriate cc values */ + ctx->cc.t5t.magicNumber = NDEF_T5T_CC_MAGIC_1_BYTE_ADDR_MODE; /* E1 */ + ctx->cc.t5t.majorVersion = ndefT5TMajorVersion(NDEF_T5T_MAPPING_VERSION_1_0); + ctx->cc.t5t.minorVersion = ndefT5TMinorVersion(NDEF_T5T_MAPPING_VERSION_1_0); + ctx->cc.t5t.readAccess = NDEF_T5T_ACCESS_ALWAYS; + ctx->cc.t5t.writeAccess = NDEF_T5T_ACCESS_ALWAYS; + + ctx->cc.t5t.specialFrame = false; + ctx->cc.t5t.lockBlock = false; + ctx->cc.t5t.memoryLen = 0U; + ctx->cc.t5t.mlenOverflow = false; + + ctx->cc.t5t.multipleBlockRead = ndefT5TIsMultipleBlockReadSupported(ctx); + + /* Try to retrieve the tag's size using getSystemInfo and GetExtSystemInfo */ + if( (ctx->subCtx.t5t.sysInfoSupported == false) || (ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) == 0U) ) + { + return ERR_REQUEST; + } + ctx->cc.t5t.memoryLen = (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER); + + if( (options & NDEF_T5T_FORMAT_OPTION_NFC_FORUM) == NDEF_T5T_FORMAT_OPTION_NFC_FORUM ) /* NFC Forum format */ + { + if( ctx->cc.t5t.memoryLen >= NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING ) + { + ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_8_BYTES; + } + if( ctx->cc.t5t.memoryLen > 0U ) + { + ctx->cc.t5t.memoryLen--; /* remove CC area from memory length */ + } + } + else /* Android format */ + { + ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_4_BYTES; + if( ctx->cc.t5t.memoryLen >= NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING ) + { + ctx->cc.t5t.mlenOverflow = true; + ctx->cc.t5t.memoryLen = 0xFFU; + } + } + + if( !ctx->subCtx.t5t.legacySTHighDensity && (ctx->subCtx.t5t.sysInfo.numberOfBlock > NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR) ) + { + ctx->cc.t5t.magicNumber = NDEF_T5T_CC_MAGIC_2_BYTE_ADDR_MODE; /* E2 */ + } + } + + result = ndefT5TWriteCC(ctx); + if( result != ERR_NONE ) + { + /* If write fails, try to use special frame if not yet used */ + if( !ctx->cc.t5t.specialFrame ) + { + platformDelay(20U); /* Wait to be sure that previous command has ended */ + ctx->cc.t5t.specialFrame = true; /* Add option flag */ + result = ndefT5TWriteCC(ctx); + if( result != ERR_NONE ) + { + ctx->cc.t5t.specialFrame = false; /* Add option flag */ + return result; + } + } + else + { + return result; + } + } + + /* Update info about current NDEF */ + + ctx->subCtx.t5t.TlvNDEFOffset = ctx->cc.t5t.ccLen; + + result = ndefT5TPollerWriteBytes(ctx, ctx->subCtx.t5t.TlvNDEFOffset, emptyNDEF, sizeof(emptyNDEF), true, true); + if( result == ERR_NONE ) + { + /* Update info about current NDEF */ + ctx->messageOffset = (uint32_t)ctx->cc.t5t.ccLen + NDEF_T5T_TLV_T_LEN + NDEF_T5T_TLV_L_1_BYTES_LEN; + ctx->state = NDEF_STATE_INITIALIZED; + } + return result; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerCheckPresence(ndefContext *ctx) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + ret = ndefT5TIsDevicePresent(ctx); + + return ret; +} + + +/*******************************************************************************/ +ndefStatus ndefT5TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen) +{ + uint32_t lLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if ( ctx->state == NDEF_STATE_INVALID ) + { + return ERR_WRONG_STATE; + } + + lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T5T_TLV_L_3_BYTES_LEN : NDEF_T5T_TLV_L_1_BYTES_LEN; + + if( (messageLen + ctx->subCtx.t5t.TlvNDEFOffset + NDEF_T5T_TLV_T_LEN + lLen) > (ctx->areaLen + ctx->cc.t5t.ccLen) ) + { + return ERR_NOMEM; + } + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen) +{ + ndefStatus ret; + uint32_t lLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) ) + { + return ERR_WRONG_STATE; + } + + /* TS T5T v1.0 7.5.3.4: reset L-Field to 0 */ + ret = ndefT5TPollerWriteRawMessageLen(ctx, 0U, true); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + + lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T5T_TLV_L_3_BYTES_LEN : NDEF_T5T_TLV_L_1_BYTES_LEN; + ctx->messageOffset = ctx->subCtx.t5t.TlvNDEFOffset; + ctx->messageOffset += NDEF_T5T_TLV_T_LEN; /* T Length */ + ctx->messageOffset += lLen; /* L Length */ + ctx->state = NDEF_STATE_INITIALIZED; + + return ERR_NONE; +} + +/*******************************************************************************/ +ndefStatus ndefT5TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen, bool writeTerminator) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_INITIALIZED ) + { + return ERR_WRONG_STATE; + } + + /* TS T5T v1.0 7.5.3.6 & 7.5.3.7: update L-Field and write Terminator TLV */ + ret = ndefT5TPollerWriteRawMessageLen(ctx, messageLen, writeTerminator); + if( ret != ERR_NONE ) + { + /* Conclude procedure */ + ctx->state = NDEF_STATE_INVALID; + return ret; + } + ctx->messageLen = messageLen; + ctx->state = (ctx->messageLen == 0U) ? NDEF_STATE_INITIALIZED : NDEF_STATE_READWRITE; + return ERR_NONE; +} + + +/*******************************************************************************/ +ndefStatus ndefT5TPollerSetReadOnly(ndefContext *ctx) +{ + ndefStatus ret; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if( ctx->state != NDEF_STATE_READWRITE ) + { + return ERR_WRONG_STATE; + } + + /* Change write access */ + ctx->cc.t5t.writeAccess = NDEF_T5T_ACCESS_NEVER; + + ret = ndefT5TWriteCC(ctx); + if( ret != ERR_NONE ) + { + return ret; + } + + ret = ndefT5TLockDevice(ctx); + if( ret != ERR_NONE ) + { + return ret; + } + return ERR_NONE; +} + +#endif /* NDEF_FEATURE_FULL_API */ + +#endif /* NDEF_FEATURE_T5T */ diff --git a/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t_rf.c b/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t_rf.c new file mode 100644 index 0000000..71c8212 --- /dev/null +++ b/components/spi-st25r3911b/NDEF/source/poller/ndef_t5t_rf.c @@ -0,0 +1,871 @@ +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: NDEF firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author + * + * \brief Provides NDEF methods and definitions to access NFC-V Forum T5T + * + * This module provides an interface to perform as a NFC-V Reader/Writer + * to handle a Type 5 Tag T5T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "ndef_t5t_hal.h" +#include "ndef_t5t.h" +#include "utils.h" +#include "rfal_st25xv.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef NDEF_FEATURE_T5T + #error " NDEF: Module configuration missing. Please enable/disable T5T support by setting: NDEF_FEATURE_T5T" +#endif + +#if NDEF_FEATURE_T5T + +#ifndef NDEF_FEATURE_FULL_API + #error " NDEF: Module configuration missing. Please enable/disable Full API by setting: NDEF_FEATURE_FULL_API" +#endif + +#ifdef TEST_NDEF +#define NDEF_SKIP_T5T_SYS_INFO /* Must not call ndefT5TGetSystemInformation() in test mode */ +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define NDEF_T5T_SYSINFO_MAX_LEN 22U /*!< Max length for (Extended) Get System Info response */ + +#define NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR 256U /*!< Max number of blocks for 1 byte addressing */ + + +#ifndef NDEF_T5T_N_RETRY_ERROR +#define NDEF_T5T_N_RETRY_ERROR 2U /*!< nT5T,RETRY,ERROR DP 2.2 B.12 */ +#endif /* NDEF_T5T_N_RETRY_ERROR */ + +#define NDEF_T5T_FLAG_LEN 1U /*!< Flag byte length */ + + +/* + ***************************************************************************** + * GLOBAL TYPES + ****************************************************************************** + */ + +#define NDEF_T5T_UID_MANUFACTURER_ID_POS 6U /*!< Manufacturer ID Offset in UID buffer (reverse) */ +#define NDEF_T5T_MANUFACTURER_ID_ST 0x02U /*!< Manufacturer ID for ST */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define rfalT5TIsTransmissionError(err) ( ((err) == RFAL_ERR_FRAMING) || ((err) == RFAL_ERR_CRC) || ((err) == RFAL_ERR_PAR) || ((err) == RFAL_ERR_TIMEOUT) ) + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static ndefStatus ndefT5TPollerReadSingleBlock(ndefContext *ctx, uint16_t blockNum, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen); +static ndefStatus ndefT5TPollerReadMultipleBlocks(ndefContext *ctx, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen); + +#if !defined NDEF_SKIP_T5T_SYS_INFO +static ndefStatus ndefT5TGetSystemInformation(ndefContext *ctx, bool extended); +#endif /* NDEF_SKIP_T5T_SYS_INFO */ + +#if NDEF_FEATURE_FULL_API +static ndefStatus ndefT5TPollerWriteSingleBlock(ndefContext *ctx, uint16_t blockNum, const uint8_t* wrData); +static ndefStatus ndefT5TPollerLockSingleBlock(ndefContext *ctx, uint16_t blockNum); +#endif /* NDEF_FEATURE_FULL_API */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*******************************************************************************/ +bool ndefT5TisSTDevice(const ndefDevice *dev) +{ + if( dev == NULL ) + { + return false; + } + + return (dev->dev.nfcv.InvRes.UID[NDEF_T5T_UID_MANUFACTURER_ID_POS] == NDEF_T5T_MANUFACTURER_ID_ST); +} + + +/*******************************************************************************/ +bool ndefT5TisT5TDevice(const ndefDevice *dev) +{ + if( dev == NULL ) + { + return false; + } + + return dev->type == RFAL_NFC_LISTEN_TYPE_NFCV; +} + + +/*******************************************************************************/ +ndefStatus ndefT5TPollerAccessMode(ndefContext *ctx, const ndefDevice *dev, ndefT5TAccessMode mode) +{ + ndefT5TAccessMode accessMode = mode; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || + (dev == NULL) ) + { + return ERR_PARAM; + } + + ctx->subCtx.t5t.flags = (uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT; + + if (accessMode == NDEF_T5T_ACCESS_MODE_SELECTED) + { + if (rfalNfcvPollerSelect(ctx->subCtx.t5t.flags, dev->dev.nfcv.InvRes.UID) == ERR_NONE) + { + /* Selected mode (AMS = 0, SMS = 1) */ + ctx->subCtx.t5t.uid = NULL; + ctx->subCtx.t5t.flags |= (uint8_t)RFAL_NFCV_REQ_FLAG_SELECT; + } + else + { + /* Set Addressed mode if Selected mode failed */ + accessMode = NDEF_T5T_ACCESS_MODE_ADDRESSED; + } + } + if (accessMode == NDEF_T5T_ACCESS_MODE_ADDRESSED) + { + /* Addressed mode (AMS = 1, SMS = 0) */ + ctx->subCtx.t5t.uid = dev->dev.nfcv.InvRes.UID; + ctx->subCtx.t5t.flags |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS; + } + else if (accessMode == NDEF_T5T_ACCESS_MODE_NON_ADDRESSED) + { + /* Non-addressed mode (AMS = 0, SMS = 0) */ + ctx->subCtx.t5t.uid = NULL; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + return ERR_NONE; +} + + +/*******************************************************************************/ +uint8_t ndefT5TGetBlockLength(ndefContext *ctx) +{ + ndefStatus result; + uint16_t rcvLen; + uint8_t blockLen = 0; + + if ( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return 0; + } + + /* GetBlockLength shall be called only once during context initialization */ + if( ctx->subCtx.t5t.blockLen == 0U ) + { + /* T5T v1.1 4.1.1.3 Retrieve the Block Length */ + ctx->subCtx.t5t.legacySTHighDensity = false; + result = ndefT5TPollerReadSingleBlock(ctx, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen); + if( (result != ERR_NONE) && ctx->subCtx.t5t.stDevice) + { + /* Try High Density Legacy mode */ + ctx->subCtx.t5t.legacySTHighDensity = true; + result = ndefT5TPollerReadSingleBlock(ctx, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen); + if( result != ERR_NONE ) + { + /* High Density Legacy mode not supported */ + ctx->subCtx.t5t.legacySTHighDensity = false; + return 0; + } + } + + if( (rcvLen > 1U) && (ctx->subCtx.t5t.txrxBuf[0U] == (uint8_t)0U) ) + { + blockLen = (uint8_t)(rcvLen - 1U); + } + } + + return blockLen; +} + + +#if !defined NDEF_SKIP_T5T_SYS_INFO +/*******************************************************************************/ +ndefStatus ndefT5TGetMemoryConfig(ndefContext *ctx) +{ + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + if( !ctx->subCtx.t5t.legacySTHighDensity ) + { + /* Extended Get System Info */ + if( ndefT5TGetSystemInformation(ctx, true) == ERR_NONE ) + { + ctx->subCtx.t5t.sysInfoSupported = true; + } + } + if( !ctx->subCtx.t5t.sysInfoSupported ) + { + /* Get System Info */ + if( ndefT5TGetSystemInformation(ctx, false) == ERR_NONE ) + { + ctx->subCtx.t5t.sysInfoSupported = true; + } + } + + return ERR_NONE; +} + + +/*******************************************************************************/ +static ndefStatus ndefT5TGetSystemInformation(ndefContext *ctx, bool extended) +{ + ReturnCode ret; + uint8_t rxBuf[NDEF_T5T_SYSINFO_MAX_LEN]; + uint16_t rcvLen; + uint8_t* resp; + uint8_t flags; + const uint8_t* uid; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + uid = ctx->subCtx.t5t.uid; + flags = ctx->subCtx.t5t.flags; + + if( extended ) + { + ret = rfalNfcvPollerExtendedGetSystemInformation(flags, uid, (uint8_t)RFAL_NFCV_SYSINFO_REQ_ALL, rxBuf, (uint16_t)sizeof(rxBuf), &rcvLen); + } + else + { + if( ctx->subCtx.t5t.legacySTHighDensity ) + { + flags |= (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT; + } + ret = rfalNfcvPollerGetSystemInformation(flags, uid, rxBuf, (uint16_t)sizeof(rxBuf), &rcvLen); + } + + if( ret != RFAL_ERR_NONE ) + { + return ERR_REQUEST; + } + + resp = &rxBuf[0U]; + /* skip Flags */ + resp++; + /* get Info flags */ + ctx->subCtx.t5t.sysInfo.infoFlags = *resp; + resp++; + if( extended && (ndefT5TSysInfoLenValue(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) ) + { + return ERR_REQUEST; + } + /* get UID */ + (void)ST_MEMCPY(ctx->subCtx.t5t.sysInfo.UID, resp, RFAL_NFCV_UID_LEN); + resp = &resp[RFAL_NFCV_UID_LEN]; + if( ndefT5TSysInfoDFSIDPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U ) + { + ctx->subCtx.t5t.sysInfo.DFSID = *resp; + resp++; + } + if( ndefT5TSysInfoAFIPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U ) + { + ctx->subCtx.t5t.sysInfo.AFI = *resp; + resp++; + } + if( ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U ) + { + if ( ctx->subCtx.t5t.legacySTHighDensity || extended ) + { + /* LRIS64K/M24LR16/M24LR64 */ + ctx->subCtx.t5t.sysInfo.numberOfBlock = *resp; + resp++; + ctx->subCtx.t5t.sysInfo.numberOfBlock |= (((uint16_t)*resp) << 8U); + resp++; + } + else + { + ctx->subCtx.t5t.sysInfo.numberOfBlock = *resp; + resp++; + } + ctx->subCtx.t5t.sysInfo.blockSize = *resp; + resp++; + /* Add 1 to get real values*/ + ctx->subCtx.t5t.sysInfo.numberOfBlock++; + ctx->subCtx.t5t.sysInfo.blockSize++; + } + if( ndefT5TSysInfoICRefPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U ) + { + ctx->subCtx.t5t.sysInfo.ICRef = *resp; + resp++; + } + if( extended && (ndefT5TSysInfoCmdListPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) ) + { + ctx->subCtx.t5t.sysInfo.supportedCmd[0U] = *resp; + resp++; + ctx->subCtx.t5t.sysInfo.supportedCmd[1U] = *resp; + resp++; + ctx->subCtx.t5t.sysInfo.supportedCmd[2U] = *resp; + resp++; + ctx->subCtx.t5t.sysInfo.supportedCmd[3U] = *resp; + resp++; + } + return ERR_NONE; +} +#endif /* NDEF_SKIP_T5T_SYS_INFO */ + + +/*******************************************************************************/ +bool ndefT5TIsMultipleBlockReadSupported(ndefContext *ctx) +{ + ndefStatus result; + uint16_t rcvdLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return false; + } + + /* Autodetect the Multiple Block Read feature (CC Byte 3 b0: MBREAD) */ + result = ndefT5TPollerReadMultipleBlocks(ctx, 0U, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvdLen); + return (result == ERR_NONE); +} + + +/*******************************************************************************/ +ndefStatus ndefT5TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen) +{ + ndefStatus res; + uint8_t lastVal; + uint16_t nbRead; + uint16_t blockLen; + uint16_t startBlock; + uint16_t startAddr; + uint32_t currentLen = len; + uint32_t lvRcvLen = 0U; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || (buf == NULL) ) + { + return ERR_PARAM; + } + + if ( (ctx->subCtx.t5t.blockLen > 0U) && (len > 0U) ) + { + blockLen = (uint16_t)ctx->subCtx.t5t.blockLen; + + startBlock = (uint16_t) (offset / blockLen); + startAddr = (uint16_t) (startBlock * blockLen); + + res = ( (ctx->cc.t5t.multipleBlockRead == true) && (ctx->subCtx.t5t.useMultipleBlockRead == true) ) ? + /* Read a single block using the ReadMultipleBlock command... */ + ndefT5TPollerReadMultipleBlocks(ctx, startBlock, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead) : + ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead); + if (res != ERR_NONE) + { + return res; + } + + nbRead = (uint16_t) (nbRead + startAddr - (uint16_t)offset - 1U); + if ((uint32_t) nbRead > currentLen) + { + nbRead = (uint16_t) currentLen; + } + if (nbRead > 0U) + { + /* Remove the Flag byte */ + (void)ST_MEMCPY(buf, &ctx->subCtx.t5t.txrxBuf[1U - startAddr + (uint16_t)offset], nbRead); + } + lvRcvLen += (uint32_t)nbRead; + currentLen -= (uint32_t)nbRead; + /* Process all blocks but not the last one */ + /* Rationale: ndefT5TPollerReadSingleBlock() reads 2 extra CRC bytes and could write after buffer end */ + while (currentLen > (uint32_t)blockLen) + { + startBlock++; + lastVal = buf[lvRcvLen - 1U]; /* Read previous value that is going to be overwritten by status byte (1st byte in response) */ + + res = ( (ctx->cc.t5t.multipleBlockRead == true) && (ctx->subCtx.t5t.useMultipleBlockRead == true) ) ? + /* Read a single block using the ReadMultipleBlock command... */ + ndefT5TPollerReadMultipleBlocks(ctx, startBlock, 0U, &buf[lvRcvLen - 1U], blockLen + NDEF_T5T_FLAG_LEN + RFAL_CRC_LEN, &nbRead) : + ndefT5TPollerReadSingleBlock(ctx, startBlock, &buf[lvRcvLen - 1U], blockLen + NDEF_T5T_FLAG_LEN + RFAL_CRC_LEN, &nbRead); + if (res != ERR_NONE) + { + return res; + } + + buf[lvRcvLen - 1U] = lastVal; /* Restore previous value */ + + lvRcvLen += blockLen; + currentLen -= blockLen; + } + if (currentLen > 0U) + { + /* Process the last block. Take care of removing status byte and 2 extra CRC bytes that could write after buffer end */ + startBlock++; + + res = ( (ctx->cc.t5t.multipleBlockRead == true) && (ctx->subCtx.t5t.useMultipleBlockRead == true) ) ? + /* Read a single block using the ReadMultipleBlock command... */ + ndefT5TPollerReadMultipleBlocks(ctx, startBlock, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead) : + ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead); + if (res != ERR_NONE) + { + return res; + } + + nbRead--; /* Remove Flag byte */ + if (nbRead > currentLen) + { + nbRead = (uint16_t)currentLen; + } + if (nbRead > 0U) + { + (void)ST_MEMCPY(&buf[lvRcvLen], & ctx->subCtx.t5t.txrxBuf[1U], nbRead); + } + lvRcvLen += nbRead; + currentLen -= nbRead; + } + } + if (currentLen != 0U) + { + return ERR_SYSTEM; + } + if( rcvdLen != NULL ) + { + *rcvdLen = lvRcvLen; + } + return ERR_NONE; +} + + +/*******************************************************************************/ +static ndefStatus ndefT5TPollerReadSingleBlock(ndefContext *ctx, uint16_t blockNum, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen) +{ + ReturnCode ret; + uint8_t flags; + const uint8_t* uid; + uint32_t retry; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || (rxBuf == NULL) || (rcvLen == NULL) ) + { + return ERR_PARAM; + } + + if( ndefT5TIsValidCache(ctx, blockNum) ) + { + /* Retrieve data from cache */ + (void)ST_MEMCPY(rxBuf, ctx->subCtx.t5t.cacheBuf, NDEF_T5T_TxRx_BUFF_HEADER_SIZE + (uint32_t)ctx->subCtx.t5t.blockLen); + *rcvLen = (uint16_t)NDEF_T5T_TxRx_BUFF_HEADER_SIZE + ctx->subCtx.t5t.blockLen; + + return ERR_NONE; + } + + uid = ctx->subCtx.t5t.uid; + flags = ctx->subCtx.t5t.flags; + + retry = NDEF_T5T_N_RETRY_ERROR; + do + { + if( ctx->subCtx.t5t.legacySTHighDensity ) + { +#if RFAL_FEATURE_ST25xV + ret = rfalST25xVPollerM24LRReadSingleBlock(flags, uid, blockNum, rxBuf, rxBufLen, rcvLen); +#else + ret = RFAL_ERR_NOTSUPP; +#endif + } + else + { + if( blockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR ) + { + ret = rfalNfcvPollerReadSingleBlock(flags, uid, (uint8_t)blockNum, rxBuf, rxBufLen, rcvLen); + } + else + { + ret = rfalNfcvPollerExtendedReadSingleBlock(flags, uid, blockNum, rxBuf, rxBufLen, rcvLen); + } + } + } + while( (retry-- != 0U) && rfalT5TIsTransmissionError(ret) ); + + if( ret == RFAL_ERR_NONE ) + { + /* Update cache */ + if( *rcvLen > 0U ) + { + (void)ST_MEMCPY(ctx->subCtx.t5t.cacheBuf, rxBuf, *rcvLen); + } + ctx->subCtx.t5t.cacheBlock = blockNum; + } + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + + +/*******************************************************************************/ +static ndefStatus ndefT5TPollerReadMultipleBlocks(ndefContext *ctx, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen) +{ + ReturnCode ret; + uint8_t flags; + const uint8_t* uid; + uint32_t retry; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + uid = ctx->subCtx.t5t.uid; + flags = ctx->subCtx.t5t.flags; + + /* 5.5 The number of data blocks returned by the Type 5 Tag in its response is (NB +1) + e.g. NumOfBlocks = 0 means reading 1 block */ + + retry = NDEF_T5T_N_RETRY_ERROR; + do + { + if( ctx->subCtx.t5t.legacySTHighDensity ) + { +#if RFAL_FEATURE_ST25xV + ret = rfalST25xVPollerM24LRReadMultipleBlocks(flags, uid, firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen); +#else + ret = RFAL_ERR_NOTSUPP; +#endif + } + else + { + if( firstBlockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR ) + { + ret = rfalNfcvPollerReadMultipleBlocks(flags, uid, (uint8_t)firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen); + } + else + { + ret = rfalNfcvPollerExtendedReadMultipleBlocks(flags, uid, firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen); + } + } + } + while( (retry-- != 0U) && rfalT5TIsTransmissionError(ret) ); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + + +#if NDEF_FEATURE_FULL_API + + +/*******************************************************************************/ +ndefStatus ndefT5TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len, bool pad, bool writeTerminator) +{ + ndefStatus res; + uint16_t nbRead; + uint16_t blockLen; + uint16_t startBlock; + uint16_t startAddr; + const uint8_t* wrbuf = buf; + uint32_t currentLen = len; + bool lvWriteTerminator = writeTerminator; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) || (buf == NULL) || (len == 0U) ) + { + return ERR_PARAM; + } + blockLen = (uint16_t)ctx->subCtx.t5t.blockLen; + if( blockLen == 0U ) + { + return ERR_SYSTEM; + } + startBlock = (uint16_t) (offset / blockLen); + startAddr = (uint16_t) (startBlock * blockLen); + + if (startAddr != offset) + { + /* Unaligned start offset must read the first block before */ + res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead); + if( res != ERR_NONE ) + { + return res; + } + if( nbRead != (blockLen + 1U) ) + { + return ERR_PROTO; + } + nbRead = (uint16_t) ((uint32_t)nbRead - 1U + startAddr - offset); + if (nbRead > (uint32_t)currentLen) + { + nbRead = (uint16_t)currentLen; + } + if (nbRead > 0U) + { + (void)ST_MEMCPY(&ctx->subCtx.t5t.txrxBuf[offset - startAddr + 1U], wrbuf, nbRead); + } + if( (offset - startAddr + nbRead) < blockLen ) + { + if( pad ) + { + (void)ST_MEMSET(&ctx->subCtx.t5t.txrxBuf[offset - startAddr + nbRead + 1U], 0x00, blockLen - (offset - startAddr + nbRead)); + } + if (lvWriteTerminator ) + { + ctx->subCtx.t5t.txrxBuf[offset - startAddr + nbRead + 1U] = NDEF_TERMINATOR_TLV_T; + lvWriteTerminator = false; + } + } + res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, &ctx->subCtx.t5t.txrxBuf[1U]); + if (res != ERR_NONE) + { + return res; + } + currentLen -= nbRead; + wrbuf = &wrbuf[nbRead]; + startBlock++; + } + while (currentLen >= blockLen) + { + res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, wrbuf); + if (res != ERR_NONE) + { + return res; + } + currentLen -= blockLen; + wrbuf = &wrbuf[blockLen]; + startBlock++; + } + if ( currentLen != 0U ) + { + if( pad ) + { + (void)ST_MEMSET(ctx->subCtx.t5t.txrxBuf, 0, (uint32_t)blockLen + 1U); + } + else + { + /* Unaligned end, must read the existing block before, except if padding */ + res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &nbRead); + if( res != ERR_NONE ) + { + return res; + } + if( nbRead != (blockLen + 1U) ) + { + return ERR_PROTO; + } + } + /* currentLen > 0U */ + (void)ST_MEMCPY(&ctx->subCtx.t5t.txrxBuf[1U], wrbuf, currentLen); + if( lvWriteTerminator ) + { + ctx->subCtx.t5t.txrxBuf[1U + currentLen] = NDEF_TERMINATOR_TLV_T; + lvWriteTerminator = false; + } + res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, &ctx->subCtx.t5t.txrxBuf[1U]); + if (res != ERR_NONE) + { + return res; + } + } + if( lvWriteTerminator ) + { + (void)ST_MEMSET(ctx->subCtx.t5t.txrxBuf, 0, (uint32_t)blockLen + 1U); + ctx->subCtx.t5t.txrxBuf[1U] = NDEF_TERMINATOR_TLV_T; + (void)ndefT5TPollerWriteSingleBlock(ctx, startBlock, &ctx->subCtx.t5t.txrxBuf[1U]); + } + return ERR_NONE; +} + + +/*******************************************************************************/ +ndefStatus ndefT5TIsDevicePresent(ndefContext *ctx) +{ + ndefStatus ret; + uint16_t blockAddr; + uint16_t rcvLen; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + ndefT5TInvalidateCache(ctx); + + blockAddr = 0U; + + ret = ndefT5TPollerReadSingleBlock(ctx, blockAddr, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen); + + return ret; +} + + +/*******************************************************************************/ +static ndefStatus ndefT5TPollerWriteSingleBlock(ndefContext *ctx, uint16_t blockNum, const uint8_t* wrData) +{ + ReturnCode ret; + uint8_t flags; + const uint8_t* uid; + uint32_t retry; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + uid = ctx->subCtx.t5t.uid; + flags = ctx->subCtx.t5t.flags; + if (ctx->cc.t5t.specialFrame) + { + flags |= (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION; + } + + ndefT5TInvalidateCache(ctx); + + retry = NDEF_T5T_N_RETRY_ERROR; + do + { + if( ctx->subCtx.t5t.legacySTHighDensity ) + { +#if RFAL_FEATURE_ST25xV + ret = rfalST25xVPollerM24LRWriteSingleBlock(flags, uid, blockNum, wrData, ctx->subCtx.t5t.blockLen); +#else + ret = ERR_NOTSUPP; +#endif + } + else + { + if( blockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR ) + { + ret = rfalNfcvPollerWriteSingleBlock(flags, uid, (uint8_t)blockNum, wrData, ctx->subCtx.t5t.blockLen); + } + else + { + ret = rfalNfcvPollerExtendedWriteSingleBlock(flags, uid, blockNum, wrData, ctx->subCtx.t5t.blockLen); + } + } + } + while( (retry-- != 0U) && rfalT5TIsTransmissionError(ret) ); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + + +/*******************************************************************************/ +static ndefStatus ndefT5TPollerLockSingleBlock(ndefContext *ctx, uint16_t blockNum) +{ + ReturnCode ret; + uint8_t flags; + const uint8_t* uid; + uint32_t retry; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + uid = ctx->subCtx.t5t.uid; + flags = ctx->subCtx.t5t.flags; + if (ctx->cc.t5t.specialFrame) + { + flags |= (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION; + } + + retry = NDEF_T5T_N_RETRY_ERROR; + do + { + if( blockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR ) + { + ret = rfalNfcvPollerLockBlock(flags, uid, (uint8_t)blockNum); + } + else + { + ret = rfalNfcvPollerExtendedLockSingleBlock(flags, uid, blockNum); + } + } + while( (retry-- != 0U) && rfalT5TIsTransmissionError(ret) ); + + return (ret == RFAL_ERR_NONE ? ERR_NONE : ERR_REQUEST); +} + + +/*******************************************************************************/ +ndefStatus ndefT5TLockDevice(ndefContext *ctx) +{ + ndefStatus ret; + uint32_t numBlocks; + uint16_t i; + + if( (ctx == NULL) || (ctx->type != NDEF_DEV_T5T) ) + { + return ERR_PARAM; + } + + ctx->state = NDEF_STATE_READONLY; + numBlocks = (ctx->areaLen + (uint32_t)ctx->cc.t5t.ccLen)/(uint32_t)ctx->subCtx.t5t.blockLen; + if( ctx->cc.t5t.lockBlock && !ctx->subCtx.t5t.legacySTHighDensity ) + { + for( i = 0; i < numBlocks; i++ ) + { + ret = ndefT5TPollerLockSingleBlock(ctx, i); + if( ret != ERR_NONE ) + { + return ret; + } + } + } + + return ERR_NONE; +} + +#endif /* NDEF_FEATURE_FULL_API */ + +#endif /* NDEF_FEATURE_T5T */ diff --git a/components/spi-st25r3911b/README.md b/components/spi-st25r3911b/README.md new file mode 100644 index 0000000..1cd5fb7 --- /dev/null +++ b/components/spi-st25r3911b/README.md @@ -0,0 +1 @@ +# ESP32 component: ST25R3911B e HF reader / NFC initiator with 1.4 W supporting VHBR and AAT diff --git a/components/spi-st25r3911b/component.mk b/components/spi-st25r3911b/component.mk new file mode 100644 index 0000000..369ec2e --- /dev/null +++ b/components/spi-st25r3911b/component.mk @@ -0,0 +1,3 @@ +# Component Makefile + +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/LICENCE b/components/spi-st25r3911b/en.STSW-ST25RFAL001/LICENCE new file mode 100644 index 0000000..d5b35a4 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/LICENCE @@ -0,0 +1,54 @@ +SLA0051 +SOFTWARE LICENSE AGREEMENT (“Agreement”) +BY CLICKING ON THE "I ACCEPT" BUTTON OR BY UNZIPPING, INSTALLING, COPYING, DOWNLOADING, ACCESSING +OR OTHERWISE USING THIS SOFTWARE (HEREINAFTER “SOFTWARE” MEANS THE RELATED SOFTWARE, +DOCUMENTATION, OTHER MATERIALS, AND ANY PARTS, PERMITTED MODIFICATIONS, AND PERMITTED +DERIVATIVES THEREOF) FROM STMICROELECTRONICS INTERNATIONAL N.V, SWISS BRANCH AND/OR ITS +AFFILIATED COMPANIES (“STMICROELECTRONICS”), THE RECIPIENT, ON BEHALF OF HIMSELF OR HERSELF, OR ON +BEHALF OF ANY ENTITY BY WHICH SUCH RECIPIENT IS EMPLOYED AND/OR ENGAGED (“YOU”) AGREES TO BE +BOUND BY THIS AGREEMENT. +You represent that you have the authority to enter into this Agreement. You will comply with all laws, including export laws. +STMicroelectronics’s failure or delay to enforce this Agreement does not waive STMicroelectronics’s rights. Swiss law, except +conflict of laws, governs this Agreement, and the parties consent to exclusive jurisdiction of courts in Switzerland for litigation of +this Agreement. +Subject to the below disclaimer, the redistribution, reproduction and use in source and binary forms of the software or any part +thereof, with or without modification, are permitted provided that the following conditions are met: +1. Redistribution of source code (modified or not) must retain any copyright notice, this list of conditions and the following +disclaimer. +2. Redistributions in binary form, except as embedded into a microcontroller or microprocessor device or a software update +for such device, must reproduce any copyright notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. Neither the name of STMicroelectronics nor the names of other contributors to this software may be used to endorse or +promote products using or derived from this software or part thereof without specific written permission. +4. This software or any part thereof, including modifications and/or derivative works of this software, must be used and +execute solely and exclusively in combination with an integrated circuit that is manufactured by or for STMicroelectronics +and is an NFC tag, NFC dynamic tag, NFC reader, or UHF reader. +5. No use, reproduction or redistribution of this software may be done in any manner that would subject this software to any +Open Source Terms. “Open Source Terms” shall mean any open source license which requires as part of distribution of +software that the source code of such software is distributed therewith or otherwise made available, or open source license +that substantially complies with the Open Source definition specified at www.opensource.org and any other comparable +open source license such as for example GNU General Public License (GPL), Eclipse Public License (EPL), Apache +Software License, BSD license and MIT license. +6. STMicroelectronics has no obligation to provide any maintenance, support or updates for the software. +7. The software is and will remain the exclusive property of STMicroelectronics and its licensors. The recipient will not take +any action that jeopardizes STMicroelectronics and its licensors' proprietary rights or acquire any rights in the software, +except the limited rights specified hereunder. +8. Redistribution and use of this software partially or any part thereof other than as permitted under this license is void and +will automatically terminate your rights under this license. +DISCLAIMER +THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS, +IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY +INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT +SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +EXCEPT AS EXPRESSLY PERMITTED HEREUNDER, NO LICENSE OR OTHER RIGHTS, WHETHER EXPRESS OR +IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF +STMICROELECTRONICS OR ANY THIRD PARTY. + + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_analogConfig.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_analogConfig.h new file mode 100644 index 0000000..bc1710b --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_analogConfig.h @@ -0,0 +1,433 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_AnalogConfig.h + * + * \author bkam + * + * \brief RF Chip Analog Configuration Settings + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup AnalogConfig + * \brief RFAL Analog Config Module + * @{ + * + */ + +#ifndef RFAL_ANALOG_CONFIG_H +#define RFAL_ANALOG_CONFIG_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ + +#define RFAL_ANALOG_CONFIG_LUT_SIZE (87U) /*!< Maximum number of Configuration IDs in the Loop Up Table */ +#define RFAL_ANALOG_CONFIG_LUT_NOT_FOUND (0xFFU) /*!< Index value indicating no Configuration IDs found */ + +#define RFAL_ANALOG_CONFIG_TBL_SIZE (1024U) /*!< Maximum number of Register-Mask-Value in the Setting List */ + +/* + ****************************************************************************** + * The Analog Configuration is structured as following + * +---------+-----------------------+-----------------------------+ + * | ModeID | Num RVM configuration | RVM (Register, Value, Mask) | + * | (16bit) | (8bit) | (24bit) | + * +---------+-----------------------+-----------------------------+ + * + * The Mode ID coding for different use cases is described below + * + * 1. ModeID coding for NFC technologies (not chip specific) + * +----------------------------------------------------------------------+ + * | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +----------------------------------------------------------------------+ + * | P/L | TECH != CHIP | BR | DIR | + * +----------------------------------------------------------------------+ + * + * 2. ModeID coding for chip specific modes and events + * +----------------------------------------------------------------------+ + * | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +----------------------------------------------------------------------+ + * | P/L | TECH == CHIP | CHIP_SPECIFIC | + * +----------------------------------------------------------------------+ + * + * 3. Special ModeID coding for Direction == DPO + * +----------------------------------------------------------------------+ + * | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +----------------------------------------------------------------------+ + * | P/L | DPO_LVL | TECH* | BR | DIR == DPO | + * +----------------------------------------------------------------------+ + * ^ + * | + * +----- reuse of TECH_RFU bits as DPO level indicator + ****************************************************************************** + */ + +/* Mask bit */ +#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK (0x8000U) /*!< Mask bit of Poll Mode in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_MASK (0x7F00U) /*!< Mask bits for Technology in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_MASK (0x00F0U) /*!< Mask bits for Bit rate in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_DIRECTION_MASK (0x000FU) /*!< Mask bits for Direction in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK (0x00FFU) /*!< Mask bits for Chip Specific Technology */ + +/* Shift values */ +#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_SHIFT (15U) /*!< Shift value of Poll Mode in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_SHIFT (8U) /*!< Shift value for Technology in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_SHIFT (4U) /*!< Shift value for Technology in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_DIRECTION_SHIFT (0U) /*!< Shift value for Direction in Analog Configuration ID */ + +/* P/L: bit 15 */ +#define RFAL_ANALOG_CONFIG_POLL (0x0000U) /*!< Poll Mode bit setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_LISTEN (0x8000U) /*!< Listen Mode bit setting in Analog Configuration ID */ + +/* TECH: bit 14-8 */ +#define RFAL_ANALOG_CONFIG_TECH_CHIP (0x0000U) /*!< Chip-Specific bit setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_NFCA (0x0100U) /*!< NFC-A Technology bits setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_NFCB (0x0200U) /*!< NFC-B Technology bits setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_NFCF (0x0400U) /*!< NFC-F Technology bits setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_AP2P (0x0800U) /*!< AP2P Technology bits setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_NFCV (0x1000U) /*!< NFC-V Technology bits setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_TECH_RFU (0x2000U) /*!< RFU for Technology bits */ +#define RFAL_ANALOG_CONFIG_TECH_RFU2 (0x4000U) /*!< RFU for Technology bits */ + +/* BR: bit 7-4 */ +#define RFAL_ANALOG_CONFIG_BITRATE_COMMON (0x0000U) /*!< Common settings for all bit rates in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_106 (0x0010U) /*!< 106kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_212 (0x0020U) /*!< 212kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_424 (0x0030U) /*!< 424kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_848 (0x0040U) /*!< 848kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_1695 (0x0050U) /*!< 1695kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_3390 (0x0060U) /*!< 3390kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_6780 (0x0070U) /*!< 6780kbits/s settings in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_211p88 (0x0090U) /*!< 211.88kbits/s (ISO15693 x8) in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_105p94 (0x00A0U) /*!< 105.94kbits/s (ISO15693 x4) in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_53 (0x00B0U) /*!< 53kbits/s (ISO15693 x2) setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_26 (0x00C0U) /*!< 26kbit/s (1 out of 4) NFC-V setting Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_1p6 (0x00D0U) /*!< 1.6kbit/s (1 out of 256) NFC-V setting Analog Config ID */ +#define RFAL_ANALOG_CONFIG_BITRATE_RFU (0x00E0U) /*!< RFU for Bitrate bits */ +#define RFAL_ANALOG_CONFIG_BITRATE_RFU2 (0x00F0U) /*!< RFU for Bitrate bits */ + +/* DIR: bit 3-0 */ +#define RFAL_ANALOG_CONFIG_NO_DIRECTION (0x0000U) /*!< No direction setting in Analog Conf ID (Chip Specific only) */ +#define RFAL_ANALOG_CONFIG_TX (0x0001U) /*!< Transmission bit setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_RX (0x0002U) /*!< Reception bit setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_ANTICOL (0x0003U) /*!< Anticollision setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_DPO (0x0004U) /*!< DPO setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_DLMA (0x0005U) /*!< DLMA setting in Analog Configuration ID */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU2 (0x0006U) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU3 (0x0007U) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU4 (0x0008U) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU5 (0x0009U) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU6 (0x000AU) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU7 (0x000BU) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU8 (0x000CU) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU9 (0x000DU) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU10 (0x000EU) /*!< RFU for Direction bits */ +#define RFAL_ANALOG_CONFIG_DIRECTION_RFU11 (0x000FU) /*!< RFU for Direction bits */ + +/* bit 7-0 */ +#define RFAL_ANALOG_CONFIG_CHIP_INIT (0x0000U) /*!< Chip-Specific event: Startup;Reset;Initialize */ +#define RFAL_ANALOG_CONFIG_CHIP_DEINIT (0x0001U) /*!< Chip-Specific event: Deinitialize */ +#define RFAL_ANALOG_CONFIG_CHIP_FIELD_ON (0x0002U) /*!< Chip-Specific event: Field On */ +#define RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF (0x0003U) /*!< Chip-Specific event: Field Off */ +#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON (0x0004U) /*!< Chip-Specific event: Wake-up On */ +#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF (0x0005U) /*!< Chip-Specific event: Wake-up Off */ +#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON (0x0006U) /*!< Chip-Specific event: Listen On */ +#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF (0x0007U) /*!< Chip-Specific event: Listen Off */ +#define RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON (0x0008U) /*!< Chip-Specific event: Poll common */ +#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON (0x0009U) /*!< Chip-Specific event: Listen common */ +#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON (0x000AU) /*!< Chip-Specific event: Low Power On */ +#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF (0x000BU) /*!< Chip-Specific event: Low Power Off */ + +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_00 (0x0010U) /*!< Chip-Specific event: Power Level 00 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_01 (0x0011U) /*!< Chip-Specific event: Power Level 01 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_02 (0x0012U) /*!< Chip-Specific event: Power Level 02 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_03 (0x0013U) /*!< Chip-Specific event: Power Level 03 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_04 (0x0014U) /*!< Chip-Specific event: Power Level 04 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_05 (0x0015U) /*!< Chip-Specific event: Power Level 05 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_06 (0x0016U) /*!< Chip-Specific event: Power Level 06 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_07 (0x0017U) /*!< Chip-Specific event: Power Level 07 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_08 (0x0018U) /*!< Chip-Specific event: Power Level 08 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_09 (0x0019U) /*!< Chip-Specific event: Power Level 09 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_10 (0x001AU) /*!< Chip-Specific event: Power Level 10 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_11 (0x001BU) /*!< Chip-Specific event: Power Level 11 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_12 (0x001CU) /*!< Chip-Specific event: Power Level 12 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_13 (0x001DU) /*!< Chip-Specific event: Power Level 13 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_14 (0x001EU) /*!< Chip-Specific event: Power Level 14 (e.g DPO, WLC) */ +#define RFAL_ANALOG_CONFIG_CHIP_POWER_LVL_15 (0x001FU) /*!< Chip-Specific event: Power Level 15 (e.g DPO, WLC) */ + +#define RFAL_ANALOG_CONFIG_UPDATE_LAST (0x00U) /*!< Value indicating Last configuration set during update */ +#define RFAL_ANALOG_CONFIG_UPDATE_MORE (0x01U) /*!< Value indicating More configuration set coming during update */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(id) (RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK & (id)) /*!< Check if id indicates Listen mode */ + +#define RFAL_ANALOG_CONFIG_ID_GET_TECH(id) (RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Get the technology of Configuration ID */ +#define RFAL_ANALOG_CONFIG_ID_IS_CHIP(id) (RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Check if ID indicates Chip-specific */ +#define RFAL_ANALOG_CONFIG_ID_IS_NFCA(id) (RFAL_ANALOG_CONFIG_TECH_NFCA & (id)) /*!< Check if ID indicates NFC-A */ +#define RFAL_ANALOG_CONFIG_ID_IS_NFCB(id) (RFAL_ANALOG_CONFIG_TECH_NFCB & (id)) /*!< Check if ID indicates NFC-B */ +#define RFAL_ANALOG_CONFIG_ID_IS_NFCF(id) (RFAL_ANALOG_CONFIG_TECH_NFCF & (id)) /*!< Check if ID indicates NFC-F */ +#define RFAL_ANALOG_CONFIG_ID_IS_AP2P(id) (RFAL_ANALOG_CONFIG_TECH_AP2P & (id)) /*!< Check if ID indicates AP2P */ +#define RFAL_ANALOG_CONFIG_ID_IS_NFCV(id) (RFAL_ANALOG_CONFIG_TECH_NFCV & (id)) /*!< Check if ID indicates NFC-V */ + +#define RFAL_ANALOG_CONFIG_ID_GET_BITRATE(id) (RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Get Bitrate of Configuration ID */ +#define RFAL_ANALOG_CONFIG_ID_IS_COMMON(id) (RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Check if ID indicates common bitrate */ +#define RFAL_ANALOG_CONFIG_ID_IS_106(id) (RFAL_ANALOG_CONFIG_BITRATE_106 & (id)) /*!< Check if ID indicates 106kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_212(id) (RFAL_ANALOG_CONFIG_BITRATE_212 & (id)) /*!< Check if ID indicates 212kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_424(id) (RFAL_ANALOG_CONFIG_BITRATE_424 & (id)) /*!< Check if ID indicates 424kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_848(id) (RFAL_ANALOG_CONFIG_BITRATE_848 & (id)) /*!< Check if ID indicates 848kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_1695(id) (RFAL_ANALOG_CONFIG_BITRATE_1695 & (id)) /*!< Check if ID indicates 1695kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_3390(id) (RFAL_ANALOG_CONFIG_BITRATE_3390 & (id)) /*!< Check if ID indicates 3390kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_6780(id) (RFAL_ANALOG_CONFIG_BITRATE_6780 & (id)) /*!< Check if ID indicates 6780kbits/s */ +#define RFAL_ANALOG_CONFIG_ID_IS_26(id) (RFAL_ANALOG_CONFIG_BITRATE_26 & (id)) /*!< Check if ID indicates 1 out of 4 bitrate */ +#define RFAL_ANALOG_CONFIG_ID_IS_1p6(id) (RFAL_ANALOG_CONFIG_BITRATE_1p6 & (id)) /*!< Check if ID indicates 1 out of 256 bitrate */ + +#define RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(id) (RFAL_ANALOG_CONFIG_DIRECTION_MASK & (id)) /*!< Get Direction of Configuration ID */ +#define RFAL_ANALOG_CONFIG_ID_IS_TX(id) (RFAL_ANALOG_CONFIG_TX & (id)) /*!< Check if id indicates TX */ +#define RFAL_ANALOG_CONFIG_ID_IS_RX(id) (RFAL_ANALOG_CONFIG_RX & (id)) /*!< Check if id indicates RX */ + +#define RFAL_ANALOG_CONFIG_CONFIG_NUM(x) (sizeof(x)/sizeof((x)[0])) /*!< Get Analog Config number */ + +/*! Set Analog Config ID value by: Mode, Technology, Bitrate and Direction */ +#define RFAL_ANALOG_CONFIG_ID_SET(mode, tech, br, direction) \ + ( RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(mode) \ + | RFAL_ANALOG_CONFIG_ID_GET_TECH(tech) \ + | RFAL_ANALOG_CONFIG_ID_GET_BITRATE(br) \ + | RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(direction) \ + ) + +/* + ****************************************************************************** + * GLOBAL DATA TYPES + ****************************************************************************** + */ + +typedef uint8_t rfalAnalogConfigMode; /*!< Polling or Listening Mode of Configuration */ +typedef uint8_t rfalAnalogConfigTech; /*!< Technology of Configuration */ +typedef uint8_t rfalAnalogConfigBitrate; /*!< Bitrate of Configuration */ +typedef uint8_t rfalAnalogConfigDirection; /*!< Transmit/Receive direction of Configuration */ + +typedef uint8_t rfalAnalogConfigRegAddr[2]; /*!< Register Address to ST Chip */ +typedef uint8_t rfalAnalogConfigRegMask; /*!< Register Mask Value */ +typedef uint8_t rfalAnalogConfigRegVal; /*!< Register Value */ + +typedef uint16_t rfalAnalogConfigId; /*!< Analog Configuration ID */ +typedef uint16_t rfalAnalogConfigOffset; /*!< Analog Configuration offset address in the table */ +typedef uint8_t rfalAnalogConfigNum; /*!< Number of Analog settings for the respective Configuration ID */ + + +/*! Struct that contain the Register-Mask-Value set. Make sure that the whole structure size is even and unaligned! */ +typedef struct { + rfalAnalogConfigRegAddr addr; /*!< Register Address */ + rfalAnalogConfigRegMask mask; /*!< Register Mask Value */ + rfalAnalogConfigRegVal val; /*!< Register Value */ +} rfalAnalogConfigRegAddrMaskVal; + + +/*! Struct that represents the Analog Configs */ +typedef struct { + uint8_t id[sizeof(rfalAnalogConfigId)]; /*!< Configuration ID */ + rfalAnalogConfigNum num; /*!< Number of Config Sets to follow */ + rfalAnalogConfigRegAddrMaskVal regSet[]; /*!< Register-Mask-Value sets */ /* PRQA S 1060 # MISRA 18.7 - Flexible Array Members are the only meaningful way of denoting a variable length input buffer which follows a fixed header structure. */ +} rfalAnalogConfig; + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Initialize the Analog Configuration + * + * Reset the Analog Configuration LUT pointer to reference to default settings. + * + ***************************************************************************** + */ +void rfalAnalogConfigInitialize( void ); + + +/*! + ***************************************************************************** + * \brief Indicate if the current Analog Configuration Table is complete and ready to be used. + * + * \return true if current Analog Configuration Table is complete and ready to be used. + * \return false if current Analog Configuration Table is incomplete + * + ***************************************************************************** + */ +bool rfalAnalogConfigIsReady( void ); + + +/*! + ***************************************************************************** + * \brief Write the whole Analog Configuration table in raw format + * + * Writes the Analog Configuration and Look Up Table with the given raw table + * + * NOTE: Function does not check the validity of the given Table contents + * + * \param[in] configTbl : location of config Table to be loaded + * \param[in] configTblSize : size of the config Table to be loaded + * + * \return RFAL_ERR_NONE : if setting is updated + * \return RFAL_ERR_PARAM : if configTbl is invalid + * \return RFAL_ERR_NOMEM : if the given Table is bigger exceeds the max size + * \return RFAL_ERR_REQUEST : if the update Configuration Id is disabled + * + ***************************************************************************** + */ +ReturnCode rfalAnalogConfigListWriteRaw( const uint8_t *configTbl, uint16_t configTblSize ); + + +/*! + ***************************************************************************** + * \brief Write the Analog Configuration table with new analog settings. + * + * Writes the Analog Configuration and Look Up Table with the new list of register-mask-value + * and Configuration ID respectively. + * + * NOTE: Function does not check for the validity of the Register Address. + * + * \param[in] more : 0x00 indicates it is last Configuration ID settings; + * 0x01 indicates more Configuration ID setting(s) are coming. + * \param[in] *config : reference to the configuration list of current Configuraiton ID. + * + * \return RFAL_ERR_PARAM : if Configuration ID or parameter is invalid + * \return RFAL_ERR_NOMEM : if LUT is full + * \return RFAL_ERR_REQUEST : if the update Configuration Id is disabled + * \return RFAL_ERR_NONE : if setting is updated + * + ***************************************************************************** + */ +ReturnCode rfalAnalogConfigListWrite( uint8_t more, const rfalAnalogConfig *config ); + + +/*! + ***************************************************************************** + * \brief Read the whole Analog Configuration table in raw format + * + * Reads the whole Analog Configuration Table in raw format + * + * \param[out] tblBuf : location to the buffer to place the Config Table + * \param[in] tblBufLen : length of the buffer to place the Config Table + * \param[out] configTblSize : Config Table size + * + * \return RFAL_ERR_PARAM : if configTbl or configTblSize is invalid + * \return RFAL_ERR_NOMEM : if configTblSize is not enough for the whole table + * \return RFAL_ERR_NONE : if read is successful + * + ***************************************************************************** + */ +ReturnCode rfalAnalogConfigListReadRaw( uint8_t *tblBuf, uint16_t tblBufLen, uint16_t *configTblSize ); + + +/*! + ***************************************************************************** + * \brief Read the Analog Configuration table. + * + * Read the Analog Configuration Table + * + * \param[in] configOffset : offset to the next Configuration ID in the List Table to be read. + * \param[out] more : 0x00 indicates it is last Configuration ID settings; + * 0x01 indicates more Configuration ID setting(s) are coming. + * \param[out] config : configuration id, number of configuration sets and register-mask-value sets + * \param[in] numConfig : the remaining configuration settings space available; + * + * \return RFAL_ERR_NOMEM : if number of Configuration for respective Configuration ID is greater the the remaining configuration setting space available + * \return RFAL_ERR_NONE : if read is successful + * + ***************************************************************************** + */ +ReturnCode rfalAnalogConfigListRead( rfalAnalogConfigOffset *configOffset, uint8_t *more, rfalAnalogConfig *config, rfalAnalogConfigNum numConfig ); + + +/*! + ***************************************************************************** + * \brief Set the Analog settings of indicated Configuration ID. + * + * Update the chip with indicated analog settings of indicated Configuration ID. + * + * \param[in] configId : configuration ID + * + * \return RFAL_ERR_PARAM : if Configuration ID is invalid + * \return RFAL_ERR_INTERNAL : if error updating setting to chip + * \return RFAL_ERR_NONE : if new settings is applied to chip + * + ***************************************************************************** + */ +ReturnCode rfalSetAnalogConfig( rfalAnalogConfigId configId ); + + +/*! + ***************************************************************************** + * \brief Generates Analog Config mode ID + * + * Converts RFAL mode and bitrate into Analog Config Mode ID. + * + * Update the chip with indicated analog settings of indicated Configuration ID. + * + * \param[in] md : RFAL mode format + * \param[in] br : RFAL bit rate format + * \param[in] dir : Analog Config communication direction + * + * \return Analog Config Mode ID + * + ***************************************************************************** + */ +uint16_t rfalAnalogConfigGenModeID( rfalMode md, rfalBitRate br, uint16_t dir ); + + +#endif /* RFAL_ANALOG_CONFIG_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_cd.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_cd.h new file mode 100644 index 0000000..cc526ae --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_cd.h @@ -0,0 +1,179 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2019 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: ST25R firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_cd.h + * + * \author + * + * \brief Implementation of a Card Detection Algorithm + * + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HL + * \brief RFAL Higher Layer + * @{ + * + * \addtogroup CD + * \brief RFAL Card Detection + * @{ + * + */ + +#ifndef RFAL_CD_H +#define RFAL_CD_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! Card Detection NFC technology type */ +typedef enum +{ + RFAL_CD_TECH_NONE = 0x00, /*!< No NFC Technology */ + RFAL_CD_TECH_NFCA = 0x01, /*!< NFC Technology NFCB */ + RFAL_CD_TECH_NFCB = 0x02, /*!< NFC Technology NFCB */ + RFAL_CD_TECH_NFCF = 0x04, /*!< NFC Technology NFCF */ + RFAL_CD_TECH_NFCV = 0x08, /*!< NFC Technology NFCV */ + RFAL_CD_TECH_OTHER = 0x10 /*!< NFC Technology OTHER */ +}rfalCdTech; + + +/*! Card Detection result|outcome type */ +typedef enum +{ + RFAL_CD_NOT_FOUND = 0, /* 1 + * \param[in] values : pointer with content to be written on the register(s) + * \param[in] len : number of consecutive registers to be written + * + * + * \return RFAL_ERR_PARAM : Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : Write done with no error + ***************************************************************************** + */ +ReturnCode rfalChipWriteReg( uint16_t reg, const uint8_t* values, uint8_t len ); + +/*! + ***************************************************************************** + * \brief Reads a register on the RF Chip + * + * Checks if the given register is valid and if so, reads the value(s) + * of the RF Chip register(s) + * + * \param[in] reg : register address to be read, or the first if len > 1 + * \param[out] values : pointer where the register(s) read content will be placed + * \param[in] len : number of consecutive registers to be read + * + * \return RFAL_ERR_PARAM : Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : Read done with no error + ***************************************************************************** + */ +ReturnCode rfalChipReadReg( uint16_t reg, uint8_t* values, uint8_t len ); + +/*! + ***************************************************************************** + * \brief Change a register on the RF Chip + * + * Change the value of the register bits on the RF Chip Test set in the valueMask. + * + * \param[in] reg : register address to be modified + * \param[in] valueMask : mask value of the register bits to be changed + * \param[in] value : register value to be set + * + * \return RFAL_ERR_PARAM : Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_OK : Change done with no error + ***************************************************************************** + */ +ReturnCode rfalChipChangeRegBits( uint16_t reg, uint8_t valueMask, uint8_t value ); + +/*! + ***************************************************************************** + * \brief Writes a Test register on the RF Chip + * + * Writes the value on the RF Chip Test register + * + * \param[in] reg : register address to be written + * \param[in] value : value to be written on the register + * + * + * \return RFAL_ERR_PARAM : Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : Write done with no error + ***************************************************************************** + */ +ReturnCode rfalChipWriteTestReg( uint16_t reg, uint8_t value ); + +/*! + ***************************************************************************** + * \brief Reads a Test register on the RF Chip + * + * Reads the value of the RF Chip Test register + * + * \param[in] reg : register address to be read + * \param[out] value : pointer where the register content will be placed + * + * \return RFAL_ERR_PARAM :Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : Read done with no error + ***************************************************************************** + */ +ReturnCode rfalChipReadTestReg( uint16_t reg, uint8_t* value ); + +/*! + ***************************************************************************** + * \brief Change a Test register on the RF Chip + * + * Change the value of the register bits on the RF Chip Test set in the valueMask. + * + * \param[in] reg : test register address to be modified + * \param[in] valueMask : mask value of the register bits to be changed + * \param[in] value : register value to be set + * + * \return RFAL_ERR_PARAM : Invalid register or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_OK : Change done with no error + ***************************************************************************** + */ +ReturnCode rfalChipChangeTestRegBits( uint16_t reg, uint8_t valueMask, uint8_t value ); + +/*! + ***************************************************************************** + * \brief Execute command on the RF Chip + * + * Checks if the given command is valid and if so, executes it on + * the RF Chip + * + * \param[in] cmd : direct command to be executed + * + * \return RFAL_ERR_PARAM : Invalid command or bad request + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : Direct command executed with no error + ***************************************************************************** + */ +ReturnCode rfalChipExecCmd( uint16_t cmd ); + +/*! + ***************************************************************************** + * \brief Set RFO + * + * Sets the RFO driver resistance value used when the + * field is on (unmodulated/active) + * + * \param[in] rfo : the RFO value to be used + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipSetRFO( uint8_t rfo ); + + +/*! + ***************************************************************************** + * \brief Get RFO + * + * Gets the RFO driver resistance value used when the + * field is on (unmodulated/active) + * + * \param[out] result : the current RFO value + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipGetRFO( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Get LM Field Indicator + * + * Gets an indicator of the signal on RFI while in Passive Listen Mode + * + * \param[out] result : the current RFI value + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipGetLmFieldInd( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief Set Listen Mode Modulation + * + * Sets the modulation (modulated and unmodulated state) when Passive Listen + * Mode is used + * + * \param[in] mod : modulation to be used in modulated state + * \param[in] unmod : modulation to be used in unmodulated state + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipSetLMMod( uint8_t mod, uint8_t unmod ); + + +/*! + ***************************************************************************** + * \brief Get Listen Mode Modulation + * + * Gets the modulation (modulated and unmodulated state) when Passive Listen + * Mode is used + * + * \param[out] mod : modulation set in modulated state + * \param[out] unmod : modulation set in unmodulated state + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipGetLMMod( uint8_t* mod, uint8_t* unmod ); + + +/*! + ***************************************************************************** + * \brief Measure Amplitude + * + * Measures the RF Amplitude + * + * \param[out] result : result of RF measurement + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasureAmplitude( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Measure Phase + * + * Measures the Phase + * + * \param[out] result : result of Phase measurement + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasurePhase( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Measure Capacitance + * + * Measures the Capacitance + * + * \param[out] result : result of Capacitance measurement + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasureCapacitance( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Measure Power Supply + * + * Measures the Power Supply + * + * \param[in] param : measurement parameter (chip specific) + * \param[out] result : result of the measurement + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasurePowerSupply( uint8_t param, uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Measure I and Q + * + * Measures I and Q channels + * + * \param[out] resI : 8 bit long result of the I channel (signed) + * \param[out] resQ : 8 bit long result of the Q channel (signed) + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasureIQ( int8_t* resI, int8_t* resQ ); + + +/*! + ***************************************************************************** + * \brief Measure combined I and Q + * + * Measures I and Q channels and combines them + * + * \param[out] result : I and Q combined + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipMeasureCombinedIQ( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Set Antenna mode + * + * Sets the antenna mode. + * Differential or single ended antenna mode (RFO1 or RFO2) + * + * \param[in] single : FALSE differential ; single ended mode + * \param[in] rfiox : FALSE RFI1/RFO1 ; TRUE RFI2/RFO2 + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalChipSetAntennaMode( bool single, bool rfiox ); + +#endif /* RFAL_CHIP_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_defConfig.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_defConfig.h new file mode 100644 index 0000000..67e82c3 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_defConfig.h @@ -0,0 +1,330 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_defConfig.h + * + * \author Gustavo Patricio + * + * \brief RF Abstraction Layer (RFAL) default Config file + * + * This file contains a base/default configuration for the + * RFAL library. + * Users can and shall define their on configuration acording + * to their speficic system needs on rfal_platform.h. + * + * \addtogroup RFAL + * @{ + * + */ + +#ifndef RFAL_CONFIG_H +#define RFAL_CONFIG_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_features.h" + + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + + +/* +****************************************************************************** +* RFAL FEATURES DEFAULT CONFIGURATION +****************************************************************************** +*/ +#ifndef RFAL_FEATURE_LISTEN_MODE + #if RFAL_SUPPORT_CE || RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P + #define RFAL_FEATURE_LISTEN_MODE true /*!< Enable RFAL support for Listen Mode */ + #endif /* SUPPORT LISTEN_MODE */ +#endif /* RFAL_FEATURE_LISTEN_MODE */ + + +#ifndef RFAL_FEATURE_WAKEUP_MODE + #define RFAL_FEATURE_WAKEUP_MODE true /*!< Enable RFAL support for the Wake-Up mode */ +#endif /* RFAL_FEATURE_WAKEUP_MODE */ + + +#ifndef RFAL_FEATURE_LOWPOWER_MODE + #define RFAL_FEATURE_LOWPOWER_MODE false /*!< RFAL support for the Low Power mode, Disabled by default */ +#endif /* RFAL_FEATURE_LOWPOWER_MODE */ + + +#ifndef RFAL_FEATURE_NFCA + #if RFAL_SUPPORT_MODE_POLL_NFCA + #define RFAL_FEATURE_NFCA true /*!< Enable RFAL support for NFC-A (ISO14443A) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCA */ +#endif /* RFAL_FEATURE_NFCA */ + + +#ifndef RFAL_FEATURE_T1T + #if RFAL_SUPPORT_MODE_POLL_NFCA + #define RFAL_FEATURE_T1T true /*!< Enable RFAL support for T1T (Topaz) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCA */ +#endif /* RFAL_FEATURE_T1T */ + +#ifndef RFAL_FEATURE_T2T + #if RFAL_SUPPORT_MODE_POLL_NFCA + #define RFAL_FEATURE_T2T true /*!< Enable RFAL support for T2T */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCA */ +#endif /* RFAL_FEATURE_T2T */ + +#ifndef RFAL_FEATURE_T4T + #if RFAL_SUPPORT_MODE_POLL_NFCA + #define RFAL_FEATURE_T4T true /*!< Enable RFAL support for T4T */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCA */ +#endif /* RFAL_FEATURE_T2T */ + + +#ifndef RFAL_FEATURE_NFCB + #if RFAL_SUPPORT_MODE_POLL_NFCB + #define RFAL_FEATURE_NFCB true /*!< Enable RFAL support for NFC-B (ISO14443B) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCB */ +#endif /* RFAL_FEATURE_NFCB */ + + +#ifndef RFAL_FEATURE_ST25TB + #if RFAL_SUPPORT_MODE_POLL_NFCB + #define RFAL_FEATURE_ST25TB true /*!< Enable RFAL support for ST25TB */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCB */ +#endif /* RFAL_FEATURE_ST25TB */ + + +#ifndef RFAL_FEATURE_NFCF + #if RFAL_SUPPORT_MODE_POLL_NFCF + #define RFAL_FEATURE_NFCF true /*!< Enable RFAL support for NFC-F (FeliCa) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCF */ +#endif /* RFAL_FEATURE_NFCF */ + + +#ifndef RFAL_FEATURE_NFCV + #if RFAL_SUPPORT_MODE_POLL_NFCV + #define RFAL_FEATURE_NFCV true /*!< Enable RFAL support for NFC-V (ISO15693) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCV */ +#endif /* RFAL_FEATURE_NFCV */ + + +#ifndef RFAL_FEATURE_ISO_DEP + #if RFAL_SUPPORT_MODE_POLL_NFCA || RFAL_SUPPORT_MODE_POLL_NFCB || RFAL_SUPPORT_CE + #define RFAL_FEATURE_ISO_DEP true /*!< Enable RFAL support for ISO-DEP (ISO14443-4) */ + #endif /* RFAL_SUPPORT_MODE_ */ +#endif /* RFAL_FEATURE_ISO_DEP */ + + +#ifndef RFAL_FEATURE_ISO_DEP_POLL + #if RFAL_SUPPORT_MODE_POLL_NFCA || RFAL_SUPPORT_MODE_POLL_NFCB + #define RFAL_FEATURE_ISO_DEP_POLL true /*!< Enable RFAL support for Poller mode (PCD) ISO-DEP (ISO14443-4) */ + #endif /* RFAL_SUPPORT_MODE_ */ +#endif /* RFAL_FEATURE_ISO_DEP */ + + +#ifndef RFAL_FEATURE_ISO_DEP_LISTEN + #if RFAL_SUPPORT_CE + #define RFAL_FEATURE_ISO_DEP_LISTEN true /*!< Enable RFAL support for Listen mode (PICC) ISO-DEP (ISO14443-4) */ + #endif /* RFAL_SUPPORT_MODE_ */ +#endif /* RFAL_FEATURE_ISO_DEP */ + + +#ifndef RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN + #if RFAL_FEATURE_ISO_DEP + #define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN 256U /*!< ISO-DEP I-Block max length. Please use values as defined by rfalIsoDepFSx */ + #endif /* RFAL_FEATURE_ISO_DEP */ +#endif /* RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN */ + + +#ifndef RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN + #if RFAL_FEATURE_ISO_DEP + #define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN 512U /*!< ISO-DEP APDU max length. */ + #endif /* RFAL_FEATURE_ISO_DEP */ +#endif /* RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN */ + + +#ifndef RFAL_FEATURE_NFC_DEP + #if RFAL_SUPPORT_MODE_POLL_NFCA && RFAL_SUPPORT_MODE_POLL_NFCF + #define RFAL_FEATURE_NFC_DEP true /*!< Enable RFAL support for NFC-DEP (NFCIP1/P2P) */ + #endif /* RFAL_SUPPORT_MODE_POLL_NFCA/F */ +#endif /* RFAL_FEATURE_NFC_DEP */ + + +#ifndef RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN + #if RFAL_FEATURE_NFC_DEP + #define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN 254U /*!< NFC-DEP Block/Payload length. Allowed values: 64, 128, 192, 254 */ + #endif /* RFAL_FEATURE_NFC_DEP */ +#endif /* RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN */ + + +#ifndef RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN + #if RFAL_FEATURE_NFC_DEP + #define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 512U /*!< NFC-DEP PDU max length. */ + #endif /* RFAL_FEATURE_NFC_DEP */ +#endif /* RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN */ + + +#ifndef RFAL_FEATURE_NFC_RF_BUF_LEN + #define RFAL_FEATURE_NFC_RF_BUF_LEN 258U /*!< RF buffer length used by RFAL NFC layer */ +#endif /* RFAL_FEATURE_NFC_RF_BUF_LEN */ + + +#ifndef RFAL_FEATURE_ST25xV + #define RFAL_FEATURE_ST25xV false /*!< ST25xV Module configuration missing. Disabled by default */ +#endif + + +#ifndef RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + #define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG false /*!< Dynamic Analog Configs configuration missing. Disabled by default */ +#endif + + +#ifndef RFAL_FEATURE_DPO + #define RFAL_FEATURE_DPO false /*!< Dynamic Power Module configuration missing. Disabled by default */ +#endif + +#ifndef RFAL_FEATURE_DLMA + #define RFAL_FEATURE_DLMA false /*!< Dynamic LMA Module configuration missing. Disabled by default */ +#endif + + + + + /* + ****************************************************************************** + * RFAL OPTIONAL MACROS + ****************************************************************************** + */ + +#ifndef platformProtectST25RIrqStatus + #define platformProtectST25RIrqStatus() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */ +#endif /* platformProtectST25RIrqStatus */ + +#ifndef platformUnprotectST25RIrqStatus + #define platformUnprotectST25RIrqStatus() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */ +#endif /* platformUnprotectST25RIrqStatus */ + +#ifndef platformProtectWorker + #define platformProtectWorker() /*!< Protect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */ +#endif /* platformProtectWorker */ + +#ifndef platformUnprotectWorker + #define platformUnprotectWorker() /*!< Unprotect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */ +#endif /* platformUnprotectWorker */ + +#ifndef platformIrqST25RPinInitialize + #define platformIrqST25RPinInitialize() /*!< Initializes ST25R IRQ pin */ +#endif /* platformIrqST25RPinInitialize */ + +#ifndef platformIrqST25RSetCallback + #define platformIrqST25RSetCallback( cb ) /*!< Sets ST25R ISR callback */ +#endif /* platformIrqST25RSetCallback */ + +#ifndef platformLedsInitialize + #define platformLedsInitialize() /*!< Initializes the pins used as LEDs to outputs */ +#endif /* platformLedsInitialize */ + +#ifndef platformLedOff + #define platformLedOff( port, pin ) /*!< Turns the given LED Off */ +#endif /* platformLedOff */ + +#ifndef platformLedOn + #define platformLedOn( port, pin ) /*!< Turns the given LED On */ +#endif /* platformLedOn */ + +#ifndef platformLedToggle + #define platformLedToggle( port, pin ) /*!< Toggles the given LED */ +#endif /* platformLedToggle */ + + +#ifndef platformGetSysTick + #define platformGetSysTick() /*!< Get System Tick ( 1 tick = 1 ms) */ +#endif /* platformGetSysTick */ + +#ifndef platformTimerDestroy + #define platformTimerDestroy( timer ) /*!< Stops and released the given timer */ +#endif /* platformTimerDestroy */ + +#ifndef platformLog + #define platformLog(...) /*!< Log method */ +#endif /* platformLog */ + +#ifndef platformAssert + #define platformAssert( exp ) /*!< Asserts whether the given expression is true */ +#endif /* platformAssert */ + +#ifndef platformErrorHandle + #define platformErrorHandle() /*!< Global error handler or trap */ +#endif /* platformErrorHandle */ + + +#ifdef RFAL_USE_I2C + + #ifndef platformSpiTxRx + #define platformSpiTxRx( txBuf, rxBuf, len ) /*!< SPI transceive */ + #endif /* platformSpiTxRx */ + +#else /* RFAL_USE_I2C */ + + #ifndef platformI2CTx + #define platformI2CTx( txBuf, len, last, txOnly ) /*!< I2C Transmit */ + #endif /* platformI2CTx */ + + #ifndef platformI2CRx + #define platformI2CRx( txBuf, len ) /*!< I2C Receive */ + #endif /* platformI2CRx */ + + #ifndef platformI2CStart + #define platformI2CStart() /*!< I2C Start condition */ + #endif /* platformI2CStart */ + + #ifndef platformI2CStop + #define platformI2CStop() /*!< I2C Stop condition */ + #endif /* platformI2CStop */ + + #ifndef platformI2CRepeatStart + #define platformI2CRepeatStart() /*!< I2C Repeat Start */ + #endif /* platformI2CRepeatStart */ + + #ifndef platformI2CSlaveAddrWR + #define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write operation */ + #endif /* platformI2CSlaveAddrWR */ + + #ifndef platformI2CSlaveAddrRD + #define platformI2CSlaveAddrRD(add) /*!< I2C Slave address for Read operation */ + #endif /* platformI2CSlaveAddrRD */ + +#endif /* RFAL_USE_I2C */ + +#endif /* RFAL_CONFIG_H */ + + +/** + * @} + * + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_dpo.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_dpo.h new file mode 100644 index 0000000..732021d --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_dpo.h @@ -0,0 +1,215 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * $Revision: $ + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_dpo.h + * + * \author Martin Zechleitner + * + * \brief Dynamic Power adjustment + * + * This module provides an interface to perform the power adjustment dynamically + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup DPO + * \brief RFAL Dynamic Power Module + * @{ + * + */ + + +#ifndef RFAL_DPO_H +#define RFAL_DPO_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_DPO_TABLE_MAX_ENTRIES 4U /*!< Max DPO table entries */ +#define RFAL_DPO_TABLE_PARAM_LEN sizeof(rfalDpoEntry) /*!< DPO Parameter length */ +#define RFAL_DPO_TABLE_SIZE_MAX (RFAL_DPO_TABLE_MAX_ENTRIES * RFAL_DPO_TABLE_PARAM_LEN) /*!< Max DPO table size */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! DPO table entry struct */ +typedef struct { + uint8_t rfoRes; /*!< Setting for the resistance level of the RFO */ + uint8_t inc; /*!< Threshold for incrementing the output power */ + uint8_t dec; /*!< Threshold for decrementing the output power */ +}rfalDpoEntry; + +/*! Function pointer to methode doing the reference measurement */ +typedef ReturnCode (*rfalDpoMeasureFunc)(uint8_t*); + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + + +/*! + ***************************************************************************** + * \brief Initialize dynamic power table + * + * This function sets the internal dynamic power table to the default + * values stored in rfal_DpoTbl.h + * + ***************************************************************************** + */ +void rfalDpoInitialize( void ); + +/*! + ***************************************************************************** + * \brief Set the measurement methode + * + * This function sets the measurement method used for reference measurement. + * Based on the measurement the power will then be adjusted + * + * \param[in] pFunc: callback of measurement function + * + ***************************************************************************** + */ +void rfalDpoSetMeasureCallback( rfalDpoMeasureFunc pFunc ); + +/*! + ***************************************************************************** + * \brief Write dynamic power table + * + * Load the dynamic power table + * + * \param[in] powerTbl : location of power Table to be loaded + * \param[in] powerTblEntries : number of entries of the power Table to be loaded + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_PARAM : if configTbl is invalid + * \return RFAL_ERR_NOMEM : if the given Table is bigger exceeds the max size + ***************************************************************************** + */ +ReturnCode rfalDpoTableWrite( const rfalDpoEntry* powerTbl, uint8_t powerTblEntries ); + +/*! + ***************************************************************************** + * \brief Dynamic power table Read + * + * Read the dynamic power table + * + * \param[out] tblBuf : location to the rfalDpoEntry[] to place the Table + * \param[in] tblBufEntries : number of entries available in tblBuf to place the power Table + * \param[out] tableEntries : returned number of entries actually written into tblBuf + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_PARAM : if configTbl is invalid or parameters are invalid + ***************************************************************************** + */ +ReturnCode rfalDpoTableRead( rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries ); + +/*! + ***************************************************************************** + * \brief Dynamic power adjust + * + * It measures the current output and adjusts the power accordingly to + * the dynamic power table + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_PARAM : if configTbl is invalid or parameters are invalid + * \return RFAL_ERR_WRONG_STATE : if the current state is valid for DPO Adjustment + ***************************************************************************** + */ +ReturnCode rfalDpoAdjust( void ); + +/*! + ***************************************************************************** + * \brief Get Current Dynamic power table entry + * + * Return current used DPO power table entry settings + * + * \return RFAL_ERR_NONE : Current DpoEntry. This includes d_res, inc and dec + * + ***************************************************************************** + */ +rfalDpoEntry* rfalDpoGetCurrentTableEntry(void); + +/*! + ***************************************************************************** + * \brief Get Current Dynamic power table index + * + * \return the index currently used DPO table entry + * + ***************************************************************************** + */ +uint8_t rfalDpoGetCurrentTableIndex( void ); + +/*! + ***************************************************************************** + * \brief Dynamic power set enabled state + * + * \param[in] enable : new active state + * + * Set state to enable or disable the Dynamic power adjustment + * + ***************************************************************************** + */ +void rfalDpoSetEnabled( bool enable ); + +/*! + ***************************************************************************** + * \brief Get the Dynamic power enabled state + * + * Get state of the Dynamic power adjustment + * + * \return true : enabled + * \return false : disabled + ***************************************************************************** + */ +bool rfalDpoIsEnabled(void); + +#endif /* RFAL_DPO_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_isoDep.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_isoDep.h new file mode 100644 index 0000000..1ebae8b --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_isoDep.h @@ -0,0 +1,1041 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_isoDep.h + * + * \author Gustavo Patricio + * + * \brief Implementation of ISO-DEP protocol + * + * This implementation was based on the following specs: + * - ISO/IEC 14443-4 2nd Edition 2008-07-15 + * - NFC Forum Digital Protocol 1.1 2014-01-14 + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup ISO-DEP + * \brief RFAL ISO-DEP Module + * @{ + * + */ + +#ifndef RFAL_ISODEP_H_ +#define RFAL_ISODEP_H_ +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_nfcb.h" + + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* If module is disabled remove the need for the user to set lengths */ +#if !RFAL_FEATURE_ISO_DEP + #undef RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN + #undef RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN + + #define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN (1U) /*!< ISO-DEP I-Block max length, set to "none" */ + #define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN (1U) /*!< ISO-DEP APDU max length, set to "none" */ +#endif /* !RFAL_FEATURE_ISO_DEP */ + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ + +#define RFAL_ISODEP_PROLOGUE_SIZE (3U) /*!< Length of Prologue Field for I-Block Format */ + +#define RFAL_ISODEP_PCB_LEN (1U) /*!< PCB length */ +#define RFAL_ISODEP_DID_LEN (1U) /*!< DID length */ +#define RFAL_ISODEP_NAD_LEN (1U) /*!< NAD length */ +#define RFAL_ISODEP_NO_DID (0x10U) /*!< DID value indicating the ISO-DEP layer not to use DID */ +#define RFAL_ISODEP_NO_NAD (0xFFU) /*!< NAD value indicating the ISO-DEP layer not to use NAD */ + +#define RFAL_ISODEP_FWI_MASK (0xF0U) /*!< Mask bits of FWI */ +#define RFAL_ISODEP_FWI_SHIFT (4U) /*!< Shift val of FWI */ +#define RFAL_ISODEP_FWI_DEFAULT (4U) /*!< Default value for FWI Digital 1.0 11.6.2.17 */ +#define RFAL_ISODEP_ADV_FEATURE (0x0FU) /*!< Indicate 256 Bytes FSD and Advanc Proto Feature support:NAD & DID */ + +#define RFAL_ISODEP_DID_MAX (14U) /*!< Maximum DID value */ + +#define RFAL_ISODEP_BRI_MASK (0x07U) /*!< Mask bits for Poll to Listen Send bitrate */ +#define RFAL_ISODEP_BSI_MASK (0x70U) /*!< Mask bits for Listen to Poll Send bitrate */ +#define RFAL_ISODEP_SAME_BITRATE_MASK (0x80U) /*!< Mask bit indicate only same bit rate D for both direction support */ +#define RFAL_ISODEP_BITRATE_RFU_MASK (0x08U) /*!< Mask bit for RFU */ + +/*! Maximum Frame Waiting Time = ((256 * 16/fc) * 2^FWImax) = ((256*16/fc)*2^14) = (67108864)/fc = 2^26 (1/fc) */ +#define RFAL_ISODEP_MAX_FWT ((uint32_t)1U<<26) + + + +#define RFAL_ISODEP_FSDI_DEFAULT RFAL_ISODEP_FSXI_256 /*!< Default Frame Size Integer in Poll mode */ +#define RFAL_ISODEP_FSX_KEEP (0xFFU) /*!< Flag to keep FSX from activation */ +#define RFAL_ISODEP_DEFAULT_FSCI RFAL_ISODEP_FSXI_256 /*!< FSCI default value to be used in Listen Mode */ +#define RFAL_ISODEP_DEFAULT_FSC RFAL_ISODEP_FSX_256 /*!< FSC default value (aligned RFAL_ISODEP_DEFAULT_FSCI) */ +#define RFAL_ISODEP_DEFAULT_SFGI (0U) /*!< SFGI Default value to be used in Listen Mode */ +#define RFAL_ISODEP_DEFAULT_FWI (8U) /*!< Default Listener FWI (Max) Digital 2.0 B7 & B3 */ + +#define RFAL_ISODEP_APDU_MAX_LEN RFAL_ISODEP_FSX_1024 /*!< Max APDU length */ + +#define RFAL_ISODEP_ATTRIB_RES_MBLI_NO_INFO (0x00U) /*!< MBLI indicating no information on its internal input buffer size */ +#define RFAL_ISODEP_ATTRIB_REQ_PARAM1_DEFAULT (0x00U) /*!< Default values of Param 1 of ATTRIB_REQ Digital 1.0 12.6.1.3-5 */ +#define RFAL_ISODEP_ATTRIB_HLINFO_LEN (32U) /*!< Maximum Size of Higher Layer Information */ +#define RFAL_ISODEP_ATS_HB_MAX_LEN (15U) /*!< Maximum length of Historical Bytes Digital 1.1 13.6.2.23 */ +#define RFAL_ISODEP_ATTRIB_REQ_MIN_LEN (9U) /*!< Minimum Length of ATTRIB_REQ command */ +#define RFAL_ISODEP_ATTRIB_RES_MIN_LEN (1U) /*!< Minimum Length of ATTRIB_RES response */ + +#define RFAL_ISODEP_SPARAM_VALUES_MAX_LEN (16U) /*!< Maximum Length of the value field on S(PARAMETERS) */ +#define RFAL_ISODEP_SPARAM_TAG_BLOCKINFO (0xA0U) /*!< S(PARAMETERS) tag Block information */ +#define RFAL_ISODEP_SPARAM_TAG_BRREQ (0xA1U) /*!< S(PARAMETERS) tag Bit rates Request */ +#define RFAL_ISODEP_SPARAM_TAG_BRIND (0xA2U) /*!< S(PARAMETERS) tag Bit rates Indication */ +#define RFAL_ISODEP_SPARAM_TAG_BRACT (0xA3U) /*!< S(PARAMETERS) tag Bit rates Activation */ +#define RFAL_ISODEP_SPARAM_TAG_BRACK (0xA4U) /*!< S(PARAMETERS) tag Bit rates Acknowledgement */ + +#define RFAL_ISODEP_SPARAM_TAG_SUP_PCD2PICC (0x80U) /*!< S(PARAMETERS) tag Supported bit rates from PCD to PICC */ +#define RFAL_ISODEP_SPARAM_TAG_SUP_PICC2PCD (0x81U) /*!< S(PARAMETERS) tag Supported bit rates from PICC to PCD */ +#define RFAL_ISODEP_SPARAM_TAG_SUP_FRAME (0x82U) /*!< S(PARAMETERS) tag Supported framing options PICC to PCD */ +#define RFAL_ISODEP_SPARAM_TAG_SEL_PCD2PICC (0x83U) /*!< S(PARAMETERS) tag Selected bit rate from PCD to PICC */ +#define RFAL_ISODEP_SPARAM_TAG_SEL_PICC2PCD (0x84U) /*!< S(PARAMETERS) tag Selected bit rate from PICC to PCD */ +#define RFAL_ISODEP_SPARAM_TAG_SEL_FRAME (0x85U) /*!< S(PARAMETERS) tag Selected framing options PICC to PCD */ + +#define RFAL_ISODEP_SPARAM_TAG_LEN (1) /*!< S(PARAMETERS) Tag Length */ +#define RFAL_ISODEP_SPARAM_TAG_BRREQ_LEN (0U) /*!< S(PARAMETERS) tag Bit rates Request Length */ +#define RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN (2U) /*!< S(PARAMETERS) bit rates from PCD to PICC Length */ +#define RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN (2U) /*!< S(PARAMETERS) bit rates from PICC to PCD Length */ +#define RFAL_ISODEP_SPARAM_TAG_BRACK_LEN (0U) /*!< S(PARAMETERS) tag Bit rates Acknowledgement Length */ + +#define RFAL_ISODEP_ATS_TA_DPL_212 (0x01U) /*!< ATS TA DSI 212 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_DPL_424 (0x02U) /*!< ATS TA DSI 424 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_DPL_848 (0x04U) /*!< ATS TA DSI 848 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_DLP_212 (0x10U) /*!< ATS TA DSI 212 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_DLP_424 (0x20U) /*!< ATS TA DRI 424 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_DLP_848 (0x40U) /*!< ATS TA DRI 848 kbps support bit mask */ +#define RFAL_ISODEP_ATS_TA_SAME_D (0x80U) /*!< ATS TA same bit both directions bit mask */ +#define RFAL_ISODEP_ATS_TB_FWI_MASK (0xF0U) /*!< Mask bits for FWI (Frame Waiting Integer) in TB byte */ +#define RFAL_ISODEP_ATS_TB_SFGI_MASK (0x0FU) /*!< Mask bits for SFGI (Start-Up Frame Guard Integer) in TB byte */ + +#define RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK (0x10U) /*!< Mask bit for TA presence */ +#define RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK (0x20U) /*!< Mask bit for TB presence */ +#define RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK (0x40U) /*!< Mask bit for TC presence */ +#define RFAL_ISODEP_ATS_T0_FSCI_MASK (0x0FU) /*!< Mask bit for FSCI presence */ +#define RFAL_ISODEP_ATS_T0_OFFSET (0x01U) /*!< Offset of T0 in ATS Response */ + + +#define RFAL_ISODEP_MAX_I_RETRYS (2U) /*!< Number of retries for a I-Block Digital 2.0 16.2.5.4 */ +#define RFAL_ISODEP_MAX_R_RETRYS (3U) /*!< Number of retries for a R-Block Digital 2.0 B9 - nRETRY ACK/NAK: [2,5] */ +#define RFAL_ISODEP_MAX_WTX_NACK_RETRYS (3U) /*!< Number of S(WTX) replied with NACK Digital 2.0 B9 - nRETRY WTX[2,5] */ +#define RFAL_ISODEP_MAX_WTX_RETRYS (20U) /*!< Number of overall S(WTX) retries Digital 2.0 16.2.5.2 */ +#define RFAL_ISODEP_MAX_WTX_RETRYS_ULTD (255U) /*!< Use unlimited number of overall S(WTX) */ +#define RFAL_ISODEP_MAX_DSL_RETRYS (0U) /*!< Number of retries for a S(DESELECT) Digital 2.0 B9 - nRETRY DESELECT: [0,5] */ +#define RFAL_ISODEP_RATS_RETRIES (1U) /*!< RATS retries upon fail Digital 2.0 B7 - nRETRY RATS [0,1] */ + + +/*! Frame Size for Proximity Card Integer definitions */ +typedef enum +{ + RFAL_ISODEP_FSXI_16 = 0, /*!< Frame Size for Proximity Card Integer with 16 bytes */ + RFAL_ISODEP_FSXI_24 = 1, /*!< Frame Size for Proximity Card Integer with 24 bytes */ + RFAL_ISODEP_FSXI_32 = 2, /*!< Frame Size for Proximity Card Integer with 32 bytes */ + RFAL_ISODEP_FSXI_40 = 3, /*!< Frame Size for Proximity Card Integer with 40 bytes */ + RFAL_ISODEP_FSXI_48 = 4, /*!< Frame Size for Proximity Card Integer with 48 bytes */ + RFAL_ISODEP_FSXI_64 = 5, /*!< Frame Size for Proximity Card Integer with 64 bytes */ + RFAL_ISODEP_FSXI_96 = 6, /*!< Frame Size for Proximity Card Integer with 96 bytes */ + RFAL_ISODEP_FSXI_128 = 7, /*!< Frame Size for Proximity Card Integer with 128 bytes */ + RFAL_ISODEP_FSXI_256 = 8, /*!< Frame Size for Proximity Card Integer with 256 bytes */ + RFAL_ISODEP_FSXI_512 = 9, /*!< Frame Size for Proximity Card Integer with 512 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSXI_1024 = 10, /*!< Frame Size for Proximity Card Integer with 1024 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSXI_2048 = 11, /*!< Frame Size for Proximity Card Integer with 2048 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSXI_4096 = 12 /*!< Frame Size for Proximity Card Integer with 4096 bytes ISO14443-3 Amd2 2012 */ +} rfalIsoDepFSxI; + +/*! Frame Size for Proximity Card definitions */ +typedef enum +{ + RFAL_ISODEP_FSX_16 = 16, /*!< Frame Size for Proximity Card with 16 bytes */ + RFAL_ISODEP_FSX_24 = 24, /*!< Frame Size for Proximity Card with 24 bytes */ + RFAL_ISODEP_FSX_32 = 32, /*!< Frame Size for Proximity Card with 32 bytes */ + RFAL_ISODEP_FSX_40 = 40, /*!< Frame Size for Proximity Card with 40 bytes */ + RFAL_ISODEP_FSX_48 = 48, /*!< Frame Size for Proximity Card with 48 bytes */ + RFAL_ISODEP_FSX_64 = 64, /*!< Frame Size for Proximity Card with 64 bytes */ + RFAL_ISODEP_FSX_96 = 96, /*!< Frame Size for Proximity Card with 96 bytes */ + RFAL_ISODEP_FSX_128 = 128, /*!< Frame Size for Proximity Card with 128 bytes */ + RFAL_ISODEP_FSX_256 = 256, /*!< Frame Size for Proximity Card with 256 bytes */ + RFAL_ISODEP_FSX_512 = 512, /*!< Frame Size for Proximity Card with 512 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSX_1024 = 1024, /*!< Frame Size for Proximity Card with 1024 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSX_2048 = 2048, /*!< Frame Size for Proximity Card with 2048 bytes ISO14443-3 Amd2 2012 */ + RFAL_ISODEP_FSX_4096 = 4096, /*!< Frame Size for Proximity Card with 4096 bytes ISO14443-3 Amd2 2012 */ +} rfalIsoDepFSx; + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL DATA TYPES + ****************************************************************************** + */ + +/*! RATS format Digital 1.1 13.6.1 */ +typedef struct +{ + uint8_t CMD; /*!< RATS command byte: 0xE0 */ + uint8_t PARAM; /*!< Param indicating FSDI and DID */ +} rfalIsoDepRats; + + +/*! ATS response format Digital 1.1 13.6.2 */ +typedef struct +{ + uint8_t TL; /*!< Length Byte, including TL byte itself */ + uint8_t T0; /*!< Format Byte T0 indicating if TA, TB, TC */ + uint8_t TA; /*!< Interface Byte TA(1) */ + uint8_t TB; /*!< Interface Byte TB(1) */ + uint8_t TC; /*!< Interface Byte TC(1) */ + uint8_t HB[RFAL_ISODEP_ATS_HB_MAX_LEN]; /*!< Historical Bytes */ +} rfalIsoDepAts; + + +/*! PPS Request format (Protocol and Parameter Selection) ISO14443-4 5.3 */ +typedef struct +{ + uint8_t PPSS; /*!< Start Byte: [ 1101b | CID[4b] ] */ + uint8_t PPS0; /*!< Parameter 0:[ 000b | PPS1[1n] | 0001b ] */ + uint8_t PPS1; /*!< Parameter 1:[ 0000b | DSI[2b] | DRI[2b] ]*/ +} rfalIsoDepPpsReq; + + +/*! PPS Response format (Protocol and Parameter Selection) ISO14443-4 5.4 */ +typedef struct +{ + uint8_t PPSS; /*!< Start Byte: [ 1101b | CID[4b] ] */ +} rfalIsoDepPpsRes; + + +/*! ATTRIB Command Format Digital 1.1 15.6.1 */ +typedef struct +{ + uint8_t cmd; /*!< ATTRIB_REQ command byte */ + uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFCID0 of the card to be selected */ + struct{ + uint8_t PARAM1; /*!< PARAM1 of ATTRIB command */ + uint8_t PARAM2; /*!< PARAM2 of ATTRIB command */ + uint8_t PARAM3; /*!< PARAM3 of ATTRIB command */ + uint8_t PARAM4; /*!< PARAM4 of ATTRIB command */ + }Param; /*!< Parameter of ATTRIB command */ + uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Higher Layer Information */ +} rfalIsoDepAttribCmd; + + +/*! ATTRIB Response Format Digital 1.1 15.6.2 */ +typedef struct +{ + uint8_t mbliDid; /*!< Contains MBLI and DID */ + uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Higher Layer Information */ +} rfalIsoDepAttribRes; + +/*! S(Parameters) Command Format ISO14443-4 (2016) Table 4 */ +typedef struct +{ + uint8_t tag; /*!< S(PARAMETERS) Tag field */ + uint8_t length; /*!< S(PARAMETERS) Length field */ + uint8_t value[RFAL_ISODEP_SPARAM_VALUES_MAX_LEN]; /*!< S(PARAMETERS) Value field */ +} rfalIsoDepSParameter; + + +/*! Activation info as Poller and Listener for NFC-A and NFC-B */ +typedef union {/* PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently, device is only of type A or B at a time. Thus no problem can occur. */ + + /*! NFC-A information */ + union { + struct { + rfalIsoDepAts ATS; /*!< ATS response (Poller mode) */ + uint8_t ATSLen; /*!< ATS response length (Poller mode) */ + }Listener; + struct { + rfalIsoDepRats RATS; /*!< RATS request (Listener mode) */ + }Poller; + }A; + + /*! NFC-B information */ + union { + struct{ + rfalIsoDepAttribRes ATTRIB_RES; /*!< ATTRIB_RES (Poller mode) */ + uint8_t ATTRIB_RESLen; /*!< ATTRIB_RES length (Poller mode) */ + }Listener; + struct{ + rfalIsoDepAttribCmd ATTRIB; /*!< ATTRIB request (Listener mode) */ + uint8_t ATTRIBLen; /*!< ATTRIB request length (Listener mode) */ + }Poller; + }B; +}rfalIsoDepActivation; + + +/*! ISO-DEP device Info */ +typedef struct { + uint8_t FWI; /*!< Frame Waiting Integer */ + uint32_t FWT; /*!< Frame Waiting Time (1/fc) */ + uint32_t dFWT; /*!< Delta Frame Waiting Time (1/fc) */ + uint32_t SFGI; /*!< Start-up Frame Guard time Integer */ + uint32_t SFGT; /*!< Start-up Frame Guard Time (ms) */ + uint8_t FSxI; /*!< Frame Size Device/Card Integer (FSDI or FSCI) */ + uint16_t FSx; /*!< Frame Size Device/Card (FSD or FSC) */ + uint32_t MBL; /*!< Maximum Buffer Length (optional for NFC-B) */ + rfalBitRate DSI; /*!< Bit Rate coding from Listener (PICC) to Poller (PCD) */ + rfalBitRate DRI; /*!< Bit Rate coding from Poller (PCD) to Listener (PICC) */ + uint8_t DID; /*!< Device ID */ + uint8_t NAD; /*!< Node ADdress */ + bool supDID; /*!< DID supported flag */ + bool supNAD; /*!< NAD supported flag */ + bool supAdFt; /*!< Advanced Features supported flag */ +} rfalIsoDepInfo; + + +/*! ISO-DEP Device structure */ +typedef struct { + rfalIsoDepActivation activation; /*!< Activation Info */ + rfalIsoDepInfo info; /*!< ISO-DEP (ISO14443-4) device Info */ +} rfalIsoDepDevice; + + +/*! ATTRIB Response parameters */ +typedef struct +{ + uint8_t mbli; /*!< MBLI */ + uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Hi Layer Information */ + uint8_t HLInfoLen; /*!< Hi Layer Information Length */ +} rfalIsoDepAttribResParam; + + +/*! ATS Response parameter */ +typedef struct +{ + uint8_t fsci; /*!< Frame Size of Proximity Card Integer */ + uint8_t fwi; /*!< Frame Waiting Time Integer */ + uint8_t sfgi; /*!< Start-Up Frame Guard Time Integer */ + bool didSupport; /*!< DID Supported */ + uint8_t ta; /*!< Max supported bitrate both direction */ + uint8_t *hb; /*!< Historical Bytes data */ + uint8_t hbLen; /*!< Historical Bytes Length */ +} rfalIsoDepAtsParam; + + +/*! Structure of I-Block Buffer format from caller */ +typedef struct +{ + uint8_t prologue[RFAL_ISODEP_PROLOGUE_SIZE]; /*!< Prologue/SoD buffer */ + uint8_t inf[RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN]; /*!< INF/Payload buffer */ +} rfalIsoDepBufFormat; + + +/*! Structure of APDU Buffer format from caller */ +typedef struct +{ + uint8_t prologue[RFAL_ISODEP_PROLOGUE_SIZE]; /*!< Prologue/SoD buffer */ + uint8_t apdu[RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN]; /*!< APDU/Payload buffer */ +} rfalIsoDepApduBufFormat; + + +/*! Listen Activation Parameters Structure */ +typedef struct +{ + rfalIsoDepBufFormat *rxBuf; /*!< Receive Buffer struct reference */ + uint16_t *rxLen; /*!< Received INF data length in Bytes */ + bool *isRxChaining; /*!< Received data is not complete */ + rfalIsoDepDevice *isoDepDev; /*!< ISO-DEP device info */ +} rfalIsoDepListenActvParam; + + +/*! Structure of parameters used on ISO DEP Transceive */ +typedef struct +{ + rfalIsoDepBufFormat *txBuf; /*!< Transmit Buffer struct reference */ + uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/ + bool isTxChaining; /*!< Transmit data is not complete */ + rfalIsoDepBufFormat *rxBuf; /*!< Receive Buffer struct reference in Bytes */ + uint16_t *rxLen; /*!< Received INF data length in Bytes */ + bool *isRxChaining; /*!< Received data is not complete */ + uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */ + uint32_t dFWT; /*!< Delta FWT to be used */ + uint16_t ourFSx; /*!< Our device Frame Size (FSD or FSC) */ + uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */ + uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */ +} rfalIsoDepTxRxParam; + + +/*! Structure of parameters used on ISO DEP APDU Transceive */ +typedef struct +{ + rfalIsoDepApduBufFormat *txBuf; /*!< Transmit Buffer struct reference */ + uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/ + rfalIsoDepApduBufFormat *rxBuf; /*!< Receive Buffer struct reference in Bytes */ + uint16_t *rxLen; /*!< Received INF data length in Bytes */ + rfalIsoDepBufFormat *tmpBuf; /*!< Temp buffer for Rx I-Blocks (internal) */ + uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */ + uint32_t dFWT; /*!< Delta FWT to be used */ + uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */ + uint16_t ourFSx; /*!< Our device Frame Size (FSD or FSC) */ + uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */ +} rfalIsoDepApduTxRxParam; + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + + +/*! + ****************************************************************************** + * \brief Initialize the ISO-DEP protocol + * + * Initialize the ISO-DEP protocol layer with default config + ****************************************************************************** + */ +void rfalIsoDepInitialize( void ); + + +/*! + ****************************************************************************** + * \brief Initialize the ISO-DEP protocol + * + * Initialize the ISO-DEP protocol layer with additional parameters allowing + * to customise the protocol layer for specific behaviours + * + + * \param[in] compMode : Compliance mode to be performed + * \param[in] maxRetriesR : Number of retries for a R-Block + * Digital 2.0 B9 - nRETRY ACK/NAK: [2,5] + * \param[in] maxRetriesSnWTX : Number of retries for a S(WTX) (only in case + * of NAKs) Digital 2.0 B9 - nRETRY WTX[2,5] + * \param[in] maxRetriesSWTX : Number of overall S(WTX) retries. + * Use RFAL_ISODEP_MAX_WTX_RETRYS_ULTD for disabling + * this limit check Digital 2.0 16.2.5.2 + * \param[in] maxRetriesSDSL : Number of retries for a S(DESELECT) + * Digital 2.0 B9 - nRETRY DESELECT: [0,5] + * \param[in] maxRetriesI : Number of retries for a I-Block + * Digital 2.0 16.2.5.4 + * \param[in] maxRetriesRATS : Number of retries for RATS + * Digital 2.0 B7 - nRETRY RATS [0,1] + * + ****************************************************************************** + */ +void rfalIsoDepInitializeWithParams( rfalComplianceMode compMode, + uint8_t maxRetriesR, + uint8_t maxRetriesSnWTX, + uint8_t maxRetriesSWTX, + uint8_t maxRetriesSDSL, + uint8_t maxRetriesI, + uint8_t maxRetriesRATS ); + + +/*! + ***************************************************************************** + * \brief FSxI to FSx + * + * Convert Frame Size for proximity coupling Device Integer (FSxI) to + * Frame Size for proximity coupling Device (FSx) + * + * FSD - maximum frame size for NFC Forum Device in Poll Mode + * FSC - maximum frame size for NFC Forum Device in Listen Mode + * + * FSxI = FSDI or FSCI + * FSx = FSD or FSC + * + * The FSD/FSC value includes the header and CRC + * + * \param[in] FSxI : Frame Size for proximity coupling Device Integer + * + * \return fsx : Frame Size for proximity coupling Device (FSD or FSC) + * + ***************************************************************************** + */ +uint16_t rfalIsoDepFSxI2FSx( uint8_t FSxI ); + + +/*! + ***************************************************************************** + * \brief FWI to FWT + * + * Convert Frame Waiting time Integer (FWI) to Frame Waiting Time (FWT) in + * 1/fc units + * + * \param[in] fwi : Frame Waiting time Integer + * + * \return fwt : Frame Waiting Time in 1/fc units + * + ***************************************************************************** + */ +uint32_t rfalIsoDepFWI2FWT( uint8_t fwi ); + + +/*! + ***************************************************************************** + * \brief Check if the buffer data contains a valid RATS command + * + * Check if it is a well formed RATS command with 2 bytes + * This function does not check the validity of FSDI and DID + * + * \param[in] buf : reference to buffer containing the data to be checked + * \param[in] bufLen : length of data in the buffer in bytes + * + * \return true if the data indicates a RATS command; false otherwise + ***************************************************************************** + */ +bool rfalIsoDepIsRats( const uint8_t *buf, uint8_t bufLen ); + + +/*! + ***************************************************************************** + * \brief Check if the buffer data contains a valid ATTRIB command + * + * Check if it is a well formed ATTRIB command, but does not check the + * validity of the information inside + * + * \param[in] buf : reference to buffer containing the data to be checked + * \param[in] bufLen : length of data in the buffer in bytes + * + * \return true if the data indicates a ATTRIB command; false otherwise + ***************************************************************************** + */ +bool rfalIsoDepIsAttrib( const uint8_t *buf, uint8_t bufLen ); + + +/*! + ***************************************************************************** + * \brief Start Listen Activation Handling + * + * Start Listen Activation Handling and setup to receive first I-block which may + * contain complete or partial APDU after activation is completed + * + * Pass in RATS for T4AT, or ATTRIB for T4BT, to handle ATS or ATTRIB Response respectively + * The Activation Handling handles ATS and ATTRIB Response; and additionally PPS Response + * if a PPS is received for T4AT. + * The method uses the current RFAL state machine to determine if it is expecting RATS or ATTRIB + * + * Activation is completed if PPS Response is sent or if first PDU is received in T4T-A + * Activation is completed if ATTRIB Response is sent in T4T-B + * + * \ref rfalIsoDepListenGetActivationStatus provide status if activation is completed. + * \ref rfalIsoDepStartTransceive shall be called right after activation is completed + * + * \param[in] atsParam : reference to ATS parameters + * \param[in] attribResParam : reference to ATTRIB_RES parameters + * \param[in] buf : reference to buffer containing RATS or ATTRIB + * \param[in] bufLen : length in bytes of the given bufffer + * \param[in] actParam : reference to incoming reception information will be placed + * + * + * \warning Once the Activation has been completed the method + * rfalIsoDepGetTransceiveStatus() must be called. + * If activation has completed due to reception of a data block (not PPS) the + * buffer owned by the caller and passed on actParam must still contain this data. + * The first data will be processed (I-Block or S-DSL) by rfalIsoDepGetTransceiveStatus() + * inform the caller and then for the next transaction use rfalIsoDepStartTransceive() + * + * \return RFAL_ERR_NONE : RATS/ATTRIB is valid and activation has started + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_PROTO : Invalid request + * \return RFAL_ERR_NOTSUPP : Feature not supported + ***************************************************************************** + */ +ReturnCode rfalIsoDepListenStartActivation( rfalIsoDepAtsParam *atsParam, const rfalIsoDepAttribResParam *attribResParam, const uint8_t *buf, uint16_t bufLen, rfalIsoDepListenActvParam actParam ); + + +/*! + ***************************************************************************** + * \brief Get the current Activation Status + * + * \return RFAL_ERR_NONE if Activation is already completed + * \return RFAL_ERR_BUSY if Activation is ongoing + * \return RFAL_ERR_LINK_LOSS if Remote Field is turned off + ***************************************************************************** + */ +ReturnCode rfalIsoDepListenGetActivationStatus( void ); + + +/*! + ***************************************************************************** + * \brief Get the ISO-DEP Communication Information + * + * Gets the maximum INF length in bytes based on current Frame Size + * for proximity coupling Device (FSD or FSC) excluding the header and CRC + * + * \return maximum INF length in bytes + ***************************************************************************** + */ +uint16_t rfalIsoDepGetMaxInfLen( void ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Start Transceive + * + * This method triggers a ISO-DEP Transceive containing a complete or + * partial APDU + * It transmits the given message and handles all protocol retransmitions, + * error handling and control messages + * + * The txBuf contains a complete or partial APDU (INF) to be transmitted + * The Prologue field will be manipulated by the Transceive + * + * If the buffer contains a partial APDU and is not the last block, + * then isTxChaining must be set to true + * + * \param[in] param: reference parameters to be used for the Transceive + * + * \return RFAL_ERR_PARAM : Bad request + * \return RFAL_ERR_WRONG_STATE : The module is not in a proper state + * \return RFAL_ERR_NONE : The Transceive request has been started + ***************************************************************************** + */ +ReturnCode rfalIsoDepStartTransceive( rfalIsoDepTxRxParam param ); + + +/*! + ***************************************************************************** + * \brief Get the Transceive status + * + * Returns the status of the ISO-DEP Transceive + * + * \warning When the other device is performing chaining once a chained + * block is received the error RFAL_ERR_AGAIN is sent. At this point + * caller must handle the received data immediately. + * When RFAL_ERR_AGAIN is returned an ACK has already been sent to + * the other device and the next block might be incoming. + * If rfalWorker() is called frequently it will place the next + * block on the given buffer + * + * + * \return RFAL_ERR_NONE : Transceive has been completed successfully + * \return RFAL_ERR_BUSY : Transceive is ongoing + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : Timeout error occurred + * \return RFAL_ERR_SLEEP_REQ : Deselect has been received and responded + * \return RFAL_ERR_NOMEM : The received INF does not fit into the + * receive buffer + * \return RFAL_ERR_LINK_LOSS : Communication is lost because Reader/Writer + * has turned off its field + * \return RFAL_ERR_AGAIN : received one chaining block, continue to call + * this method to retrieve the remaining blocks + ***************************************************************************** + */ +ReturnCode rfalIsoDepGetTransceiveStatus( void ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Start APDU Transceive + * + * This method triggers a ISO-DEP Transceive containing a complete APDU + * It transmits the given message and handles all protocol retransmitions, + * error handling and control messages + * + * The txBuf contains a complete APDU to be transmitted + * The Prologue field will be manipulated by the Transceive + * + * \warning the txBuf will be modified during the transmission + * \warning the maximum RF frame which can be received is limited by param.tmpBuf + * + * \param[in] param: reference parameters to be used for the Transceive + * + * \return RFAL_ERR_PARAM : Bad request + * \return RFAL_ERR_WRONG_STATE : The module is not in a proper state + * \return RFAL_ERR_NONE : The Transceive request has been started + ***************************************************************************** + */ +ReturnCode rfalIsoDepStartApduTransceive( rfalIsoDepApduTxRxParam param ); + + +/*! + ***************************************************************************** + * \brief Get the APDU Transceive status + * + * \return RFAL_ERR_NONE : if Transceive has been completed successfully + * \return RFAL_ERR_BUSY : if Transceive is ongoing + * \return RFAL_ERR_PROTO : if a protocol error occurred + * \return RFAL_ERR_TIMEOUT : if a timeout error occurred + * \return RFAL_ERR_SLEEP_REQ : if Deselect is received and responded + * \return RFAL_ERR_NOMEM : if the received INF does not fit into the + * receive buffer + * \return RFAL_ERR_LINK_LOSS : if communication is lost because Reader/Writer + * has turned off its field + ***************************************************************************** + */ +ReturnCode rfalIsoDepGetApduTransceiveStatus( void ); + +/*! + ***************************************************************************** + * \brief ISO-DEP Send RATS + * + * This sends a RATS to make a NFC-A Listen Device to enter + * ISO-DEP layer (ISO14443-4) and checks if the received ATS is valid + * + * \param[in] FSDI : Frame Size Device Integer to be used + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[out] ats : pointer to place the ATS Response + * \param[out] atsLen : pointer to place the ATS length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, ATS received + ***************************************************************************** + */ +ReturnCode rfalIsoDepRATS( rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts *ats , uint8_t *atsLen ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Send PPS + * + * This sends a PPS to make a NFC-A Listen Device change the communications + * bit rate from 106kbps to one of the supported bit rates + * Additionally checks if the received PPS response is valid + * + * \param[in] DID : Device ID + * \param[in] DSI : DSI code the divisor from Listener (PICC) to Poller (PCD) + * \param[in] DRI : DRI code the divisor from Poller (PCD) to Listener (PICC) + * \param[out] ppsRes : pointer to place the PPS Response + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, PPS Response received + ***************************************************************************** + */ +ReturnCode rfalIsoDepPPS( uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes *ppsRes ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Send ATTRIB + * + * This sends a ATTRIB to make a NFC-B Listen Device to enter + * ISO-DEP layer (ISO14443-4) and checks if the received ATTRIB Response is valid + * + * \param[in] nfcid0 : NFCID0 to be used for the ATTRIB + * \param[in] PARAM1 : ATTRIB PARAM1 byte (communication parameters) + * \param[in] DSI : DSI code the divisor from Listener (PICC) to Poller (PCD) + * \param[in] DRI : DRI code the divisor from Poller (PCD) to Listener (PICC) + * \param[in] FSDI : PCD's Frame Size to be announced on the ATTRIB + * \param[in] PARAM3 : ATTRIB PARAM1 byte (protocol type) + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[in] HLInfo : pointer to Higher layer INF (NULL if none) + * \param[in] HLInfoLen : Length HLInfo + * \param[in] fwt : Frame Waiting Time to be used (from SENSB_RES) + * \param[out] attribRes : pointer to place the ATTRIB Response + * \param[out] attribResLen : pointer to place the ATTRIB Response length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, ATTRIB Response received + ***************************************************************************** + */ +ReturnCode rfalIsoDepATTRIB( const uint8_t* nfcid0, uint8_t PARAM1, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepFSxI FSDI, uint8_t PARAM3, uint8_t DID, const uint8_t* HLInfo, uint8_t HLInfoLen, uint32_t fwt, rfalIsoDepAttribRes *attribRes, uint8_t *attribResLen ); + + +/*! + ***************************************************************************** + * \brief Deselect PICC + * + * This function sends a deselect command to PICC and waits for its + * responce in a blocking way + * + * \return RFAL_ERR_NONE : Deselect successfully sent and acknowledged by PICC + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : No response rcvd from PICC + * + ***************************************************************************** + */ +ReturnCode rfalIsoDepDeselect( void ); + + +/*! + ***************************************************************************** + * \brief Start Deselect + * + * This function starts the exchange to send deselect command to PICC and + * waits for its response + * + * \return RFAL_ERR_NONE : Deselect successfully sent and acknowledged by PICC + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : No response rcvd from PICC + * + ***************************************************************************** + */ +ReturnCode rfalIsoDepStartDeselect( void ); + + +/*! + ***************************************************************************** + * \brief Deselect Get Status + * + * This function sends a deselect command to PICC and waits for it`s + * responce in a blocking way + * + * \return RFAL_ERR_NONE : Deselect successfully sent and acknowledged by PICC + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : No response rcvd from PICC + * + ***************************************************************************** + */ +ReturnCode rfalIsoDepGetDeselectStatus( void ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Handle NFC-A Activation + * + * This performs a NFC-A Activation into ISO-DEP layer (ISO14443-4) with the given + * parameters. It sends RATS and if the higher bit rates are supported by + * both devices it additionally sends PPS + * Once Activated all details of the device are provided on isoDepDev + * + * \param[in] FSDI : Frame Size Device Integer to be used + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[in] maxBR : Max bit rate supported by the Poller + * \param[out] rfalIsoDepDev : ISO-DEP information of the activated Listen device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollAHandleActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, rfalIsoDepDevice *rfalIsoDepDev ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Handle NFC-B Activation + * + * This performs a NFC-B Activation into ISO-DEP layer (ISO14443-4) with the given + * parameters. It sends ATTRIB and calculates supported higher bit rates of both + * devices and performs activation. + * Once Activated all details of the device are provided on isoDepDev + * + * \param[in] FSDI : Frame Size Device Integer to be used + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[in] maxBR : Max bit rate supported by the Poller + * \param[in] PARAM1 : ATTRIB PARAM1 byte (communication parameters) + * \param[in] nfcbDev : pointer to the NFC-B Device containing the SENSB_RES + * \param[in] HLInfo : pointer to Higher layer INF (NULL if none) + * \param[in] HLInfoLen : Length HLInfo + * \param[out] rfalIsoDepDev : ISO-DEP information of the activated Listen device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollBHandleActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, uint8_t PARAM1, const rfalNfcbListenDevice *nfcbDev, const uint8_t* HLInfo, uint8_t HLInfoLen, rfalIsoDepDevice *rfalIsoDepDev ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Handle S(Parameters) + * + * This checks if PICC supports S(PARAMETERS), retieves PICC's + * capabilities and sets the Bit Rate at the highest supported by both + * devices + * + * \param[out] rfalIsoDepDev : ISO-DEP information of the activated Listen device + * \param[in] maxTxBR : Maximum Tx bit rate supported by PCD + * \param[in] maxRxBR : Maximum Rx bit rate supported by PCD + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, S(PARAMETERS) selection successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollHandleSParameters( rfalIsoDepDevice *rfalIsoDepDev, rfalBitRate maxTxBR, rfalBitRate maxRxBR ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Start NFC-A Activation + * + * This starts a NFC-A Activation into ISO-DEP layer (ISO14443-4) with the given + * parameters. It sends RATS and if the higher bit rates are supported by + * both devices it additionally sends PPS + * Once Activated all details of the device are provided on isoDepDev + * + * + * \see rfalIsoDepPollAGetActivationStatus + * + * \param[in] FSDI : Frame Size Device Integer to be used + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[in] maxBR : Max bit rate supported by the Poller + * \param[out] rfalIsoDepDev : ISO-DEP information of the activated Listen device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, start of asynchronous operation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollAStartActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, rfalIsoDepDevice *rfalIsoDepDev ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Get NFC-A Activation Status + * + * Returns the activation status started by rfalIsoDepPollAStartActivation + * + * \see rfalIsoDepPollAStartActivation + * + * \return RFAL_ERR_BUSY : Operation is ongoing + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollAGetActivationStatus( void ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Start NFC-B Activation + * + * This starts a NFC-B Activation into ISO-DEP layer (ISO14443-4) with the given + * parameters. It will send ATTRIB and calculate supported higher bit rates of both + * devices and perform activation. + * Once Activated all details of the device are provided on isoDepDev + * + * \see rfalIsoDepPollBGetActivationStatus + * + * \param[in] FSDI : Frame Size Device Integer to be used + * \param[in] DID : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID + * \param[in] maxBR : Max bit rate supported by the Poller + * \param[in] PARAM1 : ATTRIB PARAM1 byte (communication parameters) + * \param[in] nfcbDev : pointer to the NFC-B Device containing the SENSB_RES + * \param[in] HLInfo : pointer to Higher layer INF (NULL if none) + * \param[in] HLInfoLen : Length HLInfo + * \param[out] rfalIsoDepDev : ISO-DEP information of the activated Listen device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, start of asynchronous operation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollBStartActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, uint8_t PARAM1, const rfalNfcbListenDevice *nfcbDev, const uint8_t* HLInfo, uint8_t HLInfoLen, rfalIsoDepDevice *rfalIsoDepDev ); + + +/*! + ***************************************************************************** + * \brief ISO-DEP Poller Get NFC-B Activation Status + * + * Returns the activation status started by rfalIsoDepPollBStartActivation + * + * \see rfalIsoDepPollBStartActivation + * + * \return RFAL_ERR_BUSY : Operation is ongoing + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalIsoDepPollBGetActivationStatus( void ); + + +#endif /* RFAL_ISODEP_H_ */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfc.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfc.h new file mode 100644 index 0000000..fc3fb34 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfc.h @@ -0,0 +1,532 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfc.h + * + * \brief RFAL NFC device + * + * This module provides the required features to behave as an NFC Poller + * or Listener device. It grants an easy to use interface for the following + * activities: Technology Detection, Collision Resolution, Activation, + * Data Exchange, and Deactivation + * + * This layer is influenced by (but not fully aligned with) the NFC Forum + * specifications, in particular: Activity 2.0 and NCI 2.0 + * + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HL + * \brief RFAL Higher Layer + * @{ + * + * \addtogroup NFC + * \brief RFAL NFC Device + * @{ + * + */ + +#ifndef RFAL_NFC_H +#define RFAL_NFC_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" +#include "rfal_nfca.h" +#include "rfal_nfcb.h" +#include "rfal_nfcf.h" +#include "rfal_nfcv.h" +#include "rfal_st25tb.h" +#include "rfal_nfcDep.h" +#include "rfal_isoDep.h" + + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + +#define RFAL_NFC_TECH_NONE 0x0000U /*!< No technology */ +#define RFAL_NFC_POLL_TECH_A 0x0001U /*!< Poll NFC-A technology Flag */ +#define RFAL_NFC_POLL_TECH_B 0x0002U /*!< Poll NFC-B technology Flag */ +#define RFAL_NFC_POLL_TECH_F 0x0004U /*!< Poll NFC-F technology Flag */ +#define RFAL_NFC_POLL_TECH_V 0x0008U /*!< Poll NFC-V technology Flag */ +#define RFAL_NFC_POLL_TECH_AP2P 0x0010U /*!< Poll AP2P technology Flag */ +#define RFAL_NFC_POLL_TECH_ST25TB 0x0020U /*!< Poll ST25TB technology Flag */ +#define RFAL_NFC_POLL_TECH_PROP 0x0040U /*!< Poll Proprietary technology Flag */ +#define RFAL_NFC_LISTEN_TECH_A 0x1000U /*!< Listen NFC-A technology Flag */ +#define RFAL_NFC_LISTEN_TECH_B 0x2000U /*!< Listen NFC-B technology Flag */ +#define RFAL_NFC_LISTEN_TECH_F 0x4000U /*!< Listen NFC-F technology Flag */ +#define RFAL_NFC_LISTEN_TECH_AP2P 0x8000U /*!< Listen AP2P technology Flag */ + + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +/*! Checks if a device is currently activated */ +#define rfalNfcIsDevActivated( st ) ( ((st)>= RFAL_NFC_STATE_ACTIVATED) && ((st)= RFAL_NFC_STATE_START_DISCOVERY) && ((st)= RFAL_NFC_POLL_TYPE_NFCA) && ((tp)<=RFAL_NFC_POLL_TYPE_AP2P ) ) + +/*! Checks if remote device is in Listen mode */ +#define rfalNfcIsRemDevListener( tp ) ( ((int16_t)(tp)>= (int16_t)RFAL_NFC_LISTEN_TYPE_NFCA) && ((tp)<=RFAL_NFC_LISTEN_TYPE_AP2P) ) + +/*! Sets the discover parameters to its default values */ +#define rfalNfcDefaultDiscParams( dp ) if( (dp) != NULL) { \ + RFAL_MEMSET( (dp), 0x00, sizeof(rfalNfcDiscoverParam) ); \ + ((rfalNfcDiscoverParam*)(dp))->compMode = RFAL_COMPLIANCE_MODE_NFC; \ + ((rfalNfcDiscoverParam*)(dp))->devLimit = 1U; \ + ((rfalNfcDiscoverParam*)(dp))->nfcfBR = RFAL_BR_212; \ + ((rfalNfcDiscoverParam*)(dp))->ap2pBR = RFAL_BR_424; \ + ((rfalNfcDiscoverParam*)(dp))->maxBR = RFAL_BR_KEEP; \ + ((rfalNfcDiscoverParam*)(dp))->isoDepFS = RFAL_ISODEP_FSXI_256; \ + ((rfalNfcDiscoverParam*)(dp))->nfcDepLR = RFAL_NFCDEP_LR_254; \ + ((rfalNfcDiscoverParam*)(dp))->GBLen = 0U; \ + ((rfalNfcDiscoverParam*)(dp))->p2pNfcaPrio = false; \ + ((rfalNfcDiscoverParam*)(dp))->wakeupEnabled = false; \ + ((rfalNfcDiscoverParam*)(dp))->wakeupConfigDefault = true; \ + ((rfalNfcDiscoverParam*)(dp))->wakeupPollBefore = false; \ + ((rfalNfcDiscoverParam*)(dp))->wakeupNPolls = 1U; \ + ((rfalNfcDiscoverParam*)(dp))->totalDuration = 1000U; \ + ((rfalNfcDiscoverParam*)(dp))->techs2Find = RFAL_NFC_TECH_NONE; \ + ((rfalNfcDiscoverParam*)(dp))->techs2Bail = RFAL_NFC_TECH_NONE; \ + } + +/* +****************************************************************************** +* GLOBAL ENUMS +****************************************************************************** +*/ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! Main state */ +typedef enum{ + RFAL_NFC_STATE_NOTINIT = 0, /*!< Not Initialized state */ + RFAL_NFC_STATE_IDLE = 1, /*!< Initialize state */ + RFAL_NFC_STATE_START_DISCOVERY = 2, /*!< Start Discovery loop state */ + RFAL_NFC_STATE_WAKEUP_MODE = 3, /*!< Wake-Up state */ + RFAL_NFC_STATE_POLL_TECHDETECT = 10, /*!< Technology Detection state */ + RFAL_NFC_STATE_POLL_COLAVOIDANCE = 11, /*!< Collision Avoidance state */ + RFAL_NFC_STATE_POLL_SELECT = 12, /*!< Wait for Selection state */ + RFAL_NFC_STATE_POLL_ACTIVATION = 13, /*!< Activation state */ + RFAL_NFC_STATE_LISTEN_TECHDETECT = 20, /*!< Listen Tech Detect */ + RFAL_NFC_STATE_LISTEN_COLAVOIDANCE = 21, /*!< Listen Collision Avoidance */ + RFAL_NFC_STATE_LISTEN_ACTIVATION = 22, /*!< Listen Activation state */ + RFAL_NFC_STATE_LISTEN_SLEEP = 23, /*!< Listen Sleep state */ + RFAL_NFC_STATE_ACTIVATED = 30, /*!< Activated state */ + RFAL_NFC_STATE_DATAEXCHANGE = 31, /*!< Data Exchange Start state */ + RFAL_NFC_STATE_DATAEXCHANGE_DONE = 33, /*!< Data Exchange terminated */ + RFAL_NFC_STATE_DEACTIVATION = 34 /*!< Deactivation state */ +}rfalNfcState; + + +/*! Device type */ +typedef enum{ + RFAL_NFC_LISTEN_TYPE_NFCA = 0, /*!< NFC-A Listener device type */ + RFAL_NFC_LISTEN_TYPE_NFCB = 1, /*!< NFC-B Listener device type */ + RFAL_NFC_LISTEN_TYPE_NFCF = 2, /*!< NFC-F Listener device type */ + RFAL_NFC_LISTEN_TYPE_NFCV = 3, /*!< NFC-V Listener device type */ + RFAL_NFC_LISTEN_TYPE_ST25TB = 4, /*!< ST25TB Listener device type */ + RFAL_NFC_LISTEN_TYPE_AP2P = 5, /*!< AP2P Listener device type */ + RFAL_NFC_LISTEN_TYPE_PROP = 6, /*!< Proprietary Listen dev type */ + RFAL_NFC_POLL_TYPE_NFCA = 10, /*!< NFC-A Poller device type */ + RFAL_NFC_POLL_TYPE_NFCB = 11, /*!< NFC-B Poller device type */ + RFAL_NFC_POLL_TYPE_NFCF = 12, /*!< NFC-F Poller device type */ + RFAL_NFC_POLL_TYPE_NFCV = 13, /*!< NFC-V Poller device type */ + RFAL_NFC_POLL_TYPE_AP2P = 15 /*!< AP2P Poller device type */ +}rfalNfcDevType; + + +/*! Device interface */ +typedef enum{ + RFAL_NFC_INTERFACE_RF = 0, /*!< RF Frame interface */ + RFAL_NFC_INTERFACE_ISODEP = 1, /*!< ISO-DEP interface */ + RFAL_NFC_INTERFACE_NFCDEP = 2 /*!< NFC-DEP interface */ +}rfalNfcRfInterface; + + +/*! Deactivation type */ +typedef enum{ + RFAL_NFC_DEACTIVATE_IDLE = 0, /*!< Deactivate and go to IDLE */ + RFAL_NFC_DEACTIVATE_SLEEP = 1, /*!< Deactivate and go to SELECT */ + RFAL_NFC_DEACTIVATE_DISCOVERY = 2 /*!< Deactivate and restart DISCOVERY */ +}rfalNfcDeactivateType; + + +/*! Device struct containing all its details */ +typedef struct{ + rfalNfcDevType type; /*!< Device's type */ + union{ /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one technology at a time */ + rfalNfcaListenDevice nfca; /*!< NFC-A Listen Device instance */ + rfalNfcbListenDevice nfcb; /*!< NFC-B Listen Device instance */ + rfalNfcfListenDevice nfcf; /*!< NFC-F Listen Device instance */ + rfalNfcvListenDevice nfcv; /*!< NFC-V Listen Device instance */ + rfalSt25tbListenDevice st25tb; /*!< ST25TB Listen Device instance*/ + }dev; /*!< Device's instance */ + + uint8_t *nfcid; /*!< Device's NFCID */ + uint8_t nfcidLen; /*!< Device's NFCID length */ + rfalNfcRfInterface rfInterface; /*!< Device's interface */ + + union{ /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one protocol at a time */ + rfalIsoDepDevice isoDep; /*!< ISO-DEP instance */ + rfalNfcDepDevice nfcDep; /*!< NFC-DEP instance */ + }proto; /*!< Device's protocol */ +}rfalNfcDevice; + + +/*! Callbacks for Proprietary|Other Technology Activity 2.1 & EMVCo 3.0 9.2 */ +typedef ReturnCode (* rfalNfcPropCallback)(void); + + +/*! Struct that holds the Proprietary NFC callbacks */ +typedef struct{ + rfalNfcPropCallback rfalNfcpPollerInitialize; /*!< Prorietary NFC Initialization callback */ + rfalNfcPropCallback rfalNfcpPollerTechnologyDetection; /*!< Prorietary NFC Technoly Detection callback */ + rfalNfcPropCallback rfalNfcpPollerStartCollisionResolution; /*!< Prorietary NFC Start Collision Resolution callback */ + rfalNfcPropCallback rfalNfcpPollerGetCollisionResolutionStatus; /*!< Prorietary NFC Get Collision Resolution status callback */ + rfalNfcPropCallback rfalNfcpStartActivation; /*!< Prorietary NFC Start Activation callback */ + rfalNfcPropCallback rfalNfcpGetActivationStatus; /*!< Prorietary NFC Get Activation status callback */ +} rfalNfcPropCallbacks; + + +/*! Discovery parameters */ +typedef struct{ + rfalComplianceMode compMode; /*!< Compliancy mode to be used */ + uint16_t techs2Find; /*!< Technologies to search for */ + uint16_t techs2Bail; /*!< Bail-out after certain NFC technologies */ + uint16_t totalDuration; /*!< Duration of a whole Poll + Listen cycle NCI 2.1 Table 46 */ + uint8_t devLimit; /*!< Max number of devices Activity 2.1 Table 11 */ + rfalBitRate maxBR; /*!< Max Bit rate to be used NCI 2.1 Table 28 */ + + rfalBitRate nfcfBR; /*!< Bit rate to poll for NFC-F NCI 2.1 Table 27 */ + uint8_t nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 to be used on the ATR_REQ/ATR_RES */ + uint8_t GB[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General bytes to be used on the ATR-REQ NCI 2.1 Table 29 */ + uint8_t GBLen; /*!< Length of the General Bytes NCI 2.1 Table 29 */ + rfalBitRate ap2pBR; /*!< Bit rate to poll for AP2P NCI 2.1 Table 31 */ + bool p2pNfcaPrio; /*!< NFC-A P2P (true) or ISO14443-4/T4T (false) priority */ + rfalNfcPropCallbacks propNfc; /*!< Proprietary Technlogy callbacks */ + + + rfalIsoDepFSxI isoDepFS; /*!< ISO-DEP Poller announced maximum frame size Digital 2.2 Table 60 */ + uint8_t nfcDepLR; /*!< NFC-DEP Poller & Listener maximum frame size Digital 2.2 Table 90 */ + + rfalLmConfPA lmConfigPA; /*!< Configuration for Passive Listen mode NFC-A */ + rfalLmConfPF lmConfigPF; /*!< Configuration for Passive Listen mode NFC-A */ + + void (*notifyCb)( rfalNfcState st ); /*!< Callback to Notify upper layer */ + + bool wakeupEnabled; /*!< Enable Wake-Up mode before polling */ + bool wakeupConfigDefault; /*!< Wake-Up mode default configuration */ + rfalWakeUpConfig wakeupConfig; /*!< Wake-Up mode configuration */ + bool wakeupPollBefore; /*!< Flag to Poll wakeupNPolls times before entering Wake-up */ + uint16_t wakeupNPolls; /*!< Number of polling cycles before|after entering Wake-up */ +}rfalNfcDiscoverParam; + + +/*! Buffer union, only one interface is used at a time */ +typedef union{ /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one interface at a time */ + uint8_t rfBuf[RFAL_FEATURE_NFC_RF_BUF_LEN]; /*!< RF buffer */ + rfalIsoDepApduBufFormat isoDepBuf; /*!< ISO-DEP buffer format (with header/prologue) */ + rfalNfcDepPduBufFormat nfcDepBuf; /*!< NFC-DEP buffer format (with header/prologue) */ +}rfalNfcBuffer; + + + +#define RFAL_NFC_MAX_DEVICES 5U /*!< Max number of devices supported */ +#define RFAL_NFC_T_FIELD_OFF 5U /*!< tFIELD_OFF minimal duration Activity 2.2 Table 26 */ + +/*! Buffer union, only one interface is used at a time */ +typedef union{ /*PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one interface at a time */ + rfalIsoDepBufFormat isoDepBuf; /*!< ISO-DEP buffer format (with header/prologue) */ + rfalNfcDepBufFormat nfcDepBuf; /*!< NFC-DEP buffer format (with header/prologue) */ +}rfalNfcTmpBuffer; + + +/*! RFAL NFC instance */ + +typedef struct{ + rfalNfcState state; /*!< Main state */ + uint16_t techsFound; /*!< Technologies found bitmask */ + uint16_t techs2do; /*!< Technologies still to be performed */ + uint16_t techDctCnt; /*!< Technologies detection counter (before WU) */ + rfalBitRate ap2pBR; /*!< Bit rate to poll for AP2P */ + uint8_t selDevIdx; /*!< Selected device index */ + rfalNfcDevice *activeDev; /*!< Active device pointer */ + rfalNfcDiscoverParam disc; /*!< Discovery parameters */ + rfalNfcDevice devList[RFAL_NFC_MAX_DEVICES]; /*!< Location of device list */ + uint8_t devCnt; /*!< Decices found counter */ + uint32_t discTmr; /*!< Discovery Total duration timer */ + ReturnCode dataExErr; /*!< Last Data Exchange error */ + rfalNfcDeactivateType deactType; /*!< Deactivation type */ + bool isRxChaining; /*!< Flag indicating Other device is chaining */ + uint32_t lmMask; /*!< Listen Mode mask */ + bool isFieldOn; /*!< Flag indicating Fieldon for Passive Poll */ + bool isTechInit; /*!< Flag indicating technology has been set */ + bool isOperOngoing; /*!< Flag indicating operation is ongoing */ + bool isDeactivating; /*!< Flag indicating deactivation is ongoing */ + + rfalNfcaSensRes sensRes; /*!< SENS_RES during card detection and activation */ + rfalNfcbSensbRes sensbRes; /*!< SENSB_RES during card detection and activation */ + uint8_t sensbResLen; /*!< SENSB_RES length */ + + rfalNfcBuffer txBuf; /*!< Tx buffer for Data Exchange */ + rfalNfcBuffer rxBuf; /*!< Rx buffer for Data Exchange */ + uint16_t rxLen; /*!< Length of received data on Data Exchange */ + +#if RFAL_FEATURE_NFC_DEP || RFAL_FEATURE_ISO_DEP + rfalNfcTmpBuffer tmpBuf; /*!< Tmp buffer for Data Exchange */ +#endif /* RFAL_FEATURE_NFC_DEP || RFAL_FEATURE_ISO_DEP */ + +}rfalNfc; + +/*******************************************************************************/ + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief RFAL NFC Worker + * + * It runs the internal state machine and runs the RFAL RF worker. + ***************************************************************************** + */ +void rfalNfcWorker( void ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Initialize + * + * It initializes this module and its dependencies + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcInitialize( void ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Discovery + * + * It set the device in Discovery state. + * In discovery it will Poll and/or Listen for the technologies configured, + * and perform Wake-up mode if configured to do so. + * + * The device list passed on disParams must not be empty. + * The number of devices on the list is indicated by the devLimit and shall + * be at >= 1. + * + * \param[in] disParams : discovery configuration parameters + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcDiscover( const rfalNfcDiscoverParam *disParams ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Get State + * + * It returns the current state + * + * \return rfalNfcState : the current state + ***************************************************************************** + */ +rfalNfcState rfalNfcGetState( void ); +rfalNfc* rfalNfcGetDev( void ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Get Devices Found + * + * It returns the location of the device list and the number of + * devices found. + * + * \param[out] devList : device list location + * \param[out] devCnt : number of devices found + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * Discovery still ongoing + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcGetDevicesFound( rfalNfcDevice **devList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Get Active Device + * + * It returns the location of the device current Active device + * + * \param[out] dev : device info location + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * No device activated + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcGetActiveDevice( rfalNfcDevice **dev ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Select Device + * + * It selects the device to be activated. + * It shall be called when more than one device has been identified to + * indicate which device shall be actived + * + * \param[in] devIdx : device index to be activated + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * Not in select state + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcSelect( uint8_t devIdx ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Start Data Exchange + * + * After a device has been activated, it starts a data exchange. + * It handles automatically which interface/protocol to be used and acts accordingly. + * + * In Listen mode the first frame/data shall be sent by the Reader/Initiator + * therefore this method must be called first with txDataLen set to zero + * to retrieve the rxData and rcvLen locations. + * + * + * \param[in] txData : data to be transmitted + * \param[in] txDataLen : size of the data to be transmitted (in bits or bytes - see below) + * \param[out] rxData : location of the received data after operation is completed + * \param[out] rvdLen : location of the length of the received data (in bits or bytes - see below) + * \param[in] fwt : FWT to be used in case of RF interface. + * If ISO-DEP or NFC-DEP interface is used, this will be ignored + * + * \warning In order to support a wider range of protocols, when RF interface is used the lengths + * are in number of bits (not bytes). Therefore both input txDataLen and output rvdLen refer to + * bits. If ISO-DEP or NFC-DEP interface is used those are expressed in number of bytes. + * + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Get Data Exchange Status + * + * Gets current Data Exchange status + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_BUSY : Transceive ongoing + * \return RFAL_ERR_AGAIN : received one chaining block, copy received data + * and continue to call this method to retrieve the + * remaining blocks + * \return RFAL_ERR_XXXX : Error occurred + * \return RFAL_ERR_TIMEOUT : No response + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_LINK_LOSS : Link Loss - External Field is Off + * \return RFAL_ERR_RF_COLLISION : Collision detected + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalNfcDataExchangeGetStatus( void ); + + +/*! + ***************************************************************************** + * \brief RFAL NFC Deactivate + * + * It triggers the deactivation procedure to terminate communications with + * remote device. + * In case the deactivation type is RFAL_NFC_DEACTIVATE_SLEEP the field is + * kept On and device selection shall follow. Otherwise the field will + * be turned Off. + * + * \warning In case the deactivation type is RFAL_NFC_DEACTIVATE_IDLE the + * deactivation procedure is executed immediately and in a blocking manner + * + * \param[in] deactType : Type of deactivation to be performed + * + * \return RFAL_ERR_WRONG_STATE : Incorrect state for this operation + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcDeactivate( rfalNfcDeactivateType deactType ); + +#endif /* RFAL_NFC_H */ + + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcDep.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcDep.h new file mode 100644 index 0000000..afad227 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcDep.h @@ -0,0 +1,782 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcDep.h + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-DEP protocol + * + * NFC-DEP is also known as NFCIP - Near Field Communication + * Interface and Protocol + * + * This implementation was based on the following specs: + * - NFC Forum Digital 1.1 + * - ECMA 340 3rd Edition 2013 + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup NFC-DEP + * \brief RFAL NFC-DEP Module + * @{ + */ + +#ifndef RFAL_NFCDEP_H_ +#define RFAL_NFCDEP_H_ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* If module is disabled remove the need for the user to set lengths */ +#if !RFAL_FEATURE_NFC_DEP + #undef RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN + #undef RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN + + #define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN 1U /*!< NFC-DEP Block/Payload length, set to "none" */ + #define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 1U /*!< NFC-DEP PDU length, set to "none" */ +#endif /* !RFAL_FEATURE_NFC_DEP */ + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ +#define RFAL_NFCDEP_FRAME_SIZE_MAX_LEN 254U /*!< Maximum Frame Size Digital 2.0 Table 90 */ +#define RFAL_NFCDEP_DEPREQ_HEADER_LEN 5U /*!< DEP_REQ header length: CMD_TYPE + CMD_CMD + PBF + DID + NAD */ + +/*! Length NFCIP DEP REQ or RES header (incl LEN) */ +#define RFAL_NFCDEP_DEP_HEADER ( RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN + RFAL_NFCDEP_DEP_PFB_LEN ) +#define RFAL_NFCDEP_HEADER ( RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN ) /*!< NFCIP header length */ +#define RFAL_NFCDEP_SB_LEN 1U /*!< SB length on NFCIP fram for NFC-A */ +#define RFAL_NFCDEP_LEN_LEN 1U /*!< LEN length on NFCIP frame */ +#define RFAL_NFCDEP_CMDTYPE_LEN 1U /*!< Length of the cmd type (REQ | RES) on NFCIP frame */ +#define RFAL_NFCDEP_CMD_LEN 1U /*!< Length of the cmd on NFCIP frame */ +#define RFAL_NFCDEP_DID_LEN 1U /*!< Length of did on NFCIP frame */ +#define RFAL_NFCDEP_DEP_PFB_LEN 1U /*!< Length of the PFB field on NFCIP frame */ + +#define RFAL_NFCDEP_DSL_RLS_LEN_NO_DID (RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) /*!< Length of DSL_REQ and RLS_REQ with no DID */ +#define RFAL_NFCDEP_DSL_RLS_LEN_DID (RFAL_NFCDEP_DSL_RLS_LEN_NO_DID + RFAL_NFCDEP_DID_LEN) /*!< Length of DSL_REQ and RLS_REQ with DID */ + +#define RFAL_NFCDEP_FS_VAL_MIN 64U /*!< Minimum LR value */ +#define RFAL_NFCDEP_LR_VAL_MASK 0x03U /*!< Bit mask for a LR value */ +#define RFAL_NFCDEP_PP_LR_MASK 0x30U /*!< Bit mask for LR value in PP byte on a ATR REQ/RES */ +#define RFAL_NFCDEP_PP_LR_SHIFT 4U /*!< Position of LR value in PP byte on a ATR REQ/RES */ + +#define RFAL_NFCDEP_DID_MAX 14U /*!< Max DID value Digital 14.6.2.3 */ +#define RFAL_NFCDEP_DID_KEEP 0xFFU /*!< Keep DID value already configured */ +#define RFAL_NFCDEP_DID_NO 0x00U /*!< No DID shall be used */ +#define RFAL_NFCDEP_NAD_NO 0x00U /*!< No NAD shall be used */ + +#define RFAL_NFCDEP_OPER_RTOX_REQ_DIS 0x01U /*!< Operation config: RTOX REQ disable */ +#define RFAL_NFCDEP_OPER_RTOX_REQ_EN 0x00U /*!< Operation config: RTOX REQ enable */ + +#define RFAL_NFCDEP_OPER_ATN_DIS 0x00U /*!< Operation config: ATN disable */ +#define RFAL_NFCDEP_OPER_ATN_EN 0x02U /*!< Operation config: ATN enable */ + +#define RFAL_NFCDEP_OPER_EMPTY_DEP_DIS 0x04U /*!< Operation config: empty DEPs disable */ +#define RFAL_NFCDEP_OPER_EMPTY_DEP_EN 0x00U /*!< Operation config: empty DEPs enable */ + +#define RFAL_NFCDEP_OPER_FULL_MI_DIS 0x00U /*!< Operation config: full chaining DEPs disable */ +#define RFAL_NFCDEP_OPER_FULL_MI_EN 0x08U /*!< Operation config: full chaining DEPs enable */ + + +#define RFAL_NFCDEP_BRS_MAINTAIN 0xC0U /*!< Value signalling that BR is to be maintained (no PSL) */ +#define RFAL_NFCDEP_BRS_Dx_MASK 0x07U /*!< Value signalling that BR is to be maintained (no PSL) */ +#define RFAL_NFCDEP_BRS_DSI_POS 3U /*!< Value signalling that BR is to be maintained (no PSL) */ + +#define RFAL_NFCDEP_WT_DELTA (16U - RFAL_NFCDEP_WT_DELTA_ADJUST) /*!< NFC-DEP dWRT (adjusted) Digital 2.0 B.10 */ +#define RFAL_NFCDEP_WT_DELTA_ADJUST 4U /*!< dWRT value adjustment */ + + +#define RFAL_NFCDEP_ATR_REQ_NFCID3_POS 2U /*!< NFCID3 offset in ATR_REQ frame */ +#define RFAL_NFCDEP_NFCID3_LEN 10U /*!< NFCID3 Length */ + +#define RFAL_NFCDEP_LEN_MIN 3U /*!< Minimum length byte LEN value */ +#define RFAL_NFCDEP_LEN_MAX 255U /*!< Maximum length byte LEN value */ + +#define RFAL_NFCDEP_ATRRES_HEADER_LEN 2U /*!< ATR RES Header Len: CmdType: 0xD5 + Cod: 0x01 */ +#define RFAL_NFCDEP_ATRRES_MIN_LEN 17U /*!< Minimum length for an ATR RES */ +#define RFAL_NFCDEP_ATRRES_MAX_LEN 64U /*!< Maximum length for an ATR RES Digital 1.0 14.6.1 */ +#define RFAL_NFCDEP_ATRREQ_MIN_LEN 16U /*!< Minimum length for an ATR REQ */ +#define RFAL_NFCDEP_ATRREQ_MAX_LEN RFAL_NFCDEP_ATRRES_MAX_LEN /*!< Maximum length for an ATR REQ Digital 1.0 14.6.1 */ + +#define RFAL_NFCDEP_GB_MAX_LEN (RFAL_NFCDEP_ATRREQ_MAX_LEN - RFAL_NFCDEP_ATRREQ_MIN_LEN) /*!< Maximum length the General Bytes on ATR Digital 1.1 16.6.3 */ + +#define RFAL_NFCDEP_WT_INI_DEFAULT RFAL_NFCDEP_WT_INI_MAX /*!< WT Initiator default value Digital 1.0 14.6.3.8 */ +#define RFAL_NFCDEP_WT_INI_MIN 0U /*!< WT Initiator minimum value Digital 1.0 14.6.3.8 */ +#define RFAL_NFCDEP_WT_INI_MAX 14U /*!< WT Initiator maximum value Digital 1.0 14.6.3.8 A.10 */ +#define RFAL_NFCDEP_RWT_INI_MAX rfalNfcDepWT2RWT( RFAL_NFCDEP_WT_INI_MAX ) /*!< RWT Initiator maximum value */ + +#define RFAL_NFCDEP_WT_TRG_MAX_D10 8U /*!< WT target max Digital 1.0 14.6.3.8 A.10 */ +#define RFAL_NFCDEP_WT_TRG_MAX_D11 14U /*!< WT target max Digital 1.1 16.6.3.9 A.9 */ +#define RFAL_NFCDEP_WT_TRG_MAX_L13 10U /*!< WT target max [LLCP] 1.3 6.2.1 */ +#define RFAL_NFCDEP_WT_TRG_MAX RFAL_NFCDEP_WT_TRG_MAX_D11 /*!< WT target max Digital x.x | LLCP x.x */ +#define RFAL_NFCDEP_RWT_TRG_MAX rfalNfcDepWT2RWT( RFAL_NFCDEP_WT_TRG_MAX ) /*!< RWT Initiator maximum value */ + +/*! Maximum Frame Waiting Time = ((256 * 16/fc)*2^FWImax) = ((256*16/fc)*2^14) = (1048576 / 64)/fc = (100000h*64)/fc */ +#define RFAL_NFCDEP_MAX_FWT ((uint32_t)1U<<20) + +#define RFAL_NFCDEP_WT_MASK 0x0FU /*!< Bit mask for the Wait Time value */ + +#define RFAL_NFCDEP_BR_MASK_106 0x01U /*!< Enable mask bit rate 106 */ +#define RFAL_NFCDEP_BR_MASK_212 0x02U /*!< Enable mask bit rate 242 */ +#define RFAL_NFCDEP_BR_MASK_424 0x04U /*!< Enable mask bit rate 424 */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define rfalNfcDepWT2RWT( wt ) ( (uint32_t)1U << (((uint32_t)(wt) & RFAL_NFCDEP_WT_MASK) + 12U) ) /*!< Converts WT value to RWT (1/fc) */ + +/*! Returns the BRS value from the given bit rate */ +#define rfalNfcDepDx2BRS( br ) ( (((uint8_t)(br) & RFAL_NFCDEP_BRS_Dx_MASK) << RFAL_NFCDEP_BRS_DSI_POS) | ((uint8_t)(br) & RFAL_NFCDEP_BRS_Dx_MASK) ) + +#define rfalNfcDepBRS2DRI( brs ) (uint8_t)( (uint8_t)(brs) & RFAL_NFCDEP_BRS_Dx_MASK ) /*!< Returns the DRI value from the given BRS byte */ +#define rfalNfcDepBRS2DSI( brs ) (uint8_t)( ((uint8_t)(brs) >> RFAL_NFCDEP_BRS_DSI_POS) & RFAL_NFCDEP_BRS_Dx_MASK ) /*!< Returns the DSI value from the given BRS byte */ + +#define rfalNfcDepPP2LR( PPx ) ( ((uint8_t)(PPx) & RFAL_NFCDEP_PP_LR_MASK ) >> RFAL_NFCDEP_PP_LR_SHIFT) /*!< Returns the LR value from the given PPx byte */ +#define rfalNfcDepLR2PP( LRx ) ( ((uint8_t)(LRx) << RFAL_NFCDEP_PP_LR_SHIFT) & RFAL_NFCDEP_PP_LR_MASK) /*!< Returns the PP byte with the given LRx value */ + +/*! Returns the Frame size value from the given LRx value */ +#define rfalNfcDepLR2FS( LRx ) (uint16_t)(RFAL_MIN( (RFAL_NFCDEP_FS_VAL_MIN * ((uint16_t)(LRx) + 1U) ), RFAL_NFCDEP_FRAME_SIZE_MAX_LEN )) + +/*! + * Despite DIGITAL 1.0 14.6.2.1 stating that the last two bytes may filled with + * any value, some devices (Samsung Google Nexus) only accept when these are 0 */ +#define rfalNfcDepSetNFCID( dst, src, len ) RFAL_MEMSET( (dst), 0x00, RFAL_NFCDEP_NFCID3_LEN ); \ + if( (len) > 0U ) {RFAL_MEMCPY( (dst), (src), (len) );} + +/* + ****************************************************************************** + * GLOBAL ENUMERATIONS + ****************************************************************************** + */ + +/*! Enumeration of NFC-DEP bit rate in ATR Digital 1.0 Table 93 and 94 */ +enum{ + RFAL_NFCDEP_Bx_NO_HIGH_BR = 0x00, /*!< Peer supports no high bit rates */ + RFAL_NFCDEP_Bx_08_848 = 0x01, /*!< Peer also supports 848 */ + RFAL_NFCDEP_Bx_16_1695 = 0x02, /*!< Peer also supports 1695 */ + RFAL_NFCDEP_Bx_32_3390 = 0x04, /*!< Peer also supports 3390 */ + RFAL_NFCDEP_Bx_64_6780 = 0x08 /*!< Peer also supports 6780 */ +}; + +/*! Enumeration of NFC-DEP bit rate Dividor in PSL Digital 1.0 Table 100 */ +enum{ + RFAL_NFCDEP_Dx_01_106 = RFAL_BR_106, /*!< Divisor D = 1 : bit rate = 106 */ + RFAL_NFCDEP_Dx_02_212 = RFAL_BR_212, /*!< Divisor D = 2 : bit rate = 212 */ + RFAL_NFCDEP_Dx_04_424 = RFAL_BR_424, /*!< Divisor D = 4 : bit rate = 424 */ + RFAL_NFCDEP_Dx_08_848 = RFAL_BR_848, /*!< Divisor D = 8 : bit rate = 848 */ + RFAL_NFCDEP_Dx_16_1695 = RFAL_BR_1695, /*!< Divisor D = 16 : bit rate = 1695 */ + RFAL_NFCDEP_Dx_32_3390 = RFAL_BR_3390, /*!< Divisor D = 32 : bit rate = 3390 */ + RFAL_NFCDEP_Dx_64_6780 = RFAL_BR_6780 /*!< Divisor D = 64 : bit rate = 6780 */ +}; + +/*! Enumeration of NFC-DEP Length Reduction (LR) Digital 1.0 Table 91 */ +enum{ + RFAL_NFCDEP_LR_64 = 0x00, /*!< Maximum payload size is 64 bytes */ + RFAL_NFCDEP_LR_128 = 0x01, /*!< Maximum payload size is 128 bytes */ + RFAL_NFCDEP_LR_192 = 0x02, /*!< Maximum payload size is 192 bytes */ + RFAL_NFCDEP_LR_254 = 0x03 /*!< Maximum payload size is 254 bytes */ +}; + +/* + ****************************************************************************** + * GLOBAL DATA TYPES + ****************************************************************************** + */ + +/*! NFC-DEP callback to check if upper layer has deactivation pending */ +typedef bool (* rfalNfcDepDeactCallback)(void); + + +/*! Enumeration of the nfcip communication modes */ +typedef enum{ + RFAL_NFCDEP_COMM_PASSIVE, /*!< Passive communication mode */ + RFAL_NFCDEP_COMM_ACTIVE /*!< Active communication mode */ +} rfalNfcDepCommMode; + + +/*! Enumeration of the nfcip roles */ +typedef enum{ + RFAL_NFCDEP_ROLE_INITIATOR, /*!< Perform as Initiator */ + RFAL_NFCDEP_ROLE_TARGET /*!< Perform as Target */ +} rfalNfcDepRole; + + +/*! Struct that holds all NFCIP configs */ +typedef struct{ + + rfalNfcDepRole role; /*!< Current NFCIP role */ + rfalNfcDepCommMode commMode; /*!< Current NFCIP communication mode */ + uint8_t oper; /*!< Operation config similar to NCI 1.0 Table 81 */ + + uint8_t did; /*!< Current Device ID (DID) */ + uint8_t nad; /*!< Current Node Addressing (NAD) */ + uint8_t bs; /*!< Bit rate in Sending Direction */ + uint8_t br; /*!< Bit rate in Receiving Direction */ + uint8_t nfcid[RFAL_NFCDEP_NFCID3_LEN]; /*!< Pointer to the NFCID to be used */ + uint8_t nfcidLen; /*!< Length of the given NFCID in nfcid */ + uint8_t gb[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Pointer General Bytes (GB) to be used */ + uint8_t gbLen; /*!< Length of the given GB in gb */ + uint8_t lr; /*!< Length Reduction (LR) to be used */ + uint8_t to; /*!< Timeout (TO) to be used */ + uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used */ + uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used */ +} rfalNfcDepConfigs; + + +/*! ATR_REQ command Digital 1.1 16.6.2 */ +typedef struct { + uint8_t CMD1; /*!< Command format 0xD4 */ + uint8_t CMD2; /*!< Command Value */ + uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value */ + uint8_t DID; /*!< DID */ + uint8_t BSi; /*!< Sending Bitrate for Initiator */ + uint8_t BRi; /*!< Receiving Bitrate for Initiator */ + uint8_t PPi; /*!< Optional Parameters presence indicator */ + uint8_t GBi[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes */ +} rfalNfcDepAtrReq; + + +/*! ATR_RES response Digital 1.1 16.6.3 */ +typedef struct { + uint8_t CMD1; /*!< Response Byte 0xD5 */ + uint8_t CMD2; /*!< Command Value */ + uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value */ + uint8_t DID; /*!< DID */ + uint8_t BSt; /*!< Sending Bitrate for Initiator */ + uint8_t BRt; /*!< Receiving Bitrate for Initiator */ + uint8_t TO; /*!< Timeout */ + uint8_t PPt; /*!< Optional Parameters presence indicator */ + uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes */ +} rfalNfcDepAtrRes; + + +/*! Structure of transmit I-PDU Buffer format from caller */ +typedef struct +{ + uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue space for NFC-DEP header*/ + uint8_t inf[RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN]; /*!< INF | Data area of the buffer */ +} rfalNfcDepBufFormat; + + +/*! Structure of APDU Buffer format from caller */ +typedef struct +{ + uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue/SoD buffer */ + uint8_t pdu[RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN]; /*!< Complete PDU/Payload buffer */ +} rfalNfcDepPduBufFormat; + + +/*! Activation info as Initiator and Target */ +typedef union { /* PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently , device is only initiatior or target a time. No problem can occur. */ + struct { + rfalNfcDepAtrRes ATR_RES; /*!< ATR RES (Initiator mode) */ + uint8_t ATR_RESLen; /*!< ATR RES length (Initiator mode) */ + }Target; /*!< Target */ + struct { + rfalNfcDepAtrReq ATR_REQ; /*!< ATR REQ (Target mode) */ + uint8_t ATR_REQLen; /*!< ATR REQ length (Target mode) */ + }Initiator; /*!< Initiator */ +} rfalNfcDepActivation; + + +/*! NFC-DEP device Info */ +typedef struct { + uint8_t GBLen; /*!< General Bytes length */ + uint8_t WT; /*!< WT to be used (ignored in Listen Mode) */ + uint32_t FWT; /*!< FWT to be used (1/fc)(ignored Listen Mode) */ + uint32_t dFWT; /*!< Delta FWT to be used (1/fc) */ + uint8_t LR; /*!< Length Reduction coding the max payload */ + uint16_t FS; /*!< Frame Size */ + rfalBitRate DSI; /*!< Bit Rate coding from Initiator to Target */ + rfalBitRate DRI; /*!< Bit Rate coding from Target to Initiator */ + uint8_t DID; /*!< Device ID (RFAL_NFCDEP_DID_NO if no DID) */ + uint8_t NAD; /*!< Node ADdress (RFAL_NFCDEP_NAD_NO if no NAD)*/ +} rfalNfcDepInfo; + + +/*! NFC-DEP Device structure */ +typedef struct { + rfalNfcDepActivation activation; /*!< Activation Info */ + rfalNfcDepInfo info; /*!< NFC-DEP device Info */ +} rfalNfcDepDevice; + + +/*! NFCIP Protocol structure for P2P Target + * + * operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter + * NCI 1.1 Table 86: NFC-DEP Operation Parameter + * and it's a bit mask composed as: + * [ 0000b + * | Chain SHALL use max. Transport Data Byte[1b] + * | I-PDU with no Transport Data SHALL NOT be sent [1b] + * | NFC-DEP Target SHALL NOT send RTOX request [1b] + * ] + * + */ +typedef struct{ + rfalNfcDepCommMode commMode; /*!< Initiator in Active P2P or Passive P2P*/ + uint8_t operParam; /*!< NFC-DEP Operation Parameter */ + uint8_t* nfcid; /*!< Initiator's NFCID2 or NFCID3 */ + uint8_t nfcidLen; /*!< Initiator's NFCID length (NFCID2/3) */ + uint8_t DID; /*!< Initiator's Device ID DID */ + uint8_t NAD; /*!< Initiator's Node ID NAD */ + uint8_t BS; /*!< Initiator's Bit Rates supported in Tx */ +#define ESP_BR BR +#undef BR + uint8_t BR; /*!< Initiator's Bit Rates supported in Rx */ +#define BR ESP_BR +#undef ESP_BR + uint8_t LR; /*!< Initiator's Length reduction */ + uint8_t* GB; /*!< Initiator's General Bytes (Gi) */ + uint8_t GBLen; /*!< Initiator's General Bytes length */ +} rfalNfcDepAtrParam; + +/*! Structure of parameters to be passed in for nfcDepListenStartActivation */ +typedef struct +{ + rfalNfcDepBufFormat *rxBuf; /*!< Receive Buffer struct reference */ + uint16_t *rxLen; /*!< Receive INF data length in bytes */ + bool *isRxChaining; /*!< Received data is not complete */ + rfalNfcDepDevice *nfcDepDev; /*!< NFC-DEP device info */ +} rfalNfcDepListenActvParam; + + +/*! NFCIP Protocol structure for P2P Target + * + * operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter + * NCI 1.1 Table 86: NFC-DEP Operation Parameter + * and it's a bit mask composed as: + * [ 0000b + * | Chain SHALL use max. Transport Data Byte[1b] + * | I-PDU with no Transport Data SHALL NOT be sent [1b] + * | NFC-DEP Target SHALL NOT send RTOX request [1b] + * ] + * + */ +typedef struct{ + rfalNfcDepCommMode commMode; /*!< Target in Active P2P or Passive P2P */ + uint8_t nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< Target's NFCID3 */ + uint8_t bst; /*!< Target's Bit Rates supported in Tx */ + uint8_t brt; /*!< Target's Bit Rates supported in Rx */ + uint8_t to; /*!< Target's timeout (TO) value */ + uint8_t ppt; /*!< Target's Presence optional Params(PPt)*/ + uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Target's General Bytes (Gt) */ + uint8_t GBtLen; /*!< Target's General Bytes length */ + uint8_t operParam; /*!< NFC-DEP Operation Parameter */ +} rfalNfcDepTargetParam; + + +/*! Structure of parameters to be passed in for nfcDepStartIpduTransceive */ +typedef struct +{ + rfalNfcDepBufFormat *txBuf; /*!< Transmit Buffer struct reference */ + uint16_t txBufLen; /*!< Transmit Buffer INF field length in bytes */ + bool isTxChaining; /*!< Transmit data is not complete */ + rfalNfcDepBufFormat *rxBuf; /*!< Receive Buffer struct reference */ + uint16_t *rxLen; /*!< Receive INF data length */ + bool *isRxChaining; /*!< Received data is not complete */ + uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */ + uint32_t dFWT; /*!< Delta FWT to be used */ + uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */ + uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */ +} rfalNfcDepTxRxParam; + + +/*! Structure of parameters used on NFC DEP PDU Transceive */ +typedef struct +{ + rfalNfcDepPduBufFormat *txBuf; /*!< Transmit Buffer struct reference */ + uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/ + rfalNfcDepPduBufFormat *rxBuf; /*!< Receive Buffer struct reference in Bytes */ + uint16_t *rxLen; /*!< Received INF data length in Bytes */ + rfalNfcDepBufFormat *tmpBuf; /*!< Temp buffer for single PDUs (internal) */ + uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */ + uint32_t dFWT; /*!< Delta FWT to be used */ + uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */ + uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */ +} rfalNfcDepPduTxRxParam; + + +/* + * ***************************************************************************** + * GLOBAL VARIABLE DECLARATIONS + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +/*! + ****************************************************************************** + * \brief NFCIP Initialize + * + * This method resets all NFC-DEP inner states, counters and context and sets + * default values + * + ****************************************************************************** + */ +void rfalNfcDepInitialize( void ); + + +/*! + ****************************************************************************** + * \brief Set deactivating callback + * + * Sets the deactivating callback so that nfcip layer can check if upper layer + * has a deactivation pending, and not perform error recovery upon specific + * errors + * + * \param[in] pFunc : method pointer to deactivation flag check + ****************************************************************************** + */ +void rfalNfcDepSetDeactivatingCallback( rfalNfcDepDeactCallback pFunc ); + + +/*! + ****************************************************************************** + * \brief Calculate Response Waiting Time + * + * Calculates the Response Waiting Time (RWT) from the given Waiting Time (WT) + * + * \param[in] wt : the WT value to calculate RWT + * + * \return RWT value in 1/fc + ****************************************************************************** + */ +uint32_t rfalNfcDepCalculateRWT( uint8_t wt ); + + +/*! + ****************************************************************************** + * \brief NFC-DEP Initiator ATR (Attribute Request) + * + * This method configures the NFC-DEP layer with given parameters and then + * sends an ATR to the Target with and checks for a valid response response + * + * \param[in] param : parameters to initialize and compose the ATR + * \param[out] atrRes : location to store the ATR_RES + * \param[out] atrResLen : length of the ATR_RES received + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_TIMEOUT : Timeout occurred + * \return RFAL_ERR_PROTO : Protocol error occurred + ****************************************************************************** + */ +ReturnCode rfalNfcDepATR( const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes *atrRes, uint8_t* atrResLen ); + + +/*! + ****************************************************************************** + * \brief NFC-DEP Initiator PSL (Parameter Selection) + * + * This method sends a PSL to the Target with the given parameters and checks + * for a valid response response + * + * The parameters must be coded according to Digital 1.1 16.7.1 + * + * \param[in] BRS : the selected Bit Rates for Initiator and Target + * \param[in] FSL : the maximum length of Commands and Responses + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_TIMEOUT : Timeout occurred + * \return RFAL_ERR_PROTO : Protocol error occurred + ****************************************************************************** + */ +ReturnCode rfalNfcDepPSL( uint8_t BRS, uint8_t FSL ); + + +/*! + ****************************************************************************** + * \brief NFC-DEP Initiator DSL (Deselect) + * + * This method checks if the NFCIP module is configured as initiator and if + * so sends a DSL REQ, waits the target's response and checks it + * + * In case of performing as target no action is taken + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_TIMEOUT : Timeout occurred + * \return RFAL_ERR_MAX_RERUNS : Timeout occurred + * \return RFAL_ERR_PROTO : Protocol error occurred + ****************************************************************************** + */ +ReturnCode rfalNfcDepDSL( void ); + + +/*! + ****************************************************************************** + * \brief NFC-DEP Initiator RLS (Release) + * + * This method checks if the NFCIP module is configured as initiator and if + * so sends a RLS REQ, waits target's response and checks it + * + * In case of performing as target no action is taken + * + * \return RFAL_ERR_NONE : No error + * \return RFAL_ERR_TIMEOUT : Timeout occurred + * \return RFAL_ERR_MAX_RERUNS : Timeout occurred + * \return RFAL_ERR_PROTO : Protocol error occurred + ****************************************************************************** + */ +ReturnCode rfalNfcDepRLS( void ); + + +/*! + ***************************************************************************** + * \brief NFC-DEP Initiator Handle Activation + * + * This performs a Activation into NFC-DEP layer with the given + * parameters. It sends ATR_REQ and if the higher bit rates are supported by + * both devices it additionally sends PSL + * Once Activated all details of the device are provided on nfcDepDev + * + * \param[in] param : required parameters to initialize and send ATR_REQ + * \param[in] desiredBR : Desired bit rate supported by the Poller + * \param[out] nfcDepDev : NFC-DEP information of the activated Listen device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalNfcDepInitiatorHandleActivation( rfalNfcDepAtrParam* param, rfalBitRate desiredBR, rfalNfcDepDevice* nfcDepDev ); + + +/*! + ****************************************************************************** + * \brief Check if buffer contains valid ATR_REQ + * + * This method checks if the given ATR_REQ is valid + * + * + * \param[in] buf : buffer holding Initiator's received request + * \param[in] bufLen : size of the msg contained on the buf in Bytes + * \param[out] nfcid3 : pointer to where the NFCID3 may be outputed, + * nfcid3 has NFCF_SENSF_NFCID3_LEN as length + * Pass NULL if output parameter not desired + * + * \return true : Valid ATR_REQ received, the ATR_RES has been computed in txBuf + * \return false : Invalid protocol request + * + ****************************************************************************** + */ +bool rfalNfcDepIsAtrReq( const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3 ); + + +/*! + ****************************************************************************** + * \brief Check is Target has received ATR + * + * This method checks if the NFCIP module is configured as target and if a + * ATR REQ has been received ( whether is in activation or in data exchange) + * + * \return true : a ATR has already been received + * \return false : no ATR has been received + ****************************************************************************** + */ +bool rfalNfcDepTargetRcvdATR( void ); + +/*! + ***************************************************************************** + * \brief NFCDEP Start Listen Activation Handling + * + * Start Activation Handling and setup to receive first frame which may + * contain complete or partial DEP-REQ after activation is completed + * + * Pass in ATR_REQ for NFC-DEP to handle ATR_RES. The Activation Handling + * handles ATR_RES and PSL_RES if a PSL_REQ is received + * + * Activation is completed if PSL_RES is sent or if first I-PDU is received + * + * \ref rfalNfcDepListenGetActivationStatus() provide status of the + * ongoing activation + * + * \warning nfcDepGetTransceiveStatus() shall be called right after activation + * is completed (i.e. rfalNfcDepListenGetActivationStatus() return RFAL_ERR_NONE) + * to check for first received frame. + * + * \param[in] param : Target parameters to be used + * \param[in] atrReq : reference to buffer containing ATR_REQ + * \param[in] atrReqLength: Length of ATR_REQ + * \param[out] rxParam : references to buffer, length and chaining indication + * for first complete LLCP to be received + * + * \return RFAL_ERR_NONE : ATR_REQ is valid and activation ongoing + * \return RFAL_ERR_PARAM : ATR_REQ or other params are invalid + * \return RFAL_ERR_LINK_LOSS : Remote Field is turned off + ***************************************************************************** + */ +ReturnCode rfalNfcDepListenStartActivation( const rfalNfcDepTargetParam *param, const uint8_t *atrReq, uint16_t atrReqLength, rfalNfcDepListenActvParam rxParam ); + + +/*! + ***************************************************************************** + * \brief Get the current NFC-DEP Activation Status + * + * \return RFAL_ERR_NONE : Activation has completed successfully + * \return RFAL_ERR_BUSY : Activation is ongoing + * \return RFAL_ERR_LINK_LOSS : Remote Field was turned off + ***************************************************************************** + */ +ReturnCode rfalNfcDepListenGetActivationStatus( void ); + +/*! + ***************************************************************************** + * \brief Start Transceive + * + * Transceives a complete or partial DEP block + * + * The txBuf contains complete or partial of DEP to be transmitted. + * The Prologue field of the I-PDU is handled internally + * + * If the buffer contains partial LLCP and is not the last block, then + * isTxChaining must be set to true + * + * \param[in] param: reference parameters to be used for the Transceive + * + * \return RFAL_ERR_PARAM : Bad request + * \return RFAL_ERR_WRONG_STATE : The module is not in a proper state + * \return RFAL_ERR_NONE : The Transceive request has been started + ***************************************************************************** + */ +ReturnCode rfalNfcDepStartTransceive( const rfalNfcDepTxRxParam *param ); + + +/*! + ***************************************************************************** + * \brief Return the Transceive status + * + * Returns the status of the NFC-DEP Transceive + * + * \warning When the other device is performing chaining once a chained + * block is received the error RFAL_ERR_AGAIN is sent. At this point + * caller must handle the received data immediately. + * When RFAL_ERR_AGAIN is returned an ACK has already been sent to + * the other device and the next block might be incoming. + * If rfalWorker() is called frequently it will place the next + * block on the given buffer + * + * \return RFAL_ERR_NONE : Transceive has been completed successfully + * \return RFAL_ERR_BUSY : Transceive is ongoing + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : Timeout error occurred + * \return RFAL_ERR_SLEEP_REQ : Deselect has been received and responded + * \return RFAL_ERR_NOMEM : The received I-PDU does not fit into the + * receive buffer + * \return RFAL_ERR_LINK_LOSS : Communication is lost because Reader/Writer + * has turned off its field + * \return RFAL_ERR_AGAIN : received one chaining block, continue to call + * this method to retrieve the remaining blocks + ***************************************************************************** + */ +ReturnCode rfalNfcDepGetTransceiveStatus( void ); + + +/*! + ***************************************************************************** + * \brief Start PDU Transceive + * + * This method triggers a NFC-DEP Transceive containing a complete PDU + * It transmits the given message and handles all protocol retransmitions, + * error handling and control messages + * + * The txBuf contains a complete PDU to be transmitted + * The Prologue field will be manipulated by the Transceive + * + * \warning the txBuf will be modified during the transmission + * \warning the maximum RF frame which can be received is limited by param.tmpBuf + * + * \param[in] param: reference parameters to be used for the Transceive + * + * \return RFAL_ERR_PARAM : Bad request + * \return RFAL_ERR_WRONG_STATE : The module is not in a proper state + * \return RFAL_ERR_NONE : The Transceive request has been started + ***************************************************************************** + */ +ReturnCode rfalNfcDepStartPduTransceive( rfalNfcDepPduTxRxParam param ); + + +/*! + ***************************************************************************** + * \brief Return the PDU Transceive status + * + * Returns the status of the NFC-DEP PDU Transceive + * + * + * \return RFAL_ERR_NONE : Transceive has been completed successfully + * \return RFAL_ERR_BUSY : Transceive is ongoing + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_TIMEOUT : Timeout error occurred + * \return RFAL_ERR_SLEEP_REQ : Deselect has been received and responded + * \return RFAL_ERR_NOMEM : The received I-PDU does not fit into the + * receive buffer + * \return RFAL_ERR_LINK_LOSS : Communication is lost because Reader/Writer + * has turned off its field + ***************************************************************************** + */ +ReturnCode rfalNfcDepGetPduTransceiveStatus( void ); + +#endif /* RFAL_NFCDEP_H_ */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfca.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfca.h new file mode 100644 index 0000000..14c07c7 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfca.h @@ -0,0 +1,574 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfca.h + * + * \author Gustavo Patricio + * + * \brief Provides several NFC-A convenience methods and definitions + * + * It provides a Poller (ISO14443A PCD) interface as well as + * some NFC-A Listener (ISO14443A PICC) helpers. + * + * The definitions and helper methods provided by this module are only + * up to ISO14443-3 layer + * + * + * An usage example is provided here: \ref exampleRfalNfca.c + * \example exampleRfalNfca.c + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup NFC-A + * \brief RFAL NFC-A Module + * @{ + * + */ + + +#ifndef RFAL_NFCA_H +#define RFAL_NFCA_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" +#include "rfal_t1t.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCA_CASCADE_1_UID_LEN 4U /*!< UID length of cascade level 1 only tag */ +#define RFAL_NFCA_CASCADE_2_UID_LEN 7U /*!< UID length of cascade level 2 only tag */ +#define RFAL_NFCA_CASCADE_3_UID_LEN 10U /*!< UID length of cascade level 3 only tag */ + +#define RFAL_NFCA_SENS_RES_PLATFORM_MASK 0x0FU /*!< SENS_RES (ATQA) platform configuration mask Digital 1.1 Table 10 */ +#define RFAL_NFCA_SENS_RES_PLATFORM_T1T 0x0CU /*!< SENS_RES (ATQA) T1T platform configuration Digital 1.1 Table 10 */ + +#define RFAL_NFCA_SEL_RES_CONF_MASK 0x60U /*!< SEL_RES (SAK) platform configuration mask Digital 1.1 Table 19 */ +#define RFAL_NFCA_SEL_RES_CONF_T2T 0x00U /*!< SEL_RES (SAK) T2T configuration Digital 1.1 Table 19 */ +#define RFAL_NFCA_SEL_RES_CONF_T4T 0x20U /*!< SEL_RES (SAK) T4T configuration Digital 1.1 Table 19 */ +#define RFAL_NFCA_SEL_RES_CONF_NFCDEP 0x40U /*!< SEL_RES (SAK) NFC-DEP configuration Digital 1.1 Table 19 */ +#define RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP 0x60U /*!< SEL_RES (SAK) T4T and NFC-DEP configuration Digital 1.1 Table 19 */ + + +/*! NFC-A minimum FDT(listen) = ((n * 128 + (84)) / fc) with n_min = 9 Digital 1.1 6.10.1 + * = (1236)/fc + * Relax with 3etu: (3*128)/fc as with multiple NFC-A cards, response may take longer (JCOP cards) + * = (1236 + 384)/fc = 1620 / fc */ +#define RFAL_NFCA_FDTMIN 1620U +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/*! Checks if device is a T1T given its SENS_RES */ +#define rfalNfcaIsSensResT1T( sensRes ) ((((rfalNfcaSensRes*)(sensRes))->platformInfo & RFAL_NFCA_SENS_RES_PLATFORM_MASK) == RFAL_NFCA_SENS_RES_PLATFORM_T1T ) + +/*! Checks if device is a T2T given its SENS_RES */ +#define rfalNfcaIsSelResT2T( selRes ) ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == RFAL_NFCA_SEL_RES_CONF_T2T ) + +/*! Checks if device is a T4T given its SENS_RES */ +#define rfalNfcaIsSelResT4T( selRes ) ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == RFAL_NFCA_SEL_RES_CONF_T4T ) + +/*! Checks if device supports NFC-DEP protocol given its SENS_RES */ +#define rfalNfcaIsSelResNFCDEP( selRes ) ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == RFAL_NFCA_SEL_RES_CONF_NFCDEP ) + +/*! Checks if device supports ISO-DEP and NFC-DEP protocol given its SENS_RES */ +#define rfalNfcaIsSelResT4TNFCDEP( selRes ) ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP ) + +/*! Checks if a NFC-A listener device supports multiple protocols (ISO-DEP and NFC-DEP) */ +#define rfalNfcaLisDevIsMultiProto( lisDev ) (((rfalNfcaListenDevice*)(lisDev))->type == RFAL_NFCA_T4T_NFCDEP ) + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! NFC-A Listen device types */ +typedef enum { + RFAL_NFCA_T1T = 0x01, /* Device configured for T1T Digital 1.1 Table 9 */ + RFAL_NFCA_T2T = 0x00, /* Device configured for T2T Digital 1.1 Table 19 */ + RFAL_NFCA_T4T = 0x20, /* Device configured for T4T Digital 1.1 Table 19 */ + RFAL_NFCA_NFCDEP = 0x40, /* Device configured for NFC-DEP Digital 1.1 Table 19 */ + RFAL_NFCA_T4T_NFCDEP = 0x60 /* Device configured for NFC-DEP and T4T Digital 1.1 Table 19 */ +} rfalNfcaListenDeviceType; + + +/*! SENS_RES (ATQA) format Digital 1.1 6.6.3 & Table 7 */ +typedef struct +{ + uint8_t anticollisionInfo; /*!< SENS_RES Anticollision Information */ + uint8_t platformInfo; /*!< SENS_RES Platform Information */ +} rfalNfcaSensRes; + + +/*! SDD_REQ (Anticollision) format Digital 1.1 6.7.1 & Table 11 */ +typedef struct +{ + uint8_t selCmd; /*!< SDD_REQ SEL_CMD: cascade Level */ + uint8_t selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/ +} rfalNfcaSddReq; + + +/*! SDD_RES (UID CLn) format Digital 1.1 6.7.2 & Table 15 */ +typedef struct +{ + uint8_t nfcid1[RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 cascade level NFCID */ + uint8_t bcc; /*!< BCC Exclusive-OR over first 4 bytes of SDD_RES */ +} rfalNfcaSddRes; + + +/*! SEL_REQ (Select) format Digital 1.1 6.8.1 & Table 17 */ +typedef struct +{ + uint8_t selCmd; /*!< SDD_REQ SEL_CMD: cascade Level */ + uint8_t selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/ + uint8_t nfcid1[RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 data */ + uint8_t bcc; /*!< Checksum calculated as exclusive-OR over the 4 bytes of NFCID1 CLn */ +} rfalNfcaSelReq; + + +/*! SEL_RES (SAK) format Digital 1.1 6.8.2 & Table 19 */ +typedef struct +{ + uint8_t sak; /*!< Select Acknowledge */ +} rfalNfcaSelRes; + + +/*! NFC-A listener device (PICC) struct */ +typedef struct +{ + rfalNfcaListenDeviceType type; /*!< NFC-A Listen device type */ + rfalNfcaSensRes sensRes; /*!< SENS_RES (ATQA) */ + rfalNfcaSelRes selRes; /*!< SEL_RES (SAK) */ + uint8_t nfcId1Len; /*!< NFCID1 Length */ + uint8_t nfcId1[RFAL_NFCA_CASCADE_3_UID_LEN]; /*!< NFCID1 (UID) */ +#ifdef RFAL_FEATURE_T1T + rfalT1TRidRes ridRes; /*!< RID_RES */ +#endif /* RFAL_FEATURE_T1T */ + bool isSleep; /*!< Device sleeping flag */ +} rfalNfcaListenDevice; + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Initialize NFC-A Poller mode + * + * This methods configures RFAL RF layer to perform as a + * NFC-A Poller/RW (ISO14443A PCD) including all default timings and bit rate + * to 106 kbps + + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerInitialize( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Check Presence + * + * This method checks if a NFC-A Listen device (PICC) is present on the field + * by sending an ALL_REQ (WUPA) or SENS_REQ (REQA) + * + * \param[in] cmd : Indicate if to send an ALL_REQ or a SENS_REQ + * \param[out] sensRes : If received, the SENS_RES + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_RF_COLLISION : Collision detected one or more device in the field + * \return RFAL_ERR_PAR : Parity error detected, one or more device in the field + * \return RFAL_ERR_CRC : CRC error detected, one or more device in the field + * \return RFAL_ERR_FRAMING : Framing error detected, one or more device in the field + * \return RFAL_ERR_PROTO : Protocol error detected, one or more device in the field + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerCheckPresence( rfal14443AShortFrameCmd cmd, rfalNfcaSensRes *sensRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Select + * + * This method selects a NFC-A Listener device (PICC) + * + * \param[in] nfcid1 : Listener device NFCID1 to be selected + * \param[in] nfcidLen : Length of the NFCID1 to be selected + * \param[out] selRes : pointer to place the SEL_RES + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerSelect( const uint8_t *nfcid1, uint8_t nfcidLen, rfalNfcaSelRes *selRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Start Select + * + * This method starts the selection of a NFC-A Listener device (PICC) + * + * \param[in] nfcid1 : Listener device NFCID1 to be selected + * \param[in] nfcidLen : Length of the NFCID1 to be selected + * \param[out] selRes : pointer to place the SEL_RES + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerStartSelect( const uint8_t *nfcid1, uint8_t nfcidLen, rfalNfcaSelRes *selRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Get Select Status + * + * This method gets the selection status + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerGetSelectStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Sleep + * + * This method sends a SLP_REQ (HLTA) + * No response is expected afterwards Digital 1.1 6.9.2.1 + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerSleep( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Start Sleep + * + * This method sends a SLP_REQ (HLTA) + * No response is expected afterwards Digital 1.1 6.9.2.1 + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerStartSleep( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Get Sleep Status + * + * Returns the Sleep status + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerGetSleepStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Technology Detection + * + * This method performs NFC-A Technology Detection as defined in the spec + * given in the compliance mode + * + * \param[in] compMode : compliance mode to be performed + * \param[out] sensRes : location to store the SENS_RES, if received + * + * When compMode is set to ISO compliance a SLP_REQ (HLTA) is not sent + * after detection. When set to EMV a ALL_REQ (WUPA) is sent instead of + * a SENS_REQ (REQA) + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerTechnologyDetection( rfalComplianceMode compMode, rfalNfcaSensRes *sensRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A Start Technology Detection + * + * This method starts NFC-A Technology Detection as defined in the spec + * given in the compliance mode + * + * \param[in] compMode : compliance mode to be performed + * \param[out] sensRes : location to store the SENS_RES, if received + * + * When compMode is set to ISO compliance a SLP_REQ (HLTA) is not sent + * after detection. When set to EMV a ALL_REQ (WUPA) is sent instead of + * a SENS_REQ (REQA) + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerStartTechnologyDetection( rfalComplianceMode compMode, rfalNfcaSensRes *sensRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A Get Technology Detection Status + * + * Returns the Technology Detection status + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerGetTechnologyDetectionStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Collision Resolution + * + * Collision resolution for one NFC-A Listener device/card (PICC) as + * defined in Activity 2.1 9.3.4 + * + * This method executes anti collision loop and select the device with higher NFCID1 + * + * When devLimit = 0 it is configured to perform collision detection only. Once a collision + * is detected the collision resolution is aborted immidiatly. If only one device is found + * with no collisions, it will properly resolved. + * + * \param[in] devLimit : device limit value (CON_DEVICES_LIMIT) + * \param[out] collPending : pointer to collision pending flag (INT_COLL_PEND) + * \param[out] selRes : location to store the last Select Response from listener device (PICC) + * \param[out] nfcId1 : location to store the NFCID1 (UID), ensure RFAL_NFCA_CASCADE_3_UID_LEN + * \param[out] nfcId1Len : pointer to length of NFCID1 (UID) + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_PROTO : Card length invalid + * \return RFAL_ERR_IGNORE : conDevLimit is 0 and there is a collision + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerSingleCollisionResolution( uint8_t devLimit, bool *collPending, rfalNfcaSelRes *selRes, uint8_t *nfcId1, uint8_t *nfcId1Len ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Full Collision Resolution + * + * Performs a full Collision resolution as defined in Activity 2.1 9.3.4 + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcaDevList + * \param[out] nfcaDevList : NFC-A listener device info + * \param[out] devCnt : Devices found counter + * + * When compMode is set to ISO compliance it assumes that the device is + * not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning. + * When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent + * at the beginning. + * + * + * When devLimit = 0 it is configured to perform collision detection only. Once a collision + * is detected the collision resolution is aborted immidiatly. If only one device is found + * with no collisions, it will properly resolved. + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerFullCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Full Collision Resolution with Sleep + * + * Performs a full Collision resolution similar to rfalNfcaPollerFullCollisionResolution + * but an additional SLP_REQ (HLTA) -> SENS_RES (REQA) is sent regardless if there + * was a collision. + * This proprietary behaviour ensures proper activation of certain devices that suffer + * from influence of Type B commands as foreseen in ISO14443-3 5.2.3 or were somehow + * not detected by the first round of collision resolution + * + * \param[in] devLimit : device limit value, and size nfcaDevList + * \param[out] nfcaDevList : NFC-A listener device info + * \param[out] devCnt : Devices found counter + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerSleepFullCollisionResolution( uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-A Poller Start Full Collision Resolution + * + * This method starts the full Collision resolution as defined + * in Activity 1.0 or 1.1 9.3.4 + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcaDevList + * \param[out] nfcaDevList : NFC-A listener device info + * \param[out] devCnt : Devices found counter + * + * When compMode is set to ISO compliance it assumes that the device is + * not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning. + * When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent at + * the beginning. + * + * + * When devLimit = 0 it is configured to perform collision detection only. Once a collision + * is detected the collision resolution is aborted immidiatly. If only one device is found + * with no collisions, it will properly resolved. + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerStartFullCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-A Get Full Collision Resolution Status + * + * Returns the Collision Resolution status + * + * \return RFAL_ERR_BUSY : Operation is ongoing + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A Listener is SLP_REQ + * + * Checks if the given buffer contains valid NFC-A SLP_REQ (HALT) + * + * \param[in] buf: buffer containing data + * \param[in] bufLen: length of the data in buffer to be checked + * + * \return true if data in buf contains a SLP_REQ ; false otherwise + ***************************************************************************** + */ +bool rfalNfcaListenerIsSleepReq( const uint8_t *buf, uint16_t bufLen ); + + +#endif /* RFAL_NFCA_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcb.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcb.h new file mode 100644 index 0000000..4f2fca8 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcb.h @@ -0,0 +1,597 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcb.h + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-B (ISO14443B) helpers + * + * It provides a NFC-B Poller (ISO14443B PCD) interface and + * also provides some NFC-B Listener (ISO14443B PICC) helpers + * + * The definitions and helpers methods provided by this module are only + * up to ISO14443-3 layer (excluding ATTRIB) + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup NFC-B + * \brief RFAL NFC-B Module + * @{ + * + */ + + +#ifndef RFAL_NFCB_H +#define RFAL_NFCB_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCB_FWTSENSB 7680U /*!< NFC-B FWT(SENSB) Digital 2.0 B.3 */ +#define RFAL_NFCB_DFWT 49152U /*!< NFC-B dFWT Delta 2.0 7.9.1.3 & B.3 */ +#define RFAL_NFCB_DTPOLL_10 rfalConvMsTo1fc(20) /*!< NFC-B Delta Tb Poll Digital 1.0 A.2 */ +#define RFAL_NFCB_DTPOLL_20 rfalConvMsTo1fc(17) /*!< NFC-B Delta Tb Poll Digital 2.1 B.3 */ + +#define RFAL_NFCB_AFI 0x00U /*!< NFC-B default Application Family Digital 1.1 7.6.1.1 */ +#define RFAL_NFCB_PARAM 0x00U /*!< NFC-B default SENSB_REQ PARAM */ +#define RFAL_NFCB_CRC_LEN 2U /*!< NFC-B CRC length and CRC_B(AID) Digital 1.1 Table 28 */ +#define RFAL_NFCB_NFCID0_LEN 4U /*!< Length of NFC-B NFCID0 */ +#define RFAL_NFCB_CMD_LEN 1U /*!< Length of NFC-B Command */ + +#define RFAL_NFCB_SENSB_RES_LEN 12U /*!< Standard length of SENSB_RES without SFGI byte */ +#define RFAL_NFCB_SENSB_RES_EXT_LEN 13U /*!< Extended length of SENSB_RES with SFGI byte */ + +#define RFAL_NFCB_SENSB_REQ_ADV_FEATURE 0x20U /*!< Bit mask for Advance Feature in SENSB_REQ */ +#define RFAL_NFCB_SENSB_RES_FSCI_MASK 0x0FU /*!< Bit mask for FSCI value in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FSCI_SHIFT 4U /*!< Shift for FSCI value in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_PROTO_RFU_MASK 0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK 0x03U /*!< Bit mask for Protocol Type TR2 in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT 1U /*!< Shift for Protocol Type TR2 in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK 0x01U /*!< Bit mask Protocol Type ISO14443 Compliant in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FWI_MASK 0x0FU /*!< Bit mask for FWI value in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FWI_SHIFT 4U /*!< Bit mask for FWI value in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_ADC_MASK 0x0CU /*!< Bit mask for ADC value in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_ADC_ADV_FEATURE_MASK 0x08U /*!< Bit mask for ADC.Advanced Proto Features in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_ADC_PROPRIETARY_MASK 0x04U /*!< Bit mask for ADC.Proprietary Application in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FO_DID_MASK 0x01U /*!< Bit mask for DID in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FO_NAD_MASK 0x02U /*!< Bit mask for DID in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_FO_MASK 0x03U /*!< Bit mask for FO value in SENSB_RES (NAD and DID) */ +#define RFAL_NFCB_SENSB_RES_SFGI_MASK 0x0FU /*!< Bit mask for SFGI in SENSB_RES */ +#define RFAL_NFCB_SENSB_RES_SFGI_SHIFT 4U /*!< Shift for SFGI in SENSB_RES */ + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +/*! Get device's FSCI given its SENSB_RES Digital 1.1 7.6.2 */ +#define rfalNfcbGetFSCI( sensbRes ) ((((rfalNfcbSensbRes*)(sensbRes))->protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_FSCI_SHIFT) & RFAL_NFCB_SENSB_RES_FSCI_MASK ) + +/*! Checks if the given NFC-B device indicates ISO-DEP support */ +#define rfalNfcbIsIsoDepSupported( dev ) ( (((rfalNfcbListenDevice*)(dev))->sensbRes.protInfo.FsciProType & RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK) != 0U ) + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! SENSB_REQ and ALLB_REQ param Digital 1.1 7.6.1 */ +typedef enum +{ + RFAL_NFCB_SENS_CMD_ALLB_REQ = 0x08, /*!< ALLB_REQ (WUPB) */ + RFAL_NFCB_SENS_CMD_SENSB_REQ = 0x00 /*!< SENSB_REQ (REQB) */ +} rfalNfcbSensCmd; + + +/*! Number of Slots (NI) codes used for NFC-B anti collision Digital 1.1 Table 26 */ +typedef enum +{ + RFAL_NFCB_SLOT_NUM_1 = 0, /*!< N=0 : 1 slot */ + RFAL_NFCB_SLOT_NUM_2 = 1, /*!< N=1 : 2 slots */ + RFAL_NFCB_SLOT_NUM_4 = 2, /*!< N=2 : 4 slots */ + RFAL_NFCB_SLOT_NUM_8 = 3, /*!< N=3 : 8 slots */ + RFAL_NFCB_SLOT_NUM_16 = 4 /*!< N=4 : 16 slots */ +}rfalNfcbSlots; + + +/*! SENSB_RES (ATQB) Application Data Format Digital 1.1 Table 28 */ +typedef struct +{ + uint8_t AFI; /*!< Application Family Identifier */ + uint8_t CRC_B[RFAL_NFCB_CRC_LEN]; /*!< CRC_B of AID */ + uint8_t numApps; /*!< Number of Applications */ +} rfalNfcbSensbResAppData; + + +/*! SENSB_RES Protocol Info format Digital 1.1 Table 29 */ +typedef struct +{ + uint8_t BRC; /*!< Bit Rate Capability */ + uint8_t FsciProType; /*!< Frame Size Card Integer [4b] | Protocol Type[4 bits] */ + uint8_t FwiAdcFo; /*!< Frame Waiting Integer [4b] | Application Data Coding [2b] | Frame Options [2b] */ + uint8_t SFGI; /*!< Optional: Start-Up Frame Guard Time Integer[4b] | RFU [4b] */ +} rfalNfcbSensbResProtocolInfo; + + +/*! SENSB_RES format Digital 1.1 7.6.2 */ +typedef struct +{ + uint8_t cmd; /*!< SENSB_RES: 50h */ + uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/ + rfalNfcbSensbResAppData appData; /*!< Application Data */ + rfalNfcbSensbResProtocolInfo protInfo; /*!< Protocol Information */ +} rfalNfcbSensbRes; + + +/*! NFC-B listener device (PICC) struct */ +typedef struct +{ + uint8_t sensbResLen; /*!< SENSB_RES length */ + rfalNfcbSensbRes sensbRes; /*!< SENSB_RES */ + bool isSleep; /*!< Device sleeping flag */ +}rfalNfcbListenDevice; + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Initialize NFC-B Poller mode + * + * This methods configures RFAL RF layer to perform as a + * NFC-B Poller/RW (ISO14443B PCD) including all default timings + * + * It sets NFC-B parameters (AFI, PARAM) to default values + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerInitialize( void ); + + +/*! + ***************************************************************************** + * \brief Set NFC-B Poller parameters + * + * This methods configures RFAL RF layer to perform as a + * NFCA Poller/RW (ISO14443A PCD) including all default timings + * + * Additionally configures NFC-B specific parameters to be used on the + * following communications + * + * \param[in] AFI : Application Family Identifier to be used + * \param[in] PARAM : PARAM to be used, it announces whether Advanced + * Features or Extended SENSB_RES is supported + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerInitializeWithParams( uint8_t AFI, uint8_t PARAM ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Check Presence + * + * This method checks if a NFC-B Listen device (PICC) is present on the field + * by sending an ALLB_REQ (WUPB) or SENSB_REQ (REQB) + * + * \param[in] cmd : Indicate if to send an ALLB_REQ or a SENSB_REQ + * \param[in] slots : The number of slots to be announced + * \param[out] sensbRes : If received, the SENSB_RES + * \param[out] sensbResLen : If received, the SENSB_RES length + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_RF_COLLISION : Collision detected one or more device in the field + * \return RFAL_ERR_PAR : Parity error detected, one or more device in the field + * \return RFAL_ERR_CRC : CRC error detected, one or more device in the field + * \return RFAL_ERR_FRAMING : Framing error detected, one or more device in the field + * \return RFAL_ERR_PROTO : Protocol error detected, invalid SENSB_RES received + * \return RFAL_ERR_NONE : No error, SENSB_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerCheckPresence( rfalNfcbSensCmd cmd, rfalNfcbSlots slots, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Start Check Presence + * + * This method starts check for a NFC-B Listen device (PICC) presence on the field + * by sending an ALLB_REQ (WUPB) or SENSB_REQ (REQB) + * + * \param[in] cmd : Indicate if to send an ALL_REQ or a SENS_REQ + * \param[in] slots : The number of slots to be announced + * \param[out] sensbRes : If received, the SENSB_RES + * \param[out] sensbResLen : If received, the SENSB_RES length + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, SENSB_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerStartCheckPresence( rfalNfcbSensCmd cmd, rfalNfcbSlots slots, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Get Check Presence Status + * + * This method get the presence check status + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_RF_COLLISION : Collision detected one or more device in the field + * \return RFAL_ERR_PAR : Parity error detected, one or more device in the field + * \return RFAL_ERR_CRC : CRC error detected, one or more device in the field + * \return RFAL_ERR_FRAMING : Framing error detected, one or more device in the field + * \return RFAL_ERR_PROTO : Protocol error detected, invalid SENSB_RES received + * \return RFAL_ERR_NONE : No error, SENSB_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerGetCheckPresenceStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Sleep + * + * This function is used to send the SLPB_REQ (HLTB) command to put the PICC with + * the given NFCID0 to state HALT so that they do not reply to further SENSB_REQ + * commands (only to ALLB_REQ) + * + * \param[in] nfcid0 : NFCID of the device to be put to Sleep + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerSleep( const uint8_t* nfcid0 ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Slot Marker + * + * This method sends a NFC-B Slot marker frame + * + * \param[in] slotCode : Slot Code [1-15] + * \param[out] sensbRes : If received, the SENSB_RES + * \param[out] sensbResLen : If received, the SENSB_RES length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerSlotMarker( uint8_t slotCode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Start Slot Marker + * + * This method starts a NFC-B Slot marker + * + * \param[in] slotCode : Slot Code [1-15] + * \param[out] sensbRes : If received, the SENSB_RES + * \param[out] sensbResLen : If received, the SENSB_RES length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerStartSlotMarker( uint8_t slotCode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Get Slot Marker Status + * + * This method gets the status of the NFC-B Slot marker + * + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, SEL_RES received + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerGetSlotMarkerStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-B Technology Detection + * + * This method performs NFC-B Technology Detection as defined in the spec + * given in the compliance mode + * + * \param[in] compMode : compliance mode to be performed + * \param[out] sensbRes : location to store the SENSB_RES, if received + * \param[out] sensbResLen : length of the SENSB_RES, if received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerTechnologyDetection( rfalComplianceMode compMode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + +/*! + ***************************************************************************** + * \brief NFC-B Start Technology Detection + * + * This method starts the NFC-B Technology Detection as defined in the spec + * given in the compliance mode + * + * \param[in] compMode : compliance mode to be performed + * \param[out] sensbRes : location to store the SENSB_RES, if received + * \param[out] sensbResLen : length of the SENSB_RES, if received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerStartTechnologyDetection( rfalComplianceMode compMode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ); + + +/*! + ***************************************************************************** + * \brief NFC-B Get Technology Detection Status + * + * This method gets the NFC-B Technology Detection status + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error, one or more device in the field + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerGetTechnologyDetectionStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Collision Resolution + * + * NFC-B Collision resolution Listener device/card (PICC) as + * defined in Activity 1.1 9.3.5 + * + * This function is used to perform collision resolution for detection in case + * of multiple NFC Forum Devices with Technology B detected. + * Target with valid SENSB_RES will be stored in nfcbDevList and devCnt incremented. + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcbDevList + * \param[out] nfcbDevList : NFC-B listener device info + * \param[out] devCnt : devices found counter + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Collision Resolution Slotted + * + * NFC-B Collision resolution Listener device/card (PICC). The sequence can + * be configured to be according to NFC Forum Activity 1.1 9.3.5, ISO10373 + * or EMVCo + * + * This function is used to perform collision resolution for detection in case + * of multiple NFC Forum Devices with Technology B are detected. + * Target with valid SENSB_RES will be stored in nfcbDevList and devCnt incremented. + * + * This method provides the means to perform a collision resolution loop with specific + * initial and end number of slots. This allows to user to start the loop already with + * greater number of slots, and or limit the end number of slots. At the end a flag + * indicating whether there were collisions pending is returned. + * + * If RFAL_COMPLIANCE_MODE_ISO is used \a initSlots must be set to RFAL_NFCB_SLOT_NUM_1 + * + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcbDevList + * \param[in] initSlots : number of slots to open initially + * \param[in] endSlots : number of slots when to stop collision resolution + * \param[out] nfcbDevList : NFC-B listener device info + * \param[out] devCnt : devices found counter + * \param[out] colPending : flag indicating whether collision are still pending + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerSlottedCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbSlots initSlots, rfalNfcbSlots endSlots, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt, bool *colPending ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Start Collision Resolution + * + * It starts the NFC-B Collision resolution Listener device/card (PICC) as + * defined in Activity 1.1 9.3.5 + * + * This function is used to trigger the collision resolution for detection in case + * of multiple NFC Forum Devices with Technology B detected. + * Target with valid SENSB_RES will be stored in nfcbDevList and devCnt incremented. + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcbDevList + * \param[out] nfcbDevList : NFC-B listener device info + * \param[out] devCnt : devices found counter + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerStartCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-B Poller Start Collision Resolution Slotted + * + * Starts NFC-B Collision resolution Listener device/card (PICC). The sequence can + * be configured to be according to NFC Forum Activity 1.1 9.3.5, ISO10373 + * or EMVCo + * + * This function is used to trigger the collision resolution for detection in case + * of multiple NFC Forum Devices with Technology B are detected. + * Target with valid SENSB_RES will be stored in nfcbDevList and devCnt incremented. + * + * This method provides the means to perform a collision resolution loop with specific + * initial and end number of slots. This allows to user to start the loop already with + * greater number of slots, and or limit the end number of slots. At the end a flag + * indicating whether there were collisions pending is returned. + * + * If RFAL_COMPLIANCE_MODE_ISO is used \a initSlots must be set to RFAL_NFCB_SLOT_NUM_1 + * + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcbDevList + * \param[in] initSlots : number of slots to open initially + * \param[in] endSlots : number of slots when to stop collision resolution + * \param[out] nfcbDevList : NFC-B listener device info + * \param[out] devCnt : devices found counter + * \param[out] colPending : flag indicating whether collision are still pending + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerStartSlottedCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbSlots initSlots, rfalNfcbSlots endSlots, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt, bool *colPending ); + + +/*! + ***************************************************************************** + * \brief NFC-B Get Collision Resolution Status + * + * Returns the Collision Resolution status + * + * \return RFAL_ERR_BUSY : Operation is ongoing + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error, activation successful + ***************************************************************************** + */ +ReturnCode rfalNfcbPollerGetCollisionResolutionStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-B TR2 code to FDT + * + * Converts the TR2 code as defined in Digital 1.1 Table 33 Minimum + * TR2 Coding to Frame Delay Time (FDT) in 1/Fc + * + * \param[in] tr2Code : TR2 code as defined in Digital 1.1 Table 33 + * + * \return FDT in 1/Fc + ***************************************************************************** + */ +uint32_t rfalNfcbTR2ToFDT( uint8_t tr2Code ); + +#endif /* RFAL_NFCB_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcf.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcf.h new file mode 100644 index 0000000..328b3be --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcf.h @@ -0,0 +1,447 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcf.h + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-F Poller (FeliCa PCD) device + * + * The definitions and helpers methods provided by this module are + * aligned with NFC-F (FeliCa - JIS X6319-4) + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup NFC-F + * \brief RFAL NFC-F Module + * @{ + * + */ + + +#ifndef RFAL_NFCF_H +#define RFAL_NFCF_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCF_NFCID2_LEN 8U /*!< NFCID2 (FeliCa IDm) length */ +#define RFAL_NFCF_SENSF_RES_LEN_MIN 16U /*!< SENSF_RES minimum length */ +#define RFAL_NFCF_SENSF_RES_LEN_MAX 18U /*!< SENSF_RES maximum length */ +#define RFAL_NFCF_SENSF_RES_PAD0_LEN 2U /*!< SENSF_RES PAD0 length */ +#define RFAL_NFCF_SENSF_RES_PAD1_LEN 3U /*!< SENSF_RES PAD1 length */ +#define RFAL_NFCF_SENSF_RES_RD_LEN 2U /*!< SENSF_RES Request Data length */ +#define RFAL_NFCF_SENSF_RES_BYTE1 1U /*!< SENSF_RES first byte value */ +#define RFAL_NFCF_SENSF_SC_LEN 2U /*!< Felica SENSF_REQ System Code length */ +#define RFAL_NFCF_SENSF_PARAMS_SC1_POS 0U /*!< System Code byte1 position in the SENSF_REQ */ +#define RFAL_NFCF_SENSF_PARAMS_SC2_POS 1U /*!< System Code byte2 position in the SENSF_REQ */ +#define RFAL_NFCF_SENSF_PARAMS_RC_POS 2U /*!< Request Code position in the SENSF_REQ */ +#define RFAL_NFCF_SENSF_PARAMS_TSN_POS 3U /*!< Time Slot Number position in the SENSF_REQ */ +#define RFAL_NFCF_POLL_MAXCARDS 16U /*!< Max number slots/cards 16 */ + + +#define RFAL_NFCF_CMD_POS 0U /*!< Command/Responce code length */ +#define RFAL_NFCF_CMD_LEN 1U /*!< Command/Responce code length */ +#define RFAL_NFCF_LENGTH_LEN 1U /*!< LEN field length */ +#define RFAL_NFCF_HEADER_LEN (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN) /*!< Header length */ + +#define RFAL_NFCF_NOS_LEN 1U /*!< Number of Services length */ +#define RFAL_NFCF_NOB_LEN 1U /*!< Number of Blocks length */ + + +#define RFAL_NFCF_SENSF_NFCID2_BYTE1_POS 0U /*!< NFCID2 byte1 position */ +#define RFAL_NFCF_SENSF_NFCID2_BYTE2_POS 1U /*!< NFCID2 byte2 position */ + +#define RFAL_NFCF_SENSF_NFCID2_PROT_TYPE_LEN 2U /*!< NFCID2 length for byte 1 and byte 2 indicating NFC-DEP or T3T support */ +#define RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP 0x01U /*!< NFCID2 byte1 NFC-DEP support Digital 1.0 Table 44 */ +#define RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP 0xFEU /*!< NFCID2 byte2 NFC-DEP support Digital 1.0 Table 44 */ + +#define RFAL_NFCF_SYSTEMCODE 0xFFFFU /*!< SENSF_RES Default System Code Digital 2.3 8.6.1.5 */ +#define RFAL_NFCF_SYSTEMCODE_LEN 2U /*!< SENSF_RES System Code length Digital 2.3 8.6.1 */ + +#define RFAL_NFCF_BLOCK_LEN 16U /*!< NFCF T3T Block size T3T 1.0 4.1 */ +#define RFAL_NFCF_CHECKUPDATE_RES_ST1_POS 9U /*!< Check|Update Res Status Flag 1 position T3T 1.0 Table 8 */ +#define RFAL_NFCF_CHECKUPDATE_RES_ST2_POS 10U /*!< Check|Update Res Status Flag 2 position T3T 1.0 Table 8 */ +#define RFAL_NFCF_CHECKUPDATE_RES_NOB_POS 11U /*!< Check|Update Res Number of Blocks position T3T 1.0 Table 8 */ + +#define RFAL_NFCF_STATUS_FLAG_SUCCESS 0x00U /*!< Check response Number of Blocks position T3T 1.0 Table 11 */ +#define RFAL_NFCF_STATUS_FLAG_ERROR 0xFFU /*!< Check response Number of Blocks position T3T 1.0 Table 11 */ + +#define RFAL_NFCF_BLOCKLISTELEM_MAX_LEN 3U /*!< Block List Element max Length (3 bytes) T3T 1.0 5.6.1 */ +#define RFAL_NFCF_BLOCKLISTELEM_LEN_BIT 0x80U /*!< Block List Element Length bit (2|3 bytes) T3T 1.0 5.6.1 */ + +#define RFAL_NFCF_SERVICECODE_RDONLY 0x000BU /*!< NDEF Service Code as Read-Only T3T 1.0 7.2.1 */ +#define RFAL_NFCF_SERVICECODE_RDWR 0x0009U /*!< NDEF Service Code as Read and Write T3T 1.0 7.2.1 */ + +#define RFAL_NFCF_TEST_LB_CMD0 0xD8U /*!< T3T loopback CMD0 ETSI TS 102 695-1 5.6.4.4.2 */ +#define RFAL_NFCF_TEST_LB_CMD1 0x00U /*!< T3T loopback CMD1 ETSI TS 102 695-1 5.6.4.4.2 */ + + +/*! NFC-F Felica command set JIS X6319-4 9.1 */ +enum +{ + RFAL_NFCF_CMD_POLLING = 0x00, /*!< SENSF_REQ (Felica Poll/REQC command to identify a card ) */ + RFAL_NFCF_CMD_POLLING_RES = 0x01, /*!< SENSF_RES (Felica Poll/REQC command response ) */ + RFAL_NFCF_CMD_REQUEST_SERVICE = 0x02, /*!< verify the existence of Area and Service */ + RFAL_NFCF_CMD_REQUEST_RESPONSE = 0x04, /*!< verify the existence of a card */ + RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION = 0x06, /*!< read Block Data from a Service that requires no authentication */ + RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES = 0x07, /*!< read Block Data response from a Service with no authentication */ + RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION = 0x08, /*!< write Block Data to a Service that requires no authentication */ + RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES = 0x09, /*!< write Block Data response to a Service with no authentication */ + RFAL_NFCF_CMD_REQUEST_SYSTEM_CODE = 0x0c, /*!< acquire the System Code registered to a card */ + RFAL_NFCF_CMD_AUTHENTICATION1 = 0x10, /*!< authenticate a card */ + RFAL_NFCF_CMD_AUTHENTICATION2 = 0x12, /*!< allow a card to authenticate a Reader/Writer */ + RFAL_NFCF_CMD_READ = 0x14, /*!< read Block Data from a Service that requires authentication */ + RFAL_NFCF_CMD_WRITE = 0x16, /*!< write Block Data to a Service that requires authentication */ +}; + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/*! Checks if the given NFC-F device indicates NFC-DEP support */ +#define rfalNfcfIsNfcDepSupported( dev ) ( (((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE1_POS] == RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP) && \ + (((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE2_POS] == RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP) ) + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + + +/*! NFC-F SENSF_RES format Digital 1.1 8.6.2 */ +typedef struct +{ + uint8_t CMD; /*!< Command Code: 01h */ + uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2 */ + uint8_t PAD0[RFAL_NFCF_SENSF_RES_PAD0_LEN]; /*!< PAD0 */ + uint8_t PAD1[RFAL_NFCF_SENSF_RES_PAD1_LEN]; /*!< PAD1 */ + uint8_t MRTIcheck; /*!< MRTIcheck */ + uint8_t MRTIupdate; /*!< MRTIupdate */ + uint8_t PAD2; /*!< PAD2 */ + uint8_t RD[RFAL_NFCF_SENSF_RES_RD_LEN]; /*!< Request Data */ +} rfalNfcfSensfRes; + + +/*! NFC-F poller device (PCD) struct */ +typedef struct +{ + uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2 */ +} rfalNfcfPollDevice; + +/*! NFC-F listener device (PICC) struct */ +typedef struct +{ + uint8_t sensfResLen; /*!< SENF_RES length */ + rfalNfcfSensfRes sensfRes; /*!< SENF_RES */ +} rfalNfcfListenDevice; + +typedef uint16_t rfalNfcfServ; /*!< NFC-F Service Code */ + +/*! NFC-F Block List Element (2 or 3 bytes element) T3T 1.0 5.6.1 */ +typedef struct +{ + uint8_t conf; /*!< Access Mode | Serv Code List Order */ + uint16_t blockNum; /*!< Block Number */ +}rfalNfcfBlockListElem; + +/*! Check Update Service list and Block list parameter */ +typedef struct +{ + uint8_t numServ; /*!< Number of Services */ + rfalNfcfServ *servList; /*!< Service Code List */ + uint8_t numBlock; /*!< Number of Blocks */ + rfalNfcfBlockListElem *blockList; /*!< Block Number List */ +}rfalNfcfServBlockListParam; + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Initialize NFC-F Poller mode + * + * This methods configures RFAL RF layer to perform as a + * NFC-F Poller/RW (FeliCa PCD) including all default timings + * + * \param[in] bitRate : NFC-F bitrate to be initialize (212 or 424) + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Incorrect bitrate + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerInitialize( rfalBitRate bitRate ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Check Presence + * + * This function sends a Poll/SENSF command according to NFC Activity spec + * It detects if a NCF-F device is within range + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_NONE : No error and some NFC-F device was detected + * + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerCheckPresence( void ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Start Check Presence + * + * This function triggers a Poll/SENSF command according to NFC Activity spec + * It detects if a NCF-F device is within range + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_NONE : No error and some NFC-F device was detected + * + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerStartCheckPresence( void ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Get Check Presence Status + * + * This function gets the status of the Check Presense operation + * triggered by rfalNfcfPollerStartCheckPresence() + * + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_NONE : No error and some NFC-F device was detected + * + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerGetCheckPresenceStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Poll + * + * This function sends to all PICCs in field the POLL command with the given + * number of slots. + * + * \param[in] slots : the number of slots to be performed + * \param[in] sysCode : as given in FeliCa poll command + * \param[in] reqCode : FeliCa communication parameters + * \param[out] cardList : Parameter of type rfalFeliCaPollRes which will hold the cards found + * \param[out] devCnt : actual number of cards found + * \param[out] collisions : number of collisions encountered + * + * \warning the list cardList has to be as big as the number of slots for the Poll + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_NONE : No error and some NFC-F device was detected + * + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes *cardList, uint8_t *devCnt, uint8_t *collisions ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Full Collision Resolution + * + * Performs a full Collision resolution as defined in Activity 1.1 9.3.4 + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcaDevList + * \param[out] nfcfDevList : NFC-F listener devices list + * \param[out] devCnt : Devices found counter + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcfListenDevice *nfcfDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-F Start Poller Collision Resolution + * + * Triggers a Collision Resolution as defined in Activity 2.1 9.3.6 + * + * \param[in] compMode : compliance mode to be performed + * \param[in] devLimit : device limit value, and size nfcaDevList + * \param[out] nfcfDevList : NFC-F listener devices list + * \param[out] devCnt : Devices found counter + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerStartCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcfListenDevice *nfcfDevList, uint8_t *devCnt ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Get Collision Resolution Status + * + * This function gets the status of the Collision Resolution operation + * triggered by rfalNfcfPollerStartCollisionResolution() + * + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_NONE : No error and some NFC-F device was detected + * + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerGetCollisionResolutionStatus( void ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Check/Read + * + * It computes a Check / Read command accoring to T3T 1.0 and JIS X6319-4 and + * sends it to PICC. If sucessfully, the rxBuf will contain the the number of + * blocks in the first byte followed by the blocks data. + * + * \param[in] nfcid2 : nfcid2 of the device + * \param[in] servBlock : parameter containing the list of Services and + * Blocks to be addressed by this command + * \param[out] rxBuf : buffer to place check/read data + * \param[in] rxBufLen : size of the rxBuf + * \param[out] rcvdLen : length of data placed in rxBuf + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_REQUEST : The request was executed with error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerCheck( const uint8_t* nfcid2, const rfalNfcfServBlockListParam *servBlock, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvdLen ); + + +/*! + ***************************************************************************** + * \brief NFC-F Poller Update/Write + * + * It computes a Update / Write command accoring to T3T 1.0 and JIS X6319-4 and + * sends it to PICC. + * + * \param[in] nfcid2 : nfcid2 of the device + * \param[in] servBlock : parameter containing the list of Services and + * Blocks to be addressed by this command + * \param[in] txBuf : buffer where the request will be composed + * \param[in] txBufLen : size of txBuf + * \param[in] blockData : data to written on the given block(s) + * \param[out] rxBuf : buffer to place check/read data + * \param[in] rxBufLen : size of the rxBuf + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_REQUEST : The request was executed with error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalNfcfPollerUpdate( const uint8_t* nfcid2, const rfalNfcfServBlockListParam *servBlock, uint8_t *txBuf, uint16_t txBufLen, const uint8_t *blockData, uint8_t *rxBuf, uint16_t rxBufLen); + +/*! + ***************************************************************************** + * \brief NFC-F Listener is T3T Request + * + * This method checks if the given data is a valid T3T command (Read or Write) + * and in case a valid request has been received it may output the request's NFCID2 + * + * \param[in] buf : buffer holding Initiator's received command + * \param[in] bufLen : length of received command in bytes + * \param[out] nfcid2 : pointer to where the NFCID2 may be outputed, + * nfcid2 has NFCF_SENSF_NFCID2_LEN as length + * Pass NULL if output parameter not desired + * + * \return true : Valid T3T command (Read or Write) received + * \return false : Invalid protocol request + * + ***************************************************************************** + */ +bool rfalNfcfListenerIsT3TReq( const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2 ); + + +#endif /* RFAL_NFCF_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcv.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcv.h new file mode 100644 index 0000000..1b0a086 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_nfcv.h @@ -0,0 +1,769 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcv.h + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-V Poller (ISO15693) device + * + * The definitions and helpers methods provided by this module + * are aligned with NFC-V Digital 2.1 + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup NFC-V + * \brief RFAL NFC-V Module + * @{ + * + */ + +#ifndef RFAL_NFCV_H +#define RFAL_NFCV_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCV_UID_LEN 8U /*!< NFC-V UID length */ +#define RFAL_NFCV_MAX_BLOCK_LEN 32U /*!< Max Block size: can be of up to 256 bits ISO 15693 2000 5 */ +#define RFAL_NFCV_BNO_LEN 1U /*!< NFC-V Block Number length */ +#define RFAL_NFCV_CRC_LEN 2U /*!< NFC-V CRC length */ +#define RFAL_NFCV_MAX_GEN_DATA_LEN (RFAL_NFCV_MAX_BLOCK_LEN + RFAL_NFCV_BNO_LEN + RFAL_NFCV_UID_LEN) /*!The RFAL encapsulates the different + * RF ICs (ST25R3911, ST25R391x, etc) into a common and easy to use interface. + * + * It provides interfaces to configure the RF IC, set/get timings, modes, bit rates, + * specific handlings, execute listen mode, etc. + * + * Furthermore it provides a common interface to perform a Transceive operations. + * The Transceive can be executed in a blocking or non blocking way.
+ * Additionally few specific Transceive methods are available to cope with the + * specifics of these particular operations. + * + * The most common interfaces are: + *
  rfalInitialize() + *
  rfalSetFDTPoll() + *
  rfalSetFDTListen() + *
  rfalSetGT() + *
  rfalSetBitRate() + *
  rfalSetMode() + *
  rfalFieldOnAndStartGT() + *
  rfalFieldOff() + *
  rfalStartTransceive() + *
  rfalGetTransceiveStatus() + *
  rfalTransceiveBlockingTxRx() + * + * An usage example is provided here: \ref exampleRfalPoller.c + * \example exampleRfalPoller.c + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup RF + * \brief RFAL RF Abstraction Layer + * @{ + * + */ + +#ifndef RFAL_RF_H +#define RFAL_RF_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_features.h" + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ +#define RFAL_VERSION 0x020A00U /*!< RFAL Current Version: v2.10.0 */ + +#define RFAL_FWT_NONE 0xFFFFFFFFU /*!< Disabled FWT: Wait forever for a response */ +#define RFAL_GT_NONE RFAL_TIMING_NONE /*!< Disabled GT: No GT will be applied after Field On */ + +#define RFAL_TIMING_NONE 0x00U /*!< Timing disabled | Don't apply */ + +#define RFAL_1FC_IN_4096FC (uint32_t)4096U /*!< Number of 1/fc cycles in one 4096/fc */ +#define RFAL_1FC_IN_2048FC (uint32_t)2048U /*!< Number of 1/fc cycles in one 2048/fc */ +#define RFAL_1FC_IN_512FC (uint32_t)512U /*!< Number of 1/fc cycles in one 512/fc */ +#define RFAL_1FC_IN_64FC (uint32_t)64U /*!< Number of 1/fc cycles in one 64/fc */ +#define RFAL_1FC_IN_8FC (uint32_t)8U /*!< Number of 1/fc cycles in one 8/fc */ +#define RFAL_US_IN_MS (uint32_t)1000U /*!< Number of us in one ms */ +#define RFAL_1MS_IN_1FC (uint32_t)13560U /*!< Number of 1/fc cycles in 1ms */ +#define RFAL_BITS_IN_BYTE (uint16_t)8U /*!< Number of bits in one byte */ + +#define RFAL_CRC_LEN 2U /*!< RF CRC LEN */ + +/*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */ +#define RFAL_TXRX_FLAGS_DEFAULT ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + + + +#define RFAL_LM_MASK_NFCA ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCA) /*!< Bitmask for Listen Mode enabling NFCA */ +#define RFAL_LM_MASK_NFCB ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCB) /*!< Bitmask for Listen Mode enabling NFCB */ +#define RFAL_LM_MASK_NFCF ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCF) /*!< Bitmask for Listen Mode enabling NFCF */ +#define RFAL_LM_MASK_ACTIVE_P2P ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_ACTIVE_P2P) /*!< Bitmask for Listen Mode enabling AP2P */ + +#define RFAL_LM_SENS_RES_LEN 2U /*!< NFC-A SENS_RES (ATQA) length */ +#define RFAL_LM_SENSB_RES_LEN 13U /*!< NFC-B SENSB_RES (ATQB) length */ +#define RFAL_LM_SENSF_RES_LEN 19U /*!< NFC-F SENSF_RES length */ +#define RFAL_LM_SENSF_SC_LEN 2U /*!< NFC-F System Code length */ + +#define RFAL_NFCID3_LEN 10U /*!< NFCID3 length */ +#define RFAL_NFCID2_LEN 8U /*!< NFCID2 length */ +#define RFAL_NFCID1_TRIPLE_LEN 10U /*!< NFCID1 length */ +#define RFAL_NFCID1_DOUBLE_LEN 7U /*!< NFCID1 length */ +#define RFAL_NFCID1_SINGLE_LEN 4U /*!< NFCID1 length */ + + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +/*! Returns the maximum supported bit rate for RW mode. Caller must check if mode is supported before, as even if mode is not supported will return the min */ +#define rfalGetMaxBrRW() ( ((RFAL_SUPPORT_BR_RW_6780) ? RFAL_BR_6780 : ((RFAL_SUPPORT_BR_RW_3390) ? RFAL_BR_3390 : ((RFAL_SUPPORT_BR_RW_1695) ? RFAL_BR_1695 : ((RFAL_SUPPORT_BR_RW_848) ? RFAL_BR_848 : ((RFAL_SUPPORT_BR_RW_424) ? RFAL_BR_424 : ((RFAL_SUPPORT_BR_RW_212) ? RFAL_BR_212 : RFAL_BR_106 ) ) ) ) ) ) ) + +/*! Returns the maximum supported bit rate for AP2P mode. Caller must check if mode is supported before, as even if mode is not supported will return the min */ +#define rfalGetMaxBrAP2P() ( ((RFAL_SUPPORT_BR_AP2P_848) ? RFAL_BR_848 : ((RFAL_SUPPORT_BR_AP2P_424) ? RFAL_BR_424 : ((RFAL_SUPPORT_BR_AP2P_212) ? RFAL_BR_212 : RFAL_BR_106 ) ) ) ) + +/*! Returns the maximum supported bit rate for CE-A mode. Caller must check if mode is supported before, as even if mode is not supported will return the min */ +#define rfalGetMaxBrCEA() ( ((RFAL_SUPPORT_BR_CE_A_848) ? RFAL_BR_848 : ((RFAL_SUPPORT_BR_CE_A_424) ? RFAL_BR_424 : ((RFAL_SUPPORT_BR_CE_A_212) ? RFAL_BR_212 : RFAL_BR_106 ) ) ) ) + +/*! Returns the maximum supported bit rate for CE-B mode. Caller must check if mode is supported before, as even if mode is not supported will return the min */ +#define rfalGetMaxBrCEB() ( ((RFAL_SUPPORT_BR_CE_B_848) ? RFAL_BR_848 : ((RFAL_SUPPORT_BR_CE_B_424) ? RFAL_BR_424 : ((RFAL_SUPPORT_BR_CE_B_212) ? RFAL_BR_212 : RFAL_BR_106 ) ) ) ) + +/*! Returns the maximum supported bit rate for CE-F mode. Caller must check if mode is supported before, as even if mode is not supported will return the min */ +#define rfalGetMaxBrCEF() ( ((RFAL_SUPPORT_BR_CE_F_424) ? RFAL_BR_424 : RFAL_BR_212 ) ) + + +#define rfalIsModeActiveComm( md ) ( ((md) == RFAL_MODE_POLL_ACTIVE_P2P) || ((md) == RFAL_MODE_LISTEN_ACTIVE_P2P) ) /*!< Checks if mode md is Active Communication */ +#define rfalIsModePassiveComm( md ) ( !rfalIsModeActiveComm(md) ) /*!< Checks if mode md is Passive Communication */ +#define rfalIsModePassiveListen( md ) ( ((md) == RFAL_MODE_LISTEN_NFCA) || ((md) == RFAL_MODE_LISTEN_NFCB) || ((md) == RFAL_MODE_LISTEN_NFCF) ) /*!< Checks if mode md is Passive Listen */ +#define rfalIsModePassivePoll( md ) ( rfalIsModePassiveComm(md) && (!rfalIsModePassiveListen(md)) ) /*!< Checks if mode md is Passive Poll */ + + +#define rfalConv1fcTo8fc( t ) (uint32_t)( (uint32_t)(t) / RFAL_1FC_IN_8FC ) /*!< Converts the given t from 1/fc to 8/fc */ +#define rfalConv8fcTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1FC_IN_8FC ) /*!< Converts the given t from 8/fc to 1/fc */ + +#define rfalConv1fcTo64fc( t ) (uint32_t)( (uint32_t)(t) / RFAL_1FC_IN_64FC ) /*!< Converts the given t from 1/fc to 64/fc */ +#define rfalConv64fcTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1FC_IN_64FC ) /*!< Converts the given t from 64/fc to 1/fc */ + +#define rfalConv1fcTo512fc( t ) (uint32_t)( (uint32_t)(t) / RFAL_1FC_IN_512FC ) /*!< Converts the given t from 1/fc to 512/fc */ +#define rfalConv512fcTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1FC_IN_512FC ) /*!< Converts the given t from 512/fc to 1/fc */ + +#define rfalConv1fcTo2018fc( t ) (uint32_t)( (uint32_t)(t) / RFAL_1FC_IN_2048FC ) /*!< Converts the given t from 1/fc to 2048/fc */ +#define rfalConv2048fcTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1FC_IN_2048FC ) /*!< Converts the given t from 2048/fc to 1/fc */ + +#define rfalConv1fcTo4096fc( t ) (uint32_t)( (uint32_t)(t) / RFAL_1FC_IN_4096FC ) /*!< Converts the given t from 1/fc to 4096/fc */ +#define rfalConv4096fcTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1FC_IN_4096FC ) /*!< Converts the given t from 4096/fc to 1/fc */ + +#define rfalConv1fcToMs( t ) (uint32_t)( (uint32_t)(t) / RFAL_1MS_IN_1FC ) /*!< Converts the given t from 1/fc to ms */ +#define rfalConvMsTo1fc( t ) (uint32_t)( (uint32_t)(t) * RFAL_1MS_IN_1FC ) /*!< Converts the given t from ms to 1/fc */ + +#define rfalConv1fcToUs( t ) (uint32_t)( ((uint32_t)(t) * RFAL_US_IN_MS) / RFAL_1MS_IN_1FC) /*!< Converts the given t from 1/fc to us */ +#define rfalConvUsTo1fc( t ) (uint32_t)( ((uint32_t)(t) * RFAL_1MS_IN_1FC) / RFAL_US_IN_MS) /*!< Converts the given t from us to 1/fc */ + +#define rfalConv64fcToMs( t ) (uint32_t)( (uint32_t)(t) / (RFAL_1MS_IN_1FC / RFAL_1FC_IN_64FC) ) /*!< Converts the given t from 64/fc to ms */ +#define rfalConvMsTo64fc( t ) (uint32_t)( (uint32_t)(t) * (RFAL_1MS_IN_1FC / RFAL_1FC_IN_64FC) ) /*!< Converts the given t from ms to 64/fc */ + +#define rfalConvBitsToBytes( n ) (uint16_t)( ((uint16_t)(n)+(RFAL_BITS_IN_BYTE-1U)) / (RFAL_BITS_IN_BYTE) ) /*!< Converts the given n from bits to bytes */ +#define rfalConvBytesToBits( n ) (uint32_t)( (uint32_t)(n) * (RFAL_BITS_IN_BYTE) ) /*!< Converts the given n from bytes to bits */ + + +#define rfalRunBlocking( e, fn ) do{ (e)=(fn); rfalWorker(); }while( (e) == RFAL_ERR_BUSY ) /*!< Macro used for the blocking methods */ + + +/*! Computes a Transceive context \a ctx with default flags and the lengths + * in bytes with the given arguments + * \a ctx : Transceive context to be assigned + * \a tB : txBuf the pointer to the buffer to be sent + * \a tBL : txBuf length in bytes + * \a rB : rxBuf the pointer to the buffer to place the received frame + * \a rBL : rxBuf length in bytes + * \a rdL : rxRcvdLen the pointer to place the rx length + * \a t : FWT to be used on this transceive in 1/fc + */ +#define rfalCreateByteTxRxContext( ctx, tB, tBL, rB, rBL, rdL, t ) \ + (ctx).txBuf = (uint8_t*)(tB); \ + (ctx).txBufLen = (uint16_t)rfalConvBytesToBits(tBL); \ + (ctx).rxBuf = (uint8_t*)(rB); \ + (ctx).rxBufLen = (uint16_t)rfalConvBytesToBits(rBL); \ + (ctx).rxRcvdLen = (uint16_t*)(rdL); \ + (ctx).flags = (uint32_t)RFAL_TXRX_FLAGS_DEFAULT; \ + (ctx).fwt = (uint32_t)(t); + + +/*! Computes a Transceive context \a ctx using lengths in bytes + * with the given flags and arguments + * \a ctx : Transceive context to be assigned + * \a tB : txBuf the pointer to the buffer to be sent + * \a tBL : txBuf length in bytes + * \a rB : rxBuf the pointer to the buffer to place the received frame + * \a rBL : rxBuf length in bytes + * \a rBL : rxBuf length in bytes + * \a t : FWT to be used on this transceive in 1/fc + */ +#define rfalCreateByteFlagsTxRxContext( ctx, tB, tBL, rB, rBL, rdL, fl, t ) \ + (ctx).txBuf = (uint8_t*)(tB); \ + (ctx).txBufLen = (uint16_t)rfalConvBytesToBits(tBL); \ + (ctx).rxBuf = (uint8_t*)(rB); \ + (ctx).rxBufLen = (uint16_t)rfalConvBytesToBits(rBL); \ + (ctx).rxRcvdLen = (uint16_t*)(rdL); \ + (ctx).flags = (uint32_t)(fl); \ + (ctx).fwt = (uint32_t)(t); + + +#define rfalLogE(...) platformLog(__VA_ARGS__) /*!< Macro for the error log method */ +#define rfalLogW(...) platformLog(__VA_ARGS__) /*!< Macro for the warning log method */ +#define rfalLogI(...) platformLog(__VA_ARGS__) /*!< Macro for the info log method */ +#define rfalLogD(...) platformLog(__VA_ARGS__) /*!< Macro for the debug log method */ + + +/* +****************************************************************************** +* GLOBAL ENUMS +****************************************************************************** +*/ + +/* RFAL Guard Time (GT) default values */ +#define RFAL_GT_NFCA rfalConvMsTo1fc(5U) /*!< GTA Digital 2.0 6.10.4.1 & B.2 */ +#define RFAL_GT_NFCB rfalConvMsTo1fc(5U) /*!< GTB Digital 2.0 7.9.4.1 & B.3 */ +#define RFAL_GT_NFCF rfalConvMsTo1fc(20U) /*!< GTF Digital 2.0 8.7.4.1 & B.4 */ +#define RFAL_GT_NFCV rfalConvMsTo1fc(5U) /*!< GTV Digital 2.0 9.7.5.1 & B.5 */ +#define RFAL_GT_PICOPASS rfalConvMsTo1fc(1U) /*!< GT Picopass */ +#define RFAL_GT_AP2P rfalConvMsTo1fc(5U) /*!< TIRFG Ecma 340 11.1.1 */ +#define RFAL_GT_AP2P_ADJUSTED rfalConvMsTo1fc(5U+25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2) */ + +/* RFAL Frame Delay Time (FDT) Listen default values */ +#define RFAL_FDT_LISTEN_NFCA_POLLER 1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1 6.10 ; EMV CCP Spec Book D v2.01 4.8.1.3 */ +#define RFAL_FDT_LISTEN_NFCB_POLLER 1008U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define RFAL_FDT_LISTEN_NFCF_POLLER 2672U /*!< TR0F,LISTEN,MIN Digital 1.1 8.7.1.1 & A.4 */ +#define RFAL_FDT_LISTEN_NFCV_POLLER 4310U /*!< FDTV,LISTEN,MIN t1 min Digital 2.1 B.5 ; ISO15693-3 2009 9.1 */ +#define RFAL_FDT_LISTEN_PICOPASS_POLLER 3400U /*!< ISO15693 t1 min - observed adjustment */ +#define RFAL_FDT_LISTEN_AP2P_POLLER 64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance */ +#define RFAL_FDT_LISTEN_NFCA_LISTENER 1172U /*!< FDTA,LISTEN,MIN Digital 1.1 6.10 */ +#define RFAL_FDT_LISTEN_NFCB_LISTENER 1024U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define RFAL_FDT_LISTEN_NFCF_LISTENER 2688U /*!< TR0F,LISTEN,MIN Digital 2.1 8.7.1.1 & B.4 */ +#define RFAL_FDT_LISTEN_AP2P_LISTENER 64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance */ + +/* RFAL Frame Delay Time (FDT) Poll default values */ +#define RFAL_FDT_POLL_NFCA_POLLER 6780U /*!< FDTA,POLL,MIN Digital 1.1 6.10.3.1 & A.2 */ +#define RFAL_FDT_POLL_NFCA_T1T_POLLER 384U /*!< RRDDT1T,MIN,B1 Digital 1.1 10.7.1 & A.5 */ +#define RFAL_FDT_POLL_NFCB_POLLER 6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3 ; EMVCo 3.0 FDTB,PCD,MIN Table A.5 */ +#define RFAL_FDT_POLL_NFCF_POLLER 6800U /*!< FDTF,POLL,MIN Digital 2.1 8.7.3 & B.4 */ +#define RFAL_FDT_POLL_NFCV_POLLER 4192U /*!< FDTV,POLL Digital 2.1 9.7.3.1 & B.5 */ +#define RFAL_FDT_POLL_PICOPASS_POLLER 1790U /*!< FDT Max */ +#define RFAL_FDT_POLL_AP2P_POLLER 6800U /*!< AP2P inhere FDT from the Technology used (use longest: TR0F,POLL,MIN + TR1F) Digital 2.2 17.11.1 */ + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! RFAL modes */ +typedef enum { + RFAL_MODE_NONE = 0, /*!< No mode selected/defined */ + RFAL_MODE_POLL_NFCA = 1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD) */ + RFAL_MODE_POLL_NFCA_T1T = 2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD) */ + RFAL_MODE_POLL_NFCB = 3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD) */ + RFAL_MODE_POLL_B_PRIME = 4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD) */ + RFAL_MODE_POLL_B_CTS = 5, /*!< Mode to perform as CTS Poller (PCD) */ + RFAL_MODE_POLL_NFCF = 6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD) */ + RFAL_MODE_POLL_NFCV = 7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD) */ + RFAL_MODE_POLL_PICOPASS = 8, /*!< Mode to perform as PicoPass / iClass Poller (PCD) */ + RFAL_MODE_POLL_ACTIVE_P2P = 9, /*!< Mode to perform as Active P2P (ISO18092) Initiator */ + RFAL_MODE_LISTEN_NFCA = 10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC) */ + RFAL_MODE_LISTEN_NFCB = 11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC) */ + RFAL_MODE_LISTEN_NFCF = 12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC) */ + RFAL_MODE_LISTEN_ACTIVE_P2P = 13 /*!< Mode to perform as Active P2P (ISO18092) Target */ +} rfalMode; + + +/*! RFAL Bit rates */ +typedef enum { + RFAL_BR_106 = 0, /*!< Bit Rate 106 kbit/s (fc/128) */ + RFAL_BR_212 = 1, /*!< Bit Rate 212 kbit/s (fc/64) */ + RFAL_BR_424 = 2, /*!< Bit Rate 424 kbit/s (fc/32) */ + RFAL_BR_848 = 3, /*!< Bit Rate 848 kbit/s (fc/16) */ + RFAL_BR_1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8) */ + RFAL_BR_3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4) */ + RFAL_BR_6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2) */ + RFAL_BR_13560 = 7, /*!< Bit Rate 13560 kbit/s (fc) */ + RFAL_BR_211p88 = 0xE9, /*!< Bit Rate 211,88 kbit/s (fc/64) Fast Mode VICC->VCD */ + RFAL_BR_105p94 = 0xEA, /*!< Bit Rate 105,94 kbit/s (fc/128) Fast Mode VICC->VCD */ + RFAL_BR_52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD */ + RFAL_BR_26p48 = 0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4 */ + RFAL_BR_1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256 */ + RFAL_BR_KEEP = 0xFF /*!< Value indicating to keep the same previous bit rate */ +} rfalBitRate; + + +/*! RFAL Compliance modes for upper modules */ +typedef enum { + RFAL_COMPLIANCE_MODE_NFC, /*!< Perform with NFC Forum 1.1 compliance */ + RFAL_COMPLIANCE_MODE_EMV, /*!< Perform with EMVCo compliance */ + RFAL_COMPLIANCE_MODE_ISO /*!< Perform with ISO10373 compliance */ +}rfalComplianceMode; + + +/*! RFAL main states flags */ +typedef enum { + RFAL_STATE_IDLE = 0, + RFAL_STATE_INIT = 1, + RFAL_STATE_MODE_SET = 2, + + RFAL_STATE_TXRX = 3, + RFAL_STATE_LM = 4, + RFAL_STATE_WUM = 5 + +} rfalState; + +/*! RFAL transceive states */ +typedef enum { + RFAL_TXRX_STATE_IDLE = 0, + RFAL_TXRX_STATE_INIT = 1, + RFAL_TXRX_STATE_START = 2, + + RFAL_TXRX_STATE_TX_IDLE = 11, + RFAL_TXRX_STATE_TX_WAIT_GT = 12, + RFAL_TXRX_STATE_TX_WAIT_FDT = 13, + RFAL_TXRX_STATE_TX_PREP_TX = 14, + RFAL_TXRX_STATE_TX_TRANSMIT = 15, + RFAL_TXRX_STATE_TX_WAIT_WL = 16, + RFAL_TXRX_STATE_TX_RELOAD_FIFO = 17, + RFAL_TXRX_STATE_TX_WAIT_TXE = 18, + RFAL_TXRX_STATE_TX_DONE = 19, + RFAL_TXRX_STATE_TX_FAIL = 20, + + RFAL_TXRX_STATE_RX_IDLE = 81, + RFAL_TXRX_STATE_RX_WAIT_EON = 82, + RFAL_TXRX_STATE_RX_WAIT_RXS = 83, + RFAL_TXRX_STATE_RX_WAIT_RXE = 84, + RFAL_TXRX_STATE_RX_READ_FIFO = 85, + RFAL_TXRX_STATE_RX_ERR_CHECK = 86, + RFAL_TXRX_STATE_RX_READ_DATA = 87, + RFAL_TXRX_STATE_RX_WAIT_EOF = 88, + RFAL_TXRX_STATE_RX_DONE = 89, + RFAL_TXRX_STATE_RX_FAIL = 90, + +} rfalTransceiveState; + + +/*! RFAL transceive flags */ +enum { + RFAL_TXRX_FLAGS_CRC_TX_AUTO = (0U<<0), /*!< CRC will be generated automatic upon transmission */ + RFAL_TXRX_FLAGS_CRC_TX_MANUAL = (1U<<0), /*!< CRC was calculated manually, included in txBuffer */ + RFAL_TXRX_FLAGS_CRC_RX_KEEP = (1U<<1), /*!< Upon Reception keep the CRC in rxBuffer (reflected on rcvd length) */ + RFAL_TXRX_FLAGS_CRC_RX_REMV = (0U<<1), /*!< Remove the CRC from rxBuffer */ + RFAL_TXRX_FLAGS_NFCIP1_ON = (1U<<2), /*!< Enable NFCIP1 mode: Add SB(F0) and LEN bytes during Tx and skip SB(F0) byte during Rx */ + RFAL_TXRX_FLAGS_NFCIP1_OFF = (0U<<2), /*!< Disable NFCIP1 mode: do not append protocol bytes while Tx nor skip while Rx */ + RFAL_TXRX_FLAGS_AGC_OFF = (1U<<3), /*!< Disable Automatic Gain Control, improving multiple devices collision detection. \b DEPRECATED: flag is depreacted, usage of Anticollision APIs based on Analog Config table with RFAL_ANALOG_CONFIG_ANTICOL settings */ + RFAL_TXRX_FLAGS_AGC_ON = (0U<<3), /*!< Enable Automatic Gain Control, improving single device reception \b DEPRECATED: flag is deprecated, usage of Anticollision APIs based on Analog Config table with RFAL_ANALOG_CONFIG_ANTICOL settings */ + RFAL_TXRX_FLAGS_PAR_RX_KEEP = (1U<<4), /*!< Disable Parity check and keep the Parity and CRC bits in the received buffer */ + RFAL_TXRX_FLAGS_PAR_RX_REMV = (0U<<4), /*!< Enable Parity check and remove the parity bits from the received buffer */ + RFAL_TXRX_FLAGS_PAR_TX_NONE = (1U<<5), /*!< Disable automatic Parity generation (ISO14443A) and use the one provided in the buffer*/ + RFAL_TXRX_FLAGS_PAR_TX_AUTO = (0U<<5), /*!< Enable automatic Parity generation (ISO14443A) */ + RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL = (1U<<6), /*!< Disable automatic adaption of flag byte (ISO15693) according to current comm params */ + RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO = (0U<<6), /*!< Enable automatic adaption of flag byte (ISO115693) according to current comm params */ + RFAL_TXRX_FLAGS_CRC_RX_MANUAL = (1U<<7), /*!< Disable automatic CRC check */ + RFAL_TXRX_FLAGS_CRC_RX_AUTO = (0U<<7), /*!< Enable automatic CRC check */ +}; + + +/*! RFAL error handling */ +typedef enum { + RFAL_ERRORHANDLING_NONE = 0, /*!< No special error handling will be performed */ + RFAL_ERRORHANDLING_EMD = 1 /*!< EMD suppression enabled Digital 2.1 4.1.1.1 ; EMVCo 3.0 4.9.2 ; ISO 14443-3 8.3 */ +} rfalEHandling; + + +/*! Struct that holds all context to be used on a Transceive */ +typedef struct { + uint8_t* txBuf; /*!< (In) Buffer where outgoing message is located */ + uint16_t txBufLen; /*!< (In) Length of the outgoing message in bits */ + + uint8_t* rxBuf; /*!< (Out) Buffer where incoming message will be placed */ + uint16_t rxBufLen; /*!< (In) Maximum length of the incoming message in bits */ + uint16_t* rxRcvdLen; /*!< (Out) Actual received length in bits */ + + uint32_t flags; /*!< (In) TransceiveFlags indication special handling */ + uint32_t fwt; /*!< (In) Frame Waiting Time in 1/fc */ +} rfalTransceiveContext; + + +/*! System callback to indicate an event that requires a system reRun */ +typedef void (* rfalUpperLayerCallback)(void); + +/*! Callback to be executed before a Transceive */ +typedef void (* rfalPreTxRxCallback)(void); + +/*! Callback to be executed after a Transceive */ +typedef void (* rfalPostTxRxCallback)(void); + +/*! Callback to sync actual transmission start */ +typedef bool (* rfalSyncTxRxCallback)(void); + +/*! Callback upon External Field detected while in Listen Mode */ +typedef void (* rfalLmEonCallback)(void); + +/*******************************************************************************/ +/* ISO14443A */ +/*******************************************************************************/ + +/*! RFAL ISO 14443A Short Frame Command */ +typedef enum +{ + RFAL_14443A_SHORTFRAME_CMD_WUPA = 0x52, /*!< ISO14443A WUPA / NFC-A ALL_REQ */ + RFAL_14443A_SHORTFRAME_CMD_REQA = 0x26 /*!< ISO14443A REQA / NFC-A SENS_REQ */ +} rfal14443AShortFrameCmd; + +/*******************************************************************************/ + + +/*******************************************************************************/ +/* FeliCa */ +/*******************************************************************************/ + +#define RFAL_FELICA_LEN_LEN 1U /*!< FeliCa LEN byte length */ +#define RFAL_FELICA_POLL_REQ_LEN (RFAL_FELICA_LEN_LEN + 1U + 2U + 1U + 1U) /*!< FeliCa Poll Request length (LEN + CMD + SC + RC + TSN) */ +#define RFAL_FELICA_POLL_RES_LEN (RFAL_FELICA_LEN_LEN + 1U + 8U + 8U + 2U) /*!< Maximum FeliCa Poll Response length (LEN + CMD + NFCID2 + PAD + RD) */ +#define RFAL_FELICA_POLL_MAX_SLOTS 16U /*!< Maximum number of slots (TSN) on FeliCa Poll */ + + +/*! NFC-F RC (Request Code) codes NFC Forum Digital 1.1 Table 42 */ +enum +{ + RFAL_FELICA_POLL_RC_NO_REQUEST = 0x00U, /*!< RC: No System Code information requested */ + RFAL_FELICA_POLL_RC_SYSTEM_CODE = 0x01U, /*!< RC: System Code information requested */ + RFAL_FELICA_POLL_RC_COM_PERFORMANCE = 0x02U /*!< RC: Advanced protocol features supported */ +}; + + +/*! NFC-F TSN (Time Slot Number) codes NFC Forum Digital 1.1 Table 43 */ +typedef enum +{ + RFAL_FELICA_1_SLOT = 0, /*!< TSN with number of Time Slots: 1 */ + RFAL_FELICA_2_SLOTS = 1, /*!< TSN with number of Time Slots: 2 */ + RFAL_FELICA_4_SLOTS = 3, /*!< TSN with number of Time Slots: 4 */ + RFAL_FELICA_8_SLOTS = 7, /*!< TSN with number of Time Slots: 8 */ + RFAL_FELICA_16_SLOTS = 15 /*!< TSN with number of Time Slots: 16 */ +} rfalFeliCaPollSlots; + + +/*! NFCF Poll Response NFC Forum Digital 1.1 Table 44 */ +typedef uint8_t rfalFeliCaPollRes[RFAL_FELICA_POLL_RES_LEN]; + + +/*******************************************************************************/ + + +/*******************************************************************************/ +/* Listen Mode */ +/*******************************************************************************/ + +/*! RFAL Listen Mode NFCID Length */ +typedef enum +{ + RFAL_LM_NFCID_LEN_04 = RFAL_NFCID1_SINGLE_LEN, /*!< Listen mode indicates 4 byte NFCID */ + RFAL_LM_NFCID_LEN_07 = RFAL_NFCID1_DOUBLE_LEN, /*!< Listen mode indicates 7 byte NFCID */ + RFAL_LM_NFCID_LEN_10 = RFAL_NFCID1_TRIPLE_LEN, /*!< Listen mode indicates 10 byte NFCID */ +} rfalLmNfcidLen; + + +/*! RFAL Listen Mode States */ +typedef enum +{ + RFAL_LM_STATE_NOT_INIT = 0x00, /*!< Not Initialized state */ + RFAL_LM_STATE_POWER_OFF = 0x01, /*!< Power Off state */ + RFAL_LM_STATE_IDLE = 0x02, /*!< Idle state Activity 1.1 5.2 */ + RFAL_LM_STATE_READY_A = 0x03, /*!< Ready A state Activity 1.1 5.3 5.4 & 5.5 */ + RFAL_LM_STATE_READY_B = 0x04, /*!< Ready B state Activity 1.1 5.11 5.12 */ + RFAL_LM_STATE_READY_F = 0x05, /*!< Ready F state Activity 1.1 5.15 */ + RFAL_LM_STATE_ACTIVE_A = 0x06, /*!< Active A state Activity 1.1 5.6 */ + RFAL_LM_STATE_CARDEMU_4A = 0x07, /*!< Card Emulation 4A state Activity 1.1 5.10 */ + RFAL_LM_STATE_CARDEMU_4B = 0x08, /*!< Card Emulation 4B state Activity 1.1 5.14 */ + RFAL_LM_STATE_CARDEMU_3 = 0x09, /*!< Card Emulation 3 state Activity 1.1 5.18 */ + RFAL_LM_STATE_TARGET_A = 0x0A, /*!< Target A state Activity 1.1 5.9 */ + RFAL_LM_STATE_TARGET_F = 0x0B, /*!< Target F state Activity 1.1 5.17 */ + RFAL_LM_STATE_SLEEP_A = 0x0C, /*!< Sleep A state Activity 1.1 5.7 */ + RFAL_LM_STATE_SLEEP_B = 0x0D, /*!< Sleep B state Activity 1.1 5.13 */ + RFAL_LM_STATE_READY_Ax = 0x0E, /*!< Ready A* state Activity 1.1 5.3 5.4 & 5.5 */ + RFAL_LM_STATE_ACTIVE_Ax = 0x0F, /*!< Active A* state Activity 1.1 5.6 */ + RFAL_LM_STATE_SLEEP_AF = 0x10, /*!< Sleep AF state Activity 1.1 5.19 */ +} rfalLmState; + + +/*! RFAL Listen Mode Passive A configs */ +typedef struct +{ + rfalLmNfcidLen nfcidLen; /*!< NFCID Len (4, 7 or 10 bytes) */ + uint8_t nfcid[RFAL_NFCID1_TRIPLE_LEN]; /*!< NFCID */ + uint8_t SENS_RES[RFAL_LM_SENS_RES_LEN]; /*!< NFC-106k; SENS_REQ Response */ + uint8_t SEL_RES; /*!< SEL_RES (SAK) with complete NFCID1 (UID) */ +} rfalLmConfPA; + + +/*! RFAL Listen Mode Passive B configs */ +typedef struct +{ + uint8_t SENSB_RES[RFAL_LM_SENSB_RES_LEN]; /*!< SENSF_RES */ +} rfalLmConfPB; + + +/*! RFAL Listen Mode Passive F configs */ +typedef struct +{ + uint8_t SC[RFAL_LM_SENSF_SC_LEN]; /*!< System Code to listen for */ + uint8_t SENSF_RES[RFAL_LM_SENSF_RES_LEN]; /*!< SENSF_RES */ +} rfalLmConfPF; + +/*! RFAL low power modes */ +typedef enum { + RFAL_LP_MODE_PD = 0, /*!< Set RF Chip in Power Down state */ + RFAL_LP_MODE_HR = 1 /*!< Set RF Chip in Hold Reset state (available for specific devices) */ +} rfalLpMode; + +/*******************************************************************************/ + + +/*******************************************************************************/ +/* Wake-Up Mode */ +/*******************************************************************************/ + +#define RFAL_WUM_REFERENCE_AUTO 0xFFU /*!< Indicates new reference is set by the driver */ + +/*! RFAL Wake-Up Mode States */ +typedef enum +{ + RFAL_WUM_STATE_NOT_INIT = 0x00, /*!< Not Initialized state */ + RFAL_WUM_STATE_INITIALIZING = 0x01, /*!< Wake-Up mode is starting */ + RFAL_WUM_STATE_ENABLED = 0x02, /*!< Wake-Up mode is enabled */ + RFAL_WUM_STATE_ENABLED_WOKE = 0x03, /*!< Wake-Up mode enabled and has received IRQ(s)*/ +} rfalWumState; + + +/*******************************************************************************/ + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + + +/*! + ***************************************************************************** + * \brief RFAL Initialize + * + * Initializes RFAL layer and the ST25R391x + * Ensures that ST25R is properly connected and returns error if any problem + * is detected + * + * \warning rfalAnalogConfigInitialize() should be called before so that + * the Analog config table has been previously initialized. + * + * \return RFAL_ERR_HW_MISMATCH : Expected HW do not match or communication error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalInitialize( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Calibrate + * + * Performs necessary calibration of RF chip in case it is indicated by current + * register settings. E.g. antenna calibration and regulator calibration + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode rfalCalibrate( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Adjust Regulators + * + * Adjusts ST25R391x regulators + * + * \param[out] result : the result of the calibrate antenna in mV + * NULL if result not requested + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode rfalAdjustRegulators( uint16_t* result ); + + +/*! + ***************************************************************************** + * \brief RFAL Set System Callback + * + * Sets a callback for the driver to call when an event has occurred that + * may require the system to be notified + * + * \param[in] pFunc : method pointer for the upper layer callback + * + ***************************************************************************** + */ +void rfalSetUpperLayerCallback( rfalUpperLayerCallback pFunc ); + + +/*! + ***************************************************************************** + * \brief RFAL Set Pre Tx Callback + * + * Sets a callback for the driver to call before a Transceive + * + * \param[in] pFunc : method pointer for the Pre Tx callback + * + ***************************************************************************** + */ +void rfalSetPreTxRxCallback( rfalPreTxRxCallback pFunc ); + + +/*! + ***************************************************************************** + * \brief RFAL Sync Pre Tx Callback + * + * Sets a callback for the driver to execute in order to Syncronize actual + * transmission start. + * If the callback is set TxRx will hold until Sync callback returns true. + * + * \param[in] pFunc : method pointer for the Sync Tx callback + * + ***************************************************************************** + */ +void rfalSetSyncTxRxCallback( rfalSyncTxRxCallback pFunc ); + + +/*! + ***************************************************************************** + * \brief RFAL Set Post Tx Callback + * + * Sets a callback for the driver to call after a Transceive + * + * \param[in] pFunc : method pointer for the Post Tx callback + * + ***************************************************************************** + */ +void rfalSetPostTxRxCallback( rfalPostTxRxCallback pFunc ); + + +/*! + ***************************************************************************** + * \brief RFAL Set LM EON Callback + * + * Sets a callback upon External Field On detected while in Passive Listen Mode + * + * \warning callabck available only on applicable devices, + * supporting Passive Listen Mode + * + * \param[in] pFunc : method pointer for the LM EON callback + * + ***************************************************************************** + */ +void rfalSetLmEonCallback( rfalLmEonCallback pFunc ); + + +/*! + ***************************************************************************** + * \brief RFAL Deinitialize + * + * Deinitializes RFAL layer and the ST25R + * + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode rfalDeinitialize( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Set Mode + * + * Sets the mode that RFAL will operate on the following communications. + * Proper initializations will be performed on the ST25R + * + * \warning bit rate value RFAL_BR_KEEP is not allowed, only in rfalSetBitRate() + * + * \warning the mode will be applied immediately on the RFchip regardless of + * any ongoing operations like Transceive, ListenMode + * + * \param[in] mode : mode for the RFAL/RFchip to perform + * \param[in] txBR : transmit bit rate + * \param[in] rxBR : receive bit rate + * + * \see rfalIsGTExpired + * \see rfalMode + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode rfalSetMode( rfalMode mode, rfalBitRate txBR, rfalBitRate rxBR ); + + +/*! + ***************************************************************************** + * \brief RFAL Get Mode + * + * Gets the mode that RFAL is set to operate + * + * \see rfalMode + * + * \return rfalMode : The current RFAL mode + ***************************************************************************** + */ +rfalMode rfalGetMode( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Set Bit Rate + * + * Sets the Tx and Rx bit rates with the given values + * The bit rate change is applied on the RF chip remaining in the same + * mode previous defined with rfalSetMode() + * + * If no mode is defined bit rates will not be applied and an error + * is returned + * + * \param[in] txBR : transmit bit rate + * \param[in] rxBR : receive bit rate + * + * \see rfalSetMode + * \see rfalMode + * \see rfalBitRate + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NOT_IMPLEMENTED : Mode not implemented + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode rfalSetBitRate( rfalBitRate txBR, rfalBitRate rxBR ); + + +/*! + ***************************************************************************** + * \brief RFAL Get Bit Rate + * + * Gets the Tx and Rx current bit rates + * + * If RFAL is not initialized or mode not set the bit rates return will + * be invalid RFAL_BR_KEEP + * + * \param[out] txBR : RFAL's current Tx Bit Rate + * \param[out] rxBR : RFAL's current Rx Bit Rate + * + * \see rfalSetBitRate + * \see rfalBitRate + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalGetBitRate( rfalBitRate *txBR, rfalBitRate *rxBR ); + + +/*! + ***************************************************************************** + * \brief Set Error Handling Mode + * + * Sets the error handling mode to be used by the RFAL + * + * \param[in] eHandling : the error handling mode + * + ***************************************************************************** + */ +void rfalSetErrorHandling( rfalEHandling eHandling ); + + +/*! + ***************************************************************************** + * \brief Get Error Handling Mode + * + * Gets the error handling mode currently used by the RFAL + * + * \return rfalEHandling : Current error handling mode + ***************************************************************************** + */ +rfalEHandling rfalGetErrorHandling( void ); + + +/*! + ***************************************************************************** + * \brief Set Observation Mode + * + * Sets ST25R391x observation modes for RF debug purposes + * + * \param[in] txMode : the observation mode to be used during transmission + * \param[in] rxMode : the observation mode to be used during reception + * + * \warning The Observation Mode is an advanced feature and should be set + * according to the documentation of the part number in use. + * Please refer to the corresponding Datasheet or Application Note(s) + ***************************************************************************** + */ +void rfalSetObsvMode( uint32_t txMode, uint32_t rxMode ); + + +/*! + ***************************************************************************** + * \brief Get Observation Mode + * + * Gets ST25R391x the current configured observation modes + * + * \param[in] txMode : the current observation mode configured for transmission + * \param[in] rxMode : the current observation mode configured for reception + * + ***************************************************************************** + */ +void rfalGetObsvMode( uint8_t* txMode, uint8_t* rxMode ); + + +/*! + ***************************************************************************** + * \brief Disable Observation Mode + * + * Disables the ST25R391x observation mode + ***************************************************************************** + */ +void rfalDisableObsvMode( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Set FDT Poll + * + * Sets the Frame Delay Time (FDT) to be used on the following + * communications. + * + * FDT Poll is the minimum time following a Poll Frame during + * which no subsequent Poll Frame can be sent (without a response from + * the Listener in between) + * FDTx,PP,MIN - Digital 1.1 6.10.2 & 7.9.2 & 8.7.2 + * + * \param[in] FDTPoll : Frame Delay Time in 1/fc cycles + * + ***************************************************************************** + */ +void rfalSetFDTPoll( uint32_t FDTPoll ); + + +/*! + ***************************************************************************** + * \brief RFAL Set FDT Poll + * + * Gets the current Frame Delay Time (FDT) + * + * FDT Poll is the minimum time following a Poll Frame during + * which no subsequent Poll Frame can be sent (without a response from + * the Listener in between) + * FDTx,PP,MIN - Digital 1.1 6.10.2 & 7.9.2 & 8.7.2 + * + * \return FDT : current FDT value in 1/fc cycles + * + ***************************************************************************** + */ +uint32_t rfalGetFDTPoll( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Set FDT Listen + * + * Sets the Frame Delay Time (FDT) Listen minimum to be used on the + * following communications. + * + * FDT Listen is the minimum time between a Poll Frame and a Listen Frame + * FDTx,LISTEN,MIN - Digital 1.1 6.10.1 & 7.9.1 & 8.7.1 + * + * \param[in] FDTListen : Frame Delay Time in 1/fc cycles + * + ***************************************************************************** + */ +void rfalSetFDTListen( uint32_t FDTListen ); + + +/*! + ***************************************************************************** + * \brief RFAL Set FDT Listen + * + * Gets the Frame Delay Time (FDT) Listen minimum + * + * FDT Listen is the minimum time between a Poll Frame and a Listen Frame + * FDTx,LISTEN,MIN - Digital 1.1 6.10.1 & 7.9.1 & 8.7.1 + * + * \return FDT : current FDT value in 1/fc cycles + * + ***************************************************************************** + */ +uint32_t rfalGetFDTListen( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Get GT + * + * Gets the current Guard Time (GT) + * + * GT is the minimum time when a device in Listen Mode is exposed to an + * unmodulated carrier + * + * \return GT : Guard Time in 1/fc cycles + * + ***************************************************************************** + */ +uint32_t rfalGetGT( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Set GT + * + * Sets the Guard Time (GT) to be used on the following communications. + * + * GT is the minimum time when a device in Listen Mode is exposed to an + * unmodulated carrier + * + * \param[in] GT : Guard Time in 1/fc cycles + * RFAL_GT_NONE if no GT should be applied + * + ***************************************************************************** + */ +void rfalSetGT( uint32_t GT ); + + +/*! + ***************************************************************************** + * \brief RFAL Is GT expired + * + * Checks whether the GT timer has expired + * + * \return true : GT has expired or not running + * \return false : GT is still running + * + ***************************************************************************** + */ +bool rfalIsGTExpired( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Turn Field On and Start GT + * + * Turns the Field On, performing Initial Collision Avoidance + * + * After Field On, if GT was set before, it starts the GT timer to be + * used on the following communications. + * + * \return RFAL_ERR_RF_COLLISION : External field detected + * \return RFAL_ERR_NONE : Field turned On + * + ***************************************************************************** + */ +ReturnCode rfalFieldOnAndStartGT( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Turn Field Off + * + * Turns the Field Off + * + * \return RFAL_ERR_NONE : Field turned Off + ***************************************************************************** + */ +ReturnCode rfalFieldOff( void ); + + + +/***************************************************************************** + * Transceive * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief RFAL Set transceive context + * + * Set the context that will be used for the following Transceive + * Output and input buffers have to be passed and all other details prior to + * the Transceive itself has been started + * + * This method only sets the context. Once set, rfalWorker has + * to be executed until is done + * + * \param[in] ctx : the context for the following Transceive + * + * \see rfalWorker + * \see rfalGetTransceiveStatus + * + * \return RFAL_ERR_NONE : Done with no error + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter or configuration + ***************************************************************************** + */ +ReturnCode rfalStartTransceive( const rfalTransceiveContext *ctx ); + + +/*! + ***************************************************************************** + * \brief Get Transceive State + * + * Gets current Transceive internal State + * + * \return rfalTransceiveState : the current Transceive internal State + ***************************************************************************** + */ +rfalTransceiveState rfalGetTransceiveState( void ); + + +/*! + ***************************************************************************** + * \brief Get Transceive Status + * + * Gets current Transceive status + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_BUSY : Transceive ongoing + * \return RFAL_ERR_XXXX : Error occurred + * \return RFAL_ERR_TIMEOUT : No response + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_LINK_LOSS : Link Loss - External Field is Off + * \return RFAL_ERR_RF_COLLISION : Collision detected + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalGetTransceiveStatus( void ); + + +/*! + ***************************************************************************** + * \brief Is Transceive in Tx + * + * Checks if Transceive is in Transmission state + * + * \return true Transmission ongoing + * \return false Not in transmission state + ***************************************************************************** + */ +bool rfalIsTransceiveInTx( void ); + + +/*! + ***************************************************************************** + * \brief Is Transceive in Rx + * + * Checks if Transceive is in Reception state + * + * \return true Transmission done/reception ongoing + * \return false Not in reception state + ***************************************************************************** + */ +bool rfalIsTransceiveInRx( void ); + + +/*! + ***************************************************************************** + * \brief Get Transceive RSSI + * + * Gets the RSSI value of the last executed Transceive in mV + * + * \param[out] rssi : RSSI value + * + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalGetTransceiveRSSI( uint16_t *rssi ); + + +/*! + ***************************************************************************** + * \brief Is Transceive Subcarrier Detected + * + * Checks on the last executed Transceive a subcarrier was detected + * + * \return true Subcarrier was detected + * \return false No subcarrier detected | Not supported + ***************************************************************************** + */ +bool rfalIsTransceiveSubcDetected( void ); + + +/*! + ***************************************************************************** + * \brief RFAL Worker + * + * This runs RFAL layer, which drives the actual Transceive procedure + * It MUST be executed frequently in order to execute the RFAL internal + * states and perform the requested operations + * + ***************************************************************************** + */ +void rfalWorker( void ); + + +/***************************************************************************** + * ISO1443A * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief Transceives an ISO14443A ShortFrame + * + * Sends REQA or WUPA to detect if there is any PICC in the field + * + * \param[in] txCmd: Command to be sent: + * 0x52 WUPA / ALL_REQ + * 0x26 REQA / SENS_REQ + * \param[out] rxBuf : buffer to place the response + * \param[in] rxBufLen : length of rxBuf in bytes + * \param[out] rxRcvdLen: received length in bits + * \param[in] fwt : Frame Waiting Time in 1/fc + * + * \warning If fwt is set to RFAL_FWT_NONE it will make endlessly for + * a response, which on a blocking method may not be the + * desired usage + * + * \return RFAL_ERR_NONE : If there is response + * \return RFAL_ERR_TIMEOUT : If there is no response + * \return RFAL_ERR_RF_COLLISION : A collision was detected + * + ***************************************************************************** + */ +ReturnCode rfalISO14443ATransceiveShortFrame( rfal14443AShortFrameCmd txCmd, uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* rxRcvdLen, uint32_t fwt ); + + +/*! + ***************************************************************************** + * \brief Sends an ISO14443A Anticollision Frame + * + * This is used to perform ISO14443A anti-collision. + * \note Anticollision is sent without CRC + * + * + * \param[in,out] buf : reference to ANTICOLLISION command (with known UID if any) to be sent (also out param) + * reception will be place on this buf after bytesToSend + * buffer must be capable of holding a whole Anticollison frame (rfalNfcaSelReq) + * \param[in,out] bytesToSend: reference number of full bytes to be sent (including CMD byte and SEL_PAR) + * if a collision occurs will contain the number of clear bytes + * \param[in,out] bitsToSend : reference to number of bits (0-7) to be sent; and received (also out param) + * if a collision occurs will indicate the number of clear bits (also out param) + * \param[out] rxLength : reference to the return the received length in bits + * \param[in] fwt : Frame Waiting Time in 1/fc + * + * \return RFAL_ERR_NONE if there is no error + ***************************************************************************** + */ +ReturnCode rfalISO14443ATransceiveAnticollisionFrame( uint8_t *buf, uint8_t *bytesToSend, uint8_t *bitsToSend, uint16_t *rxLength, uint32_t fwt ); + + +/*! + ***************************************************************************** + * \brief Start ISO14443A Anticollision Frame transceive + * + * This starts the transceive of an ISO14443A anti-collision frame. + * \note Anticollision is sent without CRC + * + * + * \param[in,out] buf : reference to ANTICOLLISION command (with known UID if any) to be sent (also out param) + * reception will be place on this buf after bytesToSend + * buffer must be capable of holding a whole Anticollison frame (rfalNfcaSelReq) + * \param[in,out] bytesToSend: reference number of full bytes to be sent (including CMD byte and SEL_PAR) + * if a collision occurs will contain the number of clear bytes + * \param[in,out] bitsToSend : reference to number of bits (0-7) to be sent; and received (also out param) + * if a collision occurs will indicate the number of clear bits (also out param) + * \param[out] rxLength : reference to the return the received length in bits + * \param[in] fwt : Frame Waiting Time in 1/fc + * + * \return RFAL_ERR_NONE if there is no error + ***************************************************************************** + */ +ReturnCode rfalISO14443AStartTransceiveAnticollisionFrame( uint8_t *buf, uint8_t *bytesToSend, uint8_t *bitsToSend, uint16_t *rxLength, uint32_t fwt ); + + +/*! + ***************************************************************************** + * \brief Get ISO14443A Anticollision Frame Status + * + * This gets the ISO14443A anti-collision frame status. + * + * + * \return RFAL_ERR_NONE if there is no error + ***************************************************************************** + */ +ReturnCode rfalISO14443AGetTransceiveAnticollisionFrameStatus( void ); + + +/***************************************************************************** + * FeliCa * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief FeliCa Poll + * + * Sends a Poll Request and collects all Poll Responses according to the + * given slots + * + * + * \param[in] slots : number of slots for the Poll Request + * \param[in] sysCode : system code (SC) for the Poll Request + * \param[in] reqCode : request code (RC) for the Poll Request + * \param[out] pollResList : list of all responses + * \param[in] pollResListSize : number of responses that can be placed in pollResList + * \param[out] devicesDetected : number of cards found + * \param[out] collisionsDetected: number of collisions detected + * + * \return RFAL_ERR_NONE : If there is no error + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_TIMEOUT : If there is no response + ***************************************************************************** + */ +ReturnCode rfalFeliCaPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes* pollResList, uint8_t pollResListSize, uint8_t *devicesDetected, uint8_t *collisionsDetected ); + +/*! + ***************************************************************************** + * \brief Start FeliCa Poll + * + * Triggers a Poll Request and all Poll Responses will be collected according + * to the given nuber of slots + * + * + * \param[in] slots : number of slots for the Poll Request + * \param[in] sysCode : system code (SC) for the Poll Request + * \param[in] reqCode : request code (RC) for the Poll Request + * \param[out] pollResList : list of all responses + * \param[in] pollResListSize : number of responses that can be placed in pollResList + * \param[out] devicesDetected : number of cards found + * \param[out] collisionsDetected: number of collisions detected + * + * \return RFAL_ERR_NONE : If there is no error + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + ***************************************************************************** + */ +ReturnCode rfalStartFeliCaPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes* pollResList, uint8_t pollResListSize, uint8_t *devicesDetected, uint8_t *collisionsDetected ); + +/*! + ***************************************************************************** + * \brief Get FeliCa Poll Status + * + * Gets the current state of the Felica Poll Request triggered before + * by rfalStartFeliCaPoll() + * + * + * + * \return RFAL_ERR_NONE : If there is no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_TIMEOUT : If there is no response + ***************************************************************************** + */ +ReturnCode rfalGetFeliCaPollStatus( void ); + + +/***************************************************************************** + * ISO15693 * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief Sends an ISO15693 Anticollision Frame + * + * This send the Anticollision|Inventory frame (INVENTORY_REQ) + * + * \warning rxBuf must be able to contain the payload and CRC + * + * \param[in] txBuf : Buffer where outgoing message is located + * \param[in] txBufLen : Length of the outgoing message in bytes + * \param[out] rxBuf : Buffer where incoming message will be placed + * \param[in] rxBufLen : Maximum length of the incoming message in bytes + * \param[out] actLen : Actual received length in bits + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalISO15693TransceiveAnticollisionFrame( uint8_t *txBuf, uint8_t txBufLen, uint8_t *rxBuf, uint8_t rxBufLen, uint16_t *actLen ); + + +/*! + ***************************************************************************** + * \brief Sends an ISO15693 Anticollision EOF + * + * This sends the Anticollision|Inventory EOF used as a slot marker + * + * \warning rxBuf must be able to contain the payload and CRC + * + * \param[out] rxBuf : Buffer where incoming message will be placed + * \param[in] rxBufLen : Maximum length of the incoming message in bytes + * \param[out] actLen : Actual received length in bits + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalISO15693TransceiveEOFAnticollision( uint8_t *rxBuf, uint8_t rxBufLen, uint16_t *actLen ); + + +/*! + ***************************************************************************** + * \brief Sends an ISO15693 EOF + * + * This is method sends an ISO15693 (EoF) used for a Write operation + * + * \warning rxBuf must be able to contain the payload and CRC + * + * \param[out] rxBuf : Buffer where incoming message will be placed + * \param[in] rxBufLen : Maximum length of the incoming message in bytes + * \param[out] actLen : Actual received length in bytes + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalISO15693TransceiveEOF( uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *actLen ); + + +/*! + ***************************************************************************** + * \brief Transceive Blocking Tx + * + * This is method triggers a Transceive and executes it blocking until the + * Tx has been completed + * + * \param[in] txBuf : Buffer where outgoing message is located + * \param[in] txBufLen : Length of the outgoing message in bytes + * \param[out] rxBuf : Buffer where incoming message will be placed + * \param[in] rxBufLen : Maximum length of the incoming message in bytes + * \param[out] actLen : Actual received length in bits + * \param[in] flags : TransceiveFlags indication special handling + * \param[in] fwt : Frame Waiting Time in 1/fc + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_BUSY : Transceive ongoing + * \return RFAL_ERR_XXXX : Error occurred + * \return RFAL_ERR_LINK_LOSS : Link Loss - External Field is Off + * \return RFAL_ERR_RF_COLLISION : Collision detected + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalTransceiveBlockingTx( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* actLen, uint32_t flags, uint32_t fwt ); + +/*! + ***************************************************************************** + * \brief Transceive Blocking Rx + * + * This is method executes the reception of an ongoing Transceive triggered + * before by rfalTransceiveBlockingTx() + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_BUSY : Transceive ongoing + * \return RFAL_ERR_XXXX : Error occurred + * \return RFAL_ERR_TIMEOUT : No response + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_LINK_LOSS : Link Loss - External Field is Off + * \return RFAL_ERR_RF_COLLISION : Collision detected + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalTransceiveBlockingRx( void ); + +/*! + ***************************************************************************** + * \brief Transceive Blocking + * + * This is method triggers a Transceive and executes it blocking until it + * has been completed + * + * \param[in] txBuf : Buffer where outgoing message is located + * \param[in] txBufLen : Length of the outgoing message in bytes + * \param[out] rxBuf : Buffer where incoming message will be placed + * \param[in] rxBufLen : Maximum length of the incoming message in bytes + * \param[out] actLen : Actual received length in bytes + * \param[in] flags : TransceiveFlags indication special handling + * \param[in] fwt : Frame Waiting Time in 1/fc + * + * \return RFAL_ERR_NONE : Transceive done with no error + * \return RFAL_ERR_BUSY : Transceive ongoing + * \return RFAL_ERR_XXXX : Error occurred + * \return RFAL_ERR_TIMEOUT : No response + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PAR : Parity error detected + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_LINK_LOSS : Link Loss - External Field is Off + * \return RFAL_ERR_RF_COLLISION : Collision detected + * \return RFAL_ERR_IO : Internal error + ***************************************************************************** + */ +ReturnCode rfalTransceiveBlockingTxRx( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* actLen, uint32_t flags, uint32_t fwt ); + + + +/***************************************************************************** + * Listen Mode * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief Is external Field On + * + * Checks if external field (other peer/device) is on/detected + * + * \return true External field is On + * \return false No external field is detected + * + ***************************************************************************** + */ +bool rfalIsExtFieldOn( void ); + + +/*! + ***************************************************************************** + * \brief Listen Mode start + * + * Configures RF Chip to go into listen mode enabling the given technologies + * + * + * \param[in] lmMask: mask with the enabled/disabled listen modes + * use: RFAL_LM_MASK_NFCA ; RFAL_LM_MASK_NFCB ; + * RFAL_LM_MASK_NFCF ; RFAL_LM_MASK_ACTIVE_P2P + * \param[in] confA: pointer to Passive A configurations (NULL if disabled) + * \param[in] confB: pointer to Passive B configurations (NULL if disabled) + * \param[in] confF: pointer to Passive F configurations (NULL if disabled) + * \param[in] rxBuf: buffer to place incoming data + * \param[in] rxBufLen: length in bits of rxBuf + * \param[in] rxLen: pointer to write the data length in bits placed into rxBuf + * + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parametere mask + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalListenStart( uint32_t lmMask, const rfalLmConfPA *confA, const rfalLmConfPB *confB, const rfalLmConfPF *confF, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rxLen ); + + +/*! + ***************************************************************************** + * \brief Listen Mode start Sleeping + * + * \param[in] sleepSt : sleep state to be set + * \param[in] rxBuf : buffer to place incoming data + * \param[in] rxBufLen : length in bits of rxBuf + * \param[in] rxLen : pointer to write the data length in bits placed into rxBuf + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalListenSleepStart( rfalLmState sleepSt, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rxLen ); + + +/*! + ***************************************************************************** + * \brief Listen Mode Stop + * + * Disables the listen mode on the RF Chip + * + * \warning the listen mode will be disabled immediately on the RFchip regardless + * of any ongoing operations like Transceive + * + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalListenStop( void ); + + +/*! + ***************************************************************************** + * \brief Listen Mode get state + * + * Sets the new state of the Listen Mode and applies the necessary changes + * on the RF Chip + * + * \param[out] dataFlag: indicates that Listen Mode has rcvd data and caller + * must process it. The received message is located + * at the rxBuf passed on rfalListenStart(). + * rfalListenSetState() will clear this flag + * if NULL output parameter will no be written/returned + * \param[out] lastBR: bit rate detected of the last initiator request + * if NULL output parameter will no be written/returned + * + * \return rfalLmState RFAL_LM_STATE_NOT_INIT : LM not initialized properly + * Any Other : LM State + * + ***************************************************************************** + */ +rfalLmState rfalListenGetState( bool *dataFlag, rfalBitRate *lastBR ); + + +/*! + ***************************************************************************** + * \brief Listen Mode set state + * + * Sets the new state of the Listen Mode and applies the necessary changes + * on the RF Chip + * + * \param[in] newSt : New state to go to + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalListenSetState( rfalLmState newSt ); + + +/***************************************************************************** + * Wake-Up Mode * + *****************************************************************************/ + +/*! + ***************************************************************************** + * \brief Wake-Up Mode Start + * + * Sets the RF Chip in Low Power Wake-Up Mode according to the given + * configuration. + * + * \param[in] config : Generic Wake-Up configuration provided by lower + * layers. If NULL will automatically configure the + * Wake-Up mode + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalWakeUpModeStart( const rfalWakeUpConfig *config ); + + +/*! + ***************************************************************************** + * \brief Wake-Up has Woke + * + * Returns true if the Wake-Up mode is enabled and it has already received + * the indication from the RF Chip that the surrounding environment has changed + * and flagged at least one wake-Up interrupt + * + * \return true : Wake-Up mode enabled and has received a wake-up IRQ + * \return false : no Wake-Up IRQ has been received + * + ***************************************************************************** + */ +bool rfalWakeUpModeHasWoke( void ); + + +/*! + ***************************************************************************** + * \brief Wake-Up is Enabled + * + * Returns true if the Wake-Up mode is enabled and it has already completed + * its starting up sequence. + * When the option to obtain a reference value from WU is enabled, the startup + * sequence takes longer. Otherwise WU mode is running after rfalWakeUpModeStart + * + * \return true : Wake-Up mode enabled + * \return false : Wake-Up mode not enabled + * + ***************************************************************************** + */ +bool rfalWakeUpModeIsEnabled( void ); + + +/*! + ***************************************************************************** + * \brief Wake-Up Get Info + * + * Returns the current information while Wake-up mode is running + * + * \warning The information returned will only be updated in case force is + * enabled, or if an event IRQ has happen. + * Otherwise the info will be filled with zeros. + * + * \param[in] force : Force info update info by retrieving it from device + * \param[out] info : pointer where WU mode info is to be stored + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + ***************************************************************************** + */ +ReturnCode rfalWakeUpModeGetInfo( bool force, rfalWakeUpInfo *info ); + +/*! + ***************************************************************************** + * \brief Wake-Up Mode Stop + * + * Stops the Wake-Up Mode + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalWakeUpModeStop( void ); + + +/*! + ***************************************************************************** + * \brief Low Power Mode Start + * + * Sets the RF Chip in Low Power Mode. + * In this mode the RF Chip is placed in Low Power Mode, similar to Wake-up + * mode but no operation nor period measurement is performed. + * Mode must be terminated by rfalLowPowerModeStop() + * + * \param[in] mode : low power mode to be set + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalLowPowerModeStart( rfalLpMode mode ); + + +/*! + ***************************************************************************** + * \brief Low Power Mode Stop + * + * Stops the Low Power Mode re-enabling the device + * + * \return RFAL_ERR_WRONG_STATE : Not initialized properly + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : Done with no error + * + ***************************************************************************** + */ +ReturnCode rfalLowPowerModeStop( void ); + + +#endif /* RFAL_RF_H */ + + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25tb.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25tb.h new file mode 100644 index 0000000..b91d9a7 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25tb.h @@ -0,0 +1,350 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_st25tb.h + * + * \author Gustavo Patricio + * + * \brief Implementation of ST25TB interface + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup ST25TB + * \brief RFAL ST25TB Module + * @{ + * + */ + + +#ifndef RFAL_ST25TB_H +#define RFAL_ST25TB_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" +#include "rfal_nfcb.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_ST25TB_CHIP_ID_LEN 1U /*!< ST25TB chip ID length */ +#define RFAL_ST25TB_CRC_LEN 2U /*!< ST25TB CRC length */ +#define RFAL_ST25TB_UID_LEN 8U /*!< ST25TB Unique ID length */ +#define RFAL_ST25TB_BLOCK_LEN 4U /*!< ST25TB Data Block length */ + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ +typedef uint8_t rfalSt25tbUID[RFAL_ST25TB_UID_LEN]; /*!< ST25TB UID type */ +typedef uint8_t rfalSt25tbBlock[RFAL_ST25TB_BLOCK_LEN]; /*!< ST25TB Block type */ + + +/*! ST25TB listener device (PICC) struct */ +typedef struct +{ + uint8_t chipID; /*!< Device's session Chip ID */ + rfalSt25tbUID UID; /*!< Device's UID */ + bool isDeselected; /*!< Device deselect flag */ +}rfalSt25tbListenDevice; + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Initialize ST25TB Poller mode + * + * This methods configures RFAL RF layer to perform as a + * ST25TB Poller/RW including all default timings + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerInitialize( void ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Check Presence + * + * This method checks if a ST25TB Listen device (PICC) is present on the field + * by sending an Initiate command + * + * \param[out] chipId : if successfully retrieved, the device's chip ID + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_RF_COLLISION : Collision detected one or more device in the field + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerCheckPresence( uint8_t *chipId ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Collision Resolution + * + * This method performs ST25TB Collision resolution, selects the each device, + * retrieves its UID and then deselects. + * In case only one device is identified the ST25TB device is left in select + * state. + * + * \param[in] devLimit : device limit value, and size st25tbDevList + * \param[out] st25tbDevList : ST35TB listener device info + * \param[out] devCnt : Devices found counter + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_RF_COLLISION : Collision detected one or more device in the field + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt ); + +/*! + ***************************************************************************** + * \brief ST25TB Poller Initiate + * + * This method sends an Initiate command + * + * If a single device responds the chip ID will be retrieved + * + * \param[out] chipId : chip ID of the device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerInitiate( uint8_t *chipId ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Pcall + * + * This method sends a Pcall command + * If successful the device's chip ID will be retrieved + * + * \param[out] chipId : Chip ID of the device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerPcall( uint8_t *chipId ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Slot Marker + * + * This method sends a Slot Marker + * + * If a single device responds the chip ID will be retrieved + * + * \param[in] slotNum : Slot Number + * \param[out] chipIdRes : Chip ID of the device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerSlotMarker( uint8_t slotNum, uint8_t *chipIdRes ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Select + * + * This method sends a ST25TB Select command with the given chip ID. + * + * If the device is already in Selected state and receives an incorrect chip + * ID, it goes into Deselected state + * + * \param[in] chipId : chip ID of the device to be selected + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerSelect( uint8_t chipId ); + + +/*! + ***************************************************************************** + * \brief ST25TB Get UID + * + * This method sends a Get_UID command + * + * If a single device responds the chip UID will be retrieved + * + * \param[out] UID : UID of the found device + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerGetUID( rfalSt25tbUID *UID ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Read Block + * + * This method reads a block of the ST25TB + * + * \param[in] blockAddress : address of the block to be read + * \param[out] blockData : location to place the data read from block + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerReadBlock( uint8_t blockAddress, rfalSt25tbBlock *blockData ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Write Block + * + * This method writes a block of the ST25TB + * + * \param[in] blockAddress : address of the block to be written + * \param[in] blockData : data to be written on the block + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerWriteBlock( uint8_t blockAddress, const rfalSt25tbBlock *blockData ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Completion + * + * This method sends a completion command to the ST25TB. After the + * completion the card no longer will reply to any command. + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected, invalid SENSB_RES received + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerCompletion( void ); + + +/*! + ***************************************************************************** + * \brief ST25TB Poller Reset to Inventory + * + * This method sends a Reset to Inventory command to the ST25TB. + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_TIMEOUT : Timeout error, no listener device detected + * \return RFAL_ERR_PROTO : Protocol error detected, invalid SENSB_RES received + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalSt25tbPollerResetToInventory( void ); + + +#endif /* RFAL_ST25TB_H */ + +/** + * @} + * + * @} + * + * @} + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25xv.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25xv.h new file mode 100644 index 0000000..f3e7684 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_st25xv.h @@ -0,0 +1,748 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_st25xv.h + * + * \author Gustavo Patricio + * + * \brief NFC-V ST25 NFC-V Tag specific features + * + * This module provides support for ST's specific features available on + * NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup ST25xV + * \brief RFAL ST25xV Module + * @{ + * + */ + +#ifndef RFAL_ST25xV_H +#define RFAL_ST25xV_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + + +#define RFAL_NFCV_BLOCKNUM_M24LR_LEN 2U /*!< Block Number length of MR24LR tags: 16 bits */ + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Single Block (M24LR) + * + * Reads a Single Block from a M24LR tag which has the number of blocks + * bigger than 256 (M24LR16 ; M24LR64) + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * default: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] blockNum : Number of the block to read (16 bits) + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerM24LRReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Single Block (M24LR) + * + * Reads a Single Block from a M24LR tag which has the number of blocks + * bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * default: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] blockNum : Number of the block to read (16 bits) + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Write Single Block (M24LR) + * + * Writes a Single Block from a M24LR tag which has the number of blocks + * bigger than 256 (M24LR16 ; M24LR64) + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be written + * if not provided Select mode will be used + * \param[in] blockNum : Number of the block to write (16 bits) + * \param[in] wrData : data to be written on the given block + * \param[in] blockLen : number of bytes of a block + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerM24LRWriteSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, const uint8_t* wrData, uint8_t blockLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Multiple Blocks (M24LR) + * + * Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks + * bigger than 256 (M24LR16 ; M24LR64) + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] firstBlockNum : first block to be read (16 bits) + * \param[in] numOfBlocks : number of block to read + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Multiple Blocks (M24LR) + * + * Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks + * bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] firstBlockNum : first block to be read (16 bits) + * \param[in] numOfBlocks : number of block to read + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Single Block + * + * Reads a Single Block from a device (VICC) using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] blockNum : Number of the block to read + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastReadSingleBlock( uint8_t flags, const uint8_t* uid, uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Multiple Blocks + * + * Reads Multiple Blocks from a device (VICC) using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] firstBlockNum : first block to be read + * \param[in] numOfBlocks : number of block to read + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint8_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Extended Read Single Block + * + * Reads a Single Block from a device (VICC) supporting extended commands using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] blockNum : Number of the block to read (16 bits) + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Extended Read Multiple Blocks + * + * Reads Multiple Blocks from a device (VICC) supporting extended commands using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] firstBlockNum : first block to be read (16 bits) + * \param[in] numOfBlocks : number of consecutive blocks to read (16 bits) + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint16_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Configuration + * + * Reads static configuration registers at the Pointer address + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[out] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerReadConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Write Configuration + * + * Writes static configuration registers at the Pointer address + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[in] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerWriteConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ); + + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Dynamic Configuration + * + * Reads dynamic registers at the Pointer address + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[out] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerReadDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Write Dynamic Configuration + * + * Writes dynamic registers at the Pointer address + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[in] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerWriteDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Dynamic Configuration + * + * Reads dynamic registers at the Pointer address using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[out] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastReadDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Write Dynamic Configuration + * + * Writes dynamic registers at the Pointer address using ST Fast mode + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pointer : Pointer address + * \param[in] regValue : Register value + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Present Password + * + * Sends the Present Password command + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pwdNum : Password number + * \param[in] pwd : Password + * \param[in] pwdLen : Password length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerPresentPassword( uint8_t flags, const uint8_t* uid, uint8_t pwdNum, const uint8_t* pwd, uint8_t pwdLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Write Password + * + * Sends the Write Password command + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] pwdNum : Password number + * \param[in] pwd : Password + * \param[in] pwdLen : Password length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerWritePassword( uint8_t flags, const uint8_t* uid, uint8_t pwdNum, const uint8_t *pwd, uint8_t pwdLen); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Get Random Number + * + * Returns a 16 bit random number + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerGetRandomNumber( uint8_t flags, const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Message length + * + * Sends a Read Message Length message to retrieve the value of MB_LEN_Dyn + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[out] msgLen : Message Length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerReadMessageLength( uint8_t flags, const uint8_t* uid, uint8_t* msgLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Message length + * + * Sends a Fast Read Message Length message to retrieve the value of MB_LEN_Dyn using ST Fast mode. + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[out] msgLen : Message Length + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastReadMsgLength( uint8_t flags, const uint8_t* uid, uint8_t* msgLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Read Message + * + * Reads up to 256 bytes in the Mailbox from the location + * specified by MBpointer and sends back their value in the rxBuf response. + * First MailBox location is '00'. When Number of bytes is set to 00h + * and MBPointer is equals to 00h, the MB_LEN bytes of the full message + * are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes + * (i.e. 01h returns 2 bytes, FFh returns 256 bytes). + * An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length. + * RF Reading of the last byte of the mailbox message automatically clears b1 + * of MB_CTRL_Dyn HOST_PUT_MSG, and allows RF to put a new message. + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] mbPointer : MPpointer + * \param[in] numBytes : number of bytes + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerReadMessage( uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Read Message + * + * Reads up to 256 bytes in the Mailbox from the location + * specified by MBpointer and sends back their value in the rxBuf response using ST Fast mode. + * First MailBox location is '00'. When Number of bytes is set to 00h + * and MBPointer is equals to 00h, the MB_LEN bytes of the full message + * are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes + * (i.e. 01h returns 2 bytes, FFh returns 256 bytes). + * An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length. + * RF Reading of the last byte of the mailbox message automatically clears b1 + * of MB_CTRL_Dyn HOST_PUT_MSG, and allows RF to put a new message. + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] mbPointer : MPpointer + * \param[in] numBytes : number of bytes + * \param[out] rxBuf : buffer to store response (also with RES_FLAGS) + * \param[in] rxBufLen : length of rxBuf + * \param[out] rcvLen : number of bytes received + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastReadMessage( uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Write Message + * + * Sends Write message Command + * + * On receiving the Write Message command, the ST25DVxxx puts the data contained + * in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and + * set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful + * in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the + * first location '00'. MSGlength parameter of the command is the number of + * Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data). + * Write Message could be executed only when Mailbox is accessible by RF. + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] msgLen : MSGLen number of Data bytes minus 1 + * \param[in] msgData : Message Data + * \param[out] txBuf : buffer to used to build the Write Message command + * \param[in] txBufLen : length of txBuf + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerWriteMessage( uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ); + +/*! + ***************************************************************************** + * \brief NFC-V Poller Fast Write Message + * + * Sends Fast Write message Command using ST Fast mode + * + * On receiving the Write Message command, the ST25DVxxx puts the data contained + * in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and + * set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful + * in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the + * first location '00'. MSGlength parameter of the command is the number of + * Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data). + * Write Message could be executed only when Mailbox is accessible by RF. + * + * \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option + * for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT + * \param[in] uid : UID of the device to be put to be read + * if not provided Select mode will be used + * \param[in] msgLen : MSGLen number of Data bytes minus 1 + * \param[in] msgData : Message Data + * \param[out] txBuf : buffer to used to build the Write Message command + * \param[in] txBufLen : length of txBuf + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or incorrect mode + * \return RFAL_ERR_PARAM : Invalid parameters + * \return RFAL_ERR_IO : Generic internal error + * \return RFAL_ERR_CRC : CRC error detected + * \return RFAL_ERR_FRAMING : Framing error detected + * \return RFAL_ERR_PROTO : Protocol error detected + * \return RFAL_ERR_TIMEOUT : Timeout error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalST25xVPollerFastWriteMessage( uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ); + +#endif /* RFAL_ST25xV_H */ + +/** + * @} + * + * @} + * + * @} + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t1t.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t1t.h new file mode 100644 index 0000000..c8db83b --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t1t.h @@ -0,0 +1,182 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t1t.h + * + * \author Gustavo Patricio + * + * \brief Provides NFC-A T1T convenience methods and definitions + * + * This module provides an interface to perform as a NFC-A Reader/Writer + * to handle a Type 1 Tag T1T (Topaz) + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup T1T + * \brief RFAL T1T Module + * @{ + * + */ + + +#ifndef RFAL_T1T_H +#define RFAL_T1T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ +#define RFAL_T1T_UID_LEN 4 /*!< T1T UID length of cascade level 1 only tag */ +#define RFAL_T1T_HR_LENGTH 2 /*!< T1T HR(Header ROM) length */ + +#define RFAL_T1T_HR0_NDEF_MASK 0xF0 /*!< T1T HR0 NDEF capability mask T1T 1.2 2.2.2 */ +#define RFAL_T1T_HR0_NDEF_SUPPORT 0x10 /*!< T1T HR0 NDEF capable value T1T 1.2 2.2.2 */ + + +/*! NFC-A T1T (Topaz) command set */ +typedef enum +{ + RFAL_T1T_CMD_RID = 0x78, /*!< T1T Read UID */ + RFAL_T1T_CMD_RALL = 0x00, /*!< T1T Read All */ + RFAL_T1T_CMD_READ = 0x01, /*!< T1T Read */ + RFAL_T1T_CMD_WRITE_E = 0x53, /*!< T1T Write with erase (single byte) */ + RFAL_T1T_CMD_WRITE_NE = 0x1A /*!< T1T Write with no erase (single byte) */ +} rfalT1Tcmds; + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + + +/*! NFC-A T1T (Topaz) RID_RES Digital 1.1 10.6.2 & Table 50 */ +typedef struct +{ + uint8_t hr0; /*!< T1T Header ROM: HR0 */ + uint8_t hr1; /*!< T1T Header ROM: HR1 */ + uint8_t uid[RFAL_T1T_UID_LEN]; /*!< T1T UID */ +} rfalT1TRidRes; + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + + +/*! + ***************************************************************************** + * \brief Initialize NFC-A T1T Poller mode + * + * This methods configures RFAL RF layer to perform as a + * NFC-A T1T Poller/RW (Topaz) including all default timings + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT1TPollerInitialize( void ); + + +/*! + ***************************************************************************** + * \brief NFC-A T1T Poller RID + * + * This method reads the UID of a NFC-A T1T Listener device + * + * + * \param[out] ridRes : pointer to place the RID_RES + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT1TPollerRid( rfalT1TRidRes *ridRes ); + + +/*! + ***************************************************************************** + * \brief NFC-A T1T Poller RALL + * + * This method send a Read All command to a NFC-A T1T Listener device + * + * + * \param[in] uid : the UID of the device to read data + * \param[out] rxBuf : pointer to place the read data + * \param[in] rxBufLen : size of rxBuf + * \param[out] rxRcvdLen : actual received data + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT1TPollerRall( const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxRcvdLen ); + + +/*! + ***************************************************************************** + * \brief NFC-A T1T Poller Write + * + * This method writes the given data on the address of a NFC-A T1T Listener device + * + * + * \param[in] uid : the UID of the device to read data + * \param[in] address : address to write the data + * \param[in] data : the data to be written + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT1TPollerWrite( const uint8_t* uid, uint8_t address, uint8_t data ); + +#endif /* RFAL_T1T_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t2t.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t2t.h new file mode 100644 index 0000000..13c3c80 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t2t.h @@ -0,0 +1,148 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t2t.h + * + * \author Gustavo Patricio + * + * \brief Provides NFC-A T2T convenience methods and definitions + * + * This module provides an interface to perform as a NFC-A Reader/Writer + * to handle a Type 2 Tag T2T + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup T2T + * \brief RFAL T2T Module + * @{ + * + */ + + +#ifndef RFAL_T2T_H +#define RFAL_T2T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_T2T_BLOCK_LEN 4U /*!< T2T block length */ +#define RFAL_T2T_READ_DATA_LEN (4U * RFAL_T2T_BLOCK_LEN) /*!< T2T READ data length */ +#define RFAL_T2T_WRITE_DATA_LEN RFAL_T2T_BLOCK_LEN /*!< T2T WRITE data length */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief NFC-A T2T Poller Read + * + * This method sends a Read command to a NFC-A T2T Listener device + * + * + * \param[in] blockNum : Number of the block to read + * \param[out] rxBuf : pointer to place the read data + * \param[in] rxBufLen : size of rxBuf (RFAL_T2T_READ_DATA_LEN) + * \param[out] rcvLen : actual received data + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT2TPollerRead( uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); + + +/*! + ***************************************************************************** + * \brief NFC-A T2T Poller Write + * + * This method sends a Write command to a NFC-A T2T Listener device + * + * + * \param[in] blockNum : Number of the block to write + * \param[in] wrData : data to be written on the given block + * size must be of RFAL_T2T_WRITE_DATA_LEN + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT2TPollerWrite( uint8_t blockNum, const uint8_t* wrData ); + + +/*! + ***************************************************************************** + * \brief NFC-A T2T Poller Sector Select + * + * This method sends a Sector Select commands to a NFC-A T2T Listener device + * + * \param[in] sectorNum : Sector Number + * + * \return RFAL_ERR_WRONG_STATE : RFAL not initialized or mode not set + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT2TPollerSectorSelect( uint8_t sectorNum ); + +#endif /* RFAL_T2T_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t4t.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t4t.h new file mode 100644 index 0000000..f7c11d1 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_t4t.h @@ -0,0 +1,359 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t4t.h + * + * \author Gustavo Patricio + * + * \brief Provides convenience methods and definitions for T4T (ISO7816-4) + * + * This module provides an interface to exchange T4T APDUs according to + * NFC Forum T4T and ISO7816-4 + * + * This implementation was based on the following specs: + * - ISO/IEC 7816-4 3rd Edition 2013-04-15 + * - NFC Forum T4T Technical Specification 1.0 2017-08-28 + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-AL + * \brief RFAL Abstraction Layer + * @{ + * + * \addtogroup T4T + * \brief RFAL T4T Module + * @{ + * + */ + + +#ifndef RFAL_T4T_H +#define RFAL_T4T_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "rfal_rf.h" +#include "rfal_isoDep.h" + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN 4U /*!< Command-APDU prologue length (CLA INS P1 P2) */ +#define RFAL_T4T_LE_LEN 1U /*!< Le Expected Response Length (short field coding) */ +#define RFAL_T4T_LC_LEN 1U /*!< Lc Data field length (short field coding) */ +#define RFAL_T4T_MAX_RAPDU_SW1SW2_LEN 2U /*!< SW1 SW2 length */ +#define RFAL_T4T_CLA 0x00U /*!< Class byte (contains 00h because secure message are not used) */ + +#define RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME 0x04U /*!< P1 value for Select by name */ +#define RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID 0x00U /*!< P1 value for Select by file identifier */ +#define RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE 0x00U /*!< b2b1 P2 value for First or only occurence */ +#define RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE 0x00U /*!< b4b3 P2 value for Return FCI template */ +#define RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA 0x0CU /*!< b4b3 P2 value for No responce data */ + +#define RFAL_T4T_ISO7816_STATUS_COMPLETE 0x9000U /*!< Command completed \ Normal processing - No further qualification*/ + + +/* +****************************************************************************** +* GLOBAL VARIABLES +****************************************************************************** +*/ + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ +/*! NFC-A T4T Command-APDU structure */ +typedef struct +{ + uint8_t CLA; /*!< Class byte */ + uint8_t INS; /*!< Instruction byte */ + uint8_t P1; /*!< Parameter byte 1 */ + uint8_t P2; /*!< Parameter byte 2 */ + uint8_t Lc; /*!< Data field length */ + bool LcFlag; /*!< Lc flag (append Lc when true) */ + uint8_t Le; /*!< Expected Response Length */ + bool LeFlag; /*!< Le flag (append Le when true) */ + + rfalIsoDepApduBufFormat *cApduBuf; /*!< Command-APDU buffer (Tx) */ + uint16_t *cApduLen; /*!< Command-APDU Length */ +}rfalT4tCApduParam; + +/*! NFC-A T4T Response-APDU structure */ +typedef struct +{ + rfalIsoDepApduBufFormat *rApduBuf; /*!< Response-APDU buffer (Rx) */ + uint16_t rcvdLen; /*!< Full response length */ + uint16_t rApduBodyLen; /*!< Response body length */ + uint16_t statusWord; /*!< R-APDU Status Word SW1|SW2 */ +}rfalT4tRApduParam; + + + +/*! NFC-A T4T command set T4T 1.0 & ISO7816-4 2013 Table 4 */ +typedef enum +{ + RFAL_T4T_INS_SELECT = 0xA4U, /*!< T4T Select */ + RFAL_T4T_INS_READBINARY = 0xB0U, /*!< T4T ReadBinary */ + RFAL_T4T_INS_UPDATEBINARY = 0xD6U, /*!< T4T UpdateBinay */ + RFAL_T4T_INS_READBINARY_ODO = 0xB1U, /*!< T4T ReadBinary using ODO */ + RFAL_T4T_INS_UPDATEBINARY_ODO = 0xD7U /*!< T4T UpdateBinay using ODO */ +} rfalT4tCmds; + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief T4T Compose APDU + * + * This method computes a C-APDU according to NFC Forum T4T and ISO7816-4. + * + * If C-APDU contains data to be sent, it must be placed inside the buffer + * rfalT4tTxRxApduParam.txRx.cApduBuf.apdu and signaled by Lc + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * \see rfalT4TPollerParseRAPDU() + * + * \warning The ISO-DEP module is used to perform the tranceive. Usually + * activation has been done via ISO-DEP activatiavtion. If not + * please call rfalIsoDepInitialize() before. + * + * \param[in,out] apduParam : APDU parameters + * apduParam.cApduLen will contain the APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeCAPDU( const rfalT4tCApduParam *apduParam ); + + +/*! + ***************************************************************************** + * \brief T4T Parse R-APDU + * + * This method parses a R-APDU according to NFC Forum T4T and ISO7816-4. + * It will extract the data length and check if the Satus word is expected. + * + * \param[in,out] apduParam : APDU parameters + * apduParam.rApduBodyLen will contain the data length + * apduParam.statusWord will contain the SW1 and SW2 + * + * \return RFAL_ERR_REQUEST : Status word (SW1 SW2) different from 9000 + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerParseRAPDU( rfalT4tRApduParam *apduParam ); + +/*! + ***************************************************************************** + * \brief T4T Compose Select Application APDU + * + * This method computes a Select Application APDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] aid : Application ID to be used + * \param[in] aidLen : Application ID length + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeSelectAppl( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* aid, uint8_t aidLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Select File APDU + * + * This method computes a Select File APDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] fid : File ID to be used + * \param[in] fidLen : File ID length + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeSelectFile( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Select File APDU for Mapping Version 1 + * + * This method computes a Select File APDU according to NFC Forum T4TOP_v1.0 + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] fid : File ID to be used + * \param[in] fidLen : File ID length + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeSelectFileV1Mapping( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Read Data APDU + * + * This method computes a Read Data APDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] offset : File offset + * \param[in] expLen : Expected length (Le) + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeReadData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, uint8_t expLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Read Data ODO APDU + * + * This method computes a Read Data ODO APDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] offset : File offset + * \param[in] expLen : Expected length (Le) + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeReadDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, uint8_t expLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Write Data APDU + * + * This method computes a Write Data APDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] offset : File offset + * \param[in] data : Data to be written + * \param[in] dataLen : Data length to be written (Lc) + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeWriteData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen ); + +/*! + ***************************************************************************** + * \brief T4T Compose Write Data ODO APDU + * + * This method computes a Write Data ODO sAPDU according to NFC Forum T4T + * + * To transceive the formed APDU the ISO-DEP layer shall be used + * + * \see rfalIsoDepStartApduTransceive() + * \see rfalIsoDepGetApduTransceiveStatus() + * + * \param[out] cApduBuf : buffer where the C-APDU will be placed + * \param[in] offset : File offset + * \param[in] data : Data to be written + * \param[in] dataLen : Data length to be written (Lc) + * \param[out] cApduLen : Composed C-APDU length + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_PROTO : Protocol error + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode rfalT4TPollerComposeWriteDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen ); + +#endif /* RFAL_T4T_H */ + +/** + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_utils.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_utils.h new file mode 100644 index 0000000..2f13946 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/include/rfal_utils.h @@ -0,0 +1,176 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_utils.h + * + * \author Gustavo Patricio + * + * \brief RF Abstraction Layer (RFAL) Utils + * + * \addtogroup RFAL + * @{ + * + */ + +#ifndef RFAL_UTILS_H +#define RFAL_UTILS_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include +#include + + +/* +****************************************************************************** +* GLOBAL DATA TYPES +****************************************************************************** +*/ + +typedef uint16_t ReturnCode; /*!< Standard Return Code type from function. */ + +/* +****************************************************************************** +* DEFINES +****************************************************************************** +*/ + +/* + * Error codes to be used within the application. + * They are represented by an uint8_t + */ + +#define RFAL_ERR_NONE ((ReturnCode)0U) /*!< no error occurred */ +#define RFAL_ERR_NOMEM ((ReturnCode)1U) /*!< not enough memory to perform the requested operation */ +#define RFAL_ERR_BUSY ((ReturnCode)2U) /*!< device or resource busy */ +#define RFAL_ERR_IO ((ReturnCode)3U) /*!< generic IO error */ +#define RFAL_ERR_TIMEOUT ((ReturnCode)4U) /*!< error due to timeout */ +#define RFAL_ERR_REQUEST ((ReturnCode)5U) /*!< invalid request or requested function can't be executed at the moment */ +#define RFAL_ERR_NOMSG ((ReturnCode)6U) /*!< No message of desired type */ +#define RFAL_ERR_PARAM ((ReturnCode)7U) /*!< Parameter error */ +#define RFAL_ERR_SYSTEM ((ReturnCode)8U) /*!< System error */ +#define RFAL_ERR_FRAMING ((ReturnCode)9U) /*!< Framing error */ +#define RFAL_ERR_OVERRUN ((ReturnCode)10U) /*!< lost one or more received bytes */ +#define RFAL_ERR_PROTO ((ReturnCode)11U) /*!< protocol error */ +#define RFAL_ERR_INTERNAL ((ReturnCode)12U) /*!< Internal Error */ +#define RFAL_ERR_AGAIN ((ReturnCode)13U) /*!< Call again */ +#define RFAL_ERR_MEM_CORRUPT ((ReturnCode)14U) /*!< memory corruption */ +#define RFAL_ERR_NOT_IMPLEMENTED ((ReturnCode)15U) /*!< not implemented */ +#define RFAL_ERR_PC_CORRUPT ((ReturnCode)16U) /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */ +#define RFAL_ERR_SEND ((ReturnCode)17U) /*!< error sending*/ +#define RFAL_ERR_IGNORE ((ReturnCode)18U) /*!< indicates error detected but to be ignored */ +#define RFAL_ERR_SEMANTIC ((ReturnCode)19U) /*!< indicates error in state machine (unexpected cmd) */ +#define RFAL_ERR_SYNTAX ((ReturnCode)20U) /*!< indicates error in state machine (unknown cmd) */ +#define RFAL_ERR_CRC ((ReturnCode)21U) /*!< crc error */ +#define RFAL_ERR_NOTFOUND ((ReturnCode)22U) /*!< transponder not found */ +#define RFAL_ERR_NOTUNIQUE ((ReturnCode)23U) /*!< transponder not unique - more than one transponder in field */ +#define RFAL_ERR_NOTSUPP ((ReturnCode)24U) /*!< requested operation not supported */ +#define RFAL_ERR_WRITE ((ReturnCode)25U) /*!< write error */ +#define RFAL_ERR_FIFO ((ReturnCode)26U) /*!< fifo over or underflow error */ +#define RFAL_ERR_PAR ((ReturnCode)27U) /*!< parity error */ +#define RFAL_ERR_DONE ((ReturnCode)28U) /*!< transfer has already finished */ +#define RFAL_ERR_RF_COLLISION ((ReturnCode)29U) /*!< collision error (Bit Collision or during RF Collision avoidance ) */ +#define RFAL_ERR_HW_OVERRUN ((ReturnCode)30U) /*!< lost one or more received bytes */ +#define RFAL_ERR_RELEASE_REQ ((ReturnCode)31U) /*!< device requested release */ +#define RFAL_ERR_SLEEP_REQ ((ReturnCode)32U) /*!< device requested sleep */ +#define RFAL_ERR_WRONG_STATE ((ReturnCode)33U) /*!< incorrent state for requested operation */ +#define RFAL_ERR_MAX_RERUNS ((ReturnCode)34U) /*!< blocking procedure reached maximum runs */ +#define RFAL_ERR_DISABLED ((ReturnCode)35U) /*!< operation aborted due to disabled configuration */ +#define RFAL_ERR_HW_MISMATCH ((ReturnCode)36U) /*!< expected hw do not match */ +#define RFAL_ERR_LINK_LOSS ((ReturnCode)37U) /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */ +#define RFAL_ERR_INVALID_HANDLE ((ReturnCode)38U) /*!< invalid or not initialized device handle */ + +#define RFAL_ERR_INCOMPLETE_BYTE ((ReturnCode)40U) /*!< Incomplete byte rcvd */ +#define RFAL_ERR_INCOMPLETE_BYTE_01 ((ReturnCode)41U) /*!< Incomplete byte rcvd - 1 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_02 ((ReturnCode)42U) /*!< Incomplete byte rcvd - 2 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_03 ((ReturnCode)43U) /*!< Incomplete byte rcvd - 3 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_04 ((ReturnCode)44U) /*!< Incomplete byte rcvd - 4 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_05 ((ReturnCode)45U) /*!< Incomplete byte rcvd - 5 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_06 ((ReturnCode)46U) /*!< Incomplete byte rcvd - 6 bit */ +#define RFAL_ERR_INCOMPLETE_BYTE_07 ((ReturnCode)47U) /*!< Incomplete byte rcvd - 7 bit */ + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ +/*! Common code to exit a function with the error if function f return error */ +#define RFAL_EXIT_ON_ERR(r, f) \ + (r) = (f); \ + if (RFAL_ERR_NONE != (r)) \ + { \ + return (r); \ + } + + +/*! Common code to exit a function if process/function f has not concluded */ +#define RFAL_EXIT_ON_BUSY(r, f) \ + (r) = (f); \ + if (RFAL_ERR_BUSY == (r)) \ + { \ + return (r); \ + } + +#define RFAL_SIZEOF_ARRAY(a) (sizeof(a) / sizeof((a)[0])) /*!< Compute the size of an array */ +#define RFAL_MAX(a, b) (((a) > (b)) ? (a) : (b)) /*!< Return the maximum of the 2 values */ +#define RFAL_MIN(a, b) (((a) < (b)) ? (a) : (b)) /*!< Return the minimum of the 2 values */ +#define RFAL_GETU16(a) (((uint16_t)(a)[0] << 8) | (uint16_t)(a)[1])/*!< Cast two Big Endian 8-bits byte array to 16-bits unsigned */ +#define RFAL_GETU32(a) (((uint32_t)(a)[0] << 24) | ((uint32_t)(a)[1] << 16) | ((uint32_t)(a)[2] << 8) | ((uint32_t)(a)[3])) /*!< Cast four Big Endian 8-bit byte array to 32-bit unsigned */ + + +#ifdef __CSMC__ +/* STM8 COSMIC */ +#define RFAL_MEMMOVE(s1,s2,n) memmove(s1,s2,n) /* PRQA S 5003 # CERT C 9 - string.h from Cosmic only provides functions with low qualified parameters */ /*!< map memmove to string library code */ +static inline void * RFAL_MEMCPY(void *s1, const void *s2, uint32_t n) { return memcpy(s1,s2,(uint16_t)n); } /* PRQA S 0431 # MISRA 1.1 - string.h from Cosmic only provides functions with low qualified parameters */ +#define RFAL_MEMSET(s1,c,n) memset(s1,(char)(c),n) /*!< map memset to string library code */ +static inline int32_t RFAL_BYTECMP(void *s1, const void *s2, uint32_t n) { return (int32_t)memcmp(s1,s2,(uint16_t)n); } /* PRQA S 0431 # MISRA 1.1 - string.h from Cosmic only provides functions with low qualified parameters */ + +#else /* __CSMC__ */ + +#define RFAL_MEMMOVE memmove /*!< map memmove to string library code */ +#define RFAL_MEMCPY memcpy /*!< map memcpy to string library code */ +#define RFAL_MEMSET memset /*!< map memset to string library code */ +#define RFAL_BYTECMP memcmp /*!< map bytecmp to string library code */ +#endif /* __CSMC__ */ + +#define RFAL_NO_WARNING(v) ((void) (v)) /*!< Macro to suppress compiler warning */ + + +#ifndef NULL + #define NULL (void*)0 /*!< represents a NULL pointer */ +#endif /* !NULL */ + + + +#endif /* RFAL_UTILS_H */ + + +/** + * @} + * + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/rfal_platform.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/rfal_platform.h new file mode 100644 index 0000000..8dde088 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/rfal_platform.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + + +//Probably unneeded +////#include "spi.h" +////#include "timer.h" +////#include "main.h" +////#include "logger.h" +//// +////#define ST25R_SS_PIN SPI1_CS_Pin /*!< GPIO pin used for ST25R SPI SS */ +////#define ST25R_SS_PORT SPI1_CS_GPIO_Port /*!< GPIO port used for ST25R SPI SS port */ +//// +#define ST25R_INT_PIN 34 /*!< GPIO pin used for ST25R External Interrupt */ +////#define ST25R_INT_PORT ST25R_IRQ_GPIO_Port /*!< GPIO port used for ST25R External Interrupt */ +//// +////#ifdef LED_FIELD_Pin +////#define PLATFORM_LED_FIELD_PIN LED_FIELD_Pin /*!< GPIO pin used as field LED */ +////#endif +//// +////#ifdef LED_FIELD_GPIO_Port +////#define PLATFORM_LED_FIELD_PORT LED_FIELD_GPIO_Port /*!< GPIO port used as field LED */ +////#endif +//// +//// +////#define PLATFORM_LED_A_PIN LED_A_Pin /*!< GPIO pin used for LED A */ +////#define PLATFORM_LED_A_PORT LED_A_GPIO_Port /*!< GPIO port used for LED A */ +////#define PLATFORM_LED_B_PIN LED_B_Pin /*!< GPIO pin used for LED B */ +////#define PLATFORM_LED_B_PORT LED_B_GPIO_Port /*!< GPIO port used for LED B */ +////#define PLATFORM_LED_F_PIN LED_F_Pin /*!< GPIO pin used for LED F */ +////#define PLATFORM_LED_F_PORT LED_F_GPIO_Port /*!< GPIO port used for LED F */ +////#define PLATFORM_LED_V_PIN LED_V_Pin /*!< GPIO pin used for LED V */ +////#define PLATFORM_LED_V_PORT LED_V_GPIO_Port /*!< GPIO port used for LED V */ +////#define PLATFORM_LED_AP2P_PIN LED_AP2P_Pin /*!< GPIO pin used for LED AP2P */ +////#define PLATFORM_LED_AP2P_PORT LED_AP2P_GPIO_Port /*!< GPIO port used for LED AP2P*/ +//// +////#define PLATFORM_USER_BUTTON_PIN B1_Pin /*!< GPIO pin user button */ +////#define PLATFORM_USER_BUTTON_PORT B1_GPIO_Port /*!< GPIO port user button */ +//// + +#define platformProtectST25RComm() if (global_st25r3911b->spi_semaphore != NULL) xSemaphoreTake(global_st25r3911b->spi_semaphore, portMAX_DELAY);/*!< Protect unique access to ST25R communication channel - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */ +#define platformUnprotectST25RComm() if (global_st25r3911b->spi_semaphore != NULL) xSemaphoreGive(global_st25r3911b->spi_semaphore);/*!< Unprotect unique access to ST25R communication channel - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */ + +//#define platformProtectST25RIrqStatus() platformProtectST25RComm() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */ +//#define platformUnprotectST25RIrqStatus() platformUnprotectST25RComm() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */ +// +//#define platformProtectWorker() /* Protect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */ +//#define platformUnprotectWorker() /* Unprotect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */ +// +#define platformIrqST25RSetCallback( cb ) global_st25r3911b->irq_callback = cb +#define platformIrqST25RPinInitialize() + +//#define platformIrqST25RSetCallback( cb ) +//#define platformIrqST25RPinInitialize() +// +// +//#define platformLedsInitialize() /*!< Initializes the pins used as LEDs to outputs*/ +// +//#define platformLedOff( port, pin ) platformGpioClear((port), (pin)) /*!< Turns the given LED Off */ +//#define platformLedOn( port, pin ) platformGpioSet((port), (pin)) /*!< Turns the given LED On */ +//#define platformLedToggle( port, pin ) platformGpioToggle((port), (pin)) /*!< Toggle the given LED */ +// +//#define platformGpioSet( port, pin ) HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET) /*!< Turns the given GPIO High */ +//#define platformGpioClear( port, pin ) HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET) /*!< Turns the given GPIO Low */ +//#define platformGpioToggle( port, pin ) HAL_GPIO_TogglePin(port, pin) /*!< Toggles the given GPIO */ +#define platformGpioIsHigh( port, pin ) (gpio_get_level(pin) == true) /*!< Checks if the given LED is High */ +#define platformGpioIsLow( port, pin ) (!platformGpioIsHigh(port, pin)) /*!< Checks if the given LED is Low */ +// + +#define platformTimerCreate( t ) (xTaskGetTickCount() + pdMS_TO_TICKS(t)) /*!< Create a timer with the given time (ms) */ +#define platformTimerIsExpired( timer ) (xTaskGetTickCount() > timer) /*!< Checks if the given timer is expired */ +#define platformTimerDestroy( timer ) /*!< Stop and release the given timer */ +#define platformDelay( t ) vTaskDelay( pdMS_TO_TICKS(t) ) /*!< Performs a delay for the given time (ms) */ + +#define platformGetSysTick() /*!< Get System Tick ( 1 tick = 1 ms) */ + +//#define platformErrorHandle() _Error_Handler(__FILE__,__LINE__) /*!< Global error handler or trap */ +// +#define platformSpiSelect() gpio_set_level(global_st25r3911b->pin_cs, false) /*!< SPI SS\CS: Chip|Slave Select */ +#define platformSpiDeselect() gpio_set_level(global_st25r3911b->pin_cs, true) /*!< SPI SS\CS: Chip|Slave Deselect */ +#define platformSpiTxRx( txBuf, rxBuf, len ) st25r3911b_rxtx(global_st25r3911b, txBuf, rxBuf, len) /*!< SPI transceive */ +// +//#define platformLog(...) ESP_LOGI("nfc", __VA_ARGS__) /*!< Log method */ + +//extern uint8_t globalCommProtectCnt; /* Global Protection Counter provided per platform - instantiated in main.c */ + + +#define RFAL_FEATURE_LISTEN_MODE false /*!< Enable/Disable RFAL support for Listen Mode */ +#define RFAL_FEATURE_WAKEUP_MODE true /*!< Enable/Disable RFAL support for the Wake-Up mode */ +#define RFAL_FEATURE_LOWPOWER_MODE false /*!< Enable/Disable RFAL support for the Low Power mode */ +#define RFAL_FEATURE_NFCA true /*!< Enable/Disable RFAL support for NFC-A (ISO14443A) */ +#define RFAL_FEATURE_NFCB false /*!< Enable/Disable RFAL support for NFC-B (ISO14443B) */ +#define RFAL_FEATURE_NFCF false /*!< Enable/Disable RFAL support for NFC-F (FeliCa) */ +#define RFAL_FEATURE_NFCV false /*!< Enable/Disable RFAL support for NFC-V (ISO15693) */ +#define RFAL_FEATURE_T1T false /*!< Enable/Disable RFAL support for T1T (Topaz) */ +#define RFAL_FEATURE_T2T false /*!< Enable/Disable RFAL support for T2T */ +#define RFAL_FEATURE_T4T false /*!< Enable/Disable RFAL support for T4T */ +#define RFAL_FEATURE_ST25TB false /*!< Enable/Disable RFAL support for ST25TB */ +#define RFAL_FEATURE_ST25xV false /*!< Enable/Disable RFAL support for ST25TV/ST25DV */ +#define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG false /*!< Enable/Disable Analog Configs to be dynamically updated (RAM) */ +#define RFAL_FEATURE_DPO false /*!< Enable/Disable RFAL Dynamic Power Output support */ +#define RFAL_FEATURE_ISO_DEP true /*!< Enable/Disable RFAL support for ISO-DEP (ISO14443-4) */ +#define RFAL_FEATURE_ISO_DEP_POLL true /*!< Enable/Disable RFAL support for Poller mode (PCD) ISO-DEP (ISO14443-4) */ +#define RFAL_FEATURE_ISO_DEP_LISTEN false /*!< Enable/Disable RFAL support for Listen mode (PICC) ISO-DEP (ISO14443-4) */ +#define RFAL_FEATURE_NFC_DEP true /*!< Enable/Disable RFAL support for NFC-DEP (NFCIP1/P2P) */ + +#define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN 256U /*!< ISO-DEP I-Block max length. Please use values as defined by rfalIsoDepFSx */ +#define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN 254U /*!< NFC-DEP Block/Payload length. Allowed values: 64, 128, 192, 254 */ +#define RFAL_FEATURE_NFC_RF_BUF_LEN 258U /*!< RF buffer length used by RFAL NFC layer */ + +#define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN 512U /*!< ISO-DEP APDU max length. Please use multiples of I-Block max length */ +#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 512U /*!< NFC-DEP PDU max length. */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_analogConfig.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_analogConfig.c new file mode 100644 index 0000000..599c1a7 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_analogConfig.c @@ -0,0 +1,488 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_analogConfig.c + * + * \author bkam + * + * \brief Funcitons to manage and set analog settings. + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_analogConfig.h" +#include "rfal_chip.h" +#include "rfal_utils.h" +#include "rfal_platform.h" + + + + +/* Check whether the Default Analog settings are to be used or custom ones */ +#ifdef RFAL_ANALOG_CONFIG_CUSTOM + extern const uint8_t rfalAnalogConfigCustomSettings[]; + extern const uint16_t rfalAnalogConfigCustomSettingsLength; +#else + #include "rfal_analogConfigTbl.h" +#endif + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ + + +#define RFAL_TEST_REG 0x0080U /*!< Test Register indicator */ + +/* + ****************************************************************************** + * MACROS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL DATA TYPES + ****************************************************************************** + */ + +#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + static uint8_t gRfalAnalogConfig[RFAL_ANALOG_CONFIG_TBL_SIZE]; /*!< Analog Configuration Settings List */ +#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ + + +/*! Struct for Analog Config Look Up Table Update */ +typedef struct { + const uint8_t *currentAnalogConfigTbl; /*!< Reference to start of current Analog Configuration */ + uint16_t configTblSize; /*!< Total size of Analog Configuration */ + bool ready; /*!< Indicate if Look Up Table is complete and ready for use */ +} rfalAnalogConfigMgmt; + +static rfalAnalogConfigMgmt gRfalAnalogConfigMgmt; /*!< Analog Configuration LUT management */ + +/* + ****************************************************************************** + * LOCAL TABLES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static rfalAnalogConfigNum rfalAnalogConfigSearch( rfalAnalogConfigId configId, uint16_t *configOffset ); + +#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + static void rfalAnalogConfigPtrUpdate( const uint8_t* analogConfigTbl ); +#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ + +/* + ****************************************************************************** + * GLOBAL VARIABLE DEFINITIONS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*******************************************************************************/ +void rfalAnalogConfigInitialize( void ) +{ + /* Use default Analog configuration settings in Flash by default. */ + +/* Check whether the Default Analog settings are to be used or custom ones */ +#ifdef RFAL_ANALOG_CONFIG_CUSTOM + gRfalAnalogConfigMgmt.currentAnalogConfigTbl = rfalAnalogConfigCustomSettings; + gRfalAnalogConfigMgmt.configTblSize = rfalAnalogConfigCustomSettingsLength; +#else + gRfalAnalogConfigMgmt.currentAnalogConfigTbl = rfalAnalogConfigDefaultSettings; + gRfalAnalogConfigMgmt.configTblSize = sizeof(rfalAnalogConfigDefaultSettings); +#endif + + gRfalAnalogConfigMgmt.ready = true; +} + + +/*******************************************************************************/ +bool rfalAnalogConfigIsReady( void ) +{ + return gRfalAnalogConfigMgmt.ready; +} + + +/*******************************************************************************/ +ReturnCode rfalAnalogConfigListWriteRaw( const uint8_t *configTbl, uint16_t configTblSize ) +{ +#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + + /* Check if the Configuration Table exceed the Table size */ + if ( configTblSize >= RFAL_ANALOG_CONFIG_TBL_SIZE ) + { + return RFAL_ERR_NOMEM; + } + + /* Check for invalid parameters */ + if( (configTbl == NULL) || (configTblSize == 0U) ) + { + return RFAL_ERR_PARAM; + } + + /* NOTE: On this API (rfalAnalogConfigListWriteRaw) the current AC Table is not reset upon error, as on rfalAnalogConfigListWrite. */ + /* On rfalAnalogConfigListWrite the AC table is written in mutiple chunks of data which may lead to an invalid|incomplte AC */ + /* table if an error arises, where here the whole AC Table is written all together. */ + + /* NOTE: Function does not check for the validity of the Table contents (conf IDs, conf sets, register address) */ + RFAL_MEMCPY( gRfalAnalogConfig, configTbl, configTblSize ); + + /* Update the total size of configuration settings */ + gRfalAnalogConfigMgmt.configTblSize = configTblSize; + + rfalAnalogConfigPtrUpdate(gRfalAnalogConfig); + return RFAL_ERR_NONE; + +#else + + // If Analog Configuration Update is to be disabled + RFAL_NO_WARNING(configTbl); + RFAL_NO_WARNING(configTblSize); + return RFAL_ERR_REQUEST; + +#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ +} + + +/*******************************************************************************/ +ReturnCode rfalAnalogConfigListWrite( uint8_t more, const rfalAnalogConfig *config ) +{ +#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + + rfalAnalogConfigId configId; + rfalAnalogConfigNum numConfig; + uint8_t configSize; + + if( true == gRfalAnalogConfigMgmt.ready ) + { /* First Update to the Configuration list. */ + gRfalAnalogConfigMgmt.ready = false; // invalidate the config List + gRfalAnalogConfigMgmt.configTblSize = 0; // Clear the config List + } + + configId = RFAL_GETU16(config->id); + + /* Check validity of the Configuration ID. */ + /* NOTE: Direction DPO uses 2msb of the Technology field as level indicator */ + if( ((RFAL_ANALOG_CONFIG_TECH_RFU <= RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) && ((RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId) != RFAL_ANALOG_CONFIG_DPO) && (RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId) != RFAL_ANALOG_CONFIG_DLMA)) ) + ||((RFAL_ANALOG_CONFIG_BITRATE_6780 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId)) && (RFAL_ANALOG_CONFIG_BITRATE_211p88 > RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) + ||(RFAL_ANALOG_CONFIG_BITRATE_1p6 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId)) + ) + { + rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */ + return RFAL_ERR_PARAM; + } + + numConfig = config->num; + configSize = (uint8_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (numConfig * sizeof(rfalAnalogConfigRegAddrMaskVal))); + + /* Check if the Configuration Set exceed the Table size. */ + if( RFAL_ANALOG_CONFIG_TBL_SIZE <= (gRfalAnalogConfigMgmt.configTblSize + configSize) ) + { + rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */ + return RFAL_ERR_NOMEM; + } + + /* NOTE: Function does not check for the validity of the Register Address. */ + RFAL_MEMCPY(&gRfalAnalogConfig[gRfalAnalogConfigMgmt.configTblSize], (const uint8_t*)config, configSize); + + /* Increment the total size of configuration settings. */ + gRfalAnalogConfigMgmt.configTblSize += configSize; + + /* Check if it is the last Analog Configuration to load. */ + if( RFAL_ANALOG_CONFIG_UPDATE_LAST == more ) + { /* Update the Analog Configuration to the new settings. */ + rfalAnalogConfigPtrUpdate(gRfalAnalogConfig); + } + + return RFAL_ERR_NONE; + +#else + + // If Analog Configuration Update is to be disabled + RFAL_NO_WARNING(config); + RFAL_NO_WARNING(more); + return RFAL_ERR_DISABLED; + +#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ + +} + + +/*******************************************************************************/ +ReturnCode rfalAnalogConfigListReadRaw( uint8_t *tblBuf, uint16_t tblBufLen, uint16_t *configTblSize ) +{ + /* Check if the the current table will fit into the given buffer */ + if( tblBufLen < gRfalAnalogConfigMgmt.configTblSize ) + { + return RFAL_ERR_NOMEM; + } + + /* Check for invalid parameters */ + if( (configTblSize == NULL) || (tblBuf == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Copy the whole Table to the given buffer */ + if( gRfalAnalogConfigMgmt.configTblSize > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( tblBuf, gRfalAnalogConfigMgmt.currentAnalogConfigTbl, gRfalAnalogConfigMgmt.configTblSize ); + } + *configTblSize = gRfalAnalogConfigMgmt.configTblSize; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalAnalogConfigListRead( rfalAnalogConfigOffset *configOffset, uint8_t *more, rfalAnalogConfig *config, rfalAnalogConfigNum numConfig ) +{ + uint16_t configSize; + const rfalAnalogConfigOffset offset = *configOffset; + rfalAnalogConfigNum numConfigSet; + + /* Check if the number of register-mask-value settings for the respective Configuration ID will fit into the buffer passed in. */ + if( gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)] > numConfig ) + { + return RFAL_ERR_NOMEM; + } + + /* Get the number of Configuration set */ + numConfigSet = gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)]; + + /* Pass Configuration Register-Mask-Value sets */ + configSize = (sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal))); + RFAL_MEMCPY( (uint8_t*) config + , &gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset] + , configSize + ); + *configOffset = offset + configSize; + + /* Check if it is the last Analog Configuration in the Table.*/ + *more = (uint8_t)((*configOffset >= gRfalAnalogConfigMgmt.configTblSize) ? RFAL_ANALOG_CONFIG_UPDATE_LAST + : RFAL_ANALOG_CONFIG_UPDATE_MORE); + + return RFAL_ERR_NONE; + +} + + +/*******************************************************************************/ +ReturnCode rfalSetAnalogConfig( rfalAnalogConfigId configId ) +{ + rfalAnalogConfigOffset configOffset = 0; + rfalAnalogConfigNum numConfigSet; + const rfalAnalogConfigRegAddrMaskVal *configTbl; + ReturnCode retCode = RFAL_ERR_NONE; + rfalAnalogConfigNum i; + + if( true != gRfalAnalogConfigMgmt.ready ) + { + return RFAL_ERR_REQUEST; + } + + /* Search LUT for the specific Configuration ID */ + while( true ) + { + numConfigSet = rfalAnalogConfigSearch(configId, &configOffset); + if( RFAL_ANALOG_CONFIG_LUT_NOT_FOUND == numConfigSet ) + { + break; + } + + configTbl = (rfalAnalogConfigRegAddrMaskVal *)( (uintptr_t)gRfalAnalogConfigMgmt.currentAnalogConfigTbl + (uint32_t)configOffset); + /* Increment the offset to the next index to search from */ + configOffset += (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal)); + + if ((gRfalAnalogConfigMgmt.configTblSize + 1U) < configOffset) + { /* Error check make sure that the we do not access outside the configuration Table Size */ + return RFAL_ERR_NOMEM; + } + + for ( i = 0; i < numConfigSet; i++) + { + if( (RFAL_GETU16(configTbl[i].addr) & RFAL_TEST_REG) != 0U ) + { + RFAL_EXIT_ON_ERR(retCode, rfalChipChangeTestRegBits( (RFAL_GETU16(configTbl[i].addr) & ~RFAL_TEST_REG), configTbl[i].mask, configTbl[i].val) ); + } + else + { + RFAL_EXIT_ON_ERR(retCode, rfalChipChangeRegBits( RFAL_GETU16(configTbl[i].addr), configTbl[i].mask, configTbl[i].val) ); + } + } + + } /* while(found Analog Config Id) */ + + return retCode; +} + + +/*******************************************************************************/ +uint16_t rfalAnalogConfigGenModeID( rfalMode md, rfalBitRate br, uint16_t dir ) +{ + uint16_t id; + + /* Assign Poll/Listen Mode */ + id = ((md >= RFAL_MODE_LISTEN_NFCA) ? RFAL_ANALOG_CONFIG_LISTEN : RFAL_ANALOG_CONFIG_POLL); + + /* Assign Technology */ + switch( md ) + { + case RFAL_MODE_POLL_NFCA: + case RFAL_MODE_POLL_NFCA_T1T: + case RFAL_MODE_LISTEN_NFCA: + id |= RFAL_ANALOG_CONFIG_TECH_NFCA; + break; + + case RFAL_MODE_POLL_NFCB: + case RFAL_MODE_POLL_B_PRIME: + case RFAL_MODE_POLL_B_CTS: + case RFAL_MODE_LISTEN_NFCB: + id |= RFAL_ANALOG_CONFIG_TECH_NFCB; + break; + + case RFAL_MODE_POLL_NFCF: + case RFAL_MODE_LISTEN_NFCF: + id |= RFAL_ANALOG_CONFIG_TECH_NFCF; + break; + + case RFAL_MODE_POLL_NFCV: + case RFAL_MODE_POLL_PICOPASS: + id |= RFAL_ANALOG_CONFIG_TECH_NFCV; + break; + + case RFAL_MODE_POLL_ACTIVE_P2P: + case RFAL_MODE_LISTEN_ACTIVE_P2P: + id |= RFAL_ANALOG_CONFIG_TECH_AP2P; + break; + + default: + id = RFAL_ANALOG_CONFIG_TECH_CHIP; + break; + } + + /* Assign Bitrate */ + id |= (((((uint16_t)(br) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(br) : ((uint16_t)(br)+1U)) << RFAL_ANALOG_CONFIG_BITRATE_SHIFT) & RFAL_ANALOG_CONFIG_BITRATE_MASK); + + /* Assign Direction */ + id |= ((dir<detType = RFAL_CD_SINGLE_MULTI_TECH; + gCd.st = RFAL_CD_ST_NOT_DETECTED;/* Single device was another technology and now NFC-A */ + break; + } + + gCd.st = RFAL_CD_ST_NFCA_COLRES_START; /* NFC-A detected perform collision resolution */ + break; + } + + gCd.st = RFAL_CD_ST_NFCB_INIT; /* NFC-A not detected, move to NFC-B */ + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCA_COLRES_START: + + err = rfalNfcaPollerStartFullCollisionResolution( RFAL_COMPLIANCE_MODE_ISO, 0, &gCd.nfcaDev, &gCd.devCnt ); + if( err != RFAL_ERR_NONE ) + { + gCd.lastErr = err; + gCd.st = RFAL_CD_ST_ERROR; /* Collision resolution could not be performed */ + break; + } + + gCd.st = RFAL_CD_ST_NFCA_COLRES; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCA_COLRES: + + err = rfalNfcaPollerGetFullCollisionResolutionStatus(); + if( err != RFAL_ERR_BUSY ) + { + if( (err == RFAL_ERR_NONE) && (gCd.devCnt == 1U) ) /* Collision resolution OK and a single card was found */ + { + gCd.mulDevCnt++; + gCd.techFound = RFAL_CD_TECH_NFCA; + } + + /* Check if multiple cards or technologies have already been identified */ + if( (err != RFAL_ERR_NONE) || (gCd.devCnt > 1U) || (gCd.mulDevCnt > 1U) ) + { + gCd.res->detType = RFAL_CD_MULTIPLE_DEV; /* Report multiple devices. A T1T will also fail at ColRes */ + gCd.st = RFAL_CD_ST_DETECTED; + + break; + } + + gCd.st = RFAL_CD_ST_NFCB_INIT; /* Move to NFC-B */ + } + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCB_INIT: + + /* Verify if we are performing multi technology check */ + if( (gCd.skipTechFound) && (gCd.techFound == RFAL_CD_TECH_NFCB) ) + { + gCd.st = RFAL_CD_ST_NFCF_INIT; /* If single card card found before was NFC-B skip tech now */ + break; + } + + rfalNfcbPollerInitialize(); /* Initialize for NFC-B */ + rfalFieldOnAndStartGT(); /* Turns the Field On if not already and start GT timer */ + + gCd.st = RFAL_CD_ST_NFCB_TECHDET; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCB_TECHDET: + + if( !rfalIsGTExpired() ) + { + break; /* Wait until GT has been fulfilled */ + } + + err = rfalNfcbPollerTechnologyDetection( RFAL_COMPLIANCE_MODE_NFC, &sensbRes, &gCd.devCnt ); + if( err == RFAL_ERR_NONE ) + { + /* Verify if we are performing multi technology check OR already found one on the first round */ + if( gCd.skipTechFound ) + { + gCd.res->detType = RFAL_CD_SINGLE_MULTI_TECH; + gCd.st = RFAL_CD_ST_NOT_DETECTED;/* Single device was another technology and now NFC-B */ + break; + } + else if( gCd.techFound != RFAL_CD_TECH_NONE ) /* If on the first round check if other Tech was already found */ + { + gCd.res->detType = RFAL_CD_MULTIPLE_TECH; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + gCd.st = RFAL_CD_ST_NFCB_COLRES_START; /* NFC-B detected perform collision resolution */ + break; + } + + gCd.st = RFAL_CD_ST_NFCF_INIT; /* NFC-B not detected, move to NFC-B */ + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCB_COLRES_START: + + err = rfalNfcbPollerStartCollisionResolution( RFAL_COMPLIANCE_MODE_NFC, 0, &gCd.nfcbDev, &gCd.devCnt ); + if( err != RFAL_ERR_NONE ) + { + gCd.lastErr = err; + gCd.st = RFAL_CD_ST_ERROR; /* Collision resolution could not be performed */ + break; + } + + gCd.st = RFAL_CD_ST_NFCB_COLRES; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCB_COLRES: + + err = rfalNfcbPollerGetCollisionResolutionStatus(); + if( err != RFAL_ERR_BUSY ) + { + if( (err == RFAL_ERR_NONE) && (gCd.devCnt == 1U) ) /* Collision resolution OK and a single card was found */ + { + gCd.mulDevCnt++; + gCd.techFound = RFAL_CD_TECH_NFCB; + } + + /* Check if multiple cards or technologies have already been identified */ + if( (err != RFAL_ERR_NONE) || (gCd.devCnt > 1U) || (gCd.mulDevCnt > 1U) ) + { + gCd.res->detType = RFAL_CD_MULTIPLE_DEV; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.st = RFAL_CD_ST_NFCF_INIT; /* Move to NFC-F */ + } + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCF_INIT: + + /* Verify if we are performing multi technology check */ + if( (gCd.skipTechFound) && (gCd.techFound == RFAL_CD_TECH_NFCF) ) + { + gCd.st = RFAL_CD_ST_PROPRIETARY; /* If single card card found before was NFC-F skip tech now */ + break; + } + + rfalNfcfPollerInitialize(RFAL_BR_212); /* Initialize for NFC-F */ + rfalFieldOnAndStartGT(); /* Turns the Field On if not already and start GT timer */ + + gCd.st = RFAL_CD_ST_NFCF_TECHDET_START; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCF_TECHDET_START: + if( !rfalIsGTExpired() ) + { + break; /* Wait until GT has been fulfilled */ + } + + err = rfalNfcfPollerStartCheckPresence(); + gCd.st = RFAL_CD_ST_NFCF_TECHDET; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCF_TECHDET: + + err = rfalNfcfPollerGetCheckPresenceStatus(); + if( err == RFAL_ERR_BUSY ) + { + break; /* Wait until NFC-F Technlogy Detection is completed */ + } + + if( gCd.skipTechFound ) /* Verify if we are performing multi technology check */ + { + gCd.st = RFAL_CD_ST_PROPRIETARY; + + /* If single device was another technology and now NFC-F, otherwise conclude*/ + if(err == RFAL_ERR_NONE) + { + gCd.res->detType = RFAL_CD_SINGLE_MULTI_TECH; + gCd.st = RFAL_CD_ST_NOT_DETECTED; + } + break; + } + + if( err == RFAL_ERR_NONE ) + { + if( gCd.techFound != RFAL_CD_TECH_NONE ) /* If on the first round check if other Tech was already found */ + { + gCd.res->detType = RFAL_CD_MULTIPLE_TECH; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.st = RFAL_CD_ST_NFCF_COLRES_START; /* NFC-F detected, perform collision resolution */ + break; + } + + gCd.st = RFAL_CD_ST_NFCV_INIT; /* NFC-F not detected, move to NFC-V */ + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCF_COLRES_START: + + err = rfalNfcfPollerStartCollisionResolution( RFAL_COMPLIANCE_MODE_NFC, 0, &gCd.nfcfDev, &gCd.devCnt ); + if( err != RFAL_ERR_NONE ) + { + gCd.lastErr = err; + gCd.st = RFAL_CD_ST_ERROR; /* Collision resolution could not be performed */ + break; + } + + gCd.st = RFAL_CD_ST_NFCF_COLRES; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCF_COLRES: + + err = rfalNfcfPollerGetCollisionResolutionStatus(); + if( err != RFAL_ERR_BUSY ) + { + if( (err == RFAL_ERR_NONE) && (gCd.devCnt == 1U) ) /* Collision resolution OK and a single card was found */ + { + gCd.mulDevCnt++; + gCd.techFound = RFAL_CD_TECH_NFCF; + } + + /* Check if multiple cards or technologies have already been identified */ + if( (err != RFAL_ERR_NONE) || (gCd.devCnt > 1U) || (gCd.mulDevCnt > 1U) ) + { + gCd.res->detType = RFAL_CD_MULTIPLE_DEV; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.st = RFAL_CD_ST_NFCV_INIT; /* Move to NFC-V */ + } + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_NFCV_INIT: + + rfalNfcvPollerInitialize(); /* Initialize for NFC-V */ + rfalFieldOnAndStartGT(); /* Turns the Field On if not already and start GT timer */ + + gCd.st = RFAL_CD_ST_NFCV_TECHDET; + break; + + /*******************************************************************************/ + case RFAL_CD_ST_NFCV_TECHDET: + + if( !rfalIsGTExpired() ) + { + break; /* Wait until GT has been fulfilled */ + } + + err = rfalNfcvPollerCheckPresence( &invRes ); + if( err == RFAL_ERR_NONE ) + { + if( gCd.techFound != RFAL_CD_TECH_NONE ) /* If other Tech was already found */ + { + gCd.res->detType = RFAL_CD_MULTIPLE_TECH; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.techFound = RFAL_CD_TECH_NFCV; /* If NFC-V is regarded as card as CE NFC-V is currently not supported by active devices */ + gCd.res->detType = RFAL_CD_CARD_TECH; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.st = RFAL_CD_ST_PROPRIETARY; /* Move to Proprietary NFC Technologies */ + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_PROPRIETARY: + + rfalFieldOff(); + platformTimerDestroy( gCd.tmr ); + gCd.tmr = platformTimerCreate( (uint8_t)rfalConv1fcToMs(RFAL_GT_NFCA) ); + + /* If none of the other NFC technologies was not seen on a second round, regard as card */ + if( gCd.skipTechFound ) + { + gCd.res->detType = RFAL_CD_SINGLE_DEV; + gCd.st = RFAL_CD_ST_DETECTED; + + + /*******************************************************************************/ + /* Only one device found which does not support NFC-DEP and only * + * answered in one technology, perform heartbeat detection */ + + #ifdef RFAL_CD_HB + gCd.st = RFAL_CD_ST_HB_START; + #endif /* RFAL_CD_HB */ + + /*******************************************************************************/ + + break; + } + + gCd.st = RFAL_CD_ST_ST25TB_INIT; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_ST25TB_INIT: + + if( (!platformTimerIsExpired( gCd.tmr )) ) /* Check if field has been Off long enough */ + { + break; + } + + rfalSt25tbPollerInitialize(); /* Initialize for ST25TB */ + err = rfalFieldOnAndStartGT(); /* Turns the Field On if not already and start GT timer */ + + if( err != RFAL_ERR_NONE ) + { + gCd.lastErr = err; + gCd.st = RFAL_CD_ST_ERROR; /* Unable to turn the field On, cannot continue Card Detection */ + break; + } + + gCd.st = RFAL_CD_ST_ST25TB_TECHDET; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_ST25TB_TECHDET: + + if( (!rfalIsGTExpired()) ) + { + break; /* Wait until GT has been fulfilled */ + } + + err = rfalSt25tbPollerCheckPresence( NULL ); + if( err == RFAL_ERR_NONE ) + { + gCd.techFound = RFAL_CD_TECH_OTHER; /* If ST25TB is regarded as card as CE is not supported by active devices */ + gCd.res->detType = RFAL_CD_CARD_TECH; + gCd.st = RFAL_CD_ST_DETECTED; + break; + } + + gCd.st = RFAL_CD_ST_CHECK_PROTO; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_CHECK_PROTO: + + if( gCd.mulDevCnt == 0U ) /* No NFC listener has been detected */ + { + gCd.res->detType = RFAL_CD_NOT_FOUND; + gCd.st = RFAL_CD_ST_NOT_DETECTED; + break; + } + + if( gCd.mulDevCnt == 1U ) /* A single NFC listener has been identified */ + { + /* Check if it supports NFC-DEP protocol */ + if( ( (gCd.techFound == RFAL_CD_TECH_NFCA) && ((gCd.nfcaDev.type == RFAL_NFCA_NFCDEP) || (gCd.nfcaDev.type == RFAL_NFCA_T4T_NFCDEP)) ) || + ( (gCd.techFound == RFAL_CD_TECH_NFCF) && rfalNfcfIsNfcDepSupported( &gCd.nfcfDev ) ) ) + { + gCd.res->detType = RFAL_CD_SINGLE_P2P; + gCd.st = RFAL_CD_ST_NOT_DETECTED;/* NFC-DEP supported, regarded as non passive card */ + break; + } + + /* If a single NFC listener has been detected, and did not announce NFC-DEP support, * + * check if it supports mutiple NFC technologies (skip the one it was previous seen) */ + gCd.skipTechFound = true; + gCd.st = RFAL_CD_ST_NFCA_INIT; + + /* Reset Field once again to avoid unwanted effect of Proprietary NFC Tech modulation */ + rfalFieldOff(); + platformTimerDestroy( gCd.tmr ); + gCd.tmr = platformTimerCreate( (uint8_t)rfalConv1fcToMs(RFAL_GT_NFCA) ); + break; + } + + gCd.res->detType = RFAL_CD_MULTIPLE_DEV; + gCd.st = RFAL_CD_ST_DETECTED; + break; + + + #ifdef RFAL_CD_HB + /*******************************************************************************/ + case RFAL_CD_ST_HB_START: + + if( (!platformTimerIsExpired( gCd.tmr )) ) /* Check if field has been Off long enough */ + { + break; + } + + switch( gCd.techFound ) + { + case RFAL_CD_TECH_NFCF: + rfalNfcfPollerInitialize( RFAL_BR_212 ); + break; + + case RFAL_CD_TECH_NFCB: + rfalNfcbPollerInitialize(); + break; + + case RFAL_CD_TECH_NFCA: + default: + rfalNfcaPollerInitialize(); + break; + } + + err = rfalFieldOnAndStartGT(); + if( err != RFAL_ERR_NONE ) + { + gCd.lastErr = err; + gCd.st = RFAL_CD_ST_ERROR; /* Unable to turn the field On, cannot continue Card Detection */ + break; + } + + gCd.st = RFAL_CD_ST_HB; + break; + + + /*******************************************************************************/ + case RFAL_CD_ST_HB: + if( !rfalIsGTExpired() ) /* Check if GT has been fulfilled */ + { + break; + } + + if( rfalCdHbDetect( gCd.techFound ) ) /* Perform tha heartbeat detection sequence */ + { + gCd.res->detType = RFAL_CD_SINGLE_HB; + gCd.st = RFAL_CD_ST_NOT_DETECTED; /* Single device performing ALM, no passive card */ + break; + } + + gCd.res->detType = RFAL_CD_SINGLE_DEV; + gCd.st = RFAL_CD_ST_DETECTED; /* ALM not detected on single device, regard as card */ + break; + #endif /* RFAL_CD_HB */ + + + /*******************************************************************************/ + case RFAL_CD_ST_DETECTED: + case RFAL_CD_ST_NOT_DETECTED: + + /* Card Detection completed, return outcome */ + gCd.res->detected = ((gCd.st == RFAL_CD_ST_NOT_DETECTED) ? false : true); + + rfalFieldOff(); + gCd.st = RFAL_CD_ST_IDLE; + + return RFAL_ERR_NONE; + + + /*******************************************************************************/ + case RFAL_CD_ST_IDLE: + return RFAL_ERR_WRONG_STATE; + + + /*******************************************************************************/ + case RFAL_CD_ST_ERROR: + + gCd.res->detType = RFAL_CD_UNKOWN; + gCd.res->detected = true; /* Error ocurred, mark as card present to avoid damage */ + + rfalFieldOff(); + gCd.st = RFAL_CD_ST_IDLE; + + return gCd.lastErr; + + + /*******************************************************************************/ + default: + return RFAL_ERR_INTERNAL; + } + + return RFAL_ERR_BUSY; +} + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.c new file mode 100644 index 0000000..5140391 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.c @@ -0,0 +1,81 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_crc.c + * + * \author Oliver Regenfelder + * + * \brief CRC calculation implementation + * + */ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_crc.h" + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte); + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ +uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length) +{ + uint16_t crc = preloadValue; + uint16_t index; + + for (index = 0; index < length; index++) + { + crc = rfalCrcUpdateCcitt(crc, buf[index]); + } + + return crc; +} + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ +static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte) +{ + uint16_t crc = crcSeed; + uint8_t dat = dataByte; + + dat ^= (uint8_t)(crc & 0xFFU); + dat ^= (dat << 4); + + crc = (crc >> 8)^(((uint16_t) dat) << 8)^(((uint16_t) dat) << 3)^(((uint16_t) dat) >> 4); + + return crc; +} + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.h new file mode 100644 index 0000000..3b4bdfe --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_crc.h @@ -0,0 +1,70 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_crc.h + * + * \author Ulrich Herrmann + * + * \brief CRC calculation module + * + */ +/*! + * + */ + +#ifndef RFAL_CRC_H_ +#define RFAL_CRC_H_ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief Calculate CRC according to CCITT standard. + * + * This function takes \a length bytes from \a buf and calculates the CRC + * for this data. The result is returned. + * \note This implementation calculates the CRC with LSB first, i.e. all + * bytes are "read" from right to left. + * + * \param[in] preloadValue : Initial value of CRC calculation. + * \param[in] buf : buffer to calculate the CRC for. + * \param[in] length : size of the buffer. + * + * \return 16 bit long crc value. + * + ***************************************************************************** + */ +extern uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length); + +#endif /* RFAL_CRC_H_ */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_dpo.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_dpo.c new file mode 100644 index 0000000..17b433b --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_dpo.c @@ -0,0 +1,318 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: ST25R391x firmware + * $Revision: $ + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_dpo.c + * + * \author Martin Zechleitner + * + * \brief Functions to manage and set dynamic power settings + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_dpoTbl.h" +#include "rfal_dpo.h" +#include "rfal_platform.h" +#include "rfal_rf.h" +#include "rfal_chip.h" +#include "rfal_analogConfig.h" +#include "rfal_utils.h" + + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_DPO + */ + +#if RFAL_FEATURE_DPO + + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ +#define RFAL_DPO_ANALOGCONFIG_SHIFT 13U +#define RFAL_DPO_ANALOGCONFIG_MASK 0x6000U + +/* + ****************************************************************************** + * LOCAL DATA TYPES + ****************************************************************************** + */ + +/*! RFAL DPO instance */ +typedef struct{ + bool enabled; + const uint8_t* currentDpo; + uint8_t tableEntries; + uint8_t table[RFAL_DPO_TABLE_SIZE_MAX]; + uint8_t tableEntry; + rfalDpoMeasureFunc measureCallback; + rfalMode curMode; + rfalBitRate curBR; +}rfalDpo; + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +static rfalDpo gRfalDpo; + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ +void rfalDpoInitialize( void ) +{ + /* By default DPO is disabled */ + rfalDpoSetEnabled( false ); + + + /* Set default measurement */ + #if defined(ST25R3911) || defined(ST25R3916) || defined(ST25R3916B) + gRfalDpo.measureCallback = rfalChipMeasureAmplitude; + #else + gRfalDpo.measureCallback = rfalChipMeasureCombinedIQ; + #endif /* ST25R */ + + + /* Use the default Dynamic Power values */ + gRfalDpo.currentDpo = rfalDpoDefaultSettings; + gRfalDpo.tableEntries = (sizeof(rfalDpoDefaultSettings) / RFAL_DPO_TABLE_PARAM_LEN); + + RFAL_MEMCPY( gRfalDpo.table, gRfalDpo.currentDpo, sizeof(rfalDpoDefaultSettings) ); +} + + +/*******************************************************************************/ +void rfalDpoSetMeasureCallback( rfalDpoMeasureFunc pFunc ) +{ + gRfalDpo.measureCallback = pFunc; +} + + +/*******************************************************************************/ +ReturnCode rfalDpoTableWrite( const rfalDpoEntry* powerTbl, uint8_t powerTblEntries ) +{ + uint8_t entry; + + /* Check if the table size parameter is too big */ + if( (powerTblEntries * RFAL_DPO_TABLE_PARAM_LEN) > RFAL_DPO_TABLE_SIZE_MAX) + { + return RFAL_ERR_NOMEM; + } + + /* Check if the first increase entry is 0xFF */ + if( (powerTblEntries == 0U) || (powerTbl == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Check if the entries of the dynamic power table are valid */ + for( entry = 0; entry < powerTblEntries; entry++ ) + { + if(powerTbl[entry].inc < powerTbl[entry].dec) + { + return RFAL_ERR_PARAM; + } + } + + /* Copy the data set */ + RFAL_MEMCPY( gRfalDpo.table, (const uint8_t*)powerTbl, (powerTblEntries * RFAL_DPO_TABLE_PARAM_LEN) ); + gRfalDpo.currentDpo = gRfalDpo.table; + gRfalDpo.tableEntries = powerTblEntries; + + if( gRfalDpo.tableEntry > powerTblEntries ) + { + /* powerTblEntries is always greater then zero, verified at parameter check */ + gRfalDpo.tableEntry = (powerTblEntries - 1U); + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalDpoTableRead( rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries ) +{ + /* Wrong request */ + if( (tblBuf == NULL) || (tblBufEntries < gRfalDpo.tableEntries) || (tableEntries == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Not properly initialized */ + if( gRfalDpo.currentDpo == NULL ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Copy the whole Table to the given buffer */ + RFAL_MEMCPY( (uint8_t*)tblBuf, gRfalDpo.currentDpo, (tblBufEntries * RFAL_DPO_TABLE_PARAM_LEN) ); + *tableEntries = gRfalDpo.tableEntries; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalDpoAdjust( void ) +{ + uint8_t refValue; + uint16_t modeID; + rfalBitRate br; + rfalMode mode; + uint8_t tableEntry; + const rfalDpoEntry* dpoTable; + + /* Initialize local vars */ + tableEntry = gRfalDpo.tableEntry; + dpoTable = (const rfalDpoEntry*) gRfalDpo.currentDpo; + refValue = 0; + mode = RFAL_MODE_NONE; + br = RFAL_BR_KEEP; + + /* Obtain RFAL's current mode and bit rate */ + mode = rfalGetMode(); + rfalGetBitRate( &br, NULL ); + + + /* Check if the Power Adjustment is disabled and * + * if the callback to the measurement method is properly set */ + if( (!gRfalDpo.enabled) || (gRfalDpo.measureCallback == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Ensure that the current mode is Passive Poller and table is initialized*/ + if( !rfalIsModePassivePoll( mode ) || (gRfalDpo.currentDpo == NULL) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Ensure a proper measure reference value */ + if( RFAL_ERR_NONE != gRfalDpo.measureCallback( &refValue ) ) + { + return RFAL_ERR_IO; + } + + if( refValue >= dpoTable[gRfalDpo.tableEntry].inc ) + { /* Increase the output power */ + /* the top of the table represents the highest amplitude value*/ + if( gRfalDpo.tableEntry == 0U ) + { + /* Maximum driver value has been reached */ + } + else + { + /* Go up in the table to decrease the driver resistance */ + tableEntry--; + } + } + else if(refValue <= dpoTable[gRfalDpo.tableEntry].dec) + { /* Decrease the output power */ + /* The bottom is the highest possible value */ + if( (gRfalDpo.tableEntry + 1U) >= gRfalDpo.tableEntries) + { + /* minimum driver value has been reached */ + } + else + { + /* Go down in the table to increase the driver resistance */ + tableEntry++; + } + } + else + { + /* Fall through to evaluate whether to write dpo and its associated analog configs */ + } + + /* Apply new configs if there was a change on DPO level or RFAL mode|bitrate */ + if( (mode != gRfalDpo.curMode) || (br != gRfalDpo.curBR) || (tableEntry != gRfalDpo.tableEntry) ) + { + /* Update local context */ + gRfalDpo.curMode = mode; + gRfalDpo.curBR = br; + gRfalDpo.tableEntry = tableEntry; + + /* Get the new value for RFO resistance form the table and apply the new RFO resistance setting */ + rfalChipSetRFO( dpoTable[gRfalDpo.tableEntry].rfoRes ); + + /* Apply the DPO Analog Config according to this threshold */ + /* Technology field is being extended for DPO: 2msb are used for threshold step (only 4 allowed) */ + modeID = rfalAnalogConfigGenModeID( gRfalDpo.curMode, gRfalDpo.curBR, RFAL_ANALOG_CONFIG_DPO ); /* Generate Analog Config mode ID */ + modeID |= (((uint16_t)gRfalDpo.tableEntry << RFAL_DPO_ANALOGCONFIG_SHIFT) & RFAL_DPO_ANALOGCONFIG_MASK); /* Add DPO threshold step|level */ + rfalSetAnalogConfig( modeID ); /* Apply DPO Analog Config */ + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +rfalDpoEntry* rfalDpoGetCurrentTableEntry( void ) +{ + rfalDpoEntry* dpoTable = (rfalDpoEntry*) gRfalDpo.currentDpo; + return &dpoTable[gRfalDpo.tableEntry]; +} + + +/*******************************************************************************/ +uint8_t rfalDpoGetCurrentTableIndex( void ) +{ + return gRfalDpo.tableEntry; +} + + +/*******************************************************************************/ +void rfalDpoSetEnabled( bool enable ) +{ + gRfalDpo.enabled = enable; + gRfalDpo.curMode = RFAL_MODE_NONE; + gRfalDpo.curBR = RFAL_BR_KEEP; + gRfalDpo.tableEntry = 0; +} + + +/*******************************************************************************/ +bool rfalDpoIsEnabled( void ) +{ + return gRfalDpo.enabled; +} + +#endif /* RFAL_FEATURE_DPO */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.c new file mode 100644 index 0000000..9d22f5c --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.c @@ -0,0 +1,530 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_iso15693_2.c + * + * \author Ulrich Herrmann + * + * \brief Implementation of ISO-15693-2 + * + */ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_iso15693_2.h" +#include "rfal_crc.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFCV + */ + +#if RFAL_FEATURE_NFCV + +/* +****************************************************************************** +* LOCAL MACROS +****************************************************************************** +*/ + +#define ISO_15693_DEBUG(...) /*!< Macro for the log method */ + +/* +****************************************************************************** +* LOCAL DEFINES +****************************************************************************** +*/ +#define ISO15693_DAT_SOF_1_4 0x21 /* LSB constants */ +#define ISO15693_DAT_EOF_1_4 0x04 +#define ISO15693_DAT_00_1_4 0x02 +#define ISO15693_DAT_01_1_4 0x08 +#define ISO15693_DAT_10_1_4 0x20 +#define ISO15693_DAT_11_1_4 0x80 + +#define ISO15693_DAT_SOF_1_256 0x81 +#define ISO15693_DAT_EOF_1_256 0x04 +#define ISO15693_DAT_SLOT0_1_256 0x02 +#define ISO15693_DAT_SLOT1_1_256 0x08 +#define ISO15693_DAT_SLOT2_1_256 0x20 +#define ISO15693_DAT_SLOT3_1_256 0x80 + +#define ISO15693_PHY_DAT_MANCHESTER_1 0xaaaa + +#define ISO15693_PHY_BIT_BUFFER_SIZE 1000 /*!< size of the receiving buffer. Might be adjusted if longer datastreams are expected. */ + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ +static rfalIso15693PhyConfig_t gIso15693PhyConfig; /*!< current phy configuration */ + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode rfalIso15693PhyVCDCode1Of4(const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen); +static ReturnCode rfalIso15693PhyVCDCode1Of256(const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen); + + + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ +ReturnCode rfalIso15693PhyConfigure(const rfalIso15693PhyConfig_t* config, const struct iso15693StreamConfig ** needed_stream_config ) +{ + static struct iso15693StreamConfig auxConfig = { /* MISRA 8.9 */ + .useBPSK = 0, /* 0: subcarrier, 1:BPSK */ + .din = 5, /* 2^5*fc = 423750 Hz: divider for the in subcarrier frequency */ + .dout = 7, /*!< 2^7*fc = 105937 : divider for the in subcarrier frequency */ + .report_period_length = 3, /*!< 8=2^3 the length of the reporting period */ + }; + + + /* make a copy of the configuration */ + RFAL_MEMCPY( (uint8_t*)&gIso15693PhyConfig, (const uint8_t*)config, sizeof(rfalIso15693PhyConfig_t)); + + if ( config->speedMode <= 3U) + { /* If valid speed mode adjust report period accordingly */ + auxConfig.report_period_length = (3U - (uint8_t)config->speedMode); + } + else + { /* If invalid default to normal (high) speed */ + auxConfig.report_period_length = 3; + } + + *needed_stream_config = &auxConfig; + + return RFAL_ERR_NONE; +} + +ReturnCode rfalIso15693PhyGetConfiguration(rfalIso15693PhyConfig_t* config) +{ + RFAL_MEMCPY(config, &gIso15693PhyConfig, sizeof(rfalIso15693PhyConfig_t)); + + return RFAL_ERR_NONE; +} + +ReturnCode rfalIso15693VCDCode(uint8_t* buffer, uint16_t length, bool sendCrc, bool sendFlags, bool picopassMode, + uint16_t *subbit_total_length, uint16_t *offset, + uint8_t* outbuf, uint16_t outBufSize, uint16_t* actOutBufSize) +{ + ReturnCode err = RFAL_ERR_NONE; + uint8_t eof, sof; + uint8_t transbuf[2]; + uint16_t crc = 0; + ReturnCode (*txFunc)(const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen); + uint8_t crc_len; + uint8_t* outputBuf; + uint16_t outputBufSize; + + crc_len = (uint8_t)((sendCrc)?2:0); + + *actOutBufSize = 0; + + if (ISO15693_VCD_CODING_1_4 == gIso15693PhyConfig.coding) + { + sof = ISO15693_DAT_SOF_1_4; + eof = ISO15693_DAT_EOF_1_4; + txFunc = rfalIso15693PhyVCDCode1Of4; + *subbit_total_length = ( + ( 1U /* SOF */ + + ((length + (uint16_t)crc_len) * 4U) + + 1U) /* EOF */ + ); + if (outBufSize < 5U) { /* 5 should be safe: enough for sof + 1byte data in 1of4 */ + return RFAL_ERR_NOMEM; + } + } + else + { + sof = ISO15693_DAT_SOF_1_256; + eof = ISO15693_DAT_EOF_1_256; + txFunc = rfalIso15693PhyVCDCode1Of256; + *subbit_total_length = ( + ( 1U /* SOF */ + + ((length + (uint16_t)crc_len) * 64U) + + 1U) /* EOF */ + ); + + if (*offset != 0U) + { + if (outBufSize < 64U) { /* 64 should be safe: enough a single byte data in 1of256 */ + return RFAL_ERR_NOMEM; + } + } + else + { + if (outBufSize < 65U) { /* At beginning of a frame we need at least 65 bytes to start: enough for sof + 1byte data in 1of256 */ + return RFAL_ERR_NOMEM; + } + } + } + + if (length == 0U) + { + *subbit_total_length = 1; + } + + if ((length != 0U) && (0U == *offset) && sendFlags && (!picopassMode)) + { + /* set high datarate flag */ + buffer[0] |= (uint8_t)ISO15693_REQ_FLAG_HIGH_DATARATE; + /* clear sub-carrier flag - we only support single sub-carrier */ + buffer[0] = (uint8_t)(buffer[0] & ~ISO15693_REQ_FLAG_TWO_SUBCARRIERS); /* MISRA 10.3 */ + } + + outputBuf = outbuf; /* MISRA 17.8: Use intermediate variable */ + outputBufSize = outBufSize; /* MISRA 17.8: Use intermediate variable */ + + /* Send SOF if at 0 offset */ + if ((length != 0U) && (0U == *offset)) + { + *outputBuf = sof; + (*actOutBufSize)++; + outputBufSize--; + outputBuf++; + } + + while ((*offset < length) && (err == RFAL_ERR_NONE)) + { + uint16_t filled_size; + /* send data */ + err = txFunc(buffer[*offset], outputBuf, outputBufSize, &filled_size); + (*actOutBufSize) += filled_size; + outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */ + outputBufSize -= filled_size; + if (err == RFAL_ERR_NONE) { + (*offset)++; + } + } + if (err != RFAL_ERR_NONE) { + return RFAL_ERR_AGAIN; + } + + while ((err == RFAL_ERR_NONE) && sendCrc && (*offset < (length + 2U))) + { + uint16_t filled_size; + if ((0U==crc) && (length != 0U)) + { + crc = rfalCrcCalculateCcitt( (uint16_t) ((picopassMode) ? 0xE012U : 0xFFFFU), /* In PicoPass Mode a different Preset Value is used */ + ((picopassMode) ? (buffer + 1U) : buffer), /* CMD byte is not taken into account in PicoPass mode */ + ((picopassMode) ? (length - 1U) : length)); /* CMD byte is not taken into account in PicoPass mode */ + + crc = (uint16_t)((picopassMode) ? crc : ~crc); + } + /* send crc */ + transbuf[0] = (uint8_t)(crc & 0xffU); + transbuf[1] = (uint8_t)((crc >> 8) & 0xffU); + err = txFunc(transbuf[*offset - length], outputBuf, outputBufSize, &filled_size); + (*actOutBufSize) += filled_size; + outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */ + outputBufSize -= filled_size; + if (err == RFAL_ERR_NONE) { + (*offset)++; + } + } + if (err != RFAL_ERR_NONE) { + return RFAL_ERR_AGAIN; + } + + if (((!sendCrc) && (*offset == length)) + || (sendCrc && (*offset == (length + 2U)))) + { + *outputBuf = eof; + (*actOutBufSize)++; + outputBufSize--; + outputBuf++; + } + else + { + return RFAL_ERR_AGAIN; + } + + return err; +} + +ReturnCode rfalIso15693VICCDecode(const uint8_t *inBuf, + uint16_t inBufLen, + uint8_t* outBuf, + uint16_t outBufLen, + uint16_t* outBufPos, + uint16_t* bitsBeforeCol, + uint16_t ignoreBits, + bool picopassMode ) +{ + ReturnCode err = RFAL_ERR_NONE; + uint16_t crc; + uint16_t mp; /* Current bit position in manchester bit inBuf*/ + uint16_t bp; /* Current bit position in outBuf */ + + *bitsBeforeCol = 0; + *outBufPos = 0; + + /* first check for valid SOF. Since it starts with 3 unmodulated pulses it is 0x17. */ + if ((inBuf[0] & 0x1fU) != 0x17U) + { + ISO_15693_DEBUG("0x%x\n", iso15693PhyBitBuffer[0]); + return RFAL_ERR_FRAMING; + } + ISO_15693_DEBUG("SOF\n"); + + if (outBufLen == 0U) + { + return RFAL_ERR_NONE; + } + + mp = 5; /* 5 bits were SOF, now manchester starts: 2 bits per payload bit */ + bp = 0; + + RFAL_MEMSET(outBuf,0,outBufLen); + + if (inBufLen == 0U) + { + return RFAL_ERR_CRC; + } + + for ( ; mp < ((inBufLen * 8U) - 2U); mp+=2U ) + { + bool isEOF = false; + + uint8_t man; + man = (inBuf[mp/8U] >> (mp%8U)) & 0x1U; + man |= ((inBuf[(mp+1U)/8U] >> ((mp+1U)%8U)) & 0x1U) << 1; + if (1U == man) + { + bp++; + } + if (2U == man) + { + outBuf[bp/8U] = (uint8_t)(outBuf[bp/8U] | (1U <<(bp%8U))); /* MISRA 10.3 */ + bp++; + } + if ((bp%8U) == 0U) + { /* Check for EOF */ + ISO_15693_DEBUG("ceof %hhx %hhx\n", inBuf[mp/8U], inBuf[mp/8+1]); + if ( ((inBuf[mp/8U] & 0xe0U) == 0xa0U) + &&(inBuf[(mp/8U)+1U] == 0x03U)) + { /* Now we know that it was 10111000 = EOF */ + ISO_15693_DEBUG("EOF\n"); + isEOF = true; + } + } + if ( ((0U == man) || (3U == man)) && (!isEOF) ) + { + if (bp >= ignoreBits) + { + err = RFAL_ERR_RF_COLLISION; + } + else + { + /* ignored collision: leave as 0 */ + bp++; + } + } + if ( (bp >= (outBufLen * 8U)) || (err == RFAL_ERR_RF_COLLISION) || isEOF ) + { /* Don't write beyond the end */ + break; + } + } + + *outBufPos = (bp / 8U); + *bitsBeforeCol = bp; + + if (err != RFAL_ERR_NONE) + { + return err; + } + + if ((bp%8U) != 0U) + { + return RFAL_ERR_CRC; + } + + if (*outBufPos > 2U) + { + /* finally, check crc */ + ISO_15693_DEBUG("Calculate CRC, val: 0x%x, outBufLen: ", *outBuf); + ISO_15693_DEBUG("0x%x ", *outBufPos - 2); + + crc = rfalCrcCalculateCcitt(((picopassMode) ? 0xE012U : 0xFFFFU), outBuf, *outBufPos - 2U); + crc = (uint16_t)((picopassMode) ? crc : ~crc); + + if (((crc & 0xffU) == outBuf[*outBufPos-2U]) && + (((crc >> 8U) & 0xffU) == outBuf[*outBufPos-1U])) + { + err = RFAL_ERR_NONE; + ISO_15693_DEBUG("OK\n"); + } + else + { + ISO_15693_DEBUG("error! Expected: 0x%x, got ", crc); + ISO_15693_DEBUG("0x%hhx 0x%hhx\n", outBuf[*outBufPos-2], outBuf[*outBufPos-1]); + err = RFAL_ERR_CRC; + } + } + else + { + err = RFAL_ERR_CRC; + } + + return err; +} + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief Perform 1 of 4 coding and send coded data + * + * This function takes \a length bytes from \a buffer, perform 1 of 4 coding + * (see ISO15693-2 specification) and sends the data using stream mode. + * + * \param[in] sendSof : send SOF prior to data. + * \param[in] buffer : data to send. + * \param[in] length : number of bytes to send. + * + * \return RFAL_ERR_IO : Error during communication. + * \return RFAL_ERR_NONE : No error. + * + ***************************************************************************** + */ +static ReturnCode rfalIso15693PhyVCDCode1Of4(const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen) +{ + uint8_t tmp; + ReturnCode err = RFAL_ERR_NONE; + uint16_t a; + uint8_t* outbuf = outbuffer; + + *outBufLen = 0; + + if (maxOutBufLen < 4U) { + return RFAL_ERR_NOMEM; + } + + tmp = data; + for (a = 0; a < 4U; a++) + { + switch (tmp & 0x3U) + { + case 0: + *outbuf = ISO15693_DAT_00_1_4; + break; + case 1: + *outbuf = ISO15693_DAT_01_1_4; + break; + case 2: + *outbuf = ISO15693_DAT_10_1_4; + break; + case 3: + *outbuf = ISO15693_DAT_11_1_4; + break; + default: + /* MISRA 16.4: mandatory default statement */ + break; + } + outbuf++; + (*outBufLen)++; + tmp >>= 2; + } + return err; +} + +/*! + ***************************************************************************** + * \brief Perform 1 of 256 coding and send coded data + * + * This function takes \a length bytes from \a buffer, perform 1 of 256 coding + * (see ISO15693-2 specification) and sends the data using stream mode. + * \note This function sends SOF prior to the data. + * + * \param[in] sendSof : send SOF prior to data. + * \param[in] buffer : data to send. + * \param[in] length : number of bytes to send. + * + * \return RFAL_ERR_IO : Error during communication. + * \return RFAL_ERR_NONE : No error. + * + ***************************************************************************** + */ +static ReturnCode rfalIso15693PhyVCDCode1Of256(const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen) +{ + uint8_t tmp; + ReturnCode err = RFAL_ERR_NONE; + uint16_t a; + uint8_t* outbuf = outbuffer; + + *outBufLen = 0; + + if (maxOutBufLen < 64U) { + return RFAL_ERR_NOMEM; + } + + tmp = data; + for (a = 0; a < 64U; a++) + { + switch (tmp) + { + case 0: + *outbuf = ISO15693_DAT_SLOT0_1_256; + break; + case 1: + *outbuf = ISO15693_DAT_SLOT1_1_256; + break; + case 2: + *outbuf = ISO15693_DAT_SLOT2_1_256; + break; + case 3: + *outbuf = ISO15693_DAT_SLOT3_1_256; + break; + default: + *outbuf = 0; + break; + } + outbuf++; + (*outBufLen)++; + tmp -= 4U; /* PRQA S 2911 # CERT INT30 - Intentional underflow, part of the coding */ + } + + return err; +} + +#endif /* RFAL_FEATURE_NFCV */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.h new file mode 100644 index 0000000..455b24c --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_iso15693_2.h @@ -0,0 +1,196 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_iso15693_2.h + * + * \author Ulrich Herrmann + * + * \brief Implementation of ISO-15693-2 + * + */ +/*! + * + */ + +#ifndef RFAL_ISO_15693_2_H +#define RFAL_ISO_15693_2_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" +#include "rfal_utils.h" + +/* +****************************************************************************** +* GLOBAL DATATYPES +****************************************************************************** +*/ +/*! Enum holding possible VCD codings */ +typedef enum +{ + ISO15693_VCD_CODING_1_4, + ISO15693_VCD_CODING_1_256 +}rfalIso15693VcdCoding_t; + +/*! Enum holding possible VICC datarates */ + +/*! Configuration parameter used by rfalIso15693PhyConfigure */ +typedef struct +{ + rfalIso15693VcdCoding_t coding; /*!< desired VCD coding */ + uint32_t speedMode; /*!< 0: normal mode, 1: 2^1 = x2 Fast mode, 2 : 2^2 = x4 mode, 3 : 2^3 = x8 mode - all rx pulse numbers and times are divided by 1,2,4,8 */ +}rfalIso15693PhyConfig_t; + +/*! Parameters how the stream mode should work */ +struct iso15693StreamConfig { + uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK */ + uint8_t din; /*!< the divider for the in subcarrier frequency: fc/2^din */ + uint8_t dout; /*!< the divider for the in subcarrier frequency fc/2^dout */ + uint8_t report_period_length; /*!< the length of the reporting period 2^report_period_length*/ +}; +/* +****************************************************************************** +* GLOBAL CONSTANTS +****************************************************************************** +*/ + +#define ISO15693_REQ_FLAG_TWO_SUBCARRIERS 0x01U /*!< Flag indication that communication uses two subcarriers */ +#define ISO15693_REQ_FLAG_HIGH_DATARATE 0x02U /*!< Flag indication that communication uses high bitrate */ +#define ISO15693_MASK_FDT_LISTEN (65) /*!< t1min = 308,2us = 4192/fc = 65.5 * 64/fc */ + +/*! t1max = 323,3us = 4384/fc = 68.5 * 64/fc + * 12 = 768/fc unmodulated time of single subcarrior SoF */ +#define ISO15693_FWT (69 + 12) + + + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief Initialize the ISO15693 phy + * + * \param[in] config : ISO15693 phy related configuration (See rfalIso15693PhyConfig_t) + * \param[out] needed_stream_config : return a pointer to the stream config + * needed for this iso15693 config. To be used for configure RF chip. + * + * \return RFAL_ERR_IO : Error during communication. + * \return RFAL_ERR_NONE : No error. + * + ***************************************************************************** + */ +extern ReturnCode rfalIso15693PhyConfigure(const rfalIso15693PhyConfig_t* config, const struct iso15693StreamConfig ** needed_stream_config ); + +/*! + ***************************************************************************** + * \brief Return current phy configuration + * + * This function returns current Phy configuration previously + * set by rfalIso15693PhyConfigure + * + * \param[out] config : ISO15693 phy configuration. + * + * \return RFAL_ERR_NONE : No error. + * + ***************************************************************************** + */ +extern ReturnCode rfalIso15693PhyGetConfiguration(rfalIso15693PhyConfig_t* config); + +/*! + ***************************************************************************** + * \brief Code an ISO15693 compatible frame + * + * This function takes \a length bytes from \a buffer, perform proper + * encoding and sends out the frame to the ST25R391x. + * + * \param[in] buffer : data to send, modified to adapt flags. + * \param[in] length : number of bytes to send. + * \param[in] sendCrc : If set to true, CRC is appended to the frame + * \param[in] sendFlags : If set to true, flag field is sent according to + * ISO15693. + * \param[in] picopassMode : If set to true, the coding will be according to Picopass + * \param[out] subbit_total_length : Return the complete bytes which need to + * be send for the current coding + * \param[in,out] offset : Set to 0 for first transfer, function will update it to + point to next byte to be coded + * \param[out] outbuf : buffer where the function will store the coded subbit stream + * \param[out] outBufSize : the size of the output buffer + * \param[out] actOutBufSize : the amount of data stored into the buffer at this call + * + * \return RFAL_ERR_IO : Error during communication. + * \return RFAL_ERR_AGAIN : Data was not coded all the way. Call function again with a new/emptied buffer + * \return RFAL_ERR_NO_MEM : In case outBuf is not big enough. Needs to have at + least 5 bytes for 1of4 coding and 65 bytes for 1of256 coding + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +extern ReturnCode rfalIso15693VCDCode(uint8_t* buffer, uint16_t length, bool sendCrc, bool sendFlags, bool picopassMode, + uint16_t *subbit_total_length, uint16_t *offset, + uint8_t* outbuf, uint16_t outBufSize, uint16_t* actOutBufSize); + + +/*! + ***************************************************************************** + * \brief Receive an ISO15693 compatible frame + * + * This function receives an ISO15693 frame from the ST25R391x, decodes the frame + * and writes the raw data to \a buffer. + * \note Buffer needs to be big enough to hold CRC also (+2 bytes) + * + * \param[in] inBuf : buffer with the hamming coded stream to be decoded + * \param[in] inBufLen : number of bytes to decode (=length of buffer). + * \param[out] outBuf : buffer where received data shall be written to. + * \param[in] outBufLen : Length of output buffer, should be approx twice the size of inBuf + * \param[out] outBufPos : The number of decoded bytes. Could be used in + * extended implementation to allow multiple calls + * \param[out] bitsBeforeCol : in case of RFAL_ERR_RF_COLLISION this value holds the + * number of bits in the current byte where the collision happened + * \param[in] ignoreBits : number of bits in the beginning where collisions will be ignored + * \param[in] picopassMode : if set to true, the decoding will be according to Picopass + * + * \return RFAL_ERR_RF_COLLISION : collision occured, data uncorrect + * \return RFAL_ERR_CRC : CRC error, data uncorrect + * \return RFAL_ERR_TIMEOUT : timeout waiting for data. + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +extern ReturnCode rfalIso15693VICCDecode(const uint8_t *inBuf, + uint16_t inBufLen, + uint8_t* outBuf, + uint16_t outBufLen, + uint16_t* outBufPos, + uint16_t* bitsBeforeCol, + uint16_t ignoreBits, + bool picopassMode ); + +#endif /* RFAL_ISO_15693_2_H */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_isoDep.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_isoDep.c new file mode 100644 index 0000000..9d8024d --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_isoDep.c @@ -0,0 +1,2837 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: NFCC firmware + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_isoDep.c + * + * \author Gustavo Patricio + * + * \brief Implementation of ISO-DEP protocol + * + * This implementation was based on the following specs: + * - ISO/IEC 14443-4 2nd Edition 2008-07-15 + * - NFC Forum Digital Protocol 1.1 2014-01-14 + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + +#include "rfal_isoDep.h" +#include "rfal_rf.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_ISO_DEP + */ + +#if RFAL_FEATURE_ISO_DEP + +#if ( !RFAL_FEATURE_ISO_DEP_POLL && !RFAL_FEATURE_ISO_DEP_LISTEN ) + #error " RFAL: Invalid ISO-DEP Configuration. Please select at least one mode: Poller and/or Listener. " +#endif + +/* Check for valid I-Block length [RFAL_ISODEP_FSX_16 ; RFAL_ISODEP_FSX_4096]*/ +#if( (RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN > 4096 ) || (RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN < 16) ) + #error " RFAL: Invalid ISO-DEP IBlock Max length. Please change RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN. " +#endif + +/* Check for valid APDU length. */ +#if( (RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN < RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN) ) + #error " RFAL: Invalid ISO-DEP APDU Max length. Please change RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN. " +#endif + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ +#define ISODEP_CRC_LEN RFAL_CRC_LEN /*!< ISO1443 CRC Length */ + + +#define ISODEP_PCB_POS (0U) /*!< PCB position on message header*/ +#define ISODEP_SWTX_INF_POS (1U) /*!< INF position in a S-WTX */ + +#define ISODEP_DID_POS (1U) /*!< DID position on message header*/ +#define ISODEP_SWTX_PARAM_LEN (1U) /*!< SWTX parameter length */ + +#define ISODEP_DSL_MAX_LEN ( RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN ) /*!< Deselect Req/Res length */ + +#define ISODEP_PCB_xBLOCK_MASK (0xC0U) /*!< Bit mask for Block type */ +#define ISODEP_PCB_IBLOCK (0x00U) /*!< Bit mask indicating a I-Block */ +#define ISODEP_PCB_RBLOCK (0x80U) /*!< Bit mask indicating a R-Block */ +#define ISODEP_PCB_SBLOCK (0xC0U) /*!< Bit mask indicating a S-Block */ +#define ISODEP_PCB_INVALID (0x40U) /*!< Bit mask of an Invalid PCB */ + +#define ISODEP_HDR_MAX_LEN (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + RFAL_ISODEP_NAD_LEN) /*!< Max header length (PCB + DID + NAD) */ + +#define ISODEP_PCB_IB_VALID_MASK (ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT) /*!< Bit mask for the MUST bits on I-Block */ +#define ISODEP_PCB_IB_VALID_VAL (ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on I-Block */ +#define ISODEP_PCB_RB_VALID_MASK (ISODEP_PCB_B6_BIT | ISODEP_PCB_B3_BIT | ISODEP_PCB_B2_BIT) /*!< Bit mask for the MUST bits on R-Block */ +#define ISODEP_PCB_RB_VALID_VAL (ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on R-Block */ +#define ISODEP_PCB_SB_VALID_MASK (ISODEP_PCB_B3_BIT | ISODEP_PCB_B2_BIT | ISODEP_PCB_B1_BIT) /*!< Bit mask for the MUST bits on I-Block */ +#define ISODEP_PCB_SB_VALID_VAL (ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on I-Block */ + + +#define ISODEP_PCB_B1_BIT (0x01U) /*!< Bit mask for the RFU S Blocks */ +#define ISODEP_PCB_B2_BIT (0x02U) /*!< Bit mask for the RFU bit2 in I,S,R Blocks */ +#define ISODEP_PCB_B3_BIT (0x04U) /*!< Bit mask for the RFU bit3 in R Blocks */ +#define ISODEP_PCB_B6_BIT (0x20U) /*!< Bit mask for the RFU bit2 in R Blocks */ +#define ISODEP_PCB_CHAINING_BIT (0x10U) /*!< Bit mask for the chaining bit of an ISO DEP I-Block in PCB. */ +#define ISODEP_PCB_DID_BIT (0x08U) /*!< Bit mask for the DID presence bit of an ISO DEP I,S,R Blocks PCB. */ +#define ISODEP_PCB_NAD_BIT (0x04U) /*!< Bit mask for the NAD presence bit of an ISO DEP I,S,R Blocks in PCB */ +#define ISODEP_PCB_BN_MASK (0x01U) /*!< Bit mask for the block number of an ISO DEP I,R Block in PCB */ + +#define ISODEP_SWTX_PL_MASK (0xC0U) /*!< Bit mask for the Power Level bits of the inf byte of an WTX request or response */ +#define ISODEP_SWTX_WTXM_MASK (0x3FU) /*!< Bit mask for the WTXM bits of the inf byte of an WTX request or response */ + + +#define ISODEP_RBLOCK_INF_LEN (0U) /*!< INF length of R-Block Digital 1.1 15.1.3 */ +#define ISODEP_SDSL_INF_LEN (0U) /*!< INF length of S(DSL) Digital 1.1 15.1.3 */ +#define ISODEP_SWTX_INF_LEN (1U) /*!< INF length of S(WTX) Digital 1.1 15.2.2 */ + +#define ISODEP_WTXM_MIN (1U) /*!< Minimum allowed value for the WTXM, Digital 1.0 13.2.2 */ +#define ISODEP_WTXM_MAX (59U) /*!< Maximum allowed value for the WTXM, Digital 1.0 13.2.2 */ + +#define ISODEP_PCB_Sxx_MASK (0x30U) /*!< Bit mask for the S-Block type */ +#define ISODEP_PCB_DESELECT (0x00U) /*!< Bit mask for S-Block indicating Deselect */ +#define ISODEP_PCB_WTX (0x30U) /*!< Bit mask for S-Block indicating Waiting Time eXtension */ + +#define ISODEP_PCB_Rx_MASK (0x10U) /*!< Bit mask for the R-Block type */ +#define ISODEP_PCB_ACK (0x00U) /*!< Bit mask for R-Block indicating ACK */ +#define ISODEP_PCB_NAK (0x10U) /*!< Bit mask for R-Block indicating NAK */ + +/*! Maximum length of control message (no INF) */ +#define ISODEP_CONTROLMSG_BUF_LEN (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + RFAL_ISODEP_NAD_LEN + ISODEP_SWTX_PARAM_LEN) + +#define ISODEP_FWT_DEACTIVATION (71680U) /*!< FWT used for DESELECT Digital 2.2 B10 ISO1444-4 7.2 & 8.1 */ +#define ISODEP_MAX_RERUNS (0x0FFFFFFFU)/*!< Maximum rerun retrys for a blocking protocol run*/ + + +#define ISODEP_PCBSBLOCK ( 0x00U | ISODEP_PCB_SBLOCK | ISODEP_PCB_B2_BIT ) /*!< PCB Value of a S-Block */ +#define ISODEP_PCB_SDSL ( ISODEP_PCBSBLOCK | ISODEP_PCB_DESELECT ) /*!< PCB Value of a S-Block with DESELECT */ +#define ISODEP_PCB_SWTX ( ISODEP_PCBSBLOCK | ISODEP_PCB_WTX ) /*!< PCB Value of a S-Block with WTX */ +#define ISODEP_PCB_SPARAMETERS ( ISODEP_PCB_SBLOCK | ISODEP_PCB_WTX ) /*!< PCB Value of a S-Block with PARAMETERS */ + +#define ISODEP_FWI_LIS_MAX_NFC 8U /*!< FWT Listener Max FWIT4ATmax FWIBmax Digital 1.1 A6 & A3 */ +#define ISODEP_FWI_LIS_MAX_EMVCO 7U /*!< FWT Listener Max FWIMAX EMVCo 2.6 A.5 */ +#define ISODEP_FWI_LIS_MAX (uint8_t)((gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) ? ISODEP_FWI_LIS_MAX_EMVCO : ISODEP_FWI_LIS_MAX_NFC) /*!< FWI Listener Max as NFC / EMVCo */ +#define ISODEP_FWT_LIS_MAX rfalIsoDepFWI2FWT(ISODEP_FWI_LIS_MAX) /*!< FWT Listener Max */ + +#define ISODEP_FWI_MIN_10 (1U) /*!< Minimum value for FWI Digital 1.0 11.6.2.17 */ +#define ISODEP_FWI_MIN_11 (0U) /*!< Default value for FWI Digital 1.1 13.6.2 */ +#define ISODEP_FWI_MAX (14U) /*!< Maximum value for FWI Digital 1.0 11.6.2.17 */ +#define ISODEP_SFGI_MIN (0U) /*!< Default value for FWI Digital 1.1 13.6.2.22 */ +#define ISODEP_SFGI_MAX (14U) /*!< Maximum value for FWI Digital 1.1 13.6.2.22 */ + + +#define RFAL_ISODEP_SPARAM_TVL_HDR_LEN (2U) /*!< S(PARAMETERS) TVL header length: Tag + Len */ +#define RFAL_ISODEP_SPARAM_HDR_LEN (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_SPARAM_TVL_HDR_LEN) /*!< S(PARAMETERS) header length: PCB + Tag + Len */ + + +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ +#define RFAL_ISODEP_NO_PARAM (0U) /*!< No parameter flag for rfalIsoDepHandleControlMsg() */ + +#define RFAL_ISODEP_CMD_RATS (0xE0U) /*!< RATS command Digital 1.1 13.6.1 */ + +#define RFAL_ISODEP_ATS_MIN_LEN (1U) /*!< Minimum ATS length Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_HDR_LEN (5U) /*!< ATS headerlength Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_MAX_LEN (RFAL_ISODEP_ATS_HDR_LEN + RFAL_ISODEP_ATS_HB_MAX_LEN) /*!< Maximum ATS length Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_T0_FSCI_MASK (0x0FU) /*!< ATS T0's FSCI mask Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_TB_FWI_SHIFT (4U) /*!< ATS TB's FWI shift Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_FWI_MASK (0x0FU) /*!< ATS TB's FWI shift Digital 1.1 13.6.2 */ +#define RFAL_ISODEP_ATS_TL_POS (0x00U) /*!< ATS TL's position Digital 1.1 13.6.2 */ + + +#define RFAL_ISODEP_PPS_SB (0xD0U) /*!< PPS REQ PPSS's SB value (no CID) ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_MASK (0xF0U) /*!< PPS REQ PPSS's SB mask ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_SB_DID_MASK (0x0FU) /*!< PPS REQ PPSS's DID|CID mask ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_PPS0_PPS1_PRESENT (0x11U) /*!< PPS REQ PPS0 indicating that PPS1 is present */ +#define RFAL_ISODEP_PPS_PPS1 (0x00U) /*!< PPS REQ PPS1 fixed value ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_PPS1_DSI_SHIFT (2U) /*!< PPS REQ PPS1 fixed value ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_PPS1_DXI_MASK (0x0FU) /*!< PPS REQ PPS1 fixed value ISO14443-4 5.3 */ +#define RFAL_ISODEP_PPS_RES_LEN (1U) /*!< PPS Response length ISO14443-4 5.4 */ +#define RFAL_ISODEP_PPS_STARTBYTE_POS (0U) /*!< PPS REQ PPSS's byte position ISO14443-4 5.4 */ +#define RFAL_ISODEP_PPS_PPS0_POS (1U) /*!< PPS REQ PPS0's byte position ISO14443-4 5.4 */ +#define RFAL_ISODEP_PPS_PPS1_POS (2U) /*!< PPS REQ PPS1's byte position ISO14443-4 5.4 */ +#define RFAL_ISODEP_PPS0_VALID_MASK (0xEFU) /*!< PPS REQ PPS0 valid coding mask ISO14443-4 5.4 */ + +#define RFAL_ISODEP_CMD_ATTRIB (0x1DU) /*!< ATTRIB command Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_PARAM2_DSI_SHIFT (6U) /*!< ATTRIB PARAM2 DSI shift Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_PARAM2_DRI_SHIFT (4U) /*!< ATTRIB PARAM2 DRI shift Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_PARAM2_DXI_MASK (0xF0U) /*!< ATTRIB PARAM2 DxI mask Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_PARAM2_FSDI_MASK (0x0FU) /*!< ATTRIB PARAM2 FSDI mask Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_PARAM4_DID_MASK (0x0FU) /*!< ATTRIB PARAM4 DID mask Digital 1.1 14.6.1 */ +#define RFAL_ISODEP_ATTRIB_HDR_LEN (9U) /*!< ATTRIB REQ header length Digital 1.1 14.6.1 */ + +#define RFAL_ISODEP_ATTRIB_RES_HDR_LEN (1U) /*!< ATTRIB RES header length Digital 1.1 14.6.2 */ +#define RFAL_ISODEP_ATTRIB_RES_MBLIDID_POS (0U) /*!< ATTRIB RES MBLI|DID position Digital 1.1 14.6.2 */ +#define RFAL_ISODEP_ATTRIB_RES_DID_MASK (0x0FU) /*!< ATTRIB RES DID mask Digital 1.1 14.6.2 */ +#define RFAL_ISODEP_ATTRIB_RES_MBLI_MASK (0x0FU) /*!< ATTRIB RES MBLI mask Digital 1.1 14.6.2 */ +#define RFAL_ISODEP_ATTRIB_RES_MBLI_SHIFT (4U) /*!< ATTRIB RES MBLI shift Digital 1.1 14.6.2 */ + +#define RFAL_ISODEP_DID_MASK (0x0FU) /*!< ISODEP's DID mask */ +#define RFAL_ISODEP_DID_00 (0U) /*!< ISODEP's DID value 0 */ + +#define RFAL_ISODEP_FSDI_MAX_NFC (8U) /*!< Max FSDI value Digital 2.0 14.6.1.9 & B7 & B8 */ +#define RFAL_ISODEP_FSDI_MAX_NFC_21 (0x0CU) /*!< Max FSDI value Digital 2.1 14.6.1.9 & Table 72 */ +#define RFAL_ISODEP_FSDI_MAX_EMV (0x0CU) /*!< Max FSDI value EMVCo 3.0 5.7.2.5 */ + +#define RFAL_ISODEP_RATS_PARAM_FSDI_MASK (0xF0U) /*!< Mask bits for FSDI in RATS */ +#define RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT (4U) /*!< Shift for FSDI in RATS */ +#define RFAL_ISODEP_RATS_PARAM_DID_MASK (0x0FU) /*!< Mask bits for DID in RATS */ + +#define RFAL_ISODEP_ATS_TL_OFFSET (0x00U) /*!< Offset of TL on ATS */ +#define RFAL_ISODEP_ATS_TA_OFFSET (0x02U) /*!< Offset of TA if it is present on ATS */ +#define RFAL_ISODEP_ATS_TB_OFFSET (0x03U) /*!< Offset of TB if both TA and TB is present on ATS */ +#define RFAL_ISODEP_ATS_TC_OFFSET (0x04U) /*!< Offset of TC if both TA,TB & TC are present on ATS */ +#define RFAL_ISODEP_ATS_HIST_OFFSET (0x05U) /*!< Offset of Historical Bytes if TA, TB & TC are present on ATS */ +#define RFAL_ISODEP_ATS_TC_ADV_FEAT (0x10U) /*!< Bit mask indicating support for Advanced protocol features: DID & NAD */ +#define RFAL_ISODEP_ATS_TC_DID (0x02U) /*!< Bit mask indicating support for DID */ +#define RFAL_ISODEP_ATS_TC_NAD (0x01U) /*!< Bit mask indicating support for NAD */ + +#define RFAL_ISODEP_PPS0_PPS1_PRESENT (0x11U) /*!< PPS0 byte indicating that PPS1 is present */ +#define RFAL_ISODEP_PPS0_PPS1_NOT_PRESENT (0x01U) /*!< PPS0 byte indicating that PPS1 is NOT present */ +#define RFAL_ISODEP_PPS1_DRI_MASK (0x03U) /*!< PPS1 byte DRI mask bits */ +#define RFAL_ISODEP_PPS1_DSI_MASK (0x0CU) /*!< PPS1 byte DSI mask bits */ +#define RFAL_ISODEP_PPS1_DSI_SHIFT (2U) /*!< PPS1 byte DSI shift */ +#define RFAL_ISODEP_PPS1_DxI_MASK (0x03U) /*!< PPS1 byte DSI/DRS mask bits */ + + +/*! Delta Time for polling during Activation (ATS) : 20ms Digital 1.0 11.7.1.1 & A.7 */ +#define RFAL_ISODEP_T4T_DTIME_POLL_10 rfalConvMsTo1fc(20) + +/*! Delta Time for polling during Activation (ATS) : 16.4ms Digital 1.1 13.8.1.1 & A.6 + * Use 16 ms as testcase T4AT_BI_10_03 sends a frame exactly at the border */ +#define RFAL_ISODEP_T4T_DTIME_POLL_11 216960U + +/*! Activation frame waiting time FWT(act) = 71680/fc (~5286us) Digital 1.1 13.8.1.1 & A.6 */ +#define RFAL_ISODEP_T4T_FWT_ACTIVATION (71680U + RFAL_ISODEP_T4T_DTIME_POLL_11) + + +/*! Delta frame waiting time = 16/fc Digital 1.0 11.7.1.3 & A.7*/ +#define RFAL_ISODEP_DFWT_10 16U + +/*! Delta frame waiting time = 16/fc Digital 2.0 14.8.1.3 & B.7*/ +#define RFAL_ISODEP_DFWT_20 49152U + +/* + ****************************************************************************** + * MACROS + ****************************************************************************** + */ + +#define rfalIsoDep_PCBisIBlock( pcb ) ( ((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_IB_VALID_MASK)) == (ISODEP_PCB_IBLOCK | ISODEP_PCB_IB_VALID_VAL)) /*!< Checks if pcb is a I-Block */ +#define rfalIsoDep_PCBisRBlock( pcb ) ( ((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_RB_VALID_MASK)) == (ISODEP_PCB_RBLOCK | ISODEP_PCB_RB_VALID_VAL)) /*!< Checks if pcb is a R-Block */ +#define rfalIsoDep_PCBisSBlock( pcb ) ( ((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_SB_VALID_MASK)) == (ISODEP_PCB_SBLOCK | ISODEP_PCB_SB_VALID_VAL)) /*!< Checks if pcb is a S-Block */ + +#define rfalIsoDep_PCBisChaining( pcb ) ( ((pcb) & ISODEP_PCB_CHAINING_BIT) == ISODEP_PCB_CHAINING_BIT) /*!< Checks if pcb is indicating chaining */ + +#define rfalIsoDep_PCBisDeselect( pcb ) ( ((pcb) & ISODEP_PCB_Sxx_MASK) == ISODEP_PCB_DESELECT) /*!< Checks if pcb is indicating DESELECT */ +#define rfalIsoDep_PCBisWTX( pcb ) ( ((pcb) & ISODEP_PCB_Sxx_MASK) == ISODEP_PCB_WTX) /*!< Checks if pcb is indicating WTX */ + +#define rfalIsoDep_PCBisACK( pcb ) ( ((pcb) & ISODEP_PCB_Rx_MASK) == ISODEP_PCB_ACK) /*!< Checks if pcb is indicating ACK */ +#define rfalIsoDep_PCBisNAK( pcb ) ( ((pcb) & ISODEP_PCB_Rx_MASK) == ISODEP_PCB_NAK) /*!< Checks if pcb is indicating ACK */ + +#define rfalIsoDep_PCBhasDID( pcb ) ( ((pcb) & ISODEP_PCB_DID_BIT) == ISODEP_PCB_DID_BIT) /*!< Checks if pcb is indicating DID */ +#define rfalIsoDep_PCBhasNAD( pcb ) ( ((pcb) & ISODEP_PCB_NAD_BIT) == ISODEP_PCB_NAD_BIT) /*!< Checks if pcb is indicating NAD */ + + +#define rfalIsoDep_PCBisIChaining( pcb ) ( rfalIsoDep_PCBisIBlock(pcb) && rfalIsoDep_PCBisChaining(pcb) ) /*!< Checks if pcb is I-Block indicating chaining */ + +#define rfalIsoDep_PCBisSDeselect( pcb ) ( rfalIsoDep_PCBisSBlock(pcb) && rfalIsoDep_PCBisDeselect(pcb) ) /*!< Checks if pcb is S-Block indicating DESELECT */ +#define rfalIsoDep_PCBisSWTX( pcb ) ( rfalIsoDep_PCBisSBlock(pcb) && rfalIsoDep_PCBisWTX(pcb) ) /*!< Checks if pcb is S-Block indicating WTX */ + +#define rfalIsoDep_PCBisRACK( pcb ) ( rfalIsoDep_PCBisRBlock(pcb) && rfalIsoDep_PCBisACK(pcb) ) /*!< Checks if pcb is R-Block indicating ACK */ +#define rfalIsoDep_PCBisRNAK( pcb ) ( rfalIsoDep_PCBisRBlock(pcb) && rfalIsoDep_PCBisNAK(pcb) ) /*!< Checks if pcb is R-Block indicating NAK */ + + +#define rfalIsoDep_PCBIBlock( bn ) ( (uint8_t)( 0x00U | ISODEP_PCB_IBLOCK | ISODEP_PCB_B2_BIT | ((bn) & ISODEP_PCB_BN_MASK) )) /*!< Returns an I-Block with the given block number (bn) */ +#define rfalIsoDep_PCBIBlockChaining( bn ) ( (uint8_t)(rfalIsoDep_PCBIBlock(bn) | ISODEP_PCB_CHAINING_BIT)) /*!< Returns an I-Block with the given block number (bn) indicating chaining */ + +#define rfalIsoDep_PCBRBlock( bn ) ( (uint8_t)( 0x00U | ISODEP_PCB_RBLOCK | ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT | ((bn) & ISODEP_PCB_BN_MASK) ) ) /*!< Returns an R-Block with the given block number (bn) */ +#define rfalIsoDep_PCBRACK( bn ) ( (uint8_t)( rfalIsoDep_PCBRBlock( bn ) | ISODEP_PCB_ACK ) ) /*!< Returns an R-Block with the given block number (bn) indicating ACK */ +#define rfalIsoDep_PCBRNAK( bn ) ( (uint8_t)( rfalIsoDep_PCBRBlock( bn ) | ISODEP_PCB_NAK ) ) /*!< Returns an R-Block with the given block number (bn) indicating NAK */ + + +#define rfalIsoDep_GetBN( pcb ) ( (uint8_t) ((pcb) & ISODEP_PCB_BN_MASK ) ) /*!< Returns the block number (bn) from the given pcb */ +#define rfalIsoDep_GetWTXM( inf ) ( (uint8_t) ((inf) & ISODEP_SWTX_WTXM_MASK) ) /*!< Returns the WTX value from the given inf byte */ +#define rfalIsoDep_isWTXMValid( wtxm ) (((wtxm) >= ISODEP_WTXM_MIN) && ((wtxm) <= ISODEP_WTXM_MAX)) /*!< Checks if the given wtxm is valid */ + +#define rfalIsoDep_WTXMListenerMax( fwt ) ( RFAL_MIN( (uint8_t)(ISODEP_FWT_LIS_MAX / (fwt)), ISODEP_WTXM_MAX) ) /*!< Calculates the Max WTXM value for the given fwt as a Listener */ + +#define rfalIsoDepCalcdSGFT( s ) (384U * ((uint32_t)1U << (s))) /*!< Calculates the dSFGT with given SFGI Digital 1.1 13.8.2.1 & A.6*/ +#define rfalIsoDepCalcSGFT( s ) (4096U * ((uint32_t)1U << (s))) /*!< Calculates the SFGT with given SFGI Digital 1.1 13.8.2 */ + +#define rfalIsoDep_PCBNextBN( bn ) (((uint8_t)(bn)^0x01U) & ISODEP_PCB_BN_MASK) /*!< Returns the value of the next block number based on bn */ +#define rfalIsoDep_PCBPrevBN( bn ) rfalIsoDep_PCBNextBN(bn) /*!< Returns the value of the previous block number based on bn */ +#define rfalIsoDep_ToggleBN( bn ) ((bn) = (((bn)^0x01U) & ISODEP_PCB_BN_MASK) ) /*!< Toggles the block number value of the given bn */ + +#define rfalIsoDep_WTXAdjust( v ) ((v) - ((v)>>3)) /*!< Adjust WTX timer value to a percentage of the total, current 88% */ + + +/*! ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2 The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */ +#define rfalIsoDepReEnableRx( rxB, rxBL, rxL ) rfalTransceiveBlockingTx( NULL, 0, rxB, rxBL, rxL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FWT_NONE ) + +#define rfalIsoDepTimerStart( timer, time_ms ) do{ platformTimerDestroy( timer ); (timer) = platformTimerCreate((uint16_t)(time_ms));} while (0) /*!< Configures and starts the WTX timer */ +#define rfalIsoDepTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks WTX timer has expired */ +#define rfalIsoDepTimerDestroy( timer ) platformTimerDestroy( timer ) /*!< Destroys WTX timer */ + +/* + ****************************************************************************** + * LOCAL DATA TYPES + ****************************************************************************** + */ + + /*! Internal structure to be used in handling of S(PARAMETRS) only */ +typedef struct +{ + uint8_t pcb; /*!< PCB byte */ + rfalIsoDepSParameter sParam; /*!< S(PARAMETERS) */ +} rfalIsoDepControlMsgSParam; + +/*! Enumeration of the possible control message types */ +typedef enum +{ + ISODEP_R_ACK, /*!< R-ACK Acknowledge */ + ISODEP_R_NAK, /*!< R-NACK Negative acknowledge */ + ISODEP_S_WTX, /*!< S-WTX Waiting Time Extension */ + ISODEP_S_DSL /*!< S-DSL Deselect */ +} rfalIsoDepControlMsg; + +/*! Enumeration of the IsoDep roles */ +typedef enum +{ + ISODEP_ROLE_PCD, /*!< Perform as Reader/PCD */ + ISODEP_ROLE_PICC /*!< Perform as Card/PICC */ +} rfalIsoDepRole; + +/*! ISO-DEP layer states */ +typedef enum +{ + ISODEP_ST_IDLE, /*!< Idle State */ + ISODEP_ST_PCD_TX, /*!< PCD Transmission State */ + ISODEP_ST_PCD_RX, /*!< PCD Reception State */ + ISODEP_ST_PCD_WAIT_DSL, /*!< PCD Wait for DSL response */ + + ISODEP_ST_PICC_ACT_ATS, /*!< PICC has replied to RATS (ATS) */ + ISODEP_ST_PICC_ACT_ATTRIB, /*!< PICC has replied to ATTRIB */ + ISODEP_ST_PICC_RX, /*!< PICC Reception State */ + ISODEP_ST_PICC_SWTX, /*!< PICC Waiting Time eXtension */ + ISODEP_ST_PICC_SDSL, /*!< PICC S(DSL) response ongoing */ + ISODEP_ST_PICC_TX, /*!< PICC Transmission State */ + + ISODEP_ST_PCD_ACT_RATS, /*!< PCD activation (RATS) */ + ISODEP_ST_PCD_ACT_PPS, /*!< PCD activation (PPS) */ + +} rfalIsoDepState; + + + + +/*! Holds all ISO-DEP data(counters, buffers, ID, timeouts, frame size) */ +typedef struct{ + rfalIsoDepState state; /*!< ISO-DEP module state */ + rfalIsoDepRole role; /*!< Current ISO-DEP role */ + + uint8_t blockNumber; /*!< Current block number */ + uint8_t did; /*!< Current DID */ + uint8_t nad; /*!< Current DID */ + uint8_t cntIRetrys; /*!< I-Block retry counter */ + uint8_t cntRRetrys; /*!< R-Block retry counter */ + uint8_t cntSDslRetrys; /*!< S(DESELECT) retry counter */ + uint8_t cntSWtxRetrys; /*!< Overall S(WTX) retry counter */ + uint8_t cntSWtxNack; /*!< R(NACK) answered with S(WTX) counter */ + uint32_t fwt; /*!< Current FWT (Frame Waiting Time) */ + uint32_t dFwt; /*!< Current delta FWT */ + uint16_t fsx; /*!< Current FSx FSC or FSD (max Frame size) */ + bool isTxChaining; /*!< Flag for chaining on Tx */ + bool isRxChaining; /*!< Flag for chaining on Rx */ + uint8_t* txBuf; /*!< Tx buffer pointer */ + uint8_t* rxBuf; /*!< Rx buffer pointer */ + uint16_t txBufLen; /*!< Tx buffer length */ + uint16_t rxBufLen; /*!< Rx buffer length */ + uint8_t txBufInfPos; /*!< Start of payload in txBuf */ + uint8_t rxBufInfPos; /*!< Start of payload in rxBuf */ + + + uint16_t ourFsx; /*!< Our current FSx FSC or FSD (Frame size) */ + uint8_t lastPCB; /*!< Last PCB sent */ + uint8_t lastWTXM; /*!< Last WTXM sent */ + uint8_t atsTA; /*!< TA on ATS */ + uint8_t hdrLen; /*!< Current ISO-DEP length */ + rfalBitRate txBR; /*!< Current Tx Bit Rate */ + rfalBitRate rxBR; /*!< Current Rx Bit Rate */ + uint16_t *rxLen; /*!< Output parameter ptr to Rx length */ + bool *rxChaining; /*!< Output parameter ptr to Rx chaining flag */ + uint32_t WTXTimer; /*!< Timer used for WTX */ + bool lastDID00; /*!< Last PCD block had DID flag (for DID = 0) */ + + bool isTxPending; /*!< Flag pending Block while waiting WTX Ack */ + bool isWait4WTX; /*!< Flag for waiting WTX Ack */ + + uint8_t maxRetriesI; /*!< Number of retries for a I-Block */ + uint8_t maxRetriesR; /*!< Number of retries for a R-Block */ + uint8_t maxRetriesSDSL;/*!< Number of retries for S(DESELECT) errors */ + uint8_t maxRetriesSWTX;/*!< Number of retries for S(WTX) errors */ + uint8_t maxRetriesSnWTX;/*!< Number of retries S(WTX) replied w NACK */ + uint8_t maxRetriesRATS;/*!< Number of retries for RATS */ + + rfalComplianceMode compMode; /*!< Compliance mode */ + + uint8_t ctrlBuf[ISODEP_CONTROLMSG_BUF_LEN]; /*!< Control msg buf */ + uint16_t ctrlRxLen; /*!< Control msg rcvd len */ + + union { /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one frame at a time */ + #if RFAL_FEATURE_NFCA + rfalIsoDepRats ratsReq; + rfalIsoDepPpsReq ppsReq; + #endif /* RFAL_FEATURE_NFCA */ + + #if RFAL_FEATURE_NFCB + rfalIsoDepAttribCmd attribReq; + #endif /* RFAL_FEATURE_NFCB */ + }actv; /*!< Activation buffer */ + + uint8_t* rxLen8; /*!< Receive length (8-bit) */ + rfalIsoDepDevice* actvDev; /*!< Activation Device Info */ + rfalIsoDepListenActvParam actvParam; /*!< Listen Activation context */ + + + rfalIsoDepApduTxRxParam APDUParam; /*!< APDU TxRx params */ + uint16_t APDUTxPos; /*!< APDU Tx position */ + uint16_t APDURxPos; /*!< APDU Rx position */ + bool isAPDURxChaining; /*!< APDU Transceive chaining flag */ + +}rfalIsoDep; + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +static rfalIsoDep gIsoDep; /*!< ISO-DEP Module instance */ + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ +static void rfalIsoDepClearCounters( void ); +static ReturnCode rfalIsoDepTx( uint8_t pcb, const uint8_t* txBuf, uint8_t *infBuf, uint16_t infLen, uint32_t fwt ); +static ReturnCode rfalIsoDepHandleControlMsg( rfalIsoDepControlMsg controlMsg, uint8_t param ); +static void rfalIsoDepApdu2IBLockParam( rfalIsoDepApduTxRxParam apduParam, rfalIsoDepTxRxParam *iBlockParam, uint16_t txPos, uint16_t rxPos ); + +#if RFAL_FEATURE_ISO_DEP_POLL + static ReturnCode rfalIsoDepDataExchangePCD( uint16_t *outActRxLen, bool *outIsChaining ); + static void rfalIsoDepCalcBitRate(rfalBitRate maxAllowedBR, uint8_t piccBRCapability, rfalBitRate *dsi, rfalBitRate *dri); + static uint32_t rfalIsoDepSFGI2SFGT( uint8_t sfgi ); + + #if RFAL_FEATURE_NFCA + static ReturnCode rfalIsoDepStartRATS( rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts *ats, uint8_t *atsLen ); + static ReturnCode rfalIsoDepGetRATSStatus( void ); + static ReturnCode rfalIsoDepStartPPS( uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes *ppsRes ); + static ReturnCode rfalIsoDepGetPPSSTatus( void ); + #endif /* RFAL_FEATURE_NFCA */ + + #if RFAL_FEATURE_NFCB + static ReturnCode rfalIsoDepStartATTRIB( const uint8_t* nfcid0, uint8_t PARAM1, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepFSxI FSDI, uint8_t PARAM3, uint8_t DID, const uint8_t* HLInfo, uint8_t HLInfoLen, uint32_t fwt, rfalIsoDepAttribRes *attribRes, uint8_t *attribResLen ); + static ReturnCode rfalIsoDepGetATTRIBStatus( void ); + #endif /* RFAL_FEATURE_NFCB */ + +#endif /* RFAL_FEATURE_ISO_DEP_POLL */ + +#if RFAL_FEATURE_ISO_DEP_LISTEN + static ReturnCode rfalIsoDepDataExchangePICC( void ); + static ReturnCode rfalIsoDepReSendControlMsg( void ); +#endif + + +/* + ****************************************************************************** + * LOCAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +static void rfalIsoDepClearCounters( void ) +{ + gIsoDep.cntIRetrys = 0; + gIsoDep.cntRRetrys = 0; + gIsoDep.cntSDslRetrys = 0; + gIsoDep.cntSWtxRetrys = 0; + gIsoDep.cntSWtxNack = 0; +} + +/*******************************************************************************/ +static ReturnCode rfalIsoDepTx( uint8_t pcb, const uint8_t* txBuf, uint8_t *infBuf, uint16_t infLen, uint32_t fwt ) +{ + uint8_t *txBlock; + uint16_t txBufLen; + uint8_t computedPcb; + rfalTransceiveContext ctx; + + + txBlock = infBuf; /* Point to beginning of the INF, and go backwards */ + gIsoDep.lastPCB = pcb; /* Store the last PCB sent */ + + + if ( infLen > 0U ) + { + if ( ((uintptr_t)infBuf - (uintptr_t)txBuf) < gIsoDep.hdrLen ) /* Check that we can fit the header in the given space */ + { + return RFAL_ERR_NOMEM; + } + } + + + /*******************************************************************************/ + /* Compute optional PCB bits */ + computedPcb = pcb; + if (((gIsoDep.did != RFAL_ISODEP_NO_DID) && (gIsoDep.did != RFAL_ISODEP_DID_00)) || ((gIsoDep.did == RFAL_ISODEP_DID_00) && (gIsoDep.lastDID00)) ) { computedPcb |= ISODEP_PCB_DID_BIT; } + if (gIsoDep.nad != RFAL_ISODEP_NO_NAD) { computedPcb |= ISODEP_PCB_NAD_BIT; } + if ((gIsoDep.isTxChaining) && (rfalIsoDep_PCBisIBlock(computedPcb)) ) { computedPcb |= ISODEP_PCB_CHAINING_BIT; } + + + /*******************************************************************************/ + /* Compute Payload on the given txBuf, start by the PCB | DID | NAD | before INF */ + + if( (ISODEP_PCB_NAD_BIT & computedPcb) != 0U ) + { + *(--txBlock) = gIsoDep.nad; /* NAD is optional */ + } + + if( (ISODEP_PCB_DID_BIT & computedPcb) != 0U) + { + *(--txBlock) = gIsoDep.did; /* DID is optional */ + } + + *(--txBlock) = computedPcb; /* PCB always present */ + + txBufLen = (infLen + (uint16_t)((uintptr_t)infBuf - (uintptr_t)txBlock)); /* Calculate overall buffer size */ + + if( txBufLen > (gIsoDep.fsx - ISODEP_CRC_LEN) ) /* Check if msg length violates the maximum frame size FSC */ + { + return RFAL_ERR_NOTSUPP; + } + + + rfalCreateByteFlagsTxRxContext( ctx, txBlock, txBufLen, gIsoDep.rxBuf, gIsoDep.rxBufLen, gIsoDep.rxLen, RFAL_TXRX_FLAGS_DEFAULT, ((gIsoDep.role == ISODEP_ROLE_PICC) ? RFAL_FWT_NONE : fwt ) ); + return rfalStartTransceive( &ctx ); +} + +/*******************************************************************************/ +static ReturnCode rfalIsoDepHandleControlMsg( rfalIsoDepControlMsg controlMsg, uint8_t param ) +{ + uint8_t pcb; + uint8_t infLen; + uint32_t fwtTemp; + + infLen = 0; + fwtTemp = (gIsoDep.fwt + gIsoDep.dFwt); + RFAL_MEMSET( gIsoDep.ctrlBuf, 0x00, ISODEP_CONTROLMSG_BUF_LEN ); + + switch( controlMsg ) + { + /*******************************************************************************/ + case ISODEP_R_ACK: + + if( gIsoDep.cntRRetrys++ > gIsoDep.maxRetriesR ) + { + return RFAL_ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */ + } + + pcb = rfalIsoDep_PCBRACK( gIsoDep.blockNumber ); + break; + + + /*******************************************************************************/ + case ISODEP_R_NAK: + + if( ( gIsoDep.cntRRetrys++ > gIsoDep.maxRetriesR ) || /* Max R Block retries reached */ + ( gIsoDep.cntSWtxNack >= gIsoDep.maxRetriesSnWTX ) ) /* Max number PICC is allowed to respond with S(WTX) to R(NAK) */ + { + return RFAL_ERR_TIMEOUT; + } + + pcb = rfalIsoDep_PCBRNAK( gIsoDep.blockNumber ); + break; + + + /*******************************************************************************/ + case ISODEP_S_WTX: + + if( (gIsoDep.cntSWtxRetrys++ > gIsoDep.maxRetriesSWTX) && (gIsoDep.maxRetriesSWTX != RFAL_ISODEP_MAX_WTX_RETRYS_ULTD) ) + { + return RFAL_ERR_PROTO; + } + + /* Check if WTXM is valid */ + if( ! rfalIsoDep_isWTXMValid(param) ) + { + return RFAL_ERR_PROTO; + } + + if( gIsoDep.role == ISODEP_ROLE_PCD ) + { + /* Calculate temp Wait Time eXtension */ + fwtTemp = (gIsoDep.fwt * param); + fwtTemp = RFAL_MIN( RFAL_ISODEP_MAX_FWT, fwtTemp ); + fwtTemp += gIsoDep.dFwt; + } + + pcb = ISODEP_PCB_SWTX; + gIsoDep.ctrlBuf[ RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + infLen++] = param; + break; + + + /*******************************************************************************/ + case ISODEP_S_DSL: + + if( gIsoDep.cntSDslRetrys++ > gIsoDep.maxRetriesSDSL ) + { + return RFAL_ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */ + } + + if( gIsoDep.role == ISODEP_ROLE_PCD ) + { + /* Digital 1.0 - 13.2.7.3 Poller must wait fwtDEACTIVATION */ + fwtTemp = ISODEP_FWT_DEACTIVATION; + gIsoDep.state = ISODEP_ST_PCD_WAIT_DSL; + } + pcb = ISODEP_PCB_SDSL; + break; + + /*******************************************************************************/ + default: + return RFAL_ERR_INTERNAL; + } + + return rfalIsoDepTx( pcb, gIsoDep.ctrlBuf, &gIsoDep.ctrlBuf[RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN], infLen, fwtTemp ); +} + +#if RFAL_FEATURE_ISO_DEP_LISTEN +/*******************************************************************************/ +static ReturnCode rfalIsoDepReSendControlMsg( void ) +{ + if( rfalIsoDep_PCBisRACK( gIsoDep.lastPCB ) ) + { + return rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ); + } + + if( rfalIsoDep_PCBisRNAK( gIsoDep.lastPCB ) ) + { + return rfalIsoDepHandleControlMsg( ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM ); + } + + if( rfalIsoDep_PCBisSDeselect( gIsoDep.lastPCB ) ) + { + return rfalIsoDepHandleControlMsg( ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM ); + } + + if( rfalIsoDep_PCBisSWTX( gIsoDep.lastPCB ) ) + { + return rfalIsoDepHandleControlMsg( ISODEP_S_WTX, gIsoDep.lastWTXM ); + } + return RFAL_ERR_WRONG_STATE; +} +#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + +/*******************************************************************************/ +void rfalIsoDepInitialize( void ) +{ + gIsoDep.state = ISODEP_ST_IDLE; + gIsoDep.role = ISODEP_ROLE_PCD; + gIsoDep.did = RFAL_ISODEP_NO_DID; + gIsoDep.nad = RFAL_ISODEP_NO_NAD; + gIsoDep.blockNumber = 0; + gIsoDep.isTxChaining = false; + gIsoDep.isRxChaining = false; + gIsoDep.lastDID00 = false; + gIsoDep.lastPCB = ISODEP_PCB_INVALID; + gIsoDep.fsx = (uint16_t)RFAL_ISODEP_FSX_16; + gIsoDep.ourFsx = (uint16_t)RFAL_ISODEP_FSX_16; + gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN; + + gIsoDep.rxLen = NULL; + gIsoDep.rxBuf = NULL; + gIsoDep.rxBufInfPos = 0U; + gIsoDep.txBufInfPos = 0U; + + gIsoDep.isTxPending = false; + gIsoDep.isWait4WTX = false; + + gIsoDep.compMode = RFAL_COMPLIANCE_MODE_NFC; + gIsoDep.maxRetriesR = RFAL_ISODEP_MAX_R_RETRYS; + gIsoDep.maxRetriesI = RFAL_ISODEP_MAX_I_RETRYS; + gIsoDep.maxRetriesSDSL = RFAL_ISODEP_MAX_DSL_RETRYS; + gIsoDep.maxRetriesSWTX = RFAL_ISODEP_MAX_WTX_RETRYS; + gIsoDep.maxRetriesSnWTX = RFAL_ISODEP_MAX_WTX_NACK_RETRYS; + gIsoDep.maxRetriesRATS = RFAL_ISODEP_RATS_RETRIES; + + gIsoDep.APDURxPos = 0; + gIsoDep.APDUTxPos = 0; + gIsoDep.APDUParam.rxLen = NULL; + gIsoDep.APDUParam.rxBuf = NULL; + gIsoDep.APDUParam.txBuf = NULL; + + rfalIsoDepClearCounters(); + + /* Destroy any ongoing WTX timer */ + rfalIsoDepTimerDestroy( gIsoDep.WTXTimer ); + gIsoDep.WTXTimer = 0U; +} + + +/*******************************************************************************/ +void rfalIsoDepInitializeWithParams( rfalComplianceMode compMode, + uint8_t maxRetriesR, + uint8_t maxRetriesSnWTX, + uint8_t maxRetriesSWTX, + uint8_t maxRetriesSDSL, + uint8_t maxRetriesI, + uint8_t maxRetriesRATS ) +{ + rfalIsoDepInitialize(); + + gIsoDep.compMode = compMode; + gIsoDep.maxRetriesR = maxRetriesR; + gIsoDep.maxRetriesSnWTX = maxRetriesSnWTX; + gIsoDep.maxRetriesSWTX = maxRetriesSWTX; + gIsoDep.maxRetriesSDSL = maxRetriesSDSL; + gIsoDep.maxRetriesI = maxRetriesI; + gIsoDep.maxRetriesRATS = maxRetriesRATS; +} + + +#if RFAL_FEATURE_ISO_DEP_POLL +/*******************************************************************************/ +static ReturnCode rfalIsoDepDataExchangePCD( uint16_t *outActRxLen, bool *outIsChaining ) +{ + ReturnCode ret; + uint8_t rxPCB; + + /* Check out parameters */ + if( (outActRxLen == NULL) || (outIsChaining == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *outIsChaining = false; + + /* Calculate header required and check if the buffers InfPositions are suitable */ + gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN; + if ((gIsoDep.did != RFAL_ISODEP_NO_DID) && (gIsoDep.did != RFAL_ISODEP_DID_00)) { gIsoDep.hdrLen += RFAL_ISODEP_DID_LEN; } + if (gIsoDep.nad != RFAL_ISODEP_NO_NAD) { gIsoDep.hdrLen += RFAL_ISODEP_NAD_LEN; } + + /* Check if there is enough space before the infPos to append ISO-DEP headers on rx and tx */ + if( (gIsoDep.rxBufInfPos < gIsoDep.hdrLen) || (gIsoDep.txBufInfPos < gIsoDep.hdrLen) ) + { + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + switch( gIsoDep.state ) + { + /*******************************************************************************/ + case ISODEP_ST_IDLE: + return RFAL_ERR_NONE; + + /*******************************************************************************/ + case ISODEP_ST_PCD_TX: + ret = rfalIsoDepTx( rfalIsoDep_PCBIBlock( gIsoDep.blockNumber ), gIsoDep.txBuf, &gIsoDep.txBuf[gIsoDep.txBufInfPos], gIsoDep.txBufLen, (gIsoDep.fwt + gIsoDep.dFwt) ); + switch( ret ) + { + case RFAL_ERR_NONE: + gIsoDep.state = ISODEP_ST_PCD_RX; + break; + + default: + return ret; + } + /* fall through */ + + /*******************************************************************************/ + case ISODEP_ST_PCD_WAIT_DSL: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + case ISODEP_ST_PCD_RX: + + ret = rfalGetTransceiveStatus(); + switch( ret ) + { + /* Data rcvd with error or timeout -> Send R-NAK */ + case RFAL_ERR_TIMEOUT: + case RFAL_ERR_CRC: + case RFAL_ERR_PAR: + case RFAL_ERR_FRAMING: /* added to handle test cases scenario TC_POL_NFCB_T4AT_BI_82_x_y & TC_POL_NFCB_T4BT_BI_82_x_y */ + case RFAL_ERR_INCOMPLETE_BYTE: /* added to handle test cases scenario TC_POL_NFCB_T4AT_BI_82_x_y & TC_POL_NFCB_T4BT_BI_82_x_y */ + + if( gIsoDep.isRxChaining ) + { /* Rule 5 - In PICC chaining when a invalid/timeout occurs -> R-ACK */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ) ); + } + else if( gIsoDep.state == ISODEP_ST_PCD_WAIT_DSL ) + { /* Rule 8 - If s-Deselect response fails MAY retransmit */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM ) ); + } + else + { /* Rule 4 - When a invalid block or timeout occurs -> R-NACK */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM ) ); + } + return RFAL_ERR_BUSY; + + case RFAL_ERR_NONE: + break; + + case RFAL_ERR_BUSY: + return RFAL_ERR_BUSY; /* Debug purposes */ + + default: + return ret; + } + + /*******************************************************************************/ + /* No error, process incoming msg */ + /*******************************************************************************/ + + (*outActRxLen) = rfalConvBitsToBytes( *outActRxLen ); + + + /* Check rcvd msg length, cannot be less then the expected header */ + if( ((*outActRxLen) < gIsoDep.hdrLen) || ((*outActRxLen) >= gIsoDep.ourFsx) ) + { + return RFAL_ERR_PROTO; + } + + /* Grab rcvd PCB */ + rxPCB = gIsoDep.rxBuf[ ISODEP_PCB_POS ]; + + + /* EMVCo doesn't allow usage of for CID or NAD EMVCo 2.6 TAble 10.2 */ + if( (gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) && ( rfalIsoDep_PCBhasDID(rxPCB) || rfalIsoDep_PCBhasNAD(rxPCB)) ) + { + return RFAL_ERR_PROTO; + } + + /* If we are expecting DID, check if PCB signals its presence and if device ID match*/ + if( (gIsoDep.did != RFAL_ISODEP_NO_DID) && (gIsoDep.did != RFAL_ISODEP_DID_00) && ( (!rfalIsoDep_PCBhasDID(rxPCB)) || (gIsoDep.did != gIsoDep.rxBuf[ ISODEP_DID_POS ])) ) + { + return RFAL_ERR_PROTO; + } + + + /*******************************************************************************/ + /* Process S-Block */ + /*******************************************************************************/ + if( rfalIsoDep_PCBisSBlock(rxPCB) ) + { + /* Check if is a Wait Time eXtension */ + if( rfalIsoDep_PCBisSWTX(rxPCB) ) + { + /* Check if PICC has requested S(WTX) as response to R(NAK) EMVCo 3.0 10.3.5.5 / Digital 2.0 16.2.6.5 */ + if( rfalIsoDep_PCBisRNAK( gIsoDep.lastPCB ) ) + { + gIsoDep.cntSWtxNack++; /* Count S(WTX) upon R(NAK) */ + gIsoDep.cntRRetrys = 0; /* Reset R-Block counter has PICC has responded */ + } + else + { + gIsoDep.cntSWtxNack = 0; /* Reset R(NACK)->S(WTX) counter */ + } + + /* Rule 3 - respond to S-block: get 1st INF byte S(STW): Power + WTXM */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_S_WTX, rfalIsoDep_GetWTXM(gIsoDep.rxBuf[gIsoDep.hdrLen]) ) ); + return RFAL_ERR_BUSY; + } + + /* Check if is a deselect response */ + if( rfalIsoDep_PCBisSDeselect(rxPCB) ) + { + if( gIsoDep.state == ISODEP_ST_PCD_WAIT_DSL ) + { + rfalIsoDepInitialize(); /* Session finished reInit vars */ + return RFAL_ERR_NONE; + } + + /* Deselect response not expected */ + /* fall through to PROTO error */ + } + /* Unexpected S-Block */ + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Process R-Block */ + /*******************************************************************************/ + else if( rfalIsoDep_PCBisRBlock(rxPCB) ) + { + if( rfalIsoDep_PCBisRACK(rxPCB) ) /* Check if is a R-ACK */ + { + if( rfalIsoDep_GetBN(rxPCB) == gIsoDep.blockNumber ) /* Expected block number */ + { + /* Rule B - ACK with expected bn -> Increment block number */ + gIsoDep.blockNumber = rfalIsoDep_PCBNextBN( gIsoDep.blockNumber ); + + /* R-ACK only allowed when PCD chaining */ + if( !gIsoDep.isTxChaining ) + { + return RFAL_ERR_PROTO; + } + + /* Rule 7 - Chaining transaction done, continue chaining */ + rfalIsoDepClearCounters(); + return RFAL_ERR_NONE; /* This block has been transmitted */ + } + else + { + /* Rule 6 - R-ACK with wrong block number retransmit */ + /* Digital 2.0 16.2.5.4 - Retransmit maximum two times */ + /* EMVCo 3.0 10.3.4.3 - PCD may re-transmit the last I-Block or report error */ + if( gIsoDep.cntIRetrys++ < gIsoDep.maxRetriesI ) + { + gIsoDep.cntRRetrys = 0; /* Clear R counter only */ + gIsoDep.state = ISODEP_ST_PCD_TX; + return RFAL_ERR_BUSY; + } + return RFAL_ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */ + } + } + else /* Unexcpected R-Block */ + { + return RFAL_ERR_PROTO; + } + } + + /*******************************************************************************/ + /* Process I-Block */ + /*******************************************************************************/ + else if( rfalIsoDep_PCBisIBlock(rxPCB) ) + { + /*******************************************************************************/ + /* is PICC performing chaining */ + if( rfalIsoDep_PCBisChaining(rxPCB) ) + { + gIsoDep.isRxChaining = true; + *outIsChaining = true; + + if( rfalIsoDep_GetBN(rxPCB) == gIsoDep.blockNumber ) + { + /* Rule B - ACK with correct block number -> Increase Block number */ + rfalIsoDep_ToggleBN( gIsoDep.blockNumber ); + + rfalIsoDepClearCounters(); /* Clear counters in case R counter is already at max */ + + /* Rule 2 - Send ACK */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ) ); + + /* Received I-Block with chaining, send current data to DH */ + + /* remove ISO DEP header, check is necessary to move the INF data on the buffer */ + *outActRxLen -= gIsoDep.hdrLen; + if( (gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*outActRxLen > 0U) ) + { + RFAL_MEMMOVE( &gIsoDep.rxBuf[gIsoDep.rxBufInfPos], &gIsoDep.rxBuf[gIsoDep.hdrLen], *outActRxLen ); + } + + rfalIsoDepClearCounters(); + return RFAL_ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived */ + } + else + { + /* Rule 5 - PICC chaining invalid I-Block -> R-ACK */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ) ); + } + return RFAL_ERR_BUSY; + } + + gIsoDep.isRxChaining = false; /* clear PICC chaining flag */ + + if( rfalIsoDep_GetBN(rxPCB) == gIsoDep.blockNumber ) + { + /* Rule B - I-Block with correct block number -> Increase Block number */ + rfalIsoDep_ToggleBN( gIsoDep.blockNumber ); + + /* I-Block transaction done successfully */ + + /* remove ISO DEP header, check is necessary to move the INF data on the buffer */ + *outActRxLen -= gIsoDep.hdrLen; + if( (gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*outActRxLen > 0U) ) + { + RFAL_MEMMOVE( &gIsoDep.rxBuf[gIsoDep.rxBufInfPos], &gIsoDep.rxBuf[gIsoDep.hdrLen], *outActRxLen ); + } + + gIsoDep.state = ISODEP_ST_IDLE; + rfalIsoDepClearCounters(); + return RFAL_ERR_NONE; + } + else + { + if( (gIsoDep.compMode != RFAL_COMPLIANCE_MODE_ISO) ) + { + /* Invalid Block (not chaining) -> Raise error Digital 1.1 15.2.6.4 EMVCo 2.6 10.3.5.4 */ + return RFAL_ERR_PROTO; + } + + /* Rule 4 - Invalid Block -> R-NAK */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM ) ); + return RFAL_ERR_BUSY; + } + } + else /* not S/R/I - Block */ + { + return RFAL_ERR_PROTO; + } + /* fall through */ + + /*******************************************************************************/ + default: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + /* MISRA 16.4: no empty default (comment will suffice) */ + break; + } + + return RFAL_ERR_INTERNAL; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepDeselect( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartDeselect() ); + rfalRunBlocking( ret, rfalIsoDepGetDeselectStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepStartDeselect( void ) +{ + /*******************************************************************************/ + /* Using local static vars and static config to cope with a Deselect after * + * RATS\ATTRIB without any I-Block exchanged */ + gIsoDep.rxLen = &gIsoDep.ctrlRxLen; + gIsoDep.rxBuf = gIsoDep.ctrlBuf; + gIsoDep.rxBufLen = ISODEP_CONTROLMSG_BUF_LEN - (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN); + gIsoDep.rxBufInfPos = (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN); + gIsoDep.txBufInfPos = (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN); + + + /* Send DSL request */ + return rfalIsoDepHandleControlMsg( ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM ); +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepGetDeselectStatus( void ) +{ + ReturnCode ret; + bool dummyB; + + RFAL_EXIT_ON_BUSY( ret, rfalIsoDepDataExchangePCD( gIsoDep.rxLen, &dummyB ) ); + + rfalIsoDepInitialize(); + return ret; +} + +#endif /* RFAL_FEATURE_ISO_DEP_POLL */ + + +/*******************************************************************************/ +uint32_t rfalIsoDepFWI2FWT( uint8_t fwi ) +{ + uint32_t result; + uint8_t tmpFWI; + + tmpFWI = fwi; + + /* RFU values -> take the default value + * Digital 1.0 11.6.2.17 FWI[1,14] + * Digital 1.1 7.6.2.22 FWI[0,14] + * EMVCo 2.6 Table A.5 FWI[0,14] */ + if( tmpFWI > ISODEP_FWI_MAX ) + { + tmpFWI = RFAL_ISODEP_FWI_DEFAULT; + } + + /* FWT = (256 x 16/fC) x 2^FWI => 2^(FWI+12) Digital 1.1 13.8.1 & 7.9.1 */ + + result = ((uint32_t)1U << (tmpFWI + 12U)); + result = RFAL_MIN( RFAL_ISODEP_MAX_FWT, result); /* Maximum Frame Waiting Time must be fulfilled */ + + return result; +} + + +/*******************************************************************************/ +uint16_t rfalIsoDepFSxI2FSx( uint8_t FSxI ) +{ + uint16_t fsx; + uint8_t fsi; + + /* Enforce maximum FSxI/FSx allowed - NFC Forum and EMVCo differ */ + fsi = (( gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV ) ? RFAL_MIN( FSxI, RFAL_ISODEP_FSDI_MAX_EMV ) : RFAL_MIN( FSxI, RFAL_ISODEP_FSDI_MAX_NFC )); + + switch( fsi ) + { + case (uint8_t)RFAL_ISODEP_FSXI_16: fsx = (uint16_t)RFAL_ISODEP_FSX_16; break; + case (uint8_t)RFAL_ISODEP_FSXI_24: fsx = (uint16_t)RFAL_ISODEP_FSX_24; break; + case (uint8_t)RFAL_ISODEP_FSXI_32: fsx = (uint16_t)RFAL_ISODEP_FSX_32; break; + case (uint8_t)RFAL_ISODEP_FSXI_40: fsx = (uint16_t)RFAL_ISODEP_FSX_40; break; + case (uint8_t)RFAL_ISODEP_FSXI_48: fsx = (uint16_t)RFAL_ISODEP_FSX_48; break; + case (uint8_t)RFAL_ISODEP_FSXI_64: fsx = (uint16_t)RFAL_ISODEP_FSX_64; break; + case (uint8_t)RFAL_ISODEP_FSXI_96: fsx = (uint16_t)RFAL_ISODEP_FSX_96; break; + case (uint8_t)RFAL_ISODEP_FSXI_128: fsx = (uint16_t)RFAL_ISODEP_FSX_128; break; + case (uint8_t)RFAL_ISODEP_FSXI_256: fsx = (uint16_t)RFAL_ISODEP_FSX_256; break; + case (uint8_t)RFAL_ISODEP_FSXI_512: fsx = (uint16_t)RFAL_ISODEP_FSX_512; break; + case (uint8_t)RFAL_ISODEP_FSXI_1024: fsx = (uint16_t)RFAL_ISODEP_FSX_1024; break; + case (uint8_t)RFAL_ISODEP_FSXI_2048: fsx = (uint16_t)RFAL_ISODEP_FSX_2048; break; + case (uint8_t)RFAL_ISODEP_FSXI_4096: fsx = (uint16_t)RFAL_ISODEP_FSX_4096; break; + default: fsx = (uint16_t)RFAL_ISODEP_FSX_256; break; + } + return fsx; +} + + +#if RFAL_FEATURE_ISO_DEP_LISTEN + +/*******************************************************************************/ +bool rfalIsoDepIsRats( const uint8_t *buf, uint8_t bufLen ) +{ + if(buf != NULL) + { + if ((RFAL_ISODEP_CMD_RATS == (uint8_t)*buf) && (sizeof(rfalIsoDepRats) == bufLen)) + { + return true; + } + } + return false; +} + + +/*******************************************************************************/ +bool rfalIsoDepIsAttrib( const uint8_t *buf, uint8_t bufLen ) +{ + if(buf != NULL) + { + if ( (RFAL_ISODEP_CMD_ATTRIB == (uint8_t)*buf) && + (RFAL_ISODEP_ATTRIB_REQ_MIN_LEN <= bufLen) && + ((RFAL_ISODEP_ATTRIB_REQ_MIN_LEN + RFAL_ISODEP_ATTRIB_HLINFO_LEN) >= bufLen) ) + { + return true; + } + } + return false; +} + + + +/*******************************************************************************/ +ReturnCode rfalIsoDepListenStartActivation( rfalIsoDepAtsParam *atsParam, const rfalIsoDepAttribResParam *attribResParam, const uint8_t *buf, uint16_t bufLen, rfalIsoDepListenActvParam actParam) +{ + uint8_t *txBuf; + uint8_t bufIt; + const uint8_t *buffer = buf; + + /*******************************************************************************/ + bufIt = 0; + txBuf = (uint8_t*)actParam.rxBuf; /* Use the rxBuf as TxBuf as well, the struct enforces a size enough RFAL_MAX( NFCA_ATS_MAX_LEN, NFCB_ATTRIB_RES_MAX_LEN ) */ + gIsoDep.txBR = RFAL_BR_106; + gIsoDep.rxBR = RFAL_BR_106; + + /* Check for a valid buffer pointer */ + if( buffer == NULL ) + { + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + if( *buffer == RFAL_ISODEP_CMD_RATS ) + { + /* Check ATS parameters */ + if( atsParam == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* If requested copy RATS to device info */ + if( actParam.isoDepDev != NULL ) + { + RFAL_MEMCPY( (uint8_t*)&actParam.isoDepDev->activation.A.Poller.RATS, buffer, sizeof(rfalIsoDepRats) ); /* Copy RATS' CMD + PARAM */ + } + + + /*******************************************************************************/ + /* Process RATS */ + buffer++; + gIsoDep.fsx = rfalIsoDepFSxI2FSx( (((*buffer) & RFAL_ISODEP_RATS_PARAM_FSDI_MASK) >> RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) ); + gIsoDep.did = (*buffer & RFAL_ISODEP_DID_MASK); + + + /*******************************************************************************/ + /* Digital 1.1 13.6.1.8 - DID has to between 0 and 14 */ + if( gIsoDep.did > RFAL_ISODEP_DID_MAX ) + { + return RFAL_ERR_PROTO; + } + + /* Check if we are configured to support DID */ + if(!atsParam->didSupport) + { + gIsoDep.did = RFAL_ISODEP_NO_DID; /* Even if requested by PCD to use a certain DID, the ATS setting prevails */ + } + + + /*******************************************************************************/ + /* Check RFAL supported bit rates */ + if( ((!RFAL_SUPPORT_BR_CE_A_212) && (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_212) != 0U) || ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_212) != 0U))) || + ((!RFAL_SUPPORT_BR_CE_A_424) && (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_424) != 0U) || ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_424) != 0U))) || + ((!RFAL_SUPPORT_BR_CE_A_848) && (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_848) != 0U) || ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_848) != 0U))) ) + { + return RFAL_ERR_NOTSUPP; + } + + /* Enforce proper FWI configuration */ + if( atsParam->fwi > ISODEP_FWI_LIS_MAX) + { + atsParam->fwi = ISODEP_FWI_LIS_MAX; + } + + gIsoDep.atsTA = atsParam->ta; + gIsoDep.fwt = rfalIsoDepFWI2FWT(atsParam->fwi); + gIsoDep.ourFsx = rfalIsoDepFSxI2FSx(atsParam->fsci); + + + /* Ensure proper/maximum Historical Bytes length */ + atsParam->hbLen = RFAL_MIN( RFAL_ISODEP_ATS_HB_MAX_LEN, atsParam->hbLen ); + + /*******************************************************************************/ + /* Compute ATS */ + + txBuf[ bufIt++ ] = (RFAL_ISODEP_ATS_HIST_OFFSET + atsParam->hbLen); /* TL */ + txBuf[ bufIt++ ] = ( (RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK | RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK | + RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK)| atsParam->fsci ); /* T0 */ + txBuf[ bufIt++ ] = atsParam->ta; /* TA */ + txBuf[ bufIt++ ] = ( (atsParam->fwi << RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) | + (atsParam->sfgi & RFAL_ISODEP_RATS_PARAM_FSDI_MASK) ); /* TB */ + txBuf[ bufIt++ ] = (uint8_t)((atsParam->didSupport) ? RFAL_ISODEP_ATS_TC_DID : 0U); /* TC */ + + if( atsParam->hbLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( &txBuf[bufIt], atsParam->hb, atsParam->hbLen ); /* T1-Tk */ + bufIt += atsParam->hbLen; + } + + gIsoDep.state = ISODEP_ST_PICC_ACT_ATS; + + } + /*******************************************************************************/ + else if( *buffer == RFAL_ISODEP_CMD_ATTRIB ) + { + /* Check ATTRIB parameters */ + if( attribResParam == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* REMARK: ATTRIB handling */ + RFAL_NO_WARNING(attribResParam); + RFAL_NO_WARNING(bufLen); + return RFAL_ERR_NOT_IMPLEMENTED; + } + else + { + return RFAL_ERR_PARAM; + } + + gIsoDep.actvParam = actParam; + + + /*******************************************************************************/ + /* If requested copy to ISO-DEP device info */ + if( actParam.isoDepDev != NULL ) + { + actParam.isoDepDev->info.DID = gIsoDep.did; + actParam.isoDepDev->info.FSx = gIsoDep.fsx; + actParam.isoDepDev->info.FWT = gIsoDep.fwt; + actParam.isoDepDev->info.dFWT = 0; + actParam.isoDepDev->info.DSI = gIsoDep.txBR; + actParam.isoDepDev->info.DRI = gIsoDep.rxBR; + } + + return rfalTransceiveBlockingTx( txBuf, bufIt, (uint8_t*)actParam.rxBuf, sizeof( rfalIsoDepBufFormat ), actParam.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FWT_NONE ); +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepListenGetActivationStatus( void ) +{ + ReturnCode err; + uint8_t* txBuf; + uint8_t bufIt; + + rfalBitRate dsi; + rfalBitRate dri; + + + /* Check if Activation is running */ + if( gIsoDep.state < ISODEP_ST_PICC_ACT_ATS ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check if Activation has finished already */ + if( gIsoDep.state >= ISODEP_ST_PICC_RX ) + { + return RFAL_ERR_NONE; + } + + + /*******************************************************************************/ + /* Check for incoming msg */ + err = rfalGetTransceiveStatus(); + switch( err ) + { + /*******************************************************************************/ + case RFAL_ERR_NONE: + break; + + /*******************************************************************************/ + case RFAL_ERR_LINK_LOSS: + case RFAL_ERR_BUSY: + case RFAL_ERR_SLEEP_REQ: /* S(DSL) handled by lower layer should cause an error reported */ + return err; + + /*******************************************************************************/ + case RFAL_ERR_CRC: + case RFAL_ERR_PAR: + case RFAL_ERR_FRAMING: + + /* ISO14443 4 5.6.2.2 2 If ATS has been replied upon a invalid block, PICC disables the PPS responses */ + if( gIsoDep.state == ISODEP_ST_PICC_ACT_ATS ) + { + gIsoDep.state = ISODEP_ST_PICC_RX; + break; + } + /* fall through */ + + /*******************************************************************************/ + default: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + /* ReEnable the receiver and wait for another frame */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen ); + + return RFAL_ERR_BUSY; + } + + + txBuf = (uint8_t*)gIsoDep.actvParam.rxBuf; /* Use the rxBuf as TxBuf as well, the struct enforces a size enough RFAL_MAX(NFCA_PPS_RES_LEN, ISODEP_DSL_MAX_LEN) */ + dri = RFAL_BR_KEEP; /* The RFAL_BR_KEEP is used to check if PPS with BR change was requested */ + dsi = RFAL_BR_KEEP; /* MISRA 9.1 */ + bufIt = 0; + + + /*******************************************************************************/ + gIsoDep.role = ISODEP_ROLE_PICC; + + /*******************************************************************************/ + if( gIsoDep.state == ISODEP_ST_PICC_ACT_ATS ) + { + /* Check for a PPS ISO 14443-4 5.3 */ + if( ( ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS] & RFAL_ISODEP_PPS_MASK) == RFAL_ISODEP_PPS_SB ) + { + /* ISO 14443-4 5.3.1 Check if the we are the addressed DID/CID */ + /* ISO 14443-4 5.3.2 Check for a valid PPS0 */ + if( (( ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS] & RFAL_ISODEP_DID_MASK) != gIsoDep.did) || + (( ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS0_POS] & RFAL_ISODEP_PPS0_VALID_MASK) != RFAL_ISODEP_PPS0_PPS1_NOT_PRESENT) ) + { + /* Invalid DID on PPS request or Invalid PPS0, reEnable the receiver and wait another frame */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen ); + + return RFAL_ERR_BUSY; + } + + /*******************************************************************************/ + /* Check PPS1 presence */ + if( ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS0_POS] == RFAL_ISODEP_PPS0_PPS1_PRESENT ) + { + uint8_t newdri = ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS1_POS] & RFAL_ISODEP_PPS1_DxI_MASK; /* MISRA 10.8 */ + uint8_t newdsi = (((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS1_POS] >> RFAL_ISODEP_PPS1_DSI_SHIFT) & RFAL_ISODEP_PPS1_DxI_MASK; /* MISRA 10.8 */ + /* PRQA S 4342 2 # MISRA 10.5 - Layout of enum rfalBitRate and above masks guarantee no invalid enum values to be created */ + dri = (rfalBitRate) (newdri); + dsi = (rfalBitRate) (newdsi); + + if( ((!(RFAL_SUPPORT_BR_CE_A_106)) && (( dsi == RFAL_BR_106 ) || ( dri == RFAL_BR_106 ))) || + ((!(RFAL_SUPPORT_BR_CE_A_212)) && (( dsi == RFAL_BR_212 ) || ( dri == RFAL_BR_212 ))) || + ((!(RFAL_SUPPORT_BR_CE_A_424)) && (( dsi == RFAL_BR_424 ) || ( dri == RFAL_BR_424 ))) || + ((!(RFAL_SUPPORT_BR_CE_A_848)) && (( dsi == RFAL_BR_848 ) || ( dri == RFAL_BR_848 ))) ) + { + return RFAL_ERR_PROTO; + } + } + + /*******************************************************************************/ + /* Compute and send PPS RES / Ack */ + txBuf[ bufIt++ ] = ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS]; + + rfalTransceiveBlockingTx( txBuf, bufIt, (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FWT_NONE ); + + /*******************************************************************************/ + /* Exchange the bit rates if requested */ + if( dri != RFAL_BR_KEEP ) + { + rfalSetBitRate( dsi, dri ); + + gIsoDep.txBR = dsi; /* DSI codes the divisor from PICC to PCD */ + gIsoDep.rxBR = dri; /* DRI codes the divisor from PCD to PICC */ + + + if(gIsoDep.actvParam.isoDepDev != NULL) + { + gIsoDep.actvParam.isoDepDev->info.DSI = dsi; + gIsoDep.actvParam.isoDepDev->info.DRI = dri; + } + } + } + /* Check for a S-Deselect is done on Data Exchange Activity */ + } + + /*******************************************************************************/ + gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN; + gIsoDep.hdrLen += RFAL_ISODEP_DID_LEN; /* Always assume DID to be aligned with Digital 1.1 15.1.2 and ISO14443 4 5.6.3 #454 */ + gIsoDep.hdrLen += (uint8_t)((gIsoDep.nad != RFAL_ISODEP_NO_NAD) ? RFAL_ISODEP_NAD_LEN : 0U); + + /*******************************************************************************/ + /* Rule C - The PICC block number shall be initialized to 1 at activation */ + gIsoDep.blockNumber = 1; + + /* Activation done, keep the rcvd data in, reMap the activation buffer to the global to be retrieved by the DEP method */ + gIsoDep.rxBuf = (uint8_t*)gIsoDep.actvParam.rxBuf; + gIsoDep.rxBufLen = sizeof( rfalIsoDepBufFormat ); + gIsoDep.rxBufInfPos = (uint8_t)((uint32_t)gIsoDep.actvParam.rxBuf->inf - (uint32_t)gIsoDep.actvParam.rxBuf->prologue); + gIsoDep.rxLen = gIsoDep.actvParam.rxLen; + gIsoDep.rxChaining = gIsoDep.actvParam.isRxChaining; + + gIsoDep.state = ISODEP_ST_PICC_RX; + return RFAL_ERR_NONE; +} + +#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + + +/*******************************************************************************/ +uint16_t rfalIsoDepGetMaxInfLen( void ) +{ + /* Check whether all parameters are valid, otherwise return minimum default value */ + if( (gIsoDep.fsx < (uint16_t)RFAL_ISODEP_FSX_16) || (gIsoDep.fsx > (uint16_t)RFAL_ISODEP_FSX_4096) || (gIsoDep.hdrLen > ISODEP_HDR_MAX_LEN) ) + { + const uint16_t aux = (uint16_t)RFAL_ISODEP_FSX_16; /* MISRA 10.1 */ + return (aux - RFAL_ISODEP_PCB_LEN - ISODEP_CRC_LEN); + } + + return (gIsoDep.fsx - gIsoDep.hdrLen - ISODEP_CRC_LEN); +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepStartTransceive( rfalIsoDepTxRxParam param ) +{ + gIsoDep.txBuf = param.txBuf->prologue; + gIsoDep.txBufInfPos = (uint8_t)((uintptr_t)param.txBuf->inf - (uintptr_t)param.txBuf->prologue); + gIsoDep.txBufLen = param.txBufLen; + gIsoDep.isTxChaining = param.isTxChaining; + + gIsoDep.rxBuf = param.rxBuf->prologue; + gIsoDep.rxBufInfPos = (uint8_t)((uintptr_t)param.rxBuf->inf - (uintptr_t)param.rxBuf->prologue); + gIsoDep.rxBufLen = sizeof(rfalIsoDepBufFormat); + + gIsoDep.rxLen = param.rxLen; + gIsoDep.rxChaining = param.isRxChaining; + + + gIsoDep.fwt = param.FWT; + gIsoDep.dFwt = param.dFWT; + gIsoDep.fsx = param.FSx; + gIsoDep.did = param.DID; + + /* Only change the FSx from activation if no to Keep */ + gIsoDep.ourFsx = (( param.ourFSx != RFAL_ISODEP_FSX_KEEP ) ? param.ourFSx : gIsoDep.ourFsx); + + /* Clear inner control params for next dataExchange */ + gIsoDep.isRxChaining = false; + rfalIsoDepClearCounters(); + + if(gIsoDep.role == ISODEP_ROLE_PICC) + { + if(gIsoDep.txBufLen > 0U) + { + /* Ensure that an RTOX Ack is not being expected at moment */ + if( !gIsoDep.isWait4WTX ) + { + gIsoDep.state = ISODEP_ST_PICC_TX; + return RFAL_ERR_NONE; + } + else + { + /* If RTOX Ack is expected, signal a pending Tx to be transmitted right after */ + gIsoDep.isTxPending = true; + } + } + + /* Digital 1.1 15.2.5.1 The first block SHALL be sent by the Reader/Writer */ + gIsoDep.state = ISODEP_ST_PICC_RX; + return RFAL_ERR_NONE; + } + + gIsoDep.state = ISODEP_ST_PCD_TX; + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepGetTransceiveStatus( void ) +{ + if( gIsoDep.role == ISODEP_ROLE_PICC) + { +#if RFAL_FEATURE_ISO_DEP_LISTEN + return rfalIsoDepDataExchangePICC(); +#else + return RFAL_ERR_NOTSUPP; +#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + } + else + { +#if RFAL_FEATURE_ISO_DEP_POLL + return rfalIsoDepDataExchangePCD( gIsoDep.rxLen, gIsoDep.rxChaining ); +#else + return RFAL_ERR_NOTSUPP; +#endif /* RFAL_FEATURE_ISO_DEP_POLL */ + } +} + + +#if RFAL_FEATURE_ISO_DEP_LISTEN + +/*******************************************************************************/ +static ReturnCode rfalIsoDepDataExchangePICC( void ) +{ + uint8_t rxPCB; + ReturnCode ret; + + switch( gIsoDep.state ) + { + /*******************************************************************************/ + case ISODEP_ST_IDLE: + return RFAL_ERR_NONE; + + + /*******************************************************************************/ + case ISODEP_ST_PICC_TX: + + ret = rfalIsoDepTx( rfalIsoDep_PCBIBlock( gIsoDep.blockNumber ), gIsoDep.txBuf, &gIsoDep.txBuf[gIsoDep.txBufInfPos], gIsoDep.txBufLen, RFAL_FWT_NONE ); + + /* Clear pending Tx flag */ + gIsoDep.isTxPending = false; + + switch( ret ) + { + case RFAL_ERR_NONE: + gIsoDep.state = ISODEP_ST_PICC_RX; + return RFAL_ERR_BUSY; + + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + return ret; + + + /*******************************************************************************/ + case ISODEP_ST_PICC_RX: + + ret = rfalGetTransceiveStatus(); + switch( ret ) + { + /*******************************************************************************/ + /* Data rcvd with error or timeout -> mute */ + case RFAL_ERR_TIMEOUT: + case RFAL_ERR_CRC: + case RFAL_ERR_PAR: + case RFAL_ERR_FRAMING: + + /* Digital 1.1 - 15.2.6.2 The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.rxLen ); + + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case RFAL_ERR_LINK_LOSS: + return ret; /* Debug purposes */ + + case RFAL_ERR_BUSY: + return ret; /* Debug purposes */ + + /*******************************************************************************/ + case RFAL_ERR_NONE: + *gIsoDep.rxLen = rfalConvBitsToBytes( *gIsoDep.rxLen ); + break; + + /*******************************************************************************/ + default: + return ret; + } + break; + + + /*******************************************************************************/ + case ISODEP_ST_PICC_SWTX: + + if( !rfalIsoDepTimerisExpired( gIsoDep.WTXTimer ) ) /* Do nothing until WTX timer has expired */ + { + return RFAL_ERR_BUSY; + } + + /* Set waiting for WTX Ack Flag */ + gIsoDep.isWait4WTX = true; + + /* Digital 1.1 15.2.2.9 - Calculate the WTXM such that FWTtemp <= FWTmax */ + gIsoDep.lastWTXM = (uint8_t)rfalIsoDep_WTXMListenerMax( gIsoDep.fwt ); + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_S_WTX, gIsoDep.lastWTXM ) ); + + gIsoDep.state = ISODEP_ST_PICC_RX; /* Go back to Rx to process WTX ack */ + return RFAL_ERR_BUSY; + + + /*******************************************************************************/ + case ISODEP_ST_PICC_SDSL: + + if( !rfalIsTransceiveInTx() ) /* Wait until DSL response has been sent */ + { + rfalIsoDepInitialize(); /* Session finished reInit vars, go back to ISODEP_ST_IDLE */ + return RFAL_ERR_SLEEP_REQ; /* Notify Deselect request */ + } + return RFAL_ERR_BUSY; + + + /*******************************************************************************/ + default: + return RFAL_ERR_INTERNAL; + } + + /* ISO 14443-4 7.5.6.2 CE SHALL NOT attempt error recovery -> clear counters */ + rfalIsoDepClearCounters(); + + /*******************************************************************************/ + /* No error, process incoming msg */ + /*******************************************************************************/ + + /* Grab rcvd PCB */ + rxPCB = gIsoDep.rxBuf[ ISODEP_PCB_POS ]; + + + /*******************************************************************************/ + /* When DID=0 PCD may or may not use DID, therefore check whether current PCD request + * has DID present to be reflected on max INF length #454 */ + + /* ReCalculate Header Length */ + gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN; + gIsoDep.hdrLen += (uint8_t)( (rfalIsoDep_PCBhasDID(rxPCB)) ? RFAL_ISODEP_DID_LEN : 0U ); + gIsoDep.hdrLen += (uint8_t)( (rfalIsoDep_PCBhasNAD(rxPCB)) ? RFAL_ISODEP_NAD_LEN : 0U ); + + /* Store whether last PCD block had DID. for PICC special handling of DID = 0 */ + if( gIsoDep.did == RFAL_ISODEP_DID_00 ) + { + gIsoDep.lastDID00 = ( (rfalIsoDep_PCBhasDID(rxPCB)) ? true : false ); + } + + /*******************************************************************************/ + /* Check rcvd msg length, cannot be less then the expected header OR * + * if the rcvd msg exceeds our announced frame size (FSD) */ + if( ((*gIsoDep.rxLen) < gIsoDep.hdrLen) || ((*gIsoDep.rxLen) > (gIsoDep.ourFsx - ISODEP_CRC_LEN)) ) + { + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO Ignore this protocol request */ + } + /* If we are not supporting DID, but we receive one OR + * If we are expecting DID, check if PCB signals its presence and if device ID match OR + * If our DID=0 and DID is sent but with an incorrect value */ + if( ((gIsoDep.did == RFAL_ISODEP_NO_DID) && (rfalIsoDep_PCBhasDID(rxPCB))) || + ((gIsoDep.did != RFAL_ISODEP_NO_DID) && (gIsoDep.did != RFAL_ISODEP_DID_00) && ( (!rfalIsoDep_PCBhasDID(rxPCB)) || (gIsoDep.did != gIsoDep.rxBuf[ ISODEP_DID_POS ]))) || + ((gIsoDep.did == RFAL_ISODEP_DID_00) && rfalIsoDep_PCBhasDID(rxPCB) && (RFAL_ISODEP_DID_00 != gIsoDep.rxBuf[ ISODEP_DID_POS ]) ) ) + { + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen ); + return RFAL_ERR_BUSY; /* Ignore a wrong DID request */ + } + + /* If we aren't expecting NAD and it's received */ + if( (gIsoDep.nad == RFAL_ISODEP_NO_NAD) && rfalIsoDep_PCBhasNAD(rxPCB) ) + { + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.actvParam.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.actvParam.rxLen ); + return RFAL_ERR_BUSY; /* Ignore a unexpected NAD request */ + } + + /*******************************************************************************/ + /* Process S-Block */ + /*******************************************************************************/ + if( rfalIsoDep_PCBisSBlock(rxPCB) ) + { + /* Check if is a Wait Time eXtension */ + if( rfalIsoDep_PCBisSWTX(rxPCB) ) + { + /* Check if we're expecting a S-WTX */ + if( rfalIsoDep_PCBisWTX( gIsoDep.lastPCB ) ) + { + /* Digital 1.1 15.2.2.11 S(WTX) Ack with different WTXM -> Protocol Error * + * Power level indication also should be set to 0 */ + if( ( gIsoDep.rxBuf[ gIsoDep.hdrLen ] == gIsoDep.lastWTXM) && ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_SWTX_INF_LEN) ) + { + /* Clear waiting for RTOX Ack Flag */ + gIsoDep.isWait4WTX = false; + + /* Check if a Tx is already pending */ + if( gIsoDep.isTxPending ) + { + /* Has a pending Tx, go immediately to TX */ + gIsoDep.state = ISODEP_ST_PICC_TX; + return RFAL_ERR_BUSY; + } + + /* Set WTX timer */ + rfalIsoDepTimerStart( gIsoDep.WTXTimer, rfalIsoDep_WTXAdjust( (gIsoDep.lastWTXM * rfalConv1fcToMs( gIsoDep.fwt )) ) ); + + gIsoDep.state = ISODEP_ST_PICC_SWTX; + return RFAL_ERR_BUSY; + } + } + /* Unexpected/Incorrect S-WTX, fall into reRenable */ + } + + /* Check if is a Deselect request */ + if( rfalIsoDep_PCBisSDeselect(rxPCB) && ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_SDSL_INF_LEN) ) + { + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM ) ); + + /* S-DSL transmission ongoing, wait until complete */ + gIsoDep.state = ISODEP_ST_PICC_SDSL; + return RFAL_ERR_BUSY; + } + + /* Unexpected S-Block, fall into reRenable */ + } + + /*******************************************************************************/ + /* Process R-Block */ + /*******************************************************************************/ + else if( rfalIsoDep_PCBisRBlock(rxPCB) && ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_RBLOCK_INF_LEN)) + { + if( rfalIsoDep_PCBisRACK(rxPCB) ) /* Check if is a R-ACK */ + { + if( rfalIsoDep_GetBN(rxPCB) == gIsoDep.blockNumber ) /* Check block number */ + { + /* Rule 11 - R(ACK) with current bn -> re-transmit */ + if( !rfalIsoDep_PCBisIBlock(gIsoDep.lastPCB) ) + { + rfalIsoDepReSendControlMsg(); + } + else + { + gIsoDep.state = ISODEP_ST_PICC_TX; + } + + return RFAL_ERR_BUSY; + } + else + { + if( !gIsoDep.isTxChaining ) + { + /* Rule 13 violation R(ACK) without performing chaining */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.rxLen ); + return RFAL_ERR_BUSY; + } + + /* Rule E - R(ACK) with not current bn -> toggle bn */ + rfalIsoDep_ToggleBN( gIsoDep.blockNumber ); + + /* This block has been transmitted and acknowledged, perform WTX until next data is provided */ + + /* Rule 9 - PICC is allowed to send an S(WTX) instead of an I-block or an R(ACK) */ + rfalIsoDepTimerStart( gIsoDep.WTXTimer, rfalIsoDep_WTXAdjust( rfalConv1fcToMs( gIsoDep.fwt )) ); + gIsoDep.state = ISODEP_ST_PICC_SWTX; + + /* Rule 13 - R(ACK) with not current bn -> continue chaining */ + return RFAL_ERR_NONE; /* This block has been transmitted */ + } + } + else if( rfalIsoDep_PCBisRNAK(rxPCB) ) /* Check if is a R-NACK */ + { + if( rfalIsoDep_GetBN(rxPCB) == gIsoDep.blockNumber ) /* Check block number */ + { + /* Rule 11 - R(NAK) with current bn -> re-transmit last x-Block */ + if( !rfalIsoDep_PCBisIBlock(gIsoDep.lastPCB) ) + { + rfalIsoDepReSendControlMsg(); + } + else + { + gIsoDep.state = ISODEP_ST_PICC_TX; + } + + return RFAL_ERR_BUSY; + } + else + { + /* Rule 12 - R(NAK) with not current bn -> R(ACK) */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ) ); + + return RFAL_ERR_BUSY; + } + } + else + { + /* MISRA 15.7 - Empty else */ + } + + /* Unexpected R-Block, fall into reRenable */ + } + + /*******************************************************************************/ + /* Process I-Block */ + /*******************************************************************************/ + else if( rfalIsoDep_PCBisIBlock(rxPCB) ) + { + /* Rule D - When an I-block is received, the PICC shall toggle its block number before sending a block */ + rfalIsoDep_ToggleBN( gIsoDep.blockNumber ); + + /*******************************************************************************/ + /* Check if the block number is the one expected */ + /* Check if PCD sent an I-Block instead ACK/NACK when we are chaining */ + if( (rfalIsoDep_GetBN(rxPCB) != gIsoDep.blockNumber) || (gIsoDep.isTxChaining) ) + { + /* Remain in the same Block Number */ + rfalIsoDep_ToggleBN( gIsoDep.blockNumber ); + + /* ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2 The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.rxLen ); + return RFAL_ERR_BUSY; + } + + /*******************************************************************************/ + /* is PCD performing chaining ? */ + if( rfalIsoDep_PCBisChaining(rxPCB) ) + { + gIsoDep.isRxChaining = true; + *gIsoDep.rxChaining = true; /* Output Parameter*/ + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepHandleControlMsg( ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM ) ); + + /* Received I-Block with chaining, send current data to DH */ + + /* remove ISO DEP header, check is necessary to move the INF data on the buffer */ + *gIsoDep.rxLen -= gIsoDep.hdrLen; + if( (gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*gIsoDep.rxLen > 0U) ) + { + RFAL_MEMMOVE( &gIsoDep.rxBuf[gIsoDep.rxBufInfPos], &gIsoDep.rxBuf[gIsoDep.hdrLen], *gIsoDep.rxLen ); + } + return RFAL_ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/ + } + + + /*******************************************************************************/ + /* PCD is not performing chaining */ + gIsoDep.isRxChaining = false; /* clear PCD chaining flag */ + *gIsoDep.rxChaining = false; /* Output Parameter */ + + /* remove ISO DEP header, check is necessary to move the INF data on the buffer */ + *gIsoDep.rxLen -= gIsoDep.hdrLen; + if( (gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*gIsoDep.rxLen > 0U) ) + { + RFAL_MEMMOVE( &gIsoDep.rxBuf[gIsoDep.rxBufInfPos], &gIsoDep.rxBuf[gIsoDep.hdrLen], *gIsoDep.rxLen ); + } + + + /*******************************************************************************/ + /* Reception done, send data back and start WTX timer */ + rfalIsoDepTimerStart( gIsoDep.WTXTimer, rfalIsoDep_WTXAdjust( rfalConv1fcToMs( gIsoDep.fwt )) ); + + gIsoDep.state = ISODEP_ST_PICC_SWTX; + return RFAL_ERR_NONE; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + /* Unexpected/Unknown Block */ + /* ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2 The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */ + rfalIsoDepReEnableRx( (uint8_t*)gIsoDep.rxBuf, sizeof( rfalIsoDepBufFormat ), gIsoDep.rxLen ); + + return RFAL_ERR_BUSY; +} +#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + + +#if RFAL_FEATURE_ISO_DEP_POLL + +#if RFAL_FEATURE_NFCA + +/*******************************************************************************/ +static ReturnCode rfalIsoDepStartRATS( rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts *ats, uint8_t *atsLen ) +{ + rfalTransceiveContext ctx; + + if( ats == NULL) + { + return RFAL_ERR_PARAM; + } + + gIsoDep.rxBuf = (uint8_t*) ats; + gIsoDep.rxLen8 = atsLen; + gIsoDep.did = DID; + + /*******************************************************************************/ + /* Compose RATS */ + gIsoDep.actv.ratsReq.CMD = RFAL_ISODEP_CMD_RATS; + gIsoDep.actv.ratsReq.PARAM = (((uint8_t)FSDI << RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) & RFAL_ISODEP_RATS_PARAM_FSDI_MASK) | (DID & RFAL_ISODEP_RATS_PARAM_DID_MASK); + + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)&gIsoDep.actv.ratsReq, sizeof(rfalIsoDepRats), (uint8_t*)ats, sizeof(rfalIsoDepAts), &gIsoDep.rxBufLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ISODEP_T4T_FWT_ACTIVATION ); + return rfalStartTransceive( &ctx ); +} + + +/*******************************************************************************/ +static ReturnCode rfalIsoDepGetRATSStatus( void ) +{ + ReturnCode ret; + + ret = rfalGetTransceiveStatus(); + if( ret == RFAL_ERR_NONE ) + { + gIsoDep.rxBufLen = rfalConvBitsToBytes(gIsoDep.rxBufLen); + + /* Check for valid ATS length Digital 1.1 13.6.2.1 & 13.6.2.3 */ + if( (gIsoDep.rxBufLen < RFAL_ISODEP_ATS_MIN_LEN) || (gIsoDep.rxBufLen > RFAL_ISODEP_ATS_MAX_LEN) || ( gIsoDep.rxBuf[RFAL_ISODEP_ATS_TL_POS] != gIsoDep.rxBufLen) ) + { + return RFAL_ERR_PROTO; + } + + /* Assign our FSx, in case the a Deselect is send without Transceive */ + gIsoDep.ourFsx = rfalIsoDepFSxI2FSx( (uint8_t) (gIsoDep.actv.ratsReq.PARAM >> RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) ); + + /* Check and assign if ATS length was requested (length also available on TL) */ + if( gIsoDep.rxLen8 != NULL ) + { + *gIsoDep.rxLen8 = (uint8_t)gIsoDep.rxBufLen; + } + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepRATS( rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts *ats , uint8_t *atsLen) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartRATS(FSDI, DID, ats, atsLen) ); + rfalRunBlocking( ret, rfalIsoDepGetRATSStatus() ); + + return ret; +} + + +/*******************************************************************************/ +static ReturnCode rfalIsoDepStartPPS( uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes *ppsRes ) +{ + rfalTransceiveContext ctx; + + if( (ppsRes == NULL) || (DSI > RFAL_BR_848) || (DRI > RFAL_BR_848) || ((DID > RFAL_ISODEP_DID_MAX) && (DID != RFAL_ISODEP_NO_DID)) ) + { + return RFAL_ERR_PARAM; + } + + gIsoDep.rxBuf = (uint8_t*) ppsRes; + + /*******************************************************************************/ + /* Compose PPS Request */ + gIsoDep.actv.ppsReq.PPSS = (RFAL_ISODEP_PPS_SB | (DID & RFAL_ISODEP_PPS_SB_DID_MASK)); + gIsoDep.actv.ppsReq.PPS0 = RFAL_ISODEP_PPS_PPS0_PPS1_PRESENT; + gIsoDep.actv.ppsReq.PPS1 = (RFAL_ISODEP_PPS_PPS1 | ((((uint8_t)DSI< RFAL_BR_848) || (DRI > RFAL_BR_848) || ((DID > RFAL_ISODEP_DID_MAX) && (DID != RFAL_ISODEP_NO_DID)) ) + { + return RFAL_ERR_NONE; + } + + gIsoDep.rxBuf = (uint8_t*) attribRes; + gIsoDep.rxLen8 = attribResLen; + gIsoDep.did = DID; + + /*******************************************************************************/ + /* Compose ATTRIB command */ + gIsoDep.actv.attribReq.cmd = RFAL_ISODEP_CMD_ATTRIB; + gIsoDep.actv.attribReq.Param.PARAM1 = PARAM1; + gIsoDep.actv.attribReq.Param.PARAM2 = ( ((((uint8_t)DSI< 0U) ) + { + RFAL_MEMCPY(gIsoDep.actv.attribReq.HLInfo, HLInfo, RFAL_MIN(HLInfoLen, RFAL_ISODEP_ATTRIB_HLINFO_LEN) ); + } + + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)&gIsoDep.actv.attribReq, (uint16_t)(RFAL_ISODEP_ATTRIB_HDR_LEN + RFAL_MIN((uint16_t)HLInfoLen, RFAL_ISODEP_ATTRIB_HLINFO_LEN)), (uint8_t*)gIsoDep.rxBuf, sizeof(rfalIsoDepAttribRes), &gIsoDep.rxBufLen, RFAL_TXRX_FLAGS_DEFAULT, fwt ); + return rfalStartTransceive( &ctx ); +} + + +/*******************************************************************************/ +static ReturnCode rfalIsoDepGetATTRIBStatus( void ) +{ + ReturnCode ret; + + ret = rfalGetTransceiveStatus(); + if( ret == RFAL_ERR_NONE ) + { + gIsoDep.rxBufLen = rfalConvBitsToBytes(gIsoDep.rxBufLen); + + /* Check for valid ATTRIB Response Digital 2.3 15.6.2.1 */ + if( (gIsoDep.rxBufLen < RFAL_ISODEP_ATTRIB_RES_HDR_LEN) ) + { + return RFAL_ERR_PROTO; + } + + if( gIsoDep.rxLen8 != NULL ) + { + *gIsoDep.rxLen8 = (uint8_t)gIsoDep.rxBufLen; + } + + gIsoDep.ourFsx = rfalIsoDepFSxI2FSx( (uint8_t)(gIsoDep.actv.attribReq.Param.PARAM2 & RFAL_ISODEP_ATTRIB_PARAM2_FSDI_MASK) ); + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepATTRIB( const uint8_t* nfcid0, uint8_t PARAM1, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepFSxI FSDI, uint8_t PARAM3, uint8_t DID, const uint8_t* HLInfo, uint8_t HLInfoLen, uint32_t fwt, rfalIsoDepAttribRes *attribRes, uint8_t *attribResLen ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartATTRIB( nfcid0, PARAM1, DSI, DRI, FSDI, PARAM3, DID, HLInfo, HLInfoLen, fwt, attribRes, attribResLen ) ); + rfalRunBlocking( ret, rfalIsoDepGetATTRIBStatus() ); + + return ret; +} + +#endif /* RFAL_FEATURE_NFCB */ + + +#if RFAL_FEATURE_NFCA + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollAHandleActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, rfalIsoDepDevice *rfalIsoDepDev ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepPollAStartActivation( FSDI, DID, maxBR, rfalIsoDepDev ) ); + rfalRunBlocking( ret, rfalIsoDepPollAGetActivationStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollAStartActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, rfalIsoDepDevice *rfalIsoDepDev ) +{ + ReturnCode ret; + + if( rfalIsoDepDev == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Enable EMD suppresssion|handling according to Digital 2.1 4.1.1.1 ; EMVCo 3.0 4.9.2 ; ISO 14443-3 8.3 */ + rfalSetErrorHandling( RFAL_ERRORHANDLING_EMD ); + + /* Start RATS Transceive */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartRATS( FSDI, DID, &rfalIsoDepDev->activation.A.Listener.ATS, &rfalIsoDepDev->activation.A.Listener.ATSLen ) ); + + rfalIsoDepDev->info.DSI = maxBR; + gIsoDep.actvDev = rfalIsoDepDev; + gIsoDep.cntRRetrys = gIsoDep.maxRetriesRATS; + gIsoDep.state = ISODEP_ST_PCD_ACT_RATS; + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollAGetActivationStatus( void ) +{ + ReturnCode ret; + uint8_t msgIt; + rfalBitRate maxBR; + + switch( gIsoDep.state ) + { + /*******************************************************************************/ + case ISODEP_ST_PCD_ACT_RATS: + + ret = rfalIsoDepGetRATSStatus(); + if( ret != RFAL_ERR_BUSY ) + { + if( ret != RFAL_ERR_NONE ) + { + /* EMVCo 2.6 9.6.1.1 & 9.6.1.2 If a timeout error is detected retransmit, on transmission error abort */ + if( (gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) && (ret != RFAL_ERR_TIMEOUT) ) + { + break; + } + + if( gIsoDep.cntRRetrys != 0U ) + { + /* Ensure FDT before retransmission (reuse RFAL GT timer) */ + rfalSetGT( rfalGetFDTPoll() ); + rfalFieldOnAndStartGT(); + + /* Send RATS retransmission */ /* PRQA S 4342 1 # MISRA 10.5 - Layout of enum rfalIsoDepFSxI is guaranteed whithin 4bit range */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartRATS( (rfalIsoDepFSxI)(uint8_t)(gIsoDep.actv.ratsReq.PARAM >> RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT), + gIsoDep.did, + &gIsoDep.actvDev->activation.A.Listener.ATS, + &gIsoDep.actvDev->activation.A.Listener.ATSLen ) ); + gIsoDep.cntRRetrys--; + ret = RFAL_ERR_BUSY; + } + /* Switch between NFC Forum and ISO14443-4 behaviour #595 + * ISO14443-4 5.6.1 If RATS fails, a Deactivation sequence should be performed as defined on clause 8 (ISO10373-6 Scenario H.2.5) + * Activity 1.1 9.6 Device Deactivation Activity is to be only performed when there's an active device */ + else if( gIsoDep.compMode == RFAL_COMPLIANCE_MODE_ISO ) + { + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartDeselect() ); + + /* State ISODEP_ST_PCD_WAIT_DSL already set by rfalIsoDepHandleControlMsg DSL */ + return RFAL_ERR_BUSY; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + else /* ATS received */ + { + maxBR = gIsoDep.actvDev->info.DSI; /* Retrieve requested max bitrate */ + + /*******************************************************************************/ + /* Process ATS Response */ + gIsoDep.actvDev->info.FWI = RFAL_ISODEP_FWI_DEFAULT; /* Default value EMVCo 2.6 5.7.2.6 */ + gIsoDep.actvDev->info.SFGI = 0U; + gIsoDep.actvDev->info.MBL = 0U; + gIsoDep.actvDev->info.DSI = RFAL_BR_106; + gIsoDep.actvDev->info.DRI = RFAL_BR_106; + gIsoDep.actvDev->info.FSxI = (uint8_t)RFAL_ISODEP_FSXI_32; /* FSC default value is 32 bytes ISO14443-A 5.2.3 */ + + + /*******************************************************************************/ + /* Check for ATS optional fields */ + if( gIsoDep.actvDev->activation.A.Listener.ATS.TL > RFAL_ISODEP_ATS_MIN_LEN ) + { + msgIt = RFAL_ISODEP_ATS_MIN_LEN; + + /* Format byte T0 is optional, if present assign FSDI */ + gIsoDep.actvDev->info.FSxI = (gIsoDep.actvDev->activation.A.Listener.ATS.T0 & RFAL_ISODEP_ATS_T0_FSCI_MASK); + + /* T0 has already been processed, always the same position */ + msgIt++; + + /* Check if TA is present */ + if( (gIsoDep.actvDev->activation.A.Listener.ATS.T0 & RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK) != 0U ) + { + rfalIsoDepCalcBitRate( maxBR, ((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++], &gIsoDep.actvDev->info.DSI, &gIsoDep.actvDev->info.DRI ); + } + + /* Check if TB is present */ + if( (gIsoDep.actvDev->activation.A.Listener.ATS.T0 & RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK) != 0U ) + { + gIsoDep.actvDev->info.SFGI = ((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++]; + gIsoDep.actvDev->info.FWI = (uint8_t)((gIsoDep.actvDev->info.SFGI >> RFAL_ISODEP_ATS_TB_FWI_SHIFT) & RFAL_ISODEP_ATS_FWI_MASK); + gIsoDep.actvDev->info.SFGI &= RFAL_ISODEP_ATS_TB_SFGI_MASK; + } + + /* Check if TC is present */ + if( (gIsoDep.actvDev->activation.A.Listener.ATS.T0 & RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK) != 0U ) + { + /* Check for Protocol features support */ + /* Advanced protocol features defined on Digital 1.0 Table 69, removed after */ + gIsoDep.actvDev->info.supAdFt = (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt] & RFAL_ISODEP_ATS_TC_ADV_FEAT) != 0U) ? true : false); + gIsoDep.actvDev->info.supDID = (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt] & RFAL_ISODEP_ATS_TC_DID) != 0U) ? true : false); + gIsoDep.actvDev->info.supNAD = (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++] & RFAL_ISODEP_ATS_TC_NAD) != 0U) ? true : false); + } + } + + gIsoDep.actvDev->info.FSx = rfalIsoDepFSxI2FSx(gIsoDep.actvDev->info.FSxI); + gIsoDep.fsx = gIsoDep.actvDev->info.FSx; + + gIsoDep.actvDev->info.SFGT = rfalIsoDepSFGI2SFGT( (uint8_t)gIsoDep.actvDev->info.SFGI ); + + /* Ensure SFGT before following frame (reuse RFAL GT timer) */ + rfalSetGT( rfalConvMsTo1fc(gIsoDep.actvDev->info.SFGT) ); + rfalFieldOnAndStartGT(); + + gIsoDep.actvDev->info.FWT = rfalIsoDepFWI2FWT( gIsoDep.actvDev->info.FWI ); + gIsoDep.actvDev->info.dFWT = RFAL_ISODEP_DFWT_20; + + gIsoDep.actvDev->info.DID = ( (gIsoDep.actvDev->info.supDID) ? gIsoDep.did : RFAL_ISODEP_NO_DID); + gIsoDep.actvDev->info.NAD = RFAL_ISODEP_NO_NAD; + + + /*******************************************************************************/ + /* If higher bit rates are supported by both devices, send PPS */ + if( (gIsoDep.actvDev->info.DSI != RFAL_BR_106) || (gIsoDep.actvDev->info.DRI != RFAL_BR_106) ) + { + /* Send PPS */ /* PRQA S 0310 1 # MISRA 11.3 - Intentional safe cast to avoiding buffer duplication */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartPPS( gIsoDep.actvDev->info.DID, gIsoDep.actvDev->info.DSI, gIsoDep.actvDev->info.DRI, (rfalIsoDepPpsRes*)&gIsoDep.ctrlBuf )); + + gIsoDep.state = ISODEP_ST_PCD_ACT_PPS; + return RFAL_ERR_BUSY; + } + + return RFAL_ERR_NONE; + } + } + break; + + /*******************************************************************************/ + case ISODEP_ST_PCD_ACT_PPS: + + ret = rfalIsoDepGetPPSSTatus(); + if( ret != RFAL_ERR_BUSY ) + { + /* Check whether PPS has been acknowledge */ + if( ret == RFAL_ERR_NONE ) + { + /* DSI code the divisor from PICC to PCD */ + /* DRI code the divisor from PCD to PICC */ + rfalSetBitRate( gIsoDep.actvDev->info.DRI, gIsoDep.actvDev->info.DSI ); + } + else + { + /* If PPS has faled keep activation bit rate */ + gIsoDep.actvDev->info.DSI = RFAL_BR_106; + gIsoDep.actvDev->info.DRI = RFAL_BR_106; + + /* Ignore PPS response fail, proceed to data exchange */ + ret = RFAL_ERR_NONE; + } + } + break; + + /*******************************************************************************/ + case ISODEP_ST_PCD_WAIT_DSL: + + ret = rfalIsoDepGetDeselectStatus(); + if( ret != RFAL_ERR_BUSY ) + { + /* Report activation failed with generic tranmission error */ + ret = RFAL_ERR_FRAMING; + } + break; + + /*******************************************************************************/ + default: + ret = RFAL_ERR_WRONG_STATE; + break; + } + + return ret; +} +#endif /* RFAL_FEATURE_NFCA */ + +#if RFAL_FEATURE_NFCB + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollBHandleActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, uint8_t PARAM1, const rfalNfcbListenDevice *nfcbDev, const uint8_t* HLInfo, uint8_t HLInfoLen, rfalIsoDepDevice *rfalIsoDepDev ) +{ + + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepPollBStartActivation( FSDI, DID, maxBR, PARAM1, nfcbDev, HLInfo, HLInfoLen, rfalIsoDepDev ) ); + rfalRunBlocking( ret, rfalIsoDepPollBGetActivationStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollBStartActivation( rfalIsoDepFSxI FSDI, uint8_t DID, rfalBitRate maxBR, uint8_t PARAM1, const rfalNfcbListenDevice *nfcbDev, const uint8_t* HLInfo, uint8_t HLInfoLen, rfalIsoDepDevice *rfalIsoDepDev ) +{ + ReturnCode ret; + uint32_t tr2; + + /***************************************************************************/ + /* Initialize ISO-DEP Device with info from SENSB_RES */ + rfalIsoDepDev->info.FWI = ((nfcbDev->sensbRes.protInfo.FwiAdcFo >> RFAL_NFCB_SENSB_RES_FWI_SHIFT) & RFAL_NFCB_SENSB_RES_FWI_MASK); + rfalIsoDepDev->info.FWT = rfalIsoDepFWI2FWT( rfalIsoDepDev->info.FWI ); + rfalIsoDepDev->info.dFWT = RFAL_NFCB_DFWT; + rfalIsoDepDev->info.SFGI = (((uint32_t)nfcbDev->sensbRes.protInfo.SFGI >> RFAL_NFCB_SENSB_RES_SFGI_SHIFT) & RFAL_NFCB_SENSB_RES_SFGI_MASK); + rfalIsoDepDev->info.SFGT = rfalIsoDepSFGI2SFGT( (uint8_t)rfalIsoDepDev->info.SFGI ); + rfalIsoDepDev->info.FSxI = ((nfcbDev->sensbRes.protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_FSCI_SHIFT) & RFAL_NFCB_SENSB_RES_FSCI_MASK); + rfalIsoDepDev->info.FSx = rfalIsoDepFSxI2FSx(rfalIsoDepDev->info.FSxI); + rfalIsoDepDev->info.DID = DID; + rfalIsoDepDev->info.supDID = ((( nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_FO_DID_MASK ) != 0U) ? true : false); + rfalIsoDepDev->info.supNAD = ((( nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_FO_NAD_MASK ) != 0U) ? true : false); + + + /* Check if DID requested is supported by PICC */ + if( (DID != RFAL_ISODEP_NO_DID) && (!rfalIsoDepDev->info.supDID) ) + { + return RFAL_ERR_PARAM; + } + + /* Enable EMD suppresssion|handling according to Digital 2.1 4.1.1.1 ; EMVCo 3.0 4.9.2 ; ISO 14443-3 8.3 */ + rfalSetErrorHandling( RFAL_ERRORHANDLING_EMD ); + + /***************************************************************************/ + /* Set FDT Poll to be used on upcoming communications */ + if( gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV ) + { + /* Disregard Minimum TR2 returned by PICC, always use FDTb MIN EMVCo 3.0 6.3.2.10 */ + rfalSetFDTPoll( RFAL_FDT_POLL_NFCB_POLLER ); + } + else + { + tr2 = rfalNfcbTR2ToFDT(((nfcbDev->sensbRes.protInfo.FsciProType >>RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT) & RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK)); + if( rfalGetFDTPoll() < tr2 ) + { + /* In case TR2 is longer than the one currently running, ensure it's fulfilled (max: 9472/fc => 700us) */ + platformDelay( 1 ); + } + + /* Apply minimum TR2 from SENSB_RES Digital 2.1 7.6.2.23 */ + rfalSetFDTPoll( tr2 ); + } + + + /* Calculate max Bit Rate */ + rfalIsoDepCalcBitRate( maxBR, nfcbDev->sensbRes.protInfo.BRC, &rfalIsoDepDev->info.DSI, &rfalIsoDepDev->info.DRI ); + + /***************************************************************************/ + /* Send ATTRIB Command */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartATTRIB( (const uint8_t*)&nfcbDev->sensbRes.nfcid0, + (((nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_ADC_ADV_FEATURE_MASK) != 0U) ? PARAM1 : RFAL_ISODEP_ATTRIB_REQ_PARAM1_DEFAULT), + rfalIsoDepDev->info.DSI, + rfalIsoDepDev->info.DRI, + FSDI, + (gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK : (nfcbDev->sensbRes.protInfo.FsciProType & ( (RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK<info.FWT + rfalIsoDepDev->info.dFWT), + &rfalIsoDepDev->activation.B.Listener.ATTRIB_RES, + &rfalIsoDepDev->activation.B.Listener.ATTRIB_RESLen + ) ); + + + gIsoDep.actvDev = rfalIsoDepDev; + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollBGetActivationStatus( void ) +{ + ReturnCode ret; + uint8_t mbli; + + /***************************************************************************/ + /* Process ATTRIB Response */ + ret = rfalIsoDepGetATTRIBStatus(); + if( ret != RFAL_ERR_BUSY) + { + if( ret == RFAL_ERR_NONE ) + { + /* Digital 1.1 14.6.2.3 - Check if received DID match */ + uint8_t expected_did = ((RFAL_ISODEP_NO_DID==gIsoDep.did) ? RFAL_ISODEP_DID_00 : gIsoDep.did); + if( (gIsoDep.actvDev->activation.B.Listener.ATTRIB_RES.mbliDid & RFAL_ISODEP_ATTRIB_RES_DID_MASK) != expected_did ) + { + return RFAL_ERR_PROTO; + } + + /* Retrieve MBLI and calculate new FDS/MBL (Maximum Buffer Length) */ + mbli = ((gIsoDep.actvDev->activation.B.Listener.ATTRIB_RES.mbliDid >> RFAL_ISODEP_ATTRIB_RES_MBLI_SHIFT) & RFAL_ISODEP_ATTRIB_RES_MBLI_MASK); + if( mbli > 0U) + { + /* Digital 1.1 14.6.2 Calculate Maximum Buffer Length MBL = FSC x 2^(MBLI-1) */ + gIsoDep.actvDev->info.MBL = (gIsoDep.actvDev->info.FSx * ((uint32_t)1U<<(mbli-1U))); + } + + /* DSI code the divisor from PICC to PCD */ + /* DRI code the divisor from PCD to PICC */ + rfalSetBitRate( gIsoDep.actvDev->info.DRI, gIsoDep.actvDev->info.DSI ); + + + /* REMARK: SoF EoF TR0 and TR1 are not passed on to RF layer */ + + + /* Start the SFGT timer (reuse RFAL GT timer) */ + rfalSetGT( rfalConvMsTo1fc(gIsoDep.actvDev->info.SFGT) ); + rfalFieldOnAndStartGT(); + } + else + { + gIsoDep.actvDev->info.DSI = RFAL_BR_106; + gIsoDep.actvDev->info.DRI = RFAL_BR_106; + } + + /*******************************************************************************/ + /* Store already FS info, rfalIsoDepGetMaxInfLen() may be called before setting TxRx params */ + gIsoDep.fsx = gIsoDep.actvDev->info.FSx; + } + + return ret; +} + +#endif /* RFAL_FEATURE_NFCB */ + + +/*******************************************************************************/ +ReturnCode rfalIsoDepPollHandleSParameters( rfalIsoDepDevice *rfalIsoDepDev, rfalBitRate maxTxBR, rfalBitRate maxRxBR ) +{ + uint8_t it; + uint8_t supPCD2PICC; + uint8_t supPICC2PCD; + uint8_t currenttxBR; + uint8_t currentrxBR; + rfalBitRate txBR; + rfalBitRate rxBR; + uint16_t rcvLen; + ReturnCode ret; + rfalIsoDepControlMsgSParam sParam; + + + if( (rfalIsoDepDev == NULL) || (maxTxBR > RFAL_BR_13560) || (maxRxBR > RFAL_BR_13560) ) + { + return RFAL_ERR_PARAM; + } + + it = 0; + supPICC2PCD = 0x00; + supPCD2PICC = 0x00; + txBR = RFAL_BR_106; + rxBR = RFAL_BR_106; + sParam.pcb = ISODEP_PCB_SPARAMETERS; + + /*******************************************************************************/ + /* Send S(PARAMETERS) - Block Info */ + sParam.sParam.tag = RFAL_ISODEP_SPARAM_TAG_BLOCKINFO; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRREQ; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRREQ_LEN; + sParam.sParam.length = it; + + /* Send S(PARAMETERS). Use a fixed FWI of 4 ISO14443-4 2016 7.2 */ + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTxRx( (uint8_t*)&sParam, (RFAL_ISODEP_SPARAM_HDR_LEN + (uint16_t)it), (uint8_t*)&sParam, sizeof(rfalIsoDepControlMsgSParam), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, ISODEP_FWT_DEACTIVATION )); + + it = 0; + + /*******************************************************************************/ + /* Check S(PARAMETERS) response */ + if( (sParam.pcb != ISODEP_PCB_SPARAMETERS) || (sParam.sParam.tag != RFAL_ISODEP_SPARAM_TAG_BLOCKINFO) || + (sParam.sParam.value[it] != RFAL_ISODEP_SPARAM_TAG_BRIND) || (rcvLen < RFAL_ISODEP_SPARAM_HDR_LEN) || + (rcvLen != ((uint16_t)sParam.sParam.length + RFAL_ISODEP_SPARAM_HDR_LEN)) ) + { + return RFAL_ERR_PROTO; + } + + /* Retrieve PICC's bit rate PICC capabilities */ + for( it=0; it<(rcvLen-(uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN); it++ ) + { + if( (sParam.sParam.value[it] == RFAL_ISODEP_SPARAM_TAG_SUP_PCD2PICC) && (sParam.sParam.value[it+(uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN] == RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN) ) + { + supPCD2PICC = sParam.sParam.value[it + RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN]; + } + + if( (sParam.sParam.value[it] == RFAL_ISODEP_SPARAM_TAG_SUP_PICC2PCD) && (sParam.sParam.value[it+(uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN] == RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN) ) + { + supPICC2PCD = sParam.sParam.value[it + RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN]; + } + } + + /*******************************************************************************/ + /* Check if requested bit rates are supported by PICC */ + if( (supPICC2PCD == 0x00U) || (supPCD2PICC == 0x00U) ) + { + return RFAL_ERR_PROTO; + } + + for( it=0; it<=(uint8_t)maxTxBR; it++ ) + { + if( (supPCD2PICC & (0x01U << it)) != 0U ) + { + txBR = (rfalBitRate)it; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and above clamping of maxTxBR guarantee no invalid enum values to be created */ + } + } + for( it=0; it<=(uint8_t)maxRxBR; it++ ) + { + if( (supPICC2PCD & (0x01U << it)) != 0U ) + { + rxBR = (rfalBitRate)it; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and above clamping of maxTxBR guarantee no invalid enum values to be created */ + } + } + + it = 0; + currenttxBR = (uint8_t)txBR; + currentrxBR = (uint8_t)rxBR; + + /*******************************************************************************/ + /* Send S(PARAMETERS) - Bit rates Activation */ + sParam.sParam.tag = RFAL_ISODEP_SPARAM_TAG_BLOCKINFO; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRACT; + sParam.sParam.value[it++] = ( RFAL_ISODEP_SPARAM_TVL_HDR_LEN + RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN + RFAL_ISODEP_SPARAM_TVL_HDR_LEN + RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN); + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_SEL_PCD2PICC; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN; + sParam.sParam.value[it++] = ((uint8_t)0x01U << currenttxBR); + sParam.sParam.value[it++] = 0x00U; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_SEL_PICC2PCD; + sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN; + sParam.sParam.value[it++] = ((uint8_t)0x01U << currentrxBR); + sParam.sParam.value[it++] = 0x00U; + sParam.sParam.length = it; + + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTxRx( (uint8_t*)&sParam, (RFAL_ISODEP_SPARAM_HDR_LEN + (uint16_t)it), (uint8_t*)&sParam, sizeof(rfalIsoDepControlMsgSParam), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, (rfalIsoDepDev->info.FWT + rfalIsoDepDev->info.dFWT) )); + + it = 0; + + /*******************************************************************************/ + /* Check S(PARAMETERS) Acknowledge */ + if( (sParam.pcb != ISODEP_PCB_SPARAMETERS) || (sParam.sParam.tag != RFAL_ISODEP_SPARAM_TAG_BLOCKINFO) || + (sParam.sParam.value[it] != RFAL_ISODEP_SPARAM_TAG_BRACK) || (rcvLen < RFAL_ISODEP_SPARAM_HDR_LEN) ) + { + return RFAL_ERR_PROTO; + } + + RFAL_EXIT_ON_ERR( ret, rfalSetBitRate( txBR, rxBR ) ); + + rfalIsoDepDev->info.DRI = txBR; + rfalIsoDepDev->info.DSI = rxBR; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +static void rfalIsoDepCalcBitRate( rfalBitRate maxAllowedBR, uint8_t piccBRCapability, rfalBitRate *dsi, rfalBitRate *dri ) +{ + uint8_t driMask; + uint8_t dsiMask; + int16_t i; + bool bitrateFound; + rfalBitRate curMaxBR; + + curMaxBR = maxAllowedBR; + + do + { + bitrateFound = true; + + (*dsi) = RFAL_BR_106; + (*dri) = RFAL_BR_106; + + /* Digital 1.0 5.6.2.5 & 11.6.2.14: A received RFU value of b4 = 1b MUST be interpreted as if b7 to b1 ? 0000000b (only 106 kbits/s in both direction) */ + if( ((RFAL_ISODEP_BITRATE_RFU_MASK & piccBRCapability) != 0U) || (curMaxBR > RFAL_BR_848) || (curMaxBR == RFAL_BR_KEEP) ) + { + return; + } + + /***************************************************************************/ + /* Determine Listen->Poll bit rate */ + dsiMask = (piccBRCapability & RFAL_ISODEP_BSI_MASK); + for( i = 2; i >= 0; i-- ) /* Check supported bit rate from the highest */ + { + if (((dsiMask & (0x10U << (uint8_t)i)) != 0U) && (((uint8_t)i+1U) <= (uint8_t)curMaxBR)) + { + const uint8_t newdsi = ((uint8_t) i) + 1U; + (*dsi) = (rfalBitRate)newdsi; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and range of loop variable guarantee no invalid enum values to be created */ + break; + } + } + + /***************************************************************************/ + /* Determine Poll->Listen bit rate */ + driMask = (piccBRCapability & RFAL_ISODEP_BRI_MASK); + for( i = 2; i >= 0; i-- ) /* Check supported bit rate from the highest */ + { + if (((driMask & (0x01U << (uint8_t)i)) != 0U) && (((uint8_t)i+1U) <= (uint8_t)curMaxBR)) + { + const uint8_t newdri = ((uint8_t) i) + 1U; + (*dri) = (rfalBitRate)newdri; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and range of loop variable guarantee no invalid enum values to be created */ + break; + } + } + + /***************************************************************************/ + /* Check if different bit rate is supported */ + + /* Digital 1.0 Table 67: if b8=1b, then only the same bit rate divisor for both directions is supported */ + if( (piccBRCapability & RFAL_ISODEP_SAME_BITRATE_MASK) != 0U ) + { + (*dsi) = RFAL_MIN((*dsi), (*dri)); + (*dri) = (*dsi); + /* Check that the baudrate is supported */ + if( (RFAL_BR_106 != (*dsi)) && ( !(((dsiMask & (0x10U << ((uint8_t)(*dsi) - 1U))) != 0U) && ((driMask & (0x01U << ((uint8_t)(*dri) - 1U))) != 0U)) ) ) + { + bitrateFound = false; + curMaxBR = (*dsi); /* set allowed bitrate to be lowest and determine bit rate again */ + } + } + } while (!(bitrateFound)); + +} + +/*******************************************************************************/ +static uint32_t rfalIsoDepSFGI2SFGT( uint8_t sfgi ) +{ + uint32_t sfgt; + uint8_t tmpSFGI; + + tmpSFGI = sfgi; + + if (tmpSFGI > ISODEP_SFGI_MAX) + { + tmpSFGI = ISODEP_SFGI_MIN; + } + + if (tmpSFGI != ISODEP_SFGI_MIN) + { + /* If sfgi != 0 wait SFGT + dSFGT Digital 1.1 13.8.2.1 */ + sfgt = rfalIsoDepCalcSGFT(sfgi) + rfalIsoDepCalcdSGFT(sfgi); + } + /* Otherwise use FDTPoll min Digital 1.1 13.8.2.3*/ + else + { + sfgt = RFAL_FDT_POLL_NFCA_POLLER; + } + + /* Convert carrier cycles to milli seconds */ + return (rfalConv1fcToMs(sfgt) + 1U); +} + +#endif /* RFAL_FEATURE_ISO_DEP_POLL */ + + + /*******************************************************************************/ + static void rfalIsoDepApdu2IBLockParam( rfalIsoDepApduTxRxParam apduParam, rfalIsoDepTxRxParam *iBlockParam, uint16_t txPos, uint16_t rxPos ) +{ + RFAL_NO_WARNING(rxPos); /* Keep this param for future use */ + + iBlockParam->DID = apduParam.DID; + iBlockParam->FSx = apduParam.FSx; + iBlockParam->ourFSx = apduParam.ourFSx; + iBlockParam->FWT = apduParam.FWT; + iBlockParam->dFWT = apduParam.dFWT; + + if( (apduParam.txBufLen - txPos) > rfalIsoDepGetMaxInfLen() ) + { + iBlockParam->isTxChaining = true; + iBlockParam->txBufLen = rfalIsoDepGetMaxInfLen(); + } + else + { + iBlockParam->isTxChaining = false; + iBlockParam->txBufLen = (apduParam.txBufLen - txPos); + } + + /* TxBuf is moved to the beginning for every I-Block */ + iBlockParam->txBuf = (rfalIsoDepBufFormat*)apduParam.txBuf; /* PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */ + iBlockParam->rxBuf = apduParam.tmpBuf; /* Simply using the apdu buffer is not possible because of current ACK handling */ + iBlockParam->isRxChaining = &gIsoDep.isAPDURxChaining; + iBlockParam->rxLen = apduParam.rxLen; +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepStartApduTransceive( rfalIsoDepApduTxRxParam param ) +{ + rfalIsoDepTxRxParam txRxParam; + + /* Initialize and store APDU context */ + gIsoDep.APDUParam = param; + gIsoDep.APDUTxPos = 0; + gIsoDep.APDURxPos = 0; + + /* Assign current FSx to calculate INF length (only change the FSx from activation if no to Keep) */ + gIsoDep.ourFsx = (( param.ourFSx != RFAL_ISODEP_FSX_KEEP ) ? param.ourFSx : gIsoDep.ourFsx); + gIsoDep.fsx = param.FSx; + + /* Convert APDU TxRxParams to I-Block TxRxParams */ + rfalIsoDepApdu2IBLockParam( gIsoDep.APDUParam, &txRxParam, gIsoDep.APDUTxPos, gIsoDep.APDURxPos ); + + return rfalIsoDepStartTransceive( txRxParam ); +} + + +/*******************************************************************************/ +ReturnCode rfalIsoDepGetApduTransceiveStatus( void ) +{ + ReturnCode ret; + rfalIsoDepTxRxParam txRxParam; + + ret = rfalIsoDepGetTransceiveStatus(); + switch( ret ) + { + /*******************************************************************************/ + case RFAL_ERR_NONE: + + /* Check if we are still doing chaining on Tx */ + if( gIsoDep.isTxChaining ) + { + /* Add already Tx bytes */ + gIsoDep.APDUTxPos += gIsoDep.txBufLen; + + /* Convert APDU TxRxParams to I-Block TxRxParams */ + rfalIsoDepApdu2IBLockParam( gIsoDep.APDUParam, &txRxParam, gIsoDep.APDUTxPos, gIsoDep.APDURxPos ); + + if( txRxParam.txBufLen > 0U ) /* MISRA 21.18 */ + { + /* Move next I-Block to beginning of APDU Tx buffer */ + RFAL_MEMCPY( gIsoDep.APDUParam.txBuf->apdu, &gIsoDep.APDUParam.txBuf->apdu[gIsoDep.APDUTxPos], txRxParam.txBufLen ); + } + + RFAL_EXIT_ON_ERR( ret, rfalIsoDepStartTransceive( txRxParam ) ); + return RFAL_ERR_BUSY; + } + + /* APDU TxRx is done */ + /* fall through */ + + /*******************************************************************************/ + case RFAL_ERR_AGAIN: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* Check if no APDU transceive has been started before (data from rfalIsoDepListenStartActivation) */ + if( gIsoDep.APDUParam.rxLen == NULL ) + { + if( ret == RFAL_ERR_AGAIN ) + { + /* In Listen mode first chained packet cannot be retrieved via APDU interface */ + return RFAL_ERR_NOTSUPP; + } + + /* TxRx is complete and full data is already available */ + return RFAL_ERR_NONE; + } + + if( *gIsoDep.APDUParam.rxLen > 0U ) /* MISRA 21.18 */ + { + /* Ensure that data in tmpBuf still fits into APDU buffer */ + if( (gIsoDep.APDURxPos + (*gIsoDep.APDUParam.rxLen)) > (uint16_t)RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN ) + { + return RFAL_ERR_NOMEM; + } + + /* Copy chained packet from tmp buffer to APDU buffer */ + RFAL_MEMCPY( &gIsoDep.APDUParam.rxBuf->apdu[gIsoDep.APDURxPos], gIsoDep.APDUParam.tmpBuf->inf, *gIsoDep.APDUParam.rxLen ); + gIsoDep.APDURxPos += *gIsoDep.APDUParam.rxLen; + } + + /* Update output param rxLen */ + *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos; + + /* Wait for following I-Block or APDU TxRx has finished */ + return ((ret == RFAL_ERR_AGAIN) ? RFAL_ERR_BUSY : RFAL_ERR_NONE); + + /*******************************************************************************/ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + + return ret; + } + +#endif /* RFAL_FEATURE_ISO_DEP */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfc.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfc.c new file mode 100644 index 0000000..4187efe --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfc.c @@ -0,0 +1,2278 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2020 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/*! \file rfal_nfc.c + * + * \author Gustavo Patricio + * + * \brief RFAL NFC device + * + * This module provides the required features to behave as an NFC Poller + * or Listener device. It grants an easy to use interface for the following + * activities: Technology Detection, Collision Resolution, Activation, + * Data Exchange, and Deactivation + * + * This layer is influenced by (but not fully aligned with) the NFC Forum + * specifications, in particular: Activity 2.0 and NCI 2.0 + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfc.h" +#include "rfal_utils.h" +#include "rfal_analogConfig.h" + + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +#define rfalNfcNfcNotify( st ) if( gNfcDev.disc.notifyCb != NULL ) gNfcDev.disc.notifyCb( (st) ) + +#define rfalNfcpCbPollerInitialize() ((gNfcDev.disc.propNfc.rfalNfcpPollerInitialize != NULL) ? gNfcDev.disc.propNfc.rfalNfcpPollerInitialize() : RFAL_ERR_NOTSUPP ) +#define rfalNfcpCbPollerTechnologyDetection() ((gNfcDev.disc.propNfc.rfalNfcpPollerTechnologyDetection != NULL) ? gNfcDev.disc.propNfc.rfalNfcpPollerTechnologyDetection() : RFAL_ERR_TIMEOUT ) +#define rfalNfcpCbPollerStartCollisionResolution() ((gNfcDev.disc.propNfc.rfalNfcpPollerStartCollisionResolution != NULL) ? gNfcDev.disc.propNfc.rfalNfcpPollerStartCollisionResolution() : RFAL_ERR_NOTSUPP ) +#define rfalNfcpCbPollerGetCollisionResolutionStatus() ((gNfcDev.disc.propNfc.rfalNfcpPollerGetCollisionResolutionStatus != NULL) ? gNfcDev.disc.propNfc.rfalNfcpPollerGetCollisionResolutionStatus() : RFAL_ERR_NOTSUPP ) +#define rfalNfcpCbStartActivation() ((gNfcDev.disc.propNfc.rfalNfcpStartActivation != NULL) ? gNfcDev.disc.propNfc.rfalNfcpStartActivation() : RFAL_ERR_NOTSUPP ) +#define rfalNfcpCbGetActivationStatus() ((gNfcDev.disc.propNfc.rfalNfcpGetActivationStatus != NULL) ? gNfcDev.disc.propNfc.rfalNfcpGetActivationStatus() : RFAL_ERR_NOTSUPP ) + +#define rfalNfcHasPollerTechs() ((gNfcDev.disc.techs2Find & (RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V | \ + RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB | RFAL_NFC_POLL_TECH_PROP)) != 0U) + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + + + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ +#ifdef RFAL_TEST_MODE + rfalNfc gNfcDev; +#else /* RFAL_TEST_MODE */ + static rfalNfc gNfcDev; +#endif /* RFAL_TEST_MODE */ + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode rfalNfcPollTechDetetection( void ); +static ReturnCode rfalNfcPollCollResolution( void ); +static ReturnCode rfalNfcPollActivation( uint8_t devIt ); +static ReturnCode rfalNfcDeactivation( void ); + +#if RFAL_FEATURE_NFC_DEP +static ReturnCode rfalNfcNfcDepActivate( rfalNfcDevice *device, rfalNfcDepCommMode commMode, const uint8_t *atrReq, uint16_t atrReqLen ); +#endif /* RFAL_FEATURE_NFC_DEP */ + +#if RFAL_FEATURE_LISTEN_MODE +static ReturnCode rfalNfcListenActivation( void ); +#endif /* RFAL_FEATURE_LISTEN_MODE*/ + + +/*******************************************************************************/ +ReturnCode rfalNfcInitialize( void ) +{ + ReturnCode err; + + gNfcDev.state = RFAL_NFC_STATE_NOTINIT; + + +#ifdef RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG + /* Initialize the AC if not already done */ + /* Prevents reseting to default AC table in case another has been loaded */ + /* meanwhile - For use cases where a dynamic AC is loaded at run time */ + if( (!rfalAnalogConfigIsReady()) ) +#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ + { + rfalAnalogConfigInitialize(); /* Initialize RFAL's Analog Configs */ + } + + RFAL_EXIT_ON_ERR( err, rfalInitialize() ); /* Initialize RFAL */ + + RFAL_MEMSET( &gNfcDev, 0x00, sizeof(gNfcDev) ); + + gNfcDev.state = RFAL_NFC_STATE_IDLE; /* Go to initialized */ + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcDiscover( const rfalNfcDiscoverParam *disParams ) +{ + /* Check if initialization has been performed */ + if( gNfcDev.state != RFAL_NFC_STATE_IDLE ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check valid parameters */ + if( (disParams == NULL) || (disParams->devLimit > RFAL_NFC_MAX_DEVICES) || (disParams->devLimit == 0U) || + ( (disParams->maxBR > RFAL_BR_1695) && (disParams->maxBR != RFAL_BR_KEEP) ) || + ( ((disParams->techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) && (disParams->nfcfBR != RFAL_BR_212) && (disParams->nfcfBR != RFAL_BR_424) ) || + ( (((disParams->techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) && (disParams->ap2pBR > RFAL_BR_424)) || (disParams->GBLen > RFAL_NFCDEP_GB_MAX_LEN) ) ) + { + return RFAL_ERR_PARAM; + } + + if( (((disParams->techs2Find & RFAL_NFC_POLL_TECH_A) != 0U) && (!((bool)RFAL_FEATURE_NFCA))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_B) != 0U) && (!((bool)RFAL_FEATURE_NFCB))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) && (!((bool)RFAL_FEATURE_NFCF))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_V) != 0U) && (!((bool)RFAL_FEATURE_NFCV))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_ST25TB) != 0U) && (!((bool)RFAL_FEATURE_ST25TB))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) && (!((bool)RFAL_FEATURE_NFC_DEP))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_A) != 0U) && (!((bool)RFAL_FEATURE_NFCA))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_B) != 0U) && (!((bool)RFAL_FEATURE_NFCB))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_F) != 0U) && (!((bool)RFAL_FEATURE_NFCF))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_AP2P) != 0U) && (!((bool)RFAL_FEATURE_NFC_DEP))) ) + { + return RFAL_ERR_DISABLED; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */ + } + + if( (((disParams->techs2Find & RFAL_NFC_POLL_TECH_A) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_NFCA))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_B) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_NFCB))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_NFCF))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_V) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_NFCV))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_ST25TB) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_NFCB))) || + (((disParams->techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) && (!((bool)RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_A) != 0U) && (!((bool)RFAL_SUPPORT_MODE_LISTEN_NFCA))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_B) != 0U) && (!((bool)RFAL_SUPPORT_MODE_LISTEN_NFCB))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_F) != 0U) && (!((bool)RFAL_SUPPORT_MODE_LISTEN_NFCF))) || + (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_AP2P) != 0U) && (!((bool)RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P))) ) + { + return RFAL_ERR_NOTSUPP; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */ + } + + /* Initialize context for discovery */ + gNfcDev.activeDev = NULL; + gNfcDev.techsFound = RFAL_NFC_TECH_NONE; + gNfcDev.techDctCnt = 0; + gNfcDev.devCnt = 0; + gNfcDev.deactType = RFAL_NFC_DEACTIVATE_DISCOVERY; + gNfcDev.isTechInit = false; + gNfcDev.isFieldOn = false; + gNfcDev.isDeactivating = false; + gNfcDev.disc = *disParams; + + + /* Calculate Listen Mask */ + gNfcDev.lmMask = 0U; + gNfcDev.lmMask |= (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_A) != 0U) ? RFAL_LM_MASK_NFCA : 0U); + gNfcDev.lmMask |= (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_B) != 0U) ? RFAL_LM_MASK_NFCB : 0U); + gNfcDev.lmMask |= (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_F) != 0U) ? RFAL_LM_MASK_NFCF : 0U); + gNfcDev.lmMask |= (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_AP2P) != 0U) ? RFAL_LM_MASK_ACTIVE_P2P : 0U); + +#if !RFAL_FEATURE_LISTEN_MODE + /* Check if Listen Mode is supported/Enabled */ + if( gNfcDev.lmMask != 0U ) + { + return RFAL_ERR_DISABLED; + } +#endif + + gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcDeactivate( rfalNfcDeactivateType deactType ) +{ + ReturnCode ret; + + /* Check for valid state */ + if( (gNfcDev.state <= RFAL_NFC_STATE_IDLE) || ((deactType == RFAL_NFC_DEACTIVATE_SLEEP) && ((gNfcDev.state < RFAL_NFC_STATE_ACTIVATED) || (gNfcDev.activeDev == NULL))) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check valid paramters for the deactivation types */ + if( ( (deactType == RFAL_NFC_DEACTIVATE_SLEEP) && rfalNfcIsRemDevPoller(gNfcDev.activeDev->type) ) || + ( (deactType == RFAL_NFC_DEACTIVATE_DISCOVERY) && (gNfcDev.disc.techs2Find == RFAL_NFC_TECH_NONE) ) ) + { + return RFAL_ERR_PARAM; + } + + gNfcDev.deactType = deactType; + + /* Check if Discovery is to continue afterwards or back to Select */ + if( (deactType == RFAL_NFC_DEACTIVATE_DISCOVERY) || (deactType == RFAL_NFC_DEACTIVATE_SLEEP) ) + { + /* If so let the state machine continue*/ + gNfcDev.state = RFAL_NFC_STATE_DEACTIVATION; + } + else + { + /* Otherwise deactivate immediately and go to IDLE */ + rfalRunBlocking( ret, rfalNfcDeactivation() ); + gNfcDev.state = RFAL_NFC_STATE_IDLE; + } + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcSelect( uint8_t devIdx ) +{ + /* Check for valid state */ + if( gNfcDev.state != RFAL_NFC_STATE_POLL_SELECT ) + { + return RFAL_ERR_WRONG_STATE; + } + + gNfcDev.isTechInit = false; + gNfcDev.selDevIdx = devIdx; + gNfcDev.state = RFAL_NFC_STATE_POLL_ACTIVATION; + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +rfalNfc* rfalNfcGetDev( void ) +{ + return &gNfcDev; +} + +/*******************************************************************************/ +rfalNfcState rfalNfcGetState( void ) +{ + return gNfcDev.state; +} + +/*******************************************************************************/ +ReturnCode rfalNfcGetDevicesFound( rfalNfcDevice **devList, uint8_t *devCnt ) +{ + /* Check for valid state */ + if( gNfcDev.state < RFAL_NFC_STATE_POLL_SELECT ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check valid parameters */ + if( (devList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *devCnt = gNfcDev.devCnt; + *devList = gNfcDev.devList; + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcGetActiveDevice( rfalNfcDevice **dev ) +{ + /* Check for valid state */ + if( gNfcDev.state < RFAL_NFC_STATE_ACTIVATED ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check valid parameter */ + if( dev == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Check for valid state */ + if( (gNfcDev.devCnt == 0U) || (gNfcDev.activeDev == NULL) ) + { + return RFAL_ERR_REQUEST; + } + + *dev = gNfcDev.activeDev; + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +void rfalNfcWorker( void ) +{ + ReturnCode err; + + rfalWorker(); /* Execute RFAL process */ + + switch( gNfcDev.state ) + { + /*******************************************************************************/ + case RFAL_NFC_STATE_NOTINIT: + case RFAL_NFC_STATE_IDLE: + break; + + /*******************************************************************************/ + case RFAL_NFC_STATE_START_DISCOVERY: + + /* Initialize context for discovery cycle */ + gNfcDev.devCnt = 0; + gNfcDev.selDevIdx = 0; + gNfcDev.techsFound = RFAL_NFC_TECH_NONE; + gNfcDev.techs2do = gNfcDev.disc.techs2Find; + gNfcDev.state = RFAL_NFC_STATE_POLL_TECHDETECT; + gNfcDev.isDeactivating = false; + + /* Start total duration timer */ + platformTimerDestroy( gNfcDev.discTmr ); + gNfcDev.discTmr = (uint32_t)platformTimerCreate( gNfcDev.disc.totalDuration ); + + #if RFAL_FEATURE_WAKEUP_MODE + /* Check if Low power Wake-Up is to be performed */ + if( (gNfcDev.disc.wakeupEnabled) && ( ((gNfcDev.techDctCnt == 0U) && (gNfcDev.disc.wakeupPollBefore == false)) || (gNfcDev.techDctCnt >= gNfcDev.disc.wakeupNPolls)) ) + { + /* Initialize Low power Wake-up mode and wait */ + err = rfalWakeUpModeStart( (gNfcDev.disc.wakeupConfigDefault ? NULL : &gNfcDev.disc.wakeupConfig) ); + if( err == RFAL_ERR_NONE ) + { + gNfcDev.state = RFAL_NFC_STATE_WAKEUP_MODE; + } + } + gNfcDev.techDctCnt++; + + #endif /* RFAL_FEATURE_WAKEUP_MODE */ + + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller that WU or Technology Detection has started */ + break; + + /*******************************************************************************/ + case RFAL_NFC_STATE_WAKEUP_MODE: + + #if RFAL_FEATURE_WAKEUP_MODE + /* Check if the Wake-up mode has woke */ + if( rfalWakeUpModeHasWoke() ) + { + rfalWakeUpModeStop(); /* Disable Wake-up mode */ + gNfcDev.state = RFAL_NFC_STATE_POLL_TECHDETECT; /* Go to Technology detection */ + gNfcDev.techDctCnt = 1; /* Tech Detect counter (1 woke) */ + + /* (Re)Start total duration timer upon waking up */ + platformTimerDestroy( gNfcDev.discTmr ); + gNfcDev.discTmr = (uint32_t)platformTimerCreate( gNfcDev.disc.totalDuration ); + + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller that WU has woke */ + } + #endif /* RFAL_FEATURE_WAKEUP_MODE */ + + break; + + /*******************************************************************************/ + case RFAL_NFC_STATE_POLL_TECHDETECT: + + err = rfalNfcPollTechDetetection(); /* Perform Technology Detection */ + if( err != RFAL_ERR_BUSY ) /* Wait until all technologies are performed */ + { + if( ( err != RFAL_ERR_NONE) || (gNfcDev.techsFound == RFAL_NFC_TECH_NONE) )/* Check if any error occurred or no techs were found */ + { + rfalFieldOff(); + gNfcDev.isFieldOn = false; + gNfcDev.state = RFAL_NFC_STATE_LISTEN_TECHDETECT; /* Nothing found as poller, go to listener */ + break; + } + + gNfcDev.techs2do = gNfcDev.techsFound; /* Store the found technologies for collision resolution */ + gNfcDev.state = RFAL_NFC_STATE_POLL_COLAVOIDANCE; /* One or more devices found, go to Collision Avoidance */ + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_POLL_COLAVOIDANCE: + + err = rfalNfcPollCollResolution(); /* Resolve any eventual collision */ + if( err != RFAL_ERR_BUSY ) /* Wait until all technologies are performed */ + { + if( (err != RFAL_ERR_NONE) || (gNfcDev.devCnt == 0U) ) /* Check if any error occurred or no devices were found */ + { + gNfcDev.deactType = RFAL_NFC_DEACTIVATE_DISCOVERY; + gNfcDev.state = RFAL_NFC_STATE_DEACTIVATION; + break; /* Unable to retrieve any device, restart loop */ + } + + /* Check if more than one device has been found */ + if( gNfcDev.devCnt > 1U ) + { + /* If more than one device was found inform upper layer to choose which one to activate */ + if( gNfcDev.disc.notifyCb != NULL ) + { + gNfcDev.state = RFAL_NFC_STATE_POLL_SELECT; + gNfcDev.disc.notifyCb( gNfcDev.state ); + break; + } + } + + /* If only one device or no callback has been set, activate the first device found */ + gNfcDev.selDevIdx = 0U; + gNfcDev.state = RFAL_NFC_STATE_POLL_ACTIVATION; + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_POLL_ACTIVATION: + + err = rfalNfcPollActivation( gNfcDev.selDevIdx ); + if( err != RFAL_ERR_BUSY ) /* Wait until all Activation is complete */ + { + if( err != RFAL_ERR_NONE ) /* Check if activation has failed */ + { + /* Check if more than one device has been found */ + if( (gNfcDev.devCnt > 1U) && (gNfcDev.disc.notifyCb != NULL) ) + { + gNfcDev.state = RFAL_NFC_STATE_POLL_SELECT; + rfalNfcNfcNotify( gNfcDev.state ); + break; + } + + gNfcDev.deactType = RFAL_NFC_DEACTIVATE_DISCOVERY; /* Ensure deactivation, not Sleep */ + gNfcDev.state = RFAL_NFC_STATE_DEACTIVATION; /* If Activation failed, restart loop */ + break; + } + + gNfcDev.state = RFAL_NFC_STATE_ACTIVATED; /* Device has been properly activated */ + rfalNfcNfcNotify( gNfcDev.state ); /* Inform upper layer that a device has been activated */ + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_DATAEXCHANGE: + + rfalNfcDataExchangeGetStatus(); /* Run the internal state machine */ + + if( gNfcDev.dataExErr != RFAL_ERR_BUSY ) /* If Dataexchange has terminated */ + { + gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE; /* Go to done state */ + rfalNfcNfcNotify( gNfcDev.state ); /* And notify caller */ + } + if( gNfcDev.dataExErr == RFAL_ERR_SLEEP_REQ ) /* Check if Listen mode has to go to Sleep */ + { + gNfcDev.state = RFAL_NFC_STATE_LISTEN_SLEEP; /* Go to Listen Sleep state */ + rfalNfcNfcNotify( gNfcDev.state ); /* And notify caller */ + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_DEACTIVATION: + + err = rfalNfcDeactivation(); /* Deactivate current device */ + if( err != RFAL_ERR_BUSY ) + { + if( gNfcDev.deactType == RFAL_NFC_DEACTIVATE_SLEEP ) + { + gNfcDev.state = RFAL_NFC_STATE_POLL_SELECT; + } + else + { + gNfcDev.state = ( (gNfcDev.deactType == RFAL_NFC_DEACTIVATE_DISCOVERY) ? RFAL_NFC_STATE_START_DISCOVERY : RFAL_NFC_STATE_IDLE ); + } + + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller */ + } + break; + + /*******************************************************************************/ + case RFAL_NFC_STATE_LISTEN_TECHDETECT: + + if( platformTimerIsExpired( gNfcDev.discTmr ) ) + { + #if RFAL_FEATURE_LISTEN_MODE + rfalListenStop(); + #else + rfalFieldOff(); + #endif /* RFAL_FEATURE_LISTEN_MODE */ + gNfcDev.isFieldOn = false; + + gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */ + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller */ + break; + } + + #if RFAL_FEATURE_LISTEN_MODE + + if( gNfcDev.lmMask != 0U ) /* Check if configured to perform Listen mode */ + { + err = rfalListenStart( gNfcDev.lmMask, &gNfcDev.disc.lmConfigPA, NULL, &gNfcDev.disc.lmConfigPF, (uint8_t*)&gNfcDev.rxBuf.rfBuf, (uint16_t)rfalConvBytesToBits(sizeof(gNfcDev.rxBuf.rfBuf)), &gNfcDev.rxLen ); + if( err == RFAL_ERR_NONE ) + { + gNfcDev.state = RFAL_NFC_STATE_LISTEN_COLAVOIDANCE; /* Wait for listen mode to be activated */ + } + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_LISTEN_COLAVOIDANCE: + + if( platformTimerIsExpired( gNfcDev.discTmr ) ) /* Check if the total duration has been reached */ + { + rfalListenStop(); + gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */ + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller */ + break; + } + + /* Check for external field */ + if( rfalListenGetState( NULL, NULL ) >= RFAL_LM_STATE_IDLE ) + { + gNfcDev.state = RFAL_NFC_STATE_LISTEN_ACTIVATION; /* Wait for listen mode to be activated */ + } + break; + + + /*******************************************************************************/ + case RFAL_NFC_STATE_LISTEN_ACTIVATION: + case RFAL_NFC_STATE_LISTEN_SLEEP: + + err = rfalNfcListenActivation(); + if( err != RFAL_ERR_BUSY ) + { + if( err == RFAL_ERR_NONE ) + { + gNfcDev.activeDev = gNfcDev.devList; /* Assign the active device to be used further on */ + gNfcDev.devCnt++; + + gNfcDev.state = RFAL_NFC_STATE_ACTIVATED; /* Device has been properly activated */ + rfalNfcNfcNotify( gNfcDev.state ); /* Inform upper layer that a device has been activated */ + } + else if( (!platformTimerIsExpired( gNfcDev.discTmr )) && (err == RFAL_ERR_LINK_LOSS) && (gNfcDev.state == RFAL_NFC_STATE_LISTEN_ACTIVATION) ) + { + break; /* Field|Link broken during activation, keep in Listen the remaining total duration */ + } + else + { + rfalListenStop(); + gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */ + rfalNfcNfcNotify( gNfcDev.state ); /* Notify caller */ + } + } + #endif /* RFAL_FEATURE_LISTEN_MODE */ + break; + + /*******************************************************************************/ + case RFAL_NFC_STATE_ACTIVATED: + case RFAL_NFC_STATE_POLL_SELECT: + case RFAL_NFC_STATE_DATAEXCHANGE_DONE: + default: + return; + } +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ) +{ + ReturnCode err; + rfalTransceiveContext ctx; + + /*******************************************************************************/ + /* The Data Exchange is divided in two different moments, the trigger/Start of * + * the transfer followed by the check until its completion */ + if( (gNfcDev.state >= RFAL_NFC_STATE_ACTIVATED) && (gNfcDev.activeDev != NULL) ) + { + + /*******************************************************************************/ + /* In Listen mode is the Poller that initiates the communicatation */ + /* Assign output parameters and rfalNfcDataExchangeGetStatus will return */ + /* incoming data from Poller/Initiator */ + if( (gNfcDev.state == RFAL_NFC_STATE_ACTIVATED) && rfalNfcIsRemDevPoller( gNfcDev.activeDev->type ) ) + { + if( txDataLen > 0U ) + { + return RFAL_ERR_WRONG_STATE; + } + + *rvdLen = (uint16_t*)&gNfcDev.rxLen; + *rxData = (uint8_t*)( (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ? gNfcDev.rxBuf.isoDepBuf.apdu : + ((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ? gNfcDev.rxBuf.nfcDepBuf.pdu : gNfcDev.rxBuf.rfBuf)); + return RFAL_ERR_NONE; + } + + + /*******************************************************************************/ + switch( gNfcDev.activeDev->rfInterface ) /* Check which RF interface shall be used/has been activated */ + { + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_RF: + + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, RFAL_TXRX_FLAGS_DEFAULT, fwt ); + ctx.txBufLen = txDataLen; /* RF interface uses number of bits */ + + *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; + *rvdLen = (uint16_t*)&gNfcDev.rxLen; + err = rfalStartTransceive( &ctx ); + break; + + #if RFAL_FEATURE_ISO_DEP + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_ISODEP: + { + rfalIsoDepApduTxRxParam rfalIsoDepTxRx; + + if( txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu) ) + { + return RFAL_ERR_NOMEM; + } + + if( txDataLen > 0U ) + { + RFAL_MEMCPY( (uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen ); + } + + rfalIsoDepTxRx.DID = RFAL_ISODEP_NO_DID; + rfalIsoDepTxRx.ourFSx = RFAL_ISODEP_FSX_KEEP; + rfalIsoDepTxRx.FSx = gNfcDev.activeDev->proto.isoDep.info.FSx; + rfalIsoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT; + rfalIsoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT; + rfalIsoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf; + rfalIsoDepTxRx.txBufLen = txDataLen; + rfalIsoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf; + rfalIsoDepTxRx.rxLen = &gNfcDev.rxLen; + rfalIsoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf; + *rxData = (uint8_t*)gNfcDev.rxBuf.isoDepBuf.apdu; + *rvdLen = (uint16_t*)&gNfcDev.rxLen; + + /*******************************************************************************/ + /* Trigger a RFAL ISO-DEP Transceive */ + err = rfalIsoDepStartApduTransceive( rfalIsoDepTxRx ); + break; + } + #endif /* RFAL_FEATURE_ISO_DEP */ + + #if RFAL_FEATURE_NFC_DEP + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_NFCDEP: + { + rfalNfcDepPduTxRxParam rfalNfcDepTxRx; + + if( txDataLen > sizeof(gNfcDev.txBuf.nfcDepBuf.pdu) ) + { + return RFAL_ERR_NOMEM; + } + + if( txDataLen > 0U) + { + RFAL_MEMCPY( (uint8_t*)gNfcDev.txBuf.nfcDepBuf.pdu, txData, txDataLen ); + } + + rfalNfcDepTxRx.DID = RFAL_NFCDEP_DID_KEEP; + rfalNfcDepTxRx.FSx = rfalNfcIsRemDevListener(gNfcDev.activeDev->type) ? + rfalNfcDepLR2FS( (uint8_t)rfalNfcDepPP2LR( gNfcDev.activeDev->proto.nfcDep.activation.Target.ATR_RES.PPt ) ) : + rfalNfcDepLR2FS( (uint8_t)rfalNfcDepPP2LR( gNfcDev.activeDev->proto.nfcDep.activation.Initiator.ATR_REQ.PPi ) ); + rfalNfcDepTxRx.dFWT = gNfcDev.activeDev->proto.nfcDep.info.dFWT; + rfalNfcDepTxRx.FWT = gNfcDev.activeDev->proto.nfcDep.info.FWT; + rfalNfcDepTxRx.txBuf = &gNfcDev.txBuf.nfcDepBuf; + rfalNfcDepTxRx.txBufLen = txDataLen; + rfalNfcDepTxRx.rxBuf = &gNfcDev.rxBuf.nfcDepBuf; + rfalNfcDepTxRx.rxLen = &gNfcDev.rxLen; + rfalNfcDepTxRx.tmpBuf = &gNfcDev.tmpBuf.nfcDepBuf; + *rxData = (uint8_t*)gNfcDev.rxBuf.nfcDepBuf.pdu; + *rvdLen = (uint16_t*)&gNfcDev.rxLen; + + /*******************************************************************************/ + /* Trigger a RFAL NFC-DEP Transceive */ + err = rfalNfcDepStartPduTransceive( rfalNfcDepTxRx ); + break; + } + #endif /* RFAL_FEATURE_NFC_DEP */ + + /*******************************************************************************/ + default: + err = RFAL_ERR_PARAM; + break; + } + + /* If a transceive has succesfully started flag Data Exchange as ongoing */ + if( err == RFAL_ERR_NONE ) + { + gNfcDev.dataExErr = RFAL_ERR_BUSY; + gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE; + } + + return err; + } + + return RFAL_ERR_WRONG_STATE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDataExchangeGetStatus( void ) +{ + /*******************************************************************************/ + /* Check if it's the first frame received in Listen mode */ + if( gNfcDev.state == RFAL_NFC_STATE_ACTIVATED ) + { + /* Continue data exchange as normal */ + gNfcDev.dataExErr = RFAL_ERR_BUSY; + gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE; + + /* Check if we performing in T3T CE */ + if( (gNfcDev.activeDev->type == RFAL_NFC_POLL_TYPE_NFCF) && (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_RF) ) + { + /* The first frame has been retrieved by rfalListenMode, flag data immediately */ + /* Can only call rfalGetTransceiveStatus() after starting a transceive with rfalStartTransceive */ + gNfcDev.dataExErr = RFAL_ERR_NONE; + } + } + + + /*******************************************************************************/ + /* Check if we are in we have been placed to sleep, and return last error */ + if( gNfcDev.state == RFAL_NFC_STATE_LISTEN_SLEEP ) + { + return gNfcDev.dataExErr; /* RFAL_ERR_SLEEP_REQ */ + } + + + /*******************************************************************************/ + /* Check if Data exchange has been started */ + if( (gNfcDev.state != RFAL_NFC_STATE_DATAEXCHANGE) && (gNfcDev.state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check if Data exchange is still ongoing */ + if( gNfcDev.dataExErr == RFAL_ERR_BUSY ) + { + switch( gNfcDev.activeDev->rfInterface ) + { + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_RF: + gNfcDev.dataExErr = rfalGetTransceiveStatus(); + break; + + #if RFAL_FEATURE_ISO_DEP + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_ISODEP: + gNfcDev.dataExErr = rfalIsoDepGetApduTransceiveStatus(); + break; + #endif /* RFAL_FEATURE_ISO_DEP */ + + /*******************************************************************************/ + #if RFAL_FEATURE_NFC_DEP + case RFAL_NFC_INTERFACE_NFCDEP: + gNfcDev.dataExErr = rfalNfcDepGetPduTransceiveStatus(); + break; + #endif /* RFAL_FEATURE_NFC_DEP */ + + /*******************************************************************************/ + default: + gNfcDev.dataExErr = RFAL_ERR_PARAM; + break; + } + + #if RFAL_FEATURE_LISTEN_MODE + /*******************************************************************************/ + /* If a Sleep request has been received (Listen Mode) go to sleep immediately */ + if( gNfcDev.dataExErr == RFAL_ERR_SLEEP_REQ ) + { + RFAL_EXIT_ON_ERR( gNfcDev.dataExErr, rfalListenSleepStart( RFAL_LM_STATE_SLEEP_A, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen ) ); + + /* If set Sleep was succesfull keep restore the Sleep request signal */ + gNfcDev.dataExErr = RFAL_ERR_SLEEP_REQ; + } + #endif /* RFAL_FEATURE_LISTEN_MODE */ + + } + + return gNfcDev.dataExErr; +} + +/*! + ****************************************************************************** + * \brief Poller Technology Detection + * + * This method implements the Technology Detection / Poll for different + * device technologies. + * + * \return RFAL_ERR_NONE : Operation completed with no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_XXXX : Error occurred + * + ****************************************************************************** + */ +static ReturnCode rfalNfcPollTechDetetection( void ) +{ + ReturnCode err; + + err = RFAL_ERR_NONE; + + /* Suppress warning when specific RFAL features have been disabled */ + RFAL_NO_WARNING(err); + + + /*******************************************************************************/ + /* AP2P Technology Detection */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_AP2P) != 0U) ) + { + + #if RFAL_FEATURE_NFC_DEP + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalSetMode( RFAL_MODE_POLL_ACTIVE_P2P, gNfcDev.disc.ap2pBR, gNfcDev.disc.ap2pBR ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + rfalSetFDTListen( RFAL_FDT_LISTEN_AP2P_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_AP2P_POLLER ); + rfalSetGT( RFAL_GT_AP2P_ADJUSTED ); + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* Turns the Field On and starts GT timer */ + gNfcDev.isTechInit = true; + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_AP2P; + + err = rfalNfcNfcDepActivate( gNfcDev.devList, RFAL_NFCDEP_COMM_ACTIVE, NULL, 0 );/* Poll for NFC-A devices */ + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_AP2P; + + gNfcDev.devList->type = RFAL_NFC_LISTEN_TYPE_AP2P; + gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_NFCDEP; + gNfcDev.devCnt++; + + return RFAL_ERR_NONE; + } + + gNfcDev.isTechInit = false; + rfalFieldOff(); + } + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFC_DEP */ + } + + + /*******************************************************************************/ + /* Turn Field On if Passive Poll technologies are enabled */ + /*******************************************************************************/ + if( (!gNfcDev.isFieldOn) && ( (gNfcDev.disc.techs2Find & (RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_ST25TB | RFAL_NFC_POLL_TECH_PROP)) != 0U) ) + { + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* Turns the Field On */ + gNfcDev.isFieldOn = true; + return RFAL_ERR_BUSY; + } + + + /*******************************************************************************/ + /* Passive NFC-A Technology Detection */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_A) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_A) != 0U) ) + { + + #if RFAL_FEATURE_NFCA + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerInitialize() ); /* Initialize RFAL for NFC-A */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field is already On only starts GT timer */ + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; /* No operation currently ongoing */ + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + if( !gNfcDev.isOperOngoing ) + { + rfalNfcaPollerStartTechnologyDetection( gNfcDev.disc.compMode, &gNfcDev.sensRes );/* Poll for NFC-A devices */ + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalNfcaPollerGetTechnologyDetectionStatus(); + if( err != RFAL_ERR_BUSY ) + { + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_A; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_A; + } + + /* Check if bail-out after NFC-A Activity 2.1 9.2.3.21 */ + if( ((gNfcDev.disc.techs2Bail & RFAL_NFC_POLL_TECH_A) != 0U) && (gNfcDev.techsFound != 0U) ) + { + return RFAL_ERR_NONE; + } + } + + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFCA */ + } + + + /*******************************************************************************/ + /* Passive NFC-B Technology Detection */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_B) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_B) != 0U) ) + { + #if RFAL_FEATURE_NFCB + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcbPollerInitialize() ); /* Initialize RFAL for NFC-B */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field is already On only starts GT timer */ + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; /* No operation currently ongoing */ + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + + if( !gNfcDev.isOperOngoing ) + { + rfalNfcbPollerStartTechnologyDetection( gNfcDev.disc.compMode, &gNfcDev.sensbRes, &gNfcDev.sensbResLen );/* Poll for NFC-B devices */ + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalNfcbPollerGetTechnologyDetectionStatus(); + if( err != RFAL_ERR_BUSY ) + { + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_B; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_B; + } + + /* Check if bail-out after NFC-B Activity 2.1 9.2.3.26 */ + if( ((gNfcDev.disc.techs2Bail & RFAL_NFC_POLL_TECH_B) != 0U) && (gNfcDev.techsFound != 0U) ) + { + return RFAL_ERR_NONE; + } + } + + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFCB */ + } + + /*******************************************************************************/ + /* Passive NFC-F Technology Detection */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_F) != 0U) ) + { + #if RFAL_FEATURE_NFCF + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcfPollerInitialize( gNfcDev.disc.nfcfBR ) );/* Initialize RFAL for NFC-F */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field is already On only starts GT timer */ + + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; /* No operation currently ongoing */ + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + + if( !gNfcDev.isOperOngoing ) + { + rfalNfcfPollerStartCheckPresence(); + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalNfcfPollerGetCheckPresenceStatus(); /* Poll for NFC-F devices */ + if( err != RFAL_ERR_BUSY ) + { + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_F; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_F; + } + + /* Check if bail-out after NFC-F Activity 2.1 9.2.3.31 */ + if( ((gNfcDev.disc.techs2Bail & RFAL_NFC_POLL_TECH_F) != 0U) && (gNfcDev.techsFound != 0U) ) + { + return RFAL_ERR_NONE; + } + } + + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFCF */ + } + + + /*******************************************************************************/ + /* Passive NFC-V Technology Detection */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_V) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_V) != 0U) ) + { + #if RFAL_FEATURE_NFCV + + rfalNfcvInventoryRes invRes; + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcvPollerInitialize() ); /* Initialize RFAL for NFC-V */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field is already On only starts GT timer */ + gNfcDev.isTechInit = true; + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + err = rfalNfcvPollerCheckPresence( &invRes ); /* Poll for NFC-V devices */ + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_V; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_V; + } + + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFCV */ + } + + + /*******************************************************************************/ + /* Passive Proprietary Technology ST25TB */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_ST25TB) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_ST25TB) != 0U) ) + { + #if RFAL_FEATURE_ST25TB + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalSt25tbPollerInitialize() ); /* Initialize RFAL for NFC-V */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field is already On only starts GT timer */ + gNfcDev.isTechInit = true; + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + err = rfalSt25tbPollerCheckPresence( NULL ); /* Poll for ST25TB devices */ + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_ST25TB; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_ST25TB; + } + + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_ST25TB */ + } + + /*******************************************************************************/ + /* Passive Proprietary Technology */ + /*******************************************************************************/ + if( ((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_PROP) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_PROP) != 0U) ) + { + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcpCbPollerInitialize() ); /* Initialize RFAL for Proprietary NFC */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* As field may already be On only starts GT timer */ + gNfcDev.isTechInit = true; + } + + if( rfalIsGTExpired() ) /* Wait until Guard Time is fulfilled */ + { + err = rfalNfcpCbPollerTechnologyDetection(); /* Poll for devices */ + if( err == RFAL_ERR_NONE ) + { + gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_PROP; + } + + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_PROP; + } + + return RFAL_ERR_BUSY; + } + + return RFAL_ERR_NONE; +} + +/*! + ****************************************************************************** + * \brief Poller Collision Resolution + * + * This method implements the Collision Resolution on all technologies that + * have been detected before. + * + * \return RFAL_ERR_NONE : Operation completed with no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_XXXX : Error occurred + * + ****************************************************************************** + */ +static ReturnCode rfalNfcPollCollResolution( void ) +{ + uint8_t i; + static uint8_t devCnt; + ReturnCode err; + + err = RFAL_ERR_NONE; + i = 0; + + /* Suppress warning when specific RFAL features have been disabled */ + RFAL_NO_WARNING(err); + RFAL_NO_WARNING(devCnt); + RFAL_NO_WARNING(i); + + /* Check if device limit has been reached */ + if( gNfcDev.devCnt >= gNfcDev.disc.devLimit ) + { + return RFAL_ERR_NONE; + } + + /*******************************************************************************/ + /* NFC-A Collision Resolution */ + /*******************************************************************************/ +#if RFAL_FEATURE_NFCA + if( ((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_A) != 0U) && ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_A) != 0U) ) /* If a NFC-A device was found/detected, perform Collision Resolution */ + { + static rfalNfcaListenDevice nfcaDevList[RFAL_NFC_MAX_DEVICES]; + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerInitialize() ); /* Initialize RFAL for NFC-A */ + RFAL_EXIT_ON_ERR( err, rfalFieldOnAndStartGT() ); /* Turns the Field On and starts GT timer */ + + gNfcDev.isTechInit = true; /* Technology has been initialized */ + gNfcDev.isOperOngoing = false; /* No operation currently ongoing */ + } + + if( !rfalIsGTExpired() ) + { + return RFAL_ERR_BUSY; + } + + if( !gNfcDev.isOperOngoing ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerStartFullCollisionResolution( gNfcDev.disc.compMode, (gNfcDev.disc.devLimit - gNfcDev.devCnt), nfcaDevList, &devCnt ) ); + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalNfcaPollerGetFullCollisionResolutionStatus(); + if( err != RFAL_ERR_BUSY ) + { + gNfcDev.isTechInit = false; + gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_A; + + if( (err == RFAL_ERR_NONE) && (devCnt != 0U) ) + { + for( i=0; i gNfcDev.devCnt ) + { + return RFAL_ERR_WRONG_STATE; + } + + switch( gNfcDev.devList[devIt].type ) + { + /*******************************************************************************/ + /* AP2P Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_NFC_DEP + case RFAL_NFC_LISTEN_TYPE_AP2P: + /* Activation has already been (ATR_REQ) */ + + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + break; + #endif /* RFAL_FEATURE_NFC_DEP */ + + + /*******************************************************************************/ + /* Passive NFC-A Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_NFCA + case RFAL_NFC_LISTEN_TYPE_NFCA: + + if( !gNfcDev.isTechInit ) + { + rfalNfcaPollerInitialize(); + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; + return RFAL_ERR_BUSY; + } + + if( gNfcDev.devList[devIt].dev.nfca.isSleep ) /* Check if desired device is in Sleep */ + { + if( !gNfcDev.isOperOngoing ) + { + /* Wake up all cards */ + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerCheckPresence( RFAL_14443A_SHORTFRAME_CMD_WUPA, &gNfcDev.sensRes ) ); + + /* Select specific device */ + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerStartSelect( gNfcDev.devList[devIt].dev.nfca.nfcId1, gNfcDev.devList[devIt].dev.nfca.nfcId1Len, &gNfcDev.devList[devIt].dev.nfca.selRes ) ); + + gNfcDev.isOperOngoing = true; + } + else + { + RFAL_EXIT_ON_ERR( err, rfalNfcaPollerGetSelectStatus() ); + + + /* In case multiple NFC-A devices are present, when activating/waking a device that + is sleeping (not the last one) will make the active one to go back to IDLE. + Marking it as in sleep (Activity 2.2 9.4.4 Optional Symbol 2) will ensure that + gets correctly activated afterwards */ + for( devIdx = 0; devIdx < gNfcDev.devCnt; devIdx++ ) + { + if( gNfcDev.devList[devIdx].type == RFAL_NFC_LISTEN_TYPE_NFCA ) + { + gNfcDev.devList[devIdx].dev.nfca.isSleep = true; + } + } + + gNfcDev.devList[devIt].dev.nfca.isSleep = false; + gNfcDev.isOperOngoing = false; + } + return RFAL_ERR_BUSY; + } + + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfca.nfcId1; + gNfcDev.devList[devIt].nfcidLen = gNfcDev.devList[devIt].dev.nfca.nfcId1Len; + + /* If device supports multiple technologies assign protocol requested */ + nfcaType = gNfcDev.devList[devIt].dev.nfca.type; + if( nfcaType == RFAL_NFCA_T4T_NFCDEP ) + { + nfcaType = ( (gNfcDev.disc.p2pNfcaPrio) ? RFAL_NFCA_NFCDEP : RFAL_NFCA_T4T); + } + + /*******************************************************************************/ + /* Perform protocol specific activation */ + switch( nfcaType ) + { + /*******************************************************************************/ + case RFAL_NFCA_T1T: + + /* No further activation needed for T1T (RID already performed) */ + + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfca.ridRes.uid; + gNfcDev.devList[devIt].nfcidLen = RFAL_T1T_UID_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; + break; + + case RFAL_NFCA_T2T: + + /* No further activation needed for a T2T */ + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; + break; + + + /*******************************************************************************/ + case RFAL_NFCA_T4T: /* Device supports ISO-DEP */ + + #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL + if( !gNfcDev.isOperOngoing ) + { + /* Perform ISO-DEP (ISO14443-4) activation: RATS and PPS if supported */ + rfalIsoDepInitializeWithParams( gNfcDev.disc.compMode, RFAL_ISODEP_MAX_R_RETRYS, RFAL_ISODEP_MAX_WTX_NACK_RETRYS, RFAL_ISODEP_MAX_WTX_RETRYS, RFAL_ISODEP_MAX_DSL_RETRYS, RFAL_ISODEP_MAX_I_RETRYS, RFAL_ISODEP_RATS_RETRIES); + RFAL_EXIT_ON_ERR( err, rfalIsoDepPollAStartActivation( gNfcDev.disc.isoDepFS, RFAL_ISODEP_NO_DID, gNfcDev.disc.maxBR, &gNfcDev.devList[devIt].proto.isoDep ) ); + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalIsoDepPollAGetActivationStatus(); + if( err != RFAL_ERR_NONE ) + { + return err; + } + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_ISODEP; /* NFC-A T4T device activated */ + #else + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* No ISO-DEP supported activate using RF interface */ + #endif /* RFAL_FEATURE_ISO_DEP_POLL */ + break; + + /*******************************************************************************/ + case RFAL_NFCA_NFCDEP: /* Device supports NFC-DEP */ + + #if RFAL_FEATURE_NFC_DEP + /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */ + RFAL_EXIT_ON_ERR( err, rfalNfcNfcDepActivate( &gNfcDev.devList[devIt], RFAL_NFCDEP_COMM_PASSIVE, NULL, 0 ) ); + + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_NFCDEP; /* NFC-A P2P device activated */ + #else + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* No NFC-DEP supported activate using RF interface */ + #endif /* RFAL_FEATURE_NFC_DEP */ + break; + + /*******************************************************************************/ + case RFAL_NFCA_T4T_NFCDEP: /* Multiple proto resolved based on NFCA P2P Prio config */ + default: + return RFAL_ERR_WRONG_STATE; + } + break; + #endif /* RFAL_FEATURE_NFCA */ + + + /*******************************************************************************/ + /* Passive NFC-B Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_NFCB + case RFAL_NFC_LISTEN_TYPE_NFCB: + + if( !gNfcDev.isTechInit ) + { + rfalNfcbPollerInitialize(); + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; + + if( gNfcDev.devList[devIt].dev.nfcb.isSleep ) /* Check if desired device is in Sleep */ + { + /* Wake up all cards. SENSB_RES may return collision but the NFCID0 is available to explicitly select NFC-B card via ATTRIB; so error will be ignored here */ + rfalNfcbPollerStartCheckPresence( RFAL_NFCB_SENS_CMD_ALLB_REQ, RFAL_NFCB_SLOT_NUM_1, &gNfcDev.sensbRes, &gNfcDev.sensbResLen ); + } + + return RFAL_ERR_BUSY; + } + + if( gNfcDev.devList[devIt].dev.nfcb.isSleep ) /* Check if desired device is still in Sleep */ + { + /* Wake up all cards. SENSB_RES may return collision but the NFCID0 is available to explicitly select NFC-B card via ATTRIB; so error will be ignored here */ + RFAL_EXIT_ON_BUSY( err, rfalNfcbPollerGetCheckPresenceStatus() ); + + gNfcDev.devList[devIt].dev.nfcb.isSleep = false; + } + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcb.sensbRes.nfcid0; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCB_NFCID0_LEN; + + #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL + /* Check if device supports ISO-DEP (ISO14443-4) */ + if( (gNfcDev.devList[devIt].dev.nfcb.sensbRes.protInfo.FsciProType & RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK) != 0U ) + { + if( !gNfcDev.isOperOngoing ) + { + rfalIsoDepInitializeWithParams( gNfcDev.disc.compMode, RFAL_ISODEP_MAX_R_RETRYS, RFAL_ISODEP_MAX_WTX_NACK_RETRYS, RFAL_ISODEP_MAX_WTX_RETRYS, RFAL_ISODEP_MAX_DSL_RETRYS, RFAL_ISODEP_MAX_I_RETRYS, RFAL_ISODEP_RATS_RETRIES); + /* Perform ISO-DEP (ISO14443-4) activation: ATTRIB */ + RFAL_EXIT_ON_ERR( err, rfalIsoDepPollBStartActivation( gNfcDev.disc.isoDepFS, RFAL_ISODEP_NO_DID, gNfcDev.disc.maxBR, 0x00, &gNfcDev.devList[devIt].dev.nfcb, NULL, 0, &gNfcDev.devList[devIt].proto.isoDep ) ); + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalIsoDepPollBGetActivationStatus(); + if( err != RFAL_ERR_NONE ) + { + return err; + } + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_ISODEP; /* NFC-B T4T device activated */ + break; + } + + #endif /* RFAL_FEATURE_ISO_DEP_POLL */ + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* NFC-B device activated */ + break; + + #endif /* RFAL_FEATURE_NFCB */ + + + /*******************************************************************************/ + /* Passive NFC-F Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_NFCF + case RFAL_NFC_LISTEN_TYPE_NFCF: + + rfalNfcfPollerInitialize( gNfcDev.disc.nfcfBR ); + + #if RFAL_FEATURE_NFC_DEP + if( rfalNfcfIsNfcDepSupported( &gNfcDev.devList[devIt].dev.nfcf ) ) + { + /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */ + RFAL_EXIT_ON_ERR( err, rfalNfcNfcDepActivate( &gNfcDev.devList[devIt], RFAL_NFCDEP_COMM_PASSIVE, NULL, 0 ) ); + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_NFCDEP; /* NFC-F P2P device activated */ + break; + } + #endif /* RFAL_FEATURE_NFC_DEP */ + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcf.sensfRes.NFCID2; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCF_NFCID2_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* NFC-F T3T device activated */ + break; + #endif /* RFAL_FEATURE_NFCF */ + + + /*******************************************************************************/ + /* Passive NFC-V Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_NFCV + case RFAL_NFC_LISTEN_TYPE_NFCV: + + rfalNfcvPollerInitialize(); + + /* No specific activation needed for a T5T */ + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcv.InvRes.UID; + gNfcDev.devList[devIt].nfcidLen = RFAL_NFCV_UID_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* NFC-V T5T device activated */ + break; + #endif /* RFAL_FEATURE_NFCV */ + + + /*******************************************************************************/ + /* Passive ST25TB Activation */ + /*******************************************************************************/ + #if RFAL_FEATURE_ST25TB + case RFAL_NFC_LISTEN_TYPE_ST25TB: + + rfalSt25tbPollerInitialize(); + + /* No specific activation needed for a ST25TB */ + + /* Set NFCID */ + gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.st25tb.UID; + gNfcDev.devList[devIt].nfcidLen = RFAL_ST25TB_UID_LEN; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* ST25TB device activated */ + break; + #endif /* RFAL_FEATURE_ST25TB */ + + + /*******************************************************************************/ + /* Passive Proprietary NFC Activation */ + /*******************************************************************************/ + case RFAL_NFC_LISTEN_TYPE_PROP: + + if( !gNfcDev.isTechInit ) + { + RFAL_EXIT_ON_ERR( err, rfalNfcpCbPollerInitialize() ); + gNfcDev.isTechInit = true; + gNfcDev.isOperOngoing = false; + return RFAL_ERR_BUSY; + } + + + if( !gNfcDev.isOperOngoing ) + { + /* Start activation */ + RFAL_EXIT_ON_ERR( err, rfalNfcpCbStartActivation() ); + + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + + err = rfalNfcpCbGetActivationStatus(); + if( err != RFAL_ERR_NONE ) + { + return err; + } + + /* Clear NFCID */ + gNfcDev.devList[devIt].nfcid = NULL; + gNfcDev.devList[devIt].nfcidLen = 0; + + gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; + break; + + + /*******************************************************************************/ + default: + return RFAL_ERR_WRONG_STATE; + } + + gNfcDev.activeDev = &gNfcDev.devList[devIt]; /* Assign active device to be used further on */ + gNfcDev.isOperOngoing = false; + return RFAL_ERR_NONE; +} + + +/*! + ****************************************************************************** + * \brief Listener Activation + * + * This method handles the listen mode Activation according to the different + * protocols the Reader/Initiator performs + * + * \return RFAL_ERR_NONE : Operation completed with no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_PROTO : Unexpected frame received + * \return RFAL_ERR_XXXX : Error occurred + * + ****************************************************************************** + */ +#if RFAL_FEATURE_LISTEN_MODE +static ReturnCode rfalNfcListenActivation( void ) +{ + bool isDataRcvd; + ReturnCode ret; + rfalLmState lmSt; + rfalBitRate bitRate; +#if RFAL_FEATURE_NFC_DEP + uint8_t hdrLen; + + /* Set the header length in NFC-A */ + hdrLen = (RFAL_NFCDEP_SB_LEN + RFAL_NFCDEP_LEN_LEN); +#endif /* RFAL_FEATURE_NFC_DEP */ + + + lmSt = rfalListenGetState( &isDataRcvd, &bitRate ); + switch(lmSt) + { + + #if RFAL_FEATURE_NFCA + /*******************************************************************************/ + case RFAL_LM_STATE_ACTIVE_A: /* NFC-A CE activation */ + case RFAL_LM_STATE_ACTIVE_Ax: + + if( isDataRcvd ) /* Check if Reader/Initator has sent some data */ + { + /* Check if received data is a Sleep request */ + if( rfalNfcaListenerIsSleepReq( gNfcDev.rxBuf.rfBuf, rfalConvBitsToBytes(gNfcDev.rxLen)) ) /* Check if received data is a SLP_REQ */ + { + /* Set the Listen Mode in Sleep state */ + RFAL_EXIT_ON_ERR( ret, rfalListenSleepStart( RFAL_LM_STATE_SLEEP_A, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen ) ); + } + + #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN + /* Check if received data is a valid RATS */ + else if( rfalIsoDepIsRats( gNfcDev.rxBuf.rfBuf, (uint8_t)rfalConvBitsToBytes(gNfcDev.rxLen) ) ) + { + rfalIsoDepAtsParam atsParam; + rfalIsoDepListenActvParam rxParam; + + /* Set ATS parameters */ + atsParam.fsci = (uint8_t)RFAL_ISODEP_DEFAULT_FSCI; + atsParam.fwi = RFAL_ISODEP_DEFAULT_FWI; + atsParam.sfgi = RFAL_ISODEP_DEFAULT_SFGI; + atsParam.didSupport = false; + atsParam.ta = RFAL_ISODEP_ATS_TA_SAME_D; + atsParam.hb = NULL; + atsParam.hbLen = 0; + + /* Set Rx parameters */ + rxParam.rxBuf = (rfalIsoDepBufFormat*) &gNfcDev.rxBuf.isoDepBuf; /* PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */ + rxParam.rxLen = &gNfcDev.rxLen; + rxParam.isoDepDev = &gNfcDev.devList->proto.isoDep; + rxParam.isRxChaining = &gNfcDev.isRxChaining; + + rfalListenSetState( RFAL_LM_STATE_CARDEMU_4A ); /* Set next state CE T4T */ + rfalIsoDepInitialize(); /* Initialize ISO-DEP layer to handle ISO14443-a activation / RATS */ + + /* Set ISO-DEP layer to digest RATS and handle activation */ + RFAL_EXIT_ON_ERR( ret, rfalIsoDepListenStartActivation( &atsParam, NULL, gNfcDev.rxBuf.rfBuf, gNfcDev.rxLen, rxParam ) ); + } + #endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + + #if RFAL_FEATURE_NFC_DEP + + /* Check if received data is a valid ATR_REQ */ + else if( rfalNfcDepIsAtrReq( &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen), gNfcDev.devList->nfcid ) ) + { + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA; + RFAL_EXIT_ON_ERR( ret, rfalNfcNfcDepActivate( gNfcDev.devList, RFAL_NFCDEP_COMM_PASSIVE, &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen) ) ); + } + #endif /* RFAL_FEATURE_NFC_DEP */ + + else + { + return RFAL_ERR_PROTO; + } + } + return RFAL_ERR_BUSY; + + #endif /* RFAL_FEATURE_NFCA */ + + #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN + /*******************************************************************************/ + case RFAL_LM_STATE_CARDEMU_4A: /* T4T ISO-DEP activation */ + + ret = rfalIsoDepListenGetActivationStatus(); + if( ret == RFAL_ERR_NONE ) + { + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA; + gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_ISODEP; + gNfcDev.devList->nfcid = NULL; + gNfcDev.devList->nfcidLen = 0; + } + return ( (ret == RFAL_ERR_LINK_LOSS) ? RFAL_ERR_PROTO : ret); /* Link loss during protocol activation, reMap error */ + + #endif /* RFAL_FEATURE_ISO_DEP_LISTEN */ + + /*******************************************************************************/ + case RFAL_LM_STATE_READY_F: /* NFC-F CE activation */ + + if( isDataRcvd ) /* Wait for the first received data */ + { + #if RFAL_FEATURE_NFC_DEP + /* Set the header length in NFC-F */ + hdrLen = RFAL_NFCDEP_LEN_LEN; + + if( rfalNfcDepIsAtrReq( &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen), gNfcDev.devList->nfcid ) ) + { + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCF; + RFAL_EXIT_ON_ERR( ret, rfalNfcNfcDepActivate( gNfcDev.devList, RFAL_NFCDEP_COMM_PASSIVE, &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen) ) ); + } + else + #endif /* RFAL_FEATURE_NFC_DEP */ + { + rfalListenSetState( RFAL_LM_STATE_CARDEMU_3 ); /* First data already received - set T3T CE */ + } + } + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case RFAL_LM_STATE_CARDEMU_3: /* T3T activated */ + + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCF; + gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_RF; + gNfcDev.devList->nfcid = NULL; + gNfcDev.devList->nfcidLen = 0; + + return RFAL_ERR_NONE; + + #if RFAL_FEATURE_NFC_DEP + /*******************************************************************************/ + case RFAL_LM_STATE_TARGET_A: /* NFC-DEP activation */ + case RFAL_LM_STATE_TARGET_F: + + ret = rfalNfcDepListenGetActivationStatus(); + if( ret == RFAL_ERR_NONE ) + { + gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_NFCDEP; + gNfcDev.devList->nfcid = gNfcDev.devList->proto.nfcDep.activation.Initiator.ATR_REQ.NFCID3; + gNfcDev.devList->nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + } + return ret; + #endif /* RFAL_FEATURE_NFC_DEP */ + + /*******************************************************************************/ + case RFAL_LM_STATE_IDLE: /* AP2P activation */ + if( isDataRcvd ) /* Check if Reader/Initator has sent some data */ + { + if( (gNfcDev.lmMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U ) /* Check if AP2P is enabled */ + { + + #if RFAL_FEATURE_NFC_DEP + /* Calculate the header length in NFC-A or NFC-F mode*/ + hdrLen = ( (bitRate == RFAL_BR_106) ? (RFAL_NFCDEP_SB_LEN + RFAL_NFCDEP_LEN_LEN) : RFAL_NFCDEP_LEN_LEN ); + + if( rfalNfcDepIsAtrReq( &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen), NULL) ) + { + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_AP2P; + rfalSetMode( (RFAL_MODE_LISTEN_ACTIVE_P2P), bitRate, bitRate ); + rfalSetFDTListen( RFAL_FDT_LISTEN_AP2P_LISTENER ); + RFAL_EXIT_ON_ERR( ret, rfalNfcNfcDepActivate( gNfcDev.devList, RFAL_NFCDEP_COMM_ACTIVE, &gNfcDev.rxBuf.rfBuf[hdrLen], (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen) ) ); + } + else + #endif /* RFAL_FEATURE_NFC_DEP */ + { + return RFAL_ERR_PROTO; + } + } + } + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case RFAL_LM_STATE_READY_A: + case RFAL_LM_STATE_READY_Ax: + case RFAL_LM_STATE_SLEEP_A: + case RFAL_LM_STATE_SLEEP_AF: + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case RFAL_LM_STATE_POWER_OFF: + return RFAL_ERR_LINK_LOSS; + + default: /* Wait for activation */ + break; + } + + return RFAL_ERR_INTERNAL; +} +#endif /* RFAL_FEATURE_LISTEN_MODE */ + + +/*! + ****************************************************************************** + * \brief Poller NFC DEP Activate + * + * This method performs NFC-DEP Activation + * + * \param[in] device : device info + * \param[in] commMode : communication mode (Passive/Active) + * \param[in] atrReq : received ATR_REQ + * \param[in] atrReqLen : received ATR_REQ size + * + * \return RFAL_ERR_NONE : Operation completed with no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_XXXX : Error occurred + * + ****************************************************************************** + */ +#if RFAL_FEATURE_NFC_DEP +static ReturnCode rfalNfcNfcDepActivate( rfalNfcDevice *device, rfalNfcDepCommMode commMode, const uint8_t *atrReq, uint16_t atrReqLen ) +{ + rfalNfcDepAtrParam initParam; + + /* Suppress warnings if Listen mode is disabled */ + RFAL_NO_WARNING(atrReq); + RFAL_NO_WARNING(atrReqLen); + + /* If we are in Poll mode */ + if( rfalNfcIsRemDevListener( device->type ) ) + { + /*******************************************************************************/ + /* If Passive F use the NFCID2 retrieved from SENSF */ + if( device->type == RFAL_NFC_LISTEN_TYPE_NFCF ) + { + initParam.nfcid = device->dev.nfcf.sensfRes.NFCID2; + initParam.nfcidLen = RFAL_NFCF_NFCID2_LEN; + } + else + { + initParam.nfcid = gNfcDev.disc.nfcid3; + initParam.nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + } + + initParam.BS = RFAL_NFCDEP_Bx_NO_HIGH_BR; +#define ESP_BR BR +#undef BR + initParam.BR = RFAL_NFCDEP_Bx_NO_HIGH_BR; +#define BR ESP_BR +#undef ESP_BR + initParam.DID = RFAL_NFCDEP_DID_NO; + initParam.NAD = RFAL_NFCDEP_NAD_NO; + initParam.LR = gNfcDev.disc.nfcDepLR; + initParam.GB = gNfcDev.disc.GB; + initParam.GBLen = gNfcDev.disc.GBLen; + initParam.commMode = commMode; + initParam.operParam = (RFAL_NFCDEP_OPER_FULL_MI_EN | RFAL_NFCDEP_OPER_EMPTY_DEP_DIS | RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN); + + rfalNfcDepInitialize(); + /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */ + return rfalNfcDepInitiatorHandleActivation( &initParam, gNfcDev.disc.maxBR, &device->proto.nfcDep ); + } + + /* If we are in Listen mode */ +#if RFAL_FEATURE_LISTEN_MODE + else if( rfalNfcIsRemDevPoller( device->type ) ) + { + rfalNfcDepListenActvParam actvParams; + rfalNfcDepTargetParam targetParam; + + RFAL_MEMCPY(targetParam.nfcid3, (uint8_t*)gNfcDev.disc.nfcid3, RFAL_NFCDEP_NFCID3_LEN); + targetParam.bst = RFAL_NFCDEP_Bx_NO_HIGH_BR; + targetParam.brt = RFAL_NFCDEP_Bx_NO_HIGH_BR; + targetParam.to = RFAL_NFCDEP_WT_TRG_MAX_L13; /* [LLCP] 1.3 6.2.1 */ + targetParam.ppt = rfalNfcDepLR2PP(gNfcDev.disc.nfcDepLR); + if( gNfcDev.disc.GBLen >= RFAL_NFCDEP_GB_MAX_LEN ) + { + return RFAL_ERR_PARAM; + } + targetParam.GBtLen = gNfcDev.disc.GBLen; + if( gNfcDev.disc.GBLen > 0U ) + { + RFAL_MEMCPY(targetParam.GBt, gNfcDev.disc.GB, gNfcDev.disc.GBLen); + } + targetParam.operParam = (RFAL_NFCDEP_OPER_FULL_MI_EN | RFAL_NFCDEP_OPER_EMPTY_DEP_DIS | RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN); + targetParam.commMode = commMode; + + + /* Set activation buffer (including header) for NFC-DEP */ + actvParams.rxBuf = (rfalNfcDepBufFormat*) &gNfcDev.rxBuf.nfcDepBuf; /* PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */ + actvParams.rxLen = &gNfcDev.rxLen; + actvParams.isRxChaining = &gNfcDev.isRxChaining; + actvParams.nfcDepDev = &gNfcDev.devList->proto.nfcDep; + + rfalListenSetState( ((device->type == RFAL_NFC_POLL_TYPE_NFCA) ? RFAL_LM_STATE_TARGET_A : RFAL_LM_STATE_TARGET_F) ); + + rfalNfcDepInitialize(); + /* Perform NFC-DEP (P2P) activation: send ATR_RES and handle activation */ + return rfalNfcDepListenStartActivation( &targetParam, atrReq, atrReqLen, actvParams ); + } +#endif /* RFAL_FEATURE_LISTEN_MODE */ + + else + { + return RFAL_ERR_INTERNAL; + } +} +#endif /* RFAL_FEATURE_NFC_DEP */ + + +/*! + ****************************************************************************** + * \brief Poller NFC Deactivate + * + * This method Deactivates the device if a deactivation procedure exists + * + * \return RFAL_ERR_NONE : Operation completed with no error + * \return RFAL_ERR_BUSY : Operation ongoing + * \return RFAL_ERR_XXXX : Error occurred + * + ****************************************************************************** + */ +static ReturnCode rfalNfcDeactivation( void ) +{ + bool aux; + ReturnCode ret; + + ret = RFAL_ERR_NONE; + aux = false; + + /* Suppress warning when specific RFAL features have been disabled */ + RFAL_NO_WARNING( ret ); + + + /* Check if a device has been activated */ + if( gNfcDev.activeDev != NULL ) + { + if( rfalNfcIsRemDevListener( gNfcDev.activeDev->type ) ) /* Listen mode no additional deactivation to be performed*/ + { + switch( gNfcDev.activeDev->rfInterface ) + { + /*******************************************************************************/ + case RFAL_NFC_INTERFACE_RF: + break; /* No specific deactivation to be performed */ + + /*******************************************************************************/ + #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL + case RFAL_NFC_INTERFACE_ISODEP: + + if( !gNfcDev.isOperOngoing ) + { + ret = rfalIsoDepStartDeselect(); + if( ret == RFAL_ERR_NONE ) /* Send a Deselect to device */ + { + gNfcDev.isOperOngoing = true; + return RFAL_ERR_BUSY; + } + } + else + { + RFAL_EXIT_ON_BUSY( ret, rfalIsoDepGetDeselectStatus() ); /* Check if deselection has finished */ + + aux = true; /* Mark device as deselected */ + gNfcDev.isOperOngoing = false; + } + break; + #endif /* RFAL_FEATURE_ISO_DEP_POLL */ + + /*******************************************************************************/ + #if RFAL_FEATURE_NFC_DEP + case RFAL_NFC_INTERFACE_NFCDEP: + switch ( gNfcDev.activeDev->type ) + { + case RFAL_NFC_LISTEN_TYPE_AP2P: + rfalNfcDepRLS(); /* Send a Release to device */ + break; + + default: + rfalNfcDepDSL(); /* Send a Deselect to device */ + aux = true; /* Mark device as deselected */ + break; + + } + break; + #endif /* RFAL_FEATURE_NFC_DEP */ + + default: + return RFAL_ERR_REQUEST; + } + } + } + + /* If deactivation type is only to Sleep, mark it and keep Field On */ + if( (gNfcDev.deactType == RFAL_NFC_DEACTIVATE_SLEEP) && (gNfcDev.activeDev != NULL) && (aux) ) + { + gNfcDev.isOperOngoing = false; + + + if( gNfcDev.activeDev->type == RFAL_NFC_LISTEN_TYPE_NFCA ) + { + gNfcDev.activeDev->dev.nfca.isSleep = true; + } + else if( gNfcDev.activeDev->type == RFAL_NFC_LISTEN_TYPE_NFCB ) + { + gNfcDev.activeDev->dev.nfcb.isSleep = true; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + else + { + if( !gNfcDev.isDeactivating ) /* Check if the Field deactivation has not started */ + { + #if RFAL_FEATURE_WAKEUP_MODE + rfalWakeUpModeStop(); + #endif /* RFAL_FEATURE_WAKEUP_MODE */ + + #if RFAL_FEATURE_LISTEN_MODE + rfalListenStop(); + #else + rfalFieldOff(); + #endif + + if( (gNfcDev.isFieldOn) && rfalNfcHasPollerTechs() ) /* Check if configured to Poll modes and the Field is On */ + { + aux = platformTimerIsExpired(gNfcDev.discTmr); /* Check total duration timer is already expired */ + if( ((platformGetSysTick() + RFAL_NFC_T_FIELD_OFF) > gNfcDev.discTmr) || (aux) ) /* In case Total Duration has expired or expring in less than tFIELD_OFF */ + { + platformTimerDestroy( gNfcDev.discTmr ); + gNfcDev.discTmr = (uint32_t)platformTimerCreate( RFAL_NFC_T_FIELD_OFF ); /* Ensure that Operating Field is in Off condition at least tFIELD_OFF */ + } + + gNfcDev.isDeactivating = true; + return RFAL_ERR_BUSY; + } + } + else /* The Field deactivation has started */ + { + if( !platformTimerIsExpired(gNfcDev.discTmr) ) + { + return RFAL_ERR_BUSY; /* Ensure Operating Field in Off condition for the time remaining */ + } + } + } + + gNfcDev.activeDev = NULL; /* Clear Active Device info */ + gNfcDev.isDeactivating = false; + gNfcDev.isTechInit = false; + gNfcDev.isFieldOn = false; + return RFAL_ERR_NONE; +} + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcDep.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcDep.c new file mode 100644 index 0000000..4860683 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcDep.c @@ -0,0 +1,2739 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: NFCC firmware + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcDep.c + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-DEP protocol + * + * NFC-DEP is also known as NFCIP - Near Field Communication + * Interface and Protocol + * + * This implementation was based on the following specs: + * - NFC Forum Digital 1.1 + * - ECMA 340 3rd Edition 2013 + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfcDep.h" +#include "rfal_nfcf.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFC_DEP + */ + +#if RFAL_FEATURE_NFC_DEP + +/* Check for valid Block/Payload length Digital 2.0 Table 90*/ +#if( (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 64) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 128) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 192) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 254) ) + #error " RFAL: Invalid NFC-DEP Block Max length. Please change RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN. " +#endif + +/* Check for valid PDU length */ +#if( (RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN < RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN) ) + #error " RFAL: Invalid NFC-DEP PDU Max length. Please change RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN. " +#endif + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ +#define NFCIP_ATR_RETRY_MAX 2U /*!< Max consecutive retrys of an ATR REQ with transm error*/ + +#define NFCIP_PSLPAY_LEN (2U) /*!< PSL Payload length (BRS + FSL) */ +#define NFCIP_PSLREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL REQ length (incl LEN) */ +#define NFCIP_PSLRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL RES length (incl LEN) */ + +#define NFCIP_ATRREQ_BUF_LEN (RFAL_NFCDEP_ATRREQ_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR REQ max length (incl LEN) */ +#define NFCIP_ATRRES_BUF_LEN (RFAL_NFCDEP_ATRRES_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR RES max length (incl LEN) */ + +#define NFCIP_RLSREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< RLS REQ length (incl LEN) */ +#define NFCIP_RLSRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< RSL RES length (incl LEN) */ +#define NFCIP_RLSRES_MIN (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN) */ + +#define NFCIP_DSLREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL REQ length (incl LEN) */ +#define NFCIP_DSLRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL RES length (incl LEN) */ +#define NFCIP_DSLRES_MIN (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a DSL RES (incl LEN) */ + +#define NFCIP_DSLRES_MAX_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< Maximum length for a DSL RES (incl LEN) */ +#define NFCIP_RLSRES_MAX_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN) */ +#define NFCIP_TARGET_RES_MAX ( RFAL_MAX( NFCIP_RLSRES_MAX_LEN, NFCIP_DSLRES_MAX_LEN) ) /*!< Max target control res length */ + + + +#define NFCIP_NO_FWT RFAL_FWT_NONE /*!< No FWT value - Target Mode */ +#define NFCIP_INIT_MIN_RTOX 1U /*!< Minimum RTOX value Digital 1.0 14.8.4.1 */ +#define NFCIP_INIT_MAX_RTOX 59U /*!< Maximum RTOX value Digital 1.0 14.8.4.1 */ + +#define NFCIP_TARG_MIN_RTOX 1U /*!< Minimum target RTOX value Digital 1.0 14.8.4.1 */ +#define NFCIP_TARG_MAX_RTOX 59U /*!< Maximum target RTOX value Digital 1.0 14.8.4.1 */ + +#define NFCIP_TRECOV 1280U /*!< Digital 1.0 A.10 Trecov */ + +#define NFCIP_TIMEOUT_ADJUSTMENT 3072U /*!< Timeout Adjustment to compensate timing from end of Tx to end of frame */ +#define NFCIP_RWT_ACTIVATION (0x1000001U + NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2 B.11 RWT ACTIVATION 2^24 + RWT Delta + Adjustment*/ +#define NFCIP_RWT_ACM_ACTIVATION (0x200001U + NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2 B.11 RWT ACTIVATION 2^21 + RWT Delta + Adjustment*/ + +#define RFAL_NFCDEP_HEADER_PAD (RFAL_NFCDEP_DEPREQ_HEADER_LEN - RFAL_NFCDEP_LEN_MIN) /*!< Difference between expected rcvd header len and max foreseen */ + +#ifndef RFAL_NFCDEP_MAX_TX_RETRYS +#define RFAL_NFCDEP_MAX_TX_RETRYS (uint8_t)3U /*!< Number of retransmit retyrs */ +#endif /* RFAL_NFCDEP_MAX_TX_RETRYS */ + +#ifndef RFAL_NFCDEP_TO_RETRYS +#define RFAL_NFCDEP_TO_RETRYS (uint8_t)3U /*!< Number of retrys for Timeout */ +#endif /* RFAL_NFCDEP_TO_RETRYS */ + +#ifndef RFAL_NFCDEP_MAX_RTOX_RETRYS +#define RFAL_NFCDEP_MAX_RTOX_RETRYS (uint8_t)10U /*!< Number of retrys for RTOX Digital 2.0 17.12.4.3 */ +#endif /* RFAL_NFCDEP_MAX_RTOX_RETRYS */ + +#ifndef RFAL_NFCDEP_MAX_NACK_RETRYS +#define RFAL_NFCDEP_MAX_NACK_RETRYS (uint8_t)3U /*!< Number of retrys for NACK */ +#endif /* RFAL_NFCDEP_MAX_NACK_RETRYS */ + +#ifndef RFAL_NFCDEP_MAX_ATN_RETRYS +#define RFAL_NFCDEP_MAX_ATN_RETRYS (uint8_t)3U /*!< Number of retrys for ATN */ +#endif /* RFAL_NFCDEP_MAX_ATN_RETRYS */ + +#define NFCIP_MIN_TXERROR_LEN 4U /*!< Minimum frame length with error to be ignored Digital 1.0 14.12.5.4 */ + +#define NFCIP_REQ (uint8_t)0xD4U /*!= NFCIP_ST_INIT_IDLE) && ((st) <= NFCIP_ST_INIT_RLS) ) /*!< Checks if module is set as Initiator */ +#define nfcipIsTarget( st ) (!nfcipIsInitiator(st)) /*!< Checks if module is set as Target */ + +#define nfcipIsBRAllowed( br, mBR ) (((1U<<(br)) & (mBR)) != 0U) /*!< Checks bit rate is allowed by given mask */ + +#define nfcipIsEmptyDEPEnabled( op ) (!nfcipIsEmptyDEPDisabled(op)) /*!< Checks if empty payload is allowed by operation config NCI 1.0 Table 81 */ +#define nfcipIsEmptyDEPDisabled( op ) (((op) & RFAL_NFCDEP_OPER_EMPTY_DEP_DIS) != 0U) /*!< Checks if empty payload is not allowed by operation config NCI 1.0 Table 81 */ + +#define nfcipIsRTOXReqEnabled( op ) (!nfcipIsRTOXReqDisabled(op)) /*!< Checks if send a RTOX_REQ is allowed by operation config NCI 1.0 Table 81 */ +#define nfcipIsRTOXReqDisabled( op ) (((op) & RFAL_NFCDEP_OPER_RTOX_REQ_DIS) != 0U) /*!< Checks if send a RTOX_REQ is not allowed by operation config NCI 1.0 Table 81 */ + + +/*! Checks if isDeactivating callback is set and calls it, otherwise returns false */ +#define nfcipIsDeactivationPending() ( (gNfcip.isDeactivating == NULL) ? false : gNfcip.isDeactivating() ) + +/*! Returns the RWT Activation according to the current communication mode */ +#define nfcipRWTActivation() ((gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE) ? NFCIP_RWT_ACM_ACTIVATION : NFCIP_RWT_ACTIVATION) + + +#define nfcipRTOXAdjust( v ) ((v) - ((v)>>3)) /*!< Adjust RTOX timer value to a percentage of the total, current 88% */ + +/*******************************************************************************/ + +// timerPollTimeoutValue is necessary after timerCalculateTimeout so that system will wake up upon timer timeout. +#define nfcipTimerStart( timer, time_ms ) do{platformTimerDestroy( timer); (timer) = platformTimerCreate((uint16_t)(time_ms));} while (0) /*!< Configures and starts the RTOX timer */ +#define nfcipTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks RTOX timer has expired */ +#define nfcipTimerDestroy( timer ) platformTimerDestroy( timer ) /*!< Destroys RTOX timer */ + +#define nfcipLogE(...) /*!< Macro for the error log method */ +#define nfcipLogW(...) /*!< Macro for the warning log method */ +#define nfcipLogI(...) /*!< Macro for the info log method */ +#define nfcipLogD(...) /*!< Macro for the debug log method */ + + +/*! Digital 1.1 - 16.12.5.2 The Target SHALL NOT attempt any error recovery and remains in Rx mode upon Transmission or a Protocol Error */ +#define nfcDepReEnableRx( rxB, rxBL, rxL ) rfalTransceiveBlockingTx( NULL, 0, (rxB), (rxBL), (rxL), ( RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON ), RFAL_FWT_NONE ) + +/* + ****************************************************************************** + * LOCAL DATA TYPES + ****************************************************************************** + */ + +/*! Struct that holds all DEP parameters/configs for the following communications */ +typedef struct{ + uint8_t did; /*!< Device ID (DID) to be used */ + + uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent */ + uint16_t txBufLen; /*!< Length of the data in the txBuf */ + uint8_t txBufPaylPos; /*!< Position inside txBuf where data starts */ + bool txChaining; /*!< Flag indicating chaining on transmission */ + + uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data */ + uint16_t rxBufLen; /*!< Length of the data in the rxBuf */ + uint8_t rxBufPaylPos; /*!< Position inside rxBuf where data is to be placed*/ + + uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used */ + uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used */ + uint16_t fsc; /*!< Frame Size (FSC) to be used */ + +} rfalNfcDepDEPParams; + +/*! NFCIP module states */ +typedef enum +{ + NFCIP_ST_IDLE, + NFCIP_ST_INIT_IDLE, + NFCIP_ST_INIT_ATR, + NFCIP_ST_INIT_PSL, + NFCIP_ST_INIT_DEP_IDLE, + NFCIP_ST_INIT_DEP_TX, + NFCIP_ST_INIT_DEP_RX, + NFCIP_ST_INIT_DEP_ATN, + NFCIP_ST_INIT_DSL, + NFCIP_ST_INIT_RLS, + + NFCIP_ST_TARG_WAIT_ATR, + NFCIP_ST_TARG_WAIT_ACTV, + NFCIP_ST_TARG_DEP_IDLE, + NFCIP_ST_TARG_DEP_RX, + NFCIP_ST_TARG_DEP_RTOX, + NFCIP_ST_TARG_DEP_TX, + NFCIP_ST_TARG_DEP_SLEEP +} rfalNfcDepState; + +/*! NFCIP commands (Request, Response) */ +typedef enum{ + NFCIP_CMD_ATR_REQ = 0x00, + NFCIP_CMD_ATR_RES = 0x01, + NFCIP_CMD_WUP_REQ = 0x02, + NFCIP_CMD_WUP_RES = 0x03, + NFCIP_CMD_PSL_REQ = 0x04, + NFCIP_CMD_PSL_RES = 0x05, + NFCIP_CMD_DEP_REQ = 0x06, + NFCIP_CMD_DEP_RES = 0x07, + NFCIP_CMD_DSL_REQ = 0x08, + NFCIP_CMD_DSL_RES = 0x09, + NFCIP_CMD_RLS_REQ = 0x0A, + NFCIP_CMD_RLS_RES = 0x0B +} rfalNfcDepCmd; + + +/*! Struct that holds all NFCIP data */ +typedef struct{ + rfalNfcDepConfigs cfg; /*!< Holds the current configuration to be used */ + + rfalNfcDepState state; /*!< Current state of the NFCIP module */ + uint8_t pni; /*!< Packet Number Information (PNI) counter */ + + uint8_t lastCmd; /*!< Last command sent */ + uint8_t lastPFB; /*!< Last PFB sent */ + uint8_t lastPFBnATN; /*!< Last PFB sent (excluding ATN) */ + uint8_t lastRTOX; /*!< Last RTOX value sent */ + + uint8_t cntTxRetrys; /*!< Retransmissions counter */ + uint8_t cntTORetrys; /*!< Timeouts counter */ + uint8_t cntRTOXRetrys; /*!< RTOX counter */ + uint8_t cntNACKRetrys; /*!< NACK counter */ + uint8_t cntATNRetrys; /*!< Attention (ATN) counter */ + + uint16_t fsc; /*!< Current Frame Size (FSC) to be used */ + bool isTxChaining; /*!< Flag for chaining on Transmission */ + bool isRxChaining; /*!< Flag for chaining on Reception */ + uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent */ + uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data */ + uint16_t txBufLen; /*!< Length of the data in the txBuf */ + uint16_t rxBufLen; /*!< Length of rxBuf buffer */ + uint16_t* rxRcvdLen; /*!< Length of the data in the rxBuf */ + uint8_t txBufPaylPos; /*!< Position in txBuf where data starts */ + uint8_t rxBufPaylPos; /*!< Position in rxBuf where data is to be placed */ + bool *isChaining; /*!< Flag for chaining on Reception */ + + rfalNfcDepDevice *nfcDepDev; /*!< Pointer to NFC-DEP device info */ + + uint32_t RTOXTimer; /*!< Timer used for RTOX */ + rfalNfcDepDeactCallback isDeactivating; /*!< Deactivating flag check callback */ + + bool isReqPending; /*!< Flag pending REQ from Target activation */ + bool isTxPending; /*!< Flag pending DEP Block while waiting RTOX Ack */ + bool isWait4RTOX; /*!< Flag for waiting RTOX Ack */ + + rfalNfcDepPduTxRxParam PDUParam; /*!< PDU TxRx params */ + uint16_t PDUTxPos; /*!< PDU Tx position */ + uint16_t PDURxPos; /*!< PDU Rx position */ + bool isPDURxChaining; /*!< PDU Transceive chaining flag */ +}rfalNfcDep; + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + +static rfalNfcDep gNfcip; /*!< NFCIP module instance */ + + +/* + ****************************************************************************** + * LOCAL FUNCTION PROTOTYPES + ****************************************************************************** + */ + +static ReturnCode nfcipTxRx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint32_t fwt, uint8_t* paylBuf, uint8_t paylBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxActLen ); +static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfbData, uint32_t fwt ); +static ReturnCode nfcipDEPControlMsg( uint8_t pfb, uint8_t RTOX ); +static ReturnCode nfcipInitiatorHandleDEP( ReturnCode rxRes, uint16_t rxLen, uint16_t *outActRxLen, bool *outIsChaining ); +static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining ); +static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS ); + + +/*! + ****************************************************************************** + * \brief NFCIP Configure + * + * Configures the nfcip layer with the given configurations + * + * \param[in] cfg : nfcip configuration for following communication + ****************************************************************************** + */ +static void nfcipConfig( const rfalNfcDepConfigs * cfg ); + + +/*! + ****************************************************************************** + * \brief Set DEP parameters + * + * This method sets the parameters/configs for following Data Exchange + * Sets the nfcip module state according to the role it is configured + * + * + * \warning To be used only after proper Initiator/Target activation: + * nfcipTargetHandleActivation() or nfcipInitiatorActivate() has + * returned success + * + * This must be called before nfcipRun() in case of Target to pass + * rxBuffer + * + * Everytime some data needs to be transmitted call this to set it and + * call nfcipRun() until done or error + * + * \param[in] DEPParams : the parameters to be used during Data Exchange + ****************************************************************************** + */ +static void nfcipSetDEPParams( const rfalNfcDepDEPParams *DEPParams ); + + +/*! + ****************************************************************************** + * \brief NFCIP run protocol + * + * This method handles all the nfcip protocol during Data Exchange (DEP + * requests and responses). + * + * A data exchange cycle is considered a DEP REQ and a DEP RES. + * + * In case of Tx chaining(MI) must signal it with nfcipSetDEPParams() + * In case of Rx chaining(MI) outIsChaining will be set to true and the + * current data returned + * + * \param[out] outActRxLen : data received length + * \param[out] outIsChaining : true if other peer is performing chaining(MI) + * + * \return RFAL_ERR_NONE : Data exchange cycle completed successfully + * \return RFAL_ERR_TIMEOUT : Timeout occurred + * \return RFAL_ERR_PROTO : Protocol error occurred + * \return RFAL_ERR_AGAIN : Other peer is doing chaining(MI), current block + * was received successfully call again until complete + * + ****************************************************************************** + */ +static ReturnCode nfcipRun( uint16_t *outActRxLen, bool *outIsChaining ); + + +/*! + ****************************************************************************** + * \brief Transmission method + * + * This method checks if the current communication is Active or Passive + * and performs the necessary procedures for each communication type + * + * Transmits the data hold in txBuf + * + * \param[in] txBuf : buffer to transmit + * \param[in] txBufLen : txBuffer capacity + * \param[in] fwt : fwt for current Tx + * + * \return RFAL_ERR_NONE : No error + ****************************************************************************** + */ +static ReturnCode nfcipDataTx( uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt ); + + +/*! + ****************************************************************************** + * \brief Reception method + * + * This method checks if the current communication is Active or Passive + * and calls the appropriate reception method + * + * Copies incoming data to rxBuf + * + * \param[in] blocking : reception is to be done blocking or non-blocking + * + * \return RFAL_ERR_BUSY : Busy + * \return RFAL_ERR_NONE : No error + ****************************************************************************** + */ +static ReturnCode nfcipDataRx( bool blocking ); + + +/* + ****************************************************************************** + * LOCAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ + + +/*******************************************************************************/ +static bool nfcipDxIsSupported( uint8_t Dx, uint8_t BRx, uint8_t BSx ) +{ + uint8_t Bx; + + /* Take the min of the possible bit rates, we'll use one for both directions */ + Bx = RFAL_MIN(BRx, BSx); + + /* Lower bit rates must be supported for P2P */ + if( (Dx <= (uint8_t)RFAL_NFCDEP_Dx_04_424) ) + { + return true; + } + + if( (Dx == (uint8_t)RFAL_NFCDEP_Dx_08_848) && (Bx >= (uint8_t)RFAL_NFCDEP_Bx_08_848) ) + { + return true; + } + + return false; +} + + +/*******************************************************************************/ +static ReturnCode nfcipTxRx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint32_t fwt, uint8_t* paylBuf, uint8_t paylBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxActLen ) +{ + ReturnCode ret; + + if( (cmd == NFCIP_CMD_DEP_REQ) || (cmd == NFCIP_CMD_DEP_RES) ) /* this method cannot be used for DEPs */ + { + return RFAL_ERR_PARAM; + } + + /* Assign the global params for this TxRx */ + gNfcip.rxBuf = rxBuf; + gNfcip.rxBufLen = rxBufLen; + gNfcip.rxRcvdLen = rxActLen; + + + /*******************************************************************************/ + /* Transmission */ + /*******************************************************************************/ + if(txBuf != NULL) /* if nothing to Tx, just do Rx */ + { + RFAL_EXIT_ON_ERR( ret, nfcipTx( cmd, txBuf, paylBuf, paylBufLen, 0, fwt ) ); + } + + /*******************************************************************************/ + /* Reception */ + /*******************************************************************************/ + ret = nfcipDataRx( true ); + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /*******************************************************************************/ + *rxActLen = *rxBuf; /* Use LEN byte instead due to with/without CRC modes */ + return RFAL_ERR_NONE; /* Tx and Rx completed successfully */ +} + + +/*******************************************************************************/ +static ReturnCode nfcipDEPControlMsg( uint8_t pfb, uint8_t RTOX ) +{ + uint8_t ctrlMsg[20]; + uint32_t fwt; + + + /*******************************************************************************/ + /* Calculate Cmd and fwt to be used */ + /*******************************************************************************/ + const rfalNfcDepCmd depCmd = ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_CMD_DEP_RES : NFCIP_CMD_DEP_REQ); + fwt = ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_NO_FWT : (nfcip_PFBisSTO( pfb ) ? ( (RTOX*gNfcip.cfg.fwt) + gNfcip.cfg.dFwt) : (gNfcip.cfg.fwt + gNfcip.cfg.dFwt) ) ); + + if( nfcip_PFBisSTO( pfb ) ) + { + ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN] = RTOX; + return nfcipTx( depCmd, ctrlMsg, &ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN], sizeof(uint8_t), pfb, fwt ); + } + else + { + return nfcipTx( depCmd, ctrlMsg, NULL, 0, pfb, fwt ); + } +} + +/*******************************************************************************/ +static void nfcipClearCounters( void ) +{ + gNfcip.cntATNRetrys = 0; + gNfcip.cntNACKRetrys = 0; + gNfcip.cntTORetrys = 0; + gNfcip.cntTxRetrys = 0; + gNfcip.cntRTOXRetrys = 0; +} + +/*******************************************************************************/ +static ReturnCode nfcipInitiatorHandleDEP( ReturnCode rxRes, uint16_t rxLen, uint16_t *outActRxLen, bool *outIsChaining ) +{ + ReturnCode ret; + uint8_t nfcDepLen; + uint8_t rxMsgIt; + uint8_t rxPFB; + uint8_t rxRTOX; + uint8_t optHdrLen; + + ret = RFAL_ERR_INTERNAL; + rxMsgIt = 0; + optHdrLen = 0; + + *outActRxLen = 0; + *outIsChaining = false; + + + /*******************************************************************************/ + /* Handle reception errors */ + /*******************************************************************************/ + switch( rxRes ) + { + /*******************************************************************************/ + /* Timeout -> Digital 1.0 14.15.5.6 */ + case RFAL_ERR_TIMEOUT: + + nfcipLogI( " NFCIP(I) TIMEOUT TORetrys:%d \r\n", gNfcip.cntTORetrys ); + + /* Digital 1.0 14.15.5.6 - If nTO >= Max raise protocol error */ + if( gNfcip.cntTORetrys++ >= RFAL_NFCDEP_TO_RETRYS ) + { + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Upon Timeout error, if Deactivation is pending, no more error recovery + * will be done #54. + * This is used to address the issue some devices that havea big TO. + * Normally LLCP layer has timeout already, and NFCIP layer is still + * running error handling, retrying ATN/NACKs */ + /*******************************************************************************/ + if( nfcipIsDeactivationPending() ) + { + nfcipLogI( " skipping error recovery due deactivation pending \r\n"); + return RFAL_ERR_TIMEOUT; + } + + /* Digital 1.0 14.15.5.6 1) If last PDU was NACK */ + if( nfcip_PFBisRNACK(gNfcip.lastPFB) ) + { + /* Digital 1.0 14.15.5.6 2) if NACKs failed raise protocol error */ + if( gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS ) + { + return RFAL_ERR_PROTO; + } + + /* Send NACK */ + nfcipLogI( " NFCIP(I) Sending NACK retry: %d \r\n", gNfcip.cntNACKRetrys ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_NACK(gNfcip.pni), 0 ) ); + return RFAL_ERR_BUSY; + } + + nfcipLogI( " NFCIP(I) Checking if to send ATN ATNRetrys: %d \r\n", gNfcip.cntATNRetrys ); + + /* Digital 1.0 14.15.5.6 3) Otherwise send ATN */ + if( gNfcip.cntATNRetrys++ >= RFAL_NFCDEP_MAX_ATN_RETRYS ) + { + return RFAL_ERR_PROTO; + } + + /* Send ATN */ + nfcipLogI( " NFCIP(I) Sending ATN \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_ATN(), 0 ) ); + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + /* Data rcvd with error -> Digital 1.0 14.12.5.4 */ + case RFAL_ERR_CRC: + case RFAL_ERR_PAR: + case RFAL_ERR_FRAMING: + case RFAL_ERR_RF_COLLISION: + + nfcipLogI( " NFCIP(I) rx Error: %d \r\n", rxRes ); + + /* Digital 1.0 14.12.5.4 Tx Error with data, ignore */ + if( rxLen < NFCIP_MIN_TXERROR_LEN ) + { + nfcipLogI( " NFCIP(I) Transmission error w data \r\n" ); +#if 0 + if(gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE) + { + nfcipLogI( " NFCIP(I) Transmission error w data -> reEnabling Rx \r\n" ); + nfcipReEnableRxTout( NFCIP_TRECOV ); + return RFAL_ERR_BUSY; + } +#endif /* 0 */ + } + + /* Digital 1.1 16.12.5.4 if NACKs failed raise Transmission error */ + if( gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS ) + { + return RFAL_ERR_FRAMING; + } + + /* Send NACK */ + nfcipLogI( " NFCIP(I) Sending NACK \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_NACK(gNfcip.pni), 0 ) ); + return RFAL_ERR_BUSY; + + case RFAL_ERR_NONE: + break; + + case RFAL_ERR_BUSY: + return RFAL_ERR_BUSY; /* Debug purposes */ + + default: + nfcipLogW( " NFCIP(I) Error: %d \r\n", rxRes ); + return rxRes; + } + + /*******************************************************************************/ + /* Rx OK check if valid DEP PDU */ + /*******************************************************************************/ + + if( gNfcip.rxBuf == NULL ) + { + return RFAL_ERR_IO; + } + + /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */ + nfcDepLen = gNfcip.rxBuf[rxMsgIt++]; + + nfcipLogD( " NFCIP(I) rx OK: %d bytes \r\n", nfcDepLen ); + + /* Digital 1.0 14.15.5.5 Protocol Error */ + if( gNfcip.rxBuf[rxMsgIt++] != NFCIP_RES ) + { + nfcipLogW( " NFCIP(I) error %02X instead of %02X \r\n", gNfcip.rxBuf[(rxMsgIt-1U)], NFCIP_RES ); + return RFAL_ERR_PROTO; + } + + /* Digital 1.0 14.15.5.5 Protocol Error */ + if( gNfcip.rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DEP_RES ) + { + nfcipLogW( " NFCIP(I) error %02X instead of %02X \r\n", gNfcip.rxBuf[(rxMsgIt-1U)], NFCIP_CMD_DEP_RES ); + return RFAL_ERR_PROTO; + } + + rxPFB = gNfcip.rxBuf[rxMsgIt++]; + + /*******************************************************************************/ + /* Check for valid PFB type */ + if( !(nfcip_PFBisSPDU( rxPFB ) || nfcip_PFBisRPDU( rxPFB ) || nfcip_PFBisIPDU( rxPFB )) ) + { + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Digital 1.0 14.8.2.1 check if DID is expected and match -> Protocol Error */ + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (!nfcip_PFBhasDID( rxPFB )) ) + { + return RFAL_ERR_PROTO; + } + optHdrLen++; /* Inc header optional field cnt*/ + } + else if( nfcip_PFBhasDID( rxPFB ) ) /* DID not expected but rcv */ + { + return RFAL_ERR_PROTO; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + /*******************************************************************************/ + /* Digital 1.0 14.6.2.8 & 14.6.3.11 NAD must not be used */ + if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) + { + if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.nad) || (!nfcip_PFBhasNAD( rxPFB )) ) + { + return RFAL_ERR_PROTO; + } + optHdrLen++; /* Inc header optional field cnt*/ + } + else if( nfcip_PFBhasNAD( rxPFB ) ) /* NAD not expected but rcv */ + { + return RFAL_ERR_PROTO; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + /*******************************************************************************/ + /* Process R-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisRPDU( rxPFB ) ) + { + /*******************************************************************************/ + /* R ACK */ + /*******************************************************************************/ + if( nfcip_PFBisRACK( rxPFB ) ) + { + nfcipLogI( " NFCIP(I) Rcvd ACK \r\n" ); + if( gNfcip.pni == nfcip_PBF_PNI( rxPFB ) ) + { + /* 14.12.3.3 R-ACK with correct PNI -> Increment */ + gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); + + /* R-ACK while not performing chaining -> Protocol error*/ + if( !gNfcip.isTxChaining ) + { + return RFAL_ERR_PROTO; + } + + nfcipClearCounters(); + gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; + return RFAL_ERR_NONE; /* This block has been transmitted */ + } + else /* Digital 1.0 14.12.4.5 ACK with wrong PNI Initiator may retransmit */ + { + if( gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS ) + { + return RFAL_ERR_PROTO; + } + + /* Extended the MAY in Digital 1.0 14.12.4.5 to only reTransmit if the ACK + * is for the previous DEP, otherwise raise Protocol immediately + * If the PNI difference is more than 1 it is worthless to reTransmit 3x + * and after raise the error */ + + if( nfcip_PNIDec( gNfcip.pni ) == nfcip_PBF_PNI( rxPFB ) ) + { + /* ReTransmit */ + nfcipLogI( " NFCIP(I) Rcvd ACK prev PNI -> reTx \r\n" ); + gNfcip.state = NFCIP_ST_INIT_DEP_TX; + return RFAL_ERR_BUSY; + } + + nfcipLogI( " NFCIP(I) Rcvd ACK unexpected far PNI -> Error \r\n" ); + return RFAL_ERR_PROTO; + } + } + else /* Digital 1.0 - 14.12.5.2 Target must never send NACK */ + { + return RFAL_ERR_PROTO; + } + } + + /*******************************************************************************/ + /* Process S-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisSPDU( rxPFB ) ) + { + nfcipLogI( " NFCIP(I) Rcvd S-PDU \r\n" ); + /*******************************************************************************/ + /* S ATN */ + /*******************************************************************************/ + if( nfcip_PFBisSATN( rxPFB ) ) /* If is a S-ATN */ + { + nfcipLogI( " NFCIP(I) Rcvd ATN \r\n" ); + if( nfcip_PFBisSATN( gNfcip.lastPFB ) ) /* Check if is expected */ + { + gNfcip.cntATNRetrys = 0; /* Clear ATN counter */ + + /* Although spec is not clear NFC Forum Digital test is expecting to + * retransmit upon receiving ATN_RES */ + if( nfcip_PFBisSTO( gNfcip.lastPFBnATN ) ) + { + nfcipLogI( " NFCIP(I) Rcvd ATN -> reTx RTOX_RES \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), gNfcip.lastRTOX ) ); + } + else + { + /* ReTransmit ? */ + if( gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS ) + { + return RFAL_ERR_PROTO; + } + + nfcipLogI( " NFCIP(I) Rcvd ATN -> reTx PNI: %d \r\n", gNfcip.pni ); + gNfcip.state = NFCIP_ST_INIT_DEP_TX; + } + + return RFAL_ERR_BUSY; + } + else /* Digital 1.0 14.12.4.4 & 14.12.4.8 */ + { + return RFAL_ERR_PROTO; + } + } + /*******************************************************************************/ + /* S TO */ + /*******************************************************************************/ + else if( nfcip_PFBisSTO( rxPFB ) ) /* If is a S-TO (RTOX) */ + { + nfcipLogI( " NFCIP(I) Rcvd TO \r\n" ); + + rxRTOX = gNfcip.rxBuf[rxMsgIt++]; + + /* Digital 1.1 16.12.4.3 - Initiator MAY stop accepting subsequent RTOX Req * + * - RTOX request to an ATN -> Protocol error */ + if( (gNfcip.cntRTOXRetrys++ > RFAL_NFCDEP_MAX_RTOX_RETRYS) || nfcip_PFBisSATN( gNfcip.lastPFB ) ) + { + return RFAL_ERR_PROTO; + } + + /* Digital 1.1 16.8.4.1 RTOX must be between [1,59] */ + if( (rxRTOX < NFCIP_INIT_MIN_RTOX) || (rxRTOX > NFCIP_INIT_MAX_RTOX) ) + { + return RFAL_ERR_PROTO; + } + + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), rxRTOX ) ); + gNfcip.lastRTOX = rxRTOX; + + return RFAL_ERR_BUSY; + } + else + { + /* Unexpected S-PDU */ + return RFAL_ERR_PROTO; + } + } + + /*******************************************************************************/ + /* Process I-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisIPDU( rxPFB ) ) + { + if( gNfcip.pni != nfcip_PBF_PNI( rxPFB ) ) + { + nfcipLogI( " NFCIP(I) Rcvd IPDU wrong PNI curPNI: %d rxPNI: %d \r\n", gNfcip.pni , nfcip_PBF_PNI( rxPFB ) ); + return RFAL_ERR_PROTO; + } + + nfcipLogD( " NFCIP(I) Rcvd IPDU OK PNI: %d \r\n", gNfcip.pni ); + + /* 14.12.3.3 I-PDU with correct PNI -> Increment */ + gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); + + + /* Successful data Exchange */ + nfcipClearCounters(); + *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen); + + if( (&gNfcip.rxBuf[gNfcip.rxBufPaylPos] != &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) && (*outActRxLen > 0U) ) + { + RFAL_MEMMOVE( &gNfcip.rxBuf[gNfcip.rxBufPaylPos], &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen], *outActRxLen ); + } + + /*******************************************************************************/ + /* Check if target is indicating chaining MI */ + /*******************************************************************************/ + if( nfcip_PFBisIMI( rxPFB ) ) + { + gNfcip.isRxChaining = true; + *outIsChaining = true; + + nfcipLogD( " NFCIP(I) Rcvd IPDU OK w MI -> ACK \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); + + return RFAL_ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/ + } + else + { + gNfcip.isRxChaining = false; + gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; + + ret = RFAL_ERR_NONE; /* Data exchange done */ + } + } + return ret; +} + + +/*******************************************************************************/ +static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining ) +{ + ReturnCode ret; + uint8_t nfcDepLen; + uint8_t rxMsgIt; + uint8_t rxPFB; + uint8_t optHdrLen; + uint8_t resBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_TARGET_RES_MAX]; + + + ret = RFAL_ERR_INTERNAL; + rxMsgIt = 0; + optHdrLen = 0; + + *outActRxLen = 0; + *outIsChaining = false; + + + /*******************************************************************************/ + /* Handle reception errors */ + /*******************************************************************************/ + switch( rxRes ) + { + /*******************************************************************************/ + case RFAL_ERR_NONE: + break; + + case RFAL_ERR_LINK_LOSS: + nfcipLogW( " NFCIP(T) Error: %d \r\n", rxRes ); + return rxRes; + + case RFAL_ERR_BUSY: + return RFAL_ERR_BUSY; /* Debug purposes */ + + case RFAL_ERR_TIMEOUT: + case RFAL_ERR_CRC: + case RFAL_ERR_PAR: + case RFAL_ERR_FRAMING: + case RFAL_ERR_PROTO: + default: + /* Digital 1.1 16.12.5.2 The Target MUST NOT attempt any error recovery. * + * The Target MUST always stay in receive mode when a * + * Transmission Error or a Protocol Error occurs. * + * * + * Do not push Transmission/Protocol Errors to upper layer in Listen Mode #766 */ + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; + } + + /*******************************************************************************/ + /* Rx OK check if valid DEP PDU */ + /*******************************************************************************/ + + if( gNfcip.rxBuf == NULL ) + { + return RFAL_ERR_IO; + } + + /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */ + nfcDepLen = gNfcip.rxBuf[rxMsgIt++]; + + nfcipLogD( " NFCIP(T) rx OK: %d bytes \r\n", nfcDepLen ); + + if( gNfcip.rxBuf[rxMsgIt++] != NFCIP_REQ ) + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad request */ + } + + + /*******************************************************************************/ + /* Check whether target rcvd a normal DEP or deactivation request */ + /*******************************************************************************/ + switch( gNfcip.rxBuf[rxMsgIt++] ) + { + /*******************************************************************************/ + case (uint8_t)NFCIP_CMD_DEP_REQ: + break; /* Continue to normal DEP processing */ + + /*******************************************************************************/ + case (uint8_t)NFCIP_CMD_DSL_REQ: + + nfcipLogI( " NFCIP(T) rx DSL \r\n" ); + + /* Digital 1.0 14.9.1.2 If DID is used and incorrect ignore it */ + /* [Digital 1.0, 16.9.1.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */ + if ( (((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) && (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) ) + || ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) && (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_NO_DID)) + ) + { + nfcipLogI( " NFCIP(T) DSL wrong DID, ignoring \r\n" ); + return RFAL_ERR_BUSY; + } + + nfcipTx( NFCIP_CMD_DSL_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT ); + + gNfcip.state = NFCIP_ST_TARG_DEP_SLEEP; + return RFAL_ERR_SLEEP_REQ; + + /*******************************************************************************/ + case (uint8_t)NFCIP_CMD_RLS_REQ: + + nfcipLogI( " NFCIP(T) rx RLS \r\n" ); + + /* Digital 1.0 14.10.1.2 If DID is used and incorrect ignore it */ + /* [Digital 1.0, 16.10.2.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */ + if ( (((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) && (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) ) + || ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) && (nfcDepLen > RFAL_NFCDEP_DSL_RLS_LEN_NO_DID)) + ) + { + nfcipLogI( " NFCIP(T) RLS wrong DID, ignoring \r\n" ); + return RFAL_ERR_BUSY; + } + + nfcipTx( NFCIP_CMD_RLS_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT ); + + gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; + return RFAL_ERR_RELEASE_REQ; + + /*******************************************************************************/ + /*case NFCIP_CMD_PSL_REQ: PSL must be handled in Activation only */ + /*case NFCIP_CMD_WUP_REQ: WUP not in NFC Forum Digital 1.0 */ + default: + + /* Don't go to NFCIP_ST_TARG_DEP_IDLE state as it needs to ignore this * + * invalid frame, and keep waiting for more frames */ + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad frame */ + } + + /*******************************************************************************/ + + rxPFB = gNfcip.rxBuf[rxMsgIt++]; /* Store rcvd PFB */ + + /*******************************************************************************/ + /* Check for valid PFB type */ + if( !(nfcip_PFBisSPDU( rxPFB ) || nfcip_PFBisRPDU( rxPFB ) || nfcip_PFBisIPDU( rxPFB )) ) + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore invalid PFB */ + } + + /*******************************************************************************/ + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + if( !nfcip_PFBhasDID( rxPFB ) ) + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad/missing DID */ + } + if( gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did ) /* MISRA 13.5 */ + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad/missing DID */ + } + optHdrLen++; /* Inc header optional field cnt*/ + } + else if( nfcip_PFBhasDID( rxPFB ) ) /* DID not expected but rcv */ + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected DID */ + } + else + { + /* MISRA 15.7 - Empty else */ + } + + + /*******************************************************************************/ + if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) + { + if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (!nfcip_PFBhasDID( rxPFB )) ) + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad/missing DID */ + } + optHdrLen++; /* Inc header optional field cnt*/ + } + else if( nfcip_PFBhasNAD( rxPFB ) ) /* NAD not expected but rcv */ + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected NAD */ + } + else + { + /* MISRA 15.7 - Empty else */ + } + + + /*******************************************************************************/ + /* Process R-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisRPDU( rxPFB ) ) + { + nfcipLogD( " NFCIP(T) Rcvd R-PDU \r\n" ); + /*******************************************************************************/ + /* R ACK */ + /*******************************************************************************/ + if( nfcip_PFBisRACK( rxPFB ) ) + { + nfcipLogI( " NFCIP(T) Rcvd ACK \r\n" ); + if( gNfcip.pni == nfcip_PBF_PNI( rxPFB ) ) + { + /* R-ACK while not performing chaining -> Protocol error */ + if( !gNfcip.isTxChaining ) + { + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected ACK */ + } + + /* This block has been transmitted and acknowledged, perform RTOX until next data is provided */ + + /* Digital 1.1 16.12.4.7 - If ACK rcvd continue with chaining or an RTOX */ + nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( rfalNfcDepWT2RWT( gNfcip.cfg.to ) )) ); + gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; + + return RFAL_ERR_NONE; /* This block has been transmitted */ + } + + /* Digital 1.0 14.12.3.4 - If last send was ATN and rx PNI is minus 1 */ + else if( nfcip_PFBisSATN( gNfcip.lastPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB )) ) + { + nfcipLogI( " NFCIP(T) wrong PNI, last was ATN reTx \r\n" ); + /* Spec says to leave current PNI as is, but will be Inc after Tx, remaining the same */ + gNfcip.pni = nfcip_PNIDec( gNfcip.pni ); + + gNfcip.state = NFCIP_ST_TARG_DEP_TX; + return RFAL_ERR_BUSY; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + /*******************************************************************************/ + /* R NACK */ + /*******************************************************************************/ + /* ISO 18092 12.6.1.3.3 When rcv NACK if PNI = prev PNI sent -> reTx */ + else if( nfcip_PFBisRNACK( rxPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB ) ) ) + { + nfcipLogI( " NFCIP(T) Rcvd NACK \r\n" ); + + gNfcip.pni = nfcip_PNIDec( gNfcip.pni ); /* Dec so that has the prev PNI */ + + gNfcip.state = NFCIP_ST_TARG_DEP_TX; + return RFAL_ERR_BUSY; + } + else + { + nfcipLogI( " NFCIP(T) Unexpected R-PDU \r\n" ); + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected R-PDU */ + } + } + + /*******************************************************************************/ + /* Process S-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisSPDU( rxPFB ) ) + { + nfcipLogD( " NFCIP(T) Rcvd S-PDU \r\n" ); + + /*******************************************************************************/ + /* S ATN */ + /*******************************************************************************/ + /* ISO 18092 12.6.3 Attention */ + if( nfcip_PFBisSATN( rxPFB ) ) /* If is a S-ATN */ + { + nfcipLogI( " NFCIP(T) Rcvd ATN curPNI: %d \r\n", gNfcip.pni ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_ATN(), 0 ) ); + return RFAL_ERR_BUSY; + } + + /*******************************************************************************/ + /* S TO */ + /*******************************************************************************/ + else if( nfcip_PFBisSTO( rxPFB ) ) /* If is a S-TO (RTOX) */ + { + if( nfcip_PFBisSTO( gNfcip.lastPFBnATN ) ) + { + nfcipLogI( " NFCIP(T) Rcvd TO \r\n" ); + + /* Digital 1.1 16.8.4.6 RTOX value in RES different that in REQ -> Protocol Error */ + if( gNfcip.lastRTOX != gNfcip.rxBuf[rxMsgIt++] ) + { + nfcipLogI( " NFCIP(T) Mismatched RTOX value \r\n" ); + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected RTOX value */ + } + + /* Clear waiting for RTOX Ack Flag */ + gNfcip.isWait4RTOX = false; + + /* Check if a Tx is already pending */ + if( gNfcip.isTxPending ) + { + nfcipLogW( " NFCIP(T) Tx pending, go immediately to TX \r\n" ); + + gNfcip.state = NFCIP_ST_TARG_DEP_TX; + return RFAL_ERR_BUSY; + } + + /* Start RTOX timer and change to check state */ + nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( gNfcip.lastRTOX * rfalNfcDepWT2RWT(gNfcip.cfg.to ) ) ) ); + gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; + + return RFAL_ERR_BUSY; + } + } + else + { + /* Unexpected S-PDU */ + nfcipLogI( " NFCIP(T) Unexpected S-PDU \r\n" ); + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore unexpected S-PDU */ + } + } + + /*******************************************************************************/ + /* Process I-PDU */ + /*******************************************************************************/ + if( nfcip_PFBisIPDU( rxPFB ) ) + { + if( gNfcip.pni != nfcip_PBF_PNI( rxPFB ) ) + { + nfcipLogI( " NFCIP(T) Rcvd IPDU wrong PNI curPNI: %d rxPNI: %d \r\n", gNfcip.pni, nfcip_PBF_PNI( rxPFB ) ); + + /* Digital 1.1 16.12.3.4 - If last send was ATN and rx PNI is minus 1 */ + if( nfcip_PFBisSATN(gNfcip.lastPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB )) ) + { + /* Spec says to leave current PNI as is, but will be Inc after Data Tx, remaining the same */ + gNfcip.pni = nfcip_PNIDec(gNfcip.pni); + + if( nfcip_PFBisIMI( rxPFB ) ) + { + nfcipLogI( " NFCIP(T) PNI = prevPNI && ATN before && chaining -> send ACK \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); + + /* Digital 1.1 16.12.3.4 (...) leave the current PNI unchanged afterwards */ + gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); + } + else + { + nfcipLogI( " NFCIP(T) PNI = prevPNI && ATN before -> reTx last I-PDU \r\n" ); + gNfcip.state = NFCIP_ST_TARG_DEP_TX; + } + + return RFAL_ERR_BUSY; + } + + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + return RFAL_ERR_BUSY; /* RFAL_ERR_PROTO - Ignore bad PNI value */ + } + + nfcipLogD( " NFCIP(T) Rcvd IPDU OK PNI: %d \r\n", gNfcip.pni ); + + /*******************************************************************************/ + /* Successful data exchange */ + /*******************************************************************************/ + *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen); + + nfcipClearCounters(); + + if( (&gNfcip.rxBuf[gNfcip.rxBufPaylPos] != &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) && (*outActRxLen > 0U) ) + { + RFAL_MEMMOVE( &gNfcip.rxBuf[gNfcip.rxBufPaylPos], &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen], *outActRxLen ); + } + + + /*******************************************************************************/ + /* Check if Initiator is indicating chaining MI */ + /*******************************************************************************/ + if( nfcip_PFBisIMI( rxPFB ) ) + { + gNfcip.isRxChaining = true; + *outIsChaining = true; + + nfcipLogD( " NFCIP(T) Rcvd IPDU OK w MI -> ACK \r\n" ); + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); + + gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); + + return RFAL_ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/ + } + else + { + if(gNfcip.isRxChaining) + { + nfcipLogI( " NFCIP(T) Rcvd last IPDU chaining finished \r\n" ); + } + + /*******************************************************************************/ + /* Reception done, send to DH and start RTOX timer */ + /*******************************************************************************/ + nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( rfalNfcDepWT2RWT( gNfcip.cfg.to ) )) ); + gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; + + gNfcip.isRxChaining = false; + ret = RFAL_ERR_NONE; /* Data exchange done */ + } + } + return ret; +} + + +/*******************************************************************************/ +static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfbData, uint32_t fwt ) +{ + uint16_t txBufIt; + uint8_t *txBlock; + uint8_t *payloadBuf; + uint8_t pfb; + + + if( txBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + + payloadBuf = paylBuf; /* MISRA 17.8: Use intermediate variable */ + + if( (paylLen == 0U) || (payloadBuf == NULL) ) + { + payloadBuf = (uint8_t*) &txBuf[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /* If not a DEP (no Data) ensure enough space for header */ + } + + + txBufIt = 0; + pfb = pfbData; /* MISRA 17.8: Use intermediate variable */ + + txBlock = payloadBuf; /* Point to beginning of the Data, and go backwards */ + + + gNfcip.lastCmd = (uint8_t)cmd; /* Store last cmd sent */ + gNfcip.lastPFB = NFCIP_PFB_INVALID; /* Reset last pfb sent */ + + /*******************************************************************************/ + /* Compute outgoing NFCIP message */ + /*******************************************************************************/ + switch( cmd ) + { + /*******************************************************************************/ + case NFCIP_CMD_ATR_RES: + case NFCIP_CMD_ATR_REQ: + + rfalNfcDepSetNFCID( payloadBuf, gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen ); /* NFCID */ + txBufIt += RFAL_NFCDEP_NFCID3_LEN; + + payloadBuf[txBufIt++] = gNfcip.cfg.did; /* DID */ + payloadBuf[txBufIt++] = gNfcip.cfg.bs; /* BS */ + payloadBuf[txBufIt++] = gNfcip.cfg.br; /* BR */ + + if( cmd == NFCIP_CMD_ATR_RES ) + { + payloadBuf[txBufIt++] = gNfcip.cfg.to; /* ATR_RES[ TO ] */ + } + + if( gNfcip.cfg.gbLen > 0U) + { + payloadBuf[txBufIt++] = nfcip_PPwGB( gNfcip.cfg.lr ); /* PP signalling GB */ + RFAL_MEMCPY( &payloadBuf[txBufIt], gNfcip.cfg.gb, gNfcip.cfg.gbLen ); /* set General Bytes */ + txBufIt += gNfcip.cfg.gbLen; + } + else + { + payloadBuf[txBufIt++] = rfalNfcDepLR2PP( gNfcip.cfg.lr ); /* PP without GB */ + } + + if( (txBufIt + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) > RFAL_NFCDEP_ATRREQ_MAX_LEN ) /* Check max ATR length (ATR_REQ = ATR_RES)*/ + { + return RFAL_ERR_PARAM; + } + break; + + /*******************************************************************************/ + case NFCIP_CMD_WUP_REQ: /* ISO 18092 - 12.5.2.1 */ + + rfalNfcDepSetNFCID( (payloadBuf), gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen ); /* NFCID */ + txBufIt += RFAL_NFCDEP_NFCID3_LEN; + + *(--txBlock) = gNfcip.cfg.did; /* DID */ + break; + + /*******************************************************************************/ + case NFCIP_CMD_WUP_RES: /* ISO 18092 - 12.5.2.2 */ + case NFCIP_CMD_PSL_REQ: + case NFCIP_CMD_PSL_RES: + + *(--txBlock) = gNfcip.cfg.did; /* DID */ + break; + + /*******************************************************************************/ + case NFCIP_CMD_RLS_REQ: + case NFCIP_CMD_RLS_RES: + case NFCIP_CMD_DSL_REQ: + case NFCIP_CMD_DSL_RES: + + /* Digital 1.0 - 14.8.1.1 & 14.9.1.1 & 14.10.1.1 Only add DID if not 0 */ + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + *(--txBlock) = gNfcip.cfg.did; /* DID */ + } + break; + + /*******************************************************************************/ + case NFCIP_CMD_DEP_REQ: + case NFCIP_CMD_DEP_RES: + + /* Compute optional PFB bits */ + if (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) { pfb |= NFCIP_PFB_DID_BIT; } + if (gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) { pfb |= NFCIP_PFB_NAD_BIT; } + if ((gNfcip.isTxChaining) && (nfcip_PFBisIPDU(pfb)) ) { pfb |= NFCIP_PFB_MI_BIT; } + + /* Store PFB for future handling */ + gNfcip.lastPFB = pfb; /* store PFB sent */ + + if( !nfcip_PFBisSATN(pfb) ) + { + gNfcip.lastPFBnATN = pfb; /* store last PFB different then ATN */ + } + + + /* Add NAD if it is to be supported */ + if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) + { + *(--txBlock) = gNfcip.cfg.nad; /* NAD */ + } + + /* Digital 1.0 - 14.8.1.1 & 14.8.1.1 Only add DID if not 0 */ + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + *(--txBlock) = gNfcip.cfg.did; /* DID */ + } + + *(--txBlock) = pfb; /* PFB */ + + + /* NCI 1.0 - Check if Empty frames are allowed */ + if( (paylLen == 0U) && nfcipIsEmptyDEPDisabled(gNfcip.cfg.oper) && nfcip_PFBisIPDU(pfb) ) + { + return RFAL_ERR_PARAM; + } + break; + + /*******************************************************************************/ + default: + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + /* Prepend Header */ + /*******************************************************************************/ + *(--txBlock) = (uint8_t)cmd; /* CMD */ + *(--txBlock) = (uint8_t)( nfcipCmdIsReq(cmd) ? NFCIP_REQ : NFCIP_RES ); /* CMDType */ + + + txBufIt += paylLen + (uint16_t)((uintptr_t)payloadBuf - (uintptr_t)txBlock); /* Calculate overall buffer size */ + + + if( txBufIt > gNfcip.fsc ) /* Check if msg length violates the maximum payload size FSC */ + { + return RFAL_ERR_NOTSUPP; + } + + /*******************************************************************************/ + return nfcipDataTx( txBlock, txBufIt, fwt ); +} + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +static void nfcipConfig( const rfalNfcDepConfigs * cfg ) +{ + if (cfg == NULL) + { + return; + } + + RFAL_MEMCPY(&gNfcip.cfg, cfg, sizeof(rfalNfcDepConfigs)); /* Copy given config to local */ + + gNfcip.cfg.to = RFAL_MIN( RFAL_NFCDEP_WT_TRG_MAX, gNfcip.cfg.to); /* Ensure proper WT value */ + gNfcip.cfg.did = nfcip_DIDMax( gNfcip.cfg.did ); /* Ensure proper DID value */ + gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); /* Calculate FSC based on given LR */ + + gNfcip.state = ( ( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_ST_TARG_WAIT_ATR : NFCIP_ST_INIT_IDLE ); +} + + +/*******************************************************************************/ +static ReturnCode nfcipRun( uint16_t *outActRxLen, bool *outIsChaining ) +{ + ReturnCode ret; + + ret = RFAL_ERR_SYNTAX; + + nfcipLogD( " NFCIP Run() state: %d \r\n", gNfcip.state ); + + switch( gNfcip.state ) + { + /*******************************************************************************/ + case NFCIP_ST_IDLE: + case NFCIP_ST_INIT_DEP_IDLE: + case NFCIP_ST_TARG_DEP_IDLE: + case NFCIP_ST_TARG_DEP_SLEEP: + return RFAL_ERR_NONE; + + /*******************************************************************************/ + case NFCIP_ST_INIT_DEP_TX: + + nfcipLogD( " NFCIP(I) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen ); + ret = nfcipTx( NFCIP_CMD_DEP_REQ, gNfcip.txBuf, &gNfcip.txBuf[gNfcip.txBufPaylPos], gNfcip.txBufLen, nfcip_PFBIPDU( gNfcip.pni ), (gNfcip.cfg.fwt + gNfcip.cfg.dFwt) ); + + switch( ret ) + { + case RFAL_ERR_NONE: + gNfcip.state = NFCIP_ST_INIT_DEP_RX; + break; + + case RFAL_ERR_PARAM: + default: + gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; + return ret; + } + /* fall through */ + + /*******************************************************************************/ + case NFCIP_ST_INIT_DEP_RX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + ret = nfcipDataRx( false ); + + if( ret != RFAL_ERR_BUSY ) + { + ret = nfcipInitiatorHandleDEP( ret, ((gNfcip.rxRcvdLen != NULL) ? *gNfcip.rxRcvdLen : 0U), outActRxLen, outIsChaining ); + } + + break; + + /*******************************************************************************/ + case NFCIP_ST_TARG_DEP_RTOX: + + if( !nfcipTimerisExpired( gNfcip.RTOXTimer ) ) /* Do nothing until RTOX timer has expired */ + { + return RFAL_ERR_BUSY; + } + + /* If we cannot send a RTOX raise a Timeout error so that we do not + * hold the field On forever in AP2P */ + if( nfcipIsRTOXReqDisabled(gNfcip.cfg.oper) ) + { + /* We should reEnable Rx, and measure time between our field Off to + * either report link loss or recover #287 */ + nfcipLogI( " NFCIP(T) RTOX not sent due to config, NOT reenabling Rx \r\n" ); + return RFAL_ERR_TIMEOUT; + } + + if( gNfcip.cntRTOXRetrys++ > RFAL_NFCDEP_MAX_RTOX_RETRYS ) /* Check maximum consecutive RTOX requests */ + { + return RFAL_ERR_PROTO; + } + + nfcipLogI( " NFCIP(T) RTOX sent \r\n" ); + + gNfcip.lastRTOX = nfcip_RTOXTargMax(gNfcip.cfg.to); /* Calculate requested RTOX value, and send it */ + RFAL_EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), gNfcip.lastRTOX ) ); + + /* Set waiting for RTOX Ack Flag */ + gNfcip.isWait4RTOX = true; + + gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* Go back to Rx to process RTOX ack */ + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case NFCIP_ST_TARG_DEP_TX: + + nfcipLogD( " NFCIP(T) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen ); + ret = nfcipTx( NFCIP_CMD_DEP_RES, gNfcip.txBuf, &gNfcip.txBuf[gNfcip.txBufPaylPos], gNfcip.txBufLen, nfcip_PFBIPDU( gNfcip.pni ), NFCIP_NO_FWT ); + + /* Clear flags */ + gNfcip.isTxPending = false; + gNfcip.isWait4RTOX = false; + + /* Digital 1.0 14.12.3.4 Increment the current PNI after Tx */ + gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); + + switch( ret ) + { + case RFAL_ERR_NONE: + gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* All OK, goto Rx state */ + break; + + case RFAL_ERR_PARAM: + default: + gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; /* Upon Tx error, goto IDLE state */ + return ret; + } + /* fall through */ + + /*******************************************************************************/ + case NFCIP_ST_TARG_DEP_RX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + if( gNfcip.isReqPending ) /* if already has Data should be from a DEP from nfcipTargetHandleActivation() */ + { + nfcipLogD( " NFCIP(T) Skipping Rx Using DEP from Activation \r\n" ); + + gNfcip.isReqPending = false; + ret = RFAL_ERR_NONE; + } + else + { + ret = nfcipDataRx( false ); + } + + if( ret != RFAL_ERR_BUSY ) + { + ret = nfcipTargetHandleRX( ret, outActRxLen, outIsChaining ); + } + + break; + + /*******************************************************************************/ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + return ret; +} + + +/*******************************************************************************/ +void rfalNfcDepSetDeactivatingCallback( rfalNfcDepDeactCallback pFunc ) +{ + gNfcip.isDeactivating = pFunc; +} + + +/*******************************************************************************/ +void rfalNfcDepInitialize( void ) +{ + nfcipLogD( " NFCIP Ini() \r\n" ); + + gNfcip.state = NFCIP_ST_IDLE; + gNfcip.isDeactivating = NULL; + + gNfcip.isTxPending = false; + gNfcip.isWait4RTOX = false; + gNfcip.isReqPending = false; + + + gNfcip.cfg.oper = (RFAL_NFCDEP_OPER_FULL_MI_DIS | RFAL_NFCDEP_OPER_EMPTY_DEP_EN | RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN); + + gNfcip.cfg.did = RFAL_NFCDEP_DID_NO; + gNfcip.cfg.nad = RFAL_NFCDEP_NAD_NO; + + gNfcip.cfg.br = RFAL_NFCDEP_Bx_NO_HIGH_BR; + gNfcip.cfg.bs = RFAL_NFCDEP_Bx_NO_HIGH_BR; + + gNfcip.cfg.lr = RFAL_NFCDEP_LR_254; + gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); + + gNfcip.cfg.gbLen = 0; + + gNfcip.cfg.fwt = NFCIP_RWT_ACTIVATION; + gNfcip.cfg.dFwt = RFAL_NFCDEP_WT_DELTA; + + gNfcip.pni = 0; + + /* Destroy any ongoing RTOX timer*/ + nfcipTimerDestroy( gNfcip.RTOXTimer ); + gNfcip.RTOXTimer = 0U; + + gNfcip.PDUTxPos = 0; + gNfcip.PDURxPos = 0; + gNfcip.PDUParam.rxLen = NULL; + gNfcip.PDUParam.rxBuf = NULL; + gNfcip.PDUParam.txBuf = NULL; + + + nfcipClearCounters(); +} + + +/*******************************************************************************/ +static void nfcipSetDEPParams( const rfalNfcDepDEPParams *DEPParams ) +{ + nfcipLogD( " NFCIP SetDEP() txLen: %d \r\n", DEPParams->txBufLen ); + + gNfcip.isTxChaining = DEPParams->txChaining; + gNfcip.txBuf = DEPParams->txBuf; + gNfcip.rxBuf = DEPParams->rxBuf; + gNfcip.txBufLen = DEPParams->txBufLen; + gNfcip.rxBufLen = DEPParams->rxBufLen; + gNfcip.txBufPaylPos = DEPParams->txBufPaylPos; + gNfcip.rxBufPaylPos = DEPParams->rxBufPaylPos; + + if( DEPParams->did != RFAL_NFCDEP_DID_KEEP ) + { + gNfcip.cfg.did = nfcip_DIDMax( DEPParams->did ); + } + + gNfcip.cfg.fwt = DEPParams->fwt; + gNfcip.cfg.dFwt = DEPParams->dFwt; + gNfcip.fsc = DEPParams->fsc; + + + + if(gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) + { + /* If there's any data to be sent go for Tx */ + if(DEPParams->txBufLen > 0U) + { + /* Ensure that an RTOX Ack is not being expected at moment */ + if( !gNfcip.isWait4RTOX ) + { + gNfcip.state = NFCIP_ST_TARG_DEP_TX; + return; + } + else + { + /* If RTOX Ack is expected, signal a pending Tx to be transmitted right after */ + gNfcip.isTxPending = true; + nfcipLogW( " NFCIP(T) Waiting RTOX, queueing outgoing DEP Block \r\n" ); + } + } + + /*Digital 1.0 14.12.4.1 In target mode the first PDU MUST be sent by the Initiator */ + gNfcip.state = NFCIP_ST_TARG_DEP_RX; + return; + } + + /* New data TxRx request clear previous error counters for consecutive TxRx without reseting communication/protocol layer*/ + nfcipClearCounters(); + + gNfcip.state = NFCIP_ST_INIT_DEP_TX; +} + + +/*******************************************************************************/ +bool rfalNfcDepTargetRcvdATR( void ) +{ + return ( (gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) && nfcipIsTarget(gNfcip.state) && (gNfcip.state > NFCIP_ST_TARG_WAIT_ATR) ); +} + + +/*******************************************************************************/ +bool rfalNfcDepIsAtrReq( const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3 ) +{ + uint8_t msgIt; + + msgIt = 0; + + if ( (bufLen < RFAL_NFCDEP_ATRREQ_MIN_LEN) || (bufLen > RFAL_NFCDEP_ATRREQ_MAX_LEN) ) + { + return false; + } + + if ( buf[msgIt++] != NFCIP_REQ ) + { + return false; + } + + if( buf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_REQ ) + { + return false; + } + + /* Output NFID3 if requested */ + if( nfcid3 != NULL ) + { + RFAL_MEMCPY( nfcid3, &buf[RFAL_NFCDEP_ATR_REQ_NFCID3_POS], RFAL_NFCDEP_NFCID3_LEN ); + } + + return true; +} + + +/*******************************************************************************/ +static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS ) +{ + ReturnCode ret; + uint8_t msgIt; + uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_PSLRES_LEN]; + + /*******************************************************************************/ + /* Check if we are in correct state */ + /*******************************************************************************/ + if( gNfcip.state != NFCIP_ST_TARG_WAIT_ACTV ) + { + return RFAL_ERR_WRONG_STATE; + } + + + /*******************************************************************************/ + /* Check required parameters */ + /*******************************************************************************/ + if( outBRS == NULL ) + { + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + /* Wait and process incoming cmd (PSL / DEP) */ + /*******************************************************************************/ + ret = nfcipDataRx( false ); + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + if( gNfcip.rxBuf == NULL ) + { + return RFAL_ERR_IO; + } + + + msgIt = 0; + *outBRS = RFAL_NFCDEP_BRS_MAINTAIN; /* set out BRS to be maintained */ + + msgIt++; /* Skip LEN byte */ + + if ( gNfcip.rxBuf[msgIt++] != NFCIP_REQ ) + { + return RFAL_ERR_PROTO; + } + + if( gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_PSL_REQ ) + { + msgIt++; + + if( gNfcip.rxBuf[msgIt++] != gNfcip.cfg.did ) /* Checking DID */ + { + return RFAL_ERR_PROTO; + } + + nfcipLogI( " NFCIP(T) PSL REQ rcvd \r\n" ); + + *outBRS = gNfcip.rxBuf[msgIt++]; /* assign output BRS value */ + + /* Store FSL(LR) and update current config */ + gNfcip.cfg.lr = (gNfcip.rxBuf[msgIt++] & RFAL_NFCDEP_LR_VAL_MASK); + gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); + + /*******************************************************************************/ + /* Update NFC-DDE Device info */ + if( nfcDepDev != NULL ) + { + /* Update Bitrate info */ + /* PRQA S 4342 2 # MISRA 10.5 - Layout of enum rfalBitRate and definition of rfalNfcDepBRS2DSI guarantee no invalid enum values to be created */ + nfcDepDev->info.DSI = (rfalBitRate)rfalNfcDepBRS2DSI( *outBRS ); /* DSI codes the bit rate from Initiator to Target */ + nfcDepDev->info.DRI = (rfalBitRate)rfalNfcDepBRS2DRI( *outBRS ); /* DRI codes the bit rate from Target to Initiator */ + + /* Update Length Reduction and Frame Size */ + nfcDepDev->info.LR = gNfcip.cfg.lr; + nfcDepDev->info.FS = gNfcip.fsc; + + /* Update PPi byte */ + nfcDepDev->activation.Initiator.ATR_REQ.PPi &= ~RFAL_NFCDEP_PP_LR_MASK; + nfcDepDev->activation.Initiator.ATR_REQ.PPi |= rfalNfcDepLR2PP( gNfcip.cfg.lr ); + } + + rfalSetBitRate( RFAL_BR_KEEP, gNfcip.nfcDepDev->info.DSI ); + + RFAL_EXIT_ON_ERR( ret, nfcipTx( NFCIP_CMD_PSL_RES, txBuf, NULL, 0, 0, NFCIP_NO_FWT ) ); + } + else + { + if( gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_DEP_REQ ) + { + msgIt++; + + /*******************************************************************************/ + /* Digital 1.0 14.12.3.1 PNI must be initialized to 0 */ + if( nfcip_PBF_PNI( gNfcip.rxBuf[msgIt] ) != 0U ) + { + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Digital 1.0 14.8.2.1 check if DID is expected and match -> Protocol Error */ + if( nfcip_PFBhasDID( gNfcip.rxBuf[ msgIt] ) ) + { + if( gNfcip.rxBuf[++msgIt] != gNfcip.cfg.did ) + { + return RFAL_ERR_PROTO; + } + } + else if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) /* DID expected but not rcv */ + { + return RFAL_ERR_PROTO; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + + /* Signal Request pending to be digested on normal Handling (DEP_REQ, DSL_REQ, RLS_REQ) */ + gNfcip.isReqPending = true; + } + + gNfcip.state = NFCIP_ST_TARG_DEP_RX; + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepATR( const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes *atrRes, uint8_t* atrResLen ) +{ + ReturnCode ret; + rfalNfcDepConfigs cfg; + uint16_t rxLen; + uint8_t msgIt; + uint8_t txBuf[RFAL_NFCDEP_ATRREQ_MAX_LEN]; + uint8_t rxBuf[NFCIP_ATRRES_BUF_LEN]; + + + if( (param == NULL) || (atrRes == NULL) || (atrResLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + RFAL_MEMSET( &cfg, 0x00, sizeof(rfalNfcDepConfigs) ); + + /*******************************************************************************/ + /* Configure NFC-DEP layer */ + /*******************************************************************************/ + + cfg.did = param->DID; + cfg.nad = param->NAD; + cfg.fwt = RFAL_NFCDEP_MAX_FWT; + cfg.dFwt = RFAL_NFCDEP_WT_DELTA; +#define ESP_BR BR +#undef BR + cfg.br = param->BR; +#define BR ESP_BR +#undef ESP_BR + cfg.bs = param->BS; + cfg.lr = param->LR; + cfg.to = RFAL_NFCDEP_WT_TRG_MAX; /* Not used in Initiator mode */ + + + cfg.gbLen = param->GBLen; + if( cfg.gbLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( cfg.gb, param->GB, cfg.gbLen ); + } + + cfg.nfcidLen = param->nfcidLen; + if( cfg.nfcidLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( cfg.nfcid, param->nfcid, cfg.nfcidLen ); + } + + cfg.role = RFAL_NFCDEP_ROLE_INITIATOR; + cfg.oper = param->operParam; + cfg.commMode = param->commMode; + + rfalNfcDepInitialize(); + nfcipConfig( &cfg ); + + /*******************************************************************************/ + /* Send ATR_REQ */ + /*******************************************************************************/ + + RFAL_EXIT_ON_ERR( ret, nfcipTxRx(NFCIP_CMD_ATR_REQ, txBuf, nfcipRWTActivation(), NULL, 0, rxBuf, NFCIP_ATRRES_BUF_LEN, &rxLen ) ); + + + /*******************************************************************************/ + /* ATR sent, check response */ + /*******************************************************************************/ + msgIt = 0; + rxLen = ((uint16_t)rxBuf[msgIt++] - RFAL_NFCDEP_LEN_LEN); /* use LEN byte */ + + if( (rxLen < RFAL_NFCDEP_ATRRES_MIN_LEN) || (rxLen > RFAL_NFCDEP_ATRRES_MAX_LEN) ) /* Checking length: ATR_RES */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[msgIt++] != NFCIP_RES ) /* Checking if is a response*/ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_RES ) /* Checking if is a ATR RES */ + { + return RFAL_ERR_PROTO; + } + + RFAL_MEMCPY( (uint8_t*)atrRes, (rxBuf + RFAL_NFCDEP_LEN_LEN), rxLen ); + *atrResLen = (uint8_t)rxLen; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepPSL( uint8_t BRS, uint8_t FSL ) +{ + ReturnCode ret; + uint16_t rxLen; + uint8_t msgIt; + uint8_t txBuf[NFCIP_PSLREQ_LEN + NFCIP_PSLPAY_LEN]; + uint8_t rxBuf[NFCIP_PSLRES_LEN]; + + msgIt = NFCIP_PSLREQ_LEN; + + txBuf[msgIt++] = BRS; + txBuf[msgIt++] = FSL; + + /*******************************************************************************/ + /* Send PSL REQ and wait for response */ + /*******************************************************************************/ + RFAL_EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_PSL_REQ, txBuf, (gNfcip.cfg.fwt + gNfcip.cfg.dFwt), &txBuf[NFCIP_PSLREQ_LEN], (msgIt - NFCIP_PSLREQ_LEN), rxBuf, NFCIP_PSLRES_LEN, &rxLen ) ); + + + /*******************************************************************************/ + /* PSL sent, check response */ + /*******************************************************************************/ + msgIt = 0; + rxLen = (uint16_t)(rxBuf[msgIt++]); /* use LEN byte */ + + if( rxLen < NFCIP_PSLRES_LEN ) /* Checking length: LEN + RLS_RES */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[msgIt++] != NFCIP_RES ) /* Checking if is a response */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_PSL_RES ) /* Checking if is a PSL RES */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[msgIt++] != gNfcip.cfg.did ) /* Checking DID */ + { + return RFAL_ERR_PROTO; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepDSL( void ) +{ + ReturnCode ret; + uint8_t txBuf[ RFAL_NFCDEP_HEADER_PAD + NFCIP_DSLREQ_LEN]; + uint8_t rxBuf[NFCIP_DSLRES_LEN]; + uint8_t rxMsgIt; + uint16_t rxLen = 0; + + if( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET ) + { + return RFAL_ERR_NONE; /* Target has no deselect procedure */ + } + + /* Repeating a DSL REQ is optional, not doing it */ + RFAL_EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_DSL_REQ, txBuf, (gNfcip.cfg.fwt + gNfcip.cfg.dFwt), NULL, 0, rxBuf, (uint16_t)sizeof(rxBuf), &rxLen ) ); + + /*******************************************************************************/ + rxMsgIt = 0; + + if( rxBuf[rxMsgIt++] < NFCIP_DSLRES_MIN ) /* Checking length: LEN + DSL_RES */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[rxMsgIt++] != NFCIP_RES ) /* Checking if is a response */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DSL_RES ) /* Checking if is DSL RES */ + { + return RFAL_ERR_PROTO; + } + + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + if ( rxBuf[rxMsgIt++] != gNfcip.cfg.did ) + { + return RFAL_ERR_PROTO; + } + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepRLS( void ) +{ + ReturnCode ret; + uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_RLSREQ_LEN]; + uint8_t rxBuf[NFCIP_RLSRES_LEN]; + uint8_t rxMsgIt; + uint16_t rxLen = 0; + + if ( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET ) /* Target has no release procedure */ + { + return RFAL_ERR_NONE; + } + + /* Repeating a RLS REQ is optional, not doing it */ + RFAL_EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_RLS_REQ, txBuf, (gNfcip.cfg.fwt + gNfcip.cfg.dFwt), NULL, 0, rxBuf, (uint16_t)sizeof(rxBuf), &rxLen ) ); + + /*******************************************************************************/ + rxMsgIt = 0; + + if( rxBuf[rxMsgIt++] < NFCIP_RLSRES_MIN ) /* Checking length: LEN + RLS_RES */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[rxMsgIt++] != NFCIP_RES ) /* Checking if is a response */ + { + return RFAL_ERR_PROTO; + } + + if( rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_RLS_RES ) /* Checking if is RLS RES */ + { + return RFAL_ERR_PROTO; + } + + if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) + { + if ( rxBuf[rxMsgIt++] != gNfcip.cfg.did ) + { + return RFAL_ERR_PROTO; + } + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepInitiatorHandleActivation( rfalNfcDepAtrParam* param, rfalBitRate desiredBR, rfalNfcDepDevice* nfcDepDev ) +{ + ReturnCode ret; + uint8_t maxRetyrs; + uint8_t PSL_BRS; + uint8_t PSL_FSL; + bool sendPSL; + + if( (param == NULL) || (nfcDepDev == NULL) ) + { + return RFAL_ERR_PARAM; + } + + param->NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.2.9 Initiator SHALL NOT use NAD */ + maxRetyrs = NFCIP_ATR_RETRY_MAX; + + /*******************************************************************************/ + /* Send ATR REQ and wait for response */ + /*******************************************************************************/ + do{ /* Upon transmission error ATR REQ should be retried */ + + ret = rfalNfcDepATR( param, &nfcDepDev->activation.Target.ATR_RES, &nfcDepDev->activation.Target.ATR_RESLen ); + + if( nfcipIsTransmissionError(ret) ) + { + continue; + } + break; + } + while( (maxRetyrs--) != 0U ); + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /*******************************************************************************/ + /* Compute NFC-DEP device with ATR_RES */ + /*******************************************************************************/ + nfcDepDev->info.GBLen = (nfcDepDev->activation.Target.ATR_RESLen - RFAL_NFCDEP_ATRRES_MIN_LEN); + nfcDepDev->info.DID = nfcDepDev->activation.Target.ATR_RES.DID; + nfcDepDev->info.NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.3.11 Initiator SHALL ignore b1 of PPt */ + nfcDepDev->info.LR = rfalNfcDepPP2LR( nfcDepDev->activation.Target.ATR_RES.PPt ); + nfcDepDev->info.FS = rfalNfcDepLR2FS( nfcDepDev->info.LR ); + nfcDepDev->info.WT = (nfcDepDev->activation.Target.ATR_RES.TO & RFAL_NFCDEP_WT_MASK); + nfcDepDev->info.FWT = rfalNfcDepCalculateRWT( nfcDepDev->info.WT ); + nfcDepDev->info.dFWT = RFAL_NFCDEP_WT_DELTA; + + rfalGetBitRate( &nfcDepDev->info.DSI, &nfcDepDev->info.DRI ); + + + + /*******************************************************************************/ + /* Check if a PSL needs to be sent */ + /*******************************************************************************/ + sendPSL = false; + PSL_BRS = rfalNfcDepDx2BRS( nfcDepDev->info.DSI ); /* Set current bit rate divisor on both directions */ + PSL_FSL = nfcDepDev->info.LR; /* Set current Frame Size */ + + + + /* Activity 1.0 9.4.4.15 & 9.4.6.3 NFC-DEP Activation PSL + * Activity 2.0 9.4.4.17 & 9.4.6.6 NFC-DEP Activation PSL + * + * PSL_REQ shall only be sent if desired bit rate is different from current (Activity 1.0) + * PSL_REQ shall be sent to update LR or bit rate (Activity 2.0) + * */ + +#if 0 /* PSL due to LR is disabled, can be enabled if desired*/ + /*******************************************************************************/ + /* Check Frame Size */ + /*******************************************************************************/ + if( gNfcip.cfg.lr < nfcDepDev->info.LR ) /* If our Length reduction is smaller */ + { + sendPSL = true; + + nfcDepDev->info.LR = RFAL_MIN( nfcDepDev->info.LR, gNfcip.cfg.lr ); + + gNfcip.cfg.lr = nfcDepDev->info.LR; /* Update nfcip LR to be used */ + gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); /* Update nfcip FSC to be used */ + + PSL_FSL = gNfcip.cfg.lr; /* Set LR to be sent */ + + nfcipLogI( " NFCIP(I) Frame Size differ, PSL new fsc: %d \r\n", gNfcip.fsc ); + } +#endif + + + /*******************************************************************************/ + /* Check Baud rates */ + /*******************************************************************************/ + if( (nfcDepDev->info.DSI != desiredBR) && (desiredBR != RFAL_BR_KEEP) ) /* if desired BR is different */ + { + if( nfcipDxIsSupported( (uint8_t)desiredBR, nfcDepDev->activation.Target.ATR_RES.BRt, nfcDepDev->activation.Target.ATR_RES.BSt ) ) /* if desired BR is supported */ /* MISRA 13.5 */ + { + sendPSL = true; + PSL_BRS = rfalNfcDepDx2BRS( desiredBR ); + + nfcipLogI( " NFCIP(I) BR differ, PSL BR: 0x%02X \r\n", PSL_BRS ); + } + } + + + /*******************************************************************************/ + if( sendPSL ) + { + /* Apply target's FWT for PSL_REQ Digital 2.2 17.11.2.5 */ + gNfcip.cfg.fwt = nfcDepDev->info.FWT; + + /*******************************************************************************/ + /* Send PSL REQ and wait for response */ + /*******************************************************************************/ + RFAL_EXIT_ON_ERR( ret, rfalNfcDepPSL(PSL_BRS, PSL_FSL) ); + + /* Check if bit rate has been changed */ + if( nfcDepDev->info.DSI != desiredBR ) + { + /* Check if device was in Passive NFC-A and went to higher bit rates, use NFC-F */ + if( (nfcDepDev->info.DSI == RFAL_BR_106) && (gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE) ) + { + + #if RFAL_FEATURE_NFCF + /* If Passive initialize NFC-F module */ + rfalNfcfPollerInitialize( desiredBR ); + #else /* RFAL_FEATURE_NFCF */ + return RFAL_ERR_NOTSUPP; + #endif /* RFAL_FEATURE_NFCF */ + + } + + nfcDepDev->info.DRI = desiredBR; /* DSI Bit Rate coding from Initiator to Target */ + nfcDepDev->info.DSI = desiredBR; /* DRI Bit Rate coding from Target to Initiator */ + + rfalSetBitRate( nfcDepDev->info.DSI, nfcDepDev->info.DRI ); + } + + + return RFAL_ERR_NONE; /* PSL has been sent */ + } + + return RFAL_ERR_NONE; /* No PSL has been sent */ +} + + +/*******************************************************************************/ +uint32_t rfalNfcDepCalculateRWT( uint8_t wt ) +{ + /* Digital 1.0 14.6.3.8 & Digital 1.1 16.6.3.9 */ + /* Digital 1.1 16.6.3.9 treat all RFU values as WT=14 */ + const uint8_t responseWaitTime = RFAL_MIN( RFAL_NFCDEP_WT_INI_MAX, wt ); + + return (uint32_t)rfalNfcDepWT2RWT(responseWaitTime); +} + + + +/*******************************************************************************/ +static ReturnCode nfcipDataTx( uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt ) +{ + return rfalTransceiveBlockingTx( txBuf, txBufLen, gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen, (RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON), ((fwt == NFCIP_NO_FWT) ? RFAL_FWT_NONE : fwt) ); +} + + +/*******************************************************************************/ +static ReturnCode nfcipDataRx( bool blocking ) +{ + ReturnCode ret; + + /* Perform Rx either blocking or non-blocking */ + if( blocking ) + { + ret = rfalTransceiveBlockingRx(); + } + else + { + ret = rfalGetTransceiveStatus(); + } + + if( ret != RFAL_ERR_BUSY ) + { + if( gNfcip.rxRcvdLen != NULL ) + { + (*gNfcip.rxRcvdLen) = rfalConvBitsToBytes( *gNfcip.rxRcvdLen ); + + if( (ret == RFAL_ERR_NONE) && (gNfcip.rxBuf != NULL) ) + { + /* Digital 1.1 16.4.1.3 - Length byte LEN SHALL have a value between 3 and 255 -> otherwise treat as Transmission Error * + * - Ensure that actual received and frame length do match, otherwise treat as Transmission error */ + if( (*gNfcip.rxRcvdLen != (uint16_t)*gNfcip.rxBuf) || (*gNfcip.rxRcvdLen < RFAL_NFCDEP_LEN_MIN) || (*gNfcip.rxRcvdLen > RFAL_NFCDEP_LEN_MAX) ) + { + return RFAL_ERR_FRAMING; + } + } + } + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepListenStartActivation( const rfalNfcDepTargetParam *param, const uint8_t *atrReq, uint16_t atrReqLength, rfalNfcDepListenActvParam rxParam ) +{ + ReturnCode ret; + rfalNfcDepConfigs cfg; + + + if( (param == NULL) || (atrReq == NULL) || (rxParam.rxLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + + /*******************************************************************************/ + /* Check whether is a valid ATR_REQ Compute NFC-DEP device */ + if( !rfalNfcDepIsAtrReq( atrReq, atrReqLength, NULL ) ) + { + return RFAL_ERR_PARAM; + } + + rxParam.nfcDepDev->activation.Initiator.ATR_REQLen = (uint8_t)atrReqLength; /* nfcipIsAtrReq() is already checking Min and Max buffer lengths */ + if( atrReqLength > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( (uint8_t*)&rxParam.nfcDepDev->activation.Initiator.ATR_REQ, atrReq, atrReqLength ); + } + + rxParam.nfcDepDev->info.GBLen = (uint8_t)(atrReqLength - RFAL_NFCDEP_ATRREQ_MIN_LEN); + rxParam.nfcDepDev->info.DID = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID; + rxParam.nfcDepDev->info.NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.2.9 Initiator SHALL NOT use NAD */ + rxParam.nfcDepDev->info.LR = rfalNfcDepPP2LR( rxParam.nfcDepDev->activation.Initiator.ATR_REQ.PPi ); + rxParam.nfcDepDev->info.FS = rfalNfcDepLR2FS( rxParam.nfcDepDev->info.LR ); + rxParam.nfcDepDev->info.WT = 0; + rxParam.nfcDepDev->info.FWT = NFCIP_NO_FWT; + rxParam.nfcDepDev->info.dFWT = NFCIP_NO_FWT; + + rfalGetBitRate( &rxParam.nfcDepDev->info.DSI, &rxParam.nfcDepDev->info.DRI ); + + + /* Store Device Info location, updated upon a PSL */ + gNfcip.nfcDepDev = rxParam.nfcDepDev; + + + /*******************************************************************************/ + cfg.did = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID; + cfg.nad = RFAL_NFCDEP_NAD_NO; + + cfg.fwt = RFAL_NFCDEP_MAX_FWT; + cfg.dFwt = RFAL_NFCDEP_WT_DELTA; + + cfg.br = param->brt; + cfg.bs = param->bst; + + cfg.lr = rfalNfcDepPP2LR(param->ppt); + + cfg.gbLen = param->GBtLen; + if( cfg.gbLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY(cfg.gb, param->GBt, cfg.gbLen); + } + + cfg.nfcidLen = RFAL_NFCDEP_NFCID3_LEN; + RFAL_MEMCPY(cfg.nfcid, param->nfcid3, RFAL_NFCDEP_NFCID3_LEN); + + cfg.to = param->to; + + cfg.role = RFAL_NFCDEP_ROLE_TARGET; + cfg.oper = param->operParam; + cfg.commMode = param->commMode; + + rfalNfcDepInitialize(); + nfcipConfig( &cfg ); + + + /*******************************************************************************/ + /* Reply with ATR RES to Initiator */ + /*******************************************************************************/ + gNfcip.rxBuf = (uint8_t*)rxParam.rxBuf; + gNfcip.rxBufLen = sizeof(rfalNfcDepBufFormat); + gNfcip.rxRcvdLen = rxParam.rxLen; + gNfcip.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; + gNfcip.isChaining = rxParam.isRxChaining; + gNfcip.txBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; + + RFAL_EXIT_ON_ERR( ret, nfcipTx( NFCIP_CMD_ATR_RES, (uint8_t*) gNfcip.rxBuf, NULL, 0, 0, NFCIP_NO_FWT ) ); + + gNfcip.state = NFCIP_ST_TARG_WAIT_ACTV; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepListenGetActivationStatus( void ) +{ + ReturnCode err; + uint8_t BRS; + + BRS = RFAL_NFCDEP_BRS_MAINTAIN; + + err = nfcipTargetHandleActivation( gNfcip.nfcDepDev, &BRS ); + + switch (err) + { + case RFAL_ERR_NONE: + + if( BRS != RFAL_NFCDEP_BRS_MAINTAIN ) + { + /* DSI codes the bit rate from Initiator to Target */ + /* DRI codes the bit rate from Target to Initiator */ + + if( gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE ) + { + RFAL_EXIT_ON_ERR( err, rfalSetMode( RFAL_MODE_LISTEN_ACTIVE_P2P, gNfcip.nfcDepDev->info.DRI, gNfcip.nfcDepDev->info.DSI )); + } + else + { + RFAL_EXIT_ON_ERR( err, rfalSetMode( ((RFAL_BR_106 == gNfcip.nfcDepDev->info.DRI) ? RFAL_MODE_LISTEN_NFCA : RFAL_MODE_LISTEN_NFCF), gNfcip.nfcDepDev->info.DRI, gNfcip.nfcDepDev->info.DSI )); + } + } + break; + + case RFAL_ERR_BUSY: + // do nothing + break; + + case RFAL_ERR_PROTO: + default: + // re-enable receiving of data + nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); + break; + } + + return err; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepStartTransceive( const rfalNfcDepTxRxParam *param ) +{ + rfalNfcDepDEPParams nfcDepParams; + + nfcDepParams.txBuf = (uint8_t *)param->txBuf; + nfcDepParams.txBufLen = param->txBufLen; + nfcDepParams.txChaining = param->isTxChaining; + nfcDepParams.txBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; /* position in txBuf where actual outgoing data is located */ + nfcDepParams.did = RFAL_NFCDEP_DID_KEEP; + nfcDepParams.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; + nfcDepParams.rxBuf = (uint8_t *)param->rxBuf; + nfcDepParams.rxBufLen = sizeof(rfalNfcDepBufFormat); + nfcDepParams.fsc = param->FSx; + nfcDepParams.fwt = param->FWT; + nfcDepParams.dFwt = param->dFWT; + + gNfcip.rxRcvdLen = param->rxLen; + gNfcip.isChaining = param->isRxChaining; + + nfcipSetDEPParams(&nfcDepParams); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepGetTransceiveStatus( void ) +{ + return nfcipRun( gNfcip.rxRcvdLen, gNfcip.isChaining ); +} + + + + + + + + + + + + + + + + /*******************************************************************************/ + static void rfalNfcDepPdu2BLockParam( rfalNfcDepPduTxRxParam pduParam, rfalNfcDepTxRxParam *blockParam, uint16_t txPos, uint16_t rxPos ) +{ + uint16_t maxInfLen; + + RFAL_NO_WARNING(rxPos); /* Keep this param for future use */ + + blockParam->DID = pduParam.DID; + blockParam->FSx = pduParam.FSx; + blockParam->FWT = pduParam.FWT; + blockParam->dFWT = pduParam.dFWT; + + /* Calculate max INF/Payload to be sent to other device */ + maxInfLen = (blockParam->FSx - (RFAL_NFCDEP_HEADER + RFAL_NFCDEP_DEP_PFB_LEN)); + maxInfLen += ((blockParam->DID != RFAL_NFCDEP_DID_NO) ? RFAL_NFCDEP_DID_LEN : 0U); + + + if( (pduParam.txBufLen - txPos) > maxInfLen ) + { + blockParam->isTxChaining = true; + blockParam->txBufLen = maxInfLen; + } + else + { + blockParam->isTxChaining = false; + blockParam->txBufLen = (pduParam.txBufLen - txPos); + } + + /* TxBuf is moved to the beginning for every Block */ + blockParam->txBuf = (rfalNfcDepBufFormat*)pduParam.txBuf; /* PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */ + blockParam->rxBuf = pduParam.tmpBuf; /* Simply using the pdu buffer is not possible because of current ACK handling */ + blockParam->isRxChaining = &gNfcip.isPDURxChaining; + blockParam->rxLen = pduParam.rxLen; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepStartPduTransceive( rfalNfcDepPduTxRxParam param ) +{ + rfalNfcDepTxRxParam txRxParam; + + /* Initialize and store APDU context */ + gNfcip.PDUParam = param; + gNfcip.PDUTxPos = 0; + gNfcip.PDURxPos = 0; + + /* Convert PDU TxRxParams to Block TxRxParams */ + rfalNfcDepPdu2BLockParam( gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos ); + + return rfalNfcDepStartTransceive( &txRxParam ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcDepGetPduTransceiveStatus( void ) +{ + ReturnCode ret; + rfalNfcDepTxRxParam txRxParam; + + ret = rfalNfcDepGetTransceiveStatus(); + switch( ret ) + { + /*******************************************************************************/ + case RFAL_ERR_NONE: + + /* Check if we are still doing chaining on Tx */ + if( gNfcip.isTxChaining ) + { + /* Add already Tx bytes */ + gNfcip.PDUTxPos += gNfcip.txBufLen; + + /* Convert APDU TxRxParams to I-Block TxRxParams */ + rfalNfcDepPdu2BLockParam( gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos ); + + if( txRxParam.txBufLen > 0U ) /* MISRA 21.18 */ + { + /* Move next Block to beginning of APDU Tx buffer */ + RFAL_MEMCPY( gNfcip.PDUParam.txBuf->pdu, &gNfcip.PDUParam.txBuf->pdu[gNfcip.PDUTxPos], txRxParam.txBufLen ); + } + + RFAL_EXIT_ON_ERR( ret, rfalNfcDepStartTransceive( &txRxParam ) ); + return RFAL_ERR_BUSY; + } + + /* PDU TxRx is done */ + /* fall through */ + + /*******************************************************************************/ + case RFAL_ERR_AGAIN: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + + /* Check if no PDU transceive has been started before (data from rfalNfcDepListenStartActivation) */ + if( gNfcip.PDUParam.rxLen == NULL ) + { + /* In Listen mode first chained packet cannot be retrieved via APDU interface */ + if( ret == RFAL_ERR_AGAIN ) + { + return RFAL_ERR_NOTSUPP; + } + + /* TxRx is complete and full data is already available */ + return RFAL_ERR_NONE; + } + + + if( (*gNfcip.PDUParam.rxLen) > 0U ) /* MISRA 21.18 */ + { + /* Ensure that data in tmpBuf still fits into PDU buffer */ + if( (uint16_t)((uint16_t)gNfcip.PDURxPos + (*gNfcip.PDUParam.rxLen)) > RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN ) + { + return RFAL_ERR_NOMEM; + } + + /* Copy chained packet from tmp buffer to PDU buffer */ + RFAL_MEMCPY( &gNfcip.PDUParam.rxBuf->pdu[gNfcip.PDURxPos], gNfcip.PDUParam.tmpBuf->inf, *gNfcip.PDUParam.rxLen ); + gNfcip.PDURxPos += *gNfcip.PDUParam.rxLen; + } + + /* Update output param rxLen */ + *gNfcip.PDUParam.rxLen = gNfcip.PDURxPos; + + /* Wait for following Block or PDU TxRx is done */ + return ((ret == RFAL_ERR_AGAIN) ? RFAL_ERR_BUSY : RFAL_ERR_NONE); + + /*******************************************************************************/ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + + return ret; + } + + +#endif /* RFAL_FEATURE_NFC_DEP */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfca.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfca.c new file mode 100644 index 0000000..e499486 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfca.c @@ -0,0 +1,1031 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfca.c + * + * \author Gustavo Patricio + * + * \brief Provides several NFC-A convenience methods and definitions + * + * It provides a Poller (ISO14443A PCD) interface and as well as + * some NFC-A Listener (ISO14443A PICC) helpers. + * + * The definitions and helpers methods provided by this module are only + * up to ISO14443-3 layer + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfca.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFCA + */ + +#if RFAL_FEATURE_NFCA + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCA_SLP_FWT rfalConvMsTo1fc(1) /*!< Check 1ms for any modulation ISO14443-3 6.4.3 */ +#define RFAL_NFCA_SLP_CMD 0x50U /*!< SLP cmd (byte1) Digital 1.1 6.9.1 & Table 20 */ +#define RFAL_NFCA_SLP_BYTE2 0x00U /*!< SLP byte2 Digital 1.1 6.9.1 & Table 20 */ +#define RFAL_NFCA_SLP_CMD_POS 0U /*!< SLP cmd position Digital 1.1 6.9.1 & Table 20 */ +#define RFAL_NFCA_SLP_BYTE2_POS 1U /*!< SLP byte2 position Digital 1.1 6.9.1 & Table 20 */ + +#define RFAL_NFCA_SDD_CT 0x88U /*!< Cascade Tag value Digital 1.1 6.7.2 */ +#define RFAL_NFCA_SDD_CT_LEN 1U /*!< Cascade Tag length */ + +#define RFAL_NFCA_SLP_REQ_LEN 2U /*!< SLP_REQ length */ + +#define RFAL_NFCA_SEL_CMD_LEN 1U /*!< SEL_CMD length */ +#define RFAL_NFCA_SEL_PAR_LEN 1U /*!< SEL_PAR length */ +#define RFAL_NFCA_SEL_SELPAR rfalNfcaSelPar(7U, 0U)/*!< SEL_PAR on Select is always with 4 data/nfcid */ +#define RFAL_NFCA_BCC_LEN 1U /*!< BCC length */ + +#define RFAL_NFCA_SDD_REQ_LEN (RFAL_NFCA_SEL_CMD_LEN + RFAL_NFCA_SEL_PAR_LEN) /*!< SDD_REQ length */ +#define RFAL_NFCA_SDD_RES_LEN (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_BCC_LEN) /*!< SDD_RES length */ + +#define RFAL_NFCA_T_RETRANS 5U /*!< t RETRANSMISSION [3, 33]ms EMVCo 2.6 A.5 */ +#define RFAL_NFCA_N_RETRANS 2U /*!< Number of retries EMVCo 2.6 9.6.1.3 */ + + +/*! SDD_REQ (Select) Cascade Levels */ +enum +{ + RFAL_NFCA_SEL_CASCADE_L1 = 0, /*!< SDD_REQ Cascade Level 1 */ + RFAL_NFCA_SEL_CASCADE_L2 = 1, /*!< SDD_REQ Cascade Level 2 */ + RFAL_NFCA_SEL_CASCADE_L3 = 2 /*!< SDD_REQ Cascade Level 3 */ +}; + +/*! SDD_REQ (Select) request Cascade Level command Digital 1.1 Table 15 */ +enum +{ + RFAL_NFCA_CMD_SEL_CL1 = 0x93, /*!< SDD_REQ command Cascade Level 1 */ + RFAL_NFCA_CMD_SEL_CL2 = 0x95, /*!< SDD_REQ command Cascade Level 2 */ + RFAL_NFCA_CMD_SEL_CL3 = 0x97, /*!< SDD_REQ command Cascade Level 3 */ +}; + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ +#define rfalNfcaSelPar( nBy, nbi ) (uint8_t)((((nBy)<<4U) & 0xF0U) | ((nbi)&0x0FU) ) /*!< Calculates SEL_PAR with the bytes/bits to be sent */ +#define rfalNfcaCLn2SELCMD( cl ) (uint8_t)((uint8_t)(RFAL_NFCA_CMD_SEL_CL1) + (2U*(cl))) /*!< Calculates SEL_CMD with the given cascade level */ +#define rfalNfcaNfcidLen2CL( len ) ((len) / 5U) /*!< Calculates cascade level by the NFCID length */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! Technology Detection context */ +typedef struct{ + rfalComplianceMode compMode; /*!< Compliancy mode to be used */ + ReturnCode ret; /*!< Outcome of presence check */ +}rfalNfcaTechDetParams; + + +/*! Colission Resolution states */ +typedef enum{ + RFAL_NFCA_CR_IDLE, /*!< IDLE state */ + RFAL_NFCA_CR_CL, /*!< New Cascading Level state */ + RFAL_NFCA_CR_SDD_TX, /*!< Perform anticollsion Tx state */ + RFAL_NFCA_CR_SDD, /*!< Perform anticollsion state */ + RFAL_NFCA_CR_SEL_TX, /*!< Perform CL Selection Tx state */ + RFAL_NFCA_CR_SEL, /*!< Perform CL Selection state */ + RFAL_NFCA_CR_DONE /*!< Collision Resolution done state */ +}rfalNfcaColResState; + + +/*! Full Colission Resolution states */ +typedef enum{ + RFAL_NFCA_CR_FULL_START, /*!< Start Full Collision Resolution state */ + RFAL_NFCA_CR_FULL_SLPCHECK, /*!< Sleep and Check for restart state */ + RFAL_NFCA_CR_FULL_RESTART /*!< Restart Full Collision Resolution state */ +}rfalNfcaFColResState; + + +/*! Colission Resolution context */ +typedef struct{ + uint8_t devLimit; /*!< Device limit to be used */ + rfalComplianceMode compMode; /*!< Compliancy mode to be used */ + rfalNfcaListenDevice* nfcaDevList; /*!< Location of the device list */ + uint8_t* devCnt; /*!< Location of the device counter */ + bool collPending; /*!< Collision pending flag */ + + bool* collPend; /*!< Location of collision pending flag (Single CR) */ + rfalNfcaSelReq selReq; /*!< SelReqused during anticollision (Single CR) */ + rfalNfcaSelRes* selRes; /*!< Location to place of the SEL_RES(SAK) (Single CR) */ + uint8_t* nfcId1; /*!< Location to place the NFCID1 (Single CR) */ + uint8_t* nfcId1Len; /*!< Location to place the NFCID1 length (Single CR) */ + uint8_t cascadeLv; /*!< Current Cascading Level (Single CR) */ + rfalNfcaColResState state; /*!< Single Collision Resolution state (Single CR) */ + rfalNfcaFColResState fState; /*!< Full Collision Resolution state (Full CR) */ + uint8_t bytesTxRx; /*!< TxRx bytes used during anticollision loop (Single CR) */ + uint8_t bitsTxRx; /*!< TxRx bits used during anticollision loop (Single CR) */ + uint16_t rxLen; /*!< Local reception length */ + uint32_t tmrFDT; /*!< FDT timer used between SED_REQs (Single CR) */ + uint8_t retries; /*!< Retries to be performed upon a timeout error (Single CR)*/ + uint8_t backtrackCnt; /*!< Backtrack retries (Single CR) */ + bool doBacktrack; /*!< Backtrack flag (Single CR) */ +}rfalNfcaColResParams; + + +/*! Colission Resolution context */ +typedef struct{ + + uint8_t cascadeLv; /*!< Current Cascading Level */ + uint8_t fCascadeLv; /*!< Final Cascading Level */ + rfalNfcaSelRes* selRes; /*!< Location to place of the SEL_RES(SAK) */ + uint16_t rxLen; /*!< Local reception length */ + const uint8_t* nfcid1; /*!< Location of the NFCID to be selected */ + uint8_t nfcidOffset; /*!< Selected NFCID offset */ + bool isRx; /*!< Selection is in reception state */ +}rfalNfcaSelParams; + + +/*! SLP_REQ (HLTA) format Digital 1.1 6.9.1 & Table 20 */ +typedef struct +{ + uint8_t frame[RFAL_NFCA_SLP_REQ_LEN]; /*!< SLP: 0x50 0x00 */ +} rfalNfcaSlpReq; + + +/*! RFAL NFC-A instance */ +typedef struct{ + rfalNfcaTechDetParams DT; /*!< Technology Detection context */ + rfalNfcaColResParams CR; /*!< Collision Resolution context */ + rfalNfcaSelParams SEL; /*!< Selection|Activation context */ + + rfalNfcaSlpReq slpReq; /*!< SLP_REx buffer */ +} rfalNfca; + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ +static rfalNfca gNfca; /*!< RFAL NFC-A instance */ + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static uint8_t rfalNfcaCalculateBcc( const uint8_t* buf, uint8_t bufLen ); +static ReturnCode rfalNfcaPollerStartSingleCollisionResolution( uint8_t devLimit, bool *collPending, rfalNfcaSelRes *selRes, uint8_t *nfcId1, uint8_t *nfcId1Len ); +static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus( void ); + +/* + ****************************************************************************** + * LOCAL FUNCTIONS + ****************************************************************************** + */ + +static uint8_t rfalNfcaCalculateBcc( const uint8_t* buf, uint8_t bufLen ) +{ + uint8_t i; + uint8_t BCC; + + BCC = 0; + + /* BCC is XOR over first 4 bytes of the SDD_RES Digital 1.1 6.7.2 */ + for(i = 0; i < bufLen; i++) + { + BCC ^= buf[i]; + } + + return BCC; +} + +/*******************************************************************************/ +static ReturnCode rfalNfcaPollerStartSingleCollisionResolution( uint8_t devLimit, bool *collPending, rfalNfcaSelRes *selRes, uint8_t *nfcId1, uint8_t *nfcId1Len ) +{ + /* Check parameters */ + if( (collPending == NULL) || (selRes == NULL) || (nfcId1 == NULL) || (nfcId1Len == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Initialize output parameters */ + *collPending = false; /* Activity 1.1 9.3.4.6 */ + *nfcId1Len = 0; + RFAL_MEMSET( nfcId1, 0x00, RFAL_NFCA_CASCADE_3_UID_LEN ); + + + /* Save parameters */ + gNfca.CR.devLimit = devLimit; + gNfca.CR.collPend = collPending; + gNfca.CR.selRes = selRes; + gNfca.CR.nfcId1 = nfcId1; + gNfca.CR.nfcId1Len = nfcId1Len; + + platformTimerDestroy( gNfca.CR.tmrFDT ); + gNfca.CR.tmrFDT = RFAL_TIMING_NONE; + gNfca.CR.retries = RFAL_NFCA_N_RETRANS; + gNfca.CR.cascadeLv = (uint8_t)RFAL_NFCA_SEL_CASCADE_L1; + gNfca.CR.state = RFAL_NFCA_CR_CL; + + gNfca.CR.doBacktrack = false; + gNfca.CR.backtrackCnt = 3U; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus( void ) +{ + ReturnCode ret; + uint8_t collBit = 1U; /* standards mandate or recommend collision bit to be set to One. */ + + + /* Check if FDT timer is still running */ + if(gNfca.CR.tmrFDT != RFAL_TIMING_NONE ) + { + if( (!platformTimerIsExpired( gNfca.CR.tmrFDT )) ) + { + return RFAL_ERR_BUSY; + } + } + + /*******************************************************************************/ + /* Go through all Cascade Levels Activity 1.1 9.3.4 */ + if( gNfca.CR.cascadeLv > (uint8_t)RFAL_NFCA_SEL_CASCADE_L3 ) + { + return RFAL_ERR_INTERNAL; + } + + switch( gNfca.CR.state ) + { + /*******************************************************************************/ + case RFAL_NFCA_CR_CL: + + /* Initialize the SDD_REQ to send for the new cascade level */ + RFAL_MEMSET( (uint8_t*)&gNfca.CR.selReq, 0x00, sizeof(rfalNfcaSelReq) ); + + gNfca.CR.bytesTxRx = RFAL_NFCA_SDD_REQ_LEN; + gNfca.CR.bitsTxRx = 0U; + gNfca.CR.state = RFAL_NFCA_CR_SDD_TX; + + /* fall through */ + + /*******************************************************************************/ + case RFAL_NFCA_CR_SDD_TX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* Calculate SEL_CMD and SEL_PAR with the bytes/bits to be sent */ + gNfca.CR.selReq.selCmd = rfalNfcaCLn2SELCMD( gNfca.CR.cascadeLv ); + gNfca.CR.selReq.selPar = rfalNfcaSelPar(gNfca.CR.bytesTxRx, gNfca.CR.bitsTxRx); + + /* Send SDD_REQ (Anticollision frame) */ + rfalISO14443AStartTransceiveAnticollisionFrame( (uint8_t*)&gNfca.CR.selReq, &gNfca.CR.bytesTxRx, &gNfca.CR.bitsTxRx, &gNfca.CR.rxLen, RFAL_NFCA_FDTMIN ); + + gNfca.CR.state = RFAL_NFCA_CR_SDD; + break; + + + /*******************************************************************************/ + case RFAL_NFCA_CR_SDD: + + RFAL_EXIT_ON_BUSY( ret, rfalISO14443AGetTransceiveAnticollisionFrameStatus() ); + + /* Retry upon timeout EMVCo 2.6 9.6.1.3 */ + if( (ret == RFAL_ERR_TIMEOUT) && (gNfca.CR.devLimit==0U) && (gNfca.CR.retries != 0U) ) + { + gNfca.CR.retries--; + platformTimerDestroy( gNfca.CR.tmrFDT ); + gNfca.CR.tmrFDT = platformTimerCreate( RFAL_NFCA_T_RETRANS ); + + gNfca.CR.state = RFAL_NFCA_CR_SDD_TX; + break; + } + + /* Covert rxLen into bytes */ + gNfca.CR.rxLen = rfalConvBitsToBytes( gNfca.CR.rxLen ); + + + if( (ret == RFAL_ERR_TIMEOUT) && (gNfca.CR.backtrackCnt != 0U) && (!gNfca.CR.doBacktrack) + && (!((RFAL_NFCA_SDD_REQ_LEN == gNfca.CR.bytesTxRx) && (0U == gNfca.CR.bitsTxRx))) ) + { + /* In multiple card scenarios it may always happen that some + * collisions of a weaker tag go unnoticed. If then a later + * collision is recognized and the strong tag has a 0 at the + * collision position then no tag will respond. Catch this + * corner case and then try with the bit being sent as zero. */ + rfalNfcaSensRes sensRes; + ret = RFAL_ERR_RF_COLLISION; + rfalNfcaPollerCheckPresence( RFAL_14443A_SHORTFRAME_CMD_REQA, &sensRes ); + /* Algorithm below does a post-increment, decrement to go back to current position */ + if (0U == gNfca.CR.bitsTxRx) + { + gNfca.CR.bitsTxRx = 7; + gNfca.CR.bytesTxRx--; + } + else + { + gNfca.CR.bitsTxRx--; + } + collBit = (uint8_t)( ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx) ); + collBit = (uint8_t)((0U==collBit)?1U:0U); // invert the collision bit + gNfca.CR.doBacktrack = true; + gNfca.CR.backtrackCnt--; + } + else + { + gNfca.CR.doBacktrack = false; + } + + if( ret == RFAL_ERR_RF_COLLISION ) + { + /* Check received length */ + if( (gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) > (RFAL_NFCA_SDD_RES_LEN + RFAL_NFCA_SDD_REQ_LEN) ) + { + return RFAL_ERR_PROTO; + } + + if( ((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) > (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN)) && (gNfca.CR.backtrackCnt != 0U) ) + { /* Collision in BCC: Anticollide only UID part */ + gNfca.CR.backtrackCnt--; + gNfca.CR.bytesTxRx = (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN) - 1U; + gNfca.CR.bitsTxRx = 7; + collBit = (uint8_t)( ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx) ); /* Not a real collision, extract the actual bit for the subsequent code */ + } + + if( (gNfca.CR.devLimit == 0U) && (!(*gNfca.CR.collPend)) ) + { + /* Activity 1.0 & 1.1 9.3.4.12: If CON_DEVICES_LIMIT has a value of 0, then + * NFC Forum Device is configured to perform collision detection only */ + *gNfca.CR.collPend = true; + return RFAL_ERR_IGNORE; + } + + *gNfca.CR.collPend = true; + + /* Set and select the collision bit, with the number of bytes/bits successfully TxRx */ + if (collBit != 0U) + { + ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] = (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] | (1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */ + } + else + { + ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] = (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & ~(1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */ + } + + gNfca.CR.bitsTxRx++; + + /* Check if number of bits form a byte */ + if( gNfca.CR.bitsTxRx == RFAL_BITS_IN_BYTE ) + { + gNfca.CR.bitsTxRx = 0; + gNfca.CR.bytesTxRx++; + } + + gNfca.CR.state = RFAL_NFCA_CR_SDD_TX; + break; + } + + /*******************************************************************************/ + /* Check if Collision loop has failed */ + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + + /* If collisions are to be reported check whether the response is complete */ + if( (gNfca.CR.devLimit == 0U) && (gNfca.CR.rxLen != sizeof(rfalNfcaSddRes)) ) + { + return RFAL_ERR_PROTO; + } + + /* Check if the received BCC match */ + if( gNfca.CR.selReq.bcc != rfalNfcaCalculateBcc( gNfca.CR.selReq.nfcid1, RFAL_NFCA_CASCADE_1_UID_LEN ) ) + { + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Anticollision OK, Select this Cascade Level */ + gNfca.CR.selReq.selPar = RFAL_NFCA_SEL_SELPAR; + + gNfca.CR.retries = RFAL_NFCA_N_RETRANS; + gNfca.CR.state = RFAL_NFCA_CR_SEL_TX; + break; + + /*******************************************************************************/ + case RFAL_NFCA_CR_SEL_TX: + + /* Send SEL_REQ (Select command) - Retry upon timeout EMVCo 2.6 9.6.1.3 */ + rfalTransceiveBlockingTx( (uint8_t*)&gNfca.CR.selReq, sizeof(rfalNfcaSelReq), (uint8_t*)gNfca.CR.selRes, sizeof(rfalNfcaSelRes), &gNfca.CR.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCA_FDTMIN ); + gNfca.CR.state = RFAL_NFCA_CR_SEL; + break; + + /*******************************************************************************/ + case RFAL_NFCA_CR_SEL: + + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + /* Retry upon timeout EMVCo 2.6 9.6.1.3 */ + if( (ret == RFAL_ERR_TIMEOUT) && (gNfca.CR.devLimit==0U) && (gNfca.CR.retries != 0U) ) + { + gNfca.CR.retries--; + platformTimerDestroy( gNfca.CR.tmrFDT ); + gNfca.CR.tmrFDT = platformTimerCreate( RFAL_NFCA_T_RETRANS ); + + gNfca.CR.state = RFAL_NFCA_CR_SEL_TX; + break; + } + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + gNfca.CR.rxLen = rfalConvBitsToBytes( gNfca.CR.rxLen ); + + /* Ensure proper response length */ + if( gNfca.CR.rxLen != sizeof(rfalNfcaSelRes) ) + { + return RFAL_ERR_PROTO; + } + + /*******************************************************************************/ + /* Check cascade byte, if cascade tag then go next cascade level */ + if( *gNfca.CR.selReq.nfcid1 == RFAL_NFCA_SDD_CT ) + { + /* Cascade Tag present, store nfcid1 bytes (excluding cascade tag) and continue for next CL */ + RFAL_MEMCPY( &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len], &((uint8_t*)&gNfca.CR.selReq.nfcid1)[RFAL_NFCA_SDD_CT_LEN], (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN) ); + *gNfca.CR.nfcId1Len += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN); + + /* Go to next cascade level */ + gNfca.CR.state = RFAL_NFCA_CR_CL; + gNfca.CR.cascadeLv++; + } + else + { + /* UID Selection complete, Stop Cascade Level loop */ + RFAL_MEMCPY( &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len], (uint8_t*)&gNfca.CR.selReq.nfcid1, RFAL_NFCA_CASCADE_1_UID_LEN ); + *gNfca.CR.nfcId1Len += RFAL_NFCA_CASCADE_1_UID_LEN; + + gNfca.CR.state = RFAL_NFCA_CR_DONE; + break; /* Only flag operation complete on the next execution */ + } + break; + + /*******************************************************************************/ + case RFAL_NFCA_CR_DONE: + return RFAL_ERR_NONE; + + /*******************************************************************************/ + default: + return RFAL_ERR_WRONG_STATE; + } + return RFAL_ERR_BUSY; +} + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerInitialize( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalSetMode( RFAL_MODE_POLL_NFCA, RFAL_BR_106, RFAL_BR_106 ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + + rfalSetGT( RFAL_GT_NFCA ); + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCA_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_NFCA_POLLER ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerCheckPresence( rfal14443AShortFrameCmd cmd, rfalNfcaSensRes *sensRes ) +{ + ReturnCode ret; + uint16_t rcvLen; + + /* Digital 1.1 6.10.1.3 For Commands ALL_REQ, SENS_REQ, SDD_REQ, and SEL_REQ, the NFC Forum Device * + * MUST treat receipt of a Listen Frame at a time after FDT(Listen, min) as a Timeour Error */ + + ret = rfalISO14443ATransceiveShortFrame( cmd, (uint8_t*)sensRes, (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)), &rcvLen, RFAL_NFCA_FDTMIN ); + if( (ret == RFAL_ERR_RF_COLLISION) || (ret == RFAL_ERR_CRC) || (ret == RFAL_ERR_NOMEM) || (ret == RFAL_ERR_FRAMING) || (ret == RFAL_ERR_PAR) || (ret == RFAL_ERR_INCOMPLETE_BYTE) ) + { + ret = RFAL_ERR_NONE; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerTechnologyDetection( rfalComplianceMode compMode, rfalNfcaSensRes *sensRes ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartTechnologyDetection( compMode, sensRes ) ); + rfalRunBlocking( ret, rfalNfcaPollerGetTechnologyDetectionStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerStartTechnologyDetection( rfalComplianceMode compMode, rfalNfcaSensRes *sensRes ) +{ + ReturnCode ret; + + gNfca.DT.compMode = compMode; + gNfca.DT.ret = rfalNfcaPollerCheckPresence( ((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_14443A_SHORTFRAME_CMD_WUPA : RFAL_14443A_SHORTFRAME_CMD_REQA), sensRes ); + + /* Send SLP_REQ as Activity 1.1 9.2.3.6 and EMVCo 2.6 9.2.1.3 */ + if( (gNfca.DT.compMode != RFAL_COMPLIANCE_MODE_ISO) && (gNfca.DT.ret == RFAL_ERR_NONE) ) + { + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSleep() ); + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerGetTechnologyDetectionStatus( void ) +{ + ReturnCode ret; + + /* If Sleep was sent, wait until its termination */ + if( (gNfca.DT.compMode != RFAL_COMPLIANCE_MODE_ISO) && (gNfca.DT.ret == RFAL_ERR_NONE) ) + { + RFAL_EXIT_ON_BUSY( ret, rfalNfcaPollerGetSleepStatus() ); + } + + return gNfca.DT.ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerSingleCollisionResolution( uint8_t devLimit, bool *collPending, rfalNfcaSelRes *selRes, uint8_t *nfcId1, uint8_t *nfcId1Len ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSingleCollisionResolution( devLimit, collPending, selRes, nfcId1, nfcId1Len ) ); + rfalRunBlocking( ret, rfalNfcaPollerGetSingleCollisionResolutionStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerStartFullCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ) +{ + ReturnCode ret; + rfalNfcaSensRes sensRes; + uint16_t rcvLen; + + if( (nfcaDevList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *devCnt = 0; + ret = RFAL_ERR_NONE; + + /*******************************************************************************/ + /* Send ALL_REQ before Anticollision if a Sleep was sent before Activity 1.1 9.3.4.1 and EMVco 2.6 9.3.2.1 */ + if( compMode != RFAL_COMPLIANCE_MODE_ISO ) + { + ret = rfalISO14443ATransceiveShortFrame( RFAL_14443A_SHORTFRAME_CMD_WUPA, (uint8_t*)&nfcaDevList->sensRes, (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)), &rcvLen, RFAL_NFCA_FDTMIN ); + if(ret != RFAL_ERR_NONE) + { + if( (compMode == RFAL_COMPLIANCE_MODE_EMV) || ((ret != RFAL_ERR_RF_COLLISION) && (ret != RFAL_ERR_CRC) && (ret != RFAL_ERR_FRAMING) && (ret != RFAL_ERR_PAR) && (ret != RFAL_ERR_INCOMPLETE_BYTE)) ) + { + return ret; + } + } + + /* Check proper SENS_RES/ATQA size */ + if( (ret == RFAL_ERR_NONE) && (rfalConvBytesToBits(sizeof(rfalNfcaSensRes)) != rcvLen) ) + { + return RFAL_ERR_PROTO; + } + } + + /*******************************************************************************/ + /* Store the SENS_RES from Technology Detection or from WUPA */ + sensRes = nfcaDevList->sensRes; + + if( devLimit > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMSET( nfcaDevList, 0x00, (sizeof(rfalNfcaListenDevice) * devLimit) ); + } + + /* Restore the prev SENS_RES, assuming that the SENS_RES received is from first device + * When only one device is detected it's not woken up then we'll have no SENS_RES (ATQA) */ + nfcaDevList->sensRes = sensRes; + + /* Save parameters */ + gNfca.CR.devCnt = devCnt; + gNfca.CR.devLimit = devLimit; + gNfca.CR.nfcaDevList = nfcaDevList; + gNfca.CR.compMode = compMode; + gNfca.CR.fState = RFAL_NFCA_CR_FULL_START; + + + #if RFAL_FEATURE_T1T + /*******************************************************************************/ + /* Only check for T1T if previous SENS_RES was received without a transmission * + * error. When collisions occur bits in the SENS_RES may look like a T1T */ + /* If T1T Anticollision is not supported Activity 1.1 9.3.4.3 */ + if( rfalNfcaIsSensResT1T( &nfcaDevList->sensRes ) && (devLimit != 0U) && (ret == RFAL_ERR_NONE) && (compMode != RFAL_COMPLIANCE_MODE_EMV) ) + { + /* RID_REQ shall be performed Activity 1.1 9.3.4.24 */ + rfalT1TPollerInitialize(); + RFAL_EXIT_ON_ERR( ret, rfalT1TPollerRid( &nfcaDevList->ridRes ) ); + + *devCnt = 1U; + nfcaDevList->isSleep = false; + nfcaDevList->type = RFAL_NFCA_T1T; + nfcaDevList->nfcId1Len = RFAL_NFCA_CASCADE_1_UID_LEN; + RFAL_MEMCPY( &nfcaDevList->nfcId1, &nfcaDevList->ridRes.uid, RFAL_NFCA_CASCADE_1_UID_LEN ); + + return RFAL_ERR_NONE; + } + #endif /* RFAL_FEATURE_T1T */ + + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSingleCollisionResolution( devLimit, &gNfca.CR.collPending, &nfcaDevList->selRes, (uint8_t*)&nfcaDevList->nfcId1, &nfcaDevList->nfcId1Len ) ); + + gNfca.CR.fState = RFAL_NFCA_CR_FULL_START; + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus( void ) +{ + ReturnCode ret; + uint8_t newDevType; + + if( (gNfca.CR.nfcaDevList == NULL) || (gNfca.CR.devCnt == NULL) ) + { + return RFAL_ERR_WRONG_STATE; + } + + + switch( gNfca.CR.fState ) + { + /*******************************************************************************/ + case RFAL_NFCA_CR_FULL_START: + + /*******************************************************************************/ + /* Check whether a T1T has already been detected */ + if( rfalNfcaIsSensResT1T( &gNfca.CR.nfcaDevList->sensRes ) && (gNfca.CR.nfcaDevList->type == RFAL_NFCA_T1T) ) + { + /* T1T doesn't support Anticollision */ + return RFAL_ERR_NONE; + } + + /* fall through */ + + /*******************************************************************************/ + case RFAL_NFCA_CR_FULL_RESTART: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /*******************************************************************************/ + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerGetSingleCollisionResolutionStatus() ); + + /* Assign Listen Device */ + newDevType = ((uint8_t)gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes.sak) & RFAL_NFCA_SEL_RES_CONF_MASK; /* MISRA 10.8 */ + /* PRQA S 4342 1 # MISRA 10.5 - Guaranteed that no invalid enum values are created: see guard_eq_RFAL_NFCA_T2T, .... */ + gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].type = (rfalNfcaListenDeviceType) newDevType; + gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].isSleep = false; + (*gNfca.CR.devCnt)++; + + + /* If a collision was detected and device counter is lower than limit Activity 1.1 9.3.4.21 */ + if( (*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending) ) + { + /* Put this device to Sleep Activity 1.1 9.3.4.22 */ + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSleep() ); + gNfca.CR.nfcaDevList[(*gNfca.CR.devCnt - 1U)].isSleep = true; + + gNfca.CR.fState = RFAL_NFCA_CR_FULL_SLPCHECK; + return RFAL_ERR_BUSY; + } + else + { + /* Exit loop */ + gNfca.CR.collPending = false; + } + break; + + + /*******************************************************************************/ + case RFAL_NFCA_CR_FULL_SLPCHECK: + + RFAL_EXIT_ON_BUSY( ret, rfalNfcaPollerGetSleepStatus() ); + + /* Send a new SENS_REQ to check for other cards Activity 1.1 9.3.4.23 */ + ret = rfalNfcaPollerCheckPresence( RFAL_14443A_SHORTFRAME_CMD_REQA, &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].sensRes ); + if( ret == RFAL_ERR_TIMEOUT ) + { + /* No more devices found, exit */ + gNfca.CR.collPending = false; + } + else + { + /* Another device found, restart|continue loop */ + gNfca.CR.collPending = true; + + /*******************************************************************************/ + /* Check if collision resolution shall continue */ + if( (*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending) ) + { + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSingleCollisionResolution( gNfca.CR.devLimit, + &gNfca.CR.collPending, + &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes, + (uint8_t*)&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1, + &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1Len ) ); + + gNfca.CR.fState = RFAL_NFCA_CR_FULL_RESTART; + return RFAL_ERR_BUSY; + } + } + break; + + /*******************************************************************************/ + default: + return RFAL_ERR_WRONG_STATE; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerFullCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartFullCollisionResolution( compMode, devLimit, nfcaDevList, devCnt ) ); + rfalRunBlocking( ret, rfalNfcaPollerGetFullCollisionResolutionStatus() ); + + return ret; +} + +ReturnCode rfalNfcaPollerSleepFullCollisionResolution( uint8_t devLimit, rfalNfcaListenDevice *nfcaDevList, uint8_t *devCnt ) +{ + bool firstRound; + uint8_t tmpDevCnt; + ReturnCode ret; + + + if( (nfcaDevList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Only use ALL_REQ (WUPA) on the first round */ + firstRound = true; + *devCnt = 0; + + + /* Perform collision resolution until no new device is found */ + do + { + tmpDevCnt = 0; + ret = rfalNfcaPollerFullCollisionResolution( (firstRound ? RFAL_COMPLIANCE_MODE_NFC : RFAL_COMPLIANCE_MODE_ISO), (devLimit - *devCnt), &nfcaDevList[*devCnt], &tmpDevCnt ); + + if( (ret == RFAL_ERR_NONE) && (tmpDevCnt > 0U) ) + { + *devCnt += tmpDevCnt; + + /* Check whether to seacrh for more devices */ + if( *devCnt < devLimit ) + { + /* Set last found device to sleep (all others are slept already) */ + rfalNfcaPollerSleep(); + nfcaDevList[((*devCnt)-1U)].isSleep = true; + + /* Check if any other device is present */ + ret = rfalNfcaPollerCheckPresence( RFAL_14443A_SHORTFRAME_CMD_REQA, &nfcaDevList[*devCnt].sensRes ); + if( ret == RFAL_ERR_NONE ) + { + firstRound = false; + continue; + } + } + } + break; + } + while( true ); + + return ((*devCnt > 0U) ? RFAL_ERR_NONE : ret); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerSelect( const uint8_t *nfcid1, uint8_t nfcidLen, rfalNfcaSelRes *selRes ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSelect( nfcid1, nfcidLen, selRes ) ); + rfalRunBlocking( ret, rfalNfcaPollerGetSelectStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerStartSelect( const uint8_t *nfcid1, uint8_t nfcidLen, rfalNfcaSelRes *selRes ) +{ + if( (nfcid1 == NULL) || (nfcidLen > RFAL_NFCA_CASCADE_3_UID_LEN) || (selRes == NULL) ) + { + return RFAL_ERR_PARAM; + } + + + /* Calculate Cascate Level */ + gNfca.SEL.fCascadeLv = rfalNfcaNfcidLen2CL( nfcidLen ); + gNfca.SEL.cascadeLv = RFAL_NFCA_SEL_CASCADE_L1; + + gNfca.SEL.nfcidOffset = 0; + gNfca.SEL.isRx = false; + gNfca.SEL.selRes = selRes; + gNfca.SEL.nfcid1 = nfcid1; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerGetSelectStatus( void ) +{ + ReturnCode ret; + rfalNfcaSelReq selReq; + + if( (!gNfca.SEL.isRx) ) + { + /*******************************************************************************/ + /* Go through all Cascade Levels Activity 1.1 9.4.4 */ + if( gNfca.SEL.cascadeLv <= gNfca.SEL.fCascadeLv ) + { + /* Assign SEL_CMD according to the CLn and SEL_PAR*/ + selReq.selCmd = rfalNfcaCLn2SELCMD(gNfca.SEL.cascadeLv); + selReq.selPar = RFAL_NFCA_SEL_SELPAR; + + /* Compute NFCID/Data on the SEL_REQ command Digital 1.1 Table 18 */ + if( gNfca.SEL.fCascadeLv != gNfca.SEL.cascadeLv ) + { + *selReq.nfcid1 = RFAL_NFCA_SDD_CT; + RFAL_MEMCPY( &selReq.nfcid1[RFAL_NFCA_SDD_CT_LEN], &gNfca.SEL.nfcid1[gNfca.SEL.nfcidOffset], (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN) ); + gNfca.SEL.nfcidOffset += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN); + } + else + { + RFAL_MEMCPY( selReq.nfcid1, &gNfca.SEL.nfcid1[gNfca.SEL.nfcidOffset], RFAL_NFCA_CASCADE_1_UID_LEN ); + } + + /* Calculate nfcid's BCC */ + selReq.bcc = rfalNfcaCalculateBcc( (uint8_t*)&selReq.nfcid1, sizeof(selReq.nfcid1) ); + + /*******************************************************************************/ + /* Send SEL_REQ */ + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTx( (uint8_t*)&selReq, sizeof(rfalNfcaSelReq), (uint8_t*)gNfca.SEL.selRes, sizeof(rfalNfcaSelRes), &gNfca.SEL.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCA_FDTMIN ) ); + + /* Wait for Rx to conclude */ + gNfca.SEL.isRx = true; + + return RFAL_ERR_BUSY; + } + } + else + { + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + /* Ensure proper response length */ + if( rfalConvBitsToBytes( gNfca.SEL.rxLen ) != sizeof(rfalNfcaSelRes) ) + { + return RFAL_ERR_PROTO; + } + + /* Check if there are more level(s) to be selected */ + if( gNfca.SEL.cascadeLv < gNfca.SEL.fCascadeLv ) + { + /* Advance to the next cascade lavel */ + gNfca.SEL.cascadeLv++; + gNfca.SEL.isRx = false; + + return RFAL_ERR_BUSY; + } + } + + /* REMARK: Could check if NFCID1 is complete */ + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerSleep( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcaPollerStartSleep() ); + rfalRunBlocking( ret, rfalNfcaPollerGetSleepStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerStartSleep( void ) +{ + rfalTransceiveContext ctx; + + gNfca.slpReq.frame[RFAL_NFCA_SLP_CMD_POS] = RFAL_NFCA_SLP_CMD; + gNfca.slpReq.frame[RFAL_NFCA_SLP_BYTE2_POS] = RFAL_NFCA_SLP_BYTE2; + + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)&gNfca.slpReq, sizeof(rfalNfcaSlpReq), (uint8_t*)&gNfca.slpReq, sizeof(gNfca.slpReq), NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCA_SLP_FWT ); + return rfalStartTransceive( &ctx ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcaPollerGetSleepStatus( void ) +{ + ReturnCode ret; + + /* ISO14443-3 6.4.3 HLTA - If PICC responds with any modulation during 1 ms this response shall be interpreted as not acknowledge + Digital 2.0 6.9.2.1 & EMVCo 3.0 5.6.2.1 - consider the HLTA command always acknowledged + No check to be compliant with NFC and EMVCo, and to improve interoprability (Kovio RFID Tag) + */ + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +bool rfalNfcaListenerIsSleepReq( const uint8_t *buf, uint16_t bufLen ) +{ + /* Check if length and payload match */ + if( (bufLen != sizeof(rfalNfcaSlpReq)) || (buf[RFAL_NFCA_SLP_CMD_POS] != RFAL_NFCA_SLP_CMD) || (buf[RFAL_NFCA_SLP_BYTE2_POS] != RFAL_NFCA_SLP_BYTE2) ) + { + return false; + } + + return true; +} + +/* If the guards here don't compile then the code above cannot work anymore. */ +extern uint8_t guard_eq_RFAL_NFCA_T2T[((RFAL_NFCA_SEL_RES_CONF_MASK&(uint8_t)RFAL_NFCA_T2T) == (uint8_t)RFAL_NFCA_T2T)?1:(-1)]; +extern uint8_t guard_eq_RFAL_NFCA_T4T[((RFAL_NFCA_SEL_RES_CONF_MASK&(uint8_t)RFAL_NFCA_T4T) == (uint8_t)RFAL_NFCA_T4T)?1:(-1)]; +extern uint8_t guard_eq_RFAL_NFCA_NFCDEP[((RFAL_NFCA_SEL_RES_CONF_MASK&(uint8_t)RFAL_NFCA_NFCDEP) == (uint8_t)RFAL_NFCA_NFCDEP)?1:(-1)]; +extern uint8_t guard_eq_RFAL_NFCA_T4T_NFCDEP[((RFAL_NFCA_SEL_RES_CONF_MASK&(uint8_t)RFAL_NFCA_T4T_NFCDEP) == (uint8_t)RFAL_NFCA_T4T_NFCDEP)?1:(-1)]; +#endif /* RFAL_FEATURE_NFCA */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcb.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcb.c new file mode 100644 index 0000000..2593733 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcb.c @@ -0,0 +1,727 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcb.c + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-B (ISO14443B) helpers + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfcb.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFCB + */ + +#if RFAL_FEATURE_NFCB + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED 0x10U /*!< Bit mask for Extended SensB Response support in SENSB_REQ */ +#define RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU 0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES */ +#define RFAL_NFCB_SLOT_MARKER_SC_SHIFT 4U /*!< Slot Code position on SLOT_MARKER APn */ + +#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN 1U /*!< SLOT_MARKER Slot Code minimum Digital 1.1 Table 37 */ +#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX 16U /*!< SLOT_MARKER Slot Code maximum Digital 1.1 Table 37 */ + +#define RFAL_NFCB_ACTIVATION_FWT (RFAL_NFCB_FWTSENSB + RFAL_NFCB_DTPOLL_20) /*!< FWT(SENSB) + dTbPoll Digital 2.0 7.9.1.3 */ + +/*! Advanced and Extended bit mask in Parameter of SENSB_REQ */ +#define RFAL_NFCB_SENSB_REQ_PARAM (RFAL_NFCB_SENSB_REQ_ADV_FEATURE | RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED) + + +/*! NFC-B commands definition */ +enum +{ + RFAL_NFCB_CMD_SENSB_REQ = 0x05, /*!< SENSB_REQ (REQB) & SLOT_MARKER Digital 1.1 Table 24*/ + RFAL_NFCB_CMD_SENSB_RES = 0x50, /*!< SENSB_RES (ATQB) & SLOT_MARKER Digital 1.1 Table 27*/ + RFAL_NFCB_CMD_SLPB_REQ = 0x50, /*!< SLPB_REQ (HLTB command) Digital 1.1 Table 38 */ + RFAL_NFCB_CMD_SLPB_RES = 0x00 /*!< SLPB_RES (HLTB Answer) Digital 1.1 Table 39 */ +}; + + +/*! NFC-B Technology Detection context */ +typedef struct{ + rfalNfcbSensbRes *sensbRes; /*!< Location of SENSB_RES */ + uint8_t *sensbResLen; /*!< Location of SENSB_RES length */ + uint16_t rxLen; /*!< Reception length (16bits) */ +}rfalNfcbTechDetParams; + + +/*! NFC-B Collision Resolution states */ +typedef enum{ + RFAL_NFCB_CR_SLOTS_TX, /*!< State where slots are open and slot markers issued */ + RFAL_NFCB_CR_SLOTS, /*!< State where slots are open and slot markers issued */ + RFAL_NFCB_CR_SLEEP, /*!< State between slotted loop */ + RFAL_NFCB_CR_END /*!< State for terminating the collision resolution */ +}rfalNfcbColResState; + + +/*! NFC-B Collision Resolution context */ +typedef struct{ + rfalComplianceMode compMode; /*!< Compliancy mode to be used */ + uint8_t devLimit; /*!< Device limit to be used */ + rfalNfcbListenDevice *nfcbDevList; /*!< Location of the device list */ + uint8_t *devCnt; /*!< Location of the device counter */ + bool *colPending; /*!< Location of the Collision pending flag */ + + uint8_t curSlots; /*!< Current number of slots */ + uint8_t curSlotNum; /*!< Current Slot number (whithin slotted loop) */ + uint8_t endSlots; /*!< Maximum number of slots allowed */ + uint8_t curDevCnt; /*!< Current device counter (per slotted loop) */ + bool colPend; /*!< Internal Collision pending flag */ + uint32_t tmr; /*!< Collision Resolution timer */ + rfalNfcbColResState state; /*!< Collision Resolution state */ +}rfalNfcbColResParams; + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +#define rfalNfcbNI2NumberOfSlots( ni ) (uint8_t)(1U << (ni)) /*!< Converts the Number of slots Identifier to slot number */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! ALLB_REQ (WUPB) and SENSB_REQ (REQB) Command Format Digital 1.1 7.6.1 */ +typedef struct +{ + uint8_t cmd; /*!< xxxxB_REQ: 05h */ + uint8_t AFI; /*!< NFC Identifier */ + uint8_t PARAM; /*!< Application Data */ +} rfalNfcbSensbReq; + +/*! SLOT_MARKER Command format Digital 1.1 7.7.1 */ +typedef struct +{ + uint8_t APn; /*!< Slot number 2..16 | 0101b */ +} rfalNfcbSlotMarker; + +/*! SLPB_REQ (HLTB) Command Format Digital 1.1 7.8.1 */ +typedef struct +{ + uint8_t cmd; /*!< SLPB_REQ: 50h */ + uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/ +} rfalNfcbSlpbReq; + + +/*! SLPB_RES (HLTB) Response Format Digital 1.1 7.8.2 */ +typedef struct +{ + uint8_t cmd; /*!< SLPB_RES: 00h */ +} rfalNfcbSlpbRes; + + +/*! RFAL NFC-B instance */ +typedef struct +{ + uint8_t AFI; /*!< AFI to be used */ + uint8_t PARAM; /*!< PARAM to be used */ + rfalNfcbColResParams CR; /*!< Collision Resolution */ + rfalNfcbTechDetParams DT; +} rfalNfcb; + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode rfalNfcbCheckSensbRes( const rfalNfcbSensbRes *sensbRes, uint8_t sensbResLen ); +static ReturnCode rfalNfcbPollerSleepTx( const uint8_t* nfcid0 ); + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +static rfalNfcb gRfalNfcb; /*!< RFAL NFC-B Instance */ + + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +static ReturnCode rfalNfcbCheckSensbRes( const rfalNfcbSensbRes *sensbRes, uint8_t sensbResLen ) +{ + /* Check response length */ + if( ( (sensbResLen != RFAL_NFCB_SENSB_RES_LEN) && (sensbResLen != RFAL_NFCB_SENSB_RES_EXT_LEN) ) ) + { + return RFAL_ERR_PROTO; + } + + /* Check SENSB_RES and Protocol Type Digital 1.1 7.6.2.19 */ + if( ((sensbRes->protInfo.FsciProType & RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU) != 0U) || (sensbRes->cmd != (uint8_t)RFAL_NFCB_CMD_SENSB_RES) ) + { + return RFAL_ERR_PROTO; + } + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +/* This function is used internally during Collision Resolution. Its * + * purpose is to block the state machine for minimmal time. * + * Activity 2.1 does not enforce response checking or error handling. */ +static ReturnCode rfalNfcbPollerSleepTx( const uint8_t* nfcid0 ) +{ + ReturnCode ret; + rfalNfcbSlpbReq slpbReq; + + if( nfcid0 == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Compute SLPB_REQ */ + slpbReq.cmd = RFAL_NFCB_CMD_SLPB_REQ; + RFAL_MEMCPY( slpbReq.nfcid0, nfcid0, RFAL_NFCB_NFCID0_LEN ); + + /* Send SLPB_REQ and ignore its response and FWT*/ + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTx( (uint8_t*)&slpbReq, sizeof(rfalNfcbSlpbReq), NULL, 0, NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_NFCB_POLLER )); + + return RFAL_ERR_NONE; +} + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerInitialize( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalSetMode( RFAL_MODE_POLL_NFCB, RFAL_BR_106, RFAL_BR_106 ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + + rfalSetGT( RFAL_GT_NFCB ); + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCB_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_NFCB_POLLER ); + + gRfalNfcb.AFI = RFAL_NFCB_AFI; + gRfalNfcb.PARAM = RFAL_NFCB_PARAM; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerInitializeWithParams( uint8_t AFI, uint8_t PARAM ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcbPollerInitialize() ); + + gRfalNfcb.AFI = AFI; + gRfalNfcb.PARAM = (PARAM & RFAL_NFCB_SENSB_REQ_PARAM); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerCheckPresence( rfalNfcbSensCmd cmd, rfalNfcbSlots slots, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcbPollerStartCheckPresence( cmd, slots, sensbRes, sensbResLen ) ); + rfalRunBlocking( ret, rfalNfcbPollerGetCheckPresenceStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerStartCheckPresence( rfalNfcbSensCmd cmd, rfalNfcbSlots slots, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + rfalNfcbSensbReq sensbReq; + + + /* Check if the command requested and given the slot number are valid */ + if( ((RFAL_NFCB_SENS_CMD_SENSB_REQ != cmd) && (RFAL_NFCB_SENS_CMD_ALLB_REQ != cmd)) || + (slots > RFAL_NFCB_SLOT_NUM_16) || (sensbRes == NULL) || (sensbResLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *sensbResLen = 0; + RFAL_MEMSET(sensbRes, 0x00, sizeof(rfalNfcbSensbRes) ); + + /* Compute SENSB_REQ */ + sensbReq.cmd = RFAL_NFCB_CMD_SENSB_REQ; + sensbReq.AFI = gRfalNfcb.AFI; + sensbReq.PARAM = (((uint8_t)gRfalNfcb.PARAM & RFAL_NFCB_SENSB_REQ_PARAM) | (uint8_t)cmd | (uint8_t)slots); + + gRfalNfcb.DT.sensbRes = sensbRes; + gRfalNfcb.DT.sensbResLen = sensbResLen; + + /* Send SENSB_REQ */ + return rfalTransceiveBlockingTx( (uint8_t*)&sensbReq, sizeof(rfalNfcbSensbReq), (uint8_t*)sensbRes, sizeof(rfalNfcbSensbRes), &gRfalNfcb.DT.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCB_FWTSENSB ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerGetCheckPresenceStatus( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + /* Covert bits to bytes (u8) */ + (*gRfalNfcb.DT.sensbResLen) = (uint8_t)rfalConvBitsToBytes(gRfalNfcb.DT.rxLen); + + /* Check if a transmission error was detected */ + if( (ret == RFAL_ERR_CRC) || (ret == RFAL_ERR_FRAMING) ) + { + /* Invalidate received frame as an error was detected (CollisionResolution checks if valid) */ + (*gRfalNfcb.DT.sensbResLen) = 0; + return RFAL_ERR_NONE; + } + + if( ret == RFAL_ERR_NONE ) + { + return rfalNfcbCheckSensbRes( gRfalNfcb.DT.sensbRes, *gRfalNfcb.DT.sensbResLen ); + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerSleep( const uint8_t* nfcid0 ) +{ + uint16_t rxLen; + ReturnCode ret; + rfalNfcbSlpbReq slpbReq; + rfalNfcbSlpbRes slpbRes; + + if( nfcid0 == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Compute SLPB_REQ */ + slpbReq.cmd = RFAL_NFCB_CMD_SLPB_REQ; + RFAL_MEMCPY( slpbReq.nfcid0, nfcid0, RFAL_NFCB_NFCID0_LEN ); + + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTxRx( (uint8_t*)&slpbReq, sizeof(rfalNfcbSlpbReq), (uint8_t*)&slpbRes, sizeof(rfalNfcbSlpbRes), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCB_ACTIVATION_FWT )); + + /* Check SLPB_RES */ + if( (rxLen != sizeof(rfalNfcbSlpbRes)) || (slpbRes.cmd != (uint8_t)RFAL_NFCB_CMD_SLPB_RES) ) + { + return RFAL_ERR_PROTO; + } + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerSlotMarker( uint8_t slotCode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcbPollerStartSlotMarker( slotCode, sensbRes, sensbResLen ) ); + rfalRunBlocking( ret, rfalNfcbPollerGetSlotMarkerStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerStartSlotMarker( uint8_t slotCode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + rfalNfcbSlotMarker slotMarker; + + /* Check parameters */ + if( (sensbRes == NULL) || (sensbResLen == NULL) || + (slotCode < RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN) || + (slotCode > RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX) ) + { + return RFAL_ERR_PARAM; + } + /* Compose and send SLOT_MARKER with disabled AGC to detect collisions */ + slotMarker.APn = ((slotCode << RFAL_NFCB_SLOT_MARKER_SC_SHIFT) | (uint8_t)RFAL_NFCB_CMD_SENSB_REQ); + + gRfalNfcb.DT.sensbRes = sensbRes; + gRfalNfcb.DT.sensbResLen = sensbResLen; + + return rfalTransceiveBlockingTx( (uint8_t*)&slotMarker, sizeof(rfalNfcbSlotMarker), (uint8_t*)gRfalNfcb.DT.sensbRes, sizeof(rfalNfcbSensbRes), &gRfalNfcb.DT.rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCB_FWTSENSB ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerGetSlotMarkerStatus( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + /* Covert bits to bytes (u8) */ + (*gRfalNfcb.DT.sensbResLen) = (uint8_t)rfalConvBitsToBytes(gRfalNfcb.DT.rxLen); + + /* Check if a transmission error was detected */ + if( (ret == RFAL_ERR_CRC) || (ret == RFAL_ERR_FRAMING) ) + { + return RFAL_ERR_RF_COLLISION; + } + + if( ret == RFAL_ERR_NONE ) + { + return rfalNfcbCheckSensbRes( gRfalNfcb.DT.sensbRes, *gRfalNfcb.DT.sensbResLen ); + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerTechnologyDetection( rfalComplianceMode compMode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + return rfalNfcbPollerCheckPresence( ((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_NFCB_SENS_CMD_ALLB_REQ : RFAL_NFCB_SENS_CMD_SENSB_REQ), RFAL_NFCB_SLOT_NUM_1, sensbRes, sensbResLen ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerStartTechnologyDetection( rfalComplianceMode compMode, rfalNfcbSensbRes *sensbRes, uint8_t *sensbResLen ) +{ + return rfalNfcbPollerStartCheckPresence( ((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_NFCB_SENS_CMD_ALLB_REQ : RFAL_NFCB_SENS_CMD_SENSB_REQ), RFAL_NFCB_SLOT_NUM_1, sensbRes, sensbResLen ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerGetTechnologyDetectionStatus( void ) +{ + return rfalNfcbPollerGetCheckPresenceStatus(); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcbPollerStartCollisionResolution( compMode, devLimit, nfcbDevList, devCnt) ); + rfalRunBlocking( ret, rfalNfcbPollerGetCollisionResolutionStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerSlottedCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbSlots initSlots, rfalNfcbSlots endSlots, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt, bool *colPending ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcbPollerStartSlottedCollisionResolution( compMode, devLimit, initSlots, endSlots, nfcbDevList, devCnt, colPending ) ); + rfalRunBlocking( ret, rfalNfcbPollerGetCollisionResolutionStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerStartCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt ) +{ + return rfalNfcbPollerStartSlottedCollisionResolution( compMode, devLimit, RFAL_NFCB_SLOT_NUM_1, RFAL_NFCB_SLOT_NUM_16, nfcbDevList, devCnt, &gRfalNfcb.CR.colPend ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerStartSlottedCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcbSlots initSlots, rfalNfcbSlots endSlots, rfalNfcbListenDevice *nfcbDevList, uint8_t *devCnt, bool *colPending ) +{ + /* Check parameters. In ISO | Activity 1.0 mode the initial slots must be 1 as continuation of Technology Detection */ + if( (nfcbDevList == NULL) || (devCnt == NULL) || (colPending == NULL) || (initSlots > RFAL_NFCB_SLOT_NUM_16) || + (endSlots > RFAL_NFCB_SLOT_NUM_16) || ((compMode == RFAL_COMPLIANCE_MODE_ISO) && (initSlots != RFAL_NFCB_SLOT_NUM_1)) ) + { + return RFAL_ERR_PARAM; + } + + (*devCnt) = 0; + (*colPending) = false; + platformTimerDestroy( gRfalNfcb.CR.tmr ); + + /* Store parameters */ + gRfalNfcb.CR.compMode = compMode; + gRfalNfcb.CR.devLimit = devLimit; + gRfalNfcb.CR.curSlots = (uint8_t)initSlots; + gRfalNfcb.CR.endSlots = (uint8_t)endSlots; + gRfalNfcb.CR.nfcbDevList = nfcbDevList; + gRfalNfcb.CR.colPending = colPending; + gRfalNfcb.CR.devCnt = devCnt; + (*gRfalNfcb.CR.devCnt) = 0U; + gRfalNfcb.CR.curDevCnt = 0U; + gRfalNfcb.CR.curSlotNum = 0U; + gRfalNfcb.CR.tmr = RFAL_TIMING_NONE; + + gRfalNfcb.CR.state = RFAL_NFCB_CR_SLOTS_TX; + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcbPollerGetCollisionResolutionStatus( void ) +{ + ReturnCode ret; + rfalNfcbSensCmd cmd; + + /* Check if operation is still not complete */ + if( gRfalNfcb.CR.tmr != RFAL_TIMING_NONE ) + { + if( (!platformTimerIsExpired(gRfalNfcb.CR.tmr)) ) + { + return RFAL_ERR_BUSY; + } + } + + switch( gRfalNfcb.CR.state ) + { + /*******************************************************************************/ + case RFAL_NFCB_CR_SLOTS_TX: + + /* Check if it's the first iteration on ISO | Activity 1.0 mode */ + if( (gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_ISO) && (gRfalNfcb.CR.curSlots == (uint8_t)RFAL_NFCB_SLOT_NUM_1) ) + { + /* Do nothing in case Activity 1.0, where the previous SENSB_RES from technology detection should be used */ + } + /* Send SENSB_REQ with number of slots if not the first Activity 2.1 9.3.5.24 - Symbol 23 */ + else if( gRfalNfcb.CR.curSlotNum == 0U ) + { + /* Send ALLB_REQ Activity 2.1 9.3.5.2 and 9.3.5.3 (Symbol 1 and 2) */ + cmd = ((gRfalNfcb.CR.curSlots == (uint8_t)RFAL_NFCB_SLOT_NUM_1) ? RFAL_NFCB_SENS_CMD_ALLB_REQ : RFAL_NFCB_SENS_CMD_SENSB_REQ ); + + /* PRQA S 4342 1 # MISRA 10.5 - Layout of rfalNfcbSlots and the limited loop guarantee that no invalid enum values are created. */ + rfalNfcbPollerStartCheckPresence( cmd, (rfalNfcbSlots)gRfalNfcb.CR.curSlots, &gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbRes, &gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbResLen ); + } + else + { + /* Activity 2.1 9.3.5.26 - Symbol 25 */ + rfalNfcbPollerStartSlotMarker( gRfalNfcb.CR.curSlotNum, &gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbRes, &gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbResLen ); + } + + gRfalNfcb.CR.state = RFAL_NFCB_CR_SLOTS; + return RFAL_ERR_BUSY; + + + /*******************************************************************************/ + case RFAL_NFCB_CR_SLOTS: + + RFAL_EXIT_ON_BUSY( ret, rfalNfcbPollerGetSlotMarkerStatus() ); + + /*******************************************************************************/ + if( gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_EMV ) + { + /* Report (timeout) error immediately EMVCo 3.0 9.6.1.3 */ + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Check if there was a transmission error on WUPB EMVCo 3.0 9.3.3.1 */ + if( gRfalNfcb.CR.nfcbDevList->sensbResLen == 0U ) + { + return RFAL_ERR_FRAMING; + } + } + + + /*******************************************************************************/ + /* Activity 2.1 9.3.5.7 and 9.3.5.8 - Symbol 6 */ + if( ret != RFAL_ERR_TIMEOUT ) + { + /* Activity 2.1 9.3.5.8 - Symbol 7 */ + if( (rfalNfcbCheckSensbRes( &gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbRes, gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].sensbResLen) == RFAL_ERR_NONE) && (ret == RFAL_ERR_NONE) ) + { + gRfalNfcb.CR.nfcbDevList[*gRfalNfcb.CR.devCnt].isSleep = false; + + if( gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_EMV ) + { + (*gRfalNfcb.CR.devCnt)++; + return ret; + } + else if( gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_ISO ) + { + /* Activity 1.0 9.3.5.8 - Symbol 7 */ + (*gRfalNfcb.CR.devCnt)++; + gRfalNfcb.CR.curDevCnt++; + + /* Activity 1.0 9.3.5.10 - Symbol 9 */ + if( (*gRfalNfcb.CR.devCnt >= gRfalNfcb.CR.devLimit) || (gRfalNfcb.CR.curSlotNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1) ) + { + return ret; + } + + /* Activity 2.1 9.3.5.11 - Symbol 10 */ + rfalNfcbPollerSleep( gRfalNfcb.CR.nfcbDevList[(*gRfalNfcb.CR.devCnt)-1U].sensbRes.nfcid0 ); + gRfalNfcb.CR.nfcbDevList[(*gRfalNfcb.CR.devCnt)-1U].isSleep = true; + } + else if( gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_NFC ) + { + /* Activity 2.1 9.3.5.10 and 9.3.5.11 - Symbol 9 and Symbol 11*/ + if( gRfalNfcb.CR.curDevCnt != 0U ) + { + rfalNfcbPollerSleepTx( gRfalNfcb.CR.nfcbDevList[(*gRfalNfcb.CR.devCnt) - (uint8_t)1U].sensbRes.nfcid0 ); + gRfalNfcb.CR.nfcbDevList[(*gRfalNfcb.CR.devCnt) - (uint8_t)1U].isSleep = true; + + gRfalNfcb.CR.tmr = platformTimerCreate( (uint16_t)rfalConv1fcToMs(RFAL_NFCB_ACTIVATION_FWT) ); + ret = RFAL_ERR_BUSY; + } + + /* Activity 2.1 9.3.5.12 - Symbol 11 */ + (*gRfalNfcb.CR.devCnt)++; + gRfalNfcb.CR.curDevCnt++; + + /* Activity 2.1 9.3.5.6 - Symbol 13 */ + if( (*gRfalNfcb.CR.devCnt >= gRfalNfcb.CR.devLimit) || (gRfalNfcb.CR.curSlots == (uint8_t)RFAL_NFCB_SLOT_NUM_1) ) + { + gRfalNfcb.CR.state = RFAL_NFCB_CR_END; + return RFAL_ERR_BUSY; + } + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + else + { + /* If deviceLimit is set to 0 the NFC Forum Device is configured to perform collision detection only Activity 1.0 and 1.1 9.3.5.5 - Symbol 4 */ + if( (gRfalNfcb.CR.devLimit == 0U) && (gRfalNfcb.CR.curSlotNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1) ) + { + return RFAL_ERR_RF_COLLISION; + } + + /* Activity 2.1 9.3.5.9 - Symbol 8 */ + (*gRfalNfcb.CR.colPending) = true; + } + } + + /* Activity 2.1 9.3.5.15 - Symbol 14 & 15*/ + if( (gRfalNfcb.CR.curSlotNum + 1U) < rfalNfcbNI2NumberOfSlots(gRfalNfcb.CR.curSlots) ) + { + gRfalNfcb.CR.curSlotNum++; + gRfalNfcb.CR.state = RFAL_NFCB_CR_SLOTS_TX; + } + else + { + /* Activity 2.1 9.3.5.17 - Symbol 16 */ + if( !(*gRfalNfcb.CR.colPending) ) + { + break; + } + + /* Activity 1.1 9.3.5.18 - Symbol 17 */ + if( gRfalNfcb.CR.curDevCnt == 0U ) + { + /* Activity 2.1 9.3.5.19 - Symbol 18 */ + if( (gRfalNfcb.CR.curSlotNum + 1U) >= rfalNfcbNI2NumberOfSlots(gRfalNfcb.CR.endSlots) ) + { + break; + } + + /* Activity 2.1 9.3.5.20 - Symbol 19 */ + gRfalNfcb.CR.curSlots++; + } + + gRfalNfcb.CR.state = RFAL_NFCB_CR_SLEEP; + } + + return RFAL_ERR_BUSY; + + + /*******************************************************************************/ + case RFAL_NFCB_CR_SLEEP: + + /* Activity 2.1 9.3.5.23 - Symbol 22 */ + if( (gRfalNfcb.CR.compMode == RFAL_COMPLIANCE_MODE_NFC) && (gRfalNfcb.CR.curDevCnt != 0U) ) + { + rfalNfcbPollerSleepTx( gRfalNfcb.CR.nfcbDevList[((*gRfalNfcb.CR.devCnt) - (uint8_t)1U)].sensbRes.nfcid0 ); + gRfalNfcb.CR.nfcbDevList[((*gRfalNfcb.CR.devCnt) - (uint8_t)1U)].isSleep = true; + + gRfalNfcb.CR.tmr = platformTimerCreate( (uint16_t) rfalConv1fcToMs(RFAL_NFCB_ACTIVATION_FWT) ); + } + + /* Activity 2.1 9.3.5.6 - Symbol 5 */ + gRfalNfcb.CR.curSlotNum = 0U; + gRfalNfcb.CR.curDevCnt = 0U; + (*gRfalNfcb.CR.colPending) = false; + + gRfalNfcb.CR.state = RFAL_NFCB_CR_SLOTS_TX; + return RFAL_ERR_BUSY; + + /*******************************************************************************/ + case RFAL_NFCB_CR_END: + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +uint32_t rfalNfcbTR2ToFDT( uint8_t tr2Code ) +{ + /*******************************************************************************/ + /* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */ + /*! TR2 Table according to Digital 1.1 Table 33 */ + const uint16_t rfalNfcbTr2Table[4] = { 1792, 3328, 5376, 9472 }; + /*******************************************************************************/ + + return (uint32_t)rfalNfcbTr2Table[ (tr2Code & RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK) ]; +} + +#endif /* RFAL_FEATURE_NFCB */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcf.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcf.c new file mode 100644 index 0000000..3f0602b --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcf.c @@ -0,0 +1,650 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcf.c + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-F Poller (FeliCa PCD) device + * + * The definitions and helpers methods provided by this module are + * aligned with NFC-F (FeliCa - JIS X6319-4) + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfcf.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFCF + */ + +#if RFAL_FEATURE_NFCF + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ +#define RFAL_NFCF_SENSF_REQ_LEN_MIN 5U /*!< SENSF_RES minimum length */ + +#define RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN 15U /*!< Minimum length for a Check Command T3T 5.4.1 */ +#define RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN 31U /*!< Minimum length for an Update Command T3T 5.5.1 */ + +#define RFAL_NFCF_CHECK_RES_MIN_LEN 11U /*!< CHECK Response minimum length T3T 1.0 Table 8 */ +#define RFAL_NFCF_UPDATE_RES_MIN_LEN 11U /*!< UPDATE Response minimum length T3T 1.0 Table 8 */ + +#define RFAL_NFCF_CHECK_REQ_MAX_LEN 86U /*!< Max length of a Check request T3T 1.0 Table 7 */ +#define RFAL_NFCF_CHECK_REQ_MAX_SERV 15U /*!< Max Services number on Check request T3T 1.0 5.4.1.5 */ +#define RFAL_NFCF_CHECK_REQ_MAX_BLOCK 15U /*!< Max Blocks number on Check request T3T 1.0 5.4.1.10 */ +#define RFAL_NFCF_UPDATE_REQ_MAX_SERV 15U /*!< Max Services number Update request T3T 1.0 5.4.1.5 */ +#define RFAL_NFCF_UPDATE_REQ_MAX_BLOCK 13U /*!< Max Blocks number on Update request T3T 1.0 5.4.1.10 */ + + +/*! MRT Check | Update = (Tt3t x ((A+1) + n (B+1)) x 4^E) + dRWTt3t T3T 5.8 + Max values used: A = 7 ; B = 7 ; E = 3 ; n = 15 (NFC Forum n = 15, JIS n = 32) +*/ +#define RFAL_NFCF_MRT_CHECK_UPDATE ((4096U * (8U + (15U * 8U)) * 64U ) + 16U) + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ +#define rfalNfcfSlots2CardNum( s ) ((uint8_t)(s)+1U) /*!< Converts Time Slot Number (TSN) into num of slots */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! Structure/Buffer to hold the SENSF_RES with LEN byte prepended */ +typedef struct{ + uint8_t LEN; /*!< NFC-F LEN byte */ + rfalNfcfSensfRes SENSF_RES; /*!< SENSF_RES */ +} rfalNfcfSensfResBuf; + + +/*! Greedy collection for NFCF GRE_POLL_F Activity 1.0 Table 10 */ +typedef struct{ + uint8_t pollFound; /*!< Number of devices found by the Poll */ + uint8_t pollCollision; /*!< Number of collisions detected */ + rfalFeliCaPollRes POLL_F[RFAL_NFCF_POLL_MAXCARDS]; /*!< GRE_POLL_F Activity 1.0 Table 10 */ +} rfalNfcfGreedyF; + + +/*! NFC-F SENSF_REQ format Digital 1.1 8.6.1 */ +typedef struct +{ + uint8_t CMD; /*!< Command code: 00h */ + uint8_t SC[RFAL_NFCF_SENSF_SC_LEN]; /*!< System Code */ + uint8_t RC; /*!< Request Code */ + uint8_t TSN; /*!< Time Slot Number */ +} rfalNfcfSensfReq; + + + +/*! Colission Resolution states */ +typedef enum{ + RFAL_NFCF_CR_POLL, /*!< Poll Request */ + RFAL_NFCF_CR_PARSE, /*!< Parse Poll Response */ + RFAL_NFCF_CR_POLL_SC, /*!< Poll Request with RC=SC */ +}rfalNfcFColResState; + + + +/*! Colission Resolution context */ +typedef struct{ + rfalNfcfGreedyF greedyF; + uint8_t devLimit; /*!< Device limit to be used */ + rfalComplianceMode compMode; /*!< Compliancy mode to be used */ + rfalNfcfListenDevice* nfcfDevList; /*!< Location of the device list */ + uint8_t* devCnt; /*!< Location of the device counter */ + bool collPending; /*!< Collision pending flag */ + bool nfcDepFound; + rfalNfcFColResState state; /*!< Single Collision Resolution state (Single CR) */ +}rfalNfcfColResParams; + + +/*! RFAL NFC-F instance */ +typedef struct +{ + rfalNfcfColResParams CR; /*!< Collision Resolution */ +} rfalNfcf; + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ +static rfalNfcf gNfcf; /*!< RFAL NFC-F instance */ + + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static void rfalNfcfComputeValidSENF( rfalNfcfListenDevice *outDevInfo, uint8_t *curDevIdx, uint8_t devLimit, bool overwrite, bool *nfcDepFound ); + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +/*******************************************************************************/ +static void rfalNfcfComputeValidSENF( rfalNfcfListenDevice *outDevInfo, uint8_t *curDevIdx, uint8_t devLimit, bool overwrite, bool *nfcDepFound ) +{ + uint8_t tmpIdx; + bool duplicate; + const rfalNfcfSensfResBuf *sensfBuf; + rfalNfcfSensfResBuf sensfCopy; + + + /*******************************************************************************/ + /* Go through all responses check if valid and duplicates */ + /*******************************************************************************/ + while( (gNfcf.CR.greedyF.pollFound > 0U) && ((*curDevIdx) < devLimit) ) + { + duplicate = false; + gNfcf.CR.greedyF.pollFound--; + + /* MISRA 11.3 - Cannot point directly into different object type, use local copy */ + RFAL_MEMCPY( (uint8_t*)&sensfCopy, (uint8_t*)&gNfcf.CR.greedyF.POLL_F[gNfcf.CR.greedyF.pollFound], sizeof(rfalNfcfSensfResBuf) ); + + + /* Point to received SENSF_RES */ + sensfBuf = &sensfCopy; + + + /* Check for devices that are already in device list */ + for( tmpIdx = 0; tmpIdx < (*curDevIdx); tmpIdx++ ) + { + if( RFAL_BYTECMP( sensfBuf->SENSF_RES.NFCID2, outDevInfo[tmpIdx].sensfRes.NFCID2, RFAL_NFCF_NFCID2_LEN ) == 0 ) + { + duplicate = true; + break; + } + } + + /* If is a duplicate skip this (and not to overwrite)*/ + if(duplicate && (!overwrite)) + { + continue; + } + + /* Check if response length is OK */ + if( (( sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) < RFAL_NFCF_SENSF_RES_LEN_MIN) || ((sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) > RFAL_NFCF_SENSF_RES_LEN_MAX) ) + { + continue; + } + + /* Check if the response is a SENSF_RES / Polling response */ + if( sensfBuf->SENSF_RES.CMD != (uint8_t)RFAL_NFCF_CMD_POLLING_RES ) + { + continue; + } + + /* Check if is an overwrite request or new device*/ + if(duplicate && overwrite) + { + /* overwrite deviceInfo/GRE_SENSF_RES with SENSF_RES */ + outDevInfo[tmpIdx].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN); + RFAL_MEMCPY( &outDevInfo[tmpIdx].sensfRes, &sensfBuf->SENSF_RES, outDevInfo[tmpIdx].sensfResLen ); + continue; + } + else + { + /* fill deviceInfo/GRE_SENSF_RES with new SENSF_RES */ + outDevInfo[(*curDevIdx)].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN); + RFAL_MEMCPY( &outDevInfo[(*curDevIdx)].sensfRes, &sensfBuf->SENSF_RES, outDevInfo[(*curDevIdx)].sensfResLen ); + } + + /* Check if this device supports NFC-DEP and signal it (ACTIVITY 1.1 9.3.6.63) */ + *nfcDepFound = rfalNfcfIsNfcDepSupported( &outDevInfo[(*curDevIdx)] ); + + (*curDevIdx)++; + } +} + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerInitialize( rfalBitRate bitRate ) +{ + ReturnCode ret; + + if( (bitRate != RFAL_BR_212) && (bitRate != RFAL_BR_424) ) + { + return RFAL_ERR_PARAM; + } + + RFAL_EXIT_ON_ERR( ret, rfalSetMode( RFAL_MODE_POLL_NFCF, bitRate, bitRate ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + + rfalSetGT( RFAL_GT_NFCF ); + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCF_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_NFCF_POLLER ); + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes *cardList, uint8_t *devCnt, uint8_t *collisions ) +{ + return rfalFeliCaPoll( slots, sysCode, reqCode, cardList, rfalNfcfSlots2CardNum(slots), devCnt, collisions ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerCheckPresence( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcfPollerStartCheckPresence() ); + rfalRunBlocking( ret, rfalNfcfPollerGetCheckPresenceStatus() ); + + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerStartCheckPresence( void ) +{ + gNfcf.CR.greedyF.pollFound = 0; + gNfcf.CR.greedyF.pollCollision = 0; + + /* ACTIVITY 1.0 & 1.1 - 9.2.3.17 SENSF_REQ must be with number of slots equal to 4 + * SC must be 0xFFFF + * RC must be 0x00 (No system code info required) */ + return rfalStartFeliCaPoll( RFAL_FELICA_4_SLOTS, RFAL_NFCF_SYSTEMCODE, RFAL_FELICA_POLL_RC_NO_REQUEST, gNfcf.CR.greedyF.POLL_F, rfalNfcfSlots2CardNum(RFAL_FELICA_4_SLOTS), &gNfcf.CR.greedyF.pollFound, &gNfcf.CR.greedyF.pollCollision ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerGetCheckPresenceStatus( void ) +{ + return rfalGetFeliCaPollStatus(); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcfListenDevice *nfcfDevList, uint8_t *devCnt ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalNfcfPollerStartCollisionResolution( compMode, devLimit, nfcfDevList, devCnt ) ); + rfalRunBlocking( ret, rfalNfcfPollerGetCollisionResolutionStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerStartCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcfListenDevice *nfcfDevList, uint8_t *devCnt ) +{ + if( (nfcfDevList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *devCnt = 0; + + /*******************************************************************************************/ + /* ACTIVITY 1.0 - 9.3.6.3 Copy valid SENSF_RES in GRE_POLL_F into GRE_SENSF_RES */ + /* ACTIVITY 1.0 - 9.3.6.6 The NFC Forum Device MUST remove all entries from GRE_SENSF_RES[]*/ + /* ACTIVITY 2.1 - 9.3.6.2 Populate GRE_SENSF_RES with data from GRE_POLL_F */ + /* */ + /* CON_DEVICES_LIMIT = 0 Just check if devices from Tech Detection exceeds -> always true */ + /* Allow the number of slots open on Technology Detection */ + /*******************************************************************************************/ + rfalNfcfComputeValidSENF( nfcfDevList, devCnt, ((devLimit == 0U) ? rfalNfcfSlots2CardNum( RFAL_FELICA_4_SLOTS ) : devLimit), false, &gNfcf.CR.nfcDepFound ); + + /* Store context */ + gNfcf.CR.nfcfDevList = nfcfDevList; + gNfcf.CR.compMode = compMode; + gNfcf.CR.devLimit = devLimit; + gNfcf.CR.devCnt = devCnt; + gNfcf.CR.state = RFAL_NFCF_CR_POLL; + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerGetCollisionResolutionStatus( void ) +{ + ReturnCode ret; + + switch( gNfcf.CR.state ) + { + /*******************************************************************************/ + case RFAL_NFCF_CR_POLL: + case RFAL_NFCF_CR_POLL_SC: + + + if( gNfcf.CR.state == RFAL_NFCF_CR_POLL ) + { + /*******************************************************************************/ + /* Activity 2.1 9.3.6.3 - Symbol 2 Check if devices found are lower than the limit */ + if( *gNfcf.CR.devCnt >= gNfcf.CR.devLimit ) + { + break; + } + + /*******************************************************************************/ + /* Activity 1.0 - 9.3.6.5 Copy valid SENSF_RES and then to remove it */ + /* Activity 1.1 - 9.3.6.65 Copy and filter duplicates */ + /* For now, due to some devices keep generating different nfcid2, we use 1.0 */ + /* Phones detected: Samsung Galaxy Nexus,Samsung Galaxy S3,Samsung Nexus S */ + /*******************************************************************************/ + *gNfcf.CR.devCnt = 0; + } + + RFAL_EXIT_ON_ERR( ret, rfalStartFeliCaPoll( RFAL_FELICA_16_SLOTS, + RFAL_NFCF_SYSTEMCODE, + (uint8_t)((gNfcf.CR.state == RFAL_NFCF_CR_POLL_SC) ? RFAL_FELICA_POLL_RC_SYSTEM_CODE : RFAL_FELICA_POLL_RC_NO_REQUEST), + gNfcf.CR.greedyF.POLL_F, + rfalNfcfSlots2CardNum((uint8_t)RFAL_FELICA_16_SLOTS), + &gNfcf.CR.greedyF.pollFound, + &gNfcf.CR.greedyF.pollCollision ) ); + + gNfcf.CR.state = RFAL_NFCF_CR_PARSE; + return RFAL_ERR_BUSY; + + + /*******************************************************************************/ + case RFAL_NFCF_CR_PARSE: + + RFAL_EXIT_ON_BUSY( ret, rfalGetFeliCaPollStatus() ); + + if( ret == RFAL_ERR_NONE ) + { + /* Activity 2.1 9.3.6.5 - Symbol 4 Update device list */ + rfalNfcfComputeValidSENF( gNfcf.CR.nfcfDevList, gNfcf.CR.devCnt, gNfcf.CR.devLimit, false, &gNfcf.CR.nfcDepFound ); + } + + /*******************************************************************************/ + /* Activity 2.1 9.3.6.6 - Symbol 5 Check if any device supports NFC DEP */ + if( (gNfcf.CR.nfcDepFound) && (gNfcf.CR.compMode == RFAL_COMPLIANCE_MODE_NFC) ) + { + /* Send another poll request with RC = System Code */ + gNfcf.CR.state = RFAL_NFCF_CR_POLL_SC; + + /* Set compliance mode to invalid (non NFC) to poll for NFC-DEP devices only once */ + gNfcf.CR.compMode = RFAL_COMPLIANCE_MODE_EMV; + return RFAL_ERR_BUSY; + } + + break; + + /*******************************************************************************/ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + + } + + return RFAL_ERR_NONE; + +} + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerCheck( const uint8_t* nfcid2, const rfalNfcfServBlockListParam *servBlock, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvdLen ) +{ + uint8_t txBuf[RFAL_NFCF_CHECK_REQ_MAX_LEN]; + uint8_t msgIt; + uint8_t i; + ReturnCode ret; + const uint8_t *checkRes; + + /* Check parameters */ + if( (nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || + (servBlock->numBlock == 0U) || (servBlock->numBlock > RFAL_NFCF_CHECK_REQ_MAX_BLOCK) || + (servBlock->numServ == 0U) || (servBlock->numServ > RFAL_NFCF_CHECK_REQ_MAX_SERV) || + (rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECK_RES_MIN_LEN)) ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + + /*******************************************************************************/ + /* Compose CHECK command/request */ + + txBuf[msgIt++] = RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION; /* Command Code */ + + RFAL_MEMCPY( &txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN ); /* NFCID2 */ + msgIt += RFAL_NFCF_NFCID2_LEN; + + txBuf[msgIt++] = servBlock->numServ; /* NoS */ + for( i = 0; i < servBlock->numServ; i++) + { + txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code */ + txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU); + } + + txBuf[msgIt++] = servBlock->numBlock; /* NoB */ + for( i = 0; i < servBlock->numBlock; i++) + { + txBuf[msgIt++] = servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */ + if( (servBlock->blockList[i].conf & RFAL_NFCF_BLOCKLISTELEM_LEN_BIT) != 0U ) /* Check if 2 or 3 byte block list element */ + { + txBuf[msgIt++] = (uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */ + } + else + { + txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */ + txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU); + } + } + + /*******************************************************************************/ + /* Transceive CHECK command/request */ + ret = rfalTransceiveBlockingTxRx( txBuf, msgIt, rxBuf, rxBufLen, rcvdLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCF_MRT_CHECK_UPDATE ); + + if( ret == RFAL_ERR_NONE ) + { + /* Skip LEN byte */ + checkRes = (rxBuf + RFAL_NFCF_LENGTH_LEN); + + /* Check NFCID and response length T3T v1.0 5.4.2.3 */ + if( (RFAL_BYTECMP( nfcid2, &checkRes[RFAL_NFCF_CMD_LEN], RFAL_NFCF_NFCID2_LEN ) != 0) || + (*rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) ) + { + ret = RFAL_ERR_PROTO; + } + /* Check for a valid response */ + else if( (checkRes[RFAL_NFCF_CMD_POS] != (uint8_t)RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES) || + (checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) || + (checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ) + { + ret = RFAL_ERR_REQUEST; + } + /* CHECK succesfull, remove header */ + else + { + (*rcvdLen) -= (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_NOB_POS); + + if( *rcvdLen > 0U ) + { + RFAL_MEMMOVE( rxBuf, &checkRes[RFAL_NFCF_CHECKUPDATE_RES_NOB_POS], (*rcvdLen) ); + } + } + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalNfcfPollerUpdate( const uint8_t* nfcid2, const rfalNfcfServBlockListParam *servBlock, uint8_t *txBuf, uint16_t txBufLen, const uint8_t *blockData, uint8_t *rxBuf, uint16_t rxBufLen ) +{ + uint8_t i; + uint16_t msgIt; + uint16_t rcvdLen; + uint16_t auxLen; + const uint8_t *updateRes; + ReturnCode ret; + + /* Check parameters */ + if( (nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || (txBuf == NULL) || + (servBlock->numBlock == 0U) || (servBlock->numBlock > RFAL_NFCF_UPDATE_REQ_MAX_BLOCK) || + (servBlock->numServ == 0U) || (servBlock->numServ > RFAL_NFCF_UPDATE_REQ_MAX_SERV) || + (rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_UPDATE_RES_MIN_LEN)) ) + { + return RFAL_ERR_PARAM; + } + + /* Calculate required txBuffer lenth T3T 1.0 Table 9 */ + auxLen = (uint16_t)( RFAL_NFCF_CMD_LEN + RFAL_NFCF_NFCID2_LEN + RFAL_NFCF_NOS_LEN + ( servBlock->numServ * sizeof(rfalNfcfServ) ) + + RFAL_NFCF_NOB_LEN + (uint16_t)((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCKLISTELEM_MAX_LEN) + (uint16_t)((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN) ); + + + /* Check whether the provided buffer is sufficient for this request */ + if( txBufLen < auxLen ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + + /*******************************************************************************/ + /* Compose UPDATE command/request */ + + txBuf[msgIt++] = RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION; /* Command Code */ + + RFAL_MEMCPY( &txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN ); /* NFCID2 */ + msgIt += RFAL_NFCF_NFCID2_LEN; + + txBuf[msgIt++] = servBlock->numServ; /* NoS */ + for( i = 0; i < servBlock->numServ; i++) + { + txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code */ + txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU); + } + + txBuf[msgIt++] = servBlock->numBlock; /* NoB */ + for( i = 0; i < servBlock->numBlock; i++) + { + txBuf[msgIt++] = servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */ + if( (servBlock->blockList[i].conf & RFAL_NFCF_BLOCKLISTELEM_LEN_BIT) != 0U ) /* Check if 2 or 3 byte block list element */ + { + txBuf[msgIt++] = (uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */ + } + else + { + txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */ + txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU); + } + } + + auxLen = ((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN); + RFAL_MEMCPY( &txBuf[msgIt], blockData, auxLen ); /* Block Data */ + msgIt += auxLen; + + + /*******************************************************************************/ + /* Transceive UPDATE command/request */ + ret = rfalTransceiveBlockingTxRx( txBuf, msgIt, rxBuf, rxBufLen, &rcvdLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCF_MRT_CHECK_UPDATE ); + + if( ret == RFAL_ERR_NONE ) + { + /* Skip LEN byte */ + updateRes = (rxBuf + RFAL_NFCF_LENGTH_LEN); + + /* Check NFCID and response length T3T v1.0 5.5.2.3 */ + if( (RFAL_BYTECMP( nfcid2, &updateRes[RFAL_NFCF_CMD_LEN], RFAL_NFCF_NFCID2_LEN ) != 0) || + (rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) ) + { + ret = RFAL_ERR_PROTO; + } + /* Check for a valid response */ + else if( (updateRes[RFAL_NFCF_CMD_POS] != (uint8_t)RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES) || + (updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) || + (updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ) + { + ret = RFAL_ERR_REQUEST; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + + return ret; +} + + + +/*******************************************************************************/ +bool rfalNfcfListenerIsT3TReq( const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2 ) +{ + /* Check cmd byte */ + switch( *buf ) + { + case RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION: + if( bufLen < RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN ) + { + return false; + } + break; + + case RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION: + if( bufLen < RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN ) + { + return false; + } + break; + + default: + return false; + } + + /* Output NFID2 if requested */ + if( nfcid2 != NULL ) + { + RFAL_MEMCPY( nfcid2, &buf[RFAL_NFCF_CMD_LEN], RFAL_NFCF_NFCID2_LEN ); + } + + return true; +} + +#endif /* RFAL_FEATURE_NFCF */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcv.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcv.c new file mode 100644 index 0000000..b128936 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_nfcv.c @@ -0,0 +1,883 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_nfcv.c + * + * \author Gustavo Patricio + * + * \brief Implementation of NFC-V Poller (ISO15693) device + * + * The definitions and helpers methods provided by this module are + * aligned with NFC-V (ISO15693) + * + * The definitions and helpers methods provided by this module + * are aligned with NFC-V Digital 2.1 + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_nfcv.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_NFCV + */ + +#if RFAL_FEATURE_NFCV + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCV_INV_REQ_FLAG 0x06U /*!< INVENTORY_REQ INV_FLAG Digital 2.1 9.6.1 */ +#define RFAL_NFCV_MASKVAL_MAX_LEN 8U /*!< Mask value max length: 64 bits (UID length) */ +#define RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN 64U /*!< Mask value max length in 1 Slot mode in bits Digital 2.1 9.6.1.6 */ +#define RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN 60U /*!< Mask value max length in 16 Slot mode in bits Digital 2.1 9.6.1.6 */ +#define RFAL_NFCV_MAX_SLOTS 16U /*!< NFC-V max number of Slots */ +#define RFAL_NFCV_INV_REQ_HEADER_LEN 3U /*!< INVENTORY_REQ header length (INV_FLAG, CMD, MASK_LEN) */ +#define RFAL_NFCV_INV_RES_LEN 10U /*!< INVENTORY_RES length */ +#define RFAL_NFCV_WR_MUL_REQ_HEADER_LEN 4U /*!< Write Multiple header length (INV_FLAG, CMD, [UID], BNo, Bno) */ + + +#define RFAL_NFCV_CMD_LEN 1U /*!< Commandbyte length */ +#define RFAL_NFCV_FLAG_POS 0U /*!< Flag byte position */ +#define RFAL_NFCV_FLAG_LEN 1U /*!< Flag byte length */ +#define RFAL_NFCV_DATASTART_POS 1U /*!< Position of start of data */ +#define RFAL_NFCV_DSFI_LEN 1U /*!< DSFID length */ +#define RFAL_NFCV_SLPREQ_REQ_FLAG 0x22U /*!< SLPV_REQ request flags Digital 2.0 (Candidate) 9.7.1.1 */ +#define RFAL_NFCV_RES_FLAG_NOERROR 0x00U /*!< RES_FLAG indicating no error (checked during activation) */ + +#define RFAL_NFCV_MAX_COLL_SUPPORTED 16U /*!< Maximum number of collisions supported by the Anticollision loop */ + +#define RFAL_NFCV_FDT_MAX1 4394U /*!< Read alike command FWT FDTV,LISTEN,MAX1 Digital 2.0 B.5 */ + +/*! Maximum Wait time FDTV,EOF and MAX2 FDTV,LISTEN,MAX2 + Tolerance = 270644 + 512 = 271156 (~20ms) Digital 2.3 B.5*/ +#define RFAL_NFCV_FDT_MAX 271156U + +/*! Time from special frame to EOF + * ISO15693 2009 10.4.2 : <20ms + * NFC Forum defines Digital 2.3 9.7.4 : FDTV,EOF = [10 ; 20]ms + */ +#define RFAL_NFCV_FDT_EOF rfalConvMsTo1fc(16) + + + +/*! Time between slots - ISO 15693 defines t3min depending on modulation depth and data rate. + * With only high-bitrate supported, AM modulation and a length of 12 bytes (96bits) for INV_RES we get: + * - ISO t3min = 96/26 ms + 300us = 4 ms + * - NFC Forum defines FDTV,INVENT_NORES = (4394 + 2048)/fc. Digital 2.0 B.5*/ +#define RFAL_NFCV_FDT_V_INVENT_NORES 4U + + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + /*! Checks if a valid INVENTORY_RES is valid Digital 2.2 9.6.2.1 & 9.6.2.3 */ + #define rfalNfcvCheckInvRes( f, l ) (((l)==rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN)) && ((f)==RFAL_NFCV_RES_FLAG_NOERROR)) + + + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! NFC-V INVENTORY_REQ format Digital 2.0 9.6.1 */ +typedef struct +{ + uint8_t INV_FLAG; /*!< Inventory Flags */ + uint8_t CMD; /*!< Command code: 01h */ + uint8_t MASK_LEN; /*!< Mask Value Length */ + uint8_t MASK_VALUE[RFAL_NFCV_MASKVAL_MAX_LEN]; /*!< Mask Value */ +} rfalNfcvInventoryReq; + + +/*! NFC-V SLP_REQ format Digital 2.0 (Candidate) 9.7.1 */ +typedef struct +{ + uint8_t REQ_FLAG; /*!< Request Flags */ + uint8_t CMD; /*!< Command code: 02h */ + uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value */ +} rfalNfcvSlpvReq; + + +/*! Container for a collision found during Anticollision loop */ +typedef struct +{ + uint8_t maskLen; + uint8_t maskVal[RFAL_NFCV_MASKVAL_MAX_LEN]; +}rfalNfcvCollision; + + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode rfalNfcvParseError( uint8_t err ); + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +static ReturnCode rfalNfcvParseError( uint8_t err ) +{ + switch(err) + { + case RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED: + case RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED: + return RFAL_ERR_NOTSUPP; + + case RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED: + return RFAL_ERR_PROTO; + + case RFAL_NFCV_ERROR_WRITE_FAILED: + return RFAL_ERR_WRITE; + + default: + return RFAL_ERR_REQUEST; + } +} + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerInitialize( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalSetMode( RFAL_MODE_POLL_NFCV, RFAL_BR_26p48, RFAL_BR_26p48 ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + + rfalSetGT( RFAL_GT_NFCV ); + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCV_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_NFCV_POLLER ); + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerCheckPresence( rfalNfcvInventoryRes *invRes ) +{ + ReturnCode ret; + + /* INVENTORY_REQ with 1 slot and no Mask Activity 2.0 (Candidate) 9.2.3.32 */ + ret = rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_1, 0, NULL, invRes, NULL ); + + if( (ret == RFAL_ERR_RF_COLLISION) || (ret == RFAL_ERR_CRC) || + (ret == RFAL_ERR_FRAMING) || (ret == RFAL_ERR_PROTO) ) + { + ret = RFAL_ERR_NONE; + } + + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerInventory( rfalNfcvNumSlots nSlots, uint8_t maskLen, const uint8_t *maskVal, rfalNfcvInventoryRes *invRes, uint16_t* rcvdLen ) +{ + ReturnCode ret; + rfalNfcvInventoryReq invReq; + uint16_t rxLen; + + if( ((maskVal == NULL) && (maskLen != 0U)) || (invRes == NULL) ) + { + return RFAL_ERR_PARAM; + } + + invReq.INV_FLAG = (RFAL_NFCV_INV_REQ_FLAG | (uint8_t)nSlots); + invReq.CMD = RFAL_NFCV_CMD_INVENTORY; + invReq.MASK_LEN = (uint8_t)RFAL_MIN( maskLen, ((nSlots == RFAL_NFCV_NUM_SLOTS_1) ? RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN : RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN) ); /* Digital 2.0 9.6.1.6 */ + + if( (rfalConvBitsToBytes(invReq.MASK_LEN) > 0U) && (maskVal != NULL) ) /* MISRA 21.18 & 1.3 */ + { + RFAL_MEMCPY( invReq.MASK_VALUE, maskVal, rfalConvBitsToBytes(invReq.MASK_LEN) ); + } + + ret = rfalISO15693TransceiveAnticollisionFrame( (uint8_t*)&invReq, (uint8_t)(RFAL_NFCV_INV_REQ_HEADER_LEN + rfalConvBitsToBytes(invReq.MASK_LEN)), (uint8_t*)invRes, sizeof(rfalNfcvInventoryRes), &rxLen ); + + /* Check for optional output parameter */ + if( rcvdLen != NULL ) + { + *rcvdLen = rxLen; + } + + if( ret == RFAL_ERR_NONE ) + { + /* Check for valid INVENTORY_RES Digital 2.2 9.6.2.1 & 9.6.2.3 */ + if( !rfalNfcvCheckInvRes( invRes->RES_FLAG, rxLen ) ) + { + return RFAL_ERR_PROTO; + } + } + + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerCollisionResolution( rfalComplianceMode compMode, uint8_t devLimit, rfalNfcvListenDevice *nfcvDevList, uint8_t *devCnt ) +{ + ReturnCode ret; + uint8_t slotNum; + uint16_t rcvdLen; + uint8_t colIt; + uint8_t colCnt; + uint8_t colPos; + bool colPending; + rfalNfcvCollision colFound[RFAL_NFCV_MAX_COLL_SUPPORTED]; + + + if( (nfcvDevList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Initialize parameters */ + *devCnt = 0; + colIt = 0; + colCnt = 0; + colPending = false; + RFAL_MEMSET(colFound, 0x00, (sizeof(rfalNfcvCollision)*RFAL_NFCV_MAX_COLL_SUPPORTED) ); + + if( devLimit > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMSET(nfcvDevList, 0x00, (sizeof(rfalNfcvListenDevice)*devLimit) ); + } + + RFAL_NO_WARNING(colPending); /* colPending is not exposed externally, in future it might become exposed/ouput parameter */ + + if( compMode == RFAL_COMPLIANCE_MODE_NFC ) + { + /* Send INVENTORY_REQ with one slot Activity 2.1 9.3.7.1 (Symbol 0) */ + ret = rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &nfcvDevList->InvRes, NULL ); + + /* Exit if no device found Activity 2.1 9.3.7.2 (Symbol 1) */ + /* Exit if no correct frame (no Transmission Error) Activity 2.1 9.3.7.3 (Symbol 2) */ + if( (ret == RFAL_ERR_TIMEOUT) || ((ret == RFAL_ERR_PROTO)) ) + { + return RFAL_ERR_NONE; + } + + /* Valid Response found without transmission error/collision Activity 2.1 9.3.7.6 (Symbol 5) */ + if( ret == RFAL_ERR_NONE ) + { + (*devCnt)++; + return RFAL_ERR_NONE; + } + + /* A Collision has been identified Activity 2.1 9.3.7.4 (Symbol 3) */ + colPending = true; + colCnt = 1; + + /* Check if the Collision Resolution is set to perform only Collision detection Activity 2.1 9.3.7.5 (Symbol 4)*/ + if( devLimit == 0U ) + { + return RFAL_ERR_RF_COLLISION; + } + + platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES); + + /*******************************************************************************/ + /* Collisions pending, Anticollision loop must be executed */ + /*******************************************************************************/ + } + else + { + /* Advance to 16 slots below without mask. Will give a good chance to identify multiple cards */ + colPending = true; + colCnt = 1; + } + + + /* Execute until all collisions are resolved Activity 2.1 9.3.7.18 (Symbol 17) */ + do + { + /* Activity 2.1 9.3.7.7 (Symbol 6 / 7) */ + colPending = false; + slotNum = 0; + + do + { + if( slotNum == 0U ) + { + /* Send INVENTORY_REQ with 16 slots Activity 2.1 9.3.7.9 (Symbol 8) */ + ret = rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_16, colFound[colIt].maskLen, colFound[colIt].maskVal, &nfcvDevList[(*devCnt)].InvRes, &rcvdLen ); + } + else + { + ret = rfalISO15693TransceiveEOFAnticollision( (uint8_t*)&nfcvDevList[(*devCnt)].InvRes, sizeof(rfalNfcvInventoryRes), &rcvdLen ); + } + slotNum++; + + /*******************************************************************************/ + if( ret != RFAL_ERR_TIMEOUT ) + { + if( rcvdLen < rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN) ) + { /* If only a partial frame was received make sure the FDT_V_INVENT_NORES is fulfilled */ + platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES); + } + + /* Check if response is a correct frame (no TxRx error) Activity 2.1 9.3.7.11 (Symbol 10)*/ + if( (ret == RFAL_ERR_NONE) || (ret == RFAL_ERR_PROTO) ) + { + /* Check if the device found is already on the list and its response is a valid INVENTORY_RES */ + if( rfalNfcvCheckInvRes( nfcvDevList[(*devCnt)].InvRes.RES_FLAG, rcvdLen ) ) + { + /* Activity 2.1 9.3.7.12 (Symbol 11) */ + (*devCnt)++; + } + } + else /* Treat everything else as collision */ + { + /* Activity 2.1 9.3.7.17 (Symbol 16) */ + colPending = true; + + + /*******************************************************************************/ + /* Ensure that this collision still fits on the container */ + if( colCnt < RFAL_NFCV_MAX_COLL_SUPPORTED ) + { + /* Store this collision on the container to be resolved later */ + /* Activity 2.1 9.3.7.17 (Symbol 16): add the collision information + * (MASK_VAL + SN) to the list containing the collision information */ + RFAL_MEMCPY(colFound[colCnt].maskVal, colFound[colIt].maskVal, RFAL_NFCV_UID_LEN); + colPos = colFound[colIt].maskLen; + colFound[colCnt].maskVal[(colPos/RFAL_BITS_IN_BYTE)] &= (uint8_t)((1U << (colPos % RFAL_BITS_IN_BYTE)) - 1U); + colFound[colCnt].maskVal[(colPos/RFAL_BITS_IN_BYTE)] |= (uint8_t)((slotNum-1U) << (colPos % RFAL_BITS_IN_BYTE)); + colFound[colCnt].maskVal[((colPos/RFAL_BITS_IN_BYTE)+1U)] = (uint8_t)((slotNum-1U) >> (RFAL_BITS_IN_BYTE - (colPos % RFAL_BITS_IN_BYTE))); + + colFound[colCnt].maskLen = (colFound[colIt].maskLen + 4U); + + colCnt++; + } + } + } + else + { + /* Timeout */ + platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES); + } + + /* Check if devices found have reached device limit Activity 2.1 9.3.7.13 (Symbol 12) */ + if( *devCnt >= devLimit ) + { + return RFAL_ERR_NONE; + } + + } while( slotNum < RFAL_NFCV_MAX_SLOTS ); /* Slot loop */ + colIt++; + } while( colIt < colCnt ); /* Collisions found loop */ + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerSleepCollisionResolution( uint8_t devLimit, rfalNfcvListenDevice *nfcvDevList, uint8_t *devCnt ) +{ + uint8_t tmpDevCnt; + ReturnCode ret; + uint8_t i; + + if( (nfcvDevList == NULL) || (devCnt == NULL) ) + { + return RFAL_ERR_PARAM; + } + + *devCnt = 0; + + do + { + tmpDevCnt = 0; + ret = rfalNfcvPollerCollisionResolution( RFAL_COMPLIANCE_MODE_ISO, (devLimit - *devCnt), &nfcvDevList[*devCnt], &tmpDevCnt ); + + for( i = *devCnt; i < (*devCnt + tmpDevCnt); i++ ) + { + rfalNfcvPollerSleep( 0x00, nfcvDevList[i].InvRes.UID ); + nfcvDevList[i].isSleep = true; + } + *devCnt += tmpDevCnt; + } + while( (ret == RFAL_ERR_NONE) && (tmpDevCnt > 0U) && (*devCnt < devLimit) ); + + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerSleep( uint8_t flags, const uint8_t* uid ) +{ + ReturnCode ret; + rfalNfcvSlpvReq slpReq; + uint8_t rxBuf; /* dummy buffer, just to perform Rx */ + + if( uid == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Compute SLPV_REQ */ + slpReq.REQ_FLAG = (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */ + slpReq.CMD = RFAL_NFCV_CMD_SLPV; + RFAL_MEMCPY( slpReq.UID, uid, RFAL_NFCV_UID_LEN ); + + /* NFC Forum device SHALL wait at least FDTVpp to consider the SLPV acknowledged (FDTVpp = FDTVpoll) Digital 2.0 (Candidate) 9.7 9.8.2 */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&slpReq, sizeof(rfalNfcvSlpvReq), &rxBuf, sizeof(rxBuf), NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCV_FDT_MAX1 ); + if( ret != RFAL_ERR_TIMEOUT ) + { + return ret; + } + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerSelect( uint8_t flags, const uint8_t* uid ) +{ + uint16_t rcvLen; + rfalNfcvGenericRes res; + + if( uid == NULL ) + { + return RFAL_ERR_PARAM; + } + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_SELECT, flags, RFAL_NFCV_PARAM_SKIP, uid, NULL, 0U, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerReadSingleBlock( uint8_t flags, const uint8_t* uid, uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t bn; + + bn = blockNum; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_READ_SINGLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, &bn, sizeof(uint8_t), rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerWriteSingleBlock( uint8_t flags, const uint8_t* uid, uint8_t blockNum, const uint8_t* wrData, uint8_t blockLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_MAX_BLOCK_LEN)]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + /* Check for valid parameters */ + if( (blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL) ) + { + return RFAL_ERR_PARAM; + } + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = blockNum; /* Set Block Number (8 bits) */ + RFAL_MEMCPY( &data[dataLen], wrData, blockLen ); /* Append Block data to write */ + dataLen += blockLen; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerLockBlock( uint8_t flags, const uint8_t* uid, uint8_t blockNum ) +{ + uint16_t rcvLen; + rfalNfcvGenericRes res; + uint8_t bn; + + bn = blockNum; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_LOCK_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, &bn, sizeof(uint8_t), (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint8_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = firstBlockNum; /* Set first Block Number */ + data[dataLen++] = numOfBlocks; /* Set number of blocks to read */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerWriteMultipleBlocks( uint8_t flags, const uint8_t* uid, uint8_t firstBlockNum, uint8_t numOfBlocks, uint8_t *txBuf, uint16_t txBufLen, uint8_t blockLen, const uint8_t* wrData, uint16_t wrDataLen ) +{ + ReturnCode ret; + uint16_t rcvLen; + uint16_t reqLen; + rfalNfcvGenericRes res; + uint16_t msgIt; + + /* Calculate required buffer length */ + reqLen = (uint16_t)((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) : (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen)); + + if( (reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || ((((uint16_t)numOfBlocks) * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) || (wrData == NULL) ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + + /* Compute Request Command */ + txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS))); + txBuf[msgIt++] = RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS; + + /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */ + if( uid != NULL ) + { + txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS; + RFAL_MEMCPY( &txBuf[msgIt], uid, RFAL_NFCV_UID_LEN ); + msgIt += (uint8_t)RFAL_NFCV_UID_LEN; + } + + txBuf[msgIt++] = firstBlockNum; + txBuf[msgIt++] = (numOfBlocks - 1U); + + if( wrDataLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( &txBuf[msgIt], wrData, wrDataLen ); + msgIt += wrDataLen; + } + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( txBuf, msgIt, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCV_FDT_MAX ); + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN ) + { + return RFAL_ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( (res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U ) + { + return rfalNfcvParseError( *res.data ); + } + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */ + data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU); + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedWriteSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, const uint8_t* wrData, uint8_t blockLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_MAX_BLOCK_LEN)]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + /* Check for valid parameters */ + if( (blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ) + { + return RFAL_ERR_PARAM; + } + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */ + data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU); + RFAL_MEMCPY( &data[dataLen], wrData, blockLen ); /* Append Block data to write */ + dataLen += blockLen; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedLockSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum ) +{ + uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */ + data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU); + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint16_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU); + data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU); + data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU); + data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU); + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK, flags, RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint16_t numOfBlocks, uint8_t *txBuf, uint16_t txBufLen, uint8_t blockLen, const uint8_t* wrData, uint16_t wrDataLen ) +{ + ReturnCode ret; + uint16_t rcvLen; + uint16_t reqLen; + rfalNfcvGenericRes res; + uint16_t msgIt; + uint16_t nBlocks; + + /* Calculate required buffer length */ + reqLen = ((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) : (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen) ); + + if( (reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (( (uint16_t)numOfBlocks * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + nBlocks = (numOfBlocks - 1U); + + /* Compute Request Command */ + txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS))); + txBuf[msgIt++] = RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK; + + /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */ + if( uid != NULL ) + { + txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS; + RFAL_MEMCPY( &txBuf[msgIt], uid, RFAL_NFCV_UID_LEN ); + msgIt += (uint8_t)RFAL_NFCV_UID_LEN; + } + + txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 0) & 0xFFU); + txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 8) & 0xFFU); + txBuf[msgIt++] = (uint8_t)((nBlocks >> 0) & 0xFFU); + txBuf[msgIt++] = (uint8_t)((nBlocks >> 8) & 0xFFU); + + if( wrDataLen > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY( &txBuf[msgIt], wrData, wrDataLen ); + msgIt += wrDataLen; + } + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( txBuf, msgIt, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCV_FDT_MAX ); + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN ) + { + return RFAL_ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( (res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U ) + { + return rfalNfcvParseError( *res.data ); + } + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerGetSystemInformation( uint8_t flags, const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_GET_SYS_INFO, flags, RFAL_NFCV_PARAM_SKIP, uid, NULL, 0U, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerExtendedGetSystemInformation( uint8_t flags, const uint8_t* uid, uint8_t requestField, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO, flags, requestField, uid, NULL, 0U, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerTransceiveReq( uint8_t cmd, uint8_t flags, uint8_t param, const uint8_t* uid, const uint8_t *data, uint16_t dataLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + ReturnCode ret; + rfalNfcvGenericReq req; + uint8_t msgIt; + rfalBitRate rxBR; + bool fastMode; + bool specialFrame; + + msgIt = 0; + fastMode = false; + specialFrame = false; + + /* Check for valid parameters */ + if( (rxBuf == NULL) || (rcvLen == NULL) || ((dataLen > 0U) && (data == NULL)) || + (dataLen > ((uid != NULL) ? RFAL_NFCV_MAX_GEN_DATA_LEN : (RFAL_NFCV_MAX_GEN_DATA_LEN - RFAL_NFCV_UID_LEN))) ) + { + return RFAL_ERR_PARAM; + } + + + /* Check if the command is an ST's Fast command */ + if( (param == RFAL_NFCV_ST_IC_MFG_CODE) && + ((cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK) || (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK) || + (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS) || (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS) || + (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) || (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH) || + (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE) || (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION) || + (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION)) ) + { + /* Store current Rx bit rate and move to fast mode */ + rfalGetBitRate( NULL, &rxBR ); + rfalSetBitRate( RFAL_BR_KEEP, RFAL_BR_52p97 ); + + fastMode = true; + } + + + /* Compute Request Command */ + req.REQ_FLAG = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS))); + req.CMD = cmd; + + /* Prepend parameter on ceratin proprietary requests: IC Manuf, Parameters */ + if( param != RFAL_NFCV_PARAM_SKIP ) + { + req.payload.data[msgIt++] = param; + } + + /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */ + if( uid != NULL ) + { + req.REQ_FLAG |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS; + RFAL_MEMCPY( &req.payload.data[msgIt], uid, RFAL_NFCV_UID_LEN ); + msgIt += RFAL_NFCV_UID_LEN; + } + + if( dataLen > 0U ) + { + RFAL_MEMCPY( &req.payload.data[msgIt], data, dataLen); + msgIt += (uint8_t)dataLen; + } + + + /* If the Option Flag | Special Frame is set in certain commands an EOF needs to be sent whithin FDTV,EOF to retrieve the VICC response Digital 2.3 9.7.4 ISO15693-3 2009 10.4.2 & 10.4.3 & 10.4.5 */ + if( ((flags & (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION) != 0U) && ((cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK) || (cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS) || + (cmd == (uint8_t)RFAL_NFCV_CMD_LOCK_BLOCK) || (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK) || + (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK) || (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK)) ) + { + specialFrame = true; + } + + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, (RFAL_NFCV_CMD_LEN + RFAL_NFCV_FLAG_LEN +(uint16_t)msgIt), rxBuf, rxBufLen, rcvLen, RFAL_TXRX_FLAGS_DEFAULT, (specialFrame ? RFAL_NFCV_FDT_EOF : RFAL_NFCV_FDT_MAX) ); + + /* If the Option Flag | Special Frame is set in certain commands an EOF needs to be sent whithin FDTV,EOF to retrieve the VICC response Digital 2.3 9.7.4 ISO15693-3 2009 10.4.2 & 10.4.3 & 10.4.5 */ + if( specialFrame ) + { + ret = rfalISO15693TransceiveEOF( rxBuf, rxBufLen, rcvLen ); + } + + /* Restore Rx BitRate */ + if( fastMode ) + { + rfalSetBitRate( RFAL_BR_KEEP, rxBR ); + } + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( (*rcvLen) < (uint8_t)RFAL_NFCV_FLAG_LEN ) + { + return RFAL_ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( (rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U ) + { + return rfalNfcvParseError( rxBuf[RFAL_NFCV_DATASTART_POS] ); + } + + return RFAL_ERR_NONE; +} + +#endif /* RFAL_FEATURE_NFCV */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25tb.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25tb.c new file mode 100644 index 0000000..f599dab --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25tb.c @@ -0,0 +1,559 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_st25tb.c + * + * \author Gustavo Patricio + * + * \brief Implementation of ST25TB interface + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_st25tb.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_ST25TB + */ + +#if RFAL_FEATURE_ST25TB + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_ST25TB_CMD_LEN 1U /*!< ST25TB length of a command */ +#define RFAL_ST25TB_SLOTS 16U /*!< ST25TB number of slots */ +#define RFAL_ST25TB_SLOTNUM_MASK 0x0FU /*!< ST25TB Slot Number bit mask on SlotMarker */ +#define RFAL_ST25TB_SLOTNUM_SHIFT 4U /*!< ST25TB Slot Number shift on SlotMarker */ + +#define RFAL_ST25TB_INITIATE_CMD1 0x06U /*!< ST25TB Initiate command byte1 */ +#define RFAL_ST25TB_INITIATE_CMD2 0x00U /*!< ST25TB Initiate command byte2 */ +#define RFAL_ST25TB_PCALL_CMD1 0x06U /*!< ST25TB Pcall16 command byte1 */ +#define RFAL_ST25TB_PCALL_CMD2 0x04U /*!< ST25TB Pcall16 command byte2 */ +#define RFAL_ST25TB_SELECT_CMD 0x0EU /*!< ST25TB Select command */ +#define RFAL_ST25TB_GET_UID_CMD 0x0BU /*!< ST25TB Get UID command */ +#define RFAL_ST25TB_COMPLETION_CMD 0x0FU /*!< ST25TB Completion command */ +#define RFAL_ST25TB_RESET_INV_CMD 0x0CU /*!< ST25TB Reset to Inventory command */ +#define RFAL_ST25TB_READ_BLOCK_CMD 0x08U /*!< ST25TB Read Block command */ +#define RFAL_ST25TB_WRITE_BLOCK_CMD 0x09U /*!< ST25TB Write Block command */ + + +#define RFAL_ST25TB_T0 2157U /*!< ST25TB t0 159 us ST25TB RF characteristics */ +#define RFAL_ST25TB_T1 2048U /*!< ST25TB t1 151 us ST25TB RF characteristics */ + +#define RFAL_ST25TB_FWT (RFAL_ST25TB_T0 + RFAL_ST25TB_T1) /*!< ST25TB FWT = T0 + T1 */ +#define RFAL_ST25TB_TW rfalConvMsTo1fc(7U) /*!< ST25TB TW : Programming time for write max 7ms */ + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! Initiate Request */ +typedef struct +{ + uint8_t cmd1; /*!< Initiate Request cmd1: 0x06 */ + uint8_t cmd2; /*!< Initiate Request cmd2: 0x00 */ +} rfalSt25tbInitiateReq; + +/*! Pcall16 Request */ +typedef struct +{ + uint8_t cmd1; /*!< Pcal16 Request cmd1: 0x06 */ + uint8_t cmd2; /*!< Pcal16 Request cmd2: 0x04 */ +} rfalSt25tbPcallReq; + + +/*! Select Request */ +typedef struct +{ + uint8_t cmd; /*!< Select Request cmd: 0x0E */ + uint8_t chipId; /*!< Chip ID */ +} rfalSt25tbSelectReq; + +/*! Read Block Request */ +typedef struct +{ + uint8_t cmd; /*!< Select Request cmd: 0x08 */ + uint8_t address; /*!< Block address */ +} rfalSt25tbReadBlockReq; + +/*! Write Block Request */ +typedef struct +{ + uint8_t cmd; /*!< Select Request cmd: 0x09 */ + uint8_t address; /*!< Block address */ + rfalSt25tbBlock data; /*!< Block Data */ +} rfalSt25tbWriteBlockReq; + + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief ST25TB Poller Do Collision Resolution + * + * This method performs ST25TB Collision resolution loop for each slot + * + * \param[in] devLimit : device limit value, and size st25tbDevList + * \param[out] st25tbDevList : ST35TB listener device info + * \param[out] devCnt : Devices found counter + * + * \return colPending : true if a collision was detected + ***************************************************************************** + */ +static bool rfalSt25tbPollerDoCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt ); + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + + +static bool rfalSt25tbPollerDoCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt ) +{ + uint8_t i; + uint8_t chipId; + ReturnCode ret; + bool col; + + col = false; + + for(i = 0; i < RFAL_ST25TB_SLOTS; i++) + { + platformDelay(1); /* Wait t2: Answer to new request delay */ + + if( i==0U ) + { + /* Step 2: Send Pcall16 */ + ret = rfalSt25tbPollerPcall( &chipId ); + } + else + { + /* Step 3-17: Send Pcall16 */ + ret = rfalSt25tbPollerSlotMarker( i, &chipId ); + } + + if( ret == RFAL_ERR_NONE ) + { + /* Found another device */ + st25tbDevList[*devCnt].chipID = chipId; + st25tbDevList[*devCnt].isDeselected = false; + + /* Select Device, retrieve its UID */ + ret = rfalSt25tbPollerSelect( chipId ); + + /* By Selecting this device, the previous gets Deselected */ + if( (*devCnt) > 0U ) + { + st25tbDevList[(*devCnt)-1U].isDeselected = true; + } + + if( RFAL_ERR_NONE == ret ) + { + ret = rfalSt25tbPollerGetUID( &st25tbDevList[*devCnt].UID ); + } + + if( RFAL_ERR_NONE == ret ) + { + (*devCnt)++; + } + } + else if( (ret == RFAL_ERR_CRC) || (ret == RFAL_ERR_FRAMING) ) + { + col = true; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + if( *devCnt >= devLimit ) + { + break; + } + } + return col; +} + + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerInitialize( void ) +{ + return rfalNfcbPollerInitialize(); +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerCheckPresence( uint8_t *chipId ) +{ + ReturnCode ret; + uint8_t chipIdRes; + + chipIdRes = 0x00; + + /* Send Initiate Request */ + ret = rfalSt25tbPollerInitiate( &chipIdRes ); + + /* Check if a transmission error was detected */ + if( (ret == RFAL_ERR_CRC) || (ret == RFAL_ERR_FRAMING) ) + { + return RFAL_ERR_NONE; + } + + /* Copy chip ID if requested */ + if( chipId != NULL ) + { + *chipId = chipIdRes; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerInitiate( uint8_t *chipId ) +{ + ReturnCode ret; + uint16_t rxLen; + rfalSt25tbInitiateReq initiateReq; + uint8_t rxBuf[RFAL_ST25TB_CHIP_ID_LEN + RFAL_ST25TB_CRC_LEN]; /* In case we receive less data that CRC, RF layer will not remove the CRC from buffer */ + + /* Compute Initiate Request */ + initiateReq.cmd1 = RFAL_ST25TB_INITIATE_CMD1; + initiateReq.cmd2 = RFAL_ST25TB_INITIATE_CMD2; + + /* Send Initiate Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&initiateReq, sizeof(rfalSt25tbInitiateReq), (uint8_t*)rxBuf, sizeof(rxBuf), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid Select Response */ + if( (ret == RFAL_ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) ) + { + return RFAL_ERR_PROTO; + } + + /* Copy chip ID if requested */ + if( chipId != NULL ) + { + *chipId = *rxBuf; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerPcall( uint8_t *chipId ) +{ + ReturnCode ret; + uint16_t rxLen; + rfalSt25tbPcallReq pcallReq; + + /* Compute Pcal16 Request */ + pcallReq.cmd1 = RFAL_ST25TB_PCALL_CMD1; + pcallReq.cmd2 = RFAL_ST25TB_PCALL_CMD2; + + /* Send Pcal16 Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&pcallReq, sizeof(rfalSt25tbPcallReq), (uint8_t*)chipId, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid Select Response */ + if( (ret == RFAL_ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) ) + { + return RFAL_ERR_PROTO; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerSlotMarker( uint8_t slotNum, uint8_t *chipIdRes ) +{ + ReturnCode ret; + uint16_t rxLen; + uint8_t slotMarker; + + if( (slotNum == 0U) || (slotNum > 15U) ) + { + return RFAL_ERR_PARAM; + } + + /* Compute SlotMarker */ + slotMarker = ( ((slotNum & RFAL_ST25TB_SLOTNUM_MASK) << RFAL_ST25TB_SLOTNUM_SHIFT) | RFAL_ST25TB_PCALL_CMD1 ); + + + /* Send SlotMarker */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&slotMarker, RFAL_ST25TB_CMD_LEN, (uint8_t*)chipIdRes, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid ChipID Response */ + if( (ret == RFAL_ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) ) + { + return RFAL_ERR_PROTO; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerSelect( uint8_t chipId ) +{ + ReturnCode ret; + uint16_t rxLen; + rfalSt25tbSelectReq selectReq; + uint8_t chipIdRes; + + /* Compute Select Request */ + selectReq.cmd = RFAL_ST25TB_SELECT_CMD; + selectReq.chipId = chipId; + + /* Send Select Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&selectReq, sizeof(rfalSt25tbSelectReq), (uint8_t*)&chipIdRes, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid Select Response */ + if( (ret == RFAL_ERR_NONE) && ((rxLen != RFAL_ST25TB_CHIP_ID_LEN) || (chipIdRes != chipId)) ) + { + return RFAL_ERR_PROTO; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerGetUID( rfalSt25tbUID *UID ) +{ + ReturnCode ret; + uint16_t rxLen; + uint8_t getUidReq; + + + /* Compute Get UID Request */ + getUidReq = RFAL_ST25TB_GET_UID_CMD; + + /* Send Select Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&getUidReq, RFAL_ST25TB_CMD_LEN, (uint8_t*)UID, sizeof(rfalSt25tbUID), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid UID Response */ + if( (ret == RFAL_ERR_NONE) && (rxLen != RFAL_ST25TB_UID_LEN) ) + { + return RFAL_ERR_PROTO; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt ) +{ + + uint8_t chipId; + ReturnCode ret; + bool detected; /* collision or device was detected */ + + if( (st25tbDevList == NULL) || (devCnt == NULL) || (devLimit == 0U) ) + { + return RFAL_ERR_PARAM; + } + + *devCnt = 0; + + /* Step 1: Send Initiate */ + ret = rfalSt25tbPollerInitiate( &chipId ); + if( ret == RFAL_ERR_NONE ) + { + /* If only 1 answer is detected */ + st25tbDevList[*devCnt].chipID = chipId; + st25tbDevList[*devCnt].isDeselected = false; + + /* Retrieve its UID and keep it Selected*/ + ret = rfalSt25tbPollerSelect( chipId ); + + if( RFAL_ERR_NONE == ret ) + { + ret = rfalSt25tbPollerGetUID( &st25tbDevList[*devCnt].UID ); + } + + if( RFAL_ERR_NONE == ret ) + { + (*devCnt)++; + } + } + /* Always proceed to Pcall16 anticollision as phase differences of tags can lead to no tag recognized, even if there is one */ + if( *devCnt < devLimit ) + { + /* Multiple device responses */ + do + { + detected = rfalSt25tbPollerDoCollisionResolution( devLimit, st25tbDevList, devCnt ); + } + while( (detected == true) && (*devCnt < devLimit) ); + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerReadBlock( uint8_t blockAddress, rfalSt25tbBlock *blockData ) +{ + ReturnCode ret; + uint16_t rxLen; + rfalSt25tbReadBlockReq readBlockReq; + + + /* Compute Read Block Request */ + readBlockReq.cmd = RFAL_ST25TB_READ_BLOCK_CMD; + readBlockReq.address = blockAddress; + + /* Send Read Block Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&readBlockReq, sizeof(rfalSt25tbReadBlockReq), (uint8_t*)blockData, sizeof(rfalSt25tbBlock), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); + + /* Check for valid UID Response */ + if( (ret == RFAL_ERR_NONE) && (rxLen != RFAL_ST25TB_BLOCK_LEN) ) + { + return RFAL_ERR_PROTO; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerWriteBlock( uint8_t blockAddress, const rfalSt25tbBlock *blockData ) +{ + ReturnCode ret; + uint16_t rxLen; + rfalSt25tbWriteBlockReq writeBlockReq; + rfalSt25tbBlock tmpBlockData; + + + /* Compute Write Block Request */ + writeBlockReq.cmd = RFAL_ST25TB_WRITE_BLOCK_CMD; + writeBlockReq.address = blockAddress; + RFAL_MEMCPY( &writeBlockReq.data, blockData, RFAL_ST25TB_BLOCK_LEN ); + + /* Send Write Block Request */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&writeBlockReq, sizeof(rfalSt25tbWriteBlockReq), tmpBlockData, RFAL_ST25TB_BLOCK_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, (RFAL_ST25TB_FWT + RFAL_ST25TB_TW) ); + + + /* Check if there was any error besides timeout */ + if( ret != RFAL_ERR_TIMEOUT ) + { + /* Check if an unexpected answer was received */ + if( ret == RFAL_ERR_NONE ) + { + return RFAL_ERR_PROTO; + } + + /* Check whether a transmission error occurred */ + if( (ret != RFAL_ERR_CRC) && (ret != RFAL_ERR_FRAMING) && (ret != RFAL_ERR_NOMEM) && (ret != RFAL_ERR_RF_COLLISION) ) + { + return ret; + } + + /* If a transmission error occurred (maybe noise while commiting data) wait maximum programming time and verify data afterwards */ + rfalSetGT( (RFAL_ST25TB_FWT + RFAL_ST25TB_TW) ); + rfalFieldOnAndStartGT(); + } + + ret = rfalSt25tbPollerReadBlock(blockAddress, &tmpBlockData); + if( ret == RFAL_ERR_NONE ) + { + if( RFAL_BYTECMP( &tmpBlockData, blockData, RFAL_ST25TB_BLOCK_LEN ) == 0 ) + { + return RFAL_ERR_NONE; + } + return RFAL_ERR_PROTO; + } + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerCompletion( void ) +{ + uint8_t completionReq; + + /* Compute Completion Request */ + completionReq = RFAL_ST25TB_COMPLETION_CMD; + + /* Send Completion Request, no response is expected */ + return rfalTransceiveBlockingTxRx( (uint8_t*)&completionReq, RFAL_ST25TB_CMD_LEN, NULL, 0, NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); +} + + +/*******************************************************************************/ +ReturnCode rfalSt25tbPollerResetToInventory( void ) +{ + uint8_t resetInvReq; + + /* Compute Completion Request */ + resetInvReq = RFAL_ST25TB_RESET_INV_CMD; + + /* Send Completion Request, no response is expected */ + return rfalTransceiveBlockingTxRx( (uint8_t*)&resetInvReq, RFAL_ST25TB_CMD_LEN, NULL, 0, NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT ); +} + +#endif /* RFAL_FEATURE_ST25TB */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25xv.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25xv.c new file mode 100644 index 0000000..509ca03 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_st25xv.c @@ -0,0 +1,556 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_st25xv.c + * + * \author Gustavo Patricio + * + * \brief NFC-V ST25 NFC-V Tag specific features + * + * This module provides support for ST's specific features available on + * NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_st25xv.h" +#include "rfal_nfcv.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_ST25xV + */ + + +#if RFAL_FEATURE_ST25xV + +#if !RFAL_FEATURE_NFCV + #error " RFAL: Invalid Configuration. Please Enable RFAL support for NFC-V." +#endif + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_ST25xV_READ_CONFIG_LEN 2U /*!< READ CONFIGURATION length */ +#define RFAL_ST25xV_READ_MSG_LEN_LEN 2U /*!< READ MESSAGE LENGTH length */ +#define RFAL_ST25xV_CONF_POINTER_LEN 1U /*!< READ/WRITE CONFIGURATION Pointer length */ +#define RFAL_ST25xV_CONF_REGISTER_LEN 1U /*!< READ/WRITE CONFIGURATION Register length */ +#define RFAL_ST25xV_PWDNUM_LEN 1U /*!< Password Number length */ +#define RFAL_ST25xV_PWD_LEN 8U /*!< Password length */ +#define RFAL_ST25xV_MBPOINTER_LEN 1U /*!< Read Message MBPointer length */ +#define RFAL_ST25xV_NUMBYTES_LEN 1U /*!< Read Message Number of Bytes length */ + +#define RFAL_ST25TV02K_TBOOT_RF 1U /*!< RF Boot time (Minimum time from carrier generation to first data) */ +#define RFAL_ST25TV02K_TRF_OFF 2U /*!< RF OFF time */ + +#define RFAL_ST25xV_FDT_POLL_MAX rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF 20 ms Digital 2.1 B.5 */ +#define RFAL_NFCV_FLAG_POS 0U /*!< Flag byte position */ +#define RFAL_NFCV_FLAG_LEN 1U /*!< Flag byte length */ + + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +static ReturnCode rfalST25xVPollerGenericReadConfiguration(uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ); +static ReturnCode rfalST25xVPollerGenericWriteConfiguration( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ); +static ReturnCode rfalST25xVPollerGenericReadMessageLength( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t* msgLen ); +static ReturnCode rfalST25xVPollerGenericReadMessage( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ); +static ReturnCode rfalST25xVPollerGenericWriteMessage( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ); +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +static ReturnCode rfalST25xVPollerGenericReadConfiguration(uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ) +{ + ReturnCode ret; + uint8_t p; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + if( regValue == NULL ) + { + return RFAL_ERR_PARAM; + } + + p = pointer; + + ret = rfalNfcvPollerTransceiveReq( cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, &p, sizeof(uint8_t), (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); + if( ret == RFAL_ERR_NONE ) + { + if( rcvLen < RFAL_ST25xV_READ_CONFIG_LEN ) + { + ret = RFAL_ERR_PROTO; + } + else + { + *regValue = res.data[0]; + } + } + return ret; +} + +/*******************************************************************************/ +static ReturnCode rfalST25xVPollerGenericWriteConfiguration( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ) +{ + uint8_t data[RFAL_ST25xV_CONF_POINTER_LEN + RFAL_ST25xV_CONF_REGISTER_LEN]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + dataLen = 0U; + + data[dataLen++] = pointer; + data[dataLen++] = regValue; + + return rfalNfcvPollerTransceiveReq( cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); + +} + +/*******************************************************************************/ +static ReturnCode rfalST25xVPollerGenericReadMessageLength( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t* msgLen ) +{ + ReturnCode ret; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + if( msgLen == NULL ) + { + return RFAL_ERR_PARAM; + } + + ret = rfalNfcvPollerTransceiveReq( cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, NULL, 0, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); + if( ret == RFAL_ERR_NONE ) + { + if( rcvLen < RFAL_ST25xV_READ_MSG_LEN_LEN ) + { + ret = RFAL_ERR_PROTO; + } + else + { + *msgLen = res.data[0]; + } + } + return ret; +} + +/*******************************************************************************/ +static ReturnCode rfalST25xVPollerGenericReadMessage( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[RFAL_ST25xV_MBPOINTER_LEN + RFAL_ST25xV_NUMBYTES_LEN]; + uint8_t dataLen; + + dataLen = 0; + + /* Compute Request Data */ + data[dataLen++] = mbPointer; + data[dataLen++] = numBytes; + + return rfalNfcvPollerTransceiveReq( cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +static ReturnCode rfalST25xVPollerGenericWriteMessage( uint8_t cmd, uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ) +{ + ReturnCode ret; + uint8_t reqFlag; + uint16_t msgIt; + rfalBitRate rxBR; + bool fastMode; + rfalNfcvGenericRes res; + uint16_t rcvLen; + + /* Calculate required Tx buf length: Mfg Code UID MSGLen MSGLen+1 */ + msgIt = (uint16_t)( msgLen + sizeof(flags) + sizeof(cmd) + 1U + ((uid != NULL) ? RFAL_NFCV_UID_LEN : 0U) + 1U + 1U ); + /* Note: MSGlength parameter of the command is the number of Data bytes minus - 1 (00 for 1 byte of data, FFh for 256 bytes of data) */ + + /* Check for valid parameters */ + if( (txBuf == NULL) || (msgData == NULL) || (txBufLen < msgIt) ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + fastMode = false; + + /* Check if the command is an ST's Fast command */ + if( cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE ) + { + /* Store current Rx bit rate and move to fast mode */ + rfalGetBitRate( NULL, &rxBR ); + rfalSetBitRate( RFAL_BR_KEEP, RFAL_BR_52p97 ); + + fastMode = true; + } + + /* Compute Request Command */ + reqFlag = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS) & ~((uint32_t)RFAL_NFCV_REQ_FLAG_SELECT))); + reqFlag |= (( uid != NULL ) ? (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS : (uint8_t)RFAL_NFCV_REQ_FLAG_SELECT); + + txBuf[msgIt++] = reqFlag; + txBuf[msgIt++] = cmd; + txBuf[msgIt++] = RFAL_NFCV_ST_IC_MFG_CODE; + + if( uid != NULL ) + { + RFAL_MEMCPY( &txBuf[msgIt], uid, RFAL_NFCV_UID_LEN ); + msgIt += RFAL_NFCV_UID_LEN; + } + txBuf[msgIt++] = msgLen; + RFAL_MEMCPY( &txBuf[msgIt], msgData, (uint16_t)(msgLen +(uint16_t) 1U) ); /* Message Data contains (MSGLength + 1) bytes */ + msgIt += (uint16_t)(msgLen + (uint16_t)1U); + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( txBuf, msgIt, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25xV_FDT_POLL_MAX ); + + + /* Restore Rx BitRate */ + if( fastMode ) + { + rfalSetBitRate( RFAL_BR_KEEP, rxBR ); + } + + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN ) + { + return RFAL_ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( (res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U ) + { + return RFAL_ERR_PROTO; + } + + return RFAL_ERR_NONE; +} + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerM24LRReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN]; + uint8_t dataLen; + + dataLen = 0; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */ + data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_READ_SINGLE_BLOCK, (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT), RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerM24LRWriteSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, const uint8_t* wrData, uint8_t blockLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_MAX_BLOCK_LEN)]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + /* Check for valid parameters */ + if( (blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL) ) + { + return RFAL_ERR_PARAM; + } + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */ + data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */ + RFAL_MEMCPY( &data[dataLen], wrData, blockLen ); /* Append Block data to write */ + dataLen += blockLen; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK, (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT), RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */ + data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */ + data[dataLen++] = numOfBlocks; /* Set number of blocks to read */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS, (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT), RFAL_NFCV_PARAM_SKIP, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastReadSingleBlock( uint8_t flags, const uint8_t* uid, uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t bn; + + bn = blockNum; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, &bn, sizeof(uint8_t), rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN]; + uint8_t dataLen; + + dataLen = 0; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */ + data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK, (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT), RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */ + data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */ + data[dataLen++] = numOfBlocks; /* Set number of blocks to read */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS, (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT), RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint8_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = firstBlockNum; /* Set first Block Number */ + data[dataLen++] = numOfBlocks; /* Set number of blocks to read */ + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock( uint8_t flags, const uint8_t* uid, uint16_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */ + data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU); + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks( uint8_t flags, const uint8_t* uid, uint16_t firstBlockNum, uint16_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)]; + uint8_t dataLen; + + dataLen = 0U; + + /* Compute Request Data */ + data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU); + data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU); + data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU); + data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU); + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerReadConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ) +{ + return rfalST25xVPollerGenericReadConfiguration(RFAL_NFCV_CMD_READ_CONFIGURATION, flags, uid, pointer, regValue ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerWriteConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ) +{ + return rfalST25xVPollerGenericWriteConfiguration( RFAL_NFCV_CMD_WRITE_CONFIGURATION, flags, uid, pointer, regValue); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerReadDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ) +{ + return rfalST25xVPollerGenericReadConfiguration(RFAL_NFCV_CMD_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerWriteDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ) +{ + return rfalST25xVPollerGenericWriteConfiguration( RFAL_NFCV_CMD_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastReadDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t* regValue ) +{ + return rfalST25xVPollerGenericReadConfiguration(RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration( uint8_t flags, const uint8_t* uid, uint8_t pointer, uint8_t regValue ) +{ + return rfalST25xVPollerGenericWriteConfiguration( RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerPresentPassword( uint8_t flags, const uint8_t* uid, uint8_t pwdNum, const uint8_t *pwd, uint8_t pwdLen) +{ + uint8_t data[RFAL_ST25xV_PWDNUM_LEN + RFAL_ST25xV_PWD_LEN]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + if( (pwdLen > RFAL_ST25xV_PWD_LEN) || (pwd == NULL) ) + { + return RFAL_ERR_PARAM; + } + + dataLen = 0U; + data[dataLen++] = pwdNum; + if( pwdLen > 0U ) + { + RFAL_MEMCPY(&data[dataLen], pwd, pwdLen); + } + dataLen += pwdLen; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_PRESENT_PASSWORD, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); + +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerWritePassword( uint8_t flags, const uint8_t* uid, uint8_t pwdNum, const uint8_t *pwd, uint8_t pwdLen) +{ + uint8_t data[RFAL_ST25xV_PWDNUM_LEN + RFAL_ST25xV_PWD_LEN]; + uint8_t dataLen; + uint16_t rcvLen; + rfalNfcvGenericRes res; + + if( (pwdLen > RFAL_ST25xV_PWD_LEN) || (pwd == NULL) ) + { + return RFAL_ERR_PARAM; + } + + dataLen = 0U; + data[dataLen++] = pwdNum; + if( pwdLen > 0U ) + { + RFAL_MEMCPY(&data[dataLen], pwd, pwdLen); + } + dataLen += pwdLen; + + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_WRITE_PASSWORD, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen ); + +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerGetRandomNumber( uint8_t flags, const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + rfalFieldOff(); + platformDelay(RFAL_ST25TV02K_TRF_OFF); + rfalNfcvPollerInitialize(); + rfalFieldOnAndStartGT(); + platformDelay(RFAL_ST25TV02K_TBOOT_RF); + return rfalNfcvPollerTransceiveReq( RFAL_NFCV_CMD_GET_RANDOM_NUMBER, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, NULL, 0U, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerWriteMessage( uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ) +{ + return rfalST25xVPollerGenericWriteMessage( RFAL_NFCV_CMD_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastWriteMessage( uint8_t flags, const uint8_t* uid, uint8_t msgLen, const uint8_t* msgData, uint8_t* txBuf, uint16_t txBufLen ) +{ + return rfalST25xVPollerGenericWriteMessage( RFAL_NFCV_CMD_FAST_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerReadMessageLength( uint8_t flags, const uint8_t* uid, uint8_t* msgLen ) +{ + return rfalST25xVPollerGenericReadMessageLength(RFAL_NFCV_CMD_READ_MESSAGE_LENGTH, flags, uid, msgLen); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastReadMsgLength( uint8_t flags, const uint8_t* uid, uint8_t* msgLen ) +{ + return rfalST25xVPollerGenericReadMessageLength(RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH, flags, uid, msgLen); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerReadMessage( uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + return rfalST25xVPollerGenericReadMessage(RFAL_NFCV_CMD_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen ); +} + +/*******************************************************************************/ +ReturnCode rfalST25xVPollerFastReadMessage( uint8_t flags, const uint8_t* uid, uint8_t mbPointer, uint8_t numBytes, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) +{ + return rfalST25xVPollerGenericReadMessage(RFAL_NFCV_CMD_FAST_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen ); +} + +#endif /* RFAL_FEATURE_ST25xV */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t1t.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t1t.c new file mode 100644 index 0000000..68c1a65 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t1t.c @@ -0,0 +1,217 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t1t.c + * + * \author Gustavo Patricio + * + * \brief Provides NFC-A T1T convenience methods and definitions + * + * This module provides an interface to perform as a NFC-A Reader/Writer + * to handle a Type 1 Tag T1T (Topaz) + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_t1t.h" +#include "rfal_utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_T1T + */ + +#if RFAL_FEATURE_T1T + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_T1T_DRD_READ (1236U*2U) /*!< DRD for Reads with n=9 => 1236/fc ~= 91 us T1T 1.2 4.4.2 */ +#define RFAL_T1T_DRD_WRITE 36052U /*!< DRD for Write with n=281 => 36052/fc ~= 2659 us T1T 1.2 4.4.2 */ +#define RFAL_T1T_DRD_WRITE_E 70996U /*!< DRD for Write/Erase with n=554 => 70996/fc ~= 5236 us T1T 1.2 4.4.2 */ + +#define RFAL_T1T_RID_RES_HR0_VAL 0x10U /*!< HR0 indicating NDEF support Digital 2.0 (Candidate) 11.6.2.1 */ +#define RFAL_T1T_RID_RES_HR0_MASK 0xF0U /*!< HR0 most significant nibble mask */ + +/* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! NFC-A T1T (Topaz) RID_REQ Digital 1.1 10.6.1 & Table 49 */ +typedef struct +{ + uint8_t cmd; /*!< T1T cmd: RID */ + uint8_t add; /*!< ADD: undefined value */ + uint8_t data; /*!< DATA: undefined value */ + uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID-echo: undefined value */ +} rfalT1TRidReq; + + +/*! NFC-A T1T (Topaz) RALL_REQ T1T 1.2 Table 4 */ +typedef struct +{ + uint8_t cmd; /*!< T1T cmd: RALL */ + uint8_t add1; /*!< ADD: 0x00 */ + uint8_t add0; /*!< ADD: 0x00 */ + uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID */ +} rfalT1TRallReq; + + +/*! NFC-A T1T (Topaz) WRITE_REQ T1T 1.2 Table 4 */ +typedef struct +{ + uint8_t cmd; /*!< T1T cmd: RALL */ + uint8_t add; /*!< ADD */ + uint8_t data; /*!< DAT */ + uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID */ +} rfalT1TWriteReq; + + +/*! NFC-A T1T (Topaz) WRITE_RES T1T 1.2 Table 4 */ +typedef struct +{ + uint8_t add; /*!< ADD */ + uint8_t data; /*!< DAT */ +} rfalT1TWriteRes; + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +ReturnCode rfalT1TPollerInitialize( void ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR(ret, rfalSetMode( RFAL_MODE_POLL_NFCA_T1T, RFAL_BR_106, RFAL_BR_106 ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NONE ); + + rfalSetGT( RFAL_GT_NONE ); /* T1T should only be initialized after NFC-A mode, therefore the GT has been fulfilled */ + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCA_POLLER ); /* T1T uses NFC-A FDT Listen with n=9 Digital 1.1 10.7.2 */ + rfalSetFDTPoll( RFAL_FDT_POLL_NFCA_T1T_POLLER ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalT1TPollerRid( rfalT1TRidRes *ridRes ) +{ + ReturnCode ret; + rfalT1TRidReq ridReq; + uint16_t rcvdLen; + + if( ridRes == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Compute RID command and set Undefined Values to 0x00 Digital 1.1 10.6.1 */ + RFAL_MEMSET( &ridReq, 0x00, sizeof(rfalT1TRidReq) ); + ridReq.cmd = (uint8_t)RFAL_T1T_CMD_RID; + + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTxRx( (uint8_t*)&ridReq, sizeof(rfalT1TRidReq), (uint8_t*)ridRes, sizeof(rfalT1TRidRes), &rcvdLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_T1T_DRD_READ ) ); + + /* Check expected RID response length and the HR0 Digital 2.0 (Candidate) 11.6.2.1 */ + if( (rcvdLen != sizeof(rfalT1TRidRes)) || ((ridRes->hr0 & RFAL_T1T_RID_RES_HR0_MASK) != RFAL_T1T_RID_RES_HR0_VAL) ) + { + return RFAL_ERR_PROTO; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalT1TPollerRall( const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxRcvdLen ) +{ + rfalT1TRallReq rallReq; + + if( (rxBuf == NULL) || (uid == NULL) || (rxRcvdLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /* Compute RALL command and set Add to 0x00 */ + RFAL_MEMSET( &rallReq, 0x00, sizeof(rfalT1TRallReq) ); + rallReq.cmd = (uint8_t)RFAL_T1T_CMD_RALL; + RFAL_MEMCPY(rallReq.uid, uid, RFAL_T1T_UID_LEN); + + return rfalTransceiveBlockingTxRx( (uint8_t*)&rallReq, sizeof(rfalT1TRallReq), (uint8_t*)rxBuf, rxBufLen, rxRcvdLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_T1T_DRD_READ ); +} + + +/*******************************************************************************/ +ReturnCode rfalT1TPollerWrite( const uint8_t* uid, uint8_t address, uint8_t data ) +{ + rfalT1TWriteReq writeReq; + rfalT1TWriteRes writeRes; + uint16_t rxRcvdLen; + ReturnCode err; + + if( uid == NULL ) + { + return RFAL_ERR_PARAM; + } + + writeReq.cmd = (uint8_t)RFAL_T1T_CMD_WRITE_E; + writeReq.add = address; + writeReq.data = data; + RFAL_MEMCPY(writeReq.uid, uid, RFAL_T1T_UID_LEN); + + err = rfalTransceiveBlockingTxRx( (uint8_t*)&writeReq, sizeof(rfalT1TWriteReq), (uint8_t*)&writeRes, sizeof(rfalT1TWriteRes), &rxRcvdLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_T1T_DRD_WRITE_E ); + + if( err == RFAL_ERR_NONE ) + { + if( (writeReq.add != writeRes.add) || (writeReq.data != writeRes.data) || (rxRcvdLen != sizeof(rfalT1TWriteRes)) ) + { + return RFAL_ERR_PROTO; + } + } + return err; +} + +#endif /* RFAL_FEATURE_T1T */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t2t.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t2t.c new file mode 100644 index 0000000..f0c5503 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t2t.c @@ -0,0 +1,238 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2018 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t2t.c + * + * \author + * + * \brief Provides NFC-A T2T convenience methods and definitions + * + * This module provides an interface to perform as a NFC-A Reader/Writer + * to handle a Type 2 Tag T2T + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_t2t.h" +#include "rfal_utils.h" + + /* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_T2T + */ + +#if RFAL_FEATURE_T2T + + /* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + #define RFAL_FDT_POLL_READ_MAX rfalConvMsTo1fc(5U) /*!< Maximum Wait time for Read command as defined in TS T2T 1.0 table 18 */ + #define RFAL_FDT_POLL_WRITE_MAX rfalConvMsTo1fc(10U) /*!< Maximum Wait time for Write command as defined in TS T2T 1.0 table 18 */ + #define RFAL_FDT_POLL_SL_MAX rfalConvMsTo1fc(1U) /*!< Maximum Wait time for Sector Select as defined in TS T2T 1.0 table 18 */ + #define RFAL_T2T_ACK_NACK_LEN 1U /*!< Len of NACK in bytes (4 bits) */ + #define RFAL_T2T_ACK 0x0AU /*!< ACK value */ + #define RFAL_T2T_ACK_MASK 0x0FU /*!< ACK value */ + + + #define RFAL_T2T_SECTOR_SELECT_P1_BYTE2 0xFFU /*!< Sector Select Packet 1 byte 2 */ + #define RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN 3U /*!< Sector Select RFU length */ + + + + /* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + +/*! NFC-A T2T command set T2T 1.0 5.1 */ +typedef enum +{ + RFAL_T2T_CMD_READ = 0x30, /*!< T2T Read */ + RFAL_T2T_CMD_WRITE = 0xA2, /*!< T2T Write */ + RFAL_T2T_CMD_SECTOR_SELECT = 0xC2 /*!< T2T Sector Select */ +} rfalT2Tcmds; + + + /*! NFC-A T2T READ T2T 1.0 5.2 and table 11 */ +typedef struct +{ + uint8_t code; /*!< Command code */ + uint8_t blNo; /*!< Block number */ +} rfalT2TReadReq; + + + /*! NFC-A T2T WRITE T2T 1.0 5.3 and table 12 */ +typedef struct +{ + uint8_t code; /*!< Command code */ + uint8_t blNo; /*!< Block number */ + uint8_t data[RFAL_T2T_WRITE_DATA_LEN]; /*!< Data */ +} rfalT2TWriteReq; + + +/*! NFC-A T2T SECTOR SELECT Packet 1 T2T 1.0 5.4 and table 13 */ +typedef struct +{ + uint8_t code; /*!< Command code */ + uint8_t byte2; /*!< Sector Select Packet 1 byte 2 */ +} rfalT2TSectorSelectP1Req; + + +/*! NFC-A T2T SECTOR SELECT Packet 2 T2T 1.0 5.4 and table 13 */ +typedef struct +{ + uint8_t secNo; /*!< Block number */ + uint8_t rfu[RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN]; /*!< Sector Select Packet RFU */ +} rfalT2TSectorSelectP2Req; + + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + + ReturnCode rfalT2TPollerRead( uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen ) + { + ReturnCode ret; + rfalT2TReadReq req; + + if( (rxBuf == NULL) || (rcvLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + req.code = (uint8_t)RFAL_T2T_CMD_READ; + req.blNo = blockNum; + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, sizeof(rfalT2TReadReq), rxBuf, rxBufLen, rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_READ_MAX ); + + /* T2T 1.0 5.2.1.7 The Reader/Writer SHALL treat a NACK in response to a READ Command as a Protocol Error */ + if( (ret == RFAL_ERR_INCOMPLETE_BYTE) && (*rcvLen == RFAL_T2T_ACK_NACK_LEN) && ((*rxBuf & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK) ) + { + return RFAL_ERR_PROTO; + } + return ret; + } + + + /*******************************************************************************/ + ReturnCode rfalT2TPollerWrite( uint8_t blockNum, const uint8_t* wrData ) + { + ReturnCode ret; + rfalT2TWriteReq req; + uint8_t res; + uint16_t rxLen; + + req.code = (uint8_t)RFAL_T2T_CMD_WRITE; + req.blNo = blockNum; + RFAL_MEMCPY(req.data, wrData, RFAL_T2T_WRITE_DATA_LEN); + + + /* Transceive WRITE Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, sizeof(rfalT2TWriteReq), &res, sizeof(uint8_t), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_WRITE_MAX ); + + /* Check for a valid ACK */ + if( (ret == RFAL_ERR_INCOMPLETE_BYTE) || (ret == RFAL_ERR_NONE) ) + { + ret = RFAL_ERR_PROTO; + + if( (rxLen == RFAL_T2T_ACK_NACK_LEN) && ((res & RFAL_T2T_ACK_MASK) == RFAL_T2T_ACK) ) + { + ret = RFAL_ERR_NONE; + } + } + + return ret; + } + + + /*******************************************************************************/ + ReturnCode rfalT2TPollerSectorSelect( uint8_t sectorNum ) + { + rfalT2TSectorSelectP1Req p1Req; + rfalT2TSectorSelectP2Req p2Req; + ReturnCode ret; + uint8_t res; + uint16_t rxLen; + + + /* Compute SECTOR SELECT Packet 1 */ + p1Req.code = (uint8_t)RFAL_T2T_CMD_SECTOR_SELECT; + p1Req.byte2 = RFAL_T2T_SECTOR_SELECT_P1_BYTE2; + + /* Transceive SECTOR SELECT Packet 1 */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&p1Req, sizeof(rfalT2TSectorSelectP1Req), &res, sizeof(uint8_t), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_SL_MAX ); + + /* Check and report any transmission error */ + if( (ret != RFAL_ERR_INCOMPLETE_BYTE) && (ret != RFAL_ERR_NONE) ) + { + return ret; + } + + /* Ensure that an ACK was received */ + if( (ret != RFAL_ERR_INCOMPLETE_BYTE) || (rxLen != RFAL_T2T_ACK_NACK_LEN) || ((res & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK) ) + { + return RFAL_ERR_PROTO; + } + + + /* Compute SECTOR SELECT Packet 2 */ + p2Req.secNo = sectorNum; + RFAL_MEMSET( &p2Req.rfu, 0x00, RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN ); + + + /* Transceive SECTOR SELECT Packet 2 */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&p2Req, sizeof(rfalT2TSectorSelectP2Req), &res, sizeof(uint8_t), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_SL_MAX ); + + /* T2T 1.0 5.4.1.14 The Reader/Writer SHALL treat any response received before the end of PATT2T,SL,MAX as a Protocol Error */ + if( (ret == RFAL_ERR_NONE) || (ret == RFAL_ERR_INCOMPLETE_BYTE) ) + { + return RFAL_ERR_PROTO; + } + + /* T2T 1.0 5.4.1.13 The Reader/Writer SHALL treat the transmission of the SECTOR SELECT Command Packet 2 as being successful when it receives no response until PATT2T,SL,MAX. */ + if( ret == RFAL_ERR_TIMEOUT ) + { + return RFAL_ERR_NONE; + } + + return ret; + } + +#endif /* RFAL_FEATURE_T2T */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t4t.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t4t.c new file mode 100644 index 0000000..709a426 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/rfal_t4t.c @@ -0,0 +1,425 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2018 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_t4t.h + * + * \author Gustavo Patricio + * + * \brief Provides convenience methods and definitions for T4T (ISO7816-4) + * + * This module provides an interface to exchange T4T APDUs according to + * NFC Forum T4T and ISO7816-4 + * + * This implementation was based on the following specs: + * - ISO/IEC 7816-4 3rd Edition 2013-04-15 + * - NFC Forum T4T Technical Specification 1.0 2017-08-28 + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ + #include "rfal_t4t.h" + #include "rfal_utils.h" + + /* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +/* Feature switch may be enabled or disabled by user at rfal_platform.h + * Default configuration (ST25R dependant) also provided at rfal_defConfig.h + * + * RFAL_FEATURE_T4T + */ + +#if RFAL_FEATURE_T4T + + /* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ +#define RFAL_T4T_OFFSET_DO 0x54U /*!< Tag value for offset BER-TLV data object */ +#define RFAL_T4T_LENGTH_DO 0x03U /*!< Len value for offset BER-TLV data object */ +#define RFAL_T4T_DATA_DO 0x53U /*!< Tag value for data BER-TLV data object */ + +#define RFAL_T4T_MAX_LC 255U /*!< Maximum Lc value for short Lc coding */ + /* +****************************************************************************** +* GLOBAL TYPES +****************************************************************************** +*/ + + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + + +/* + ****************************************************************************** + * LOCAL VARIABLES + ****************************************************************************** + */ + + +/* + ****************************************************************************** + * GLOBAL FUNCTIONS + ****************************************************************************** + */ + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeCAPDU( const rfalT4tCApduParam *apduParam ) +{ + uint8_t hdrLen; + uint16_t msgIt; + + if( (apduParam == NULL) || (apduParam->cApduBuf == NULL) || (apduParam->cApduLen == NULL) ) + { + return RFAL_ERR_PARAM; + } + + msgIt = 0; + *(apduParam->cApduLen) = 0; + + /*******************************************************************************/ + /* Compute Command-APDU according to the format T4T 1.0 5.1.2 & ISO7816-4 2013 Table 1 */ + + /* Check if Data is present */ + if( apduParam->LcFlag ) + { + if( apduParam->Lc == 0U ) + { + /* Extented field coding not supported */ + return RFAL_ERR_PARAM; + } + + /* Check whether requested Lc fits */ + if( (uint16_t)apduParam->Lc > (uint16_t)(RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_LE_LEN) ) + { + return RFAL_ERR_PARAM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */ + } + + /* Calculate the header length a place the data/body where it should be */ + hdrLen = RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN; + + /* make sure not to exceed buffer size */ + if( ((uint16_t)hdrLen + (uint16_t)apduParam->Lc + (apduParam->LeFlag ? RFAL_T4T_LC_LEN : 0U)) > RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN ) + { + return RFAL_ERR_NOMEM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */ + } + RFAL_MEMMOVE( &apduParam->cApduBuf->apdu[hdrLen], apduParam->cApduBuf->apdu, apduParam->Lc ); + } + + /* Prepend the ADPDU's header */ + apduParam->cApduBuf->apdu[msgIt++] = apduParam->CLA; + apduParam->cApduBuf->apdu[msgIt++] = apduParam->INS; + apduParam->cApduBuf->apdu[msgIt++] = apduParam->P1; + apduParam->cApduBuf->apdu[msgIt++] = apduParam->P2; + + + /* Check if Data field length is to be added */ + if( apduParam->LcFlag ) + { + apduParam->cApduBuf->apdu[msgIt++] = apduParam->Lc; + msgIt += apduParam->Lc; + } + + /* Check if Expected Response Length is to be added */ + if( apduParam->LeFlag ) + { + apduParam->cApduBuf->apdu[msgIt++] = apduParam->Le; + } + + *(apduParam->cApduLen) = msgIt; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerParseRAPDU( rfalT4tRApduParam *apduParam ) +{ + if( (apduParam == NULL) || (apduParam->rApduBuf == NULL) ) + { + return RFAL_ERR_PARAM; + } + + if( apduParam->rcvdLen < RFAL_T4T_MAX_RAPDU_SW1SW2_LEN ) + { + return RFAL_ERR_PROTO; + } + + apduParam->rApduBodyLen = (apduParam->rcvdLen - (uint16_t)RFAL_T4T_MAX_RAPDU_SW1SW2_LEN); + apduParam->statusWord = RFAL_GETU16( &apduParam->rApduBuf->apdu[ apduParam->rApduBodyLen ] ); + + /* Check SW1 SW2 T4T 1.0 5.1.3 NOTE */ + if( apduParam->statusWord == RFAL_T4T_ISO7816_STATUS_COMPLETE ) + { + return RFAL_ERR_NONE; + } + + return RFAL_ERR_REQUEST; +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeSelectAppl( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* aid, uint8_t aidLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + + if( cApduBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h A4h 00h 00h 07h AID 00h */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT; + cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME; + cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE; + cAPDU.Lc = aidLen; + cAPDU.Le = 0x00; + cAPDU.LcFlag = true; + cAPDU.LeFlag = true; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + if( (aid != NULL) && (aidLen > 0U) ) + { + RFAL_MEMCPY( cAPDU.cApduBuf->apdu, aid, aidLen ); + } + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeSelectFile( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + + if( cApduBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h A4h 00h 0Ch 02h FID - */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT; + cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID; + cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA; + cAPDU.Lc = fidLen; + cAPDU.Le = 0x00; + cAPDU.LcFlag = true; + cAPDU.LeFlag = false; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + if( (fid != NULL) && (fidLen > 0U) ) + { + RFAL_MEMCPY( cAPDU.cApduBuf->apdu, fid, fidLen ); + } + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeSelectFileV1Mapping( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + + if( cApduBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h A4h 00h 00h 02h FID - */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT; + cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID; + cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE; + cAPDU.Lc = fidLen; + cAPDU.Le = 0x00; + cAPDU.LcFlag = true; + cAPDU.LeFlag = false; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + if( (fid != NULL) && (fidLen > 0U) ) + { + RFAL_MEMCPY( cAPDU.cApduBuf->apdu, fid, fidLen ); + } + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeReadData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, uint8_t expLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + + RFAL_MEMSET( &cAPDU, 0x00, sizeof(rfalT4tCApduParam) ); + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h B0h [Offset] - - len */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY; + cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU); + cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU); + cAPDU.Le = expLen; + cAPDU.LcFlag = false; + cAPDU.LeFlag = true; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeReadDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, uint8_t expLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + uint8_t dataIt; + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h B1h 00h 00h Lc 54 03 xxyyzz len */ + /* [Offset] */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY_ODO; + cAPDU.P1 = 0x00U; + cAPDU.P2 = 0x00U; + cAPDU.Le = expLen; + cAPDU.LcFlag = true; + cAPDU.LeFlag = true; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + dataIt = 0U; + cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO; + cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO; + cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U); + cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U); + cApduBuf->apdu[dataIt++] = (uint8_t)(offset); + cAPDU.Lc = dataIt; + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeWriteData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + + if( cApduBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + RFAL_MEMSET( &cAPDU, 0x00, sizeof(rfalT4tCApduParam) ); + + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h D6h [Offset] len Data - */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY; + cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU); + cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU); + cAPDU.Lc = dataLen; + cAPDU.LcFlag = true; + cAPDU.LeFlag = false; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + if( (data != NULL) && (dataLen > 0U) ) + { + RFAL_MEMCPY( cAPDU.cApduBuf->apdu, data, dataLen ); + } + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + +/*******************************************************************************/ +ReturnCode rfalT4TPollerComposeWriteDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen ) +{ + rfalT4tCApduParam cAPDU; + uint8_t dataIt; + + if( cApduBuf == NULL ) + { + return RFAL_ERR_PARAM; + } + + RFAL_MEMSET( &cAPDU, 0x00, sizeof(rfalT4tCApduParam) ); + + /* CLA INS P1 P2 Lc Data Le */ + /* 00h D7h 00h 00h len 54 03 xxyyzz 53 Ld data - */ + /* [offset] [data] */ + cAPDU.CLA = RFAL_T4T_CLA; + cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY_ODO; + cAPDU.P1 = 0x00U; + cAPDU.P2 = 0x00U; + cAPDU.LcFlag = true; + cAPDU.LeFlag = false; + cAPDU.cApduBuf = cApduBuf; + cAPDU.cApduLen = cApduLen; + + dataIt = 0U; + cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO; + cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO; + cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U); + cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U); + cApduBuf->apdu[dataIt++] = (uint8_t)(offset); + cApduBuf->apdu[dataIt++] = RFAL_T4T_DATA_DO; + cApduBuf->apdu[dataIt++] = dataLen; + + if( (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_T4T_MAX_LC) || (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) ) + { + return (RFAL_ERR_NOMEM); + } + + if( (data != NULL) && (dataLen > 0U) ) + { + RFAL_MEMCPY( &cAPDU.cApduBuf->apdu[dataIt], data, dataLen ); + } + dataIt += dataLen; + cAPDU.Lc = dataIt; + + return rfalT4TPollerComposeCAPDU( &cAPDU ); +} + +#endif /* RFAL_FEATURE_T4T */ diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/rfal_analogConfigTbl.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/rfal_analogConfigTbl.h new file mode 100644 index 0000000..3f85736 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/rfal_analogConfigTbl.h @@ -0,0 +1,423 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + +/* + * PROJECT: ST25R391x firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file rfal_analogConfig.h + * + * \author bkam + * + * \brief ST25R3911 Analog Configuration Settings + * + */ + +#ifndef ST25R3911_ANALOGCONFIG_H +#define ST25R3911_ANALOGCONFIG_H + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include "rfal_analogConfig.h" +#include "st25r3911_com.h" + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + +/*! Macro for Configuration Setting with only one register-mask-value set: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1] */ +#define MODE_ENTRY_1_REG(MODE, R0, M0, V0) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 1, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) + +/*! Macro for Configuration Setting with only two register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1] */ +#define MODE_ENTRY_2_REG(MODE, R0, M0, V0, R1, M1, V1) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 2, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) + +/*! Macro for Configuration Setting with only three register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_3_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 3, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) + +/*! Macro for Configuration Setting with only four register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_4_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 4, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) + +/*! Macro for Configuration Setting with only five register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_5_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 5, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) + +/*! Macro for Configuration Setting with only six register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_6_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 6, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) + +/*! Macro for Configuration Setting with only seven register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_7_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 7, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) + +/*! Macro for Configuration Setting with only eight register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_8_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 8, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) + +/*! Macro for Configuration Setting with only nine register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_9_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7, R8, M8, V8) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 9, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) \ + , (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8) + +/*! Macro for Configuration Setting with only ten register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_10_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7, R8, M8, V8, R9, M9, V9) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU),10, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) \ + , (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8) \ + , (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9) + +/*! Macro for Configuration Setting with eleven register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_11_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7, R8, M8, V8, R9, M9, V9, R10, M10, V10) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU),11, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) \ + , (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8) \ + , (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9) \ + , (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10), (uint8_t)(V10) + +/*! Macro for Configuration Setting with twelve register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_12_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7, R8, M8, V8, R9, M9, V9, R10, M10, V10, R11, M11, V11) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU),12, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) \ + , (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8) \ + , (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9) \ + , (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10), (uint8_t)(V10) \ + , (uint8_t)((uint16_t)(R11) >> 8U), (uint8_t)((R11) & 0xFFU), (uint8_t)(M11), (uint8_t)(V11) + +/*! Macro for Configuration Setting with thirteen register-mask-value sets: + * - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */ +#define MODE_ENTRY_13_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6, R7, M7, V7, R8, M8, V8, R9, M9, V9, R10, M10, V10, R11, M11, V11, R12, M12, V12) \ + (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU),13, (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0) \ + , (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1) \ + , (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2) \ + , (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3) \ + , (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4) \ + , (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5) \ + , (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6) \ + , (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7) \ + , (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8) \ + , (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9) \ + , (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10), (uint8_t)(V10) \ + , (uint8_t)((uint16_t)(R11) >> 8U), (uint8_t)((R11) & 0xFFU), (uint8_t)(M11), (uint8_t)(V11) \ + , (uint8_t)((uint16_t)(R12) >> 8U), (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12) + +/* Setting for approximately 14%: */ +#define AM_MOD_DRIVER_LEVEL_DEFAULT 0xb9 +/* + ****************************************************************************** + * GLOBAL DATA TYPES + ****************************************************************************** + */ + +/* PRQA S 3674 2 # CERT ARR02 - Flexible array will be used with sizeof, on adding elements error-prone manual update of size would be required */ +/* PRQA S 3406 1 # MISRA 8.6 - Externally generated table included by the library */ /* PRQA S 1514 1 # MISRA 8.9 - Externally generated table included by the library */ + const uint8_t rfalAnalogConfigDefaultSettings[] = { + /****** Default Analog Configuration for Chip-Specific Reset. ******/ + MODE_ENTRY_10_REG( (uint32_t)(RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT) + , ST25R3911_REG_OP_CONTROL, 0x30, 0x10 /* default to AM */ + , ST25R3911_REG_IO_CONF1, 0x06, 0x06 /* MCUCLK: HF clk off */ + , ST25R3911_REG_IO_CONF1, (ST25R3911_REG_IO_CONF1_mask_out_cl | ST25R3911_REG_IO_CONF1_lf_clk_off), 0x07 /* MCUCLK: LF clk off */ + , ST25R3911_REG_IO_CONF2, 0x18, 0x18 /* pull downs */ + , ST25R3911_REG_RX_CONF4, ST25R3911_REG_RX_CONF4_mask_rg2_pm, 0x1U< 0xFFFF * 590ns = 38,7ms) */ +#define RFAL_ST25R3911_NRT_MAX_1FC rfalConv4096fcTo1fc( 0xFFFFU ) /*!< Max NRT steps in 1fc (0xFFFF steps of 4096/fc => 0xFFFF * 302us = 19.8s ) */ +#define RFAL_ST25R3911_NRT_DISABLED 0U /*!< NRT Disabled: All 0 No-response timer is not started, wait forever */ +#define RFAL_ST25R3911_MRT_MAX_1FC rfalConv64fcTo1fc( 0x00FFU ) /*!< Max MRT steps in 1fc (0x00FF steps of 64/fc => 0x00FF * 4.72us = 1.2ms ) */ +#define RFAL_ST25R3911_MRT_MIN_1FC rfalConv64fcTo1fc( 0x0004U ) /*!< Min MRT steps in 1fc ( 0<=mrt<=4 ; 4 (64/fc) => 0x0004 * 4.72us = 18.88us ) */ +#define RFAL_ST25R3911_GT_MAX_1FC rfalConvMsTo1fc( 6000U ) /*!< Max GT value allowed in 1/fc (SFGI=14 => SFGT + dSFGT = 5.4s) */ +#define RFAL_ST25R3911_GT_MIN_1FC rfalConvMsTo1fc(RFAL_ST25R3911_SW_TMR_MIN_1MS) /*!< Min GT value allowed in 1/fc */ +#define RFAL_ST25R3911_SW_TMR_MIN_1MS 1U /*!< Min value of a SW timer in ms */ + +#define RFAL_OBSMODE_DISABLE 0x00U /*!< Observation Mode disabled */ + +#define RFAL_RX_INC_BYTE_LEN (uint8_t)1U /*!< Threshold value where incoming rx shall be considered incomplete byte NFC - T2T */ +#define RFAL_EMVCO_RX_MAXLEN (uint8_t)4U /*!< Maximum value where EMVCo to apply special error handling */ +#define RFAL_EMVCO_RX_MINLEN (uint8_t)2U /*!< Minimum value where EMVCo to apply special error handling */ + +#define RFAL_NORXE_TOUT 10U /*!< Timeout to be used on a potential missing RXE - Silicon ST25R3911B Errata #1.1 */ + +#define RFAL_ISO14443A_SDD_RES_LEN 5U /*!< SDD_RES | Anticollision (UID CLn) length - rfalNfcaSddRes */ + +#define RFAL_FELICA_POLL_DELAY_TIME 512U /*!< FeliCa Poll Processing time is 2.417 ms ~512*64/fc Digital 1.1 A4 */ +#define RFAL_FELICA_POLL_SLOT_TIME 256U /*!< FeliCa Poll Time Slot duration is 1.208 ms ~256*64/fc Digital 1.1 A4 */ + +#define RFAL_ISO15693_IGNORE_BITS rfalConvBytesToBits(2U) /*!< Ignore collisions before the UID (RES_FLAG + DSFID) */ + + +/*******************************************************************************/ + +#define RFAL_LM_GT rfalConvUsTo1fc(100U) /*!< Listen Mode Guard Time enforced (GT - Passive; TIRFG - Active) */ +#define RFAL_FDT_POLL_ADJUSTMENT rfalConvUsTo1fc(80U) /*!< FDT Poll adjustment: Time between the expiration of GPT to the actual Tx */ +#define RFAL_FDT_LISTEN_MRT_ADJUSTMENT 64U /*!< MRT jitter adjustment: timeout will be between [ tout ; tout + 64 cycles ] */ +#define RFAL_AP2P_FIELDOFF_TCMDOFF 1356U /*!< Time after TXE and Field Off t,CMD,OFF Activity 2.1 3.2.1.3 & C */ + + +/*! FWT adjustment: + * 64 : NRT jitter between TXE and NRT start */ +#define RFAL_FWT_ADJUSTMENT 64U + +/*! FWT ISO14443A adjustment: + * 512 : Initial 4bit length */ +#define RFAL_FWT_A_ADJUSTMENT 512U + +/*! FWT ISO14443B adjustment: + * 2784 : Adjustment for the SOF and initial byte */ +#define RFAL_FWT_B_ADJUSTMENT 2784U + + +/*! FWT FeliCa 212 adjustment: + * 1024 : Length of the two Sync bytes at 212kbps */ +#define RFAL_FWT_F_212_ADJUSTMENT 1024U + +/*! FWT FeliCa 424 adjustment: + * 512 : Length of the two Sync bytes at 424kbps */ +#define RFAL_FWT_F_424_ADJUSTMENT 512U + + +/*! Time between our field Off and other peer field On : Tadt + (n x Trfw) + * Ecma 340 11.1.2 - Tadt: [56.64 , 188.72] us ; n: [0 , 3] ; Trfw = 37.76 us + * Should be: 189 + (3*38) = 303us ; we'll use a more relaxed setting: 605 us */ +#define RFAL_AP2P_FIELDON_TADTTRFW rfalConvUsTo1fc(605U) + + +/*! FDT Listen adjustment for ISO14443A EMVCo 2.6 4.8.1.3 ; Digital 1.1 6.10 + * + * 276: Time from the rising pulse of the pause of the logic '1' (i.e. the time point to measure the deaftime from), + * to the actual end of the EOF sequence (the point where the MRT starts). Please note that the ST25R391x uses the + * ISO14443-2 definition where the EOF consists of logic '0' followed by sequence Y. + */ +#define RFAL_FDT_LISTEN_A_ADJUSTMENT 276U + + +/*! FDT Listen adjustment for ISO14443B EMVCo 2.6 4.8.1.6 ; Digital 1.1 7.9 + * + * 340: Time from the rising edge of the EoS to the starting point of the MRT timer (sometime after the final high + * part of the EoS is completed). + * + * -64: Adjustment for the TR1PUTMIN. + * The TR1PUTMIN of the ST25R3911 is 1152/fc (72/fs). The EMVCo test case TB0000 measures the TR1PUTMIN. + * It takes the default value of TR1PUTMIN (79/fs) and reduces it by 128/fc in every iteration. + * This results in a TR1PUTMIN of 1136/fc (71/fs) for the second iteration. The ST25R3911 sends a NAK because + * the TR1PUTMIN of the ST25R3911 (72/fs) is higher than 71/fs. + * Therefore the test suite assumes TR1PUTMIN of 1264/fc (79/fs). + * The test cases TB340.0 and TB435.0 uses the TR1PUTMIN to send frames too early. In order to correctly + * recognise these frames as being sent too early (starting inside reader deaf time), the MRT has to be + * increased by at least 64/fc (8/fs). + */ +#define RFAL_FDT_LISTEN_B_ADJUSTMENT (340U - 64U) + + +/*! FDT Listen adjustment for ISO15693 + * ISO15693 2000 8.4 t1 MIN = 4192/fc + * ISO15693 2009 9.1 t1 MIN = 4320/fc + * Digital 2.1 B.5 FDTV,LISTEN,MIN = 4310/fc + * Set FDT Listen one step earlier than on the more recent spec versions for greater interoprability + */ +#define RFAL_FDT_LISTEN_V_ADJUSTMENT 128U + + + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +/*! Calculates Transceive Sanity Timer. It accounts for the slowest bit rate and the longest data format + * 1s for transmission and reception of a 4K message at 106kpbs (~425ms each direction) + * plus TxRx preparation and FIFO load over Serial Interface + */ +#define rfalCalcSanityTmr( fwt ) (uint16_t)(1000U + rfalConv1fcToMs((fwt))) + +#define rfalGennTRFW( n ) ((uint8_t)(((n)+1U)%7U)) /*!< Generate next n*TRFW used for RFCA: modulo a prime to avoid alias effects */ + +#define rfalCalcNumBytes( nBits ) (((uint32_t)(nBits) + 7U) / 8U) /*!< Returns the number of bytes required to fit given the number of bits */ + +#define rfalTimerStart( timer, time_ms ) do{ platformTimerDestroy( timer ); (timer) = platformTimerCreate((uint16_t)(time_ms)); } while(0) /*!< Configures and starts timer */ +#define rfalTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks if timer has expired */ +#define rfalTimerDestroy( timer ) platformTimerDestroy( timer ) /*!< Destroys timer */ + +#define rfalST25R3911ObsModeDisable() st25r3911WriteTestRegister(0x01U, 0x00U) /*!< Disable ST25R3911 Observation mode */ +#define rfalST25R3911ObsModeTx() st25r3911WriteTestRegister(0x01U, gRFAL.conf.obsvModeTx) /*!< Enable Observation mode 0x0A CSI: Digital TX modulation signal CSO: none */ +#define rfalST25R3911ObsModeRx() st25r3911WriteTestRegister(0x01U, gRFAL.conf.obsvModeRx) /*!< Enable Observation mode 0x04 CSI: Digital output of AM channel CSO: Digital output of PM channel */ + + +#define rfalCheckDisableObsMode() if(gRFAL.conf.obsvModeRx != 0U){ rfalST25R3911ObsModeDisable(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3911 */ +#define rfalCheckEnableObsModeTx() if(gRFAL.conf.obsvModeTx != 0U){ rfalST25R3911ObsModeTx(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3911 */ +#define rfalCheckEnableObsModeRx() if(gRFAL.conf.obsvModeRx != 0U){ rfalST25R3911ObsModeRx(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3911 */ + + +#define rfalGetIncmplBits( FIFOStatus2 ) (( (FIFOStatus2) >> 1) & 0x07U) /*!< Returns the number of bits from fifo status */ +#define rfalIsIncompleteByteError( error ) (((error) >= RFAL_ERR_INCOMPLETE_BYTE) && ((error) <= RFAL_ERR_INCOMPLETE_BYTE_07)) /*!< Checks if given error is a Incomplete error */ + +#define rfalAdjACBR( b ) (((uint16_t)(b) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(b) : ((uint16_t)(b)+1U)) /*!< Adjusts ST25R391x Bit rate to Analog Configuration */ +#define rfalConvBR2ACBR( b ) (((rfalAdjACBR((b)))<din; + st25rStreamConf.dout = rfalIso15693StreamConfig->dout; + st25rStreamConf.report_period_length = rfalIso15693StreamConfig->report_period_length; + st25rStreamConf.useBPSK = rfalIso15693StreamConfig->useBPSK; + st25r3911StreamConfigure(&st25rStreamConf); + } + + /* Set Analog configurations for this bit rate */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX ) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX ) ); + break; + + #endif /* RFAL_FEATURE_NFCV */ + + + /*******************************************************************************/ + case RFAL_MODE_POLL_ACTIVE_P2P: + + /* Set Analog configurations for this bit rate */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX ) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX ) ); + break; + + /*******************************************************************************/ + case RFAL_MODE_LISTEN_ACTIVE_P2P: + + /* Set Analog configurations for this bit rate */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX ) ); + rfalSetAnalogConfig( (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX ) ); + break; + + /*******************************************************************************/ + case RFAL_MODE_LISTEN_NFCA: + case RFAL_MODE_LISTEN_NFCB: + case RFAL_MODE_LISTEN_NFCF: + case RFAL_MODE_NONE: + return RFAL_ERR_WRONG_STATE; + + /*******************************************************************************/ + default: + return RFAL_ERR_NOT_IMPLEMENTED; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalGetBitRate( rfalBitRate *txBR, rfalBitRate *rxBR ) +{ + if( (gRFAL.state == RFAL_STATE_IDLE) || (gRFAL.mode == RFAL_MODE_NONE) ) + { + return RFAL_ERR_WRONG_STATE; + } + + if( txBR != NULL ) + { + *txBR = gRFAL.txBR; + } + + if( rxBR != NULL ) + { + *rxBR = gRFAL.rxBR; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +void rfalSetErrorHandling( rfalEHandling eHandling ) +{ + gRFAL.conf.eHandling = eHandling; +} + + +/*******************************************************************************/ +rfalEHandling rfalGetErrorHandling( void ) +{ + return gRFAL.conf.eHandling; +} + + +/*******************************************************************************/ +void rfalSetFDTPoll( uint32_t FDTPoll ) +{ + gRFAL.timings.FDTPoll = RFAL_MIN( FDTPoll, RFAL_ST25R3911_GPT_MAX_1FC ); +} + + +/*******************************************************************************/ +uint32_t rfalGetFDTPoll( void ) +{ + return gRFAL.timings.FDTPoll; +} + + +/*******************************************************************************/ +void rfalSetFDTListen( uint32_t FDTListen ) +{ + gRFAL.timings.FDTListen = RFAL_MIN( FDTListen, RFAL_ST25R3911_MRT_MAX_1FC); +} + +/*******************************************************************************/ +uint32_t rfalGetFDTListen( void ) +{ + return gRFAL.timings.FDTListen; +} + +void rfalSetGT( uint32_t GT ) +{ + gRFAL.timings.GT = RFAL_MIN( GT, RFAL_ST25R3911_GT_MAX_1FC ); +} + +/*******************************************************************************/ +uint32_t rfalGetGT( void ) +{ + return gRFAL.timings.GT; +} + +/*******************************************************************************/ +bool rfalIsGTExpired( void ) +{ + if( gRFAL.tmr.GT != RFAL_TIMING_NONE ) + { + if( !rfalTimerisExpired( gRFAL.tmr.GT ) ) + { + return false; + } + } + return true; +} + +/*******************************************************************************/ +ReturnCode rfalFieldOnAndStartGT( void ) +{ + ReturnCode ret; + + /* Check if RFAL has been initialized (Oscillator should be running) and also + * if a direct register access has been performed and left the Oscillator Off */ + if( (!st25r3911IsOscOn()) || (gRFAL.state < RFAL_STATE_INIT) ) + { + return RFAL_ERR_WRONG_STATE; + } + + ret = RFAL_ERR_NONE; + + /* Set Analog configurations for Field On event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_ON) ); + + /*******************************************************************************/ + /* Perform collision avoidance and turn field On if not already On */ + if( (!st25r3911IsTxEnabled()) || (!gRFAL.field) ) + { + +#if 0 /* RFCA */ + + /* Use Thresholds set by AnalogConfig */ + ret = st25r3911PerformCollisionAvoidance( ST25R3911_CMD_RESPONSE_RF_COLLISION_0, ST25R3911_THRESHOLD_DO_NOT_SET, ST25R3911_THRESHOLD_DO_NOT_SET, gRFAL.timings.nTRFW ); + +#else /* Manual Field On */ + + if( st25r3911IsExtFieldOn() ) + { + return RFAL_ERR_RF_COLLISION; + } + st25r3911SetRegisterBits( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_tx_en ); + + /* Clear any previous External Field events */ + st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_EON) ); + + +#endif /* Manual | RFCA */ + + /* n * TRFW timing shall vary Activity 2.1 3.3.1.1 */ + gRFAL.timings.nTRFW = rfalGennTRFW( gRFAL.timings.nTRFW ); + + + gRFAL.field = st25r3911IsTxEnabled(); + + /* Only turn on Receiver and Transmitter if field was successfully turned On */ + if( gRFAL.field ) + { + st25r3911TxRxOn(); /* Enable Tx and Rx (Tx is already On) */ + } + } + + /*******************************************************************************/ + /* Start GT timer in case the GT value is set */ + if( (gRFAL.timings.GT != RFAL_TIMING_NONE) ) + { + /* Ensure that a SW timer doesn't have a lower value then the minimum */ + rfalTimerStart( gRFAL.tmr.GT, rfalConv1fcToMs( RFAL_MAX( (gRFAL.timings.GT), RFAL_ST25R3911_GT_MIN_1FC) ) ); + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalFieldOff( void ) +{ + /* Check whether a TxRx is not yet finished */ + if( gRFAL.TxRx.state != RFAL_TXRX_STATE_IDLE ) + { + rfalCleanupTransceive(); + } + + /* Disable Tx and Rx */ + st25r3911TxRxOff(); + + /* Set Analog configurations for Field Off event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF) ); + gRFAL.field = false; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalStartTransceive( const rfalTransceiveContext *ctx ) +{ + uint32_t FxTAdj; /* FWT or FDT adjustment calculation */ + + /* Check for valid parameters */ + if( ctx == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* If parity check is disabled CRC check must be disabled as well */ + if( ((ctx->flags & (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP) != 0U) && ((ctx->flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_MANUAL) == 0U) ) + { + return RFAL_ERR_NOTSUPP; + } + + /* Ensure that RFAL is already Initialized and the mode has been set */ + if( gRFAL.state >= RFAL_STATE_MODE_SET ) + { + /*******************************************************************************/ + /* Check whether the field is already On, otherwise no TXE will be received */ + if( (!st25r3911IsTxEnabled()) && ((!rfalIsModePassiveListen( gRFAL.mode )) && (ctx->txBuf != NULL)) ) + { + return RFAL_ERR_WRONG_STATE; + } + + gRFAL.TxRx.ctx = *ctx; + + /*******************************************************************************/ + if( gRFAL.timings.FDTListen != RFAL_TIMING_NONE ) + { + /* Calculate MRT adjustment accordingly to the current mode */ + FxTAdj = RFAL_FDT_LISTEN_MRT_ADJUSTMENT; + if(gRFAL.mode == RFAL_MODE_POLL_NFCA) { FxTAdj += (uint32_t)RFAL_FDT_LISTEN_A_ADJUSTMENT; } + if(gRFAL.mode == RFAL_MODE_POLL_NFCA_T1T) { FxTAdj += (uint32_t)RFAL_FDT_LISTEN_A_ADJUSTMENT; } + if(gRFAL.mode == RFAL_MODE_POLL_NFCB) { FxTAdj += (uint32_t)RFAL_FDT_LISTEN_B_ADJUSTMENT; } + if(gRFAL.mode == RFAL_MODE_POLL_NFCV) { FxTAdj += (uint32_t)RFAL_FDT_LISTEN_V_ADJUSTMENT; } + + + /* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */ + st25r3911WriteRegister( ST25R3911_REG_MASK_RX_TIMER, (uint8_t)rfalConv1fcTo64fc( (FxTAdj > gRFAL.timings.FDTListen) ? RFAL_ST25R3911_MRT_MIN_1FC : (gRFAL.timings.FDTListen - FxTAdj) ) ); + } + + /*******************************************************************************/ + /* FDT Poll will be loaded in rfalPrepareTransceive() once the previous was expired */ + + /*******************************************************************************/ + if( rfalIsModePassiveComm( gRFAL.mode ) ) /* Passive Comms */ + { + if( (gRFAL.TxRx.ctx.fwt != RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != 0U) ) + { + /* Ensure proper timing configuration */ + if( gRFAL.timings.FDTListen >= gRFAL.TxRx.ctx.fwt ) + { + return RFAL_ERR_PARAM; + } + + FxTAdj = RFAL_FWT_ADJUSTMENT; + if(gRFAL.mode == RFAL_MODE_POLL_NFCA) { FxTAdj += (uint32_t)RFAL_FWT_A_ADJUSTMENT; } + if(gRFAL.mode == RFAL_MODE_POLL_NFCA_T1T) { FxTAdj += (uint32_t)RFAL_FWT_A_ADJUSTMENT; } + if(gRFAL.mode == RFAL_MODE_POLL_NFCB) { FxTAdj += (uint32_t)RFAL_FWT_B_ADJUSTMENT; } + if( (gRFAL.mode == RFAL_MODE_POLL_NFCF) || (gRFAL.mode == RFAL_MODE_POLL_ACTIVE_P2P) ) + { + FxTAdj += (uint32_t)((gRFAL.txBR == RFAL_BR_212) ? RFAL_FWT_F_212_ADJUSTMENT : RFAL_FWT_F_424_ADJUSTMENT ); + } + + /* Ensure that the given FWT doesn't exceed NRT maximum */ + gRFAL.TxRx.ctx.fwt = RFAL_MIN( (gRFAL.TxRx.ctx.fwt + FxTAdj), RFAL_ST25R3911_NRT_MAX_1FC ); + + /* Set FWT in the NRT */ + st25r3911SetNoResponseTime_64fcs( rfalConv1fcTo64fc( gRFAL.TxRx.ctx.fwt ) ); + } + else + { + /* Disable NRT, no NRE will be triggered, therefore wait endlessly for Rx */ + st25r3911SetNoResponseTime_64fcs( RFAL_ST25R3911_NRT_DISABLED ); + } + } + else /* Active Comms */ + { + /* Setup NRT timer for rf response RF collision timeout. */ + st25r3911SetNoResponseTime_64fcs( rfalConv1fcTo64fc(RFAL_AP2P_FIELDON_TADTTRFW) ); + + /* In Active Mode No Response Timer cannot be used to measure FWT a SW timer is used instead */ + } + + + gRFAL.state = RFAL_STATE_TXRX; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_IDLE; + gRFAL.TxRx.status = RFAL_ERR_BUSY; + gRFAL.TxRx.rxse = false; + + #if RFAL_FEATURE_NFCV + /*******************************************************************************/ + if( (RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode) ) + { /* Exchange receive buffer with internal buffer */ + gRFAL.nfcvData.origCtx = gRFAL.TxRx.ctx; + + gRFAL.TxRx.ctx.rxBuf = ((gRFAL.nfcvData.origCtx.rxBuf != NULL) ? gRFAL.nfcvData.codingBuffer : NULL); + gRFAL.TxRx.ctx.rxBufLen = (uint16_t)rfalConvBytesToBits(sizeof(gRFAL.nfcvData.codingBuffer)); + gRFAL.TxRx.ctx.flags = (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL + | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP + | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF + | (uint32_t)(gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF) + | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP + | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE; + + /* In NFCV a TxRx with a valid txBuf and txBufSize==0 indicates to send an EOF */ + /* Skip logic below that would go directly into receive */ + if ( gRFAL.TxRx.ctx.txBuf != NULL ) + { + return RFAL_ERR_NONE; + } + } + #endif /* RFAL_FEATURE_NFCV */ + + + /*******************************************************************************/ + /* Check if the Transceive start performing Tx or goes directly to Rx */ + if( (gRFAL.TxRx.ctx.txBuf == NULL) || (gRFAL.TxRx.ctx.txBufLen == 0U) ) + { + /* Clear FIFO, Clear and Enable the Interrupts */ + rfalPrepareTransceive( ); + + /* In AP2P check the field status */ + if( rfalIsModeActiveComm(gRFAL.mode) ) + { + /* Disable our field upon a Rx reEnable, NRT is restarted below*/ + st25r3911TxOff(); + } + + /* No Tx done, enable the Receiver */ + st25r3911ExecuteCommand( ST25R3911_CMD_UNMASK_RECEIVE_DATA ); + + /* Start NRT manually, if FWT = 0 (wait endlessly for Rx) chip will ignore anyhow */ + st25r3911ExecuteCommand( ST25R3911_CMD_START_NO_RESPONSE_TIMER ); + + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE; + } + + return RFAL_ERR_NONE; + } + + return RFAL_ERR_WRONG_STATE; +} + + +/*******************************************************************************/ +bool rfalIsTransceiveInTx( void ) +{ + return ( (gRFAL.TxRx.state >= RFAL_TXRX_STATE_TX_IDLE) && (gRFAL.TxRx.state < RFAL_TXRX_STATE_RX_IDLE) ); +} + + +/*******************************************************************************/ +bool rfalIsTransceiveInRx( void ) +{ + return (gRFAL.TxRx.state >= RFAL_TXRX_STATE_RX_IDLE); +} + + +/*******************************************************************************/ +ReturnCode rfalTransceiveBlockingTx( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* actLen, uint32_t flags, uint32_t fwt ) +{ + ReturnCode ret; + rfalTransceiveContext ctx; + + rfalCreateByteFlagsTxRxContext( ctx, txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt ); + RFAL_EXIT_ON_ERR( ret, rfalStartTransceive( &ctx ) ); + + return rfalTransceiveRunBlockingTx(); +} + + +/*******************************************************************************/ +static ReturnCode rfalTransceiveRunBlockingTx( void ) +{ + ReturnCode ret; + + do{ + rfalWorker(); + ret = rfalGetTransceiveStatus(); + } + while( (rfalIsTransceiveInTx()) && (ret == RFAL_ERR_BUSY) ); + + if( rfalIsTransceiveInRx() ) + { + return RFAL_ERR_NONE; + } + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalTransceiveBlockingRx( void ) +{ + ReturnCode ret; + + do{ + rfalWorker(); + ret = rfalGetTransceiveStatus(); + } + while( (rfalIsTransceiveInRx()) || (ret == RFAL_ERR_BUSY) ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalTransceiveBlockingTxRx( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* actLen, uint32_t flags, uint32_t fwt ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTx( txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt ) ); + ret = rfalTransceiveBlockingRx(); + + /* Convert received bits to bytes */ + if( actLen != NULL ) + { + *actLen = rfalConvBitsToBytes(*actLen); + } + + return ret; +} + + +/*******************************************************************************/ +static ReturnCode rfalRunTransceiveWorker( void ) +{ + if( gRFAL.state == RFAL_STATE_TXRX ) + { + /*******************************************************************************/ + /* Check Transceive Sanity Timer has expired */ + if( gRFAL.tmr.txRx != RFAL_TIMING_NONE ) + { + if( rfalTimerisExpired( gRFAL.tmr.txRx ) ) + { + /* If sanity timer has expired abort ongoing transceive and signal error */ + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + } + + /*******************************************************************************/ + /* Run Tx or Rx state machines */ + if( rfalIsTransceiveInTx() ) + { + rfalTransceiveTx(); + return rfalGetTransceiveStatus(); + } + + if( rfalIsTransceiveInRx() ) + { + rfalTransceiveRx(); + return rfalGetTransceiveStatus(); + } + } + return RFAL_ERR_WRONG_STATE; +} + +/*******************************************************************************/ +rfalTransceiveState rfalGetTransceiveState( void ) +{ + return gRFAL.TxRx.state; +} + +ReturnCode rfalGetTransceiveStatus( void ) +{ + return ((gRFAL.TxRx.state == RFAL_TXRX_STATE_IDLE) ? gRFAL.TxRx.status : RFAL_ERR_BUSY); +} + + +/*******************************************************************************/ +ReturnCode rfalGetTransceiveRSSI( uint16_t *rssi ) +{ + uint16_t amRSSI; + uint16_t pmRSSI; + + if( rssi == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Check if Manual channel is enabled */ + if( st25r3911CheckReg( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_rx_man, ST25R3911_REG_OP_CONTROL_rx_man ) ) + { + st25r3911GetRSSI( &amRSSI, &pmRSSI ); + + /* Check which channel is selected */ + *rssi = ( st25r3911CheckReg( ST25R3911_REG_RX_CONF1, ST25R3911_REG_RX_CONF1_ch_sel, ST25R3911_REG_RX_CONF1_ch_sel ) ? pmRSSI : amRSSI ); + return RFAL_ERR_NONE; + } + + *rssi = 0; + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +bool rfalIsTransceiveSubcDetected( void ) +{ + return false; +} + + +/*******************************************************************************/ +void rfalWorker( void ) +{ + platformProtectWorker(); /* Protect RFAL Worker/Task/Process */ + + switch( gRFAL.state ) + { + case RFAL_STATE_TXRX: + rfalRunTransceiveWorker(); + break; + + #if RFAL_FEATURE_LISTEN_MODE + case RFAL_STATE_LM: + rfalRunListenModeWorker(); + break; + #endif /* RFAL_FEATURE_LISTEN_MODE */ + + #if RFAL_FEATURE_WAKEUP_MODE + case RFAL_STATE_WUM: + rfalRunWakeUpModeWorker(); + break; + #endif /* RFAL_FEATURE_WAKEUP_MODE */ + + /* Nothing to be done */ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } + + platformUnprotectWorker(); /* Unprotect RFAL Worker/Task/Process */ +} + + +/*******************************************************************************/ +static void rfalErrorHandling( void ) +{ + bool rxHasIncParError; + uint8_t fifoBytesToRead; + const uint8_t reEnRx[2] = { ST25R3911_CMD_CLEAR_FIFO, ST25R3911_CMD_UNMASK_RECEIVE_DATA }; + + + fifoBytesToRead = rfalFIFOStatusGetNumBytes(); + + + /*******************************************************************************/ + /* EMVCo */ + /*******************************************************************************/ + if( gRFAL.conf.eHandling == RFAL_ERRORHANDLING_EMD ) + { + /*******************************************************************************/ + /* EMD Handling - NFC Forum Digital 1.1 4.1.1.1 ; EMVCo 2.6 4.9.2 */ + /* ReEnable the receiver on frames with a length < 4 bytes, upon: */ + /* - Collision or Framing error detected */ + /* - Residual bits are detected (hard framing error) */ + /* - Parity error */ + /* - CRC error */ + /*******************************************************************************/ + + /* Check if reception has incompete bytes or parity error */ + rxHasIncParError = ( rfalFIFOStatusIsIncompleteByte() ? true : rfalFIFOStatusIsMissingPar() ); /* MISRA 13.5 */ + + /* In case there are residual bits decrement FIFO bytes */ + if( (fifoBytesToRead > 0U) && rxHasIncParError) + { + fifoBytesToRead--; + } + + if( ( (gRFAL.fifo.bytesTotal + fifoBytesToRead) < RFAL_EMVCO_RX_MAXLEN ) && + ( (gRFAL.TxRx.status == RFAL_ERR_RF_COLLISION) || (gRFAL.TxRx.status == RFAL_ERR_FRAMING) || + (gRFAL.TxRx.status == RFAL_ERR_PAR) || (gRFAL.TxRx.status == RFAL_ERR_CRC) || + rxHasIncParError ) ) + { + /* Ignore this reception, ReEnable receiver */ + st25r3911ExecuteCommands( reEnRx, sizeof(reEnRx) ); + + + /* Ensure that the NRT has not expired meanwhile */ + if( st25r3911CheckReg( ST25R3911_REG_REGULATOR_RESULT, ST25R3911_REG_REGULATOR_RESULT_nrt_on, 0x00 ) ) + { + if( st25r3911CheckReg( ST25R3911_REG_AUX_DISPLAY, ST25R3911_REG_AUX_DISPLAY_rx_act, 0x00 ) ) + { + /* Abort reception */ + st25r3911ExecuteCommand( ST25R3911_CMD_MASK_RECEIVE_DATA ); + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + return; + } + } + + rfalFIFOStatusClear(); + gRFAL.fifo.bytesTotal = 0; + gRFAL.TxRx.status = RFAL_ERR_BUSY; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS; + } + return; + } + + /*******************************************************************************/ + /* ISO14443A Mode */ + /*******************************************************************************/ + if( gRFAL.mode == RFAL_MODE_POLL_NFCA ) + { + + /*******************************************************************************/ + /* If we received one incomplete byte (not a block and a incomplete byte at * + * the end) we will raise a specific error ( support for T2T 4 bit ACK / NAK ) * + * Otherwise just leave it as an CRC/FRAMING/PAR error */ + /*******************************************************************************/ + if( (gRFAL.TxRx.status == RFAL_ERR_PAR) || (gRFAL.TxRx.status == RFAL_ERR_CRC) ) + { + if( (rfalFIFOStatusIsIncompleteByte()) && (fifoBytesToRead == RFAL_RX_INC_BYTE_LEN) ) + { + st25r3911ReadFifo( (uint8_t*)(gRFAL.TxRx.ctx.rxBuf), fifoBytesToRead ); + if( (gRFAL.TxRx.ctx.rxRcvdLen) != NULL ) + { + *gRFAL.TxRx.ctx.rxRcvdLen = rfalFIFOGetNumIncompleteBits(); + } + + gRFAL.TxRx.status = RFAL_ERR_INCOMPLETE_BYTE; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + } + } + +} + + +/*******************************************************************************/ +static void rfalCleanupTransceive( void ) +{ + /*******************************************************************************/ + /* Transceive flags */ + /*******************************************************************************/ + + /* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity*/ + st25r3911ClrRegisterBits( ST25R3911_REG_ISO14443A_NFC, (ST25R3911_REG_ISO14443A_NFC_no_tx_par | ST25R3911_REG_ISO14443A_NFC_no_rx_par | ST25R3911_REG_ISO14443A_NFC_nfc_f0) ); + + /* Restore AGC enabled */ + st25r3911SetRegisterBits( ST25R3911_REG_RX_CONF2, ST25R3911_REG_RX_CONF2_agc_en ); + + /*******************************************************************************/ + + + /*******************************************************************************/ + /* Transceive timers */ + /*******************************************************************************/ + rfalTimerDestroy( gRFAL.tmr.txRx ); + rfalTimerDestroy( gRFAL.tmr.RXE ); + + gRFAL.tmr.txRx = RFAL_TIMING_NONE; + gRFAL.tmr.RXE = RFAL_TIMING_NONE; + /*******************************************************************************/ + + + + /*******************************************************************************/ + /* Execute Post Transceive Callback */ + /*******************************************************************************/ + if( gRFAL.callbacks.postTxRx != NULL ) + { + gRFAL.callbacks.postTxRx(); + } + /*******************************************************************************/ + +} + + +/*******************************************************************************/ +static void rfalPrepareTransceive( void ) +{ + uint32_t maskInterrupts; + uint8_t reg; + + /*******************************************************************************/ + /* In the EMVCo mode the NRT will continue to run. * + * For the clear to stop it, the EMV mode has to be disabled before */ + st25r3911ClrRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + + /* Reset receive logic */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + + /* Reset Rx Gain */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_SQUELCH ); + + + /*******************************************************************************/ + /* FDT Poll */ + /*******************************************************************************/ + if( rfalIsModePassiveComm( gRFAL.mode ) ) /* Passive Comms */ + { + /* In Passive communications General Purpose Timer is used to measure FDT Poll */ + if( gRFAL.timings.FDTPoll != RFAL_TIMING_NONE ) + { + /* Configure GPT to start at RX end */ + st25r3911StartGPTimer_8fcs( (uint16_t)rfalConv1fcTo8fc( ((gRFAL.timings.FDTPoll < RFAL_FDT_POLL_ADJUSTMENT) ? gRFAL.timings.FDTPoll : (gRFAL.timings.FDTPoll - RFAL_FDT_POLL_ADJUSTMENT)) ), ST25R3911_REG_GPT_CONTROL_gptc_erx ); + } + } + + + /*******************************************************************************/ + /* Execute Pre Transceive Callback */ + /*******************************************************************************/ + if( gRFAL.callbacks.preTxRx != NULL ) + { + gRFAL.callbacks.preTxRx(); + } + /*******************************************************************************/ + + maskInterrupts = ( ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_TXE | + ST25R3911_IRQ_MASK_RXS | ST25R3911_IRQ_MASK_RXE | + ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_NRE | + ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_CRC | + ST25R3911_IRQ_MASK_ERR1 | ST25R3911_IRQ_MASK_ERR2 ); + + + /*******************************************************************************/ + /* Transceive flags */ + /*******************************************************************************/ + + reg = (ST25R3911_REG_ISO14443A_NFC_no_tx_par_off | ST25R3911_REG_ISO14443A_NFC_no_rx_par_off | ST25R3911_REG_ISO14443A_NFC_nfc_f0_off); + + /* Check if NFCIP1 mode is to be enabled */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON) != 0U ) + { + reg |= ST25R3911_REG_ISO14443A_NFC_nfc_f0; + } + + /* Check if Parity check is to be skipped and to keep the parity + CRC bits in FIFO */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP) != 0U ) + { + reg |= ST25R3911_REG_ISO14443A_NFC_no_rx_par; + } + + /* Check if automatic Parity bits is to be disabled */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE) != 0U ) + { + reg |= ST25R3911_REG_ISO14443A_NFC_no_tx_par; + } + + /* Apply current TxRx flags on ISO14443A and NFC 106kb/s Settings Register */ + st25r3911ChangeRegisterBits( ST25R3911_REG_ISO14443A_NFC, (ST25R3911_REG_ISO14443A_NFC_no_tx_par | ST25R3911_REG_ISO14443A_NFC_no_rx_par | ST25R3911_REG_ISO14443A_NFC_nfc_f0), reg ); + + + /* Check if CRC is to be checked automatically upon reception */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_MANUAL) != 0U ) + { + st25r3911SetRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_no_crc_rx ); + } + else + { + st25r3911ClrRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_no_crc_rx ); + } + + /* Check if AGC is to be disabled */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF) != 0U ) + { + st25r3911ClrRegisterBits( ST25R3911_REG_RX_CONF2, ST25R3911_REG_RX_CONF2_agc_en ); + } + else + { + st25r3911SetRegisterBits( ST25R3911_REG_RX_CONF2, ST25R3911_REG_RX_CONF2_agc_en ); + } + /*******************************************************************************/ + + + + /*******************************************************************************/ + /* EMVCo NRT mode */ + /*******************************************************************************/ + if( gRFAL.conf.eHandling == RFAL_ERRORHANDLING_EMD ) + { + st25r3911SetRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + } + else + { + st25r3911ClrRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + } + /*******************************************************************************/ + + + + /* In Active comms enable also External Field interrupts and set RF Collsion Avoidance */ + if( rfalIsModeActiveComm( gRFAL.mode ) ) + { + maskInterrupts |= ( ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_EON | ST25R3911_IRQ_MASK_CAT | ST25R3911_IRQ_MASK_CAC ); + + /* Set n=0 for subsequent RF Collision Avoidance */ + st25r3911ChangeRegisterBits(ST25R3911_REG_AUX, ST25R3911_REG_AUX_mask_nfc_n, 0U); + } + + /*******************************************************************************/ + /* Start transceive Sanity Timer if a FWT is used */ + if( (gRFAL.TxRx.ctx.fwt != RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != 0U) ) + { + rfalTimerStart( gRFAL.tmr.txRx, rfalCalcSanityTmr( gRFAL.TxRx.ctx.fwt ) ); + } + /*******************************************************************************/ + + + /*******************************************************************************/ + /* Clear and enable these interrupts */ + st25r3911GetInterrupt( maskInterrupts ); + st25r3911EnableInterrupts( maskInterrupts ); + + /* Clear FIFO status local copy */ + rfalFIFOStatusClear(); +} + +/*******************************************************************************/ +static void rfalTransceiveTx( void ) +{ + volatile uint32_t irqs; + uint16_t tmp; + ReturnCode ret; + + /* Suppress warning in case NFC-V feature is disabled */ + ret = RFAL_ERR_NONE; + RFAL_NO_WARNING(ret); + + + irqs = ST25R3911_IRQ_MASK_NONE; + + if( gRFAL.TxRx.state != gRFAL.TxRx.lastState ) + { + #if 0 /* Debug purposes */ + rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); */ + #endif + + gRFAL.TxRx.lastState = gRFAL.TxRx.state; + } + + switch( gRFAL.TxRx.state ) + { + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_IDLE: + + /* Nothing to do */ + + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_WAIT_GT ; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_WAIT_GT: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + if( !rfalIsGTExpired() ) + { + break; + } + + rfalTimerDestroy( gRFAL.tmr.GT ); + gRFAL.tmr.GT = RFAL_TIMING_NONE; + + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_WAIT_FDT; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_WAIT_FDT: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* Only in Passive communications GPT is used to measure FDT Poll */ + if( rfalIsModePassiveComm( gRFAL.mode ) ) + { + if( st25r3911IsGPTRunning() ) + { + break; + } + } + + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_PREP_TX; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_PREP_TX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* Clear FIFO, Clear and Enable the Interrupts */ + rfalPrepareTransceive( ); + + /* Calculate when Water Level Interrupt will be triggered */ + gRFAL.fifo.expWL = (uint16_t)( st25r3911CheckReg( ST25R3911_REG_IO_CONF1, ST25R3911_REG_IO_CONF1_fifo_lt, ST25R3911_REG_IO_CONF1_fifo_lt_16bytes) ? RFAL_FIFO_OUT_LT_16 : RFAL_FIFO_OUT_LT_32 ); + + #if RFAL_FEATURE_NFCV + /*******************************************************************************/ + /* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits */ + if( (RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode) ) + { + #if 0 + /* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */ + st25r3911WriteFifo(gRFAL.TxRx.ctx.txBuf, rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen)); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + #endif + /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */ + gRFAL.nfcvData.nfcvOffset = 0; + ret = rfalIso15693VCDCode(gRFAL.TxRx.ctx.txBuf, rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen), (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U)?false:true),(((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL) != 0U)?false:true), (RFAL_MODE_POLL_PICOPASS == gRFAL.mode), + &gRFAL.fifo.bytesTotal, &gRFAL.nfcvData.nfcvOffset, gRFAL.nfcvData.codingBuffer, RFAL_MIN( (uint16_t)ST25R3911_FIFO_DEPTH, (uint16_t)sizeof(gRFAL.nfcvData.codingBuffer) ), &gRFAL.fifo.bytesWritten); + + if( (ret != RFAL_ERR_NONE) && (ret != RFAL_ERR_AGAIN) ) + { + gRFAL.TxRx.status = ret; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL; + break; + } + /* Set the number of full bytes and bits to be transmitted */ + st25r3911SetNumTxBits( rfalConvBytesToBits(gRFAL.fifo.bytesTotal) ); + + /* Load FIFO with coded bytes */ + st25r3911WriteFifo( gRFAL.nfcvData.codingBuffer, (uint8_t)gRFAL.fifo.bytesWritten ); + + } + /*******************************************************************************/ + else + #endif /* RFAL_FEATURE_NFCV */ + { + /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */ + gRFAL.fifo.bytesTotal = (uint16_t)rfalCalcNumBytes(gRFAL.TxRx.ctx.txBufLen); + + /* Set the number of full bytes and bits to be transmitted */ + st25r3911SetNumTxBits( gRFAL.TxRx.ctx.txBufLen ); + + /* Load FIFO with total length or FIFO's maximum */ + gRFAL.fifo.bytesWritten = RFAL_MIN( gRFAL.fifo.bytesTotal, ST25R3911_FIFO_DEPTH ); + st25r3911WriteFifo( gRFAL.TxRx.ctx.txBuf, (uint8_t)gRFAL.fifo.bytesWritten ); + } + + /*Check if Observation Mode is enabled and set it on ST25R391x */ + rfalCheckEnableObsModeTx(); + + + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_TRANSMIT; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_TRANSMIT: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /*******************************************************************************/ + /* Execute Sync Transceive Callback */ + /*******************************************************************************/ + if( gRFAL.callbacks.syncTxRx != NULL ) + { + /* If set, wait for sync callback to signal sync/trigger transmission */ + if( !gRFAL.callbacks.syncTxRx() ) + { + break; + } + } + + /*******************************************************************************/ + /* Trigger/Start transmission */ + if( (gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U ) + { + st25r3911ExecuteCommand( ST25R3911_CMD_TRANSMIT_WITHOUT_CRC ); + } + else + { + st25r3911ExecuteCommand( ST25R3911_CMD_TRANSMIT_WITH_CRC ); + } + + /* Check if a WL level is expected or TXE should come */ + gRFAL.TxRx.state = (( gRFAL.fifo.bytesWritten < gRFAL.fifo.bytesTotal ) ? RFAL_TXRX_STATE_TX_WAIT_WL : RFAL_TXRX_STATE_TX_WAIT_TXE); + break; + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_WAIT_WL: + + irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_TXE) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + if( ((irqs & ST25R3911_IRQ_MASK_FWL) != 0U) && ((irqs & ST25R3911_IRQ_MASK_TXE) == 0U) ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_RELOAD_FIFO; + } + else + { + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL; + break; + } + + /* fall through */ + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_RELOAD_FIFO: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + #if RFAL_FEATURE_NFCV + /*******************************************************************************/ + /* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits */ + if( (RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode) ) + { + uint16_t maxLen; + + /* Load FIFO with the remaining length or maximum available (which fit on the coding buffer) */ + maxLen = (uint16_t)RFAL_MIN( (gRFAL.fifo.bytesTotal - gRFAL.fifo.bytesWritten), gRFAL.fifo.expWL); + maxLen = (uint16_t)RFAL_MIN( maxLen, sizeof(gRFAL.nfcvData.codingBuffer) ); + tmp = 0; + + /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */ + ret = rfalIso15693VCDCode(gRFAL.TxRx.ctx.txBuf, rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen), (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U)?false:true), (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL) != 0U)?false:true), (RFAL_MODE_POLL_PICOPASS == gRFAL.mode), + &gRFAL.fifo.bytesTotal, &gRFAL.nfcvData.nfcvOffset, gRFAL.nfcvData.codingBuffer, maxLen, &tmp); + + if( (ret != RFAL_ERR_NONE) && (ret != RFAL_ERR_AGAIN) ) + { + gRFAL.TxRx.status = ret; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL; + break; + } + + /* Load FIFO with coded bytes */ + st25r3911WriteFifo( gRFAL.nfcvData.codingBuffer, (uint8_t)tmp ); + } + /*******************************************************************************/ + else + #endif /* RFAL_FEATURE_NFCV */ + { + /* Load FIFO with the remaining length or maximum available */ + tmp = RFAL_MIN( (gRFAL.fifo.bytesTotal - gRFAL.fifo.bytesWritten), gRFAL.fifo.expWL); /* tmp holds the number of bytes written on this iteration */ + st25r3911WriteFifo( &gRFAL.TxRx.ctx.txBuf[gRFAL.fifo.bytesWritten], (uint8_t)tmp ); + } + + /* Update total written bytes to FIFO */ + gRFAL.fifo.bytesWritten += tmp; + + /* Check if a WL level is expected or TXE should come */ + gRFAL.TxRx.state = (( gRFAL.fifo.bytesWritten < gRFAL.fifo.bytesTotal ) ? RFAL_TXRX_STATE_TX_WAIT_WL : RFAL_TXRX_STATE_TX_WAIT_TXE); + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_WAIT_TXE: + + irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_TXE) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + + if( (irqs & ST25R3911_IRQ_MASK_TXE) != 0U ) + { + /* In Active comm start SW timer to measure FWT */ + if( rfalIsModeActiveComm( gRFAL.mode) && (gRFAL.TxRx.ctx.fwt != RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != 0U) ) + { + rfalTimerStart( gRFAL.tmr.FWT, rfalConv1fcToMs( gRFAL.TxRx.ctx.fwt ) ); + } + + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_DONE; + } + else if( (irqs & ST25R3911_IRQ_MASK_FWL) != 0U ) + { + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #TBD */ + /* ST25R3911 may send a WL even when all bytes have been written to FIFO */ + /*******************************************************************************/ + break; /* Ignore ST25R3911 FIFO WL if total TxLen is already on the FIFO */ + } + else + { + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL; + break; + } + + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_DONE: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* If no rxBuf is provided do not wait/expect Rx */ + if( gRFAL.TxRx.ctx.rxBuf == NULL ) + { + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + + /* Clean up Transceive */ + rfalCleanupTransceive(); + + gRFAL.TxRx.status = RFAL_ERR_NONE; + gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE; + break; + } + + rfalCheckEnableObsModeRx(); + + /* Goto Rx */ + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE; + break; + + /*******************************************************************************/ + case RFAL_TXRX_STATE_TX_FAIL: + + /* Error should be assigned by previous state */ + if( gRFAL.TxRx.status == RFAL_ERR_BUSY ) + { + gRFAL.TxRx.status = RFAL_ERR_SYSTEM; + } + + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + + /* Clean up Transceive */ + rfalCleanupTransceive(); + + gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE; + break; + + /*******************************************************************************/ + default: + gRFAL.TxRx.status = RFAL_ERR_SYSTEM; + gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL; + break; + } +} + + +/*******************************************************************************/ +static void rfalTransceiveRx( void ) +{ + volatile uint32_t irqs; + uint8_t tmp; + uint8_t aux; + + irqs = ST25R3911_IRQ_MASK_NONE; + + if( gRFAL.TxRx.state != gRFAL.TxRx.lastState ) + { + #if 0 /* Debug purposes */ + rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); + #endif + + gRFAL.TxRx.lastState = gRFAL.TxRx.state; + } + + switch( gRFAL.TxRx.state ) + { + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_IDLE: + + /* Clear rx counters */ + gRFAL.fifo.bytesWritten = 0; // Total bytes written on RxBuffer + gRFAL.fifo.bytesTotal = 0; // Total bytes in FIFO will now be from Rx + if( gRFAL.TxRx.ctx.rxRcvdLen != NULL ) + { + *gRFAL.TxRx.ctx.rxRcvdLen = 0; + } + + gRFAL.TxRx.state = ( rfalIsModeActiveComm( gRFAL.mode ) ? RFAL_TXRX_STATE_RX_WAIT_EON : RFAL_TXRX_STATE_RX_WAIT_RXS ); + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_WAIT_RXS: + + /*******************************************************************************/ + /* If in Active comm, Check if FWT SW timer has expired */ + if( rfalIsModeActiveComm( gRFAL.mode ) && (gRFAL.TxRx.ctx.fwt != (uint32_t)RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != (uint32_t)0U) ) + { + if( rfalTimerisExpired( gRFAL.tmr.FWT ) ) + { + gRFAL.TxRx.status = RFAL_ERR_TIMEOUT; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + } + + /*******************************************************************************/ + irqs = st25r3911GetInterrupt( ( ST25R3911_IRQ_MASK_RXS | ST25R3911_IRQ_MASK_NRE | ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_RXE) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.7 */ + /* NRE interrupt may be triggered twice */ + /* Ignore NRE if is detected together with no Rx Start */ + /*******************************************************************************/ + + /* Only raise Timeout if NRE is detected with no Rx Start (NRT EMV mode) */ + if( ((irqs & ST25R3911_IRQ_MASK_NRE) != 0U) && ((irqs & ST25R3911_IRQ_MASK_RXS) == 0U) ) + { + gRFAL.TxRx.status = RFAL_ERR_TIMEOUT; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + + /* Only raise Link Loss if EOF is detected with no Rx Start */ + if( ((irqs & ST25R3911_IRQ_MASK_EOF) != 0U) && ((irqs & ST25R3911_IRQ_MASK_RXS) == 0U) ) + { + /* In AP2P a Field On has already occurred - treat this as timeout | mute */ + gRFAL.TxRx.status = ( rfalIsModeActiveComm( gRFAL.mode ) ? RFAL_ERR_TIMEOUT : RFAL_ERR_LINK_LOSS ); + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + + if( (irqs & ST25R3911_IRQ_MASK_RXS) != 0U ) + { + /* If we got RXS + RXE together, jump directly into RFAL_TXRX_STATE_RX_ERR_CHECK */ + if( (irqs & ST25R3911_IRQ_MASK_RXE) != 0U ) + { + gRFAL.TxRx.rxse = true; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_ERR_CHECK; + break; + } + else + { + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.1 */ + /* Rarely on corrupted frames I_rxs gets signaled but I_rxe is not signaled */ + /* Use a SW timer to handle an eventual missing RXE */ + rfalTimerStart( gRFAL.tmr.RXE, RFAL_NORXE_TOUT ); + /*******************************************************************************/ + + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXE; + } + } + else if( (irqs & ST25R3911_IRQ_MASK_RXE) != 0U ) + { + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.9 */ + /* ST25R3911 may indicate RXE without RXS previously, this happens upon some */ + /* noise or incomplete byte frames with less than 4 bits */ + /*******************************************************************************/ + + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + + rfalErrorHandling(); + break; + } + else + { + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_WAIT_RXE: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_RXE | ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_EOF) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911B Errata #1.1 */ + /* ST25R3911 may indicate RXS without RXE afterwards, this happens rarely on */ + /* corrupted frames. */ + /* SW timer is used to timeout upon a missing RXE */ + if( rfalTimerisExpired( gRFAL.tmr.RXE ) ) + { + gRFAL.TxRx.status = RFAL_ERR_FRAMING; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + /*******************************************************************************/ + + break; /* No interrupt to process */ + } + + if( ((irqs & ST25R3911_IRQ_MASK_FWL) != 0U) && ((irqs & ST25R3911_IRQ_MASK_RXE) == 0U) ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_FIFO; + break; + } + + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_ERR_CHECK; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_ERR_CHECK: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /* Retrieve and check for any error irqs */ + irqs |= st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_CRC | ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_ERR1 | ST25R3911_IRQ_MASK_ERR2 | ST25R3911_IRQ_MASK_COL) ); + + if( (irqs & ST25R3911_IRQ_MASK_ERR1) != 0U ) + { + gRFAL.TxRx.status = RFAL_ERR_FRAMING; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + + /* Check if there's a specific error handling for this */ + rfalErrorHandling(); + break; + } + /* Discard Soft Framing errors if not in EMVCo error handling */ + else if( ((irqs & ST25R3911_IRQ_MASK_ERR2) != 0U) && (gRFAL.conf.eHandling == RFAL_ERRORHANDLING_EMD) ) + { + gRFAL.TxRx.status = RFAL_ERR_FRAMING; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + + /* Check if there's a specific error handling for this */ + rfalErrorHandling(); + break; + } + else if( (irqs & ST25R3911_IRQ_MASK_PAR) != 0U ) + { + gRFAL.TxRx.status = RFAL_ERR_PAR; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + + /* Check if there's a specific error handling for this */ + rfalErrorHandling(); + break; + } + else if( (irqs & ST25R3911_IRQ_MASK_CRC) != 0U ) + { + gRFAL.TxRx.status = RFAL_ERR_CRC; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + + /* Check if there's a specific error handling for this */ + rfalErrorHandling(); + break; + } + else if( (irqs & ST25R3911_IRQ_MASK_COL) != 0U ) + { + gRFAL.TxRx.status = RFAL_ERR_RF_COLLISION; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + + /* Check if there's a specific error handling for this */ + rfalErrorHandling(); + break; + } + else if( ((irqs & ST25R3911_IRQ_MASK_EOF) != 0U) && ((irqs & ST25R3911_IRQ_MASK_RXE) == 0U) ) + { + gRFAL.TxRx.status = RFAL_ERR_LINK_LOSS; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + else if( ((irqs & ST25R3911_IRQ_MASK_RXE) != 0U) || (gRFAL.TxRx.rxse) ) + { + /* Reception ended without any error indication, * + * check FIFO status for malformed or incomplete frames */ + + /* Check if the reception ends with an incomplete byte (residual bits) */ + if( rfalFIFOStatusIsIncompleteByte() ) + { + gRFAL.TxRx.status = RFAL_ERR_INCOMPLETE_BYTE; + } + /* Check if the reception ends with missing parity bit */ + else if( rfalFIFOStatusIsMissingPar() ) + { + gRFAL.TxRx.status = RFAL_ERR_FRAMING; + } + else + { + /* MISRA 15.7 - Empty else */ + } + + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA; + } + else + { + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_READ_DATA: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + tmp = rfalFIFOStatusGetNumBytes(); + + /*******************************************************************************/ + /* Check if CRC should not be placed in rxBuf */ + if( ((gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP) == 0U) ) + { + /* Check if CRC is being placed into the FIFO and if received frame was bigger than CRC */ + if( st25r3911IsCRCinFIFO() && ((gRFAL.fifo.bytesTotal + tmp) > 0U) ) + { + /* By default CRC will not be placed into the rxBuffer */ + if( ( tmp > (uint8_t)RFAL_CRC_LEN) ) + { + tmp -= (uint8_t)RFAL_CRC_LEN; + } + /* If the CRC was already placed into rxBuffer (due to WL interrupt where CRC was already in FIFO Read) + * cannot remove it from rxBuf. Can only remove it from rxBufLen not indicate the presence of CRC */ + else if(gRFAL.fifo.bytesTotal > (uint16_t)RFAL_CRC_LEN) + { + gRFAL.fifo.bytesTotal -= (uint16_t)RFAL_CRC_LEN; + } + else + { + /* MISRA 15.7 - Empty else */ + } + } + } + + gRFAL.fifo.bytesTotal += tmp; /* add to total bytes counter */ + + /*******************************************************************************/ + /* Check if remaining bytes fit on the rxBuf available */ + if( gRFAL.fifo.bytesTotal > rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) ) + { + tmp = (uint8_t)( rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) - gRFAL.fifo.bytesWritten); + + /* Transmission errors have precedence over buffer error */ + if( gRFAL.TxRx.status == RFAL_ERR_BUSY ) + { + gRFAL.TxRx.status = RFAL_ERR_NOMEM; + } + } + + /*******************************************************************************/ + /* Retrieve remaining bytes from FIFO to rxBuf, and assign total length rcvd */ + st25r3911ReadFifo( &gRFAL.TxRx.ctx.rxBuf[gRFAL.fifo.bytesWritten], tmp); + if( (gRFAL.TxRx.ctx.rxRcvdLen != NULL) ) + { + (*gRFAL.TxRx.ctx.rxRcvdLen) = (uint16_t)rfalConvBytesToBits( gRFAL.fifo.bytesTotal ); + if( rfalFIFOStatusIsIncompleteByte() ) + { + (*gRFAL.TxRx.ctx.rxRcvdLen) -= (RFAL_BITS_IN_BYTE - rfalFIFOGetNumIncompleteBits()); + } + } + + #if RFAL_FEATURE_NFCV + /*******************************************************************************/ + /* Decode sub bit stream into payload bits for NFCV, if no error found so far */ + if( ((RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode)) && (gRFAL.TxRx.status == RFAL_ERR_BUSY) ) + { + ReturnCode ret; + uint16_t offset = 0; + + ret = rfalIso15693VICCDecode(gRFAL.TxRx.ctx.rxBuf, gRFAL.fifo.bytesTotal, + gRFAL.nfcvData.origCtx.rxBuf, rfalConvBitsToBytes(gRFAL.nfcvData.origCtx.rxBufLen), &offset, gRFAL.nfcvData.origCtx.rxRcvdLen, gRFAL.nfcvData.ignoreBits, (RFAL_MODE_POLL_PICOPASS == gRFAL.mode) ); + + if( ((RFAL_ERR_NONE == ret) || (RFAL_ERR_CRC == ret)) + && (((uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP & gRFAL.nfcvData.origCtx.flags) == 0U) + && ((*gRFAL.nfcvData.origCtx.rxRcvdLen % RFAL_BITS_IN_BYTE) == 0U) + && (*gRFAL.nfcvData.origCtx.rxRcvdLen >= rfalConvBytesToBits(RFAL_CRC_LEN) ) + ) + { + *gRFAL.nfcvData.origCtx.rxRcvdLen -= (uint16_t)rfalConvBytesToBits(RFAL_CRC_LEN); /* Remove CRC */ + } + + #if 0 + /* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */ + st25r3911WriteFifo(gRFAL.nfcvData.origCtx.rxBuf, rfalConvBitsToBytes( *gRFAL.nfcvData.origCtx.rxRcvdLen)); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + #endif + + /* Restore original ctx */ + gRFAL.TxRx.ctx = gRFAL.nfcvData.origCtx; + gRFAL.TxRx.status = ((ret != RFAL_ERR_NONE) ? ret : RFAL_ERR_BUSY); + } + #endif /* RFAL_FEATURE_NFCV */ + + /*******************************************************************************/ + /* If an error as been marked/detected don't fall into to RX_DONE */ + if( gRFAL.TxRx.status != RFAL_ERR_BUSY ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } + + if( rfalIsModeActiveComm( gRFAL.mode ) ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_EOF; + break; + } + + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_DONE; + /* fall through */ + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_DONE: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + + /* Clean up Transceive */ + rfalCleanupTransceive(); + + + gRFAL.TxRx.status = RFAL_ERR_NONE; + gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE; + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_READ_FIFO: + + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911B Errata #1.1 */ + /* ST25R3911 may indicate RXS without RXE afterwards, this happens rarely on */ + /* corrupted frames. */ + /* Re-Start SW timer to handle an eventual missing RXE */ + rfalTimerStart( gRFAL.tmr.RXE, RFAL_NORXE_TOUT ); + /*******************************************************************************/ + + + tmp = rfalFIFOStatusGetNumBytes(); + gRFAL.fifo.bytesTotal += tmp; + + /*******************************************************************************/ + /* Calculate the amount of bytes that still fits in rxBuf */ + aux = (uint8_t)(( gRFAL.fifo.bytesTotal > rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) ) ? (rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) - gRFAL.fifo.bytesWritten) : tmp); + + /*******************************************************************************/ + /* Retrieve incoming bytes from FIFO to rxBuf, and store already read amount */ + st25r3911ReadFifo( &gRFAL.TxRx.ctx.rxBuf[gRFAL.fifo.bytesWritten], aux); + gRFAL.fifo.bytesWritten += aux; + + /*******************************************************************************/ + /* If the bytes already read were not the full FIFO WL, dump the remaining * + * FIFO so that ST25R391x can continue with reception */ + if( aux < tmp ) + { + st25r3911ReadFifo( NULL, (tmp - aux) ); + } + + rfalFIFOStatusClear(); + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXE; + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_FAIL: + + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + + /* Clean up Transceive */ + rfalCleanupTransceive(); + + /* Error should be assigned by previous state */ + if( gRFAL.TxRx.status == RFAL_ERR_BUSY ) + { + gRFAL.TxRx.status = RFAL_ERR_SYSTEM; + } + + #if 0 /* Debug purposes */ + rfalLogD( "RFAL: curSt: %d Error: %d \r\n", gRFAL.TxRx.state, gRFAL.TxRx.status ); + #endif + + gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE; + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_WAIT_EON: + + irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_EON | ST25R3911_IRQ_MASK_NRE) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + if( (irqs & ST25R3911_IRQ_MASK_EON) != 0U ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS; + } + + if( (irqs & ST25R3911_IRQ_MASK_NRE) != 0U ) + { + /* ST25R3911 uses the NRT to measure other device's Field On max time: Tadt + (n x Trfw) */ + gRFAL.TxRx.status = RFAL_ERR_LINK_LOSS; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + break; + + + /*******************************************************************************/ + case RFAL_TXRX_STATE_RX_WAIT_EOF: + + irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_CAT | ST25R3911_IRQ_MASK_CAC) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + if( (irqs & ST25R3911_IRQ_MASK_CAT) != 0U ) + { + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_DONE; + } + else if( (irqs & ST25R3911_IRQ_MASK_CAC) != 0U ) + { + gRFAL.TxRx.status = RFAL_ERR_RF_COLLISION; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + else + { + gRFAL.TxRx.status = RFAL_ERR_IO; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + } + break; + + + /*******************************************************************************/ + default: + gRFAL.TxRx.status = RFAL_ERR_SYSTEM; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL; + break; + } +} + +/*******************************************************************************/ +static void rfalFIFOStatusUpdate( void ) +{ + if(gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] == RFAL_FIFO_STATUS_INVALID) + { + st25r3911ReadMultipleRegisters( ST25R3911_REG_FIFO_RX_STATUS1, gRFAL.fifo.status, ST25R3911_FIFO_STATUS_LEN ); + } +} + + +/*******************************************************************************/ +static void rfalFIFOStatusClear( void ) +{ + gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] = RFAL_FIFO_STATUS_INVALID; +} + + +/*******************************************************************************/ +static uint8_t rfalFIFOStatusGetNumBytes( void ) +{ + rfalFIFOStatusUpdate(); + + return gRFAL.fifo.status[RFAL_FIFO_STATUS_REG1]; + +} + + +/*******************************************************************************/ +static bool rfalFIFOStatusIsIncompleteByte( void ) +{ + rfalFIFOStatusUpdate(); + return ((gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & (ST25R3911_REG_FIFO_RX_STATUS2_mask_fifo_lb | ST25R3911_REG_FIFO_RX_STATUS2_fifo_ncp)) != 0U); +} + + +/*******************************************************************************/ +static bool rfalFIFOStatusIsMissingPar( void ) +{ + rfalFIFOStatusUpdate(); + return ((gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & ST25R3911_REG_FIFO_RX_STATUS2_np_lb) != 0U); +} + + +/*******************************************************************************/ +static uint8_t rfalFIFOGetNumIncompleteBits( void ) +{ + rfalFIFOStatusUpdate(); + return ((gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & ST25R3911_REG_FIFO_RX_STATUS2_mask_fifo_lb) >> ST25R3911_REG_FIFO_RX_STATUS2_shift_fifo_lb); +} + + +#if RFAL_FEATURE_NFCA + +/*******************************************************************************/ +ReturnCode rfalISO14443ATransceiveShortFrame( rfal14443AShortFrameCmd txCmd, uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* rxRcvdLen, uint32_t fwt ) +{ + ReturnCode ret; + uint8_t directCmd; + + /* Check if RFAL is properly initialized */ + if( (!st25r3911IsTxEnabled()) || (gRFAL.state < RFAL_STATE_MODE_SET) || (( gRFAL.mode != RFAL_MODE_POLL_NFCA ) && ( gRFAL.mode != RFAL_MODE_POLL_NFCA_T1T )) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check for valid parameters */ + if( (rxBuf == NULL) || (rxRcvdLen == NULL) || (fwt == RFAL_FWT_NONE) ) + { + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + /* Select the Direct Command to be performed */ + switch (txCmd) + { + case RFAL_14443A_SHORTFRAME_CMD_WUPA: + directCmd = ST25R3911_CMD_TRANSMIT_WUPA; + break; + + case RFAL_14443A_SHORTFRAME_CMD_REQA: + directCmd = ST25R3911_CMD_TRANSMIT_REQA; + break; + + default: + return RFAL_ERR_PARAM; + } + + + /*******************************************************************************/ + /* Enable anti collision to recognise collision in first byte of SENS_REQ */ + st25r3911SetRegisterBits( ST25R3911_REG_ISO14443A_NFC, ST25R3911_REG_ISO14443A_NFC_antcl); + + + /*******************************************************************************/ + /* Wait for GT and FDT */ + while( !rfalIsGTExpired() ) { /* MISRA 15.6: mandatory brackets */ }; + while( st25r3911IsGPTRunning() ) { /* MISRA 15.6: mandatory brackets */ }; + + + rfalTimerDestroy( gRFAL.tmr.GT ); + gRFAL.tmr.GT = RFAL_TIMING_NONE; + + + /*******************************************************************************/ + /* Prepare for Transceive, Receive only (bypass Tx states) */ + gRFAL.TxRx.ctx.flags = ((uint32_t) RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_MANUAL ); + gRFAL.TxRx.ctx.rxBuf = rxBuf; + gRFAL.TxRx.ctx.rxBufLen = rxBufLen; + gRFAL.TxRx.ctx.rxRcvdLen = rxRcvdLen; + gRFAL.TxRx.ctx.fwt = fwt; + + /*******************************************************************************/ + /* Load NRT with FWT */ + st25r3911SetNoResponseTime_64fcs( rfalConv1fcTo64fc( RFAL_MIN( (fwt + RFAL_FWT_ADJUSTMENT + RFAL_FWT_A_ADJUSTMENT), RFAL_ST25R3911_NRT_MAX_1FC ) ) ); + + if( gRFAL.timings.FDTListen != RFAL_TIMING_NONE ) + { + /* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */ + st25r3911WriteRegister( ST25R3911_REG_MASK_RX_TIMER, (uint8_t)rfalConv1fcTo64fc( ((RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT) > gRFAL.timings.FDTListen) ? RFAL_ST25R3911_MRT_MIN_1FC : (gRFAL.timings.FDTListen - (RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT)) ) ); + } + + /* In Passive communications General Purpose Timer is used to measure FDT Poll */ + if( gRFAL.timings.FDTPoll != RFAL_TIMING_NONE ) + { + /* Configure GPT to start at RX end */ + st25r3911StartGPTimer_8fcs( (uint16_t)rfalConv1fcTo8fc( ((gRFAL.timings.FDTPoll < RFAL_FDT_POLL_ADJUSTMENT) ? gRFAL.timings.FDTPoll : (gRFAL.timings.FDTPoll - RFAL_FDT_POLL_ADJUSTMENT)) ), ST25R3911_REG_GPT_CONTROL_gptc_erx ); + } + + /*******************************************************************************/ + rfalPrepareTransceive(); + + /* Also enable bit collision interrupt */ + st25r3911GetInterrupt( ST25R3911_IRQ_MASK_COL ); + st25r3911EnableInterrupts( ST25R3911_IRQ_MASK_COL ); + + /*Check if Observation Mode is enabled and set it on ST25R391x */ + rfalCheckEnableObsModeTx(); + + /*******************************************************************************/ + /* Chip bug: Clear nbtx bits before sending WUPA/REQA - otherwise ST25R3911 will report parity error */ + st25r3911WriteRegister( ST25R3911_REG_NUM_TX_BYTES2, 0); + + /* Send either WUPA or REQA. All affected tags will backscatter ATQA and change to READY state */ + st25r3911ExecuteCommand( directCmd ); + + /* Wait for TXE */ + if( st25r3911WaitForInterruptsTimed( ST25R3911_IRQ_MASK_TXE, (uint16_t)RFAL_MAX( rfalConv1fcToMs( fwt ), RFAL_ST25R3911_SW_TMR_MIN_1MS ) ) == 0U) + { + ret = RFAL_ERR_IO; + } + else + { + /*Check if Observation Mode is enabled and set it on ST25R391x */ + rfalCheckEnableObsModeRx(); + + /* Jump into a transceive Rx state for reception (bypass Tx states) */ + gRFAL.state = RFAL_STATE_TXRX; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE; + gRFAL.TxRx.status = RFAL_ERR_BUSY; + + /* Execute Transceive Rx blocking */ + ret = rfalTransceiveBlockingRx(); + } + + + /* Disable Collision interrupt */ + st25r3911DisableInterrupts( (ST25R3911_IRQ_MASK_COL) ); + + /* Disable anti collision again */ + st25r3911ClrRegisterBits( ST25R3911_REG_ISO14443A_NFC, ST25R3911_REG_ISO14443A_NFC_antcl ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalISO14443ATransceiveAnticollisionFrame( uint8_t *buf, uint8_t *bytesToSend, uint8_t *bitsToSend, uint16_t *rxLength, uint32_t fwt ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalISO14443AStartTransceiveAnticollisionFrame( buf, bytesToSend, bitsToSend, rxLength, fwt ) ); + rfalRunBlocking( ret, rfalISO14443AGetTransceiveAnticollisionFrameStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalISO14443AStartTransceiveAnticollisionFrame( uint8_t *buf, uint8_t *bytesToSend, uint8_t *bitsToSend, uint16_t *rxLength, uint32_t fwt ) +{ + ReturnCode ret; + rfalTransceiveContext ctx; + + + /* Check if RFAL is properly initialized */ + if( (gRFAL.state < RFAL_STATE_MODE_SET) || ( gRFAL.mode != RFAL_MODE_POLL_NFCA ) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check for valid parameters */ + if( (buf == NULL) || (bytesToSend == NULL) || (bitsToSend == NULL) || (rxLength == NULL) ) + { + return RFAL_ERR_PARAM; + } + + /*******************************************************************************/ + /* Set speficic Analog Config for Anticolission if needed */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL) ); + + + /*******************************************************************************/ + /* Enable anti collision to recognise collision in first byte of SENS_REQ */ + st25r3911SetRegisterBits( ST25R3911_REG_ISO14443A_NFC, ST25R3911_REG_ISO14443A_NFC_antcl ); + + + + /*******************************************************************************/ + /* Prepare for Transceive */ + ctx.flags = ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF ); /* Disable Automatic Gain Control (AGC) for better detection of collision */ + ctx.txBuf = buf; + ctx.txBufLen = (uint16_t)(rfalConvBytesToBits( *bytesToSend ) + *bitsToSend ); + ctx.rxBuf = &buf[*bytesToSend]; + ctx.rxBufLen = (uint16_t)rfalConvBytesToBits( RFAL_ISO14443A_SDD_RES_LEN ); + ctx.rxRcvdLen = rxLength; + ctx.fwt = fwt; + + + /*******************************************************************************/ + /* Enabling RFAL_COLRES_AGC will reduce bit collision recognition capabilities + but may help with certain devices using noisy Active Load Modulation + (e.g. Samsung Galaxy S8-US (SM-G950U)) which can be interpreted as two cards + colliding: one weak and one strong. */ +#ifdef RFAL_COLRES_AGC + ctx.flags &= ~RFAL_TXRX_FLAGS_AGC_OFF; +#endif /* RFAL_COLRES_AGC */ + + + RFAL_EXIT_ON_ERR( ret, rfalStartTransceive( &ctx ) ); + + /* Additionally enable bit collision interrupt */ + st25r3911GetInterrupt( ST25R3911_IRQ_MASK_COL ); + st25r3911EnableInterrupts( ST25R3911_IRQ_MASK_COL ); + + /*******************************************************************************/ + gRFAL.nfcaData.collByte = 0; + + /* Save the collision byte */ + if ((*bitsToSend) > 0U) + { + buf[(*bytesToSend)] <<= (RFAL_BITS_IN_BYTE - (*bitsToSend)); + buf[(*bytesToSend)] >>= (RFAL_BITS_IN_BYTE - (*bitsToSend)); + gRFAL.nfcaData.collByte = buf[(*bytesToSend)]; + } + + gRFAL.nfcaData.buf = buf; + gRFAL.nfcaData.bytesToSend = bytesToSend; + gRFAL.nfcaData.bitsToSend = bitsToSend; + gRFAL.nfcaData.rxLength = rxLength; + + /*******************************************************************************/ + /* Run Transceive Tx */ + return rfalTransceiveRunBlockingTx(); +} + + +/*******************************************************************************/ +ReturnCode rfalISO14443AGetTransceiveAnticollisionFrameStatus( void ) +{ + ReturnCode ret; + uint8_t collData; + + RFAL_EXIT_ON_BUSY( ret, rfalGetTransceiveStatus() ); + + /*******************************************************************************/ + if ((*gRFAL.nfcaData.bitsToSend) > 0U) + { + gRFAL.nfcaData.buf[(*gRFAL.nfcaData.bytesToSend)] >>= (*gRFAL.nfcaData.bitsToSend); + gRFAL.nfcaData.buf[(*gRFAL.nfcaData.bytesToSend)] <<= (*gRFAL.nfcaData.bitsToSend); + gRFAL.nfcaData.buf[(*gRFAL.nfcaData.bytesToSend)] |= gRFAL.nfcaData.collByte; + } + + if( (RFAL_ERR_RF_COLLISION == ret) ) + { + /* read out collision register */ + st25r3911ReadRegister( ST25R3911_REG_COLLISION_STATUS, &collData ); + + (*gRFAL.nfcaData.bytesToSend) = ((collData >> ST25R3911_REG_COLLISION_STATUS_shift_c_byte) & 0x0FU); // 4-bits Byte information + (*gRFAL.nfcaData.bitsToSend) = ((collData >> ST25R3911_REG_COLLISION_STATUS_shift_c_bit) & 0x07U); // 3-bits bit information + + } + + + /*******************************************************************************/ + /* Disable Collision interrupt */ + st25r3911DisableInterrupts( (ST25R3911_IRQ_MASK_COL) ); + + /* Disable anti collision again */ + st25r3911ClrRegisterBits( ST25R3911_REG_ISO14443A_NFC, ST25R3911_REG_ISO14443A_NFC_antcl ); + /*******************************************************************************/ + + + /* Restore common Analog configurations for this mode */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX) ); + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX) ); + + return ret; +} + +#endif /* RFAL_FEATURE_NFCA */ + + +#if RFAL_FEATURE_NFCV + +/*******************************************************************************/ +ReturnCode rfalISO15693TransceiveAnticollisionFrame( uint8_t *txBuf, uint8_t txBufLen, uint8_t *rxBuf, uint8_t rxBufLen, uint16_t *actLen ) +{ + ReturnCode ret; + rfalTransceiveContext ctx; + + /* Check if RFAL is properly initialized */ + if( (gRFAL.state < RFAL_STATE_MODE_SET) || ( gRFAL.mode != RFAL_MODE_POLL_NFCV ) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /*******************************************************************************/ + /* Set speficic Analog Config for Anticolission if needed */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL) ); + + + /* Ignoring collisions before the UID (RES_FLAG + DSFID) */ + gRFAL.nfcvData.ignoreBits = (uint16_t)RFAL_ISO15693_IGNORE_BITS; + + /*******************************************************************************/ + /* Prepare for Transceive */ + ctx.flags = ((txBufLen==0U)?(uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL:(uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO) | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF | ((txBufLen==0U)?(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL:(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO); /* Disable Automatic Gain Control (AGC) for better detection of collision */ + ctx.txBuf = txBuf; + ctx.txBufLen = (uint16_t)rfalConvBytesToBits(txBufLen); + ctx.rxBuf = rxBuf; + ctx.rxBufLen = (uint16_t)rfalConvBytesToBits(rxBufLen); + ctx.rxRcvdLen = actLen; + ctx.fwt = rfalConv64fcTo1fc(ISO15693_FWT); + + RFAL_EXIT_ON_ERR( ret, rfalStartTransceive( &ctx ) ); + + /*******************************************************************************/ + /* Run Transceive blocking */ + ret = rfalTransceiveRunBlockingTx(); + if( ret == RFAL_ERR_NONE) + { + ret = rfalTransceiveBlockingRx(); + } + + /* Restore common Analog configurations for this mode */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX) ); + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX) ); + + gRFAL.nfcvData.ignoreBits = 0; + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalISO15693TransceiveEOFAnticollision( uint8_t *rxBuf, uint8_t rxBufLen, uint16_t *actLen ) +{ + uint8_t dummy; + + return rfalISO15693TransceiveAnticollisionFrame( &dummy, 0, rxBuf, rxBufLen, actLen ); +} + +/*******************************************************************************/ +ReturnCode rfalISO15693TransceiveEOF( uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *actLen ) +{ + ReturnCode ret; + uint8_t dummy; + + /* Check if RFAL is properly initialized */ + if( ( gRFAL.state < RFAL_STATE_MODE_SET ) || ( gRFAL.mode != RFAL_MODE_POLL_NFCV ) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /*******************************************************************************/ + /* Run Transceive blocking */ + ret = rfalTransceiveBlockingTxRx( &dummy, + 0, + rxBuf, + rxBufLen, + actLen, + ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP |(uint32_t)RFAL_TXRX_FLAGS_AGC_ON ), + rfalConv64fcTo1fc(ISO15693_FWT) ); + return ret; +} + +#endif /* RFAL_FEATURE_NFCV */ + +#if RFAL_FEATURE_NFCF + +/*******************************************************************************/ +ReturnCode rfalFeliCaPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes* pollResList, uint8_t pollResListSize, uint8_t *devicesDetected, uint8_t *collisionsDetected ) +{ + ReturnCode ret; + + RFAL_EXIT_ON_ERR( ret, rfalStartFeliCaPoll( slots, sysCode, reqCode, pollResList, pollResListSize, devicesDetected, collisionsDetected ) ); + rfalRunBlocking( ret, rfalGetFeliCaPollStatus() ); + + return ret; +} + + +/*******************************************************************************/ +ReturnCode rfalStartFeliCaPoll( rfalFeliCaPollSlots slots, uint16_t sysCode, uint8_t reqCode, rfalFeliCaPollRes* pollResList, uint8_t pollResListSize, uint8_t *devicesDetected, uint8_t *collisionsDetected ) +{ + ReturnCode ret; + uint8_t frame[RFAL_FELICA_POLL_REQ_LEN - RFAL_FELICA_LEN_LEN]; // LEN is added by ST25R391x automatically + uint8_t frameIdx; + + /* Check if RFAL is properly initialized */ + if( (gRFAL.state < RFAL_STATE_MODE_SET) || ( gRFAL.mode != RFAL_MODE_POLL_NFCF ) ) + { + return RFAL_ERR_WRONG_STATE; + } + + frameIdx = 0; + gRFAL.nfcfData.colDetected = 0; + gRFAL.nfcfData.devDetected = 0; + + /*******************************************************************************/ + /* Compute SENSF_REQ frame */ + frame[frameIdx++] = (uint8_t)FELICA_CMD_POLLING; /* CMD: SENF_REQ */ + frame[frameIdx++] = (uint8_t)(sysCode >> 8); /* System Code (SC) */ + frame[frameIdx++] = (uint8_t)(sysCode & 0xFFU); /* System Code (SC) */ + frame[frameIdx++] = reqCode; /* Communication Parameter Request (RC)*/ + frame[frameIdx++] = (uint8_t)slots; /* TimeSlot (TSN) */ + + + /*******************************************************************************/ + /* NRT should not stop on reception - Fake EMD which uses NRT in nrt_emv * + * RFAL_ERRORHANDLING_EMD has no special handling for NFC-F mode */ + gRFAL.nfcfData.curHandling = gRFAL.conf.eHandling; + gRFAL.conf.eHandling = RFAL_ERRORHANDLING_EMD; + + /*******************************************************************************/ + /* Run transceive blocking, + * Calculate Total Response Time in(64/fc): + * 512 PICC process time + (n * 256 Time Slot duration) */ + RFAL_EXIT_ON_ERR( ret, rfalTransceiveBlockingTx( frame, + (uint16_t)frameIdx, + (uint8_t*)gRFAL.nfcfData.pollResponses, + RFAL_FELICA_POLL_RES_LEN, + &gRFAL.nfcfData.actLen, + (RFAL_TXRX_FLAGS_DEFAULT), + rfalConv64fcTo1fc( RFAL_FELICA_POLL_DELAY_TIME + (RFAL_FELICA_POLL_SLOT_TIME * ((uint32_t)slots + 1U)) ) ) ); + + /* Store context */ + gRFAL.nfcfData.pollResList = pollResList; + gRFAL.nfcfData.pollResListSize = pollResListSize; + gRFAL.nfcfData.devicesDetected = devicesDetected; + gRFAL.nfcfData.collisionsDetected = collisionsDetected; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalGetFeliCaPollStatus( void ) +{ + ReturnCode ret; + + /* Check if RFAL is properly initialized */ + if( (gRFAL.state != RFAL_STATE_TXRX) || ( gRFAL.mode != RFAL_MODE_POLL_NFCF ) ) + { + return RFAL_ERR_WRONG_STATE; + } + + ret = rfalGetTransceiveStatus(); + + /* Wait until transceive has terminated */ + if( ret == RFAL_ERR_BUSY ) + { + return ret; + } + + /* Upon timeout the full Poll Delay + (Slot time)*(nbSlots) has expired */ + if( ret != RFAL_ERR_TIMEOUT ) + { + /* Reception done, reEnabled Rx for following Slot */ + /* The Rx reEnable is done before the check of NRT to be as fast as possible for the upcoming slot * + * Tslot = 1208us | SENSF_RES (19 payload bytes at 212) = 1135us -> Potentially ~75us between responses */ + st25r3911ExecuteCommand( ST25R3911_CMD_UNMASK_RECEIVE_DATA ); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_SQUELCH ); + rfalFIFOStatusClear(); + + /* If the reception was OK, new device found */ + if( ret == RFAL_ERR_NONE ) + { + gRFAL.nfcfData.devDetected++; + + /* Overwrite the Transceive context for the next reception */ + gRFAL.TxRx.ctx.rxBuf = (uint8_t*)gRFAL.nfcfData.pollResponses[gRFAL.nfcfData.devDetected]; + } + /* If the reception was not OK, mark as collision */ + else + { + gRFAL.nfcfData.colDetected++; + } + + /* Check whether that NRT has not expired meanwhile */ + if( st25r3911CheckReg( ST25R3911_REG_REGULATOR_RESULT, ST25R3911_REG_REGULATOR_RESULT_nrt_on, ST25R3911_REG_REGULATOR_RESULT_nrt_on ) ) + { + /* Jump again into transceive Rx state for the following reception */ + gRFAL.TxRx.status = RFAL_ERR_BUSY; + gRFAL.state = RFAL_STATE_TXRX; + gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE; + return RFAL_ERR_BUSY; + } + + /* In case NRT has expired meanwhile, ensure that Rx is disabled */ + st25r3911ExecuteCommand( ST25R3911_CMD_MASK_RECEIVE_DATA ); + } + + + /*******************************************************************************/ + /* Back to previous error handling (restore NRT to normal mode) */ + gRFAL.conf.eHandling = gRFAL.nfcfData.curHandling; + + /*******************************************************************************/ + /* Assign output parameters if requested */ + if( (gRFAL.nfcfData.pollResList != NULL) && (gRFAL.nfcfData.pollResListSize > 0U) && (gRFAL.nfcfData.devDetected > 0U) ) + { + RFAL_MEMCPY( gRFAL.nfcfData.pollResList, gRFAL.nfcfData.pollResponses, (RFAL_FELICA_POLL_RES_LEN * (uint32_t)RFAL_MIN(gRFAL.nfcfData.pollResListSize, gRFAL.nfcfData.devDetected) ) ); + } + + if( gRFAL.nfcfData.devicesDetected != NULL ) + { + *gRFAL.nfcfData.devicesDetected = gRFAL.nfcfData.devDetected; + } + + if( gRFAL.nfcfData.collisionsDetected != NULL ) + { + *gRFAL.nfcfData.collisionsDetected = gRFAL.nfcfData.colDetected; + } + + return (( (gRFAL.nfcfData.colDetected != 0U) || (gRFAL.nfcfData.devDetected != 0U)) ? RFAL_ERR_NONE : ret); +} + +#endif /* RFAL_FEATURE_NFCF */ + + +/***************************************************************************** + * Listen Mode * + *****************************************************************************/ + + + +/*******************************************************************************/ +bool rfalIsExtFieldOn( void ) +{ + return st25r3911IsExtFieldOn(); +} + +#if RFAL_FEATURE_LISTEN_MODE + +/*******************************************************************************/ +ReturnCode rfalListenStart( uint32_t lmMask, const rfalLmConfPA *confA, const rfalLmConfPB *confB, const rfalLmConfPF *confF, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rxLen ) +{ + RFAL_NO_WARNING(confA); + RFAL_NO_WARNING(confB); + RFAL_NO_WARNING(confF); + + + /* Check if RFAL is initialized */ + if( gRFAL.state < RFAL_STATE_INIT ) + { + return RFAL_ERR_WRONG_STATE; + } + + gRFAL.Lm.state = RFAL_LM_STATE_NOT_INIT; + + + /*******************************************************************************/ + if( ((lmMask & RFAL_LM_MASK_NFCA) != 0U) || ((lmMask & RFAL_LM_MASK_NFCB) != 0U) || ((lmMask & RFAL_LM_MASK_NFCF) != 0U) ) + { + return RFAL_ERR_NOTSUPP; + } + + + /*******************************************************************************/ + if( (lmMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U ) + { + gRFAL.state = RFAL_STATE_LM; + + gRFAL.Lm.rxBuf = rxBuf; + gRFAL.Lm.rxBufLen = rxBufLen; + gRFAL.Lm.rxLen = rxLen; + *gRFAL.Lm.rxLen = 0; + gRFAL.Lm.dataFlag = false; + + /* Disable GPT trigger source */ + st25r3911ChangeRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_gptc_mask, ST25R3911_REG_GPT_CONTROL_gptc_no_trigger ); + + /* On Bit Rate Detection Mode ST25R391x will filter incoming frames during MRT time starting on External Field On event, use 512/fc steps */ + st25r3911WriteRegister( ST25R3911_REG_MASK_RX_TIMER, (uint8_t)rfalConv1fcTo512fc( RFAL_LM_GT ) ); + + /* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity */ + st25r3911ClrRegisterBits( ST25R3911_REG_ISO14443A_NFC, (ST25R3911_REG_ISO14443A_NFC_no_tx_par | ST25R3911_REG_ISO14443A_NFC_no_rx_par | ST25R3911_REG_ISO14443A_NFC_nfc_f0) ); + + /* Enable External Field Detector */ + st25r3911SetRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_en_fd ); + + /* n * TRFW timing shall vary Activity 2.1 3.4.1.1 */ + st25r3911ChangeRegisterBits(ST25R3911_REG_AUX, ST25R3911_REG_AUX_mask_nfc_n, gRFAL.timings.nTRFW); + gRFAL.timings.nTRFW = rfalGennTRFW( gRFAL.timings.nTRFW ); + + /* Enable Receiver */ + st25r3911ChangeRegisterBits( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_rx_en, ST25R3911_REG_OP_CONTROL_rx_en ); + + /* Set Analog configurations for generic Listen mode */ + /* Not on SetState(POWER OFF) as otherwise would be applied on every Field Event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON) ); + + /* Initialize as POWER_OFF and set proper mode in RF Chip */ + rfalListenSetState( RFAL_LM_STATE_POWER_OFF ); + } + else + { + return RFAL_ERR_REQUEST; /* Listen Start called but no mode was enabled */ + } + + return RFAL_ERR_NONE; +} + + + +/*******************************************************************************/ +static ReturnCode rfalRunListenModeWorker( void ) +{ + volatile uint32_t irqs; + uint8_t tmp; + + if( gRFAL.state != RFAL_STATE_LM ) + { + return RFAL_ERR_WRONG_STATE; + } + + switch( gRFAL.Lm.state ) + { + /*******************************************************************************/ + case RFAL_LM_STATE_POWER_OFF: + + irqs = st25r3911GetInterrupt( ( ST25R3911_IRQ_MASK_EON ) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + if( (irqs & ST25R3911_IRQ_MASK_EON) != 0U ) + { + rfalListenSetState( RFAL_LM_STATE_IDLE ); + } + else + { + break; + } + /* fall through */ + + + /*******************************************************************************/ + case RFAL_LM_STATE_IDLE: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ + + irqs = st25r3911GetInterrupt( ( ST25R3911_IRQ_MASK_NFCT | ST25R3911_IRQ_MASK_RXE | ST25R3911_IRQ_MASK_EOF ) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + if( (irqs & ST25R3911_IRQ_MASK_NFCT) != 0U ) + { + /* Retrieve detected bitrate */ + uint8_t newBr; + st25r3911ReadRegister( ST25R3911_REG_NFCIP1_BIT_RATE, &newBr ); + newBr >>= ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate_shift; + + if (newBr > ST25R3911_REG_BIT_RATE_rxrate_424) + { + newBr = ST25R3911_REG_BIT_RATE_rxrate_424; + } + + gRFAL.Lm.brDetected = (rfalBitRate)(newBr); /* PRQA S 4342 # MISRA 10.5 - Guaranteed that no invalid enum values may be created. See also equalityGuard_RFAL_BR_106 ff.*/ + } + if( ((irqs & ST25R3911_IRQ_MASK_RXE) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP) ) + { + irqs = st25r3911GetInterrupt( ( ST25R3911_IRQ_MASK_RXE | ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_CRC | ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_ERR2 | ST25R3911_IRQ_MASK_ERR1 ) ); + + if( ((irqs & ST25R3911_IRQ_MASK_CRC) != 0U) || ((irqs & ST25R3911_IRQ_MASK_PAR) != 0U) || ((irqs & ST25R3911_IRQ_MASK_ERR1) != 0U) ) + { + /* nfc_ar may have triggered RF Collision Avoidance, disable it before executing Clear (Stop All activities) */ + st25r3911ClrRegisterBits( ST25R3911_REG_MODE, ST25R3911_REG_MODE_nfc_ar ); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + st25r3911ExecuteCommand( ST25R3911_CMD_UNMASK_RECEIVE_DATA ); + st25r3911SetRegisterBits( ST25R3911_REG_MODE, ST25R3911_REG_MODE_nfc_ar ); + st25r3911TxOff(); + break; /* A bad reception occurred, remain in same state */ + } + + /* Retrieve received data */ + st25r3911ReadRegister(ST25R3911_REG_FIFO_RX_STATUS1, &tmp); + *gRFAL.Lm.rxLen = tmp; + + st25r3911ReadFifo( gRFAL.Lm.rxBuf, (uint8_t)RFAL_MIN( *gRFAL.Lm.rxLen, rfalConvBitsToBytes(gRFAL.Lm.rxBufLen) ) ); + + /* Check if the data we got has at least the CRC and remove it, otherwise leave at 0 */ + *gRFAL.Lm.rxLen -= ((*gRFAL.Lm.rxLen > RFAL_CRC_LEN) ? RFAL_CRC_LEN : *gRFAL.Lm.rxLen); + *gRFAL.Lm.rxLen = (uint16_t)rfalConvBytesToBits( *gRFAL.Lm.rxLen ); + gRFAL.Lm.dataFlag = true; + + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + } + else if( ((irqs & ST25R3911_IRQ_MASK_EOF) != 0U) && (!gRFAL.Lm.dataFlag) ) + { + rfalListenSetState( RFAL_LM_STATE_POWER_OFF ); + } + else + { + /* MISRA 15.7 - Empty else */ + } + break; + + /*******************************************************************************/ + case RFAL_LM_STATE_READY_F: + case RFAL_LM_STATE_READY_A: + case RFAL_LM_STATE_ACTIVE_A: + case RFAL_LM_STATE_ACTIVE_Ax: + case RFAL_LM_STATE_SLEEP_A: + case RFAL_LM_STATE_SLEEP_B: + case RFAL_LM_STATE_SLEEP_AF: + case RFAL_LM_STATE_READY_Ax: + case RFAL_LM_STATE_CARDEMU_4A: + case RFAL_LM_STATE_CARDEMU_4B: + case RFAL_LM_STATE_CARDEMU_3: + return RFAL_ERR_INTERNAL; + + case RFAL_LM_STATE_TARGET_F: + case RFAL_LM_STATE_TARGET_A: + break; + + /*******************************************************************************/ + default: + return RFAL_ERR_WRONG_STATE; + } + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalListenStop( void ) +{ + + /* Check if RFAL is initialized */ + if( gRFAL.state < RFAL_STATE_INIT ) + { + return RFAL_ERR_WRONG_STATE; + } + + gRFAL.Lm.state = RFAL_LM_STATE_NOT_INIT; + + /*Check if Observation Mode was enabled and disable it on ST25R391x */ + rfalCheckDisableObsMode(); + + /* Disable Receiver and Transmitter */ + rfalFieldOff(); + + /* As there's no Off mode, set default value: ISO14443A with automatic RF Collision Avoidance Off */ + st25r3911WriteRegister( ST25R3911_REG_MODE, (ST25R3911_REG_MODE_om_iso14443a | ST25R3911_REG_MODE_nfc_ar_off) ); + + /* Set Analog configurations for Listen Off event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF) ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +/* PRQA S 3673 1 # MISRA 8.13 - ST25R3911B does not support Listen mode. Implementation for other chips will modify rxBuf and rxLen */ +ReturnCode rfalListenSleepStart( rfalLmState sleepSt, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rxLen ) +{ + RFAL_NO_WARNING(sleepSt); + RFAL_NO_WARNING(rxBuf); + RFAL_NO_WARNING(rxBufLen); + RFAL_NO_WARNING(rxLen); + + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +rfalLmState rfalListenGetState( bool *dataFlag, rfalBitRate *lastBR ) +{ + /* Allow state retrieval even if gRFAL.state != RFAL_STATE_LM so * + * that this Lm state can be used by caller after activation */ + + if( lastBR != NULL ) + { + *lastBR = gRFAL.Lm.brDetected; + } + + if( dataFlag != NULL ) + { + *dataFlag = gRFAL.Lm.dataFlag; + } + + return gRFAL.Lm.state; +} + + +/*******************************************************************************/ +ReturnCode rfalListenSetState( rfalLmState newSt ) +{ + ReturnCode ret; + uint8_t tmp; + rfalLmState newState; + bool reSetState; + + + /* Check if RFAL is initialized */ + if( gRFAL.state < RFAL_STATE_INIT ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* SetState clears the Data flag */ + gRFAL.Lm.dataFlag = false; + newState = newSt; + ret = RFAL_ERR_NONE; + + do{ + reSetState = false; + + /*******************************************************************************/ + switch( newState ) + { + /*******************************************************************************/ + case RFAL_LM_STATE_POWER_OFF: + + /*******************************************************************************/ + /* Disable nfc_ar as RF Collision Avoidance timer may have already started */ + st25r3911ClrRegisterBits( ST25R3911_REG_MODE, ST25R3911_REG_MODE_nfc_ar ); + + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + + /* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */ + st25r3911TxOff(); + + /*******************************************************************************/ + /* Ensure that the NFCIP1 mode is disabled */ + st25r3911ClrRegisterBits( ST25R3911_REG_ISO14443A_NFC, ST25R3911_REG_ISO14443A_NFC_nfc_f0 ); + + + /*******************************************************************************/ + /* Clear and enable required IRQs */ + st25r3911DisableInterrupts( ST25R3911_IRQ_MASK_ALL ); + + + st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_NFCT | ST25R3911_IRQ_MASK_RXS | ST25R3911_IRQ_MASK_CRC | ST25R3911_IRQ_MASK_ERR1 | + ST25R3911_IRQ_MASK_ERR2 | ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_EON | ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_RXE ) ); + + + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata TDB */ + /* RXS and NFCT are triggered very close (specially in higher bitrates). * + * If the interrupt status register is being read when NFCT is trigerred, the * + * IRQ line might go low and NFCT is not signalled on the status register. * + * For initial bitrate detection, mask RXS, only wait for NFCT and RXE. */ + /*******************************************************************************/ + + st25r3911EnableInterrupts( (ST25R3911_IRQ_MASK_NFCT | ST25R3911_IRQ_MASK_CRC | ST25R3911_IRQ_MASK_ERR1 | + ST25R3911_IRQ_MASK_ERR2 | ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_EON | ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_RXE ) ); + + /*******************************************************************************/ + /* Clear the bitRate previously detected */ + gRFAL.Lm.brDetected = RFAL_BR_KEEP; + + + /*******************************************************************************/ + /* Apply the BitRate detection mode mode */ + st25r3911WriteRegister( ST25R3911_REG_MODE, (ST25R3911_REG_MODE_targ_targ | ST25R3911_REG_MODE_om_bit_rate_detection | ST25R3911_REG_MODE_nfc_ar_on) ); + + + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.3 */ + /* Even though bitrate is going to be detected the bitrate must be set to * + * 106kbps to get correct 106kbps parity */ + st25r3911WriteRegister( ST25R3911_REG_BIT_RATE, (ST25R3911_REG_BIT_RATE_txrate_106 | ST25R3911_REG_BIT_RATE_rxrate_106) ); + /*******************************************************************************/ + + + /*******************************************************************************/ + /* Check if external Field is already On */ + if( rfalIsExtFieldOn() ) + { + reSetState = true; + newState = RFAL_LM_STATE_IDLE; /* Set IDLE state */ + } + break; + + /*******************************************************************************/ + case RFAL_LM_STATE_IDLE: + + /*******************************************************************************/ + /* In Active P2P the Initiator may: Turn its field On; LM goes into IDLE state; + * Initiator sends an unexpected frame raising a Protocol error; Initiator + * turns its field Off and ST25R3911 performs the automatic RF Collision + * Avoidance keeping our field On; upon a Protocol error upper layer sets + * again the state to IDLE to clear dataFlag and wait for next data. + * + * Ensure that when upper layer calls SetState(IDLE), it restores initial + * configuration and that check whether an external Field is still present */ + + /* nfc_ar may have triggered RF Collision Avoidance, disable it before executing Clear (Stop All activities) */ + st25r3911ClrRegisterBits( ST25R3911_REG_MODE, ST25R3911_REG_MODE_nfc_ar ); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + st25r3911SetRegisterBits( ST25R3911_REG_MODE, ST25R3911_REG_MODE_nfc_ar ); + + /* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */ + st25r3911TxOff(); + + + /* Load 2nd/3rd stage gain setting from registers into the receiver */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_SQUELCH ); + + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.4 */ + /* Enable; disable; enable mixer to make sure the digital decoder is in * + * high state. This also switches the demodulator to mixer mode. */ + st25r3911ReadRegister( ST25R3911_REG_RX_CONF1, &tmp ); + st25r3911WriteRegister( ST25R3911_REG_RX_CONF1, (tmp | ST25R3911_REG_RX_CONF1_amd_sel) ); + st25r3911WriteRegister( ST25R3911_REG_RX_CONF1, (uint8_t)(tmp & ~ST25R3911_REG_RX_CONF1_amd_sel) ); + st25r3911WriteRegister( ST25R3911_REG_RX_CONF1, (tmp | ST25R3911_REG_RX_CONF1_amd_sel) ); + /*******************************************************************************/ + + /* ReEnable the receiver */ + st25r3911ExecuteCommand( ST25R3911_CMD_UNMASK_RECEIVE_DATA ); + + + /* If external Field is no longer detected go back to POWER_OFF */ + if( !st25r3911IsExtFieldOn() ) + { + reSetState = true; + newState = RFAL_LM_STATE_POWER_OFF; /* Set POWER_OFF state */ + } + + /*******************************************************************************/ + /*Check if Observation Mode is enabled and set it on ST25R391x */ + rfalCheckEnableObsModeRx(); + break; + + /*******************************************************************************/ + case RFAL_LM_STATE_TARGET_A: + case RFAL_LM_STATE_TARGET_F: + /* States not handled by the LM, just keep state context */ + break; + + /*******************************************************************************/ + case RFAL_LM_STATE_READY_F: + case RFAL_LM_STATE_CARDEMU_3: + case RFAL_LM_STATE_READY_Ax: + case RFAL_LM_STATE_READY_A: + case RFAL_LM_STATE_ACTIVE_Ax: + case RFAL_LM_STATE_ACTIVE_A: + case RFAL_LM_STATE_SLEEP_A: + case RFAL_LM_STATE_SLEEP_B: + case RFAL_LM_STATE_SLEEP_AF: + case RFAL_LM_STATE_CARDEMU_4A: + case RFAL_LM_STATE_CARDEMU_4B: + return RFAL_ERR_NOTSUPP; + + /*******************************************************************************/ + default: + return RFAL_ERR_WRONG_STATE; + } + } + while( reSetState ); + + gRFAL.Lm.state = newState; + + return ret; +} + +#endif /* RFAL_FEATURE_LISTEN_MODE */ + + +/******************************************************************************* + * Wake-Up Mode * + *******************************************************************************/ + +#if RFAL_FEATURE_WAKEUP_MODE + +/*******************************************************************************/ +ReturnCode rfalWakeUpModeStart( const rfalWakeUpConfig *config ) +{ + uint8_t aux; + uint8_t reg; + uint32_t irqs; + + + /* Check if RFAL is not initialized */ + if( gRFAL.state < RFAL_STATE_INIT ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* The Wake-Up procedure is explained in detail in Application Note: AN4985 */ + + if( config == NULL ) + { + gRFAL.wum.cfg.period = RFAL_WUM_PERIOD_500MS; + gRFAL.wum.cfg.irqTout = false; + + gRFAL.wum.cfg.refWU.enabled = true; /* Obtain WU reference from WU mode, not in Ready Mode */ + gRFAL.wum.cfg.refWU.refDelay = RFAL_WUM_PERIOD_10MS; /* WU reference after this time in WU mode */ + + gRFAL.wum.cfg.indAmp.enabled = true; + gRFAL.wum.cfg.indPha.enabled = true; + gRFAL.wum.cfg.cap.enabled = false; + + gRFAL.wum.cfg.indAmp.delta = 2U; + gRFAL.wum.cfg.indAmp.reference = RFAL_WUM_REFERENCE_AUTO; + gRFAL.wum.cfg.indAmp.autoAvg = false; + gRFAL.wum.cfg.indPha.delta = 2U; + gRFAL.wum.cfg.indPha.reference = RFAL_WUM_REFERENCE_AUTO; + gRFAL.wum.cfg.indPha.autoAvg = false; + } + else + { + gRFAL.wum.cfg = *config; + } + + + /* Check for valid configuration */ + if( ((gRFAL.wum.cfg.cap.enabled) && ((gRFAL.wum.cfg.indAmp.enabled) || (gRFAL.wum.cfg.indPha.enabled))) || + ((!gRFAL.wum.cfg.cap.enabled) && ((!gRFAL.wum.cfg.indAmp.enabled) && (!gRFAL.wum.cfg.indPha.enabled))) || + ((gRFAL.wum.cfg.refWU.enabled) && ((gRFAL.wum.cfg.cap.enabled) || (gRFAL.wum.cfg.indAmp.autoAvg) || (gRFAL.wum.cfg.indPha.autoAvg) || + ((gRFAL.wum.cfg.indAmp.enabled) && (gRFAL.wum.cfg.indAmp.reference != RFAL_WUM_REFERENCE_AUTO)) || + ((gRFAL.wum.cfg.indPha.enabled) && (gRFAL.wum.cfg.indPha.reference != RFAL_WUM_REFERENCE_AUTO)))) ) + { + return RFAL_ERR_PARAM; + } + + irqs = ST25R3911_IRQ_MASK_NONE; + + + /* Disable Tx, Rx, External Field Detector and set default ISO14443A mode */ + st25r3911TxRxOff(); + st25r3911ClrRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_en_fd ); + st25r3911ChangeRegisterBits(ST25R3911_REG_MODE, (ST25R3911_REG_MODE_targ | ST25R3911_REG_MODE_mask_om), (ST25R3911_REG_MODE_targ_init | ST25R3911_REG_MODE_om_iso14443a) ); + + /* Set Analog configurations for Wake-up On event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON) ); + + /*******************************************************************************/ + /* Prepare Wake-Up Timer Control Register */ + reg = (uint8_t)(((uint8_t)gRFAL.wum.cfg.period & 0x0FU) << ST25R3911_REG_WUP_TIMER_CONTROL_shift_wut); + reg |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.period < (uint8_t)RFAL_WUM_PERIOD_100MS) ? ST25R3911_REG_WUP_TIMER_CONTROL_wur : 0x00U); + + if(gRFAL.wum.cfg.irqTout) + { + reg |= ST25R3911_REG_WUP_TIMER_CONTROL_wto; + irqs |= ST25R3911_IRQ_MASK_WT; + } + + /*******************************************************************************/ + /* Check if Inductive Amplitude is to be performed */ + if( gRFAL.wum.cfg.indAmp.enabled ) + { + aux = (uint8_t)((gRFAL.wum.cfg.indAmp.delta) << ST25R3911_REG_AMPLITUDE_MEASURE_CONF_shift_am_d); + aux |= (uint8_t)(gRFAL.wum.cfg.indAmp.aaInclMeas ? ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_aam : 0x00U); + aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.indAmp.aaWeight << ST25R3911_REG_AMPLITUDE_MEASURE_CONF_shift_am_aew) & ST25R3911_REG_AMPLITUDE_MEASURE_CONF_mask_am_aew); + aux |= (uint8_t)(gRFAL.wum.cfg.indAmp.autoAvg ? ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_ae : 0x00U); + + st25r3911WriteRegister( ST25R3911_REG_AMPLITUDE_MEASURE_CONF, aux ); + + /* Only need to set the reference if not using Auto Average */ + if( (!gRFAL.wum.cfg.indAmp.autoAvg) && (!gRFAL.wum.cfg.refWU.enabled) ) + { + if( gRFAL.wum.cfg.indAmp.reference == RFAL_WUM_REFERENCE_AUTO ) + { + st25r3911MeasureAmplitude( &aux ); + gRFAL.wum.cfg.indAmp.reference = aux; + } + st25r3911WriteRegister( ST25R3911_REG_AMPLITUDE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.indAmp.reference ); + } + + reg |= ST25R3911_REG_WUP_TIMER_CONTROL_wam; + irqs |= ST25R3911_IRQ_MASK_WAM; + } + + /*******************************************************************************/ + /* Check if Inductive Phase is to be performed */ + if( gRFAL.wum.cfg.indPha.enabled ) + { + aux = (uint8_t)((gRFAL.wum.cfg.indPha.delta) << ST25R3911_REG_PHASE_MEASURE_CONF_shift_pm_d); + aux |= (uint8_t)(gRFAL.wum.cfg.indPha.aaInclMeas ? ST25R3911_REG_PHASE_MEASURE_CONF_pm_aam : 0x00U); + aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.indPha.aaWeight << ST25R3911_REG_PHASE_MEASURE_CONF_shift_pm_aew) & ST25R3911_REG_PHASE_MEASURE_CONF_mask_pm_aew); + aux |= (uint8_t)(gRFAL.wum.cfg.indPha.autoAvg ? ST25R3911_REG_PHASE_MEASURE_CONF_pm_ae : 0x00U); + + st25r3911WriteRegister( ST25R3911_REG_PHASE_MEASURE_CONF, aux ); + + /* Only need to set the reference if not using Auto Average */ + if( (!gRFAL.wum.cfg.indPha.autoAvg) && (!gRFAL.wum.cfg.refWU.enabled) ) + { + if( gRFAL.wum.cfg.indPha.reference == RFAL_WUM_REFERENCE_AUTO ) + { + st25r3911MeasurePhase( &aux ); + gRFAL.wum.cfg.indPha.reference = aux; + } + st25r3911WriteRegister( ST25R3911_REG_PHASE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.indPha.reference ); + } + + reg |= ST25R3911_REG_WUP_TIMER_CONTROL_wph; + irqs |= ST25R3911_IRQ_MASK_WPH; + } + + /*******************************************************************************/ + /* Check if Capacitive is to be performed */ + if( gRFAL.wum.cfg.cap.enabled ) + { + /*******************************************************************************/ + /* Perform Capacitive sensor calibration */ + + /* Disable Oscillator and Field */ + st25r3911ClrRegisterBits( ST25R3911_REG_OP_CONTROL, (ST25R3911_REG_OP_CONTROL_en | ST25R3911_REG_OP_CONTROL_tx_en) ); + + /* Sensor gain should be configured on Analog Config */ + + /* Perform calibration procedure */ + st25r3911CalibrateCapacitiveSensor( NULL ); + + + /*******************************************************************************/ + aux = (uint8_t)((gRFAL.wum.cfg.cap.delta) << ST25R3911_REG_CAPACITANCE_MEASURE_CONF_shift_cm_d); + aux |= (uint8_t)(gRFAL.wum.cfg.cap.aaInclMeas ? ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_aam : 0x00U); + aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.cap.aaWeight << ST25R3911_REG_CAPACITANCE_MEASURE_CONF_shift_cm_aew) & ST25R3911_REG_CAPACITANCE_MEASURE_CONF_mask_cm_aew); + aux |= (uint8_t)(gRFAL.wum.cfg.cap.autoAvg ? ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_ae : 0x00U); + + st25r3911WriteRegister( ST25R3911_REG_CAPACITANCE_MEASURE_CONF, aux ); + + /* Only need to set the reference if not using Auto Average */ + if( !gRFAL.wum.cfg.cap.autoAvg ) + { + if( gRFAL.wum.cfg.indPha.reference == RFAL_WUM_REFERENCE_AUTO ) + { + st25r3911MeasureCapacitance( &aux ); + gRFAL.wum.cfg.cap.reference = aux; + } + st25r3911WriteRegister( ST25R3911_REG_CAPACITANCE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.cap.reference ); + } + + reg |= ST25R3911_REG_WUP_TIMER_CONTROL_wcap; + irqs |= ST25R3911_IRQ_MASK_WCAP; + } + + /* Disable and clear all interrupts except Wake-Up IRQs */ + st25r3911DisableInterrupts( ST25R3911_IRQ_MASK_ALL ); + st25r3911GetInterrupt( irqs ); + st25r3911EnableInterrupts( irqs ); + + /* Use WUM state to start rfal */ + RFAL_MEMSET(&gRFAL.wum.info, 0x00, sizeof(gRFAL.wum.info)); /* clear info struct to avoid old data being used */ + gRFAL.wum.state = RFAL_WUM_STATE_ENABLED; + gRFAL.state = RFAL_STATE_WUM; + + + /*******************************************************************************/ + /* If reference is to be obtained by WU mode, set the WU config so that triggers WU IRQ upon first measurement */ + if( gRFAL.wum.cfg.refWU.enabled ) + { + if( gRFAL.wum.cfg.indAmp.enabled ) + { + st25r3911WriteRegister( ST25R3911_REG_AMPLITUDE_MEASURE_REF, 0 ); + st25r3911ChangeRegisterBits( ST25R3911_REG_AMPLITUDE_MEASURE_CONF, ST25R3911_REG_AMPLITUDE_MEASURE_CONF_mask_am_d, 0 ); + gRFAL.wum.refWUTrg = ST25R3911_IRQ_MASK_WAM; + } + + if( gRFAL.wum.cfg.indPha.enabled ) + { + st25r3911WriteRegister( ST25R3911_REG_PHASE_MEASURE_REF, 0 ); + st25r3911ChangeRegisterBits( ST25R3911_REG_PHASE_MEASURE_CONF, ST25R3911_REG_PHASE_MEASURE_CONF_mask_pm_d, 0 ); + gRFAL.wum.refWUTrg = ST25R3911_IRQ_MASK_WPH; + } + + /* Set config timing for the ref measurement */ + reg &= ~(ST25R3911_REG_WUP_TIMER_CONTROL_wur | ST25R3911_REG_WUP_TIMER_CONTROL_mask_wut); + reg |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.refWU.refDelay & 0x0FU) << ST25R3911_REG_WUP_TIMER_CONTROL_shift_wut); + reg |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.refWU.refDelay < (uint8_t)RFAL_WUM_PERIOD_100MS) ? ST25R3911_REG_WUP_TIMER_CONTROL_wur : 0x00U); + + gRFAL.wum.state = RFAL_WUM_STATE_INITIALIZING; + } + /*******************************************************************************/ + + + /* Enable Low Power Wake-Up Mode */ + st25r3911WriteRegister( ST25R3911_REG_WUP_TIMER_CONTROL, reg ); + st25r3911ChangeRegisterBits( ST25R3911_REG_OP_CONTROL, (ST25R3911_REG_OP_CONTROL_en | ST25R3911_REG_OP_CONTROL_wu), ST25R3911_REG_OP_CONTROL_wu ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +bool rfalWakeUpModeHasWoke( void ) +{ + return ((gRFAL.state == RFAL_STATE_WUM) && (gRFAL.wum.state >= RFAL_WUM_STATE_ENABLED_WOKE)); +} + + +/*******************************************************************************/ +bool rfalWakeUpModeIsEnabled( void ) +{ + return ((gRFAL.state == RFAL_STATE_WUM) && (gRFAL.wum.state >= RFAL_WUM_STATE_ENABLED)); +} + + +/*******************************************************************************/ +ReturnCode rfalWakeUpModeGetInfo( bool force, rfalWakeUpInfo *info ) +{ + /* Check if WU mode is running */ + if( (gRFAL.state != RFAL_STATE_WUM) || (gRFAL.wum.state < RFAL_WUM_STATE_ENABLED) ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check for valid parameters */ + if( info == NULL ) + { + return RFAL_ERR_PARAM; + } + + /* Clear info structure */ + RFAL_MEMSET( info, 0x00, sizeof(rfalWakeUpInfo) ); + + /* Update general information */ + info->irqWut = gRFAL.wum.info.irqWut; + gRFAL.wum.info.irqWut = false; + + /* WUT IRQ is signaled when WUT expires. Delay slightly for the actual measurement to be performed */ + if( info->irqWut ) + { + platformDelay( 1 ); + } + + if( gRFAL.wum.cfg.indAmp.enabled ) + { + /* Only retrive data if there was an WUT or WAM event (or forced) */ + if( force || (info->irqWut) || (gRFAL.wum.info.irqWuAmp) ) + { + st25r3911ReadRegister( ST25R3911_REG_AMPLITUDE_MEASURE_RESULT, &info->indAmp.lastMeas ); + + if( gRFAL.wum.cfg.indAmp.autoAvg ) + { + st25r3911ReadRegister( ST25R3911_REG_AMPLITUDE_MEASURE_AA_RESULT, &info->indAmp.reference ); + } + } + + /* Update IRQ information and clear flag upon retrieving */ + info->indAmp.irqWu = gRFAL.wum.info.irqWuAmp; + gRFAL.wum.info.irqWuAmp = false; + } + + if( gRFAL.wum.cfg.indPha.enabled ) + { + /* Only retrive data if there was an WUT or WPH event (or forced) */ + if( force || (info->irqWut) || (gRFAL.wum.info.irqWuPha) ) + { + st25r3911ReadRegister( ST25R3911_REG_PHASE_MEASURE_RESULT, &info->indPha.lastMeas ); + + if( gRFAL.wum.cfg.indPha.autoAvg ) + { + st25r3911ReadRegister( ST25R3911_REG_PHASE_MEASURE_AA_RESULT, &info->indPha.reference ); + } + } + + /* Update IRQ information and clear flag upon retrieving */ + info->indPha.irqWu = gRFAL.wum.info.irqWuPha; + gRFAL.wum.info.irqWuPha = false; + } + + if( gRFAL.wum.cfg.cap.enabled ) + { + /* Only retrive data if there was an WUT or WCAP event (or forced) */ + if( force || (info->irqWut) || (gRFAL.wum.info.irqWuCap) ) + { + st25r3911ReadRegister( ST25R3911_REG_CAPACITANCE_MEASURE_AA_RESULT, &info->cap.reference ); + + if( gRFAL.wum.cfg.cap.autoAvg ) + { + st25r3911ReadRegister( ST25R3911_REG_CAPACITANCE_MEASURE_AA_RESULT, &info->cap.reference ); + } + } + + /* Update IRQ information and clear flag upon retrieving */ + info->cap.irqWu = gRFAL.wum.info.irqWuCap; + gRFAL.wum.info.irqWuCap = false; + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +static void rfalRunWakeUpModeWorker( void ) +{ + uint32_t irqs; + uint8_t aux; + + if( gRFAL.state != RFAL_STATE_WUM ) + { + return; + } + + switch( gRFAL.wum.state ) + { + /*******************************************************************************/ + case RFAL_WUM_STATE_ENABLED: + case RFAL_WUM_STATE_ENABLED_WOKE: + + irqs = st25r3911GetInterrupt( ( ST25R3911_IRQ_MASK_WT | ST25R3911_IRQ_MASK_WAM | ST25R3911_IRQ_MASK_WPH | ST25R3911_IRQ_MASK_WCAP ) ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + + /*******************************************************************************/ + /* Check and mark which measurement(s) cause interrupt */ + if((irqs & ST25R3911_IRQ_MASK_WAM) != 0U) + { + st25r3911ReadRegister( ST25R3911_REG_AMPLITUDE_MEASURE_RESULT, &aux ); /* Debug purposes */ + + gRFAL.wum.info.irqWuAmp = true; + gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE; + } + + if((irqs & ST25R3911_IRQ_MASK_WPH) != 0U) + { + st25r3911ReadRegister( ST25R3911_REG_PHASE_MEASURE_RESULT, &aux ); /* Debug purposes */ + + gRFAL.wum.info.irqWuPha = true; + gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE; + } + + if((irqs & ST25R3911_IRQ_MASK_WCAP) != 0U) + { + st25r3911ReadRegister( ST25R3911_REG_CAPACITANCE_MEASURE_RESULT, &aux ); /* Debug purposes */ + + gRFAL.wum.info.irqWuCap = true; + gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE; + } + + if((irqs & ST25R3911_IRQ_MASK_WT) != 0U) + { + gRFAL.wum.info.irqWut = true; + } + break; + + + /*******************************************************************************/ + case RFAL_WUM_STATE_INITIALIZING: + + irqs = st25r3911GetInterrupt( gRFAL.wum.refWUTrg ); + if( irqs == ST25R3911_IRQ_MASK_NONE ) + { + break; /* No interrupt to process */ + } + + /*******************************************************************************/ + /* Check if Reference measurement is to be obtained at first WU pulse */ + if( (gRFAL.wum.cfg.refWU.enabled == true) && ((irqs & gRFAL.wum.refWUTrg) != 0U) ) + { + st25r3911ClrRegisterBits( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_wu ); + st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_WAM | ST25R3911_IRQ_MASK_WPH ) ); + + /* Set measured value(s) as reference(s) */ + if( gRFAL.wum.cfg.indAmp.enabled ) + { + st25r3911ReadRegister( ST25R3911_REG_AMPLITUDE_MEASURE_RESULT, &aux ); + st25r3911WriteRegister( ST25R3911_REG_AMPLITUDE_MEASURE_REF, aux ); + st25r3911ChangeRegisterBits( ST25R3911_REG_AMPLITUDE_MEASURE_CONF, ST25R3911_REG_AMPLITUDE_MEASURE_CONF_mask_am_d, ((gRFAL.wum.cfg.indAmp.delta) << ST25R3911_REG_AMPLITUDE_MEASURE_CONF_shift_am_d) ); + } + + if( gRFAL.wum.cfg.indPha.enabled ) + { + st25r3911ReadRegister( ST25R3911_REG_PHASE_MEASURE_RESULT, &aux ); + st25r3911WriteRegister( ST25R3911_REG_PHASE_MEASURE_REF, aux ); + st25r3911ChangeRegisterBits( ST25R3911_REG_PHASE_MEASURE_CONF, ST25R3911_REG_PHASE_MEASURE_CONF_mask_pm_d, ((gRFAL.wum.cfg.indPha.delta) << ST25R3911_REG_PHASE_MEASURE_CONF_shift_pm_d) ); + } + + /* Set WU period and enter WU mode */ + aux = (uint8_t)(((uint8_t)gRFAL.wum.cfg.period & 0x0FU) << ST25R3911_REG_WUP_TIMER_CONTROL_shift_wut); + aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.period < (uint8_t)RFAL_WUM_PERIOD_100MS) ? ST25R3911_REG_WUP_TIMER_CONTROL_wur : 0x00U); + st25r3911ChangeRegisterBits( ST25R3911_REG_WUP_TIMER_CONTROL, (ST25R3911_REG_WUP_TIMER_CONTROL_wur | ST25R3911_REG_WUP_TIMER_CONTROL_mask_wut), aux ); + st25r3911SetRegisterBits( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_wu ); + + gRFAL.wum.state = RFAL_WUM_STATE_ENABLED; + return; + } + break; + + /*******************************************************************************/ + default: + /* MISRA 16.4: no empty default statement (a comment being enough) */ + break; + } +} + + +/*******************************************************************************/ +ReturnCode rfalWakeUpModeStop( void ) +{ + /* Check if RFAL is in Wake-up mode */ + if( gRFAL.state != RFAL_STATE_WUM ) + { + return RFAL_ERR_WRONG_STATE; + } + + gRFAL.wum.state = RFAL_WUM_STATE_NOT_INIT; + + /* Re-Enable External Field Detector */ + st25r3911SetRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_en_fd ); + + /* Disable Wake-Up Mode */ + st25r3911ClrRegisterBits( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_wu ); + st25r3911DisableInterrupts( (ST25R3911_IRQ_MASK_WT | ST25R3911_IRQ_MASK_WAM | ST25R3911_IRQ_MASK_WPH | ST25R3911_IRQ_MASK_WCAP) ); + + /* Stop any ongoing activity */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + + /* Re-Enable the Oscillator */ + st25r3911OscOn(); + + /* Set Analog configurations for Wake-up Off event */ + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF) ); + + return RFAL_ERR_NONE; +} + +#endif /* RFAL_FEATURE_WAKEUP_MODE */ + + + +/******************************************************************************* + * Low-Power Mode * + *******************************************************************************/ + +#if RFAL_FEATURE_LOWPOWER_MODE + +/*******************************************************************************/ +ReturnCode rfalLowPowerModeStart( rfalLpMode mode ) +{ + /* Check if RFAL is not initialized */ + if( gRFAL.state < RFAL_STATE_INIT ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Check if mode is supported */ + if( mode != RFAL_LP_MODE_PD ) + { + return RFAL_ERR_NOTSUPP; + } + + /* Stop any ongoing activity */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + + /* Set the device in low power by disabling oscillator, transmitter, receiver and external field detector */ + st25r3911ClrRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_en_fd ); + st25r3911ClrRegisterBits( ST25R3911_REG_OP_CONTROL, ( ST25R3911_REG_OP_CONTROL_en | ST25R3911_REG_OP_CONTROL_rx_en | + ST25R3911_REG_OP_CONTROL_wu | ST25R3911_REG_OP_CONTROL_tx_en ) ); + + + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON) ); + + gRFAL.state = RFAL_STATE_IDLE; + gRFAL.lpm.isRunning = true; + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalLowPowerModeStop( void ) +{ + ReturnCode ret; + + /* Check if RFAL is on right state */ + if( !gRFAL.lpm.isRunning ) + { + return RFAL_ERR_WRONG_STATE; + } + + /* Re-enable device */ + RFAL_EXIT_ON_ERR( ret, st25r3911OscOn()); + st25r3911SetRegisterBits( ST25R3911_REG_AUX, ST25R3911_REG_AUX_en_fd ); + + + rfalSetAnalogConfig( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF) ); + + gRFAL.state = RFAL_STATE_INIT; + return RFAL_ERR_NONE; +} + +#endif /* RFAL_FEATURE_LOWPOWER_MODE */ + + +/******************************************************************************* + * RF Chip * + *******************************************************************************/ + +/*******************************************************************************/ +ReturnCode rfalChipWriteReg( uint16_t reg, const uint8_t* values, uint8_t len ) +{ + if( !st25r3911IsRegValid( (uint8_t)reg) ) + { + return RFAL_ERR_PARAM; + } + + st25r3911WriteMultipleRegisters( (uint8_t)reg, values, len ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipReadReg( uint16_t reg, uint8_t* values, uint8_t len ) +{ + if( !st25r3911IsRegValid( (uint8_t)reg) ) + { + return RFAL_ERR_PARAM; + } + + st25r3911ReadMultipleRegisters( (uint8_t)reg, values, len ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipExecCmd( uint16_t cmd ) +{ + if( !st25r3911IsCmdValid( (uint8_t)cmd) ) + { + return RFAL_ERR_PARAM; + } + + st25r3911ExecuteCommand( (uint8_t) cmd ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipWriteTestReg( uint16_t reg, uint8_t value ) +{ + st25r3911WriteTestRegister( (uint8_t)reg, value ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipReadTestReg( uint16_t reg, uint8_t* value ) +{ + st25r3911ReadTestRegister( (uint8_t)reg, value ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipChangeRegBits( uint16_t reg, uint8_t valueMask, uint8_t value ) +{ + st25r3911ChangeRegisterBits( (uint8_t)reg, valueMask, value ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipChangeTestRegBits( uint16_t reg, uint8_t valueMask, uint8_t value ) +{ + st25r3911ChangeTestRegisterBits( (uint8_t)reg, valueMask, value ); + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipSetRFO( uint8_t rfo ) +{ + st25r3911WriteRegister( ST25R3911_REG_RFO_AM_OFF_LEVEL, rfo ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipGetRFO( uint8_t* result ) +{ + st25r3911ReadRegister(ST25R3911_REG_RFO_AM_OFF_LEVEL, result); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipSetLMMod( uint8_t mod, uint8_t unmod ) +{ + RFAL_NO_WARNING(mod); + RFAL_NO_WARNING(unmod); + + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +ReturnCode rfalChipGetLMMod( uint8_t* mod, uint8_t* unmod ) +{ + if( mod != NULL ) + { + (*mod) = 0U; + } + + if( unmod != NULL ) + { + (*unmod) = 0U; + } + + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasureAmplitude( uint8_t* result ) +{ + st25r3911MeasureAmplitude( result ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasurePhase( uint8_t* result ) +{ + st25r3911MeasurePhase( result ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasureCapacitance( uint8_t* result ) +{ + st25r3911MeasureCapacitance( result ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasurePowerSupply( uint8_t param, uint8_t* result ) +{ + *result = st25r3911MeasurePowerSupply( param ); + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasureIQ( int8_t* resI, int8_t* resQ ) +{ + if( resI != NULL ) + { + (*resI) = 0; + } + + if( resQ != NULL ) + { + (*resQ) = 0; + } + + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +ReturnCode rfalChipMeasureCombinedIQ( uint8_t* result ) +{ + if( result != NULL ) + { + (*result) = 0U; + } + + return RFAL_ERR_NOTSUPP; +} + + +/*******************************************************************************/ +ReturnCode rfalChipSetAntennaMode( bool single, bool rfiox ) +{ + return st25r3911SetAntennaMode( single, rfiox ); +} + + + +/*******************************************************************************/ + +/* All bitrates defined in ST25R3911B registers are nibbles. This rfal code + * up there only works if equality to values of enum rfalBitrate is guaranteed: */ +extern uint8_t equalityGuard_RFAL_BR_106[(ST25R3911_REG_BIT_RATE_rxrate_106==(uint8_t)RFAL_BR_106)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_212[(ST25R3911_REG_BIT_RATE_rxrate_212==(uint8_t)RFAL_BR_212)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_424[(ST25R3911_REG_BIT_RATE_rxrate_424==(uint8_t)RFAL_BR_424)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_848[(ST25R3911_REG_BIT_RATE_rxrate_848==(uint8_t)RFAL_BR_848)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_1695[(ST25R3911_REG_BIT_RATE_rxrate_1695==(uint8_t)RFAL_BR_1695)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_3390[(ST25R3911_REG_BIT_RATE_rxrate_3390==(uint8_t)RFAL_BR_3390)?1:(-1)]; +extern uint8_t equalityGuard_RFAL_BR_6780[(ST25R3911_REG_BIT_RATE_rxrate_6780==(uint8_t)RFAL_BR_6780)?1:(-1)]; diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.c new file mode 100644 index 0000000..660e39a --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.c @@ -0,0 +1,780 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief ST25R3911 high level interface + * + */ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ + +#include "st25r3911.h" +#include "st25r3911_com.h" +#include "st25r3911_interrupt.h" +#include "rfal_utils.h" + + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef ST25R3911 +#error "RFAL: Missing ST25R device selection. Please globally define ST25R3911." +#endif /* ST25R3911 */ + +/* +****************************************************************************** +* LOCAL DEFINES +****************************************************************************** +*/ + +#define ST25R3911_OSC_STABLE_TIMEOUT 10U /*!< Timeout for Oscillator to get stable, datasheet: 700us, take 5 ms */ +#define ST25R3911_CA_TIMEOUT 10U /*!< Timeout for Collision Avoidance command */ +#define ST25R3911_TOUT_CALIBRATE_CAP_SENSOR 4U /*!< Max duration Calibrate Capacitive Sensor command Datasheet: 3ms */ + +#define ST25R3911_TEST_REG_PATTERN 0x33U /*!< Register Read Write test pattern used during self test */ +#define ST25R3911_TEST_WU_TOUT 12U /*!< Timetout used on WU timer during self test */ +#define ST25R3911_TEST_TMR_TOUT 20U /*!< Timetout used during self test */ +#define ST25R3911_TEST_TMR_TOUT_DELTA 2U /*!< Timetout used during self test */ +#define ST25R3911_TEST_TMR_TOUT_8FC (ST25R3911_TEST_TMR_TOUT * 1695U) /*!< Timeout in 8/fc */ + +/* +****************************************************************************** +* LOCAL CONSTANTS +****************************************************************************** +*/ + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ +static uint32_t st25r3911NoResponseTime_64fcs; + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode st25r3911ExecuteCommandAndGetResult(uint8_t cmd, uint8_t resreg, uint8_t sleeptime, uint8_t* result); + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ + +void st25r3911TxRxOn( void ) +{ + st25r3911SetRegisterBits(ST25R3911_REG_OP_CONTROL, (ST25R3911_REG_OP_CONTROL_rx_en | ST25R3911_REG_OP_CONTROL_tx_en) ); +} + +void st25r3911TxRxOff( void ) +{ + st25r3911ClrRegisterBits(ST25R3911_REG_OP_CONTROL, (ST25R3911_REG_OP_CONTROL_rx_en | ST25R3911_REG_OP_CONTROL_tx_en) ); +} + + +ReturnCode st25r3911OscOn( void ) +{ + /* Check if oscillator is already turned on and stable */ + /* Use ST25R3911_REG_OP_CONTROL_en instead of ST25R3911_REG_AUX_DISPLAY_osc_ok to be on the safe side */ + if( !st25r3911CheckReg( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_en, ST25R3911_REG_OP_CONTROL_en ) ) + { + /* Clear any eventual previous oscillator IRQ */ + st25r3911GetInterrupt( ST25R3911_IRQ_MASK_OSC ); + + /* Enable oscillator frequency stable IRQ */ + st25r3911EnableInterrupts(ST25R3911_IRQ_MASK_OSC); + + /* Clear any oscillator IRQ that was potentially pending on ST25R */ + st25r3911GetInterrupt( ST25R3911_IRQ_MASK_OSC ); + + /* enable oscillator and regulator output */ + st25r3911ModifyRegister(ST25R3911_REG_OP_CONTROL, 0x00, ST25R3911_REG_OP_CONTROL_en); + + /* wait for the oscillator interrupt */ + st25r3911WaitForInterruptsTimed(ST25R3911_IRQ_MASK_OSC, ST25R3911_OSC_STABLE_TIMEOUT); + st25r3911DisableInterrupts(ST25R3911_IRQ_MASK_OSC); + } + + /* Double check that OSC_OK signal is set */ + if( !st25r3911CheckReg( ST25R3911_REG_AUX_DISPLAY, ST25R3911_REG_AUX_DISPLAY_osc_ok, ST25R3911_REG_AUX_DISPLAY_osc_ok ) ) + { + return RFAL_ERR_SYSTEM; + } + + return RFAL_ERR_NONE; +} + + +ReturnCode st25r3911Initialize(void) +{ + uint16_t vdd_mV; + ReturnCode ret; + + /* Ensure a defined chip select state */ + platformSpiDeselect(); + + /* Execute a Set Default on ST25R3911 */ + st25r3911ExecuteCommand(ST25R3911_CMD_SET_DEFAULT); + + /* Set Registers which are not affected by Set default command to default value */ + st25r3911WriteRegister(ST25R3911_REG_OP_CONTROL, 0x00); + st25r3911WriteRegister(ST25R3911_REG_IO_CONF1, ST25R3911_REG_IO_CONF1_osc); + st25r3911WriteRegister(ST25R3911_REG_IO_CONF2, 0x00); + + + /* Enable pull downs on miso line */ + st25r3911ModifyRegister(ST25R3911_REG_IO_CONF2, 0x00, + ST25R3911_REG_IO_CONF2_miso_pd1 | + ST25R3911_REG_IO_CONF2_miso_pd2); + + + if( !st25r3911CheckChipID( NULL ) ) + { + platformErrorHandle(); + return RFAL_ERR_HW_MISMATCH; + } + + st25r3911InitInterrupts(); + +#ifdef ST25R_SELFTEST + /****************************************************************************** + * Check communication interface: + * - write a pattern in a register + * - reads back the register value + * - return RFAL_ERR_IO in case the read value is different + */ + st25r3911WriteRegister( ST25R3911_REG_BIT_RATE, ST25R3911_TEST_REG_PATTERN ); + if( !st25r3911CheckReg( ST25R3911_REG_BIT_RATE, (ST25R3911_REG_BIT_RATE_mask_rxrate | ST25R3911_REG_BIT_RATE_mask_txrate), ST25R3911_TEST_REG_PATTERN ) ) + { + platformErrorHandle(); + return RFAL_ERR_IO; + } + /* Restore default value */ + st25r3911WriteRegister( ST25R3911_REG_BIT_RATE, 0x00 ); + + /* + * Check IRQ Handling: + * - use the Wake-up timer to trigger an IRQ + * - wait the Wake-up timer interrupt + * - return RFAL_ERR_TIMEOUT when the Wake-up timer interrupt is not received + */ + st25r3911WriteRegister( ST25R3911_REG_WUP_TIMER_CONTROL, (ST25R3911_REG_WUP_TIMER_CONTROL_wur|ST25R3911_REG_WUP_TIMER_CONTROL_wto) ); + st25r3911EnableInterrupts( ST25R3911_IRQ_MASK_WT ); + st25r3911ExecuteCommand( ST25R3911_CMD_START_WUP_TIMER ); + if(st25r3911WaitForInterruptsTimed( ST25R3911_IRQ_MASK_WT, ST25R3911_TEST_WU_TOUT) == 0U ) + { + platformErrorHandle(); + return RFAL_ERR_TIMEOUT; + } + + st25r3911DisableInterrupts( ST25R3911_IRQ_MASK_WT ); + st25r3911WriteRegister( ST25R3911_REG_WUP_TIMER_CONTROL, 0U ); + /*******************************************************************************/ +#endif /* ST25R_SELFTEST */ + + ret = st25r3911OscOn(); + if( ret != RFAL_ERR_NONE ) + { + return ret; + } + + /* Measure vdd and set sup3V bit accordingly */ + vdd_mV = st25r3911MeasureVoltage(ST25R3911_REG_REGULATOR_CONTROL_mpsv_vdd); + + st25r3911ModifyRegister(ST25R3911_REG_IO_CONF2, + ST25R3911_REG_IO_CONF2_sup3V, + (uint8_t)((vdd_mV < 3600U)?ST25R3911_REG_IO_CONF2_sup3V:0U)); + + /* Make sure Transmitter and Receiver are disabled */ + st25r3911TxRxOff(); + + +#ifdef ST25R_SELFTEST_TIMER + /****************************************************************************** + * Check SW timer operation : + * - use the General Purpose timer to measure an amount of time + * - test whether an interrupt is seen when less time was given + * - test whether an interrupt is seen when sufficient time was given + */ + + st25r3911EnableInterrupts( ST25R3911_IRQ_MASK_GPE ); + st25r3911StartGPTimer_8fcs( (uint16_t)ST25R3911_TEST_TMR_TOUT_8FC, ST25R3911_REG_GPT_CONTROL_gptc_no_trigger ); + if( st25r3911WaitForInterruptsTimed(ST25R3911_IRQ_MASK_GPE, (ST25R3911_TEST_TMR_TOUT - ST25R3911_TEST_TMR_TOUT_DELTA)) != 0U ) + { + platformErrorHandle(); + return RFAL_ERR_SYSTEM; + } + + /* Stop all activities to stop the GP timer */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + (void)st25r3911GetInterrupt( ST25R3911_IRQ_MASK_GPE ); + st25r3911StartGPTimer_8fcs( (uint16_t)ST25R3911_TEST_TMR_TOUT_8FC, ST25R3911_REG_GPT_CONTROL_gptc_no_trigger ); + if(st25r3911WaitForInterruptsTimed( ST25R3911_IRQ_MASK_GPE, (ST25R3911_TEST_TMR_TOUT + ST25R3911_TEST_TMR_TOUT_DELTA)) == 0U ) + { + platformErrorHandle(); + return RFAL_ERR_SYSTEM; + } + + /* Stop all activities to stop the GP timer */ + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + /*******************************************************************************/ +#endif /* ST25R_SELFTEST_TIMER */ + + + /* After reset all interrupts are enabled. so disable them at first */ + st25r3911DisableInterrupts( ST25R3911_IRQ_MASK_ALL ); + /* And clear them, just to be sure... */ + st25r3911ClearInterrupts(); + + return RFAL_ERR_NONE; +} + +void st25r3911Deinitialize(void) +{ + st25r3911DisableInterrupts(ST25R3911_IRQ_MASK_ALL); + + /* Disabe Tx and Rx, Keep OSC */ + st25r3911TxRxOff(); + + return; +} + +ReturnCode st25r3911AdjustRegulators(uint16_t* result_mV) +{ + uint8_t result; + uint8_t io_conf2; + ReturnCode err = RFAL_ERR_NONE; + + /* Reset logic and set regulated voltages to be defined by result of Adjust Regulators command */ + st25r3911SetRegisterBits( ST25R3911_REG_REGULATOR_CONTROL, ST25R3911_REG_REGULATOR_CONTROL_reg_s ); + st25r3911ClrRegisterBits( ST25R3911_REG_REGULATOR_CONTROL, ST25R3911_REG_REGULATOR_CONTROL_reg_s ); + + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_ADJUST_REGULATORS, + ST25R3911_REG_REGULATOR_RESULT, + 5, + &result); + + st25r3911ReadRegister(ST25R3911_REG_IO_CONF2, &io_conf2); + + result >>= ST25R3911_REG_REGULATOR_RESULT_shift_reg; + result -= 5U; + if (result_mV != NULL) + { + if((io_conf2 & ST25R3911_REG_IO_CONF2_sup3V) != 0U) + { + *result_mV = 2400; + *result_mV += (uint16_t)result * 100U; + } + else + { + *result_mV = 3900; + *result_mV += (uint16_t)result * 120U; + } + } + return err; +} + +void st25r3911MeasureAmplitude(uint8_t* result) +{ + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_MEASURE_AMPLITUDE, + ST25R3911_REG_AD_RESULT, + 10, + result); +} + +void st25r3911MeasurePhase(uint8_t* result) +{ + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_MEASURE_PHASE, + ST25R3911_REG_AD_RESULT, + 10, + result); +} + +void st25r3911MeasureCapacitance(uint8_t* result) +{ + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_MEASURE_CAPACITANCE, + ST25R3911_REG_AD_RESULT, + 10, + result); +} + +void st25r3911CalibrateAntenna(uint8_t* result) +{ + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_CALIBRATE_ANTENNA, + ST25R3911_REG_ANT_CAL_RESULT, + 10, + result); +} + +void st25r3911CalibrateModulationDepth(uint8_t* result) +{ + st25r3911ExecuteCommandAndGetResult(ST25R3911_CMD_CALIBRATE_MODULATION, + ST25R3911_REG_AM_MOD_DEPTH_RESULT, + 10, + result); +} + + +ReturnCode st25r3911CalibrateCapacitiveSensor(uint8_t* result) +{ + ReturnCode ret; + uint8_t res; + + /* Clear Manual calibration values to enable automatic calibration mode */ + st25r3911ClrRegisterBits( ST25R3911_REG_CAP_SENSOR_CONTROL, ST25R3911_REG_CAP_SENSOR_CONTROL_mask_cs_mcal ); + + /* Execute automatic calibration */ + ret = st25r3911ExecuteCommandAndGetResult( ST25R3911_CMD_CALIBRATE_C_SENSOR, ST25R3911_REG_CAP_SENSOR_RESULT, ST25R3911_TOUT_CALIBRATE_CAP_SENSOR, &res ); + + /* Check wether the calibration was successull */ + if( ((res & ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_end) != ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_end) || + ((res & ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_err) == ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_err) || (ret != RFAL_ERR_NONE) ) + { + return RFAL_ERR_IO; + } + + if( result != NULL ) + { + (*result) = (uint8_t)(res >> ST25R3911_REG_CAP_SENSOR_CONTROL_shift_cs_mcal); + } + + return RFAL_ERR_NONE; +} + + +ReturnCode st25r3911SetBitrate(uint8_t txRate, uint8_t rxRate) +{ + uint8_t reg; + + st25r3911ReadRegister(ST25R3911_REG_BIT_RATE, ®); + if (rxRate != ST25R3911_BR_DO_NOT_SET) + { + if(rxRate > ST25R3911_BR_3390) + { + return RFAL_ERR_PARAM; + } + else + { + reg = (uint8_t)(reg & ~ST25R3911_REG_BIT_RATE_mask_rxrate); /* MISRA 10.3 */ + reg |= rxRate << ST25R3911_REG_BIT_RATE_shift_rxrate; + } + } + if (txRate != ST25R3911_BR_DO_NOT_SET) + { + if(txRate > ST25R3911_BR_6780) + { + return RFAL_ERR_PARAM; + } + else + { + reg = (uint8_t)(reg & ~ST25R3911_REG_BIT_RATE_mask_txrate); /* MISRA 10.3 */ + reg |= txRate<> ST25R3911_REG_FIFO_RX_STATUS2_shift_fifo_lb); +} + +uint32_t st25r3911GetNoResponseTime_64fcs(void) +{ + return st25r3911NoResponseTime_64fcs; +} + +void st25r3911StartGPTimer_8fcs(uint16_t gpt_8fcs, uint8_t trigger_source) +{ + st25r3911SetGPTime_8fcs(gpt_8fcs); + + st25r3911ModifyRegister(ST25R3911_REG_GPT_CONTROL, + ST25R3911_REG_GPT_CONTROL_gptc_mask, + trigger_source); + if (trigger_source == 0U) + { + st25r3911ExecuteCommand(ST25R3911_CMD_START_GP_TIMER); + } + + return; +} + +void st25r3911SetGPTime_8fcs(uint16_t gpt_8fcs) +{ + st25r3911WriteRegister(ST25R3911_REG_GPT1, (uint8_t)(gpt_8fcs >> 8)); + st25r3911WriteRegister(ST25R3911_REG_GPT2, (uint8_t)(gpt_8fcs & 0xffU)); + + return; +} + +bool st25r3911CheckReg( uint8_t reg, uint8_t mask, uint8_t value ) +{ + uint8_t regVal; + + regVal = 0; + st25r3911ReadRegister( reg, ®Val ); + + return ((regVal & mask) == value ); +} + + +bool st25r3911CheckChipID( uint8_t *rev ) +{ + uint8_t ID; + + ID = 0; + st25r3911ReadRegister( ST25R3911_REG_IC_IDENTITY, &ID ); + + /* Check if IC Identity Register contains ST25R3911's IC type code */ + if( (ID & ST25R3911_REG_IC_IDENTITY_mask_ic_type) != ST25R3911_REG_IC_IDENTITY_ic_type ) + { + return false; + } + + if(rev != NULL) + { + *rev = (ID & ST25R3911_REG_IC_IDENTITY_mask_ic_rev); + } + + return true; +} + +ReturnCode st25r3911SetNoResponseTime_64fcs(uint32_t nrt_64fcs) +{ + ReturnCode err = RFAL_ERR_NONE; + uint8_t nrt_step = 0; + uint32_t noResponseTime_64fcs = nrt_64fcs; /* MISRA 17.8: Use intermediate variable */ + + st25r3911NoResponseTime_64fcs = noResponseTime_64fcs; + if (noResponseTime_64fcs > (uint32_t)0xFFFFU) + { + nrt_step = ST25R3911_REG_GPT_CONTROL_nrt_step; + noResponseTime_64fcs = (noResponseTime_64fcs + 63U) / 64U; + if (noResponseTime_64fcs > (uint32_t)0xFFFFU) + { + noResponseTime_64fcs = 0xFFFFU; + err = RFAL_ERR_PARAM; + } + st25r3911NoResponseTime_64fcs = 64U * noResponseTime_64fcs; + } + + st25r3911ModifyRegister(ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_step, nrt_step); + st25r3911WriteRegister(ST25R3911_REG_NO_RESPONSE_TIMER1, (uint8_t)(noResponseTime_64fcs >> 8)); + st25r3911WriteRegister(ST25R3911_REG_NO_RESPONSE_TIMER2, (uint8_t)(noResponseTime_64fcs & 0xffU)); + + return err; +} + +ReturnCode st25r3911SetStartNoResponseTime_64fcs(uint32_t nrt_64fcs) +{ + ReturnCode err; + + err = st25r3911SetNoResponseTime_64fcs( nrt_64fcs ); + if(err == RFAL_ERR_NONE) + { + st25r3911ExecuteCommand(ST25R3911_CMD_START_NO_RESPONSE_TIMER); + } + + return err; +} + +ReturnCode st25r3911PerformCollisionAvoidance( uint8_t FieldONCmd, uint8_t pdThreshold, uint8_t caThreshold, uint8_t nTRFW ) +{ + uint8_t treMask; + uint32_t irqs; + + if( (FieldONCmd != ST25R3911_CMD_INITIAL_RF_COLLISION) && + (FieldONCmd != ST25R3911_CMD_RESPONSE_RF_COLLISION_0) && + (FieldONCmd != ST25R3911_CMD_RESPONSE_RF_COLLISION_N) ) + { + return RFAL_ERR_PARAM; + } + + /* Check if new thresholds are to be applied */ + if( (pdThreshold != ST25R3911_THRESHOLD_DO_NOT_SET) || (caThreshold != ST25R3911_THRESHOLD_DO_NOT_SET) ) + { + treMask = 0; + + if(pdThreshold != ST25R3911_THRESHOLD_DO_NOT_SET) + { + treMask |= ST25R3911_REG_FIELD_THRESHOLD_mask_trg; + } + + if(caThreshold != ST25R3911_THRESHOLD_DO_NOT_SET) + { + treMask |= ST25R3911_REG_FIELD_THRESHOLD_mask_rfe; + } + + /* Set Detection Threshold and|or Collision Avoidance Threshold */ + st25r3911ChangeRegisterBits( ST25R3911_REG_FIELD_THRESHOLD, treMask, (pdThreshold & ST25R3911_REG_FIELD_THRESHOLD_mask_trg) | (caThreshold & ST25R3911_REG_FIELD_THRESHOLD_mask_rfe ) ); + } + + /* Set n x TRFW */ + st25r3911ModifyRegister(ST25R3911_REG_AUX, ST25R3911_REG_AUX_mask_nfc_n, (nTRFW & ST25R3911_REG_AUX_mask_nfc_n) ); + + /* Enable and clear CA specific interrupts and execute command */ + st25r3911EnableInterrupts( (ST25R3911_IRQ_MASK_CAC | ST25R3911_IRQ_MASK_CAT) ); + st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_CAC | ST25R3911_IRQ_MASK_CAT) ); + + st25r3911ExecuteCommand(FieldONCmd); + + irqs = st25r3911WaitForInterruptsTimed(ST25R3911_IRQ_MASK_CAC | ST25R3911_IRQ_MASK_CAT, ST25R3911_CA_TIMEOUT ); + + /* Clear any previous External Field events and disable CA specific interrupts */ + st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_EOF | ST25R3911_IRQ_MASK_EON) ); + st25r3911DisableInterrupts(ST25R3911_IRQ_MASK_CAC | ST25R3911_IRQ_MASK_CAT); + + + if((ST25R3911_IRQ_MASK_CAC & irqs) != 0U) /* Collision occurred */ + { + return RFAL_ERR_RF_COLLISION; + } + + if((ST25R3911_IRQ_MASK_CAT & irqs) != 0U) /* No Collision detected, Field On */ + { + return RFAL_ERR_NONE; + } + + /* No interrupt detected */ + return RFAL_ERR_INTERNAL; +} + +ReturnCode st25r3911GetRegsDump(uint8_t* resRegDump, uint8_t* sizeRegDump) +{ + uint8_t regIt; + uint8_t regDump[ST25R3911_REG_IC_IDENTITY+1U]; + + if( (sizeRegDump == NULL) || (resRegDump == NULL) ) + { + return RFAL_ERR_PARAM; + } + + for( regIt = ST25R3911_REG_IO_CONF1; regIt < RFAL_SIZEOF_ARRAY(regDump); regIt++ ) + { + st25r3911ReadRegister(regIt, ®Dump[regIt] ); + } + + *sizeRegDump = RFAL_MIN(*sizeRegDump, regIt); + if( *sizeRegDump > 0U ) /* MISRA 21.18 */ + { + RFAL_MEMCPY(resRegDump, regDump, *sizeRegDump ); + } + + return RFAL_ERR_NONE; +} + + +void st25r3911SetNumTxBits( uint32_t nBits ) +{ + st25r3911WriteRegister(ST25R3911_REG_NUM_TX_BYTES2, (uint8_t)((nBits >> 0) & 0xffU)); + st25r3911WriteRegister(ST25R3911_REG_NUM_TX_BYTES1, (uint8_t)((nBits >> 8) & 0xffU)); +} + + +bool st25r3911IsCmdValid( uint8_t cmd ) +{ + if( (!((cmd >= ST25R3911_CMD_SET_DEFAULT) && (cmd <= ST25R3911_CMD_ANALOG_PRESET))) && + (!((cmd >= ST25R3911_CMD_MASK_RECEIVE_DATA) && (cmd <= ST25R3911_CMD_CLEAR_RSSI))) && + (!((cmd >= ST25R3911_CMD_TRANSPARENT_MODE) && (cmd <= ST25R3911_CMD_START_NO_RESPONSE_TIMER))) && + (!((cmd >= ST25R3911_CMD_TEST_CLEARA) && (cmd <= ST25R3911_CMD_FUSE_PPROM))) ) + { + return false; + } + return true; +} + +ReturnCode st25r3911StreamConfigure(const struct st25r3911StreamConfig *config) +{ + uint8_t smd = 0; + uint8_t mode; + + if (config->useBPSK != 0U) + { + mode = ST25R3911_REG_MODE_om_bpsk_stream; + if ((config->din<2U) || (config->din>4U)) /* not in fc/4 .. fc/16 */ + { + return RFAL_ERR_PARAM; + } + smd |= (4U - config->din) << ST25R3911_REG_STREAM_MODE_shift_scf; + + } + else + { + mode = ST25R3911_REG_MODE_om_subcarrier_stream; + if ((config->din<3U) || (config->din>6U)) /* not in fc/8 .. fc/64 */ + { + return RFAL_ERR_PARAM; + } + smd |= (6U - config->din) << ST25R3911_REG_STREAM_MODE_shift_scf; + if (config->report_period_length == 0U) + { + return RFAL_ERR_PARAM; + } + } + + if ((config->dout<1U) || (config->dout>7U)) /* not in fc/2 .. fc/128 */ + { + return RFAL_ERR_PARAM; + } + smd |= (7U - config->dout) << ST25R3911_REG_STREAM_MODE_shift_stx; + + if (config->report_period_length > 3U) + { + return RFAL_ERR_PARAM; + } + smd |= config->report_period_length << ST25R3911_REG_STREAM_MODE_shift_scp; + + st25r3911WriteRegister(ST25R3911_REG_STREAM_MODE, smd); + st25r3911ChangeRegisterBits(ST25R3911_REG_MODE, ST25R3911_REG_MODE_mask_om, mode); + + return RFAL_ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode st25r3911GetRSSI( uint16_t *amRssi, uint16_t *pmRssi ) +{ + /*******************************************************************************/ + /* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */ + /*< ST25R3911 RSSI Display Reg values:0 1 2 3 4 5 6 7 8 9 a b c d e f */ + const uint16_t st25r3911Rssi2mV[16] = { 10 ,20 ,27 ,37 ,52 ,72 ,99 ,136 ,190 ,262 ,357 ,500 ,686 ,950, 1150, 1150 }; + + /* ST25R3911 2/3 stage gain reduction [dB] 0 0 0 0 0 3 6 9 12 15 18 na na na na na */ + const uint16_t st25r3911Gain2Percent[16] = { 100, 100, 100, 100, 100, 141, 200, 281, 398, 562, 794, 1, 1, 1, 1, 1 }; + /*******************************************************************************/ + + uint8_t rssi; + uint8_t gainRed; + + st25r3911ReadRegister( ST25R3911_REG_RSSI_RESULT, &rssi ); + st25r3911ReadRegister( ST25R3911_REG_GAIN_RED_STATE, &gainRed ); + + if( amRssi != NULL ) + { + *amRssi = (uint16_t) ( ( (uint32_t)st25r3911Rssi2mV[ (rssi >> ST25R3911_REG_RSSI_RESULT_shift_rssi_am) ] * (uint32_t)st25r3911Gain2Percent[ (gainRed >> ST25R3911_REG_GAIN_RED_STATE_shift_gs_am) ] ) / 100U ); + } + + if( pmRssi != NULL ) + { + *pmRssi = (uint16_t) ( ( (uint32_t)st25r3911Rssi2mV[ (rssi & ST25R3911_REG_RSSI_RESULT_mask_rssi_pm) ] * (uint32_t)st25r3911Gain2Percent[ (gainRed & ST25R3911_REG_GAIN_RED_STATE_mask_gs_pm) ] ) / 100U ); + } + + return RFAL_ERR_NONE; +} + + +/*******************************************************************************/ +ReturnCode st25r3911SetAntennaMode( bool single, bool rfiox ) +{ + uint8_t val; + + val = 0U; + val |= ((single)? ST25R3911_REG_IO_CONF1_single : 0U); + val |= ((rfiox) ? ST25R3911_REG_IO_CONF1_rfo2 : 0U); + + st25r3911ChangeRegisterBits( ST25R3911_REG_IO_CONF1, (ST25R3911_REG_IO_CONF1_single | ST25R3911_REG_IO_CONF1_rfo2), val ); + return RFAL_ERR_NONE; +} + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief Executes a direct command and returns the result + * + * This function executes the direct command given by \a cmd waits for + * \a sleeptime for I_dct and returns the result read from register \a resreg. + * No checking of the validity of the cmd is performed. + * + * \param[in] cmd: direct command to execute. + * \param[in] resreg: Address of the register containing the result. + * \param[in] sleeptime: time in milliseconds to wait before reading the result. + * \param[out] result: 8 bit long result + * + ***************************************************************************** + */ +static ReturnCode st25r3911ExecuteCommandAndGetResult(uint8_t cmd, uint8_t resreg, uint8_t sleeptime, uint8_t* result) +{ + + st25r3911EnableInterrupts(ST25R3911_IRQ_MASK_DCT); + st25r3911GetInterrupt(ST25R3911_IRQ_MASK_DCT); + st25r3911ExecuteCommand(cmd); + st25r3911WaitForInterruptsTimed(ST25R3911_IRQ_MASK_DCT, sleeptime); + st25r3911DisableInterrupts(ST25R3911_IRQ_MASK_DCT); + + /* read out the result if the pointer is not NULL */ + if (result != NULL) + { + st25r3911ReadRegister(resreg, result); + } + + return RFAL_ERR_NONE; +} diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.h new file mode 100644 index 0000000..635d642 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911.h @@ -0,0 +1,631 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief ST25R3911 declaration file + * + * API: + * - Initialize ST25R3911 driver: #st25r3911Initialize + * - Deinitialize ST25R3911 driver: #st25r3911Deinitialize + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup ST25R3911 + * \brief RFAL ST25R3911 Driver + * @{ + * + * \addtogroup ST25R3911_Driver + * \brief RFAL ST25R3911 Driver + * @{ + * + */ + +#ifndef ST25R3911_H +#define ST25R3911_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" +#include "rfal_utils.h" + +/* +****************************************************************************** +* GLOBAL DATATYPES +****************************************************************************** +*/ + +/*! Parameters how the stream mode should work */ +struct st25r3911StreamConfig { + uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK */ + uint8_t din; /*!< the divider for the in subcarrier frequency: fc/2^din */ + uint8_t dout; /*!< the divider for the in subcarrier frequency fc/2^dout */ + uint8_t report_period_length; /*!< the length of the reporting period 2^report_period_length */ +}; + + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ +#define ST25R3911_FDT_NONE 0x00U /*!< Value indicating not to perform FDT */ + +#define MS_TO_64FCS(A) ((A) * 212U) /*!< Converts from ms to 64/fc steps */ +#define MS_FROM_64FCS(A) ((A) / 212U) /*!< Converts from 64/fc steps to ms */ + +/* ST25R3911 direct commands */ +#define ST25R3911_CMD_SET_DEFAULT 0xC1U /*!< Puts the chip in default state (same as after power-up) */ +#define ST25R3911_CMD_CLEAR_FIFO 0xC2U /*!< Stops all activities and clears FIFO */ +#define ST25R3911_CMD_TRANSMIT_WITH_CRC 0xC4U /*!< Transmit with CRC */ +#define ST25R3911_CMD_TRANSMIT_WITHOUT_CRC 0xC5U /*!< Transmit without CRC */ +#define ST25R3911_CMD_TRANSMIT_REQA 0xC6U /*!< Transmit REQA */ +#define ST25R3911_CMD_TRANSMIT_WUPA 0xC7U /*!< Transmit WUPA */ +#define ST25R3911_CMD_INITIAL_RF_COLLISION 0xC8U /*!< NFC transmit with Initial RF Collision Avoidance */ +#define ST25R3911_CMD_RESPONSE_RF_COLLISION_N 0xC9U /*!< NFC transmit with Response RF Collision Avoidance */ +#define ST25R3911_CMD_RESPONSE_RF_COLLISION_0 0xCAU /*!< NFC transmit with Response RF Collision Avoidance with n=0 */ +#define ST25R3911_CMD_NORMAL_NFC_MODE 0xCBU /*!< NFC switch to normal NFC mode */ +#define ST25R3911_CMD_ANALOG_PRESET 0xCCU /*!< Analog Preset */ +#define ST25R3911_CMD_MASK_RECEIVE_DATA 0xD0U /*!< Mask receive data */ +#define ST25R3911_CMD_UNMASK_RECEIVE_DATA 0xD1U /*!< Unmask receive data */ +#define ST25R3911_CMD_MEASURE_AMPLITUDE 0xD3U /*!< Measure singal amplitude on RFI inputs */ +#define ST25R3911_CMD_SQUELCH 0xD4U /*!< Squelch */ +#define ST25R3911_CMD_CLEAR_SQUELCH 0xD5U /*!< Clear Squelch */ +#define ST25R3911_CMD_ADJUST_REGULATORS 0xD6U /*!< Adjust regulators */ +#define ST25R3911_CMD_CALIBRATE_MODULATION 0xD7U /*!< Calibrate modulation depth */ +#define ST25R3911_CMD_CALIBRATE_ANTENNA 0xD8U /*!< Calibrate antenna */ +#define ST25R3911_CMD_MEASURE_PHASE 0xD9U /*!< Measure phase between RFO and RFI signal */ +#define ST25R3911_CMD_CLEAR_RSSI 0xDAU /*!< clear RSSI bits and restart the measurement */ +#define ST25R3911_CMD_TRANSPARENT_MODE 0xDCU /*!< Transparent mode */ +#define ST25R3911_CMD_CALIBRATE_C_SENSOR 0xDDU /*!< Calibrate the capacitive sensor */ +#define ST25R3911_CMD_MEASURE_CAPACITANCE 0xDEU /*!< Measure capacitance */ +#define ST25R3911_CMD_MEASURE_VDD 0xDFU /*!< Measure power supply voltage */ +#define ST25R3911_CMD_START_GP_TIMER 0xE0U /*!< Start the general purpose timer */ +#define ST25R3911_CMD_START_WUP_TIMER 0xE1U /*!< Start the wake-up timer */ +#define ST25R3911_CMD_START_MASK_RECEIVE_TIMER 0xE2U /*!< Start the mask-receive timer */ +#define ST25R3911_CMD_START_NO_RESPONSE_TIMER 0xE3U /*!< Start the no-repsonse timer */ +#define ST25R3911_CMD_TEST_CLEARA 0xFAU /*!< Clear Test register */ +#define ST25R3911_CMD_TEST_CLEARB 0xFBU /*!< Clear Test register */ +#define ST25R3911_CMD_TEST_ACCESS 0xFCU /*!< Enable R/W access to the test registers */ +#define ST25R3911_CMD_LOAD_PPROM 0xFDU /*!< Load data from the poly fuses to RAM */ +#define ST25R3911_CMD_FUSE_PPROM 0xFEU /*!< Fuse poly fuses with data from the RAM */ + + +#define ST25R3911_FIFO_DEPTH 96U /*!< Depth of FIFO */ + +#define ST25R3911_THRESHOLD_DO_NOT_SET 0xFFU /*!< Indicates not to change this Threshold */ + +#define ST25R3911_BR_DO_NOT_SET 0xFFU /*!< Indicates not to change this Bit Rate */ +#define ST25R3911_BR_106 0x00U /*!< ST25R3911 Bit Rate 106 kbit/s (fc/128) */ +#define ST25R3911_BR_212 0x01U /*!< ST25R3911 Bit Rate 212 kbit/s (fc/64) */ +#define ST25R3911_BR_424 0x02U /*!< ST25R3911 Bit Rate 424 kbit/s (fc/32) */ +#define ST25R3911_BR_848 0x03U /*!< ST25R3911 Bit Rate 848 kbit/s (fc/16) */ +#define ST25R3911_BR_1695 0x04U /*!< ST25R3911 Bit Rate 1696 kbit/s (fc/8) */ +#define ST25R3911_BR_3390 0x05U /*!< ST25R3911 Bit Rate 3390 kbit/s (fc/4) */ +#define ST25R3911_BR_6780 0x06U /*!< ST25R3911 Bit Rate 6780 kbit/s (fc/2) */ + +/* +****************************************************************************** +* GLOBAL MACROS +****************************************************************************** +*/ + +/*! Checks if General Purpose Timer is still running by reading gpt_on flag */ +#define st25r3911IsGPTRunning( ) ( st25r3911CheckReg(ST25R3911_REG_REGULATOR_RESULT, ST25R3911_REG_REGULATOR_RESULT_gpt_on, ST25R3911_REG_REGULATOR_RESULT_gpt_on) ) + +/*! Checks if CRC is configured to be in FIFO */ +#define st25r3911IsCRCinFIFO( ) ( st25r3911CheckReg(ST25R3911_REG_AUX, ST25R3911_REG_AUX_crc_2_fifo, ST25R3911_REG_AUX_crc_2_fifo) ) + +/*! Checks if External Filed is detected by reading ST25R3911 External Field + * Detector output */ +#define st25r3911IsExtFieldOn() ( st25r3911CheckReg(ST25R3911_REG_AUX_DISPLAY, ST25R3911_REG_AUX_DISPLAY_efd_o, ST25R3911_REG_AUX_DISPLAY_efd_o ) ) + +/*! Checks if Transmitter is enabled (Field On) */ +#define st25r3911IsTxEnabled() ( st25r3911CheckReg(ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_tx_en, ST25R3911_REG_OP_CONTROL_tx_en ) ) + +/*! Turn Off Tx (Field Off) */ +#define st25r3911TxOff() st25r3911ClrRegisterBits(ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_tx_en ); + +/*! Checks if last FIFO byte is complete */ +#define st25r3911IsLastFIFOComplete() st25r3911CheckReg( ST25R3911_REG_FIFO_RX_STATUS2, ST25R3911_REG_FIFO_RX_STATUS2_mask_fifo_lb, 0 ) + +/*! Checks if the Oscillator is enabled */ +#define st25r3911IsOscOn() st25r3911CheckReg( ST25R3911_REG_OP_CONTROL, ST25R3911_REG_OP_CONTROL_en, ST25R3911_REG_OP_CONTROL_en ) + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +/*! + ***************************************************************************** + * \brief Turn on Oscillator and Regulator + * + * This function turn on oscillator and regulator and wait for the oscillator to + * become stable. + * + * \return RFAL_ERR_SYSTEM : Failure during Oscillator activation + * \return RFAL_ERR_NONE : No error, Oscillator is active and stable, Regulator is on + * + ***************************************************************************** + */ +extern ReturnCode st25r3911OscOn( void ); + +/*! + ***************************************************************************** + * \brief Turn On Tx and Rx + * + * This function turns On Tx and Rx (Field On) + * + ***************************************************************************** + */ +extern void st25r3911TxRxOn( void ); + +/*! + ***************************************************************************** + * \brief Turn Off Tx and Rx + * + * This function turns Off Tx and Rx (Field Off) + * + ***************************************************************************** + */ +extern void st25r3911TxRxOff( void ); + +/*! + ***************************************************************************** + * \brief Initialise ST25R3911 driver + * + * This function initialises the ST25R3911 driver. + * + * \return RFAL_ERR_NONE : Operation successful + * \return RFAL_ERR_HW_MISMATCH : Expected HW do not match or communication error + * \return RFAL_ERR_IO : Error during selftest - check communication interface + * \return RFAL_ERR_TIMEOUT : Timeout during selftest - check IRQ handling + * \return RFAL_ERR_SYSTEM : Failure during seltest - check oscillator or timers + * + ***************************************************************************** + */ +extern ReturnCode st25r3911Initialize( void ); + +/*! + ***************************************************************************** + * \brief Deinitialize ST25R3911 driver + * + * Calling this function deinitializes the ST25R3911 driver. + * + ***************************************************************************** + */ +extern void st25r3911Deinitialize( void ); + + +/*! + ***************************************************************************** + * \brief Sets the bitrate registers + * + * This function sets the bitrate register for rx and tx + * + * \param txRate : speed is 2^txrate * 106 kb/s + * 0xff : don't set txrate + * \param rxRate : speed is 2^rxrate * 106 kb/s + * 0xff : don't set rxrate + * + * \return RFAL_ERR_NONE : No error, both bit rates were set + * \return RFAL_ERR_PARAM: At least one bit rate was invalid + * + ***************************************************************************** + */ +extern ReturnCode st25r3911SetBitrate( uint8_t txRate, uint8_t rxRate ); + +/*! + ***************************************************************************** + * \brief Adjusts supply regulators according to the current supply voltage + * + * On this function the power level is measured in maximum load conditions and + * the regulated voltage reference is set to 250mV below this level. + * Execution of this function lasts arround 5ms. + * + * The regulated voltages will be set to the result of Adjust Regulators + * + * \param [out] result_mV : Result of calibration in milliVolts. + * + * \return RFAL_ERR_IO : Error during communication with ST25R3911. + * \return RFAL_ERR_NONE : No error. + * + ***************************************************************************** + */ +extern ReturnCode st25r3911AdjustRegulators( uint16_t* result_mV ); + +/*! + ***************************************************************************** + * \brief Measure Amplitude + * + * This function measured the amplitude on the RFI inputs and stores the + * result in parameter \a result. + * + * \param[out] result: 8 bit long result of RF measurement. + * + ***************************************************************************** + */ +extern void st25r3911MeasureAmplitude( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief Measure Capacitance + * + * This function performs the capacitance measurement and stores the + * result in parameter \a result. + * + * \param[out] result: 8 bit long result of RF measurement. + * + ***************************************************************************** + */ +extern void st25r3911MeasureCapacitance( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief Measure Voltage + * + * This function measures the voltage on one of VDD and VSP_* + * result in parameter \a result. + * + * \param[in] mpsv : one of ST25R3911_REG_REGULATOR_CONTROL_mpsv_vdd + * ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_rf + * ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_a + * or ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_d + * + * \return the measured voltage raw values + * + ***************************************************************************** + */ +extern uint8_t st25r3911MeasurePowerSupply( uint8_t mpsv ); + +/*! + ***************************************************************************** + * \brief Measure Voltage + * + * This function measures the voltage on one of VDD and VSP_* + * result in parameter \a result. + * + * \param[in] mpsv : one of ST25R3911_REG_REGULATOR_CONTROL_mpsv_vdd + * ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_rf + * ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_a + * or ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_d + * + * \return the measured voltage in mV + * + ***************************************************************************** + */ +extern uint16_t st25r3911MeasureVoltage( uint8_t mpsv ); + +/*! + ***************************************************************************** + * \brief Calibrate antenna + * + * This function is used to calibrate the antenna using a special sequence. + * The result is stored in the \a result parameter. + * + * \param[out] result: 8 bit long result of antenna calibration algorithm. + * + ***************************************************************************** + */ +extern void st25r3911CalibrateAntenna( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief Measure Phase + * + * This function performs a Phase measurement. + * The result is stored in the \a result parameter. + * + * \param[out] result: 8 bit long result of the measurement. + * + ***************************************************************************** + */ +extern void st25r3911MeasurePhase( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief Calibrate modulation depth + * + * This function is used to calibrate the modulation depth using a special sequence. + * The result is stored in the \a result parameter. + * + * \param[out] result: 8 bit long result of antenna calibration algorithm. + * + ***************************************************************************** + */ +extern void st25r3911CalibrateModulationDepth( uint8_t* result ); + + +/*! + ***************************************************************************** + * \brief Calibrate Capacitive Sensor + * + * This function performs automatic calibration of the capacitive sensor + * and stores the result in parameter \a result. + * + * \warning To avoid interference with Xtal oscillator and reader magnetic + * field, it is strongly recommended to perform calibration + * in Power-down mode only. + * This method does not modify the Oscillator nor transmitter state, + * these should be configured before by user. + * + * \param[out] result: 5 bit long result of the calibration. + * Binary weighted, step 0.1 pF, max 3.1 pF + * + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_IO : The calibration was not successful + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +extern ReturnCode st25r3911CalibrateCapacitiveSensor( uint8_t* result ); + +/*! + ***************************************************************************** + * \brief set no response time + * + * This function executes sets the no response time to the defines value + * + * \param nrt_64fcs : no response time in 64/fc = 4.72us + * completion interrupt + * + * \return RFAL_ERR_PARAM : if time is too large + */ +extern ReturnCode st25r3911SetNoResponseTime_64fcs( uint32_t nrt_64fcs ); + +/*! + ***************************************************************************** + * \brief set no response time + * + * This function executes sets and immediately start the no response timer + * to the defines value + * This is used when needs to add more time before timeout whitout Tx + * + * \param nrt_64fcs : no response time in 64/fc = 4.72us + * completion interrupt + * + * \return RFAL_ERR_PARAM : if time is too large + */ +extern ReturnCode st25r3911SetStartNoResponseTime_64fcs( uint32_t nrt_64fcs ); + +/*! + ***************************************************************************** + * \brief Perform Collision Avoidance + * + * Performs Collision Avoidance with the given threshold and with the + * n number of TRFW + * + * \param[in] FieldONCmd : Field ON command to be executed ST25R3911_CMD_INITIAL_RF_COLLISION + * or ST25R3911_CMD_RESPONSE_RF_COLLISION_0/N + * \param[in] pdThreshold : Peer Detection Threshold (ST25R3911_REG_FIELD_THRESHOLD_trg_xx) + * 0xff : don't set Threshold (ST25R3911_THRESHOLD_DO_NOT_SET) + * \param[in] caThreshold : Collision Avoidance Threshold (ST25R3911_REG_FIELD_THRESHOLD_rfe_xx) + * 0xff : don't set Threshold (ST25R3911_THRESHOLD_DO_NOT_SET) + * \param[in] nTRFW : Number of TRFW + * + * \return RFAL_ERR_NONE : no collision detected + * \return RFAL_ERR_RF_COLLISION : collision detected + */ +extern ReturnCode st25r3911PerformCollisionAvoidance( uint8_t FieldONCmd, uint8_t pdThreshold, uint8_t caThreshold, uint8_t nTRFW ); + + +/*! + ***************************************************************************** + * \brief Get amount of bits of the last FIFO byte if incomplete + * + * Gets the number of bits of the last FIFO byte if incomplete + * + * \return the number of bits of the last FIFO byte if incomplete, 0 if + * the last byte is complete + * + ***************************************************************************** + */ +extern uint8_t st25r3911GetNumFIFOLastBits( void ); + +/*! + ***************************************************************************** + * \brief Get NRT time + * + * This returns the last value set on the NRT + * + * \warning it does not reads chip register, just the sw var that contains the + * last value set before + * + * \return the value of the NRT + */ +extern uint32_t st25r3911GetNoResponseTime_64fcs( void ); + +/*! + ***************************************************************************** + * \brief set general purpose timer timeout + * + * This function sets the proper registers but does not start the timer actually + * + * \param gpt_8fcs : general purpose timer timeout in 8/fc = 590ns + * + */ +extern void st25r3911SetGPTime_8fcs( uint16_t gpt_8fcs ); +/*! + ***************************************************************************** + * \brief Starts GPT with given timeout + * + * This function starts the general purpose timer with the given timeout + * + * \param gpt_8fcs : general purpose timer timeout in 8/fc = 590ns + * \param trigger_source : no trigger, start of Rx, end of Rx, end of Tx in NFC mode + */ +extern void st25r3911StartGPTimer_8fcs( uint16_t gpt_8fcs, uint8_t trigger_source ); + +/*! + ***************************************************************************** + * \brief Checks if register contains a expected value + * + * This function checks if the given reg contains a value that once masked + * equals the expected value + * + * \param reg : the register to check the value + * \param mask : the mask apply on register value + * \param value : expected value to be compared to + * + * \return true when reg contains the expected value | false otherwise + */ +bool st25r3911CheckReg( uint8_t reg, uint8_t mask, uint8_t value ); + +/*! + ***************************************************************************** + * \brief Sets the number Tx Bits + * + * Sets ST25R3911 internal registers with correct number of complete bytes and + * bits to be sent + * + * \param nBits : the number bits to be transmitted + ***************************************************************************** + */ +void st25r3911SetNumTxBits( uint32_t nBits ); + +/*! + ***************************************************************************** + * \brief Check Identity + * + * Checks if the chip ID is as expected. + * + * 5 bit IC type code for ST25R3911: 00001 + * The 3 lsb contain the IC revision code + * + * + * \param[out] rev : the IC revision code + * + * \return true when IC type is as expected + * + ***************************************************************************** + */ +bool st25r3911CheckChipID( uint8_t *rev ); + +/*! + ***************************************************************************** + * \brief Check if command is valid + * + * Checks if the given command is a valid ST25R3911 command + * + * \param[in] cmd: Command to check + * + * \return true if is a valid command + * \return false otherwise + * + ***************************************************************************** + */ +bool st25r3911IsCmdValid( uint8_t cmd ); + +/*! + ***************************************************************************** + * \brief Configure the stream mode of ST25R3911 + * + * This function initializes the stream with the given parameters + * + * \param[in] config : all settings for bitrates, type, etc. + * + * \return RFAL_ERR_NONE : No error, stream mode driver initialized. + * + ***************************************************************************** + */ +extern ReturnCode st25r3911StreamConfigure( const struct st25r3911StreamConfig *config ); + +/*! + ***************************************************************************** + * \brief Register Dump + * + * Retrieves all internal registers from ST25R3911 + * + * \param[out] resRegDump : pointer to the struct/buffer where the reg dump + * will be written + * \param[in,out] sizeRegDump : number of registers requested and the ones actually + * written + * \return RFAL_ERR_NONE : No error, stream mode driver initialized. + */ +extern ReturnCode st25r3911GetRegsDump( uint8_t* resRegDump, uint8_t* sizeRegDump ); + + +/*! + ***************************************************************************** + * \brief Gets the RSSI values + * + * This function gets the RSSI value of the previous reception taking into + * account the gain reductions that were used. + * RSSI value for both AM and PM channel can be retrieved. + * + * \param[out] amRssi: the RSSI on the AM channel expressed in mV + * \param[out] pmRssi: the RSSI on the PM channel expressed in mV + * + * \return RFAL_ERR_PARAM : Invalid parameter + * \return RFAL_ERR_NONE : No error + * + ***************************************************************************** + */ +ReturnCode st25r3911GetRSSI( uint16_t *amRssi, uint16_t *pmRssi ); + + +/*! + ***************************************************************************** + * \brief Set Antenna mode + * + * Sets the antenna mode. + * Differential or single ended antenna mode (RFO1 or RFO2) + * + * \param[in] single: FALSE differential ; single ended mode + * \param[in] rfiox: FALSE RFI1/RFO1 ; TRUE RFI2/RFO2 + * + * \return RFAL_ERR_IO : Internal error + * \return RFAL_ERR_NOTSUPP : Feature not supported + * \return RFAL_ERR_NONE : No error + ***************************************************************************** + */ +ReturnCode st25r3911SetAntennaMode( bool single, bool rfiox ); + + +#endif /* ST25R3911_H */ + +/** + * @} + * + * @} + * + * @} + * + * @} + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.c new file mode 100644 index 0000000..8151bb2 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.c @@ -0,0 +1,465 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief Implementation of ST25R3911 communication. + * + */ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "st25r3911_com.h" +#include "st25r3911.h" +#include "rfal_utils.h" + + +/* +****************************************************************************** +* LOCAL DEFINES +****************************************************************************** +*/ + +#define ST25R3911_WRITE_MODE (0U) /*!< ST25R3911 SPI Operation Mode: Write */ +#define ST25R3911_READ_MODE (1U << 6) /*!< ST25R3911 SPI Operation Mode: Read */ +#define ST25R3911_FIFO_LOAD (2U << 6) /*!< ST25R3911 SPI Operation Mode: FIFO Load */ +#define ST25R3911_FIFO_READ (0xBFU) /*!< ST25R3911 SPI Operation Mode: FIFO Read */ +#define ST25R3911_CMD_MODE (3U << 6) /*!< ST25R3911 SPI Operation Mode: Direct Command */ + +#define ST25R3911_CMD_LEN (1U) /*!< ST25R3911 CMD length */ +#define ST25R3911_BUF_LEN (ST25R3911_CMD_LEN+ST25R3911_FIFO_DEPTH) /*!< ST25R3911 communication buffer: CMD + FIFO length */ + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +#ifdef ST25R_COM_SINGLETXRX +static uint8_t comBuf[ST25R3911_BUF_LEN]; /*!< ST25R3911 communication buffer */ +#endif /* ST25R_COM_SINGLETXRX */ + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + +static inline void st25r3911CheckFieldSetLED(uint8_t value) +{ + if ((ST25R3911_REG_OP_CONTROL_tx_en & value) != 0U) + { +#ifdef PLATFORM_LED_FIELD_PIN + platformLedOn( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN ); + } + else + { + platformLedOff( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN ); +#endif /* PLATFORM_LED_FIELD_PIN */ + } +} + + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ +void st25r3911ReadRegister(uint8_t reg, uint8_t* value) +{ +#ifdef ST25R_COM_SINGLETXRX + uint8_t* buf = comBuf; +#else /* ST25R_COM_SINGLETXRX */ + uint8_t buf[2]; +#endif /* ST25R_COM_SINGLETXRX */ + + platformProtectST25RComm(); + platformSpiSelect(); + + buf[0] = (reg | ST25R3911_READ_MODE); + buf[1] = 0x00; + + platformSpiTxRx(buf, buf, 2); + + if(value != NULL) + { + *value = buf[1]; + } + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + + +void st25r3911ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length) +{ +#if !defined(ST25R_COM_SINGLETXRX) + const uint8_t cmd = (reg | ST25R3911_READ_MODE); +#endif /* !ST25R_COM_SINGLETXRX */ + + if (length > 0U) + { + platformProtectST25RComm(); + platformSpiSelect(); + +#ifdef ST25R_COM_SINGLETXRX + + RFAL_MEMSET( comBuf, 0x00, RFAL_MIN( (ST25R3911_CMD_LEN + (uint32_t)length), ST25R3911_BUF_LEN ) ); + comBuf[0] = (reg | ST25R3911_READ_MODE); + + platformSpiTxRx(comBuf, comBuf, RFAL_MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); /* Transceive as a single SPI call */ + RFAL_MEMCPY( values, &comBuf[ST25R3911_CMD_LEN], RFAL_MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); /* Copy from local buf to output buffer and skip cmd byte */ + +#else /* ST25R_COM_SINGLETXRX */ + + if( values != NULL ) + { + RFAL_MEMSET( values, 0x00, length ); + } + + /* Since the result comes one byte later, let's first transmit the adddress with discarding the result */ + platformSpiTxRx(&cmd, NULL, ST25R3911_CMD_LEN); + platformSpiTxRx(NULL, values, length); + +#endif /* ST25R_COM_SINGLETXRX */ + + platformSpiDeselect(); + platformUnprotectST25RComm(); + } + + return; +} + +void st25r3911ReadTestRegister(uint8_t reg, uint8_t* value) +{ + +#ifdef ST25R_COM_SINGLETXRX + uint8_t* buf = comBuf; +#else /* ST25R_COM_SINGLETXRX */ + uint8_t buf[3]; +#endif /* ST25R_COM_SINGLETXRX */ + + platformProtectST25RComm(); + platformSpiSelect(); + + buf[0] = ST25R3911_CMD_TEST_ACCESS; + buf[1] = (reg | ST25R3911_READ_MODE); + buf[2] = 0x00; + + platformSpiTxRx(buf, buf, 3); + + if(value != NULL) + { + *value = buf[2]; + } + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + +void st25r3911WriteTestRegister(uint8_t reg, uint8_t value) +{ +#ifdef ST25R_COM_SINGLETXRX + uint8_t* buf = comBuf; +#else /* ST25R_COM_SINGLETXRX */ + uint8_t buf[3]; +#endif /* ST25R_COM_SINGLETXRX */ + + platformProtectST25RComm(); + platformSpiSelect(); + + buf[0] = ST25R3911_CMD_TEST_ACCESS; + buf[1] = (reg | ST25R3911_WRITE_MODE); + buf[2] = value; + + platformSpiTxRx(buf, NULL, 3); + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + +void st25r3911WriteRegister(uint8_t reg, uint8_t value) +{ +#ifdef ST25R_COM_SINGLETXRX + uint8_t* buf = comBuf; +#else /* ST25R_COM_SINGLETXRX */ + uint8_t buf[2]; +#endif /* ST25R_COM_SINGLETXRX */ + + if (ST25R3911_REG_OP_CONTROL == reg) + { + st25r3911CheckFieldSetLED(value); + } + + platformProtectST25RComm(); + platformSpiSelect(); + + buf[0] = reg | ST25R3911_WRITE_MODE; + buf[1] = value; + + platformSpiTxRx(buf, NULL, 2); + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + +void st25r3911ClrRegisterBits( uint8_t reg, uint8_t clr_mask ) +{ + uint8_t tmp; + + st25r3911ReadRegister(reg, &tmp); + tmp &= ~clr_mask; + st25r3911WriteRegister(reg, tmp); + + return; +} + + +void st25r3911SetRegisterBits( uint8_t reg, uint8_t set_mask ) +{ + uint8_t tmp; + + st25r3911ReadRegister(reg, &tmp); + tmp |= set_mask; + st25r3911WriteRegister(reg, tmp); + + return; +} + +void st25r3911ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value) +{ + st25r3911ModifyRegister(reg, valueMask, (valueMask & value) ); +} + +void st25r3911ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask) +{ + uint8_t tmp; + + st25r3911ReadRegister(reg, &tmp); + + /* mask out the bits we don't want to change */ + tmp &= ~clr_mask; + /* set the new value */ + tmp |= set_mask; + st25r3911WriteRegister(reg, tmp); + + return; +} + +void st25r3911ChangeTestRegisterBits( uint8_t reg, uint8_t valueMask, uint8_t value ) +{ + uint8_t rdVal; + uint8_t wrVal; + + /* Read current reg value */ + st25r3911ReadTestRegister(reg, &rdVal); + + /* Compute new value */ + wrVal = (rdVal & ~valueMask); + wrVal |= (value & valueMask); + + /* Write new reg value */ + st25r3911WriteTestRegister(reg, wrVal ); + + return; +} + +void st25r3911WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length) +{ +#if !defined(ST25R_COM_SINGLETXRX) + const uint8_t cmd = (reg | ST25R3911_WRITE_MODE); +#endif /* !ST25R_COM_SINGLETXRX */ + + if ((reg <= ST25R3911_REG_OP_CONTROL) && ((reg+length) >= ST25R3911_REG_OP_CONTROL)) + { + st25r3911CheckFieldSetLED(values[ST25R3911_REG_OP_CONTROL-reg]); + } + + if (length > 0U) + { + /* make this operation atomic */ + platformProtectST25RComm(); + platformSpiSelect(); + +#ifdef ST25R_COM_SINGLETXRX + + comBuf[0] = (reg | ST25R3911_WRITE_MODE); + RFAL_MEMCPY( &comBuf[ST25R3911_CMD_LEN], values, RFAL_MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); + + platformSpiTxRx( comBuf, NULL, RFAL_MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); + +#else /*ST25R_COM_SINGLETXRX*/ + + platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN ); + platformSpiTxRx( values, NULL, length ); + +#endif /*ST25R_COM_SINGLETXRX*/ + + platformSpiDeselect(); + platformUnprotectST25RComm(); + } + + return; +} + + +void st25r3911WriteFifo(const uint8_t* values, uint8_t length) +{ +#if !defined(ST25R_COM_SINGLETXRX) + const uint8_t cmd = ST25R3911_FIFO_LOAD; +#endif /* !ST25R_COM_SINGLETXRX */ + + if( (length > 0U) && (length <= ST25R3911_FIFO_DEPTH) ) + { + platformProtectST25RComm(); + platformSpiSelect(); + +#ifdef ST25R_COM_SINGLETXRX + + comBuf[0] = ST25R3911_FIFO_LOAD; + RFAL_MEMCPY( &comBuf[ST25R3911_CMD_LEN], values, RFAL_MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); + + platformSpiTxRx( comBuf, NULL, RFAL_MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); + +#else /*ST25R_COM_SINGLETXRX*/ + + platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN ); + platformSpiTxRx( values, NULL, length ); + +#endif /*ST25R_COM_SINGLETXRX*/ + + platformSpiDeselect(); + platformUnprotectST25RComm(); + } + + return; +} + +void st25r3911ReadFifo(uint8_t* buf, uint8_t length) +{ +#if !defined(ST25R_COM_SINGLETXRX) + const uint8_t cmd = ST25R3911_FIFO_READ; +#endif /* !ST25R_COM_SINGLETXRX */ + + if(length > 0U) + { + platformProtectST25RComm(); + platformSpiSelect(); + +#ifdef ST25R_COM_SINGLETXRX + + RFAL_MEMSET( comBuf, 0x00, RFAL_MIN( (ST25R3911_CMD_LEN + (uint32_t)length), ST25R3911_BUF_LEN ) ); + comBuf[0] = ST25R3911_FIFO_READ; + + platformSpiTxRx( comBuf, comBuf, RFAL_MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); /* Transceive as a single SPI call */ + if( buf != NULL ) + { + RFAL_MEMCPY( buf, &comBuf[ST25R3911_CMD_LEN], RFAL_MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); /* Copy from local buf to output buffer and skip cmd byte */ + } + +#else /*ST25R_COM_SINGLETXRX*/ + + if( buf != NULL ) + { + RFAL_MEMSET( buf, 0x00, length ); + } + + platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN ); + platformSpiTxRx( NULL, buf, length ); + +#endif /*ST25R_COM_SINGLETXRX*/ + + platformSpiDeselect(); + platformUnprotectST25RComm(); + } + + return; +} + +void st25r3911ExecuteCommand( uint8_t cmd ) +{ + uint8_t tmpCmd; /* MISRA 17.8 */ + +#ifdef PLATFORM_LED_FIELD_PIN + if ( (cmd >= ST25R3911_CMD_TRANSMIT_WITH_CRC) && (cmd <= ST25R3911_CMD_RESPONSE_RF_COLLISION_0)) + { + platformLedOff(PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN); + } +#endif /* PLATFORM_LED_FIELD_PIN */ + + tmpCmd = (cmd | ST25R3911_CMD_MODE); + + platformProtectST25RComm(); + platformSpiSelect(); + + platformSpiTxRx( &tmpCmd, NULL, ST25R3911_CMD_LEN ); + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + + +void st25r3911ExecuteCommands(const uint8_t *cmds, uint8_t length) +{ + platformProtectST25RComm(); + platformSpiSelect(); + + platformSpiTxRx( cmds, NULL, length ); + + platformSpiDeselect(); + platformUnprotectST25RComm(); + + return; +} + +bool st25r3911IsRegValid( uint8_t reg ) +{ + if( (!(( (int16_t)reg >= (int16_t)ST25R3911_REG_IO_CONF1) && (reg <= ST25R3911_REG_CAPACITANCE_MEASURE_RESULT))) && (reg != ST25R3911_REG_IC_IDENTITY) ) + { + return false; + } + return true; +} + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.h new file mode 100644 index 0000000..1975e0f --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_com.h @@ -0,0 +1,816 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief ST25R3911 communication declaration file + * + */ +/*! + * This driver provides basic abstraction for communication with the ST25R3911. + * It uses the SPI driver for interfacing with the ST25R3911. + * + * API: + * - Read Register: #st25r3911ReadRegister + * - Modify Register: #st25r3911ModifyRegister + * - Write Register: #st25r3911WriteRegister + * - Write Multiple Registers: #st25r3911WriteMultipleRegisters + * - Load ST25R3911 FIFO with data: #st25r3911WriteFifo + * - Read from ST25R3911 FIFO: #st25r3911ReadFifo + * - Execute direct command: #st25r3911ExecuteCommand + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup ST25R3911 + * \brief RFAL ST25R3911 Driver + * @{ + * + * \addtogroup ST25R3911_Com + * \brief RFAL ST25R3911 Communication + * @{ + * + */ + +#ifndef ST25R3911_COM_H +#define ST25R3911_COM_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" +#include "rfal_utils.h" +#include "st25r3911b.h" +#include "st25r3911b_global.h" +#include +#include +#include +#include + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + +#define ST25R3911_FIFO_STATUS_LEN 2 /*!< Number of FIFO Status Register */ + + + + +#define ST25R3911_REG_IO_CONF1 0x00U /*!< RW IO Configuration Register 1 */ +#define ST25R3911_REG_IO_CONF2 0x01U /*!< RW IO Configuration Register 2 */ + +#define ST25R3911_REG_OP_CONTROL 0x02U /*!< RW Operation Control Register */ +#define ST25R3911_REG_MODE 0x03U /*!< RW Mode Definition Register */ +#define ST25R3911_REG_BIT_RATE 0x04U /*!< RW Bit Rate Definition Register */ + +#define ST25R3911_REG_ISO14443A_NFC 0x05U /*!< RW ISO14443A and NFC 106 kBit/s Settings Register */ +#define ST25R3911_REG_ISO14443B_1 0x06U /*!< RW ISO14443B Settings Register 1 */ +#define ST25R3911_REG_ISO14443B_2 0x07U /*!< RW ISO14443B Settings Register 2 */ +#define ST25R3911_REG_STREAM_MODE 0x08U /*!< RW Stream Mode Definition Register */ +#define ST25R3911_REG_AUX 0x09U /*!< RW Auxiliary Definition Register */ +#define ST25R3911_REG_RX_CONF1 0x0AU /*!< RW Receiver Configuration Register 1 */ +#define ST25R3911_REG_RX_CONF2 0x0BU /*!< RW Receiver Configuration Register 2 */ +#define ST25R3911_REG_RX_CONF3 0x0CU /*!< RW Receiver Configuration Register 3 */ +#define ST25R3911_REG_RX_CONF4 0x0DU /*!< RW Receiver Configuration Register 4 */ + +#define ST25R3911_REG_MASK_RX_TIMER 0x0EU /*!< RW Mask Receive Timer Register */ +#define ST25R3911_REG_NO_RESPONSE_TIMER1 0x0FU /*!< RW No-response Timer Register 1 */ +#define ST25R3911_REG_NO_RESPONSE_TIMER2 0x10U /*!< RW No-response Timer Register 2 */ +#define ST25R3911_REG_GPT_CONTROL 0x11U /*!< RW General Purpose Timer Control Register */ +#define ST25R3911_REG_GPT1 0x12U /*!< RW General Purpose Timer Register 1 */ +#define ST25R3911_REG_GPT2 0x13U /*!< RW General Purpose Timer Register 2 */ + +#define ST25R3911_REG_IRQ_MASK_MAIN 0x14U /*!< RW Mask Main Interrupt Register */ +#define ST25R3911_REG_IRQ_MASK_TIMER_NFC 0x15U /*!< RW Mask Timer and NFC Interrupt Register */ +#define ST25R3911_REG_IRQ_MASK_ERROR_WUP 0x16U /*!< RW Mask Error and Wake-up Interrupt Register */ +#define ST25R3911_REG_IRQ_MAIN 0x17U /*!< R Main Interrupt Register */ +#define ST25R3911_REG_IRQ_TIMER_NFC 0x18U /*!< R Timer and NFC Interrupt Register */ +#define ST25R3911_REG_IRQ_ERROR_WUP 0x19U /*!< R Error and Wake-up Interrupt Register */ +#define ST25R3911_REG_FIFO_RX_STATUS1 0x1AU /*!< R FIFO RX Status Register 1 */ +#define ST25R3911_REG_FIFO_RX_STATUS2 0x1BU /*!< R FIFO RX Status Register 2 */ +#define ST25R3911_REG_COLLISION_STATUS 0x1CU /*!< R Collision Display Register */ + +#define ST25R3911_REG_NUM_TX_BYTES1 0x1DU /*!< RW Number of Transmitted Bytes Register 1 */ +#define ST25R3911_REG_NUM_TX_BYTES2 0x1EU /*!< RW Number of Transmitted Bytes Register 2 */ + +#define ST25R3911_REG_NFCIP1_BIT_RATE 0x1FU /*!< R NFCIP Bit Rate Detection Display Register */ + +#define ST25R3911_REG_AD_RESULT 0x20U /*!< R A/D Converter Output Register */ + +#define ST25R3911_REG_ANT_CAL_CONTROL 0x21U /*!< RW Antenna Calibration Control Register */ +#define ST25R3911_REG_ANT_CAL_TARGET 0x22U /*!< RW Antenna Calibration Target Register */ +#define ST25R3911_REG_ANT_CAL_RESULT 0x23U /*!< R Antenna Calibration Display Register */ + +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL 0x24U /*!< RW AM Modulation Depth Control Register */ +#define ST25R3911_REG_AM_MOD_DEPTH_RESULT 0x25U /*!< R AM Modulation Depth Display Register */ +#define ST25R3911_REG_RFO_AM_ON_LEVEL 0x26U /*!< RW RFO AM Modulation (On) Level Definition Register */ +#define ST25R3911_REG_RFO_AM_OFF_LEVEL 0x27U /*!< RW RFO Normal (AM Off) Level Definition Register */ + +#define ST25R3911_REG_FIELD_THRESHOLD 0x29U /*!< RW External Field Detector Threshold Register */ + +#define ST25R3911_REG_REGULATOR_CONTROL 0x2AU /*!< RW Regulated Voltage Control Register */ +#define ST25R3911_REG_REGULATOR_RESULT 0x2BU /*!< R Regulator Display Register */ + +#define ST25R3911_REG_RSSI_RESULT 0x2CU /*!< R RSSI Display Register*/ +#define ST25R3911_REG_GAIN_RED_STATE 0x2DU /*!< R Gain Reduction State Register*/ + +#define ST25R3911_REG_CAP_SENSOR_CONTROL 0x2EU /*!< RW Capacitive Sensor Control Register */ +#define ST25R3911_REG_CAP_SENSOR_RESULT 0x2FU /*!< R Capacitive Sensor Display Register */ + +#define ST25R3911_REG_AUX_DISPLAY 0x30U /*!< R Auxiliary Display Register */ + +#define ST25R3911_REG_WUP_TIMER_CONTROL 0x31U /*!< RW Wake-up Timer Control Register */ +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF 0x32U /*!< RW Amplitude Measurement Configuration Register */ +#define ST25R3911_REG_AMPLITUDE_MEASURE_REF 0x33U /*!< RW Amplitude Measurement Reference Register */ +#define ST25R3911_REG_AMPLITUDE_MEASURE_AA_RESULT 0x34U /*!< R Amplitude Measurement Auto Averaging Display Register */ +#define ST25R3911_REG_AMPLITUDE_MEASURE_RESULT 0x35U /*!< R Amplitude Measurement Display Register */ +#define ST25R3911_REG_PHASE_MEASURE_CONF 0x36U /*!< RW Phase Measurement Configuration Register */ +#define ST25R3911_REG_PHASE_MEASURE_REF 0x37U /*!< RW Phase Measurement Reference Register */ +#define ST25R3911_REG_PHASE_MEASURE_AA_RESULT 0x38U /*!< R Phase Measurement Auto Averaging Display Register */ +#define ST25R3911_REG_PHASE_MEASURE_RESULT 0x39U /*!< R Phase Measurement Display Register */ +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF 0x3AU /*!< RW Capacitance Measurement Configuration Register */ +#define ST25R3911_REG_CAPACITANCE_MEASURE_REF 0x3BU /*!< RW Capacitance Measurement Reference Register */ +#define ST25R3911_REG_CAPACITANCE_MEASURE_AA_RESULT 0x3CU /*!< R Capacitance Measurement Auto Averaging Display Register */ +#define ST25R3911_REG_CAPACITANCE_MEASURE_RESULT 0x3DU /*!< R Capacitance Measurement Display Register */ + +#define ST25R3911_REG_IC_IDENTITY 0x3FU /*!< R Chip Id: 0 for old silicon, v2 silicon: 0x09 */ + + +/*! Register bit definitions \cond DOXYGEN_SUPPRESS */ + +#define ST25R3911_REG_IO_CONF1_lf_clk_off (1U<<0) +#define ST25R3911_REG_IO_CONF1_out_cl0 (1U<<1) +#define ST25R3911_REG_IO_CONF1_out_cl1 (1U<<2) +#define ST25R3911_REG_IO_CONF1_mask_out_cl (3U<<1) +#define ST25R3911_REG_IO_CONF1_osc (1U<<3) +#define ST25R3911_REG_IO_CONF1_fifo_lt (1U<<4) +#define ST25R3911_REG_IO_CONF1_fifo_lt_32bytes (0U<<4) +#define ST25R3911_REG_IO_CONF1_fifo_lt_16bytes (1U<<4) +#define ST25R3911_REG_IO_CONF1_fifo_lr (1U<<5) +#define ST25R3911_REG_IO_CONF1_fifo_lr_64bytes (0U<<5) +#define ST25R3911_REG_IO_CONF1_fifo_lr_80bytes (1U<<5) +#define ST25R3911_REG_IO_CONF1_rfo2 (1U<<6) +#define ST25R3911_REG_IO_CONF1_single (1U<<7) +#define ST25R3911_REG_IO_CONF2_slow_up (1U<<0) +#define ST25R3911_REG_IO_CONF2_io_18 (1U<<2) +#define ST25R3911_REG_IO_CONF2_miso_pd1 (1U<<3) +#define ST25R3911_REG_IO_CONF2_miso_pd2 (1U<<4) +#define ST25R3911_REG_IO_CONF2_vspd_off (1U<<6) +#define ST25R3911_REG_IO_CONF2_sup3V (1U<<7) +#define ST25R3911_REG_OP_CONTROL_wu (1U<<2) +#define ST25R3911_REG_OP_CONTROL_tx_en (1U<<3) +#define ST25R3911_REG_OP_CONTROL_rx_man (1U<<4) +#define ST25R3911_REG_OP_CONTROL_rx_chn (1U<<5) +#define ST25R3911_REG_OP_CONTROL_rx_en (1U<<6) +#define ST25R3911_REG_OP_CONTROL_en (1U<<7) +#define ST25R3911_REG_MODE_nfc_ar (1U<<0) +#define ST25R3911_REG_MODE_nfc_ar_on (1U<<0) +#define ST25R3911_REG_MODE_nfc_ar_off (0U<<0) +#define ST25R3911_REG_MODE_mask_om (0xfU<<3) +#define ST25R3911_REG_MODE_om_nfc (0x0U<<3) +#define ST25R3911_REG_MODE_om_iso14443a (0x1U<<3) +#define ST25R3911_REG_MODE_om_iso14443b (0x2U<<3) +#define ST25R3911_REG_MODE_om_felica (0x3U<<3) +#define ST25R3911_REG_MODE_om_topaz (0x4U<<3) +#define ST25R3911_REG_MODE_om_subcarrier_stream (0xeU<<3) +#define ST25R3911_REG_MODE_om_bpsk_stream (0xfU<<3) +#define ST25R3911_REG_MODE_om_bit_rate_detection (0x0U<<3) +#define ST25R3911_REG_MODE_om_nfcip1_normal_mode (0x1U<<3) +#define ST25R3911_REG_MODE_targ (1U<<7) +#define ST25R3911_REG_MODE_targ_targ (1U<<7) +#define ST25R3911_REG_MODE_targ_init (0U<<7) +#define ST25R3911_REG_BIT_RATE_mask_txrate (0xfU<<4) +#define ST25R3911_REG_BIT_RATE_shift_txrate (4U) +#define ST25R3911_REG_BIT_RATE_txrate_106 (0x0U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_212 (0x1U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_424 (0x2U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_848 (0x3U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_1695 (0x4U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_3390 (0x5U<<4) +#define ST25R3911_REG_BIT_RATE_txrate_6780 (0x6U<<4) +#define ST25R3911_REG_BIT_RATE_mask_rxrate (0xfU<<0) +#define ST25R3911_REG_BIT_RATE_shift_rxrate (0U) +#define ST25R3911_REG_BIT_RATE_rxrate_106 (0x0U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_212 (0x1U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_424 (0x2U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_848 (0x3U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_1695 (0x4U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_3390 (0x5U<<0) +#define ST25R3911_REG_BIT_RATE_rxrate_6780 (0x6U<<0) +#define ST25R3911_REG_ISO14443A_NFC_antcl (1U<<0) +#define ST25R3911_REG_ISO14443A_NFC_mask_p_len (0xfU<<1) +#define ST25R3911_REG_ISO14443A_NFC_shift_p_len (1U) +#define ST25R3911_REG_ISO14443A_NFC_nfc_f0 (1U<<5) +#define ST25R3911_REG_ISO14443A_NFC_nfc_f0_off (0U<<5) +#define ST25R3911_REG_ISO14443A_NFC_no_rx_par (1U<<6) +#define ST25R3911_REG_ISO14443A_NFC_no_rx_par_off (0U<<6) +#define ST25R3911_REG_ISO14443A_NFC_no_tx_par (1U<<7) +#define ST25R3911_REG_ISO14443A_NFC_no_tx_par_off (0U<<7) +#define ST25R3911_REG_ISO14443B_1_mask_eof (1U<<2) +#define ST25R3911_REG_ISO14443B_1_eof_10etu (0U<<2) +#define ST25R3911_REG_ISO14443B_1_eof_11etu (1U<<2) +#define ST25R3911_REG_ISO14443B_1_mask_sof (3U<<3) +#define ST25R3911_REG_ISO14443B_1_mask_sof_0 (1U<<4) +#define ST25R3911_REG_ISO14443B_1_sof_0_10etu (0U<<4) +#define ST25R3911_REG_ISO14443B_1_sof_0_11etu (1U<<4) +#define ST25R3911_REG_ISO14443B_1_mask_sof_1 (1U<<3) +#define ST25R3911_REG_ISO14443B_1_sof_1_2etu (0U<<3) +#define ST25R3911_REG_ISO14443B_1_sof_2_3etu (1U<<3) +#define ST25R3911_REG_ISO14443B_1_mask_egt (7U<<5) +#define ST25R3911_REG_ISO14443B_1_shift_egt (5U) +#define ST25R3911_REG_ISO14443B_2_eof_12 (1U<<3) +#define ST25R3911_REG_ISO14443B_2_eof_12_10to11etu (0U<<3) +#define ST25R3911_REG_ISO14443B_2_eof_12_10to12etu (1U<<3) +#define ST25R3911_REG_ISO14443B_2_no_eof (1U<<4) +#define ST25R3911_REG_ISO14443B_2_no_sof (1U<<5) +#define ST25R3911_REG_ISO14443B_2_mask_tr1 (3U<<6) +#define ST25R3911_REG_ISO14443B_2_shift_tr1 (6U) +#define ST25R3911_REG_ISO14443B_2_tr1_0 (1U<<6) +#define ST25R3911_REG_ISO14443B_2_tr1_1 (1U<<7) +#define ST25R3911_REG_ISO14443B_2_tr1_80fs80fs (0U<<6) +#define ST25R3911_REG_ISO14443B_2_tr1_64fs32fs (1U<<6) +#define ST25R3911_REG_STREAM_MODE_mask_stx (7U<<0) +#define ST25R3911_REG_STREAM_MODE_shift_stx (0U) +#define ST25R3911_REG_STREAM_MODE_stx_106 (0U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_212 (1U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_424 (2U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_848 (3U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_1695 (4U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_3390 (5U<<0) +#define ST25R3911_REG_STREAM_MODE_stx_6780 (6U<<0) +#define ST25R3911_REG_STREAM_MODE_mask_scp (3U<<3) +#define ST25R3911_REG_STREAM_MODE_shift_scp (3U) +#define ST25R3911_REG_STREAM_MODE_scp_1pulse (0U<<3) +#define ST25R3911_REG_STREAM_MODE_scp_2pulses (1U<<3) +#define ST25R3911_REG_STREAM_MODE_scp_4pulses (2U<<3) +#define ST25R3911_REG_STREAM_MODE_scp_8pulses (3U<<3) +#define ST25R3911_REG_STREAM_MODE_mask_scf (3U<<5) +#define ST25R3911_REG_STREAM_MODE_shift_scf (5U) +#define ST25R3911_REG_STREAM_MODE_scf_bpsk848 (0U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_bpsk1695 (1U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_bpsk3390 (2U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_bpsk106 (3U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_sc212 (0U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_sc424 (1U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_sc848 (2U<<5) +#define ST25R3911_REG_STREAM_MODE_scf_sc1695 (3U<<5) +#define ST25R3911_REG_AUX_mask_nfc_n (3U<<0) +#define ST25R3911_REG_AUX_nfc_n0 (1U<<0) +#define ST25R3911_REG_AUX_nfc_n1 (1U<<1) +#define ST25R3911_REG_AUX_rx_tol (1U<<2) +#define ST25R3911_REG_AUX_ook_hr (1U<<3) +#define ST25R3911_REG_AUX_en_fd (1U<<4) +#define ST25R3911_REG_AUX_tr_am (1U<<5) +#define ST25R3911_REG_AUX_crc_2_fifo (1U<<6) +#define ST25R3911_REG_AUX_no_crc_rx (1U<<7) +#define ST25R3911_REG_RX_CONF1_z12k (1U<<0) +#define ST25R3911_REG_RX_CONF1_h80 (1U<<1) +#define ST25R3911_REG_RX_CONF1_h200 (1U<<2) +#define ST25R3911_REG_RX_CONF1_mask_lp (7U<<3) +#define ST25R3911_REG_RX_CONF1_lp_1200khz (0U<<3) +#define ST25R3911_REG_RX_CONF1_lp_600khz (1U<<3) +#define ST25R3911_REG_RX_CONF1_lp_300khz (2U<<3) +#define ST25R3911_REG_RX_CONF1_lp_2000khz (4U<<3) +#define ST25R3911_REG_RX_CONF1_lp_7000khz (5U<<3) +#define ST25R3911_REG_RX_CONF1_amd_sel (1U<<6) +#define ST25R3911_REG_RX_CONF1_ch_sel (1U<<7) +#define ST25R3911_REG_RX_CONF2_sqm_dyn (1U<<1) +#define ST25R3911_REG_RX_CONF2_agc_alg (1U<<2) +#define ST25R3911_REG_RX_CONF2_agc_m (1U<<3) +#define ST25R3911_REG_RX_CONF2_agc_en (1U<<4) +#define ST25R3911_REG_RX_CONF2_lf_en (1U<<5) +#define ST25R3911_REG_RX_CONF2_lf_op (1U<<6) +#define ST25R3911_REG_RX_CONF2_rx_lp (1U<<7) +#define ST25R3911_REG_RX_CONF3_rg_nfc (1U<<0) +#define ST25R3911_REG_RX_CONF3_lim (1U<<1) +#define ST25R3911_REG_RX_CONF3_shift_rg1_pm (2U) +#define ST25R3911_REG_RX_CONF3_mask_rg1_pm (0x7U<<2) +#define ST25R3911_REG_RX_CONF3_rg1_pm0 (1U<<2) +#define ST25R3911_REG_RX_CONF3_rg1_pm1 (1U<<3) +#define ST25R3911_REG_RX_CONF3_rg1_pm2 (1U<<4) +#define ST25R3911_REG_RX_CONF3_shift_rg1_am (5U) +#define ST25R3911_REG_RX_CONF3_mask_rg1_am (0x7U<<5) +#define ST25R3911_REG_RX_CONF3_rg1_am0 (1U<<5) +#define ST25R3911_REG_RX_CONF3_rg1_am1 (1U<<6) +#define ST25R3911_REG_RX_CONF3_rg1_am2 (1U<<7) +#define ST25R3911_REG_RX_CONF4_shift_rg2_pm (0U) +#define ST25R3911_REG_RX_CONF4_mask_rg2_pm (0xfU<<0) +#define ST25R3911_REG_RX_CONF4_rg2_pm0 (1U<<0) +#define ST25R3911_REG_RX_CONF4_rg2_pm1 (1U<<1) +#define ST25R3911_REG_RX_CONF4_rg2_pm2 (1U<<2) +#define ST25R3911_REG_RX_CONF4_rg2_pm3 (1U<<3) +#define ST25R3911_REG_RX_CONF4_shift_rg2_am (4U) +#define ST25R3911_REG_RX_CONF4_mask_rg2_am (0xfU<<4) +#define ST25R3911_REG_RX_CONF4_rg2_am0 (1U<<4) +#define ST25R3911_REG_RX_CONF4_rg2_am1 (1U<<5) +#define ST25R3911_REG_RX_CONF4_rg2_am2 (1U<<6) +#define ST25R3911_REG_RX_CONF4_rg2_am3 (1U<<7) +#define ST25R3911_REG_GPT_CONTROL_nrt_step (1U<<0) +#define ST25R3911_REG_GPT_CONTROL_nrt_emv (1U<<1) +#define ST25R3911_REG_GPT_CONTROL_gptc0 (1U<<5) +#define ST25R3911_REG_GPT_CONTROL_gptc1 (1U<<6) +#define ST25R3911_REG_GPT_CONTROL_gptc2 (1U<<7) +#define ST25R3911_REG_GPT_CONTROL_gptc_mask (0x7U<<5) +#define ST25R3911_REG_GPT_CONTROL_gptc_no_trigger (0x0U<<5) +#define ST25R3911_REG_GPT_CONTROL_gptc_erx (0x1U<<5) +#define ST25R3911_REG_GPT_CONTROL_gptc_srx (0x2U<<5) +#define ST25R3911_REG_GPT_CONTROL_gptc_etx_nfc (0x3U<<5) +#define ST25R3911_REG_FIFO_RX_STATUS2_np_lb (1U<<0) +#define ST25R3911_REG_FIFO_RX_STATUS2_mask_fifo_lb (7U<<1) +#define ST25R3911_REG_FIFO_RX_STATUS2_shift_fifo_lb (1U) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_lb0 (1U<<1) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_lb1 (1U<<2) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_lb2 (1U<<3) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_ncp (1U<<4) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_ovr (1U<<5) +#define ST25R3911_REG_FIFO_RX_STATUS2_fifo_unf (1U<<6) +#define ST25R3911_REG_COLLISION_STATUS_c_pb (1U<<0) +#define ST25R3911_REG_COLLISION_STATUS_mask_c_bit (3U<<1) +#define ST25R3911_REG_COLLISION_STATUS_shift_c_bit (1U) +#define ST25R3911_REG_COLLISION_STATUS_mask_c_byte (0xfU<<4) +#define ST25R3911_REG_COLLISION_STATUS_shift_c_byte (4U) +#define ST25R3911_ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate0 (1U<<4) +#define ST25R3911_ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate1 (1U<<5) +#define ST25R3911_ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate2 (1U<<6) +#define ST25R3911_ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate3 (1U<<7) +#define ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate_mask (0xfU<<4) +#define ST25R3911_REG_NFCIP1_BIT_RATE_nfc_rate_shift (4U) +#define ST25R3911_REG_ANT_CAL_CONTROL_mask_tre (0xfU<<3) +#define ST25R3911_REG_ANT_CAL_CONTROL_shift_tre (3U) +#define ST25R3911_REG_ANT_CAL_CONTROL_tre_0 (1U<<3) +#define ST25R3911_REG_ANT_CAL_CONTROL_tre_1 (1U<<4) +#define ST25R3911_REG_ANT_CAL_CONTROL_tre_2 (1U<<5) +#define ST25R3911_REG_ANT_CAL_CONTROL_tre_3 (1U<<6) +#define ST25R3911_REG_ANT_CAL_CONTROL_trim_s (1U<<7) +#define ST25R3911_REG_ANT_CAL_RESULT_tri_err (1U<<3) +#define ST25R3911_REG_ANT_CAL_RESULT_tri_0 (1U<<4) +#define ST25R3911_REG_ANT_CAL_RESULT_tri_1 (1U<<5) +#define ST25R3911_REG_ANT_CAL_RESULT_tri_2 (1U<<6) +#define ST25R3911_REG_ANT_CAL_RESULT_tri_3 (1U<<7) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mask_mod (0x3fU<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_shift_mod (1U) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_8percent (0xbU<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_10percent (0xeU<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_14percent (0x14U<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_20percent (0x20U<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_25percent (0x2aU<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_30percent (0x37U<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_mod_33percent (0x3fU<<1) +#define ST25R3911_REG_AM_MOD_DEPTH_CONTROL_am_s (1U<<7) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram0 (1U<<0) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram1 (1U<<1) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram2 (1U<<2) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram3 (1U<<3) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram4 (1U<<4) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram5 (1U<<5) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram6 (1U<<6) +#define ST25R3911_REG_RFO_AM_MOD_LEVEL_dram7 (1U<<7) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_t0 (1U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_t1 (1U<<1) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_t2 (1U<<2) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_t3 (1U<<3) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_l0 (1U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_l1 (1U<<5) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_l2 (1U<<6) +#define ST25R3911_REG_FIELD_THRESHOLD_mask_trg (0x07U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_75mV (0x00U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_105mV (0x01U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_150mV (0x02U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_205mV (0x03U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_290mV (0x04U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_400mV (0x05U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_560mV (0x06U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_trg_800mV (0x07U<<4) +#define ST25R3911_REG_FIELD_THRESHOLD_mask_rfe (0x0FU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_75mV (0x00U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_105mV (0x01U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_150mV (0x02U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_205mV (0x03U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_290mV (0x04U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_400mV (0x05U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_560mV (0x06U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_800mV (0x07U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_25mV (0x08U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_33mV (0x09U<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_47mV (0x0AU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_64mV (0x0BU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_90mV (0x0CU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_125mV (0x0DU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_175mV (0x0EU<<0) +#define ST25R3911_REG_FIELD_THRESHOLD_rfe_250mV (0x0FU<<0) +#define ST25R3911_REG_REGULATOR_CONTROL_shift_mpsv (1U) +#define ST25R3911_REG_REGULATOR_CONTROL_mask_mpsv (3U<<1) +#define ST25R3911_REG_REGULATOR_CONTROL_mpsv_vdd (0U<<1) +#define ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_a (1U<<1) +#define ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_d (2U<<1) +#define ST25R3911_REG_REGULATOR_CONTROL_mpsv_vsp_rf (3U<<1) +#define ST25R3911_REG_REGULATOR_CONTROL_mask_rege (0xfU<<3) +#define ST25R3911_REG_REGULATOR_CONTROL_shift_rege (3U) +#define ST25R3911_REG_REGULATOR_CONTROL_reg_s (1U<<7) +#define ST25R3911_REG_REGULATOR_RESULT_mrt_on (1U<<0) +#define ST25R3911_REG_REGULATOR_RESULT_nrt_on (1U<<1) +#define ST25R3911_REG_REGULATOR_RESULT_gpt_on (1U<<2) +#define ST25R3911_REG_REGULATOR_RESULT_mask_reg (0xfU<<4) +#define ST25R3911_REG_REGULATOR_RESULT_shift_reg (4U) +#define ST25R3911_REG_REGULATOR_RESULT_reg_0 (1U<<4) +#define ST25R3911_REG_REGULATOR_RESULT_reg_1 (1U<<5) +#define ST25R3911_REG_REGULATOR_RESULT_reg_2 (1U<<6) +#define ST25R3911_REG_REGULATOR_RESULT_reg_3 (1U<<7) +#define ST25R3911_REG_RSSI_RESULT_mask_rssi_pm (0xfU) +#define ST25R3911_REG_RSSI_RESULT_shift_rssi_pm (0U) +#define ST25R3911_REG_RSSI_RESULT_rssi_pm0 (1U<<0) +#define ST25R3911_REG_RSSI_RESULT_rssi_pm1 (1U<<1) +#define ST25R3911_REG_RSSI_RESULT_rssi_pm2 (1U<<2) +#define ST25R3911_REG_RSSI_RESULT_rssi_pm3 (1U<<3) +#define ST25R3911_REG_RSSI_RESULT_mask_rssi_am (0xfU<<4) +#define ST25R3911_REG_RSSI_RESULT_shift_rssi_am (4U) +#define ST25R3911_REG_RSSI_RESULT_rssi_am_0 (1U<<4) +#define ST25R3911_REG_RSSI_RESULT_rssi_am_1 (1U<<5) +#define ST25R3911_REG_RSSI_RESULT_rssi_am_2 (1U<<6) +#define ST25R3911_REG_RSSI_RESULT_rssi_am_3 (1U<<7) +#define ST25R3911_REG_GAIN_RED_STATE_mask_gs_pm (0xfU) +#define ST25R3911_REG_GAIN_RED_STATE_shift_gs_pm (0U) +#define ST25R3911_REG_GAIN_RED_STATE_gs_pm_0 (1U<<0) +#define ST25R3911_REG_GAIN_RED_STATE_gs_pm_1 (1U<<1) +#define ST25R3911_REG_GAIN_RED_STATE_gs_pm_2 (1U<<2) +#define ST25R3911_REG_GAIN_RED_STATE_gs_pm_3 (1U<<3) +#define ST25R3911_REG_GAIN_RED_STATE_mask_gs_am (0xfU<<4) +#define ST25R3911_REG_GAIN_RED_STATE_shift_gs_am (4U) +#define ST25R3911_REG_GAIN_RED_STATE_gs_am_0 (1U<<4) +#define ST25R3911_REG_GAIN_RED_STATE_gs_am_1 (1U<<5) +#define ST25R3911_REG_GAIN_RED_STATE_gs_am_2 (1U<<6) +#define ST25R3911_REG_GAIN_RED_STATE_gs_am_3 (1U<<7) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_g0 (1U<<0) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_g1 (1U<<1) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_g2 (1U<<2) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_mask_cs_g (7U<<0) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_mcal0 (1U<<3) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_mcal1 (1U<<4) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_mcal2 (1U<<5) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_mcal3 (1U<<6) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_cs_mcal4 (1U<<7) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_mask_cs_mcal (0x1fU<<3) +#define ST25R3911_REG_CAP_SENSOR_CONTROL_shift_cs_mcal (3U) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_err (1U<<1) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal_end (1U<<2) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal0 (1U<<3) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal1 (1U<<4) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal2 (1U<<5) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal3 (1U<<6) +#define ST25R3911_REG_CAP_SENSOR_RESULT_cs_cal4 (1U<<7) +#define ST25R3911_REG_AUX_DISPLAY_en_ac (1U<<0) +#define ST25R3911_REG_AUX_DISPLAY_nfc_t (1U<<1) +#define ST25R3911_REG_AUX_DISPLAY_rx_act (1U<<2) +#define ST25R3911_REG_AUX_DISPLAY_rx_on (1U<<3) +#define ST25R3911_REG_AUX_DISPLAY_osc_ok (1U<<4) +#define ST25R3911_REG_AUX_DISPLAY_tx_on (1U<<5) +#define ST25R3911_REG_AUX_DISPLAY_efd_o (1U<<6) +#define ST25R3911_REG_AUX_DISPLAY_a_cha (1U<<7) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wcap (1U<<0) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wph (1U<<1) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wam (1U<<2) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wto (1U<<3) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wut0 (1U<<4) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wut1 (1U<<5) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wut2 (1U<<6) +#define ST25R3911_REG_WUP_TIMER_CONTROL_shift_wut (4U) +#define ST25R3911_REG_WUP_TIMER_CONTROL_mask_wut (7U<<4) +#define ST25R3911_REG_WUP_TIMER_CONTROL_wur (1U<<7) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_ae (1U<<0) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_aew0 (1U<<1) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_aew1 (1U<<2) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_shift_am_aew (1U) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_mask_am_aew (3U<<1) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_aam (1U<<3) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_d0 (1U<<4) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_d1 (1U<<5) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_d2 (1U<<6) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_am_d3 (1U<<7) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_shift_am_d (4U) +#define ST25R3911_REG_AMPLITUDE_MEASURE_CONF_mask_am_d (0xfU<<4) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_ae (1U<<0) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_aew0 (1U<<1) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_aew1 (1U<<2) +#define ST25R3911_REG_PHASE_MEASURE_CONF_shift_pm_aew (1U) +#define ST25R3911_REG_PHASE_MEASURE_CONF_mask_pm_aew (3U<<1) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_aam (1U<<3) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_d0 (1U<<4) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_d1 (1U<<5) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_d2 (1U<<6) +#define ST25R3911_REG_PHASE_MEASURE_CONF_pm_d3 (1U<<7) +#define ST25R3911_REG_PHASE_MEASURE_CONF_shift_pm_d (4U) +#define ST25R3911_REG_PHASE_MEASURE_CONF_mask_pm_d (0xfU<<4) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_ae (1U<<0) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_aew0 (1U<<1) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_aew1 (1U<<2) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_shift_cm_aew (1U) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_mask_cm_aew (3U<<1) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_aam (1U<<3) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_d0 (1U<<4) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_d1 (1U<<5) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_d2 (1U<<6) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_cm_d3 (1U<<7) +#define ST25R3911_REG_CAPACITANCE_MEASURE_CONF_shift_cm_d (4U) +#define ST25R3911_REG_IC_IDENTITY_v2 (0x09U) +#define ST25R3911_REG_IC_IDENTITY_ic_type (1U<<3) +#define ST25R3911_REG_IC_IDENTITY_mask_ic_type (0x1FU<<3) +#define ST25R3911_REG_IC_IDENTITY_shift_ic_type (3U) +#define ST25R3911_REG_IC_IDENTITY_mask_ic_rev (7U) + +/*! \endcond DOXYGEN_SUPPRESS */ + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +/*! + ***************************************************************************** + * \brief Returns the content of a register within the ST25R3911 + * + * This function is used to read out the content of ST25R3911 registers. + * + * \param[in] reg: Address of register to read. + * \param[out] value: Returned value. + * + ***************************************************************************** + */ +extern void st25r3911ReadRegister(uint8_t reg, uint8_t* value); + +/*! + ***************************************************************************** + * \brief Writes a given value to a register within the ST25R3911 + * + * This function is used to write \a value to address \a reg within the ST25R3911. + * + * \param[in] reg: Address of the register to write. + * \param[in] value: Value to be written. + * + ***************************************************************************** + */ +extern void st25r3911WriteRegister(uint8_t reg, uint8_t value); + +/*! + ***************************************************************************** + * \brief Cleart bits on Register + * + * This function clears the given bitmask on the register + * + * \warning This method does not guarantee consistency of register content + * when called from multiple contexts (task, ISR, thread) + * + * \param[in] reg: Address of the register clear + * \param[in] clr_mask: Bitmask of bit to be cleared + * + ***************************************************************************** + */ +extern void st25r3911ClrRegisterBits( uint8_t reg, uint8_t clr_mask ); + + +/*! + ***************************************************************************** + * \brief Set bits on Register + * + * This function sets the given bitmask on the register + * + * \warning This method does not guarantee consistency of register content + * when called from multiple contexts (task, ISR, thread) + * + * \param[in] reg: Address of the register clear + * \param[in] set_mask: Bitmask of bit to be cleared + * + ***************************************************************************** + */ +extern void st25r3911SetRegisterBits( uint8_t reg, uint8_t set_mask ); + + +/*! + ***************************************************************************** + * \brief Changes the given bits on a ST25R3911 register + * + * This function is used if only a particular bits should be changed within + * an ST25R3911 register. + * + * \warning This method does not guarantee consistency of register content + * when called from multiple contexts (task, ISR, thread) + * + * \param[in] reg: Address of the register to write. + * \param[in] valueMask: bitmask of bits to be changed + * \param[in] value: the bits to be written on the enabled valueMask bits + * + ***************************************************************************** + */ +extern void st25r3911ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value); + +/*! + ***************************************************************************** + * \brief Read a test register within the ST25R3911 + * + * This function is used to read the content of test address \a reg within the ST25R3911. + * + * \param[in] reg: Address of the register to read. + * \param[out] value: Returned read. + * + ***************************************************************************** + */ +extern void st25r3911ReadTestRegister(uint8_t reg, uint8_t* value); + +/*! + ***************************************************************************** + * \brief Writes a given value to a test register within the ST25R3911 + * + * This function is used to write \a value to test address \a reg within the ST25R3911. + * + * \param[in] reg: Address of the register to write. + * \param[in] value: Value to be written. + * + ***************************************************************************** + */ +extern void st25r3911WriteTestRegister(uint8_t reg, uint8_t value); + +/*! + ***************************************************************************** + * \brief Modifies a value within a ST25R3911 register + * + * This function is used if only a particular bits should be changed within + * an ST25R3911 register. + * + * \warning This method does not guarantee consistency of register content + * when called from multiple contexts (task, ISR, thread) + * + * \param[in] reg: Address of the register to write. + * \param[in] clr_mask: bitmask of bits to be cleared to 0. + * \param[in] set_mask: bitmask of bits to be set to 1. + * + ***************************************************************************** + */ +extern void st25r3911ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask); + + +/*! + ***************************************************************************** + * \brief Changes the given bits on a ST25R3911 Test register + * + * This function is used if only a particular bits should be changed within + * an ST25R3911 register. + * + * \param[in] reg: Address of the Test register to change. + * \param[in] valueMask: bitmask of bits to be changed + * \param[in] value: the bits to be written on the enabled valueMask bits + * + * \warning This method does not guarantee consistency of register content + * when called from multiple contexts (task, ISR, thread) + ***************************************************************************** + */ +extern void st25r3911ChangeTestRegisterBits( uint8_t reg, uint8_t valueMask, uint8_t value ); + +/*! + ***************************************************************************** + * \brief Writes multiple values to ST25R3911 registers + * + * This function is used to write multiple values to the ST25R3911 using the + * auto-increment feature. That is, after each write the address pointer + * inside the ST25R3911 gets incremented automatically. + * + * \param[in] reg: Address of the frist register to write. + * \param[in] values: pointer to a buffer containing the values to be written. + * \param[in] length: Number of values to be written. + * + ***************************************************************************** + */ +extern void st25r3911WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length); + +/*! + ***************************************************************************** + * \brief Reads from multiple ST25R3911 registers + * + * This function is used to read from multiple registers using the + * auto-increment feature. That is, after each read the address pointer + * inside the ST25R3911 gets incremented automatically. + * + * \param[in] reg: Address of the frist register to read from. + * \param[in] values: pointer to a buffer where the result shall be written to. + * \param[in] length: Number of registers to be read out. + * + ***************************************************************************** + */ +extern void st25r3911ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length); + +/*! + ***************************************************************************** + * \brief Writes values to ST25R3911 FIFO + * + * This function needs to be called in order to write to the ST25R3911 FIFO. + * + * \param[in] values: pointer to a buffer containing the values to be written + * to the FIFO. + * \param[in] length: Number of values to be written. + * + ***************************************************************************** + */ +extern void st25r3911WriteFifo(const uint8_t* values, uint8_t length); + +/*! + ***************************************************************************** + * \brief Read values from ST25R3911 FIFO + * + * This function needs to be called in order to read from ST25R3911 FIFO. + * + * \param[out] buf: pointer to a buffer where the FIFO content shall be + * written to. + * \param[in] length: Number of bytes to read. (= size of \a buf) + * \note: This function doesn't check whether \a length is really the + * number of available bytes in FIFO + * + ***************************************************************************** + */ +extern void st25r3911ReadFifo(uint8_t* buf, uint8_t length); + +/*! + ***************************************************************************** + * \brief Execute a direct command + * + * This function is used to start so-called direct command. These commands + * are implemented inside the chip and each command has unique code (see + * datasheet). + * + * \param[in] cmd : code of the direct command to be executed. + * + ***************************************************************************** + */ +extern void st25r3911ExecuteCommand(uint8_t cmd); + +/*! + ***************************************************************************** + * \brief Execute several direct commands + * + * This function is used to start so-called direct command. These commands + * are implemented inside the chip and each command has unique code (see + * datasheet). + * + * \param[in] cmds : codes of the direct command to be executed. + * \param[in] length : number of commands to be executed + * + ***************************************************************************** + */ +extern void st25r3911ExecuteCommands(const uint8_t *cmds, uint8_t length); + +/*! + ***************************************************************************** + * \brief Check if register ID is valid + * + * Checks if the given register ID a valid ST25R3911 register + * + * \param[in] reg: Address of register to check + * + * \return true if is a valid register ID + * \return false otherwise + * + ***************************************************************************** + */ +extern bool st25r3911IsRegValid( uint8_t reg ); + +#endif /* ST25R3911_COM_H */ + +/** + * @} + * + * @} + * + * @} + * + * @} + */ + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.c b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.c new file mode 100644 index 0000000..1a2d28c --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.c @@ -0,0 +1,305 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief ST25R3911 Interrupt handling + * + */ + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "st25r3911_interrupt.h" +#include "st25r3911_com.h" +#include "st25r3911.h" +#include "rfal_utils.h" + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + +/*! Length of the interrupt registers */ +#define ST25R3911_INT_REGS_LEN ( (ST25R3911_REG_IRQ_ERROR_WUP - ST25R3911_REG_IRQ_MAIN) + 1U ) + +/* + ****************************************************************************** + * LOCAL DATA TYPES + ****************************************************************************** + */ + +/*! Holds current and previous interrupt callback pointer as well as current Interrupt status and mask */ +typedef struct +{ + void (*prevCallback)(void); /*!< call back function for 3911 interrupt */ + void (*callback)(void); /*!< call back function for 3911 interrupt */ + uint32_t status; /*!< latest interrupt status */ + uint32_t mask; /*!< Interrupt mask. Negative mask = ST25R3911 mask regs */ + bool hasNRE; /*!< Last IRQ had NRE flag */ +}t_st25r3911Interrupt; + +/* +****************************************************************************** +* GLOBAL VARIABLES +****************************************************************************** +*/ + +static volatile t_st25r3911Interrupt st25r3911interrupt; /*!< Instance of ST25R3911 interrupt */ + + +static void st25r3911IRQCheck( uint32_t irqStatus ); + +/* +****************************************************************************** +* GLOBAL FUNCTIONS +****************************************************************************** +*/ +void st25r3911InitInterrupts( void ) +{ + platformIrqST25RPinInitialize(); + platformIrqST25RSetCallback( st25r3911Isr ); + + st25r3911interrupt.callback = NULL; + st25r3911interrupt.prevCallback = NULL; + st25r3911interrupt.status = ST25R3911_IRQ_MASK_NONE; + st25r3911interrupt.mask = ST25R3911_IRQ_MASK_NONE; + + /* Initialize LEDs if existing and defined */ + platformLedsInitialize(); + +#ifdef PLATFORM_LED_RX_PIN + platformLedOff( PLATFORM_LED_RX_PORT, PLATFORM_LED_RX_PIN ); +#endif /* PLATFORM_LED_RX_PIN */ + +#ifdef PLATFORM_LED_FIELD_PIN + platformLedOff( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN ); +#endif /* PLATFORM_LED_FIELD_PIN */ + +#ifdef PLATFORM_LED_ERR_PIN + platformLedOff( PLATFORM_LED_ERR_PORT, PLATFORM_LED_ERR_PIN ); +#endif /* PLATFORM_LED_ERR_PIN */ + +} + +void st25r3911Isr( void ) +{ + st25r3911CheckForReceivedInterrupts(); + + if (NULL != st25r3911interrupt.callback) + { + st25r3911interrupt.callback(); + } +} + +void st25r3911CheckForReceivedInterrupts( void ) +{ + uint8_t iregs[ST25R3911_INT_REGS_LEN]; + uint32_t irqStatus; + + irqStatus = ST25R3911_IRQ_MASK_NONE; + RFAL_MEMSET( iregs, (int32_t)(ST25R3911_IRQ_MASK_ALL & 0xFFU), ST25R3911_INT_REGS_LEN ); /* MISRA 10.3 */ + + /* In case the IRQ is Edge (not Level) triggered read IRQs until done */ + while( platformGpioIsHigh( ST25R_INT_PORT, ST25R_INT_PIN ) ) + { + st25r3911ReadMultipleRegisters(ST25R3911_REG_IRQ_MAIN, iregs, sizeof(iregs)); + + if ((iregs[0] & ST25R3911_IRQ_MASK_TXE) != 0U) + { + #ifdef PLATFORM_LED_FIELD_PIN + platformLedOn( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN ); + #endif /* PLATFORM_LED_FIELD_PIN */ + + #ifdef PLATFORM_LED_ERR_PIN + platformLedOff( PLATFORM_LED_ERR_PORT, PLATFORM_LED_ERR_PIN ); + #endif /* PLATFORM_LED_ERR_PIN */ + } + + #ifdef PLATFORM_LED_RX_PIN + if ((iregs[0] & ST25R3911_IRQ_MASK_RXS) != 0U) + { + platformLedOn( PLATFORM_LED_RX_PORT, PLATFORM_LED_RX_PIN ); + } + if (((iregs[0] & ST25R3911_IRQ_MASK_RXE) != 0U) || ((iregs[1] & (ST25R3911_IRQ_MASK_NRE >> 8U)) != 0U)) /* In rare cases there is rxs but not rxe, then we have nre */ + { + platformLedOff( PLATFORM_LED_RX_PORT, PLATFORM_LED_RX_PIN ); + } + #endif /* PLATFORM_LED_RX_PIN */ + + #ifdef PLATFORM_LED_ERR_PIN + + if ( (iregs[2] & ((ST25R3911_IRQ_MASK_CRC | ST25R3911_IRQ_MASK_PAR | ST25R3911_IRQ_MASK_ERR1 | ST25R3911_IRQ_MASK_ERR2) >> 16)) != 0U) + { + platformLedOn( PLATFORM_LED_ERR_PORT, PLATFORM_LED_ERR_PIN ); + } + #endif /* PLATFORM_LED_ERR_PIN */ + + + irqStatus |= (uint32_t)iregs[0]; + irqStatus |= (uint32_t)iregs[1]<<8; + irqStatus |= (uint32_t)iregs[2]<<16; + } + + /* Forward all interrupts, even masked ones to application. */ + platformProtectST25RIrqStatus(); + st25r3911interrupt.status |= irqStatus; + platformUnprotectST25RIrqStatus(); + + /* Check received IRQs */ + st25r3911IRQCheck( irqStatus ); +} + + +void st25r3911ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask) +{ + uint8_t i; + uint32_t old_mask; + uint32_t new_mask; + + old_mask = st25r3911interrupt.mask; + new_mask = (~old_mask & set_mask) | (old_mask & clr_mask); + st25r3911interrupt.mask &= ~clr_mask; + st25r3911interrupt.mask |= set_mask; + for (i=0; i<3U ; i++) + { + if (((new_mask >> (i*8U)) & 0xffU) == 0U) { + continue; + } + st25r3911WriteRegister((ST25R3911_REG_IRQ_MASK_MAIN + i), (uint8_t)((st25r3911interrupt.mask>>(i*8U))&0xffU)); + } + return; +} + + +uint32_t st25r3911WaitForInterruptsTimed(uint32_t mask, uint16_t tmo) +{ + uint32_t tmr; + uint32_t status; + + tmr = platformTimerCreate(tmo); + do + { + status = (st25r3911interrupt.status & mask); + } while( ( (!platformTimerIsExpired( tmr )) || (tmo == 0U)) && (status == 0U) ); + + status = st25r3911interrupt.status & mask; + + platformTimerDestroy(tmr); + + platformProtectST25RIrqStatus(); + st25r3911interrupt.status &= ~status; + platformUnprotectST25RIrqStatus(); + + return status; +} + +uint32_t st25r3911GetInterrupt(uint32_t mask) +{ + uint32_t irqs; + + irqs = (st25r3911interrupt.status & mask); + if (irqs != ST25R3911_IRQ_MASK_NONE) + { + platformProtectST25RIrqStatus(); + st25r3911interrupt.status &= ~irqs; + platformUnprotectST25RIrqStatus(); + } + return irqs; +} + +void st25r3911EnableInterrupts(uint32_t mask) +{ + st25r3911ModifyInterrupts(mask,0); +} + +void st25r3911DisableInterrupts(uint32_t mask) +{ + st25r3911ModifyInterrupts(0,mask); +} + +void st25r3911ClearInterrupts( void ) +{ + uint8_t iregs[3]; + + st25r3911ReadMultipleRegisters(ST25R3911_REG_IRQ_MAIN, iregs, 3); + + platformProtectST25RIrqStatus(); + st25r3911interrupt.status = 0; + platformUnprotectST25RIrqStatus(); + return; +} + +void st25r3911IRQCallbackSet( void (*cb)(void) ) +{ + st25r3911interrupt.prevCallback = st25r3911interrupt.callback; + st25r3911interrupt.callback = cb; +} + +void st25r3911IRQCallbackRestore( void ) +{ + st25r3911interrupt.callback = st25r3911interrupt.prevCallback; + st25r3911interrupt.prevCallback = NULL; +} + + +static void st25r3911IRQCheck( uint32_t irqStatus ) +{ + /*******************************************************************************/ + /* REMARK: Silicon workaround ST25R3911 Errata #1.6 */ + /* Repetitive I_nre in EMV mode when I_txe is not read */ + /* Rarely due to timing reason, the interrupt I_nre repeats several times. */ + /*******************************************************************************/ + + /* If NRT has been signaled without any other IRQ */ + if( irqStatus == (ST25R3911_IRQ_MASK_NRE | ST25R3911_IRQ_MASK_TIM) ) + { + /* If NRT was received on the last ISR as well */ + if( st25r3911interrupt.hasNRE ) + { + /* Disabling the NRT's EMV mode and and sending a Clear command stops this condition */ + st25r3911ClrRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + st25r3911ExecuteCommand( ST25R3911_CMD_CLEAR_FIFO ); + st25r3911SetRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + + /* If RFAL is being used and a Transceive is ongoing it will fail with NRE or the * + * sanity timer will conclude the ongoing transceive */ + + st25r3911SetRegisterBits( ST25R3911_REG_GPT_CONTROL, ST25R3911_REG_GPT_CONTROL_nrt_emv ); + } + + st25r3911interrupt.hasNRE = true; + } + else + { + st25r3911interrupt.hasNRE = false; + } + /*******************************************************************************/ +} + diff --git a/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.h b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.h new file mode 100644 index 0000000..3365543 --- /dev/null +++ b/components/spi-st25r3911b/en.STSW-ST25RFAL001/source/st25r3911/st25r3911_interrupt.h @@ -0,0 +1,247 @@ + +/****************************************************************************** + * @attention + * + * COPYRIGHT 2016 STMicroelectronics, all rights reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + + + +/* + * PROJECT: ST25R3911 firmware + * Revision: + * LANGUAGE: ISO C99 + */ + +/*! \file + * + * \author Ulrich Herrmann + * + * \brief ST25R3911 Interrupt header file + * + * + * \addtogroup RFAL + * @{ + * + * \addtogroup RFAL-HAL + * \brief RFAL Hardware Abstraction Layer + * @{ + * + * \addtogroup ST25R3911 + * \brief RFAL ST25R3911 Driver + * @{ + * + * \addtogroup ST25R3911_Interrupt + * \brief RFAL ST25R3911 Interrupt + * @{ + * + */ + +#ifndef ST25R3911_INTERRUPT_H +#define ST25R3911_INTERRUPT_H + +/* +****************************************************************************** +* INCLUDES +****************************************************************************** +*/ +#include "rfal_platform.h" + +/* +****************************************************************************** +* GLOBAL DEFINES +****************************************************************************** +*/ + +/* Main interrupt register. */ +#define ST25R3911_IRQ_MASK_ALL (uint32_t)(0xFFFFFFU) /*!< All ST25R3911 interrupt sources */ +#define ST25R3911_IRQ_MASK_NONE (uint32_t)(0U) /*!< No ST25R3911 interrupt source */ +#define ST25R3911_IRQ_MASK_OSC (uint32_t)(0x80U) /*!< ST25R3911 oscillator stable interrupt */ +#define ST25R3911_IRQ_MASK_FWL (uint32_t)(0x40U) /*!< ST25R3911 FIFO water level interrupt */ +#define ST25R3911_IRQ_MASK_RXS (uint32_t)(0x20U) /*!< ST25R3911 start of receive interrupt */ +#define ST25R3911_IRQ_MASK_RXE (uint32_t)(0x10U) /*!< ST25R3911 end of receive interrupt */ +#define ST25R3911_IRQ_MASK_TXE (uint32_t)(0x08U) /*!< ST25R3911 end of transmission interrupt */ +#define ST25R3911_IRQ_MASK_COL (uint32_t)(0x04U) /*!< ST25R3911 bit collision interrupt */ + +/* Timer and NFC interrupt register. */ +#define ST25R3911_IRQ_MASK_DCT (uint32_t)(0x8000U) /*!< ST25R3911 termination of direct command interrupt */ +#define ST25R3911_IRQ_MASK_NRE (uint32_t)(0x4000U) /*!< ST25R3911 no-response timer expired interrupt */ +#define ST25R3911_IRQ_MASK_GPE (uint32_t)(0x2000U) /*!< ST25R3911 general purpose timer expired interrupt */ +#define ST25R3911_IRQ_MASK_EON (uint32_t)(0x1000U) /*!< ST25R3911 external field on interrupt */ +#define ST25R3911_IRQ_MASK_EOF (uint32_t)(0x0800U) /*!< ST25R3911 external field off interrupt */ +#define ST25R3911_IRQ_MASK_CAC (uint32_t)(0x0400U) /*!< ST25R3911 collision during RF collision avoidance interrupt */ +#define ST25R3911_IRQ_MASK_CAT (uint32_t)(0x0200U) /*!< ST25R3911 minimum guard time expired interrupt */ +#define ST25R3911_IRQ_MASK_NFCT (uint32_t)(0x0100U) /*!< ST25R3911 initiator bit rate recognized interrupt */ + +/* Error and wake-up interrupt register. */ +#define ST25R3911_IRQ_MASK_CRC (uint32_t)(0x800000U) /*!< ST25R3911 CRC error interrupt */ +#define ST25R3911_IRQ_MASK_PAR (uint32_t)(0x400000U) /*!< ST25R3911 parity error interrupt */ +#define ST25R3911_IRQ_MASK_ERR2 (uint32_t)(0x200000U) /*!< ST25R3911 soft framing error interrupt */ +#define ST25R3911_IRQ_MASK_ERR1 (uint32_t)(0x100000U) /*!< ST25R3911 hard framing error interrupt */ +#define ST25R3911_IRQ_MASK_WT (uint32_t)(0x080000U) /*!< ST25R3911 wake-up interrupt */ +#define ST25R3911_IRQ_MASK_WAM (uint32_t)(0x040000U) /*!< ST25R3911 wake-up due to amplitude interrupt */ +#define ST25R3911_IRQ_MASK_WPH (uint32_t)(0x020000U) /*!< ST25R3911 wake-up due to phase interrupt */ +#define ST25R3911_IRQ_MASK_WCAP (uint32_t)(0x010000U) /*!< ST25R3911 wake-up due to capacitance measurement */ + + +#define ST25R3911_IRQ_MASK_TIM (0x02U) /*!< additional interrupts in ST25R3911_REG_IRQ_TIMER_NFC */ +#define ST25R3911_IRQ_MASK_ERR (0x01U) /*!< additional interrupts in ST25R3911_REG_IRQ_ERROR_WUP */ + + +/* +****************************************************************************** +* GLOBAL FUNCTION PROTOTYPES +****************************************************************************** +*/ + + +/*! + ***************************************************************************** + * \brief Wait until an ST25R3911 interrupt occurs + * + * This function is used to access the ST25R3911 interrupt flags. Use this + * to wait for max. \a tmo milliseconds for the \b first interrupt indicated + * with mask \a mask to occur. + * + * \param[in] mask : mask indicating the interrupts to wait for. + * \param[in] tmo : time in milliseconds until timeout occurs. If set to 0 + * the functions waits forever. + * + * \return : 0 if timeout occurred otherwise a mask indicating the cleared + * interrupts. + * + ***************************************************************************** + */ +extern uint32_t st25r3911WaitForInterruptsTimed(uint32_t mask, uint16_t tmo); + +/*! + ***************************************************************************** + * \brief Get status for the given interrupt + * + * This function is used to check whether the interrupt given by \a mask + * has occurred. If yes the interrupt gets cleared. This function returns + * only status bits which are inside \a mask. + * + * \param[in] mask : mask indicating the interrupt to check for. + * + * \return the mask of the interrupts occurred + * + ***************************************************************************** + */ +extern uint32_t st25r3911GetInterrupt(uint32_t mask); + + +/*! + ***************************************************************************** + * \brief Init the 3911 interrupt + * + * This function initiates the 3911 interrupts. + * + ***************************************************************************** + */ +extern void st25r3911InitInterrupts( void ); + + +/*! + ***************************************************************************** + * \brief Modifies the Interrupt + * + * This function modifies the interrupt + * + * \param[in] clr_mask : bit mask to be cleared on the interrupt mask + * \param[in] set_mask : bit mask to be set on the interrupt mask + ***************************************************************************** + */ +extern void st25r3911ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask); + + +/*! + ***************************************************************************** + * \brief Checks received interrupts + * + * Checks received interrupts and saves the result into global params + ***************************************************************************** + */ +extern void st25r3911CheckForReceivedInterrupts( void ); + + +/*! + ***************************************************************************** + * \brief ISR Service routine + * + * This function modifies the interrupt + ***************************************************************************** + */ +extern void st25r3911Isr( void ); + +/*! + ***************************************************************************** + * \brief Enable a given ST25R3911 Interrupt source + * + * This function enables all interrupts given by \a mask, + * ST25R3911_IRQ_MASK_ALL enables all interrupts. + * + * \param[in] mask: mask indicating the interrupts to be enabled + * + ***************************************************************************** + */ +extern void st25r3911EnableInterrupts(uint32_t mask); + +/*! + ***************************************************************************** + * \brief Disable one or more a given ST25R3911 Interrupt sources + * + * This function disables all interrupts given by \a mask. 0xff disables all. + * + * \param[in] mask: mask indicating the interrupts to be disabled. + * + ***************************************************************************** + */ +extern void st25r3911DisableInterrupts(uint32_t mask); + +/*! + ***************************************************************************** + * \brief Clear all st25r3911 irq flags + * + ***************************************************************************** + */ +extern void st25r3911ClearInterrupts(void); + +/*! + ***************************************************************************** + * \brief Sets IRQ callback for the ST25R3911 interrupt + * + * \param[in] cb: pointer to the callback method + * + ***************************************************************************** + */ +extern void st25r3911IRQCallbackSet(void (*cb)(void)); + +/*! + ***************************************************************************** + * \brief Sets IRQ callback for the ST25R3911 interrupt + * + ***************************************************************************** + */ +extern void st25r3911IRQCallbackRestore(void); + +#endif /* ST25R3911_ISR_H */ + +/** + * @} + * + * @} + * + * @} + * + * @} + */ diff --git a/components/spi-st25r3911b/include/st25r3911b.h b/components/spi-st25r3911b/include/st25r3911b.h new file mode 100644 index 0000000..731ffc6 --- /dev/null +++ b/components/spi-st25r3911b/include/st25r3911b.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define ST25R3911 +#define ST25R_SELFTEST + +#include "rfal_defConfig.h" +#include "rfal_platform.h" +#include "rfal_nfc.h" + +typedef struct ST25R3911B { + int spi_bus; + int pin_cs; + int pin_irq; + uint32_t spi_speed; + spi_device_handle_t spi_device; + SemaphoreHandle_t mutex; + SemaphoreHandle_t spi_semaphore; + TaskHandle_t intr_task_handle; + SemaphoreHandle_t intr_trigger; + void (*irq_callback)(void); +} ST25R3911B; + +esp_err_t st25r3911b_init(ST25R3911B * device); +esp_err_t st25r3911b_chip_id(uint8_t *id); +esp_err_t st25r3911b_discover(rfalNfcDevice *nfcDevice, uint32_t timeout_ms); + +esp_err_t st25r3911b_rxtx(ST25R3911B *device, const uint8_t* tx, const uint8_t* rx, uint8_t length); diff --git a/components/spi-st25r3911b/include/st25r3911b_global.h b/components/spi-st25r3911b/include/st25r3911b_global.h new file mode 100644 index 0000000..0df593a --- /dev/null +++ b/components/spi-st25r3911b/include/st25r3911b_global.h @@ -0,0 +1,5 @@ +#pragma once + +#include "st25r3911b.h" + +extern ST25R3911B* global_st25r3911b; diff --git a/components/spi-st25r3911b/st25r3911b.c b/components/spi-st25r3911b/st25r3911b.c new file mode 100644 index 0000000..771c3bf --- /dev/null +++ b/components/spi-st25r3911b/st25r3911b.c @@ -0,0 +1,344 @@ +#include "st25r3911b.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtc_wdt.h" +#include "st25r3911.h" +#include "st25r3911_com.h" +#include "st25r3911b_global.h" + +static const char *TAG = "st25r3911b"; + +/* P2P communication data */ +static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; +static uint8_t GB[] = {0x46, 0x66, 0x6d, 0x01, 0x01, 0x11, 0x02, 0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03, 0x04, 0x01, 0x32, 0x07, 0x01, 0x03}; + +#define NFC_LOG_SPI 0 + +#define MAX_HEX_STR_LENGTH 64 +char hexStr[MAX_HEX_STR_LENGTH * 2]; + +static char* hex2Str(unsigned char * data, size_t dataLen) { + unsigned char *pin = data; + const char *hex = "0123456789ABCDEF"; + char *pout = hexStr; + uint8_t i = 0; + if(dataLen == 0) { + hexStr[0] = 0; + } else { + for(; i < dataLen - 1 && i < MAX_HEX_STR_LENGTH - 1; ++i) { + *pout++ = hex[(*pin>>4)&0xF]; + *pout++ = hex[(*pin++)&0xF]; + } + *pout++ = hex[(*pin>>4)&0xF]; + *pout++ = hex[(*pin)&0xF]; + *pout = 0; + } + + return hexStr; +} + +esp_err_t st25r3911b_rxtx(ST25R3911B *device, const uint8_t* tx, const uint8_t* rx, uint8_t length) { + if (device->spi_device == NULL) return ESP_FAIL; + + esp_err_t res = ESP_OK; + size_t len = length * 8; + +#if NFC_LOG_SPI == 1 + if (tx != NULL) { + if ((tx[0] & 0xC0) == 0xC0) { + ESP_LOGI(TAG, "Command %x %d", tx[0], length); + } + } + + if (tx != NULL) { + if (tx[0] == 0x80) { + ESP_LOGI(TAG, "FIFO W %d, %x %x %x %x" , length, tx[0], tx[1], tx[2], tx[3]); + } + } +#endif + + + spi_transaction_t tx_transaction = { + .length = len, + .rxlength = len, + .tx_buffer = (void*) tx, + .rx_buffer = (void*) rx, + .user = (void *) device, + .flags = 0, + }; + res = spi_device_transmit(device->spi_device, &tx_transaction); + if (res != ESP_OK) { + ESP_LOGE(TAG, "rxtx failed with %d", res); + return res; + } + +#if NFC_LOG_SPI == 1 + if (tx != NULL && rx != NULL) { + if (tx[0] == 0xBF) { + ESP_LOGI(TAG, "FIFO R %d, %x %x %x %x" , length, rx[0], rx[1], rx[2], rx[3]); + } + } +#endif + + return res; +} + +bool st25r3911b_get_discovery_prams(rfalNfcDiscoverParam * discParam) { + if (discParam == NULL) { + return false; + } + + rfalNfcDefaultDiscParams( discParam ); + + discParam->devLimit = 1U; + + memcpy( discParam->nfcid3, NFCID3, sizeof(NFCID3) ); + memcpy( discParam->GB, GB, sizeof(GB) ); + discParam->GBLen = sizeof(GB); + discParam->p2pNfcaPrio = true; + + discParam->notifyCb = NULL; + discParam->totalDuration = 1000U; + discParam->techs2Find = RFAL_NFC_TECH_NONE; /* For the demo, enable the NFC Technologies based on RFAL Feature switches */ + + +#if RFAL_FEATURE_NFCA + discParam->techs2Find |= RFAL_NFC_POLL_TECH_A; +#endif /* RFAL_FEATURE_NFCA */ + +#if RFAL_FEATURE_NFCB + discParam->techs2Find |= RFAL_NFC_POLL_TECH_B; +#endif /* RFAL_FEATURE_NFCB */ + +#if RFAL_FEATURE_NFCF + discParam->techs2Find |= RFAL_NFC_POLL_TECH_F; +#endif /* RFAL_FEATURE_NFCF */ + +#if RFAL_FEATURE_NFCV + discParam->techs2Find |= RFAL_NFC_POLL_TECH_V; +#endif /* RFAL_FEATURE_NFCV */ + +#if RFAL_FEATURE_ST25TB + discParam->techs2Find |= RFAL_NFC_POLL_TECH_ST25TB; +#endif /* RFAL_FEATURE_ST25TB */ + +#if RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P && RFAL_FEATURE_NFC_DEP + discParam->techs2Find |= RFAL_NFC_POLL_TECH_AP2P; +#endif /* RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P && RFAL_FEATURE_NFC_DEP */ + +#if RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P && RFAL_FEATURE_NFC_DEP && RFAL_FEATURE_LISTEN_MODE + discParam->techs2Find |= RFAL_NFC_LISTEN_TECH_AP2P; +#endif /* RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P && RFAL_FEATURE_NFC_DEP && RFAL_FEATURE_LISTEN_MODE */ + +#if RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE + +#if RFAL_SUPPORT_MODE_LISTEN_NFCA + /* Set configuration for NFC-A CE */ + ST_MEMCPY( discParam->lmConfigPA.SENS_RES, ceNFCA_SENS_RES, RFAL_LM_SENS_RES_LEN ); /* Set SENS_RES / ATQA */ + ST_MEMCPY( discParam->lmConfigPA.nfcid, ceNFCA_NFCID, RFAL_LM_NFCID_LEN_04 ); /* Set NFCID / UID */ + discParam->lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 7 bytes */ + discParam->lmConfigPA.SEL_RES = ceNFCA_SEL_RES; /* Set SEL_RES / SAK */ + + discParam->techs2Find |= RFAL_NFC_LISTEN_TECH_A; +#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCA */ + +#if RFAL_SUPPORT_MODE_LISTEN_NFCF + /* Set configuration for NFC-F CE */ + ST_MEMCPY( discParam->lmConfigPF.SC, ceNFCF_SC, RFAL_LM_SENSF_SC_LEN ); /* Set System Code */ + ST_MEMCPY( &ceNFCF_SENSF_RES[RFAL_NFCF_CMD_LEN], ceNFCF_nfcid2, RFAL_NFCID2_LEN ); /* Load NFCID2 on SENSF_RES */ + ST_MEMCPY( discParam->lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES, RFAL_LM_SENSF_RES_LEN ); /* Set SENSF_RES / Poll Response */ + + discParam->techs2Find |= RFAL_NFC_LISTEN_TECH_F; +#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCF */ +#endif /* RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE */ + return true; +} + +esp_err_t st25r3911b_discover(rfalNfcDevice *nfcDevice, uint32_t timeout_ms) { + rfalNfcDiscoverParam discParam; + st25r3911b_get_discovery_prams(&discParam); + + ReturnCode err = rfalNfcDiscover( &discParam ); + if( err != RFAL_ERR_NONE ) { + ESP_LOGE(TAG, "Failed to call rfalNfcDiscover"); + return ESP_FAIL; + } + + int64_t end = esp_timer_get_time() / 1000 + timeout_ms; + + while(esp_timer_get_time() / 1000 < end) { + rfalNfcWorker(); + vTaskDelay(10 / portTICK_PERIOD_MS); + + if (rfalNfcIsDevActivated(rfalNfcGetState())) { + rfalNfcGetActiveDevice( &nfcDevice ); + vTaskDelay(50 / portTICK_PERIOD_MS); + + ESP_LOGD(TAG, "Discovered NFC device type=%d, uid=%s", nfcDevice->type, hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen )); + rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_IDLE ); + + return ESP_OK; + } + } + + rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_IDLE ); + return ESP_ERR_TIMEOUT; +} + +esp_err_t st25r3911b_test() { + esp_err_t res; + + uint8_t id = 0; + res = st25r3911b_chip_id(&id); + if (res != ESP_OK) { + return res; + } + + switch (id) { + case 0x02: + ESP_LOGI(TAG, "silicon rev. r3.1"); + break; + case 0x03: + ESP_LOGI(TAG, "silicon rev. r3.3"); + break; + case 0x04: + ESP_LOGI(TAG, "silicon rev. r4.0"); + break; + case 0x05: + ESP_LOGI(TAG, "silicon rev. r4.1"); + break; + default: + ESP_LOGE(TAG, "Currently unknown silicon rev. 0x%02x", id); + return ESP_FAIL; + } + static rfalNfcDevice *nfcDevice; + + return ESP_OK; +} + +esp_err_t st25r3911b_chip_id(uint8_t *id) { + if (global_st25r3911b == NULL) { + ESP_LOGE(TAG, "chip_id called before global device was initialized"); + } + return st25r3911CheckChipID(id) ? ESP_OK : ESP_FAIL; +} + +_Noreturn static void intr_task(void* arg) { + ST25R3911B* device = (ST25R3911B*) arg; + + while (1) { + if (xSemaphoreTake(device->intr_trigger, portMAX_DELAY)) { + ESP_LOGD(TAG, "Received interrupt"); + if (device->irq_callback != NULL) { + device->irq_callback(); + } else { + ESP_LOGI(TAG, "No NFC callback defined"); + } + } + } +} + +static void intr_handler(void* arg) { /* in interrupt handler */ + ST25R3911B* device = (ST25R3911B*) arg; + xSemaphoreGiveFromISR(device->intr_trigger, NULL); + portYIELD_FROM_ISR(); +} + +esp_err_t st25r3911b_init(ST25R3911B *device) { + esp_err_t res; + + if (device->pin_cs < 0) return ESP_FAIL; + if (device->spi_speed > 6000000) return ESP_FAIL; + + if (device->spi_device == NULL) { + spi_device_interface_config_t devcfg = {.command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 1, + .duty_cycle_pos = 128, + .cs_ena_pretrans = 1, + .cs_ena_posttrans = 0, + .clock_speed_hz = device->spi_speed, + .input_delay_ns = 0, + .spics_io_num = -1, + .queue_size = 1, + .pre_cb = NULL, + .post_cb = NULL}; + res = spi_bus_add_device(device->spi_bus, &devcfg, &device->spi_device); + if (res != ESP_OK) return res; + } + + /* Setup CS */ + gpio_config_t dc_io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1LL << device->pin_cs, + .pull_down_en = 0, + .pull_up_en = 0, + }; + res = gpio_config(&dc_io_conf); + if (res != ESP_OK) return res; + res = gpio_set_level(device->pin_cs, true); + if (res != ESP_OK) return res; + + + if (device->pin_irq) { + // Create interrupt trigger + device->intr_trigger = xSemaphoreCreateBinary(); + if (device->intr_trigger == NULL) return ESP_ERR_NO_MEM; + + // Attach interrupt to interrupt pin (if available) + res = gpio_isr_handler_add(device->pin_irq, intr_handler, (void*) device); + if (res != ESP_OK) return res; + + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_POSEDGE, + .mode = GPIO_MODE_INPUT, + .pin_bit_mask = 1LL << device->pin_irq, + .pull_down_en = 0, + .pull_up_en = 0, + }; + + res = gpio_config(&io_conf); + if (res != ESP_OK) return res; + + xTaskCreate(&intr_task, "NFC interrupt task", 4096, device, 10, &device->intr_task_handle); + } + + global_st25r3911b = device; + + ReturnCode err; + + err = st25r3911Initialize(); + if( err != RFAL_ERR_NONE ) { + ESP_LOGE(TAG, "failed to st25r3911Initialize: %d", err); + return ESP_FAIL; + } + + err = rfalNfcInitialize(); + if( err != RFAL_ERR_NONE ) { + ESP_LOGE(TAG, "failed to initialize"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Finished initializing. Starting self test"); + + return st25r3911b_test(); +} diff --git a/components/troopers24-bsp b/components/troopers24-bsp index 31baa6c..389cf17 160000 --- a/components/troopers24-bsp +++ b/components/troopers24-bsp @@ -1 +1 @@ -Subproject commit 31baa6cdff42973f39af23d83a03651279f30f50 +Subproject commit 389cf173312dab3438e5aaa05d46b31ee6ec232b diff --git a/main/factory_test.c b/main/factory_test.c index aed80ba..8e10fe5 100644 --- a/main/factory_test.c +++ b/main/factory_test.c @@ -2,15 +2,16 @@ #include #include #include +#include #include #include -#include #include #include +#include #include -#include "filesystems.h" #include "audio.h" +#include "filesystems.h" #include "hardware.h" #include "pax_gfx.h" #include "settings.h" @@ -25,7 +26,7 @@ bool wait_for_key_pressed(Keyboard* keyboard, Key key) { keyboard_input_message_t buttonMessage = {0}; int i = 0; - while (i < 10) { + while (i < 20) { if (xQueueReceive(keyboard->queue, &buttonMessage, 1000 / portTICK_PERIOD_MS) == pdTRUE) { if (buttonMessage.state && buttonMessage.input == key) { return true; @@ -60,11 +61,22 @@ bool test_keyboard_init(uint32_t* rc) { *rc = (uint32_t) 2; return false; } + ESP_LOGI(TAG, "Press UP..."); + pax_simple_rect(pax_buffer, 0xFFFFFFFF, 0, pax_buffer->height - 36, pax_buffer->width, 36); + pax_draw_text(pax_buffer, 0xFF0000FF, font, 36, 0, pax_buffer->height - 36, "Press UP"); + display_flush(); + if (!wait_for_key_pressed(keyboard, JOYSTICK_UP)) { + ESP_LOGE(TAG, "Timeout reached"); + pax_simple_rect(pax_buffer, 0xFFFFFFFF, 0, pax_buffer->height - 36, pax_buffer->width, 36); + display_flush(); + *rc = (uint32_t) 2; + return false; + } pax_simple_rect(pax_buffer, 0xFFFFFFFF, 0, pax_buffer->height - 36, pax_buffer->width, 36); display_flush(); - return (keyboard != NULL); + return true; } bool test_sdcard_init(uint32_t* rc) { @@ -117,26 +129,74 @@ bool test_sdcard_init(uint32_t* rc) { bool test_stuck_buttons(uint32_t* rc) { Keyboard* keyboard = get_keyboard(); if (keyboard == NULL) { - *rc = (uint32_t) 1; + *rc = 0xFFFFFFFF - 1; return false; } - // TODO: Replace -// RP2040* rp2040 = get_rp2040(); - uint16_t state = 0; -// esp_err_t res = rp2040_read_buttons(rp2040, &state); -// if (res != ESP_OK) { -// *rc = 0xFFFFFFFF; -// return false; -// } + vTaskDelay(pdMS_TO_TICKS(500)); -// state &= ~(1 << FPGA_CDONE); // Ignore FPGA CDONE + uint16_t state; + + esp_err_t res = pca9555_get_gpio_values(keyboard->pca, &state); + if (res != ESP_OK) { + *rc = 0xFFFFFFFF - 2; + return false; + } + state &= 0x1ff; + + ESP_LOGI(TAG, "keyboard state: %04x", state); *rc = state; return (state == 0x0000); } +/* Test routines */ +bool test_nfc_init(uint32_t* rc) { + ST25R3911B* nfc = get_nfc(); + if (nfc == NULL) { + *rc = 0xFFFFFFFF - 1; + return false; + } + + uint8_t id = 0; + esp_err_t res = st25r3911b_chip_id(&id); + if (res != ESP_OK) { + *rc = 0xFFFFFFFF - 2; + return false; + } + + *rc = id; + + return (*rc == 0x05); +} + +bool test_nfc_read_uid(uint32_t* rc) { + ST25R3911B* nfc = get_nfc(); + if (nfc == NULL) { + *rc = 0xFFFFFFFF - 1; + return false; + } + + rfalNfcDevice nfcDevice = {0}; + bool found = false; + int tries = 30; + int remaining = tries; + + while (!found && remaining-- > 0) { + esp_err_t res = st25r3911b_discover(&nfcDevice, 1000); + if (res == ESP_ERR_TIMEOUT) { + continue; + } + if (res == ESP_OK) { + found = true; + } + } + + *rc = (uint32_t) tries - remaining; + return (found == true); +} + bool run_basic_tests() { pax_buf_t* pax_buffer = get_pax_buffer(); const pax_font_t* font; @@ -152,10 +212,12 @@ bool run_basic_tests() { /* Run mandatory tests */ RUN_TEST_MANDATORY("KEYBOARD", test_keyboard_init); + RUN_TEST_MANDATORY("NFC", test_nfc_init); /* Run tests */ RUN_TEST("STUCK BUTTONS", test_stuck_buttons); RUN_TEST("SD CARD", test_sdcard_init); + RUN_TEST("NFC READ", test_nfc_read_uid); error: /* Fail result on screen */ @@ -169,7 +231,7 @@ uint8_t led_red[NUM_LEDS*3] = {0}; uint8_t led_blue[NUM_LEDS*3] = {0}; uint8_t led_white[NUM_LEDS*3] = {0}; -void factory_test() { +_Noreturn void factory_test() { for (int i = 0; i < NUM_LEDS; i++) { led_green[3*i] = 50; led_green[3*i+1] = 0; @@ -191,6 +253,7 @@ void factory_test() { pax_buf_t* pax_buffer = get_pax_buffer(); uint8_t factory_test_done = nvs_get_u8_default("system", "factory_test", 0); if (!factory_test_done) { + st77xx_backlight(true); bool result; ESP_LOGI(TAG, "Factory test start"); @@ -218,7 +281,6 @@ void factory_test() { pax_background(pax_buffer, 0xa85a32); display_flush(); } - nvs_set_u8_fixed("system", "force_sponsors", 0x01); // Force showing sponsors on first boot wifi_set_defaults(); pax_noclip(pax_buffer); pax_background(pax_buffer, 0x00FF00); @@ -226,10 +288,13 @@ void factory_test() { ws2812_send_data(led_green, sizeof(led_green)); ESP_LOGI(TAG, "Make sure the speaker is NOT muted and a sound is playing"); + pax_draw_text(pax_buffer, 0xffff0000, pax_font_sky_mono, 36, 0, 20, "SUCCESS!"); + pax_draw_text(pax_buffer, 0xffff0000, pax_font_sky_mono, 16, 0, 56, "Does the speaker work?"); + display_flush(); while (true) { - if (result) play_bootsound(); - vTaskDelay(4000 / portTICK_PERIOD_MS); + play_bootsound(); + vTaskDelay(2000 / portTICK_PERIOD_MS); } } diff --git a/main/include/factory_test.h b/main/include/factory_test.h index 713f3c1..6968f02 100644 --- a/main/include/factory_test.h +++ b/main/include/factory_test.h @@ -1,3 +1,4 @@ +#include #pragma once -void factory_test(); +_Noreturn void factory_test(); diff --git a/main/include/wifi_defaults.h b/main/include/wifi_defaults.h index ae41274..eacfe74 100644 --- a/main/include/wifi_defaults.h +++ b/main/include/wifi_defaults.h @@ -6,9 +6,9 @@ #include "esp_wifi_types.h" #include "esp_wpa2.h" -// Camp WiFi settings. +// TROOPERS WiFi settings. #define WIFI_TROOPERS_SSID "trp-badge" -#define WIFI_TROOPERS_PASSWORD "5EILZYY-kAGxzLhFrLjln3ThO6qLUd" +#define WIFI_TROOPERS_PASSWORD "TroopersBadge24" #define WIFI_TROOPERS_AUTH WIFI_AUTH_WPA2_PSK bool wifi_set_defaults(); diff --git a/main/main.c b/main/main.c index 4645b4c..6468289 100644 --- a/main/main.c +++ b/main/main.c @@ -169,8 +169,8 @@ _Noreturn void app_main(void) { /* Initialize the LEDs */ ws2812_init(GPIO_LED_DATA, 150); - const uint8_t led_off[3*NUM_LEDS]; - memset((void *) led_off, 0, 3*NUM_LEDS); + const uint8_t led_off[NUM_LEDS * 3]; + memset((void*) led_off, 0, NUM_LEDS * 3); ws2812_send_data(led_off, sizeof(led_off)); /* Enable the amplifier */ @@ -187,6 +187,32 @@ _Noreturn void app_main(void) { pca9555_set_gpio_value(io_expander, IO_AMP_GAIN0, 1); pca9555_set_gpio_value(io_expander, IO_AMP_GAIN1, 1); + /* Start NVS */ + res = nvs_init(); + if (res != ESP_OK) { + ESP_LOGE(TAG, "NVS init failed: %d", res); + wait_for_boot_anim(); + display_fatal_error(fatal_error_str, "NVS failed to initialize", "Flash may be corrupted", NULL); + stop(); + } + + nvs_handle_t handle; + res = nvs_open("system", NVS_READWRITE, &handle); + if (res != ESP_OK) { + ESP_LOGE(TAG, "NVS open failed: %d", res); + wait_for_boot_anim(); + display_fatal_error(fatal_error_str, "Failed to open NVS namespace", "Flash may be corrupted", reset_board_str); + stop(); + } + + // TODO: This is resetting the factory test status, so that factory test will run on every boot + nvs_set_u8_fixed("system", "factory_test", 0x00); + factory_test(); + + /* Initialize LCD screen */ + pax_buf_t* pax_buffer = get_pax_buffer(); + xTaskCreate(boot_animation_task, "boot_anim_task", 4096, NULL, 12, NULL); + /* Turning the backlight on */ #ifdef TR23 gpio_config_t io_conf = { @@ -213,35 +239,12 @@ _Noreturn void app_main(void) { st77xx_backlight(true); #endif - /* Initialize LCD screen */ - pax_buf_t* pax_buffer = get_pax_buffer(); - xTaskCreate(boot_animation_task, "boot_anim_task", 4096, NULL, 12, NULL); if (!wakeup_deepsleep) { /* TROOPERS */ xTaskCreate(audio_player_task, "audio_player_task", 2048, NULL, 12, NULL); } - /* Start NVS */ - res = nvs_init(); - if (res != ESP_OK) { - ESP_LOGE(TAG, "NVS init failed: %d", res); - wait_for_boot_anim(); - display_fatal_error(fatal_error_str, "NVS failed to initialize", "Flash may be corrupted", NULL); - stop(); - } - - nvs_handle_t handle; - res = nvs_open("system", NVS_READWRITE, &handle); - if (res != ESP_OK) { - ESP_LOGE(TAG, "NVS open failed: %d", res); - wait_for_boot_anim(); - display_fatal_error(fatal_error_str, "Failed to open NVS namespace", "Flash may be corrupted", reset_board_str); - stop(); - } - -// factory_test(); - /* Start AppFS */ res = appfs_init(); if (res != ESP_OK) { diff --git a/sdkconfig b/sdkconfig index 040b98d..889d320 100644 --- a/sdkconfig +++ b/sdkconfig @@ -762,7 +762,7 @@ CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y CONFIG_FREERTOS_CORETIMER_0=y # CONFIG_FREERTOS_CORETIMER_1 is not set CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y -CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set