From bb8deeb27d1f37c09b40bc2770fc577720ea0887 Mon Sep 17 00:00:00 2001 From: willem Date: Mon, 11 Oct 2021 11:30:39 +0200 Subject: [PATCH] initial commit --- LICENSE.md | 23 + README.md | 22 + .../X_NUCLEO_NFC03A1_HelloWorld.ino | 329 ++++ library.properties | 9 + src/common.h | 122 ++ src/drv_95HF.h | 248 +++ src/drv_95hf.cpp | 515 +++++ src/drv_spi.cpp | 123 ++ src/drv_spi.h | 86 + src/lib_95HF.h | 128 ++ src/lib_95HFConfigManager.cpp | 324 ++++ src/lib_95HFConfigManager.h | 112 ++ src/lib_95HF_wrapper.cpp | 401 ++++ src/lib_NDEF.cpp | 613 ++++++ src/lib_NDEF.h | 259 +++ src/lib_NDEF_AAR.cpp | 188 ++ src/lib_NDEF_AAR.h | 57 + src/lib_NDEF_Email.cpp | 413 ++++ src/lib_NDEF_Email.h | 64 + src/lib_NDEF_Geo.cpp | 372 ++++ src/lib_NDEF_Geo.h | 61 + src/lib_NDEF_MyApp.cpp | 297 +++ src/lib_NDEF_MyApp.h | 89 + src/lib_NDEF_SMS.cpp | 384 ++++ src/lib_NDEF_SMS.h | 62 + src/lib_NDEF_Text.cpp | 141 ++ src/lib_NDEF_Text.h | 49 + src/lib_NDEF_URI.cpp | 554 ++++++ src/lib_NDEF_URI.h | 62 + src/lib_NDEF_Vcard.cpp | 389 ++++ src/lib_NDEF_Vcard.h | 114 ++ src/lib_iso14443A.h | 137 ++ src/lib_iso14443Apcd.cpp | 993 ++++++++++ src/lib_iso14443Apcd.h | 129 ++ src/lib_iso14443Bpcd.cpp | 415 ++++ src/lib_iso14443Bpcd.h | 195 ++ src/lib_iso15693pcd.cpp | 1674 +++++++++++++++++ src/lib_iso15693pcd.h | 318 ++++ src/lib_iso18092pcd.cpp | 221 +++ src/lib_iso18092pcd.h | 77 + src/lib_iso7816pcd.cpp | 275 +++ src/lib_iso7816pcd.h | 110 ++ src/lib_nfctype1pcd.cpp | 248 +++ src/lib_nfctype1pcd.h | 75 + src/lib_nfctype2pcd.cpp | 344 ++++ src/lib_nfctype2pcd.h | 85 + src/lib_nfctype3pcd.cpp | 349 ++++ src/lib_nfctype3pcd.h | 75 + src/lib_nfctype4pcd.cpp | 348 ++++ src/lib_nfctype4pcd.h | 64 + src/lib_nfctype5pcd.cpp | 234 +++ src/lib_nfctype5pcd.h | 59 + src/lib_pcd.cpp | 769 ++++++++ src/lib_pcd.h | 269 +++ src/lib_wrapper.h | 52 + src/miscellaneous.h | 76 + 56 files changed, 14201 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 examples/X_NUCLEO_NFC03A1_HelloWorld/X_NUCLEO_NFC03A1_HelloWorld.ino create mode 100644 library.properties create mode 100644 src/common.h create mode 100644 src/drv_95HF.h create mode 100644 src/drv_95hf.cpp create mode 100644 src/drv_spi.cpp create mode 100644 src/drv_spi.h create mode 100644 src/lib_95HF.h create mode 100644 src/lib_95HFConfigManager.cpp create mode 100644 src/lib_95HFConfigManager.h create mode 100644 src/lib_95HF_wrapper.cpp create mode 100644 src/lib_NDEF.cpp create mode 100644 src/lib_NDEF.h create mode 100644 src/lib_NDEF_AAR.cpp create mode 100644 src/lib_NDEF_AAR.h create mode 100644 src/lib_NDEF_Email.cpp create mode 100644 src/lib_NDEF_Email.h create mode 100644 src/lib_NDEF_Geo.cpp create mode 100644 src/lib_NDEF_Geo.h create mode 100644 src/lib_NDEF_MyApp.cpp create mode 100644 src/lib_NDEF_MyApp.h create mode 100644 src/lib_NDEF_SMS.cpp create mode 100644 src/lib_NDEF_SMS.h create mode 100644 src/lib_NDEF_Text.cpp create mode 100644 src/lib_NDEF_Text.h create mode 100644 src/lib_NDEF_URI.cpp create mode 100644 src/lib_NDEF_URI.h create mode 100644 src/lib_NDEF_Vcard.cpp create mode 100644 src/lib_NDEF_Vcard.h create mode 100644 src/lib_iso14443A.h create mode 100644 src/lib_iso14443Apcd.cpp create mode 100644 src/lib_iso14443Apcd.h create mode 100644 src/lib_iso14443Bpcd.cpp create mode 100644 src/lib_iso14443Bpcd.h create mode 100644 src/lib_iso15693pcd.cpp create mode 100644 src/lib_iso15693pcd.h create mode 100644 src/lib_iso18092pcd.cpp create mode 100644 src/lib_iso18092pcd.h create mode 100644 src/lib_iso7816pcd.cpp create mode 100644 src/lib_iso7816pcd.h create mode 100644 src/lib_nfctype1pcd.cpp create mode 100644 src/lib_nfctype1pcd.h create mode 100644 src/lib_nfctype2pcd.cpp create mode 100644 src/lib_nfctype2pcd.h create mode 100644 src/lib_nfctype3pcd.cpp create mode 100644 src/lib_nfctype3pcd.h create mode 100644 src/lib_nfctype4pcd.cpp create mode 100644 src/lib_nfctype4pcd.h create mode 100644 src/lib_nfctype5pcd.cpp create mode 100644 src/lib_nfctype5pcd.h create mode 100644 src/lib_pcd.cpp create mode 100644 src/lib_pcd.h create mode 100644 src/lib_wrapper.h create mode 100644 src/miscellaneous.h diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..bdd97ae --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,23 @@ +COPYRIGHT(c) 2017 STMicroelectronics + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of STMicroelectronics nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3c7ef1 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# X-NUCLEO-NFC03A1 + +The code has been designed for ST X-NUCLEO-NFC03A1 expansion board to show how to detect, read and write NFC tags. +The X-NUCLEO-NFC03A1 is an NFC card reader evaluation board based on CR95HF-VMD5T to enable expansion of the STM32 Nucleo boards. +The CR95HF manages frame coding and decoding in Reader mode for standard applications, such as NFC, proximity and vicinity standards. +The CR95HF embeds an analog front end to provide the 13.56 MHz air interface. The CR95HF supports ISO/IEC 14443 Type A and B, ISO/IEC 15693 +(single or double subcarrier) and ISO/IEC 18092 communication protocols, besides being MIFARE® Classic compatible. +It also supports the detection, reading and writing of NFC Forum Type 1, 2, 3 and 4 tags. + +## Examples + +There is one example with the X-NUCLEO-NFC03A1 library: +* X_NUCLEO_NFC03A1_HelloWorld: This application is to show how to detect, read and write NFC Forum Type 1, 2, 3 and 4 tags. + +## Documentation + +You can find the source files at +https://github.com/stm32duino/X-NUCLEO-NFC03A1 + +The CR95HF datasheet is available at +http://www.st.com/content/st_com/en/products/nfc/st25-nfc-rfid-tags-readers/st25-nfc-rfid-readers/cr95hf.html + diff --git a/examples/X_NUCLEO_NFC03A1_HelloWorld/X_NUCLEO_NFC03A1_HelloWorld.ino b/examples/X_NUCLEO_NFC03A1_HelloWorld/X_NUCLEO_NFC03A1_HelloWorld.ino new file mode 100644 index 0000000..907e823 --- /dev/null +++ b/examples/X_NUCLEO_NFC03A1_HelloWorld/X_NUCLEO_NFC03A1_HelloWorld.ino @@ -0,0 +1,329 @@ +/** + ****************************************************************************** + * @file X_NUCLEO_NFC03A1_HelloWorld.ino + * @author AST + * @version V1.0.0 + * @date 6 December 2017 + * @brief Arduino test application for the STMicrolectronics X-NUCLEO-NFC03A1 + * NFC reader/writer expansion board. + * This application makes use of C++ classes obtained from the C + * components' drivers. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "stdint.h" +#include "stdbool.h" +#include "string.h" +#include "lib_NDEF_URI.h" +#include "lib_NDEF_SMS.h" +#include "lib_NDEF_Text.h" +#include "lib_NDEF_Email.h" +#include "lib_NDEF_Geo.h" +#include "lib_95HFConfigManager.h" +#include "miscellaneous.h" +#include "lib_95HFConfigManager.h" +#include "lib_wrapper.h" +#include "lib_NDEF_URI.h" +#include "drv_spi.h" + +#define SerialPort Serial + +/* Exported define -----------------------------------------------------------*/ +#define BULK_MAX_PACKET_SIZE 0x00000040 + +/* Regarding board antenna (and matching) appropriate +value may be modified to optimized RF performances */ +/* Analogue configuration register + ARConfigB bits 7:4 MOD_INDEX Modulation index to modulator + 3:0 RX_AMP_GAIN Defines receiver amplifier gain +For type A you can also adjust the Timer Window +*/ + +/****************** PICC ******************/ +/* ISO14443A */ +#define PICC_TYPEA_ACConfigA 0x27 /* backscaterring */ + +/* ISO14443B */ +#define PICC_TYPEB_ARConfigD 0x0E /* card demodulation gain */ +#define PICC_TYPEB_ACConfigA 0x17 /* backscaterring */ + +/* Felica */ +#define PICC_TYPEF_ACConfigA 0x17 /* backscaterring */ + +/* Private variables ---------------------------------------------------------*/ + +/* TT1 (PCD only)*/ +uint8_t TT1Tag[NFCT1_MAX_TAGMEMORY]; + +/* TT2 */ +uint8_t TT2Tag[NFCT2_MAX_TAGMEMORY]; + +/* TT3 */ +uint8_t TT3Tag[NFCT3_MAX_TAGMEMORY]; +uint8_t *TT3AttribInfo = TT3Tag, *TT3NDEFfile = &TT3Tag[NFCT3_ATTRIB_INFO_SIZE]; + +/* TT4 */ +uint8_t CardCCfile [NFCT4_MAX_CCMEMORY]; +uint8_t CardNDEFfileT4A [NFCT4_MAX_NDEFMEMORY]; +uint8_t CardNDEFfileT4B [NFCT4_MAX_NDEFMEMORY]; + +/* TT5 (PCD only)*/ +uint8_t TT5Tag[NFCT5_MAX_TAGMEMORY]; + +sURI_Info url; +extern uint8_t NDEF_Buffer []; +extern DeviceMode_t devicemode; + +sRecordInfo_uri RecordStruct; + +int8_t TagType = TRACK_NOTHING; +bool TagDetected = false; +bool terminal_msg_flag = false ; +uint8_t status = ERRORCODE_GENERIC; +static char dataOut[256]; + +#define X_NUCLEO_NFC03A1_LED1 D7 +#define X_NUCLEO_NFC03A1_LED2 D6 +#define X_NUCLEO_NFC03A1_LED3 D5 +#define X_NUCLEO_NFC03A1_LED4 D4 + +void setup() { + // 95HF HW Init + ConfigManager_HWInit(); + + // LED1 + pinMode(X_NUCLEO_NFC03A1_LED1, OUTPUT); + + // LED2 + pinMode(X_NUCLEO_NFC03A1_LED2, OUTPUT); + + // LED3 + pinMode(X_NUCLEO_NFC03A1_LED3, OUTPUT); + + // LED4 + pinMode(X_NUCLEO_NFC03A1_LED4, OUTPUT); + + // Configure USB serial interface + SerialPort.begin(115200); + + SerialPort.print("\r\n\r\n---------------------------------------\r\n******Welcome to x-nucleo-nfc03a1 demo******\r\n----------------------------------------"); + SerialPort.print("\r\n\r\nPlease bring an NFC tag to the board vicinity and Press User Button B1 on the board to start URI Writer/Reader demo on the tag"); + + terminal_msg_flag = true; + + digitalWrite(X_NUCLEO_NFC03A1_LED1, HIGH); +} + + +/* Loop ----------------------------------------------------------------------*/ + +void loop() +{ + devicemode = PCD; + + /* Scan to find if there is a tag */ + TagType = ConfigManager_TagHunting(TRACK_ALL); + + switch(TagType) + { + case TRACK_NFCTYPE1: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE1 NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + + } + break; + case TRACK_NFCTYPE2: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE2 NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + } + break; + + case TRACK_NFCTYPE3: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE3 NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + } + break; + + case TRACK_NFCTYPE4A: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE4A NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + } + break; + + case TRACK_NFCTYPE4B: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE4B NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + } + break; + + case TRACK_NFCTYPE5: + { + TagDetected = true; + + if(terminal_msg_flag == true ) + { + terminal_msg_flag = false ; + + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nTRACK_NFCTYPE5 NFC tag detected nearby"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, HIGH); + } + } + break; + + default: + { + TagDetected = false; + + if(terminal_msg_flag == false) + { + terminal_msg_flag = true ; + /*---HT UI msg----------*/ + SerialPort.print( "\r\n\r\nCurrently there is no NFC tag in the vicinity"); + digitalWrite(X_NUCLEO_NFC03A1_LED2, LOW); + digitalWrite(X_NUCLEO_NFC03A1_LED3, LOW); + digitalWrite(X_NUCLEO_NFC03A1_LED4, LOW); + } + } + break; + } + + delay(300); + + if (TagDetected == true) + { + TagDetected = false; + + /* Fill the structure of the NDEF URI */ + strcpy(url.Information,"ST website for near field communication"); + strcpy(url.protocol,"http://"); + strcpy(url.URI_Message,"st.com/st25"); + + status = NDEF_WriteURI(&url); + + delay(500); + + if(status == RESULTOK) /*---if URI write passed----------*/ + { + status = ERRORCODE_GENERIC; + + snprintf( dataOut, 256, "\r\n\r\n--------------------\r\n*****URI Writer*****\r\n--------------------\r\nURI Information written successfully on the tag: \r\n URI Information: [%s], \r\n URI Protocol: [%s] , \r\n URI Message: [%s]", (char *)url.Information, (char *)url.protocol, (char *)url.URI_Message ); + SerialPort.print( dataOut ); + + digitalWrite(X_NUCLEO_NFC03A1_LED3, HIGH); + + memset(url.Information,'\0',400); /*Clear url buffer before reading*/ + + if (TagType == TRACK_NFCTYPE1) + { + status = PCDNFCT1_ReadNDEF(); + } else if (TagType == TRACK_NFCTYPE2) + { + status = PCDNFCT2_ReadNDEF(); + } else if (TagType == TRACK_NFCTYPE3) + { + status = PCDNFCT3_ReadNDEF(); + } else if (TagType == TRACK_NFCTYPE4A || TagType == TRACK_NFCTYPE4B) + { + status = PCDNFCT4_ReadNDEF(); + } else if (TagType == TRACK_NFCTYPE5) + { + status = PCDNFCT5_ReadNDEF(); + } + + if ( status == RESULTOK ) + { + status = ERRORCODE_GENERIC; + + memset(NDEF_Buffer,'\0',20); /* Avoid printing useless characters */ + status = NDEF_IdentifyNDEF( &RecordStruct, NDEF_Buffer); + + if(status == RESULTOK && RecordStruct.TypeLength != 0) + { + if (NDEF_ReadURI(&RecordStruct, &url)==RESULTOK) /*---if URI read passed---*/ + { + snprintf( dataOut, 256, "\r\n\r\n--------------------\r\n*****URI Reader*****\r\n--------------------\r\nURI Information read successfully from the tag: \r\n URI Information: [%s], \r\n URI Protocol: [%s] , \r\n URI Message: [%s]", (char *)url.Information, (char *)url.protocol, (char *)url.URI_Message ); + + SerialPort.print( dataOut ); + + digitalWrite(X_NUCLEO_NFC03A1_LED4, HIGH); + } + } + } + } + } +} + diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..a812d7d --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=STM32duino X-NUCLEO-NFC03A1 +version=1.0.2 +author=STMicroelectronics +maintainer=stm32duino +sentence=Allows controlling the ST X-NUCLEO-NFC03A1 expansion board +paragraph=This library provides the drivers and a sample application to control ST X-NUCLEO-NFC03A1 expansion board +category=Communication +url=https://github.com/stm32duino/x-nucleo-nfc03a1 +architectures=stm32 diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..eb4ee41 --- /dev/null +++ b/src/common.h @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * @file common.h + * @author MMY Application Team + * @version $Revision: 1507 $ + * @date $Date: 2016-01-08 09:48:35 +0100 (Fri, 08 Jan 2016) $ + * @brief This file provides all the headers of the common functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2016 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _COMMON_H +#define _COMMON_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#define NFC_TAG_MEMORY 512 + +#include "miscellaneous.h" +#include "lib_95HFConfigManager.h" +#include "lib_wrapper.h" +#include "lib_NDEF_URI.h" +#include "drv_spi.h" + + +#define MAX_NDEF_MEM 0x50 + +/* Nfc Mandatory define ------------------------------------------------------*/ + +#define RESULTOK 0x00 +#define ERRORCODE_GENERIC 1 +#define ACTION_COMPLETED 0x9000 + +/* status and erroc code --------------------------------------------------- */ +#define MAIN_SUCCESS_CODE RESULTOK + +/* Enum for ST95 state aligned with new lib Ndef*/ +typedef enum {UNDEFINED_MODE=0,PICC,PCD}DeviceMode_t; +typedef enum {UNDEFINED_TAG_TYPE=0,TT1,TT2,TT3,TT4A,TT4B,TT5}TagType_t; + +/* external constants --------------------------------------------------------*/ +extern bool HID_TRANSACTION; + +/* Exported types ------------------------------------------------------------*/ +typedef void (*pFunction)(void); + +/* Exported constants --------------------------------------------------------*/ +/* Constants used by Serial Command Line Mode */ +#define CMD_STRING_SIZE 128 + +#define ApplicationAddress 0x8009000 + +#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */ +#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */ + +/* Compute the FLASH upload image size */ +#define FLASH_IMAGE_SIZE (uint32_t) (FLASH_SIZE - (ApplicationAddress - 0x08000000)) + +/* TT1 */ +#define NFCT1_MAX_TAGMEMORY (120+2) + +/* TT2 */ +#define NFCT2_MAX_TAGMEMORY NFC_TAG_MEMORY /*(must be a multiple of 8) */ +#define NFCT2_MAX_CC_SIZE 4 +#define NFCT2_MAX_CONFIG 12 +#define NFCT2_MAX_NDEFFILE (NFCT2_MAX_TAGMEMORY-NFCT2_MAX_CC_SIZE-NFCT2_MAX_CONFIG) + +/* TT3 */ +#define NFCT3_ATTRIB_INFO_SIZE 16 +#define NFCT3_MAX_NDEFFILE NFC_TAG_MEMORY +#define NFCT3_MAX_TAGMEMORY (NFCT3_MAX_NDEFFILE+NFCT3_ATTRIB_INFO_SIZE) +#define NFCT3_NB_BLOC_MSB ((NFCT3_MAX_TAGMEMORY/16)>>8) +#define NFCT3_NB_BLOC_LSB ((NFCT3_MAX_TAGMEMORY/16)&0x00FF) + +/* TT4 */ +#define NFCT4_MAX_CCMEMORY 16 +#define NFCT4A_MAX_NDEFMEMORY NFC_TAG_MEMORY +#define NFCT4B_MAX_NDEFMEMORY NFC_TAG_MEMORY +#define NFCT4_MAX_NDEFMEMORY NFCT4A_MAX_NDEFMEMORY + +/* TT5 */ +#define NFCT5_MAX_TAGMEMORY NFC_TAG_MEMORY + +#define NFC_DEVICE_MAX_NDEFMEMORY NFCT4_MAX_NDEFMEMORY +/* Exported macro ------------------------------------------------------------*/ +/* Common routines */ +/* Exported functions ------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif /* _COMMON_H */ + +/*******************(C)COPYRIGHT 2016 STMicroelectronics *****END OF FILE******/ diff --git a/src/drv_95HF.h b/src/drv_95HF.h new file mode 100644 index 0000000..93a455e --- /dev/null +++ b/src/drv_95HF.h @@ -0,0 +1,248 @@ +/** + ****************************************************************************** + * @file drv_95HF.h + * @author MMY Application Team + * @version $Revision: 1347 $ + * @date $Date: 2015-11-05 11:36:05 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of firmware functions to manage communication + * @brief between MCU and 95HF device (CR95HF) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2016 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion ------------------------------------------------ */ +#ifndef __DRV_95HF_H +#define __DRV_95HF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ----------------------------------------------------------------------------- */ +#include "drv_spi.h" +//#include "drv_uart.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup XX95HF + * @{ + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup XX95HF_Exported_Constants + * @{ + */ +/* RFtransceiver HEADER command definition ---------------------------------------------- */ +#define RFTRANS_95HF_COMMAND_SEND 0x00 +#define RFTRANS_95HF_COMMAND_RESET 0x01 +#define RFTRANS_95HF_COMMAND_RECEIVE 0x02 +#define RFTRANS_95HF_COMMAND_POLLING 0x03 +#define RFTRANS_95HF_COMMAND_IDLE 0x07 + +/* RFtransceiver mask and data to check the data (SPI polling)--------------------------- */ +#define RFTRANS_95HF_FLAG_DATA_READY 0x08 +#define RFTRANS_95HF_FLAG_DATA_READY_MASK 0x08 + +/* RF transceiver status --------------------------------------------------------------- */ +#define RFTRANS_95HF_SUCCESS_CODE RESULTOK +#define RFTRANS_95HF_NOREPLY_CODE 0x01 +#define RFTRANS_95HF_ERRORCODE_DEFAULT 0xFE +#define RFTRANS_95HF_ERRORCODE_TIMEOUT 0xFD +#define RFTRANS_95HF_ERRORCODE_POR 0x44 + +/* RF transceiver polling status ------------------------------------------------------- */ +#define RFTRANS_95HF_POLLING_RFTRANS_95HF 0x00 +#define RFTRANS_95HF_POLLING_TIMEOUT 0x01 + +/* RF transceiver number of byte of the buffers------------------------------------------ */ +#define RFTRANS_95HF_RESPONSEBUFFER_SIZE 0xFF +#define RFTRANS_95HF_MAX_BUFFER_SIZE 0xFF +/* Max of 256 (for QJC) and 768 (for QJE. Should be 512 but bug Design) */ +#define RFTRANS_95HF_MAX_ECHO 768 + +/* RF transceiver Offset of the command and the response -------------------------------- */ +#define RFTRANS_95HF_COMMAND_OFFSET 0x00 +#define RFTRANS_95HF_LENGTH_OFFSET 0x01 +#define RFTRANS_95HF_DATA_OFFSET 0x02 + +/* ECHO response ------------------------------------------------------------------------ */ +#define ECHORESPONSE 0x55 + +/* Sleep parameters --------------------------------------------------------------------- */ +#define IDLE_SLEEP_MODE 0x00 +#define IDLE_HIBERNATE_MODE 0x01 + +#define IDLE_CMD_LENTH 0x0E + +#define WU_TIMEOUT 0x01 +#define WU_TAG 0x02 +#define WU_FIELD 0x04 +#define WU_IRQ 0x08 +#define WU_SPI 0x10 + +#define HIBERNATE_ENTER_CTRL 0x0400 +#define SLEEP_ENTER_CTRL 0x0100 +#define SLEEP_FIELD_ENTER_CTRL 0x0142 + +#define HIBERNATE_WU_CTRL 0x0400 +#define SLEEP_WU_CTRL 0x3800 + +#define LEAVE_CTRL 0x1800 + +/* Calibration parameters---------------------------------------------------------------- */ +#define WU_SOURCE_OFFSET 0x02 +#define WU_PERIOD_OFFSET 0x09 +#define DACDATAL_OFFSET 0x0C +#define DACDATAH_OFFSET 0x0D +#define NBTRIALS_OFFSET 0x0F + + + +#define MAX_BUFFER_SIZE 256 + + #define ECHO 0x55 +#define LISTEN 0x05 +#define DUMMY_BYTE 0xFF + +/* set state on IRQ in pin */ +//#define RFTRANS_95HF_GET_INTERFACE() HAL_GPIO_ReadPin(INTERFACE_GPIO_PORT,INTERFACE_PIN) + +#define READERREPLY_MAX_BUFFER_SIZE 0x40 +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup XX95HF_Exported_Types + * @{ + */ +typedef enum { + RFTRANS_95HF_INTERFACE_UART = 0, + RFTRANS_95HF_INTERFACE_SPI, + RFTRANS_95HF_INTERFACE_TWI +}RFTRANS_95HF_INTERFACE; + + +/** + * @brief the different states of the RF transceiver + */ +typedef enum { + RFTRANS_95HF_STATE_UNKNOWN = 0, + RFTRANS_95HF_STATE_HIBERNATE , + RFTRANS_95HF_STATE_SLEEP, + RFTRANS_95HF_STATE_POWERUP, + RFTRANS_95HF_STATE_TAGDETECTOR, + RFTRANS_95HF_STATE_READY, + RFTRANS_95HF_STATE_READER, + RFTRANS_95HF_STATE_TAGHUNTING, +}RFTRANS_95HF_STATE; + +/** + * @brief the RF transceiver can be configured as either a reader or a card emulator + * @brief or as P2P device + */ +typedef enum { + RFTRANS_95HF_MODE_UNKNOWN = 0, + RFTRANS_95HF_MODE_READER , + RFTRANS_95HF_MODE_CARDEMULATOR , + RFTRANS_95HF_MODE_PASSIVEP2P , + RFTRANS_95HF_MODE_ACTIVEP2P , +}RFTRANS_95HF_MODE; + +/** + * @brief the Rf transceiver supports the differrent protocols + */ +typedef enum { + RFTRANS_95HF_PROTOCOL_UNKNOWN = 0, + RFTRANS_95HF_PCD_14443A, + RFTRANS_95HF_PCD_14443B, + RFTRANS_95HF_PCD_15693, + RFTRANS_95HF_PCD_18092, + RFTRANS_95HF_PICC_14443A, + RFTRANS_95HF_PICC_14443B, + RFTRANS_95HF_PICC_15693, + RFTRANS_95HF_PICC_18092, +}RFTRANS_95HF_PROTOCOL; + + +/** + * @brief structure to store driver information + */ +typedef struct { + RFTRANS_95HF_INTERFACE uInterface; + RFTRANS_95HF_STATE uState; + RFTRANS_95HF_MODE uMode; + RFTRANS_95HF_PROTOCOL uCurrentProtocol; +}drv95HF_ConfigStruct; +/** + * @} + */ + +/* External variables --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/** @defgroup XX95HF_Exported_Functions + * @{ + */ +void drv95HF_ResetSPI(void); +//int8_t drv95HF_GetInterfacePinState(void); +uint8_t drv95HF_GetSerialInterface(void); +//int8_t drv95HF_GetIRQOutState(void); +void drv95HF_InitConfigStructure(void); +void drv95HF_InitilizeSerialInterface(void); +void drv95HF_ReceiveSPIResponse(uint8_t *pData); +void drv95HF_SendSPICommand(const uint8_t *pData ); +int8_t drv95HF_SendReceive(const uint8_t *pCommand, uint8_t *pResponse); +void drv95HF_SendCmd(const uint8_t *pCommand); +int8_t drv95HF_PoolingReading(uint8_t *pResponse); + +void drv95HF_Idle(const uint8_t WU_source, const uint8_t mode); +void drv95HF_SendIRQINPulse(void); + +/** + * @} + */ + +/** + * @} + */ + + /** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __DRV_95HF_H */ + +/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/ diff --git a/src/drv_95hf.cpp b/src/drv_95hf.cpp new file mode 100644 index 0000000..99ec4b0 --- /dev/null +++ b/src/drv_95hf.cpp @@ -0,0 +1,515 @@ +/** + ****************************************************************************** + * @file drv_95HF.c + * @author MMY Application Team + * @version $Revision: 1348 $ + * @date $Date: 2015-11-05 11:36:33 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of driver functions to manage communication + * between MCU and xx95HF chip (CR95HF) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2016 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "SPI.h" +#include "stdbool.h" +#include "drv_95HF.h" +#include "lib_pcd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + + +/** @addtogroup XX95HF + * @{ + */ + +/* External variables --------------------------------------------------------*/ +/* Private typedef -----------------------------------------------------------*/ +/* Private defines -----------------------------------------------------------*/ +/* Private macros ------------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +static void drv95HF_InitializeSPI(void); +static void drv95HF_SendSPIResetByte(void); +static int8_t drv95HF_SPIPollingCommand(void); +/* Global variables ---------------------------------------------------------*/ +/** @defgroup XX95HF_Global variables + * @{ + */ +/** +* @brief buffer to exchange data with the RF tranceiver. +*/ +uint8_t u95HFBuffer [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; + +/** + * @brief This uTimeOut variable is used as a timeout duting the communication with the RF tranceiver + */ + +extern volatile bool uDataReady; +bool EnableTimeOut = true; + +/* ConfigStructure */ +drv95HF_ConfigStruct drv95HFConfig; +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup XX95HF_Private_Functions + * @{ + */ + +/** + * @brief this functions initializes the SPI in order to communicate with the 95HF device + * @param None + * @retval void + */ +static void drv95HF_InitializeSPI(void) +{ + RFTRANS_SPI_Init(); +} + +/** + * @brief This function sends a reset command over SPI bus + * @param None + * @retval None + */ +static void drv95HF_SendSPIResetByte(void) +{ + /* Send reset control byte */ + SPI_SendReceiveByte(RFTRANS_95HF_COMMAND_RESET); +} + +/** + * @brief This function polls 95HF chip until a response is ready or + * the counter of the timeout overflows + * @param None + * @retval PCD_POLLING_TIMEOUT : The time out was reached + * @retval PCD_SUCCESS_CODE : A response is available + */ +static int8_t drv95HF_SPIPollingCommand( void ) +{ + uint8_t Polling_Status = 0; + int timestamp_start = -1; + int timestamp_final = -1; + bool uTimeOut = false; + + if(EnableTimeOut) + { + timestamp_start = millis(); + } + + DEV_SPI.beginTransaction(SPISettings(1500000, MSBFIRST, SPI_MODE3)); + + do + { + /* Low level on NSS */ + RFTRANS_95HF_NSS_LOW(); + delay(2); + + /* poll the 95HF transceiver until he's ready ! */ + Polling_Status = SPI_SendReceiveByte(RFTRANS_95HF_COMMAND_POLLING); + Polling_Status &= RFTRANS_95HF_FLAG_DATA_READY_MASK; + if(EnableTimeOut) + { + /* 3sec for LLCP can be improved to adjust it dynamically */ + timestamp_final = millis(); + if((timestamp_final - timestamp_start) > 3000) + { + uTimeOut = true; + } + } + } + while( Polling_Status != RFTRANS_95HF_FLAG_DATA_READY && uTimeOut != true ); + + /* High level on NSS */ + RFTRANS_95HF_NSS_HIGH(); + + DEV_SPI.endTransaction(); + + if ( uTimeOut == true ) + { + return RFTRANS_95HF_POLLING_TIMEOUT; + } + + return RFTRANS_95HF_SUCCESS_CODE; +} + + +/** + * @} + */ + +/** @defgroup drv_95HF_Public_Functions + * @{ + */ + + +/** +* @brief Initilize the 95HF device config structure +* @param None +* @retval None +*/ +void drv95HF_InitConfigStructure (void) +{ + drv95HFConfig.uInterface = RFTRANS_95HF_INTERFACE_SPI; + drv95HFConfig.uState = RFTRANS_95HF_STATE_POWERUP; + drv95HFConfig.uCurrentProtocol = RFTRANS_95HF_PROTOCOL_UNKNOWN; + drv95HFConfig.uMode = RFTRANS_95HF_MODE_UNKNOWN; +} + +/** + * @brief Send a reset sequence over SPI bus (Reset command ,wait ,negative pulse on IRQin). + * @param None + * @retval None + */ +void drv95HF_ResetSPI(void) +{ + /* Deselect Rftransceiver over SPI */ + RFTRANS_95HF_NSS_HIGH(); + delay(1); + + DEV_SPI.beginTransaction(SPISettings(1500000, MSBFIRST, SPI_MODE3)); + /* Select 95HF device over SPI */ + RFTRANS_95HF_NSS_LOW(); + /* Send reset control byte */ + drv95HF_SendSPIResetByte(); + /* Deselect 95HF device over SPI */ + RFTRANS_95HF_NSS_HIGH(); + + DEV_SPI.endTransaction(); + + delay(3); + /* send a pulse on IRQ_in*/ + drv95HF_SendIRQINPulse(); + delay(10); /* mandatory before issuing a new command */ + + drv95HFConfig.uState = RFTRANS_95HF_STATE_READY; +} + +/** + * @brief returns the value of interface pin. + * Low level means UART bus was choose. + * High level means SPI bus was choose. + * @param None + * @retval Bit_RESET : 0 + * @retval Bit_SET : 1 + */ +//int8_t drv95HF_GetInterfacePinState(void) +//{ +// return RFTRANS_95HF_GET_INTERFACE(); +//} + +/** + * @brief This function returns the IRQout state + * @param None + * @retval Pin set : 1 + * @retval Pin reset : 0 + */ +//int8_t drv95HF_GetIRQOutState(void) +//{ +// if (HAL_GPIO_ReadPin(IRQOUT_RFTRANS_95HF_PORT, IRQOUT_RFTRANS_95HF_PIN) != GPIO_PIN_RESET) +// { +// return 0x01; +// } +// else +// { +// return 0x00; +// } +//} + +/** + * @brief This function initialize MCU serial interface peripheral (SPI or UART) + * @param None + * @retval None + */ +void drv95HF_InitilizeSerialInterface(void) +{ + /* -- Get interface pin state to select UART or SPI mode -- */ + //if (drv95HF_GetInterfacePinState() != RFTRANS_95HF_INTERFACE_UART) + //{ + /* -- Set communication type -- */ + drv95HFConfig.uInterface = RFTRANS_95HF_INTERFACE_SPI; + /* -- Initialize SPI Interface -- */ + drv95HF_InitializeSPI( ); + //} +} + + +/** + * @brief This function returns the Interface selected(UART or SPI) + * @param None + * @retval RFTRANS_INTERFACE_UART : the UART interface is selected + * @retval RFTRANS_INTERFACE_SPI : the SPI interface is selected + */ +uint8_t drv95HF_GetSerialInterface(void) +{ + return drv95HFConfig.uInterface; +} + +/** + * @brief This function sends a command over SPI bus + * @param *pData : pointer on data to send to the xx95HF + * @retval None + */ +void drv95HF_SendSPICommand(const uint8_t *pData) +{ + uint8_t DummyBuffer[MAX_BUFFER_SIZE]; + + DEV_SPI.beginTransaction(SPISettings(1500000, MSBFIRST, SPI_MODE3)); + + /* Select xx95HF over SPI */ + RFTRANS_95HF_NSS_LOW(); + + /* Send a sending request to xx95HF */ + SPI_SendReceiveByte(RFTRANS_95HF_COMMAND_SEND); + + if(*pData == ECHO) + { + /* Send a sending request to xx95HF */ + SPI_SendReceiveByte(ECHO); + } + else + { + /* Transmit the buffer over SPI */ + SPI_SendReceiveBuffer(pData, pData[RFTRANS_95HF_LENGTH_OFFSET]+RFTRANS_95HF_DATA_OFFSET, DummyBuffer); + } + + /* Deselect xx95HF over SPI */ + RFTRANS_95HF_NSS_HIGH(); + + DEV_SPI.endTransaction(); +} + + + +/** + * @brief This fucntion recovers a response from 95HF device + * @param *pData : pointer on data received from 95HF device + * @retval None + */ +void drv95HF_ReceiveSPIResponse(uint8_t *pData) +{ + uint8_t DummyBuffer[MAX_BUFFER_SIZE]; + + DEV_SPI.beginTransaction(SPISettings(1500000, MSBFIRST, SPI_MODE3)); + + /* Select 95HF transceiver over SPI */ + RFTRANS_95HF_NSS_LOW(); + + /* Request a response from 95HF transceiver */ + SPI_SendReceiveByte(RFTRANS_95HF_COMMAND_RECEIVE); + + /* Recover the "Command" byte */ + pData[RFTRANS_95HF_COMMAND_OFFSET] = SPI_SendReceiveByte(DUMMY_BYTE); + + if(pData[RFTRANS_95HF_COMMAND_OFFSET] == ECHO) + { + pData[RFTRANS_95HF_LENGTH_OFFSET] = 0x00; + /* In case we were in listen mode error code cancelled by user (0x85 0x00) must be retrieved */ + pData[RFTRANS_95HF_LENGTH_OFFSET+1] = SPI_SendReceiveByte(DUMMY_BYTE); + pData[RFTRANS_95HF_LENGTH_OFFSET+2] = SPI_SendReceiveByte(DUMMY_BYTE); + } + else if(pData[RFTRANS_95HF_COMMAND_OFFSET] == 0xFF) + { + pData[RFTRANS_95HF_LENGTH_OFFSET] = 0x00; + pData[RFTRANS_95HF_LENGTH_OFFSET+1] = SPI_SendReceiveByte(DUMMY_BYTE); + pData[RFTRANS_95HF_LENGTH_OFFSET+2] = SPI_SendReceiveByte(DUMMY_BYTE); + } + else + { + /* Recover the "Length" byte */ + pData[RFTRANS_95HF_LENGTH_OFFSET] = SPI_SendReceiveByte(DUMMY_BYTE); + /* Checks the data length */ + if(pData[RFTRANS_95HF_LENGTH_OFFSET] != 0x00) + SPI_SendReceiveBuffer(DummyBuffer, pData[RFTRANS_95HF_LENGTH_OFFSET], &pData[RFTRANS_95HF_DATA_OFFSET]); + } + + /* Deselect xx95HF over SPI */ + RFTRANS_95HF_NSS_HIGH(); + + DEV_SPI.endTransaction(); +} + +/** + * @brief This function send a command to 95HF device over SPI or UART bus and receive its response + * @param *pCommand : pointer on the buffer to send to the 95HF device ( Command | Length | Data) + * @param *pResponse : pointer on the 95HF device response ( Command | Length | Data) + * @retval RFTRANS_95HF_SUCCESS_CODE : the function is succesful + */ +int8_t drv95HF_SendReceive(const uint8_t *pCommand, uint8_t *pResponse) +{ + + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + { + /* First step - Sending command */ + drv95HF_SendSPICommand(pCommand); + /* Second step - Polling */ + if (drv95HF_SPIPollingCommand( ) != RFTRANS_95HF_SUCCESS_CODE) + { + *pResponse = RFTRANS_95HF_ERRORCODE_TIMEOUT; + return RFTRANS_95HF_POLLING_TIMEOUT; + } + /* Third step - Receiving bytes */ + drv95HF_ReceiveSPIResponse(pResponse); + } + + return RFTRANS_95HF_SUCCESS_CODE; +} + +/** + * @brief This function send a command to 95HF device over SPI or UART bus + * @param *pCommand : pointer on the buffer to send to the 95HF ( Command | Length | Data) + * @retval None + */ +void drv95HF_SendCmd(const uint8_t *pCommand) +{ + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + /* First step - Sending command */ + drv95HF_SendSPICommand(pCommand); + +// else if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_UART) + /* First step - Sending command */ +// drv95HF_SendUARTCommand(pCommand); +} + +/** + * @brief This function is a specific command. It's made polling and reading sequence. + * @param *pResponse : pointer on the 95HF device response ( Command | Length | Data) + * @retval RFTRANS_95HF_SUCCESS_CODE : the function is succesful + * @retval RFTRANS_95HF_POLLING_RFTRANS_95HF : the polling sequence returns an error + */ +int8_t drv95HF_PoolingReading (uint8_t *pResponse) +{ + *pResponse =RFTRANS_95HF_ERRORCODE_DEFAULT; + *(pResponse+1) = 0x00; + + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + { + /* First step - Polling */ + if (drv95HF_SPIPollingCommand( ) != RFTRANS_95HF_SUCCESS_CODE) + { *pResponse = RFTRANS_95HF_ERRORCODE_TIMEOUT; + return RFTRANS_95HF_ERRORCODE_TIMEOUT; + } + /* Second step - Receiving bytes */ + drv95HF_ReceiveSPIResponse(pResponse); + } + + return RFTRANS_95HF_SUCCESS_CODE; +} + +/** + * @brief Send a negative pulse on IRQin pin + * @param None + * @retval None + */ +void drv95HF_SendIRQINPulse(void) +{ + if (drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + { + /* Send a pulse on IRQ_IN */ + RFTRANS_95HF_IRQIN_HIGH() ; + delay(1); + RFTRANS_95HF_IRQIN_LOW() ; + delay(1); + RFTRANS_95HF_IRQIN_HIGH() ; + } + + /* Need to wait 10ms after the pulse before to send the first command */ + delay(10); +} + +/** + * @brief this functions put the ST95HF in sleep/hibernate mode + * @param WU_source : Source selected to wake up the device (WU_TIMEOUT,WU_TAG,WU_FIELD,WU_IRQ,WU_SPI) + * @param mode : Can be IDLE_SLEEP_MODE or IDLE_HIBERNATE_MODE + * @retval None + */ +void drv95HF_Idle(const uint8_t WU_source, const uint8_t mode) +{ + uint8_t pCommand[] = {RFTRANS_95HF_COMMAND_IDLE, IDLE_CMD_LENTH, 0, 0, 0, 0, 0 ,0x18 ,0x00 ,0x00 ,0x60 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00}; + + if (mode == IDLE_SLEEP_MODE) /* SLEEP */ + { + /* Select the wake up source*/ + pCommand[2] = WU_source; + /* Select SLEEP mode */ + if (WU_source == WU_FIELD) + { + pCommand[3] = GETMSB(SLEEP_FIELD_ENTER_CTRL); + pCommand[4] = GETLSB(SLEEP_FIELD_ENTER_CTRL); + } + else + { + pCommand[3] = GETMSB(SLEEP_ENTER_CTRL); + pCommand[4] = GETLSB(SLEEP_ENTER_CTRL); + } + pCommand[5] = GETMSB(SLEEP_WU_CTRL); + pCommand[6] = GETLSB(SLEEP_WU_CTRL); + } + else /* HIBERNATE */ + { + /* Select the wake up source, only IRQ is available for HIBERNATE mode*/ + pCommand[2] = WU_IRQ; + /* Select HIBERNATE mode */ + pCommand[3] = GETMSB(HIBERNATE_ENTER_CTRL); + pCommand[4] = GETLSB(HIBERNATE_ENTER_CTRL); + pCommand[5] = GETMSB(HIBERNATE_WU_CTRL); + pCommand[6] = GETLSB(HIBERNATE_WU_CTRL); + pCommand[10] = 0x00; + } + + /* Send the command */ + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + /* First step - Sending command */ + drv95HF_SendSPICommand(pCommand); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/ diff --git a/src/drv_spi.cpp b/src/drv_spi.cpp new file mode 100644 index 0000000..e06d0b0 --- /dev/null +++ b/src/drv_spi.cpp @@ -0,0 +1,123 @@ +/** + ****************************************************************************** + * @file drv_spi.c + * @author MMY Application Team + * @version $Revision: 1508 $ + * @date $Date: 2016-01-08 09:50:04 +0100 (Fri, 08 Jan 2016) $ + * @brief This file provides a set of firmware functions to manages SPI communications + ****************************************************************************** + * @copyright + * + *

© COPYRIGHT 2016 STMicroelectronics

+ * + * Licensed under MMY-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** +*/ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "SPI.h" +#include "drv_spi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup X_NUCLEO_NFC03A1_Spi + * @{ + */ +/* Private typedef -----------------------------------------------------------*/ +/* Private defines -----------------------------------------------------------*/ +/* Private macros ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* External variables --------------------------------------------------------*/ +/* Global variables ----------------------------------------------------------*/ + /* Public Functions ----------------------------------------------------------*/ +/** @defgroup X_NUCLEO_NFC03A1_Spi_Public_Functions + * @{ + */ +/** + * @brief Initialise HAL SPI for NFC03A1 + * @param None + * @retval None + */ +void RFTRANS_SPI_Init(void) +{ + // Configure NSS pin for CR95HF + pinMode(10, OUTPUT); + + // Configure interface pin select for CR95HF + pinMode(9, OUTPUT); + + // Configure interrupt input pin for CR95HF + pinMode(8, OUTPUT); + + // Set the interface pin select high in order to configure the NFC reader to use the SPI interface + digitalWrite(9, HIGH); + + /* SPI_NSS = High Level */ + RFTRANS_95HF_NSS_HIGH(); + + /* Set signal to high */ + RFTRANS_95HF_IRQIN_HIGH(); + + DEV_SPI.begin(); +} + +/** + * @brief Sends one byte over SPI and recovers a response + * @param data : data to send + * @retval data response from SPIx + */ +uint8_t SPI_SendReceiveByte(uint8_t data) +{ + return DEV_SPI.transfer(data); +} + +/** + * @brief reveive a byte array over SPI + * @param pCommand : pointer on the buffer to send + * @param length : length of the buffer to send + * @param pResponse : pointer on the buffer response + * @retval None + */ +void SPI_SendReceiveBuffer(const uint8_t *pCommand, uint8_t length, uint8_t *pResponse) +{ + uint8_t i; + + for(i=0; i
© COPYRIGHT 2016 STMicroelectronics
+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion ------------------------------------ */ +#ifndef __DRV_SPI_H +#define __DRV_SPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @defgroup X_NUCLEO_NFC03A1_Spi + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* External variables --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +#define DEV_SPI SPI +/* set state on SPI_NSS pin */ +#define RFTRANS_95HF_NSS_LOW() digitalWrite(10, 0) +#define RFTRANS_95HF_NSS_HIGH() digitalWrite(10, 1) +/* set state on IRQ_In pin */ +#define RFTRANS_95HF_IRQIN_LOW() digitalWrite(8, 0) +#define RFTRANS_95HF_IRQIN_HIGH() digitalWrite(8, 1) +/* Exported functions ------------------------------------------------------- */ +/** @defgroup X_NUCLEO_NFC03A1_Spi_Exported_Functions + * @{ + */ +void RFTRANS_SPI_Init(void); +void SPI_SendReceiveBuffer(const uint8_t *pCommand, uint8_t length, uint8_t *pResponse); +uint8_t SPI_SendReceiveByte(uint8_t data); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __DRV_SPI_H */ + +/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_95HF.h b/src/lib_95HF.h new file mode 100644 index 0000000..60c2626 --- /dev/null +++ b/src/lib_95HF.h @@ -0,0 +1,128 @@ +/** + ****************************************************************************** + * @file lib_95HF.h + * @author MMY Application Team + * @version $Revision: 1327 $ + * @date $Date: 2015-11-05 10:28:31 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of xx95HF device. + * @brief The commands as defined in 95HF's family product datasheet. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_95HF_H +#define _LIB_95HF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "drv_95HF.h" +#include "common.h" + +#include "lib_nfctype1pcd.h" +#include "lib_nfctype2pcd.h" +#include "lib_nfctype3pcd.h" +#include "lib_nfctype4pcd.h" +#include "lib_nfctype5pcd.h" + +/* Analogue configuration register for protocol initialization -------------------------------------------*/ +#define TIMER_WINDOW_REG_ADD 0x3A +#define TIMER_WINDOW_UPDATE_CONFIRM_CMD 0x04 + + +#define AFE_ANALOG_CONF_REG_SELECTION 0x68 +#define AFE_ANALOG_CONF_REG_UPDATE 0x69 + +#define AFE_ACCONFIGA_OFFSET 0x04 + +/* ROM CODE Revision --------------------------------------------------------------*/ +#define ROM_CODE_REVISION_OFFSET 13 + +/* RFtrans 95HF family command definition ---------------------------------------------------------------*/ +#define IDN 0x01 +#define PROTOCOL_SELECT 0x02 +#define POLL_FIELD 0x03 +#define SEND_RECEIVE 0x04 +#define LISTEN 0x05 +#define SEND 0x06 +#define IDLE 0x07 +#define READ_REGISTER 0x08 +#define WRITE_REGISTER 0x09 +#define BAUD_RATE 0x0A +#define SUB_FREQ_RES 0x0B +#define AC_FILTER 0x0D +#define TEST_MODE 0x0E +#define SLEEP_MODE 0x0F +#define ECHO 0x55 + + +/* poll field status ------------------------------------------------------------------ */ +#define POLLFIELD_RESULTSCODE_OK 0x00 + + + +// Send command field status +#define SEND_RESULTSCODE_OK 0x00 +#define SEND_ERRORCODE_LENGTH 0x82 +#define SEND_ERRORCODE_PROTOCOL 0x83 +/* Idle command field status ----------------------------------------------------------------- */ +#define IDLE_RESULTSCODE_OK 0x00 +#define IDLE_ERRORCODE_LENGTH 0x82 +/* read register command field status -------------------------------------------------------- */ +#define READREG_RESULTSCODE_OK 0x00 +#define READREG_ERRORCODE_LENGTH 0x82 +/* write register command field status ------------------------------------------------------- */ +#define WRITEREG_RESULTSCODE_OK 0x00 +/* Baud rate command field status ------------------------------------------------------------ */ +#define BAUDRATE_RESULTSCODE_OK 0x55 +/* AC filter command field status ------------------------------------------------------------ */ +#define ACFILTER_RESULTSCODE_OK 0x00 +#define ACFILTER_ERRORCODE_LENGTH 0x82 +/* sub freq command field status ------------------------------------------------------------- */ +#define SUBFREQ_RESULTSCODE_OK 0x00 +/* Test mode command field status ------------------------------------------------------------ */ +#define TESTMODE_RESULTSCODE_OK 0x00 + +#define ASK_FOR_SESSION 0x0000 +#define TAKE_SESSION 0xFFFF + +#define XX95_ACTION_COMPLETED 0x9000 + + + +typedef enum { + QJA = 0x30, + QJB, + QJC, + QJD, + QJE +}IC_VERSION; + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_95HF_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_95HFConfigManager.cpp b/src/lib_95HFConfigManager.cpp new file mode 100644 index 0000000..bc70960 --- /dev/null +++ b/src/lib_95HFConfigManager.cpp @@ -0,0 +1,324 @@ +/** + ****************************************************************************** + * @file lib_95HFConfigManager.c + * @author MMY Application Team + * @version $Revision: 1328 $ + * @date $Date: 2015-11-05 10:30:08 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of firmware functions to manages device modes. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_95HFConfigManager.h" + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family ( CR95HF )
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup Config_Manager + * @{ + * @brief This part of the library manage the configuration of the chip. + */ +/** + * @brief This buffer contains the data send/received by xx95HF + */ +extern uint8_t u95HFBuffer[RFTRANS_95HF_MAX_BUFFER_SIZE+3]; +extern ISO14443A_CARD ISO14443A_Card; + +/** @addtogroup Configuration_Manager + * @{ + * @brief This file is used to select a configuration, PICC or PCD or Initiator/Target. +*/ + +/** @addtogroup lib_ConfigManager_Private_Functions + * @{ + */ +static void ConfigManager_Init( void); +static int8_t ConfigManager_IDN(uint8_t *pResponse); +static void ConfigManager_Start(void ); +static int8_t ConfigManager_PORsequence( void ); + +/* Variables for the different modes */ +DeviceMode_t devicemode = UNDEFINED_MODE; +TagType_t nfc_tagtype = UNDEFINED_TAG_TYPE; + +/* Variable to know IC version */ +IC_VERSION IcVers = QJE; /* default set last IC version */ + +bool StopProcess = false; +bool TargetMode = true; +uint8_t TagUID[16]; + +/** + * @brief This function initialize the PICC + * @param None + * @retval None + */ +static void ConfigManager_Init( void) +{ + /* initialize the structure of the Rf tranceiver */ + drv95HF_InitConfigStructure (); + + /* configure the Serial interface to communicate with the RF transceiver */ + drv95HF_InitilizeSerialInterface ( ); +} + +/** + * @brief this function sends an IDN command to the PICC device + * @param pResponse : pointer on the PICC device reply + * @retval PICC_SUCCESSCODE : the function is succesful + */ +static int8_t ConfigManager_IDN(uint8_t *pResponse) +{ + uint8_t DataToSend[] = {IDN ,0x00}; + + /* send the command to the PICC and retrieve its response */ + drv95HF_SendReceive(DataToSend, pResponse); + + return MANAGER_SUCCESSCODE; +} + +/** + * @brief This function set a variable to inform Manager that a task is on going + * @param none + * @retval none + */ +static void ConfigManager_Start( void ) +{ + StopProcess = false; + + devicemode = UNDEFINED_MODE; + nfc_tagtype = UNDEFINED_TAG_TYPE; +} + +/** + * @brief This function sends POR sequence. It is used to initialize chip after a POR. + * @param none + * @retval MANAGER_ERRORCODE_PORERROR : the POR sequence doesn't succeded + * @retval MANAGER_SUCCESSCODE : chip is ready + */ +static int8_t ConfigManager_PORsequence( void ) +{ + uint16_t NthAttempt=0; + uint8_t command[]= {ECHO}; + + /* Power up sequence: Pulse on IRQ_IN to select UART or SPI mode */ + drv95HF_SendIRQINPulse(); + + /* SPI Reset */ + if(drv95HF_GetSerialInterface() == RFTRANS_95HF_INTERFACE_SPI) + { + drv95HF_ResetSPI(); + } + + do + { + /* send an ECHO command and checks response */ + drv95HF_SendReceive(command, u95HFBuffer); + + if (u95HFBuffer[0]==ECHORESPONSE) + return MANAGER_SUCCESSCODE; + + /* if the SPI interface is selected then send a reset command*/ + if(drv95HF_GetSerialInterface() == RFTRANS_95HF_INTERFACE_SPI) + { + drv95HF_ResetSPI(); + } + /* if the UART interface is selected then send 255 ECHO commands*/ + else if(drv95HF_GetSerialInterface() == RFTRANS_95HF_INTERFACE_UART) + { + do { + /* send an ECHO command and checks response */ + drv95HF_SendReceive(command, u95HFBuffer); + if (u95HFBuffer[0] == ECHORESPONSE) + return MANAGER_SUCCESSCODE; + }while(NthAttempt++ < RFTRANS_95HF_MAX_ECHO); + } + } while (u95HFBuffer[0]!=ECHORESPONSE && NthAttempt++ <5); + + return MANAGER_ERRORCODE_PORERROR; +} + + +/** + * @} + */ + + /** @addtogroup lib_ConfigManager_Public_Functions + * @{ + */ + +/** + * @brief This interface function inform Manager that current task must be stopped + * @param none + * @retval none + */ +void ConfigManager_Stop(void ) +{ + StopProcess = true; +} + +/** + * @brief This function initialize the NFC chip + * @brief Physical communication with chip enabled, RF communication not enabled + * @param None + * @retval None + */ +void ConfigManager_HWInit (void) +{ + + /* Initialize HW according to protocol to use */ + ConfigManager_Init(); + + /* initilialize the RF transceiver */ + if (ConfigManager_PORsequence( ) != MANAGER_SUCCESSCODE) + { + /* nothing to do, this is a trap for debug purpose you can use it to detect HW issue */ + /* or GPIO config issue */ + } + + /* Retrieve the IC version of the chip */ + ConfigManager_IDN(u95HFBuffer); + + IcVers = (IC_VERSION) (u95HFBuffer[ROM_CODE_REVISION_OFFSET]); + +} + +/** +* @brief this function searches if a NFC or RFID tag is in the RF field. +* @brief The method used is this described by the NFC specification +* @param tagsToFind : Flags to select the different kinds of tag to track, same as return value +* @retval TRACK_NOTHING : No tag in the RF field +* @retval TRACK_NFCTYPE1 : A NFC type1 tag is present in the RF field +* @retval TRACK_NFCTYPE2 : A NFC type2 tag is present in the RF field +* @retval TRACK_NFCTYPE3 : A NFC type3 tag is present in the RF field +* @retval TRACK_NFCTYPE4A : A NFC type4A tag is present in the RF field +* @retval TRACK_NFCTYPE4B : A NFC type4B tag is present in the RF field +* @retval TRACK_NFCTYPE5 : A ISO/IEC 15693 type A tag is present in the RF field +*/ +uint8_t ConfigManager_TagHunting ( uint8_t tagsToFind ) +{ + /* Start the config manager*/ + ConfigManager_Start(); + + /******* NFC type 1 ********/ + if (tagsToFind&TRACK_NFCTYPE1) + { + PCD_FieldOff(); + delay(5); + ISO14443A_Init( ); + if(ISO14443A_IsPresent() == RESULTOK) + { + if(TOPAZ_ID(TagUID) == RESULTOK) + return TRACK_NFCTYPE1; + } + } + + /******* NFC type 2 and 4A ********/ + if ((tagsToFind&TRACK_NFCTYPE2) || (tagsToFind&TRACK_NFCTYPE4A)) + { + PCD_FieldOff(); + delay(5); + ISO14443A_Init( ); + if(ISO14443A_IsPresent() == RESULTOK) + { + if(ISO14443A_Anticollision() == RESULTOK) + { + if (((ISO14443A_Card.SAK&0x60) == 0x00) && (tagsToFind&TRACK_NFCTYPE2)) /* TT2 */ + return TRACK_NFCTYPE2; + else if (((ISO14443A_Card.SAK&0x20) != 0x00) && (tagsToFind&TRACK_NFCTYPE4A))/* TT4A */ + return TRACK_NFCTYPE4A; + } + } + } + + /******* NFC type 3 ********/ + if (tagsToFind&TRACK_NFCTYPE3) + { + PCD_FieldOff(); + delay(5); + FELICA_Initialization(); + if(FELICA_IsPresent() == RESULTOK ) + return TRACK_NFCTYPE3; + } + + /******* NFC type 4B ********/ + if (tagsToFind&TRACK_NFCTYPE4B) + { + PCD_FieldOff(); + delay(5); + if(ISO14443B_IsPresent() == RESULTOK ) + { + if(ISO14443B_Anticollision() == RESULTOK) + { + return TRACK_NFCTYPE4B; + } + } + } + + /******* ISO15693 ********/ + if (tagsToFind&TRACK_NFCTYPE5) + { + PCD_FieldOff(); + delay(5); + if(ISO15693_GetUID (TagUID) == RESULTOK) + return TRACK_NFCTYPE5; + } + + + /* Turn off the field if no tag has been detected*/ + PCD_FieldOff(); + + /* No tag found */ + return TRACK_NOTHING; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_95HFConfigManager.h b/src/lib_95HFConfigManager.h new file mode 100644 index 0000000..2a68605 --- /dev/null +++ b/src/lib_95HFConfigManager.h @@ -0,0 +1,112 @@ +/** + ****************************************************************************** + * @file lib_95HFConfigManager.h + * @author MMY Application Team + * @version $Revision: 1327 $ + * @date $Date: 2015-11-05 10:28:31 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of firmware functions to manage device modes. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion --------------------------------------------*/ +#ifndef _LIB_95HFCONFIGMANAGER_H +#define _LIB_95HFCONFIGMANAGER_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes -------------------------------------------------------------------------*/ +#include "lib_iso15693pcd.h" +#include "lib_iso14443Apcd.h" +#include "lib_iso14443Bpcd.h" +#include "lib_iso18092pcd.h" + +/* Manager status and erroc code ----------------------------------------------------*/ +#define MANAGER_SUCCESSCODE RESULTOK +#define MANAGER_ERRORCODE_DEFAULT 0xF1 +#define MANAGER_ERRORCODE_PORERROR 0xF2 +#define MANAGER_ERRORCODE_COMMUNICATION_LOST 0xF3 + +/* Flags for PICC/PCD tracking ----------------------------------------------------------*/ +#define TRACK_NOTHING 0x00 +#define TRACK_NFCTYPE1 0x01 /* 0000 0001 */ +#define TRACK_NFCTYPE2 0x02 /* 0000 0010 */ +#define TRACK_NFCTYPE3 0x04 /* 0000 0100 */ +#define TRACK_NFCTYPE4A 0x08 /* 0000 1000 */ +#define TRACK_NFCTYPE4B 0x10 /* 0001 0000 */ +#define TRACK_NFCTYPE5 0x20 /* 0010 0000 */ +#define TRACK_ALL 0xFF /* 1111 1111 */ + +/* Flags for Initiator/Target tracking ------------------------------------------------------*/ +#define P2P_NOTHING 0x00 +#define INITIATOR_NFCA 0x01 /* 0000 0001 */ +#define INITIATOR_NFCF 0x02 /* 0000 0010 */ +#define TARGET_NFCA 0x04 /* 0000 0100 */ +#define TARGET_NFCF 0x08 /* 0000 1000 */ +#define TARGET_LLCPA 0x10 /* 0000 0100 */ +#define TARGET_LLCPF 0x20 /* 0000 1000 */ +#define INITIATOR_LLCPA 0x40 /* 0000 0100 */ +#define INITIATOR_LLCPF 0x80 /* 0000 1000 */ +#define P2P_ALL 0xFF /* 1111 1111 */ + +/* Flags for Proprietary P2P tracking ------------------------------------------------------*/ +#define PP2P_NOTHING 0x00 +#define PP2P_INITIATOR_NFCA 0x01 /* 0000 0001 */ +#define PP2P_TARGET_NFCA 0x10 /* 0000 0100 */ +#define PP2P_ALL 0xFF /* 1111 1111 */ + +/* Flags for SelectMode ----------------------------------------------------------*/ +#define SELECT_NOTHING 0x00 +#define SELECT_PCD 0x01 /* 0000 0001 */ +#define SELECT_PICC 0x02 /* 0000 0010 */ +#define SELECT_P2P 0x04 /* 0000 0100 */ +#define SELECT_ALL 0xFF /* 1111 1111 */ + +/* structure of the manager state --------------------------------------------------*/ +typedef struct { + uint8_t SelectedMode; + uint8_t PcdMode; + uint8_t PiccMode; + uint8_t P2pMode; + uint8_t Result; + uint16_t timeoutEmul; + uint16_t timeoutReadEmul; +}MANAGER_CONFIG; + +//typedef enum PICCEMULATOR_SELECT_TAG_TYPE PICCEMULATOR_SELECT_TAG_TYPE; + +/* public function ----------------------------------------------------------------*/ + +void ConfigManager_HWInit (void); + +uint8_t ConfigManager_TagHunting ( uint8_t tagsToFind ); + +void ConfigManager_Stop(void); + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_95HF_wrapper.cpp b/src/lib_95HF_wrapper.cpp new file mode 100644 index 0000000..ae6b1f4 --- /dev/null +++ b/src/lib_95HF_wrapper.cpp @@ -0,0 +1,401 @@ +/** + ****************************************************************************** + * @file lib_95HF_wrapper.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief Interface for xx95HF in order to use NDEF lib + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_wrapper.h" +#include "lib_NDEF.h" + +#include "lib_nfctype1pcd.h" +#include "lib_nfctype2pcd.h" +#include "lib_nfctype3pcd.h" +#include "lib_nfctype4pcd.h" +#include "lib_nfctype5pcd.h" + + /* Variables for the different modes */ +extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +bool updateFlash = false; + +/* Tag type 1 */ +extern uint8_t TT1Tag[]; + +/* Tag type 2 */ +extern uint8_t TT2Tag[]; + +/* Tag type 3 */ +extern uint8_t TT3Tag[]; +extern uint8_t *TT3AttribInfo, *TT3NDEFfile; + +/* Tag type 4 */ +/* NDEF buffer */ +extern uint8_t CardNDEFfileT4A []; +extern uint8_t CardNDEFfileT4B []; +/* CC buffer*/ +extern uint8_t CardCCfile []; + +/* Tag type 5 */ +extern uint8_t TT5Tag[]; + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + + +/** @defgroup lib_95HF_Private_Functions + * @{ + */ + +/** + * @} + */ + +/** @defgroup lib_95HF_Public_Functions + * @{ + */ + +/** + * @brief This fonction read the data stored in NDEF file at defined offset. + * @param Offset : Offset in the NDEF file. + * @param DataSize : Number of byte to read. + * @param pData : pointer on buffer to store read data. + * @retval ACTION_COMPLETED : The operation is completed. + */ +uint16_t ReadData( uint16_t Offset , uint16_t DataSize , uint8_t* pData ) +{ + uint16_t i; + switch( nfc_tagtype ) + { + case TT1: + if( DataSize > NFCT1_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + for( i = Offset; i < (DataSize+Offset); i++ ) + { + if( i == 0 ) // We need the size + { + /* 2 bytes length */ + if( TT1Tag[17] == 0xFF ) + { + pData[0] = TT1Tag[18]; + pData[1] = TT1Tag[19]; + } + /* 1 bytes length */ + else + { + pData[0] = 0x00; + pData[1] = TT1Tag[17]; + } + i++; + } + else // We need the NDEF message + { + /* 2 bytes length */ + if( TT1Tag[17] == 0xFF ) + pData[i-Offset] = TT1Tag[18+i]; + /* 1 bytes length */ + else + pData[i-Offset] = TT1Tag[16+i]; + } + } + break; + + case TT2: + if( DataSize > NFCT2_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + for( i = Offset; i < (DataSize+Offset); i++ ) + { + if( i == 0 ) // We need the size + { + /* 2 bytes length */ + if( TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+1] == 0xFF ) + { + pData[0] = TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+2]; + pData[1] = TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+3]; + } + /* 1 bytes length */ + else + { + pData[0] = 0x00; + pData[1] = TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+1]; + } + i++; + } + else // We need the NDEF message + { + /* 2 bytes length */ + if( TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+1] == 0xFF ) + pData[i-Offset] = TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+2+i]; + /* 1 bytes length */ + else + pData[i-Offset] = TT2Tag[NFCT2_MAX_CONFIG+NFCT2_MAX_CC_SIZE+i]; + } + } + break; + + case TT3: + if( DataSize > NFCT3_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + for( i = Offset; i < (DataSize+Offset); i++ ) + { + if( i == 0 ) // We need the size + { + pData[0] = TT3AttribInfo[12]; + pData[1] = TT3AttribInfo[13]; + i++; + } + else + { + pData[i-Offset] = *(TT3NDEFfile + i - 2); + } + } + break; + + case TT4A: + if( DataSize > NFCT4A_MAX_NDEFMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + memcpy( pData, &CardNDEFfileT4A[Offset], DataSize ); + break; + + case TT4B: + if( DataSize > NFCT4B_MAX_NDEFMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + memcpy( pData, &CardNDEFfileT4B[Offset], DataSize ); + break; + + case TT5: + if( DataSize > NFCT5_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + for( i = Offset; i < (DataSize+Offset); i++ ) + { + if( i == 0 ) // We need the size + { + /* 2 bytes length */ + if( TT5Tag[5] == 0xFF ) + { + pData[0] = TT5Tag[6]; + pData[1] = TT5Tag[7]; + } + /* 1 bytes length */ + else + { + pData[0] = 0x00; + pData[1] = TT5Tag[5]; + } + i++; + } + else // We need the NDEF message + { + /* 2 bytes length */ + if( TT5Tag[5] == 0xFF ) + pData[i-Offset] = TT5Tag[6+i]; + /* 1 bytes length */ + else + pData[i-Offset] = TT5Tag[4+i]; + } + } + break; + + default: + break; + } + return NDEF_OK; +} + +/** + * @brief This fonction write data in NDEF file at defined offset. + * @param Offset : Offset in the NDEF file. + * @param DataSize : Number of byte to write. + * @param pData : pointer on buffer to copy. + * @retval ACTION_COMPLETED : The operation is completed. + */ +uint16_t WriteData( uint16_t Offset, uint32_t DataSize, uint8_t* pData ) +{ + uint16_t index = 0, i, sum = 0; + switch( nfc_tagtype ) + { + case TT1: + if( DataSize > NFCT1_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + index = Offset + 14; + DataSize -= 2; + /* Write the NDEF TLV [0x03 length message] */ + TT1Tag[index++] = 0x03; + /* Size can be stored in one byte or 3 bytes depending on the length */ + if( DataSize < 255 ) + { + TT1Tag[index++] = DataSize; + } + else + { + TT1Tag[index++] = 0xFF; + TT1Tag[index++] = ( DataSize&0x0000FF00 ) >> 8; + TT1Tag[index++] = DataSize & 0x000000FF; + } + memcpy( &(TT1Tag[index]), pData+2, DataSize ); + /* Write the terminating TLV [0xFE] */ + TT1Tag[index+DataSize] = 0xFE; + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT1_WriteNDEF( ); + break; + + case TT2: + if( DataSize > NFCT2_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + index = Offset + NFCT2_MAX_CONFIG + NFCT2_MAX_CC_SIZE; + DataSize -= 2; + /* Write the NDEF TLV [0x03 length message] */ + TT2Tag[index++] = 0x03; + /* Size can be stored in one byte or 3 bytes depending on the length */ + if( DataSize < 255 ) + { + TT2Tag[index++] = DataSize; + } + else + { + TT2Tag[index++] = 0xFF; + TT2Tag[index++] = ( DataSize&0x0000FF00 ) >> 8; + TT2Tag[index++] = DataSize & 0x000000FF; + } + memcpy( &(TT2Tag[index]), pData+2, DataSize ); + /* Write the terminating TLV [0xFE] */ + TT2Tag[index+DataSize] = 0xFE; + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT2_WriteNDEF( ); + else + updateFlash = true; + break; + + case TT3: + if( DataSize > NFCT3_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + DataSize -= 2; + /* Write the ndef message first */ + memcpy( TT3NDEFfile, pData+2, DataSize ); + /* Update AttribInfo */ + TT3AttribInfo[11] = ( DataSize&0x00FF0000 ) >> 16; + TT3AttribInfo[12] = ( DataSize&0x0000FF00 ) >> 8; + TT3AttribInfo[13] = DataSize & 0x000000FF; + /* Update checksum */ + for( i = 0; i < 14; i++ ) + sum += TT3AttribInfo[i]; + TT3AttribInfo[14] = ( sum&0xFF00 ) >> 8; + TT3AttribInfo[15] = sum & 0x00FF; + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT3_WriteNDEF( ); + else + updateFlash = true; + break; + + case TT4A: + if( DataSize > NFCT4A_MAX_NDEFMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + memcpy( &(CardNDEFfileT4A[Offset]), pData, DataSize ); + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT4_WriteNDEF( ); + else + updateFlash = true; + break; + + case TT4B: + if( DataSize > NFCT4_MAX_NDEFMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + memcpy( &(CardNDEFfileT4B[Offset]), pData, DataSize ); + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT4_WriteNDEF( ); + else + updateFlash = true; + break; + + case TT5: + if( DataSize > NFCT5_MAX_TAGMEMORY ) + return NDEF_ERROR_MEMORY_INTERNAL; + index = 4; + DataSize -= 2; + /* Write the NDEF TLV [0x03 length message] */ + TT5Tag[index++] = 0x03; + /* Size can be stored in one byte or 3 bytes depending on the length */ + if( DataSize < 255 ) + { + TT5Tag[index++] = DataSize; + } + else + { + TT5Tag[index++] = 0xFF; + TT5Tag[index++] = ( DataSize&0x0000FF00 ) >> 8; + TT5Tag[index++] = DataSize & 0x000000FF; + } + memcpy( &(TT5Tag[index]), pData + 2, DataSize ); + /* Write the terminating TLV [0xFE] */ + TT5Tag[index+DataSize] = 0xFE; + /* Update the phisical tag if needed */ + if( devicemode == PCD ) + return PCDNFCT5_WriteNDEF( ); + break; + + default: + break; + } + return NDEF_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF.cpp b/src/lib_NDEF.cpp new file mode 100644 index 0000000..6c02904 --- /dev/null +++ b/src/lib_NDEF.cpp @@ -0,0 +1,613 @@ +/** + ****************************************************************************** + * @file lib_NDEF.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file, to parse and identify them. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** @defgroup libNDEF_Private_Functions + * @{ + */ + + +static uint16_t NDEF_IsNDEFPresent( void ); +static uint16_t NDEF_ParseRecordHeader( sRecordInfo_t *pRecordStruct ); +static void NDEF_ParseWellKnownType( sRecordInfo_t *pRecordStruct ); +static void NDEF_ParseMediaType( sRecordInfo_t *pRecordStruct ); +static void NDEF_ParseForumExternalType( sRecordInfo_t *pRecordStruct ); +static void NDEF_ParseURI( sRecordInfo_t *pRecordStruct ); +static void NDEF_ParseSP( sRecordInfo_t *pRecordStruct ); +static uint16_t NDEF_IdentifySPRecord( sRecordInfo_t *pRecordStruct, uint8_t* pPayload ); + +uint8_t NDEF_Buffer [NDEF_MAX_SIZE]; + +/* In case of smart Poster composed with different record, 2 records supported so far */ +sRecordInfo_t SPRecordStruct1, SPRecordStruct2; +sRecordInfo_t *SPRecordStructAdd[SP_MAX_RECORD] = { &SPRecordStruct1, &SPRecordStruct2 }; + + +/** + * @brief This function check that the tag contain a NDEF message. + * @retval NDEF_OK : There is a NDEF file stored in tag. + * @retval NDEF_ERROR : No NDEF in the tag. + */ +static uint16_t NDEF_IsNDEFPresent( void ) +{ + uint16_t FileSize; + uint8_t uNDEFHeader [0x2]; + + /* Check NDEF existence */ + ReadData( NDEF_SIZE_OFFSET, 2, uNDEFHeader ); + FileSize = (uint16_t)( (uNDEFHeader[0x00]<<8) | uNDEFHeader[0x01] ); + + if( FileSize != 0 ) + return NDEF_OK; + else + return NDEF_ERROR; +} + +/** + * @brief This function identify the type of record. + * @param pRecordStruct : pointer on the record structure to fill. + * @param pPayload : pointer on the payload. + * @retval Status : Status of the operation. + */ +static uint16_t NDEF_IdentifySPRecord( sRecordInfo_t *pRecordStruct, uint8_t* pPayload ) +{ + uint16_t status = NDEF_ERROR; + uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte; + + /* Is ID length field present */ + if( (*pPayload) & IL_Mask ) + { + IDLengthField = ID_LENGTH_FIELD; + } + else + { + IDLengthField = 0; + } + + /* it's a SR */ + if( (*pPayload) & SR_Mask ) + { + TypeNbByte = pPayload[1]; + PayloadLengthField = 1; + if( IDLengthField == ID_LENGTH_FIELD ) + IDNbByte = pPayload[3]; + else + IDNbByte = 0; + } + else + { + TypeNbByte = pPayload[1]; + PayloadLengthField = 4; + if( IDLengthField == ID_LENGTH_FIELD ) + IDNbByte = pPayload[6]; + else + IDNbByte = 0; + } + + SizeOfRecordHeader = RECORD_FLAG_FIELD + TYPE_LENGTH_FIELD + PayloadLengthField + IDLengthField + TypeNbByte + IDNbByte; + + /* it's a SR */ + if( pPayload[0] & SR_Mask ) + { + pRecordStruct->RecordFlags = pPayload[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = 0; + pRecordStruct->PayloadLength2 = 0; + pRecordStruct->PayloadLength1 = 0; + pRecordStruct->PayloadLength0 = pPayload[2]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pPayload[3+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pPayload[3+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + else + { + pRecordStruct->RecordFlags = pPayload[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = pPayload[2]; + pRecordStruct->PayloadLength2 = pPayload[3]; + pRecordStruct->PayloadLength1 = pPayload[4]; + pRecordStruct->PayloadLength0 = pPayload[5]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pPayload[6+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pPayload[6+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + + pRecordStruct->PayloadBufferAdd = (uint32_t)( pPayload + SizeOfRecordHeader ); + + status = NDEF_ParseRecordHeader( pRecordStruct ); + + return status; +} + +/** + * @brief This function parse the record header and dispatch regarding TNF value. + * @param pRecordStruct : pointer on the record structure to fill. + * @retval NDEF_OK : record identified and structure filled. + * @retval NDEF_ERROR : Not supported. + */ +static uint16_t NDEF_ParseRecordHeader( sRecordInfo_t *pRecordStruct ) +{ + uint16_t status = NDEF_OK; + + switch( (pRecordStruct->RecordFlags & TNF_Mask) ) + { + case TNF_WellKnown: + NDEF_ParseWellKnownType( pRecordStruct ); + break; + + case TNF_MediaType: + NDEF_ParseMediaType( pRecordStruct ); + break; + + case TNF_NFCForumExternal: + NDEF_ParseForumExternalType( pRecordStruct); + break; + + default: + /* currently not supported or unknown*/ + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; + status = NDEF_ERROR; + } + return status; +} + +/** + * @brief This function parse the Well Known type record. + * @param pRecordStruct : pointer on the record structure to fill. + */ +static void NDEF_ParseWellKnownType( sRecordInfo_t *pRecordStruct ) +{ + uint8_t* pPayload; + + pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd ); + + if( !memcmp( &(pRecordStruct->Type), SMART_POSTER_TYPE_STRING, pRecordStruct->TypeLength ) ) + { + /* special case where we have to parse others records */ + pRecordStruct->NDEF_Type = SMARTPOSTER_TYPE; + NDEF_ParseSP( pRecordStruct ); + } + + else if( !memcmp( &(pRecordStruct->Type), URI_TYPE_STRING, pRecordStruct->TypeLength ) ) + { + /* it's an URI Type check if it's an URL or SMS or ... */ + /* check identifier */ + if( *pPayload == URI_ID_0x00 ) + { + NDEF_ParseURI( pRecordStruct ); + } + else if( (*pPayload > URI_ID_0x00) && (*pPayload < URI_RFU) ) + { + /* email special case */ + if( *pPayload == (uint8_t) URI_ID_0x06 ) + { + pRecordStruct->NDEF_Type = URI_EMAIL_TYPE; + } + else + { + pRecordStruct->NDEF_Type = WELL_KNOWN_ABRIDGED_URI_TYPE; + } + } + else + { + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; + } + } + + else if( !memcmp( &(pRecordStruct->Type), TEXT_TYPE_STRING, pRecordStruct->TypeLength ) ) + { + pRecordStruct->NDEF_Type = TEXT_TYPE; + } + else + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; +} + +/** + * @brief This function parse the Media type record. + * @param pRecordStruct : pointer on the record structure to fill. + */ +static void NDEF_ParseMediaType( sRecordInfo_t *pRecordStruct ) +{ + if( !memcmp( &(pRecordStruct->Type), VCARD_TYPE_STRING, pRecordStruct->TypeLength ) ) + pRecordStruct->NDEF_Type = VCARD_TYPE; + else if( !memcmp( &(pRecordStruct->Type), XVCARD_TYPE_STRING, pRecordStruct->TypeLength ) ) + pRecordStruct->NDEF_Type = VCARD_TYPE; + else if( !memcmp( &(pRecordStruct->Type), XVCARD2_TYPE_STRING, pRecordStruct->TypeLength ) ) + pRecordStruct->NDEF_Type = VCARD_TYPE; + else + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; +} + +/** + * @brief This function parse the Forum External type record. + * @param pRecordStruct : pointer on the record structure to fill. + */ +static void NDEF_ParseForumExternalType( sRecordInfo_t *pRecordStruct ) +{ + if( !memcmp( &(pRecordStruct->Type), M24SR_DISCOVERY_APP_STRING, pRecordStruct->TypeLength ) ) + pRecordStruct->NDEF_Type = M24SR_DISCOVERY_APP_TYPE; + else + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; +} + +/** + * @brief This function parse the URI type record. + * @param pRecordStruct : pointer on the record structure to fill. + */ +static void NDEF_ParseURI( sRecordInfo_t *pRecordStruct ) +{ + uint8_t* pPayload; + + pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd ); + pPayload++; /* to skip URI identifier first URI payload byte */ + + if( !memcmp( pPayload, SMS_TYPE_STRING, strlen(SMS_TYPE_STRING) ) ) + { + pRecordStruct->NDEF_Type = URI_SMS_TYPE; + } + else if( !memcmp( pPayload, GEO_TYPE_STRING, strlen(GEO_TYPE_STRING) ) ) + { + pRecordStruct->NDEF_Type = URI_GEO_TYPE; + } + else + pRecordStruct->NDEF_Type = UNKNOWN_TYPE; +} + +/** + * @brief This function parse the Smart Poster. + * @param pRecordStruct : pointer on the record structure to fill. + */ +static void NDEF_ParseSP( sRecordInfo_t *pRecordStruct ) +{ + uint8_t* pPayload; + uint32_t PayloadSize = 0; + uint32_t SPPayloadSize = 0; + uint32_t OffsetInSPPayload = 0; + uint32_t RecordPosition = 0; + sRecordInfo_t *pSPRecordStruct; + + /* initialize variable with size of the payload and poiter on data */ + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd ); + + pSPRecordStruct = SPRecordStructAdd[0]; + + /* Initailize the number of record find in the SP payload */ + pRecordStruct->NbOfRecordInSPPayload = 0; + + do + { + pSPRecordStruct = SPRecordStructAdd[RecordPosition]; + /* identify the record in the SP payload */ + if( NDEF_IdentifySPRecord( pSPRecordStruct, pPayload ) == NDEF_OK ) + { + /* store add of structure that will contain the other record information */ + pRecordStruct->NbOfRecordInSPPayload++; + pRecordStruct->SPRecordStructAdd[RecordPosition] = pSPRecordStruct; + + /* After SPRecord + First Record check if we are at the end of NDEF file */ + SPPayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pSPRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pSPRecordStruct->PayloadLength1) << 8) | pSPRecordStruct->PayloadLength0; + + OffsetInSPPayload += pSPRecordStruct->PayloadOffset + SPPayloadSize; + pPayload += OffsetInSPPayload; + } + else /* Recommended Action Record for example */ + { + SPPayloadSize = 0; + } + RecordPosition++; + } + while( (OffsetInSPPayload < PayloadSize) && RecordPositionRecordFlags = pNDEF[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = 0; + pRecordStruct->PayloadLength2 = 0; + pRecordStruct->PayloadLength1 = 0; + pRecordStruct->PayloadLength0 = pNDEF[2]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pNDEF[3+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pNDEF[3+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + else + { + pRecordStruct->RecordFlags = pNDEF[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = pNDEF[2]; + pRecordStruct->PayloadLength2 = pNDEF[3]; + pRecordStruct->PayloadLength1 = pNDEF[4]; + pRecordStruct->PayloadLength0 = pNDEF[5]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pNDEF[6+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pNDEF[6+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + /* read Payload */ + status = ReadData( (uint16_t)((FIRST_RECORD_OFFSET) + pRecordStruct->PayloadOffset) , PayloadSize , pNDEF ); + + if( status != NDEF_OK ) + return NDEF_ERROR; + else + pRecordStruct->PayloadBufferAdd = (uint32_t)(pNDEF); + + NDEF_ParseRecordHeader( pRecordStruct ); + + return NDEF_OK; +} + +/** + * @brief This function read the NDEF content of the TAG. + * @param pNDEF : pointer on the buffer to store NDEF data. + * @retval NDEF_OK : NDEF file data retrieve and store in the buffer. + * @retval NDEF_ERROR : not able to read NDEF from tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot read tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be read. + */ +uint16_t NDEF_ReadNDEF( uint8_t* pNDEF ) +{ + uint16_t status = NDEF_ERROR; + uint16_t NDEF_Size = 0; + + status = ReadData( 0, 2, pNDEF ); + + if( status == NDEF_OK ) + { + NDEF_Size = (uint16_t)(*pNDEF << 8); + NDEF_Size = NDEF_Size | (uint16_t)(*++pNDEF ); + + status = ReadData( 0, NDEF_Size + 2, --pNDEF ); + } + + return status; +} + +/** + * @brief This function write the NDEF in the TAG. + * @param pNDEF : pointer on the buffer containing the NDEF data. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteNDEF( uint8_t *pNDEF ) +{ + uint16_t status = NDEF_ERROR; + uint16_t NDEF_Size = 0; + + NDEF_Size = (uint16_t)(*pNDEF << 8); + NDEF_Size = NDEF_Size | (uint16_t)(*++pNDEF ); + + status = WriteData( 0, NDEF_Size + 2, --pNDEF ); + + return status; +} + +/** + * @brief This function identify the NDEF message stored in tag. + * @param pRecordStruct : Structure to fill with record information. + * @param pNDEF : pointer on the NDEF message data. + * @retval NDEF_OK : record struct filled. + * @retval NDEF_ERROR : record struct not updated. + */ +uint16_t NDEF_IdentifyBuffer( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF ) +{ + uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte; + + /* Is ID length field present */ + if( (*pNDEF) & IL_Mask ) + { + IDLengthField = ID_LENGTH_FIELD; + } + else + { + IDLengthField = 0; + } + + /* it's a SR */ + if( (*pNDEF) & SR_Mask ) + { + /* Analyse short record layout */ + TypeNbByte = pNDEF[1]; + PayloadLengthField = 1; + if( IDLengthField == ID_LENGTH_FIELD ) + IDNbByte = pNDEF[3]; + else + IDNbByte = 0; + } + else + { + /* Analyse normal record layout */ + TypeNbByte = pNDEF[1]; + PayloadLengthField = 4; + if( IDLengthField == ID_LENGTH_FIELD ) + IDNbByte = pNDEF[6]; + else + IDNbByte = 0; + } + + SizeOfRecordHeader = RECORD_FLAG_FIELD + TYPE_LENGTH_FIELD + PayloadLengthField + IDLengthField + TypeNbByte + IDNbByte; + + /* it's a SR */ + if( pNDEF[0] & SR_Mask ) + { + pRecordStruct->RecordFlags = pNDEF[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = 0; + pRecordStruct->PayloadLength2 = 0; + pRecordStruct->PayloadLength1 = 0; + pRecordStruct->PayloadLength0 = pNDEF[2]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pNDEF[3+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pNDEF[3+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + else + { + pRecordStruct->RecordFlags = pNDEF[0]; + pRecordStruct->TypeLength = TypeNbByte; + pRecordStruct->PayloadLength3 = pNDEF[2]; + pRecordStruct->PayloadLength2 = pNDEF[3]; + pRecordStruct->PayloadLength1 = pNDEF[4]; + pRecordStruct->PayloadLength0 = pNDEF[5]; + pRecordStruct->IDLength = IDNbByte; + memcpy( pRecordStruct->Type, &pNDEF[6+IDNbByte], TypeNbByte ); + memcpy( pRecordStruct->ID, &pNDEF[6+IDNbByte+TypeNbByte], IDNbByte ); + pRecordStruct->PayloadOffset = SizeOfRecordHeader; + } + + pRecordStruct->PayloadBufferAdd = (uint32_t)(&pNDEF[pRecordStruct->PayloadOffset]); + + NDEF_ParseRecordHeader( pRecordStruct ); + + return NDEF_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF.h b/src/lib_NDEF.h new file mode 100644 index 0000000..3b5c695 --- /dev/null +++ b/src/lib_NDEF.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file lib_NDEF.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_H +#define __LIB_NDEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* include file which match the HW configuration */ +#include "common.h" +#include "lib_wrapper.h" + +#define NDEF_ACTION_COMPLETED 0x9000 + +#ifndef errorchk +#define errorchk(fCall) if (status = (fCall), status != NDEF_ACTION_COMPLETED) \ + {goto Error;} else +#endif + +/* Error codes for Higher level */ +#define NDEF_OK RESULTOK +#define NDEF_ERROR ERRORCODE_GENERIC +#define NDEF_ERROR_MEMORY_TAG 2 +#define NDEF_ERROR_MEMORY_INTERNAL 3 +#define NDEF_ERROR_LOCKED 4 +#define NDEF_ERROR_NOT_FORMATED 5 + +#define NDEF_MAX_SIZE NFC_DEVICE_MAX_NDEFMEMORY + +#define NDEF_SIZE_OFFSET 0 +#define FIRST_RECORD_OFFSET 2 + +#define RECORD_FLAG_FIELD 1 +#define TYPE_LENGTH_FIELD 1 +#define ID_LENGTH_FIELD 1 + + +#define MB_Mask ((uint8_t)(0x80)) +#define ME_Mask ((uint8_t)(0x40)) +#define CF_Mask ((uint8_t)(0x20)) +#define SR_Mask ((uint8_t)(0x10)) +#define IL_Mask ((uint8_t)(0x08)) +#define TNF_Mask ((uint8_t)(0x07)) + +#define TNF_Empty 0x00 +#define TNF_WellKnown 0x01 +#define TNF_MediaType 0x02 +#define TNF_AbsoluteURI 0x03 +#define TNF_NFCForumExternal 0x04 +#define TNF_Unknown 0x05 +#define TNF_Unchanged 0x06 +#define TNF_Reserved 0x07 + +#define SP_MAX_RECORD 2 + +#define AAR_TYPE_STRING "android.com:pkg" +#define AAR_TYPE_STRING_LENGTH 15 + +#define M24SR_DISCOVERY_APP_STRING "st.com:m24sr_discovery_democtrl" +#define M24SR_DISCOVERY_APP_STRING_LENGTH 31 + +#define VCARD_TYPE_STRING "text/vcard" +#define VCARD_TYPE_STRING_LENGTH 10 + +#define XVCARD_TYPE_STRING "text/x-vCard" +#define XVCARD_TYPE_STRING_LENGTH 12 + +#define XVCARD2_TYPE_STRING "text/x-vcard" +#define XVCARD2_TYPE_STRING_LENGTH 12 + +#define SMART_POSTER_TYPE_STRING "Sp" +#define SMART_POSTER_TYPE_STRING_LENGTH 2 + +#define URI_TYPE_STRING "U" +#define URI_TYPE_STRING_LENGTH 1 + +#define SMS_TYPE_STRING "sms:" +#define SMS_TYPE_STRING_LENGTH 4 + +#define GEO_TYPE_STRING "geo:" +#define GEO_TYPE_STRING_LENGTH 4 + +#define URI_LATITUDE_END "," +#define URI_LATITUDE_END_LENGTH 1 + +#define EMAIL_TYPE_STRING "mailto:" +#define EMAIL_TYPE_STRING_LENGTH 7 + +#define URI_FIRST_DATA_END "?" +#define URI_FIRST_DATA_END_LENGTH 1 + +#define SUBJECT_BEGIN_STRING "subject=" +#define SUBJECT_BEGIN_STRING_LENGTH 8 + +#define MESSAGE_BEGIN_STRING "body=" +#define MESSAGE_BEGIN_STRING_LENGTH 5 + +#define URI_SECOND_DATA_END "&" +#define URI_SECOND_DATA_END_LENGTH 1 + +#define TEXT_TYPE_STRING "T" +#define TEXT_TYPE_STRING_LENGTH 1 + +#define ISO_ENGLISH_CODE_STRING "en" +#define ISO_ENGLISH_CODE_STRING_LENGTH 2 + + +#define URI_ID_0x00 0x00 +#define URI_ID_0x01 0x01 +#define URI_ID_0x02 0x02 +#define URI_ID_0x03 0x03 +#define URI_ID_0x04 0x04 +#define URI_ID_0x05 0x05 +#define URI_ID_0x06 0x06 +#define URI_ID_0x07 0x07 +#define URI_ID_0x08 0x08 +#define URI_ID_0x09 0x09 +#define URI_ID_0x0A 0x0A +#define URI_ID_0x0B 0x0B +#define URI_ID_0x0C 0x0C +#define URI_ID_0x0D 0x0D +#define URI_ID_0x0E 0x0E +#define URI_ID_0x0F 0x0F +#define URI_ID_0x10 0x10 +#define URI_ID_0x11 0x11 +#define URI_ID_0x12 0x12 +#define URI_ID_0x13 0x13 +#define URI_ID_0x14 0x14 +#define URI_ID_0x15 0x15 +#define URI_ID_0x16 0x16 +#define URI_ID_0x17 0x17 +#define URI_ID_0x18 0x18 +#define URI_ID_0x19 0x19 +#define URI_ID_0x1A 0x1A +#define URI_ID_0x1B 0x1B +#define URI_ID_0x1C 0x1C +#define URI_ID_0x1D 0x1D +#define URI_ID_0x1E 0x1E +#define URI_ID_0x1F 0x1F +#define URI_ID_0x20 0x20 +#define URI_ID_0x21 0x21 +#define URI_ID_0x22 0x22 +#define URI_ID_0x23 0x23 +#define URI_RFU 0x24 + +#define URI_ID_0x01_STRING "http://www.\0" +#define URI_ID_0x02_STRING "https://www.\0" +#define URI_ID_0x03_STRING "http://\0" +#define URI_ID_0x04_STRING "https://\0" +#define URI_ID_0x05_STRING "tel:\0" +#define URI_ID_0x06_STRING "mailto:\0" +#define URI_ID_0x07_STRING "ftp://anonymous:anonymous@\0" +#define URI_ID_0x08_STRING "ftp://ftp.\0" +#define URI_ID_0x09_STRING "ftps://\0" +#define URI_ID_0x0A_STRING "sftp://\0" +#define URI_ID_0x0B_STRING "smb://\0" +#define URI_ID_0x0C_STRING "nfs://\0" +#define URI_ID_0x0D_STRING "ftp://\0" +#define URI_ID_0x0E_STRING "dav://\0" +#define URI_ID_0x0F_STRING "news:\0" +#define URI_ID_0x10_STRING "telnet://\0" +#define URI_ID_0x11_STRING "imap:\0" +#define URI_ID_0x12_STRING "rtsp://\0" +#define URI_ID_0x13_STRING "urn:\0" +#define URI_ID_0x14_STRING "pop:\0" +#define URI_ID_0x15_STRING "sip:\0" +#define URI_ID_0x16_STRING "sips:\0" +#define URI_ID_0x17_STRING "tftp:\0" +#define URI_ID_0x18_STRING "btspp://\0" +#define URI_ID_0x19_STRING "btl2cap://\0" +#define URI_ID_0x1A_STRING "btgoep://\0" +#define URI_ID_0x1B_STRING "tcpobex://\0" +#define URI_ID_0x1C_STRING "irdaobex://\0" +#define URI_ID_0x1D_STRING "file://\0" +#define URI_ID_0x1E_STRING "urn:epc:id:\0" +#define URI_ID_0x1F_STRING "urn:epc:tag\0" +#define URI_ID_0x20_STRING "urn:epc:pat:\0" +#define URI_ID_0x21_STRING "urn:epc:raw:\0" +#define URI_ID_0x22_STRING "urn:epc:\0" +#define URI_ID_0x23_STRING "urn:nfc:\0" + +typedef enum +{ + UNKNOWN_TYPE = 0, + VCARD_TYPE, + WELL_KNOWN_ABRIDGED_URI_TYPE, + URI_SMS_TYPE, + URI_GEO_TYPE, + URI_EMAIL_TYPE, + SMARTPOSTER_TYPE, + URL_TYPE, + TEXT_TYPE, + BT_TYPE, + /* list of "external type" known by this demo, other external type will be addressed as UNKNWON_TYPE */ + M24SR_DISCOVERY_APP_TYPE +} NDEF_TypeDef; + +typedef struct sRecordInfo sRecordInfo_t; +struct sRecordInfo +{ + uint8_t RecordFlags; + uint8_t TypeLength; + uint8_t PayloadLength3; + uint8_t PayloadLength2; + uint8_t PayloadLength1; + uint8_t PayloadLength0; + uint8_t IDLength; + uint8_t Type[0xFF]; + uint8_t ID[0xFF]; + uint16_t PayloadOffset; + uint32_t PayloadBufferAdd; /* add where payload content has been stored */ + NDEF_TypeDef NDEF_Type; /* to store identification ID for application */ + sRecordInfo_t *SPRecordStructAdd[SP_MAX_RECORD]; /*in case of smart poster array to store add of other sRecordInfo struct */ + uint8_t NbOfRecordInSPPayload; +}; + + +uint16_t NDEF_IdentifyNDEF( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF ); +uint16_t NDEF_IdentifyBuffer( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF ); +uint16_t NDEF_ReadNDEF( uint8_t *pNDEF ); +uint16_t NDEF_WriteNDEF( uint8_t *pNDEF ); + +#ifdef __cplusplus +} +#endif +#endif /* __LIB_NDEF_H */ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_AAR.cpp b/src/lib_NDEF_AAR.cpp new file mode 100644 index 0000000..136f692 --- /dev/null +++ b/src/lib_NDEF_AAR.cpp @@ -0,0 +1,188 @@ +/** + ****************************************************************************** + * @file lib_NDEF_AAR.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to add AAR to NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_AAR.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libAAR_Private_Functions + * @{ + */ + +/** + * @} + */ + +/** @defgroup libAAR_Public_Functions + * @{ + * @brief This file is used to manage AAR (stored or loaded in tag) + */ + + +/** + * @brief This function add AAR (Android Application Record) in the tag. + * @param pAARStruct : pointer on structure that contain AAR information. + * @retval NDEF_OK : AAR added. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_AddAAR( sAARInfo *pAARStruct ) +{ + uint16_t status = NDEF_ERROR; + uint16_t DataSize = 0; + uint16_t Offset = 0; + uint32_t AAROffset = 0; + uint16_t NDEF_Size = 0; + uint8_t RecordFlag = 0; + uint8_t AARRecordFlag = 0; + +/* AAR: External Type Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- IL=0, CF=0 and SR=1 TNF=4 NFC Forum external type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ /* android.com:pkg */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* Do we have to add AAR to an existing NDEF message */ + /* retrieve current NDEF size and current record flag*/ + status = ReadData( 0, 3, NDEF_Buffer ); + + if( status == NDEF_OK ) + { + NDEF_Size = (uint16_t)(NDEF_Buffer[0] << 8); + NDEF_Size = NDEF_Size | (uint16_t)(NDEF_Buffer[1]); + RecordFlag = NDEF_Buffer[2]; + } + + if( NDEF_Size != 0 ) + { + AAROffset = NDEF_Size + 2; + RecordFlag &= 0xBF; /* remove ME flag on NDEF */ + AARRecordFlag = 0x54; /* don't put MB flag */ + } + else + { + AAROffset = 2; + AARRecordFlag = 0xD4; /* put MB and ME flag */ + } + + /* fill AAR record header */ + Offset = 0; + NDEF_Buffer[Offset++] = AARRecordFlag; /* Record Flag */ + NDEF_Buffer[Offset++] = AAR_TYPE_STRING_LENGTH; + NDEF_Buffer[Offset++] = 0x00; /* Will be filled at the end when payload size is known */ + + memcpy( &NDEF_Buffer[Offset], AAR_TYPE_STRING, AAR_TYPE_STRING_LENGTH ); + + /* fill AAR payload */ + memcpy( &NDEF_Buffer[Offset + AAR_TYPE_STRING_LENGTH], pAARStruct->PakageName, strlen(pAARStruct->PakageName) ); + + NDEF_Buffer[2] = strlen( pAARStruct->PakageName ); + + DataSize = Offset + AAR_TYPE_STRING_LENGTH + strlen( pAARStruct->PakageName ); + + /* Write NDEF */ + status = WriteData( AAROffset, DataSize, NDEF_Buffer ); + + /* Write NDEF size to complete*/ + if( status == NDEF_OK ) + { + DataSize = NDEF_Size + DataSize; /* Must add to the NDEF size the size of the AAR record*/ + NDEF_Buffer[0] = (DataSize & 0xFF00) >> 8; + NDEF_Buffer[1] = DataSize & 0x00FF; + if( NDEF_Size != 0 ) + { + NDEF_Buffer[2] = RecordFlag; + status = WriteData( 0x00, 3, NDEF_Buffer ); + } + else + status = WriteData( 0x00, 2, NDEF_Buffer ); + } + + return status; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_AAR.h b/src/lib_NDEF_AAR.h new file mode 100644 index 0000000..ad8bbf6 --- /dev/null +++ b/src/lib_NDEF_AAR.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * @file lib_NDEF_AAR.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage AAR. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_AAR_H +#define __LIB_NDEF_AAR_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +typedef struct +{ + char PakageName[80]; +}sAARInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_AAR; + +uint16_t NDEF_AddAAR( sAARInfo *pAARStruct ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_AAR_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Email.cpp b/src/lib_NDEF_Email.cpp new file mode 100644 index 0000000..c593814 --- /dev/null +++ b/src/lib_NDEF_Email.cpp @@ -0,0 +1,413 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Email.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file that represent Email. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_Email.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + + +/** @defgroup libEmail_Private_Functions + * @{ + */ + + +static void NDEF_FillEmailStruct( uint8_t* pPayload, uint32_t PayloadSize, sEmailInfo *pEmailStruct ); +static void NDEF_ReadURI_Email( sRecordInfo_email *pRecordStruct, sEmailInfo *pEmailStruct ); + +/** + * @brief This function fill Email structure with information of NDEF message + * @param pPayload : pointer on the payload data of the NDEF message + * @param PayloadSize : number of data in the payload + * @param pEmailStruct : pointer on the structure to fill + * @retval NONE + */ +static void NDEF_FillEmailStruct( uint8_t* pPayload, uint32_t PayloadSize, sEmailInfo *pEmailStruct ) +{ + uint8_t* pLastByteAdd, *pLook4Word, *pEndString; + uint32_t SizeOfKeyWord = 0; + + pEndString = 0; + + /* First character force to NULL in case not matching found */ + *pEmailStruct->EmailAdd = 0; + *pEmailStruct->Subject = 0; + *pEmailStruct->Message = 0; + + /* Interesting information are stored before picture if any */ + /* Moreover picture is not used in this demonstration SW */ + pLastByteAdd = (uint8_t*)(pPayload + PayloadSize); + + /* first byte should be the "mailto:" well know URI type, skip it */ + pLook4Word = ++pPayload; + + /* Retrieve email add */ + if( pLook4Word != pLastByteAdd ) + { + pEndString = pLook4Word; + while( memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) ) + { + pEndString++; + } + if( ( !memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) ) || (pEndString == pLastByteAdd) ) + { + memcpy( pEmailStruct->EmailAdd, pLook4Word, pEndString-pLook4Word); + /* add end of string character */ + pEmailStruct->EmailAdd[pEndString-pLook4Word] = 0; + } + } + + pEndString += URI_FIRST_DATA_END_LENGTH; + pLook4Word = pEndString; + + /* check if e-mail subject is present */ + if( !memcmp( pLook4Word, SUBJECT_BEGIN_STRING, SUBJECT_BEGIN_STRING_LENGTH ) ) + { + SizeOfKeyWord = SUBJECT_BEGIN_STRING_LENGTH; + + /* Retrieve subject */ + if( pLook4Word != pLastByteAdd ) + { + pLook4Word += SizeOfKeyWord; + pEndString = pLook4Word; + while( memcmp( pEndString, URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) ) + { + pEndString++; + } + if( ( !memcmp( pEndString, URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH ) ) || (pEndString == pLastByteAdd) ) + { + memcpy( pEmailStruct->Subject, pLook4Word, pEndString-pLook4Word ); + /* add end of string character */ + pEmailStruct->Subject[pEndString-pLook4Word] = 0; + } + pEndString += URI_SECOND_DATA_END_LENGTH; + } + } + + pLook4Word = pEndString; + + /* check if e-mail message is present */ + if( !memcmp( pLook4Word, MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ) ) + { + pEndString += MESSAGE_BEGIN_STRING_LENGTH; + /* Retrieve message */ + memcpy( pEmailStruct->Message, pEndString, PayloadSize - (pEndString - pPayload + 1) ); + /* add end of string character */ + pEmailStruct->Message[PayloadSize-(pEndString-pPayload+1)] = 0; + } +} + +/** + * @brief This function read the Email and store data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pEmailStruct : pointer on the structure to fill. + */ +static void NDEF_ReadURI_Email( sRecordInfo_email *pRecordStruct, sEmailInfo *pEmailStruct ) +{ + uint8_t* pPayload; + uint32_t PayloadSize; + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + /* Read record header */ + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + if( pRecordStruct->NDEF_Type == URI_EMAIL_TYPE ) + NDEF_FillEmailStruct( pPayload , PayloadSize, pEmailStruct ); + +} + +/** + * @} + */ + +/** @defgroup libEmail_Public_Functions + * @{ + * @brief This file is used to manage Email (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve Eamil information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pEmailStruct : pointer on the structure to fill . + * @retval NDEF_OK : Email information from NDEF have been retrieved. + * @retval NDEF_ERROR : not able to read NDEF in tag. + */ +uint16_t NDEF_ReadEmail( sRecordInfo_email *pRecordStruct, sEmailInfo *pEmailStruct ) +{ + uint16_t status = NDEF_ERROR; + sRecordInfo_email *pSPRecordStruct; + uint32_t PayloadSize, RecordPosition; + uint8_t* pData; + + + if( pRecordStruct->NDEF_Type == URI_EMAIL_TYPE ) + { + NDEF_ReadURI_Email( pRecordStruct, pEmailStruct ); + status = NDEF_OK; + } + else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE ) + { + for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ ) + { + pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition]; + if( pSPRecordStruct->NDEF_Type == URI_EMAIL_TYPE ) + { + NDEF_ReadURI_Email( pSPRecordStruct, pEmailStruct ); + status = NDEF_OK; + } + if( pSPRecordStruct->NDEF_Type == TEXT_TYPE ) + { + PayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pSPRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pSPRecordStruct->PayloadLength1) << 8) | pSPRecordStruct->PayloadLength0; + + /* The instruction content the UTF-8 language code that is not used here */ + pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd; + PayloadSize -= *pData + 1; /* remove not usefull data */ + pData += *pData + 1; + + memcpy( pEmailStruct->Information, pData, PayloadSize ); + } + } + } + + return status; +} + +/** + * @brief This function write the NDEF file with the Email data given in the structure. + * @param pEmailStruct : pointer on structure that contain the Email information. + * @retval NDEF_OK : the function is successful. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteEmail( sEmailInfo *pEmailStruct ) +{ + uint16_t status = NDEF_ERROR, Offset = 0; + + NDEF_PrepareEmailMessage( pEmailStruct, &NDEF_Buffer[FIRST_RECORD_OFFSET], &Offset ); + + /* Write NDEF */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = (Offset & 0x00FF); + + status = WriteData( 0x00, Offset + FIRST_RECORD_OFFSET, NDEF_Buffer ); + + return status; +} + +/** + * @brief This function write the NDEF file with the Email data given in the structure. + * @param pEmailStruct : pointer on structure that contain the Email information. + * @param pNDEFMessage : pointer on the NDEF message. + * @param size : to store the size of the NDEF message generated. + */ +void NDEF_PrepareEmailMessage( sEmailInfo *pEmailStruct, uint8_t *pNDEFMessage, uint16_t *size ) +{ + uint16_t Offset = 0; + uint32_t emailSize = 0; + uint32_t infoSize = 0; + uint32_t totalSize = 0; + + /* Email is an URI but can be included in a smart poster to add text to give instruction to user for instance */ + + /* Email (smart poster) Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* Email : 1+@+1+subject+1+message */ + emailSize = 1 + strlen( pEmailStruct->EmailAdd ) + URI_FIRST_DATA_END_LENGTH + SUBJECT_BEGIN_STRING_LENGTH + + strlen( pEmailStruct->Subject ) + URI_SECOND_DATA_END_LENGTH + MESSAGE_BEGIN_STRING_LENGTH + strlen( pEmailStruct->Message ); + + /* Check if a Smart poster is needed */ + if( pEmailStruct->Information[0] != '\0' ) + { + /* Info : 1+2+info */ + infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen( pEmailStruct->Information ); + /* Total */ + totalSize = 4 + emailSize + 4 + infoSize; + if( emailSize > 255 ) totalSize += 3; /* Normal Email size */ + if( infoSize > 255 ) totalSize += 3; /* Normal Info size */ + + /* SmartPoster header */ + if( totalSize > 255 ) + { + pNDEFMessage[Offset++] = 0xC1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = totalSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0xD1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)totalSize; + } + memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH ); + Offset += SMART_POSTER_TYPE_STRING_LENGTH; + } + + /* Email header */ + pNDEFMessage[Offset] = 0x81; + if( emailSize < 256 ) pNDEFMessage[Offset] |= 0x10; // Set the SR bit + if( pEmailStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit + Offset++; + + pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH; + if( emailSize > 255 ) + { + pNDEFMessage[Offset++] = (emailSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (emailSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (emailSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = emailSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = (uint8_t)emailSize; + } + memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH ); + Offset += URI_TYPE_STRING_LENGTH; + + /* Email pay load */ + pNDEFMessage[Offset++] = URI_ID_0x06; + memcpy( &pNDEFMessage[Offset], pEmailStruct->EmailAdd, strlen(pEmailStruct->EmailAdd) ); + Offset += strlen( pEmailStruct->EmailAdd ); + memcpy( &pNDEFMessage[Offset], URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ); + Offset += URI_FIRST_DATA_END_LENGTH; + + memcpy( &pNDEFMessage[Offset], SUBJECT_BEGIN_STRING, SUBJECT_BEGIN_STRING_LENGTH ); + Offset += SUBJECT_BEGIN_STRING_LENGTH; + memcpy( &pNDEFMessage[Offset], pEmailStruct->Subject, strlen(pEmailStruct->Subject) ); + Offset += strlen( pEmailStruct->Subject ); + memcpy( &pNDEFMessage[Offset], URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH ); + Offset += URI_SECOND_DATA_END_LENGTH; + + memcpy( &pNDEFMessage[Offset], MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ); + Offset += MESSAGE_BEGIN_STRING_LENGTH; + memcpy( &pNDEFMessage[Offset], pEmailStruct->Message, strlen(pEmailStruct->Message) ); + Offset += strlen( pEmailStruct->Message ); + + /* Information header */ + if( pEmailStruct->Information[0] != '\0' ) + { + if( infoSize > 255 ) + { + pNDEFMessage[Offset++] = 0x41; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = infoSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0x51; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)infoSize; + } + + memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH ); + Offset += TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */ + memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH ); + Offset += ISO_ENGLISH_CODE_STRING_LENGTH; + + /* Information payload */ + memcpy( &pNDEFMessage[Offset], pEmailStruct->Information, strlen(pEmailStruct->Information) ); + Offset += strlen( pEmailStruct->Information ); + + } + + *size = (uint16_t)(Offset); + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Email.h b/src/lib_NDEF_Email.h new file mode 100644 index 0000000..0cc893d --- /dev/null +++ b/src/lib_NDEF_Email.h @@ -0,0 +1,64 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Email.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage Email NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_EMAIL_H +#define __LIB_NDEF_EMAIL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +/* "mailto:customer.service@st.com?subject=M24SR S/N 754FHFGJF46G329 WARRANTY&body=this is an auomatic warranty activation email" */ + +typedef struct +{ + char EmailAdd[64]; + char Subject[100]; + char Message[2000]; + char Information[400]; +}sEmailInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_email; + +uint16_t NDEF_ReadEmail( sRecordInfo_email *pRecordStruct, sEmailInfo *pEmailStruct ); +uint16_t NDEF_WriteEmail( sEmailInfo *pEmailStruct ); +void NDEF_PrepareEmailMessage( sEmailInfo *pEmailStruct, uint8_t *pNDEFMessage, uint16_t *size ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_EMAIL_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Geo.cpp b/src/lib_NDEF_Geo.cpp new file mode 100644 index 0000000..7fd4eab --- /dev/null +++ b/src/lib_NDEF_Geo.cpp @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Geo.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file that represent geolocation. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_Geo.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libGeo_Private_Functions + * @{ + */ + +static void NDEF_FillGeoStruct( uint8_t* pPayload, uint32_t PayloadSize, sGeoInfo *pGeoStruct ); +static void NDEF_ReadURI_Geo( sRecordInfo_geo *pRecordStruct, sGeoInfo *pGeoStruct ); + +/** + * @brief This function fill Geo structure with information of NDEF message. + * @param pPayload : pointer on the payload data of the NDEF message. + * @param PayloadSize : number of data in the payload. + * @param pGeoStruct : pointer on the structure to fill. + */ +static void NDEF_FillGeoStruct( uint8_t* pPayload, uint32_t PayloadSize, sGeoInfo *pGeoStruct ) +{ + uint8_t* pLastByteAdd, *pLook4Word, *pEndString; + char* pKeyWord; + uint32_t SizeOfKeyWord; + pEndString = 0; + + pKeyWord = GEO_TYPE_STRING; + SizeOfKeyWord = GEO_TYPE_STRING_LENGTH; + + /* First character force to NULL in case not matching found */ + *pGeoStruct->Latitude = 0; + *pGeoStruct->Longitude = 0; + + /* Interresting information are stored before picture if any */ + /* Moreover picture is not used in this demonstration SW */ + pLastByteAdd = (uint8_t*)(pPayload + PayloadSize); + + pLook4Word = pPayload; + while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) ) + { + pLook4Word++; + } + + /* Retrieve phone number */ + if( pLook4Word != pLastByteAdd ) + { + pLook4Word += SizeOfKeyWord; + pEndString = pLook4Word; + while( memcmp( pEndString, URI_LATITUDE_END, URI_LATITUDE_END_LENGTH ) && (pEndString < pLastByteAdd) ) + { + pEndString++; + } + if( pEndString != pLastByteAdd ) + { + memcpy( pGeoStruct->Latitude, pLook4Word, pEndString-pLook4Word ); + /* add end of string character */ + pGeoStruct->Latitude[pEndString-pLook4Word] = 0; + } + } + pEndString += URI_LATITUDE_END_LENGTH; + pLook4Word = pEndString; + + memcpy( pGeoStruct->Longitude, pEndString, PayloadSize - (pEndString - pPayload) ); + /* add end of string character */ + pGeoStruct->Longitude[PayloadSize-(pEndString-pPayload)] = 0; + +} + +/** + * @brief This function read the geoloccation information and store data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pGeoStruct : pointer on the structure to fill. + */ +static void NDEF_ReadURI_Geo( sRecordInfo_geo *pRecordStruct, sGeoInfo *pGeoStruct ) +{ + uint8_t* pPayload; + uint32_t PayloadSize; + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + /* Read record header */ + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + if( pRecordStruct->NDEF_Type == URI_GEO_TYPE ) + NDEF_FillGeoStruct( pPayload , PayloadSize, pGeoStruct ); + +} + +/** + * @} + */ + +/** @defgroup libGeo_Public_Functions + * @{ + * @brief This file is used to manage geolocation (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve Geo information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pGeoStruct : pointer on the structure to fill . + * @retval NDEF_OK : Geolocation information from NDEF have been retrieved. + * @retval NDEF_ERROR : not able to read NDEF from tag. + */ +uint16_t NDEF_ReadGeo( sRecordInfo_geo *pRecordStruct, sGeoInfo *pGeoStruct ) +{ + uint16_t status = NDEF_ERROR; + sRecordInfo_geo *pSPRecordStruct; + uint32_t PayloadSize, RecordPosition; + uint8_t* pData; + + if( pRecordStruct->NDEF_Type == URI_GEO_TYPE ) + { + NDEF_ReadURI_Geo( pRecordStruct, pGeoStruct ); + status = NDEF_OK; + } + else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE ) + { + for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ ) + { + pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition]; + if( pSPRecordStruct->NDEF_Type == URI_GEO_TYPE ) + { + NDEF_ReadURI_Geo( pSPRecordStruct, pGeoStruct ); + status = NDEF_OK; + } + if( pSPRecordStruct->NDEF_Type == TEXT_TYPE ) + { + PayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pSPRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pSPRecordStruct->PayloadLength1) << 8) | pSPRecordStruct->PayloadLength0; + + /* The instruction content the UTF-8 language code that is not used here */ + pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd; + PayloadSize -= *pData + 1; /* remove not usefull data */ + pData += *pData + 1; /* set pointer on usefull data */ + + memcpy( pGeoStruct->Information, pData, PayloadSize ); + /* add end of string character */ + pGeoStruct->Information[PayloadSize] = 0; + } + } + } + + return status; +} + +/** + * @brief This function write the NDEF file with the geolocation data given in the structure. + * @param pGeoStruct : pointer on structure that contain the geolocation information. + * @retval NDEF_OK : the function is succesful. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteGeo( sGeoInfo *pGeoStruct ) +{ + uint16_t status = NDEF_ERROR,Offset = 0; + + NDEF_PrepareGeoMessage( pGeoStruct, &NDEF_Buffer[FIRST_RECORD_OFFSET], &Offset ); + + /* Write NDEF */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = Offset & 0x00FF; + + status = WriteData( 0x00, Offset+FIRST_RECORD_OFFSET, NDEF_Buffer ); + + return status; +} + +/** + * @brief This function write the NDEF file with the geolocation data given in the structure. + * @param pGeoStruct : pointer on structure that contain the geolocation information. + * @param pNDEFMessage : pointer on the NDEF message. + * @param size : to store the size of the NDEF message generated. + */ +void NDEF_PrepareGeoMessage( sGeoInfo *pGeoStruct, uint8_t *pNDEFMessage, uint16_t *size ) +{ + uint16_t Offset = 0; + uint32_t geoSize = 0; + uint32_t infoSize = 0; + uint32_t totalSize = 0; + + /* GEO is an URI but can be included in a smart poster to add text to give instruction to user for instance */ + + /* GEO (smart poster) Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* GEO : 1+geo:+latitude+1+longitude */ + geoSize = 1 + GEO_TYPE_STRING_LENGTH + strlen(pGeoStruct->Latitude) + URI_LATITUDE_END_LENGTH + strlen(pGeoStruct->Longitude); + + /* Check if a Smart poster is needed */ + if( pGeoStruct->Information[0] != '\0' ) + { + /* Info : 1+2+info */ + infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pGeoStruct->Information); + /* Total */ + totalSize = 4 + geoSize + 4 + infoSize; + if( geoSize > 255 ) totalSize += 3; /* Normal Geo size */ + if( infoSize > 255 ) totalSize += 3; /* Normal Info size */ + + /* SmartPoster header */ + if( totalSize > 255 ) + { + pNDEFMessage[Offset++] = 0xC1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = totalSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0xD1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)totalSize; + } + memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH ); + Offset += SMART_POSTER_TYPE_STRING_LENGTH; + } + + /* GEO header */ + pNDEFMessage[Offset] = 0x81; + if( geoSize < 256 ) pNDEFMessage[Offset] |= 0x10; // Set the SR bit + if( pGeoStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit + Offset++; + + pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH; + if( geoSize > 255 ) + { + pNDEFMessage[Offset++] = (geoSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (geoSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (geoSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = geoSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = (uint8_t)geoSize; + } + memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH ); + Offset += URI_TYPE_STRING_LENGTH; + + /* GEO payload */ + pNDEFMessage[Offset++] = URI_ID_0x00; /* URI identifier no abbreviation */ + memcpy( &pNDEFMessage[Offset], GEO_TYPE_STRING, GEO_TYPE_STRING_LENGTH ); + Offset += GEO_TYPE_STRING_LENGTH; + memcpy( &pNDEFMessage[Offset], pGeoStruct->Latitude, strlen(pGeoStruct->Latitude) ); + Offset += strlen( pGeoStruct->Latitude ); + memcpy( &pNDEFMessage[Offset], URI_LATITUDE_END, URI_LATITUDE_END_LENGTH ); + Offset += URI_LATITUDE_END_LENGTH; + memcpy( &pNDEFMessage[Offset], pGeoStruct->Longitude, strlen(pGeoStruct->Longitude) ); + Offset += strlen( pGeoStruct->Longitude ); + + /* Information header */ + if( pGeoStruct->Information[0] != '\0' ) + { + if( infoSize > 255 ) + { + pNDEFMessage[Offset++] = 0x41; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = infoSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0x51; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)infoSize; + } + + memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH ); + Offset += TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */ + memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH ); + Offset += ISO_ENGLISH_CODE_STRING_LENGTH; + + /* Information payload */ + memcpy( &pNDEFMessage[Offset], pGeoStruct->Information, strlen(pGeoStruct->Information) ); + Offset += strlen( pGeoStruct->Information ); + } + + *size = (uint16_t)(Offset); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Geo.h b/src/lib_NDEF_Geo.h new file mode 100644 index 0000000..80186fe --- /dev/null +++ b/src/lib_NDEF_Geo.h @@ -0,0 +1,61 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Geo.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage Geolocation NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_GEO_H +#define __LIB_NDEF_GEO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +typedef struct +{ + char Latitude[20]; + char Longitude[20]; + char Information[100]; +}sGeoInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_geo; + +uint16_t NDEF_ReadGeo( sRecordInfo_geo *pRecordStruct, sGeoInfo *pGeoStruct ); +uint16_t NDEF_WriteGeo( sGeoInfo *pGeoStruct ); +void NDEF_PrepareGeoMessage( sGeoInfo *pGeoStruct, uint8_t *pNDEFMessage, uint16_t *size ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_GEO_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_MyApp.cpp b/src/lib_NDEF_MyApp.cpp new file mode 100644 index 0000000..3056183 --- /dev/null +++ b/src/lib_NDEF_MyApp.cpp @@ -0,0 +1,297 @@ +/** + ****************************************************************************** + * @file lib_NDEF_MyApp.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage the NDEF file of a private application. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_MyApp.h" + + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpio... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libMyApp_Private_Functions + * @{ + */ + +static void NDEF_Extract_M24SRDiscoveryApp_Input( sRecordInfo_myapp *pRecordStruct, sMyAppInfo *pMyAppStruct ); + +/** + * @brief This function read the NDEF file and store application data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pMyAppStruct : pointer on the structure to fill. + */ +static void NDEF_Extract_M24SRDiscoveryApp_Input( sRecordInfo_myapp *pRecordStruct, sMyAppInfo *pMyAppStruct ) +{ + uint8_t* pPayload; + uint8_t* pLook4Word; + uint16_t BackGroundColor, FontColor; + uint8_t i; + + /* Read record header */ + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + /* initialize struct in case not matching found */ + for( i = 0; i < 8; i++ ) + { + /* Set the Back Color */ + pMyAppStruct->LineX[i].BackGroundColor = 0xFFFF; + /* Set the Text Color */ + pMyAppStruct->LineX[i].FontColor = 0x0000; + /* Set the line number */ + pMyAppStruct->LineX[i].LineNb = i + 1; + /* Set the line content */ + memcpy( pMyAppStruct->LineX[i].String, " ", 20 ); + } + + pLook4Word = pPayload; + + for( i = 0; i < 4; i++ ) + { + pMyAppStruct->LedBlinkConf.LedConf[i] = *pLook4Word; + pLook4Word++; + } + pMyAppStruct->LedBlinkConf.Speed = *pLook4Word; + pLook4Word++; + + for( i = 0; i < 8; i++ ) + { + /* Set the line number */ + pMyAppStruct->LineX[i].LineNb = *pLook4Word; + pLook4Word++; + /* Set the Back Color */ + BackGroundColor = (uint16_t)(*pLook4Word << 8); + BackGroundColor = BackGroundColor | (uint16_t)(*++pLook4Word ); + pMyAppStruct->LineX[i].BackGroundColor = BackGroundColor; + pLook4Word++; + /* Set the Text Color */ + FontColor = (uint16_t)(*pLook4Word << 8); + FontColor = FontColor | (uint16_t)(*++pLook4Word); + pMyAppStruct->LineX[i].FontColor = FontColor; + pLook4Word++; + /* Set the line content */ + memcpy( pMyAppStruct->LineX[i].String, (char*)pLook4Word, 20 ); + pLook4Word += 20; + } + +} + +/** + * @} + */ + +/** @defgroup libMyApp_Public_Functions + * @{ + * @brief This file is used to manage proprietary NDEF (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve Application information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pMyAppStruct : pointer on the structure to fill. + * @retval NDEF_OK : NDEF file data read in the tag. + * @retval NDEF_ERROR : not able to read NDEF in tag. + */ +uint16_t NDEF_ReadMyApp( sRecordInfo_myapp *pRecordStruct, sMyAppInfo *pMyAppStruct ) +{ + uint16_t status = NDEF_ERROR; + + if( pRecordStruct->NDEF_Type == M24SR_DISCOVERY_APP_TYPE ) + { + NDEF_Extract_M24SRDiscoveryApp_Input( pRecordStruct, pMyAppStruct ); + status = NDEF_OK; + } + else + { + status = NDEF_ERROR; + } + + return status; +} + +/** + * @brief This function write the NDEF file with the Application data given in the structure. + * @brief Only used for debug purpose in this firmware version. + * @param pMyAppStruct : pointer on structure that contain the application information. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteMyApp( sMyAppInfo *pMyAppStruct ) +{ + uint16_t status = NDEF_ERROR; + uint16_t DataSize; + uint32_t PayloadSize; + uint8_t i; + uint8_t* pPayload; + + +/* External Type Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- IL=0, CF=0 and SR=1 TNF=4 NFC Forum external type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Not Used */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ /* The payload will always be 5 + 25*8=205 bytes for this application */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ /* st.com:m24sr_discovery_democtrl */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* NDEF file must be written in 2 phases, first phase NDEF size is Null */ + NDEF_Buffer[NDEF_SIZE_OFFSET] = 0x00; + NDEF_Buffer[NDEF_SIZE_OFFSET+1] = 0x00; + + /* fill URI record header */ + NDEF_Buffer[FIRST_RECORD_OFFSET] = 0xD4; /* Record Flag */ + NDEF_Buffer[FIRST_RECORD_OFFSET+1] = M24SR_DISCOVERY_APP_STRING_LENGTH; + NDEF_Buffer[FIRST_RECORD_OFFSET+2] = 0x00; /* Will be filled at the end when payload size is known */ + + memcpy( &NDEF_Buffer[FIRST_RECORD_OFFSET+3], M24SR_DISCOVERY_APP_STRING, M24SR_DISCOVERY_APP_STRING_LENGTH ); + + pPayload = &NDEF_Buffer[FIRST_RECORD_OFFSET + 3 + M24SR_DISCOVERY_APP_STRING_LENGTH]; + PayloadSize = 0; + + /**************************************************************/ + /* BLINK CONFIG data */ + + /* led 1 blinking */ + *pPayload = 0x03; + pPayload++; + /* led 2 blinking */ + *pPayload = 0x02; + pPayload++; + /* led 3 blinking */ + *pPayload = 0x02; + pPayload++; + /* led 4 blinking */ + *pPayload = 0x03; + pPayload++; + /* speed */ + *pPayload = 0x03; + pPayload++; + + PayloadSize += 5; + + /**************************************************************/ + + /**************************************************************/ + /* SCREEN config data */ + for( i = 0; i < 8; i++ ) + { + /* Line number */ + *pPayload = (uint8_t)(i + 1); + pPayload++; + /* Background color */ + *pPayload = 0xFF; + pPayload++; + *pPayload = 0xFF; + pPayload++; + /* Font Color */ + *pPayload = 0x00; + pPayload++; + *pPayload = 0x00; + pPayload++; + /* String */ + memcpy( pPayload, "ABCDEFGHIJKLMNOPQRST", 20 ); + pPayload += 20; + + PayloadSize += 25; + + } + + NDEF_Buffer[FIRST_RECORD_OFFSET+2] = PayloadSize & 0x000000FF; + + DataSize = PayloadSize + 5 + M24SR_DISCOVERY_APP_STRING_LENGTH; + + /* Write NDEF */ + status = WriteData( 0x00, DataSize, NDEF_Buffer ); + + /* Write NDEF size to complete*/ + if( status == NDEF_OK ) + { + DataSize -= 2; /* Must not count the 2 byte that represent the NDEF size */ + NDEF_Buffer[0] = (DataSize & 0xFF00) >> 8; + NDEF_Buffer[1] = DataSize & 0x00FF; + + status = WriteData( 0x00, 2, NDEF_Buffer ); + } + + return status; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_MyApp.h b/src/lib_NDEF_MyApp.h new file mode 100644 index 0000000..ac06c83 --- /dev/null +++ b/src/lib_NDEF_MyApp.h @@ -0,0 +1,89 @@ +/** + ****************************************************************************** + * @file lib_NDEF_MyApp.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file illustrate how to use M24SR with a proprietary protocol. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_MYAPP_H +#define __LIB_NDEF_MYAPP_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +#define BLINK_CONFIG "" +#define BLINK_CONFIG_STRING_SIZE 14 +#define BLINK_CONFIG_END "<\\BLINK_CONFIG>" +#define BLINK_CONFIG_END_STRING_SIZE 15 + +#define LINE_DESCR "" +#define LINE_DESCR_STRING_SIZE 12 +#define LINE_DESCR_END "<\\LINE_DESCR>" +#define LINE_DESCR_END_STRING_SIZE 13 + +#define BLINKING_NONE 0x00 +#define BLINKING_SLOW 0x01 +#define BLINKING_MEDIUM 0x02 +#define BLINKING_FAST 0x03 + + +typedef struct +{ + uint8_t LedConf[4]; + uint8_t Speed; +}sLedBlinkConfig; + +typedef struct +{ + uint8_t LineNb; + uint16_t BackGroundColor; + uint16_t FontColor; + char String[20]; +}sLineConfig; + +typedef struct +{ + sLedBlinkConfig LedBlinkConf; + sLineConfig LineX[8]; +}sMyAppInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_myapp; + +uint16_t NDEF_ReadMyApp( sRecordInfo_myapp *pRecordStruct, sMyAppInfo *pMyAppStruct ); +uint16_t NDEF_WriteMyApp( sMyAppInfo *pMyAppStruct ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_MYAPP_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_SMS.cpp b/src/lib_NDEF_SMS.cpp new file mode 100644 index 0000000..46f0882 --- /dev/null +++ b/src/lib_NDEF_SMS.cpp @@ -0,0 +1,384 @@ +/** + ****************************************************************************** + * @file lib_NDEF_SMS.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file that represent SMS. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_SMS.h" + + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libSMS_Private_Functions + * @{ + */ + +static void NDEF_FillSMSStruct( uint8_t* pPayload, uint32_t PayloadSize, sSMSInfo *pSMSStruct ); +static void NDEF_ReadURI_SMS( sRecordInfo_sms *pRecordStruct, sSMSInfo *pSMSStruct ); + +/** + * @brief This function fill SMS structure with information of NDEF message. + * @param pPayload : pointer on the payload data of the NDEF message. + * @param PayloadSize : number of data in the payload. + * @param pSMSStruct : pointer on the structure to fill. + */ +static void NDEF_FillSMSStruct( uint8_t* pPayload, uint32_t PayloadSize, sSMSInfo *pSMSStruct ) +{ + uint8_t* pLastByteAdd, *pLook4Word, *pEndString ; + char* pKeyWord; + uint32_t SizeOfKeyWord; + pEndString = 0; + + pKeyWord = SMS_TYPE_STRING; + SizeOfKeyWord = SMS_TYPE_STRING_LENGTH; + + /* First character force to NULL in case not matching found */ + *pSMSStruct->PhoneNumber = 0; + *pSMSStruct->Message = 0; + + /* Interesting information are stored before picture if any */ + /* Moreover picture is not used in this demonstration SW */ + pLastByteAdd = (uint8_t*)(pPayload + PayloadSize); + + pLook4Word = pPayload; + while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) ) + { + pLook4Word++; + } + + /* Retrieve phone number */ + if( pLook4Word != pLastByteAdd ) + { + pLook4Word += SizeOfKeyWord; + pEndString = pLook4Word; + while( memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) ) + { + pEndString++; + } + if( pEndString != pLastByteAdd ) + { + memcpy( pSMSStruct->PhoneNumber, pLook4Word, pEndString-pLook4Word ); + /* add end of string character */ + pSMSStruct->PhoneNumber[pEndString-pLook4Word] = 0; + } + } + pEndString += URI_FIRST_DATA_END_LENGTH; + pLook4Word = pEndString; + + /* check if e-mail subject is present */ + if( !memcmp( pLook4Word, MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ) ) + { + pEndString += MESSAGE_BEGIN_STRING_LENGTH; + /* Retrieve message */ + memcpy( pSMSStruct->Message, pEndString, PayloadSize - (pEndString - pPayload) ); + /* add end of string character */ + pSMSStruct->Message[PayloadSize-(pEndString-pPayload)] = 0; + } +} + +/** + * @brief This function read the SMS and store data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pSMSStruct : pointer on the structure to fill. + */ +static void NDEF_ReadURI_SMS( sRecordInfo_sms *pRecordStruct, sSMSInfo *pSMSStruct ) +{ + uint8_t* pPayload; + uint32_t PayloadSize; + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + /* Read record header */ + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + if( pRecordStruct->NDEF_Type == URI_SMS_TYPE ) + NDEF_FillSMSStruct( pPayload , PayloadSize, pSMSStruct ); + +} + +/** + * @} + */ + +/** @defgroup libSMS_Public_Functions + * @{ + * @brief This file is used to manage SMS (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve SMS information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pSMSStruct : pointer on the structure to fill. + * @retval NDEF_OK : SMS information from NDEF have been retrieve. + * @retval NDEF_ERROR : Not able to retrieve SMS information. + */ +uint16_t NDEF_ReadSMS( sRecordInfo_sms *pRecordStruct, sSMSInfo *pSMSStruct ) +{ + uint16_t status = NDEF_ERROR; + sRecordInfo_sms *pSPRecordStruct; + uint32_t PayloadSize, RecordPosition; + uint8_t* pData; + + if( pRecordStruct->NDEF_Type == URI_SMS_TYPE ) + { + NDEF_ReadURI_SMS( pRecordStruct, pSMSStruct ); + status = NDEF_OK; + } + else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE ) + { + for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ ) + { + pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition]; + if( pSPRecordStruct->NDEF_Type == URI_SMS_TYPE ) + { + NDEF_ReadURI_SMS( pSPRecordStruct, pSMSStruct ); + status = NDEF_OK; + } + if( pSPRecordStruct->NDEF_Type == TEXT_TYPE ) + { + PayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pSPRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pSPRecordStruct->PayloadLength1) << 8) | pSPRecordStruct->PayloadLength0; + + /* The instruction content the UTF-8 language code that is not used here */ + pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd; + PayloadSize -= *pData + 1; /* remove not usefull data */ + pData += *pData + 1; /* set pointer on usefull data */ + + memcpy( pSMSStruct->Information, pData, PayloadSize ); + /* add end of string character */ + pSMSStruct->Information[PayloadSize] = 0; + } + } + } + + return status; +} + +/** + * @brief This function write the NDEF file with the SMS data given in the structure. + * @param pSMSStruct : pointer on structure that contain the SMS information. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteSMS( sSMSInfo *pSMSStruct ) +{ + uint16_t status = NDEF_ERROR, Offset = 0; + + NDEF_PrepareSMSMessage( pSMSStruct, &NDEF_Buffer[FIRST_RECORD_OFFSET], &Offset ); + + /* Write NDEF */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = Offset & 0x00FF; + + status = WriteData( 0x00, Offset + FIRST_RECORD_OFFSET, NDEF_Buffer ); + + return status; +} + +/** + * @brief This function write the NDEF file with the SMS data given in the structure. + * @param pSMSStruct : pointer on structure that contain the SMS information. + * @param pNDEFMessage : pointer on the NDEF message. + * @param size : to store the size of the NDEF message generated. + */ +void NDEF_PrepareSMSMessage( sSMSInfo *pSMSStruct, uint8_t *pNDEFMessage, uint16_t *size ) +{ + uint16_t Offset = 0; + uint32_t smsSize = 0; + uint32_t infoSize= 0; + uint32_t totalSize = 0; + + /* SMS is an URI but can be included in a smart poster to add text to give instruction to user for instance */ + + /* SMS (smart poster) Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* SMS : 1+sms:+tel+1+body=+message */ + smsSize = 1 + SMS_TYPE_STRING_LENGTH + strlen(pSMSStruct->PhoneNumber) + URI_FIRST_DATA_END_LENGTH + + MESSAGE_BEGIN_STRING_LENGTH + strlen(pSMSStruct->Message); + + /* Check if a Smart poster is needed */ + if( pSMSStruct->Information[0] != '\0' ) + { + /* Info : 1+2+info */ + infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pSMSStruct->Information); + /* Total */ + totalSize = 4 + smsSize + 4 + infoSize; + if( smsSize > 255 ) totalSize += 3; /* Normal Email size */ + if( infoSize > 255 ) totalSize += 3; /* Normal Info size */ + + /* SmartPoster header */ + if( totalSize > 255 ) + { + pNDEFMessage[Offset++] = 0xC1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = totalSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0xD1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)totalSize; + } + memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH ); + Offset += SMART_POSTER_TYPE_STRING_LENGTH; + } + + /* SMS header */ + pNDEFMessage[Offset] = 0x81; + if( smsSize < 256 ) pNDEFMessage[Offset] |= 0x10; // Set the SR bit + if( pSMSStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit + Offset++; + + pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH; + if( smsSize > 255 ) + { + pNDEFMessage[Offset++] = (smsSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (smsSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (smsSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = smsSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = (uint8_t)smsSize; + } + memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH ); + Offset += URI_TYPE_STRING_LENGTH; + + /* SMS payload */ + pNDEFMessage[Offset++] = URI_ID_0x00; + memcpy( &pNDEFMessage[Offset], SMS_TYPE_STRING, SMS_TYPE_STRING_LENGTH ); + Offset += SMS_TYPE_STRING_LENGTH; + memcpy( &pNDEFMessage[Offset], pSMSStruct->PhoneNumber, strlen(pSMSStruct->PhoneNumber) ); + Offset += strlen( pSMSStruct->PhoneNumber ); + memcpy( &pNDEFMessage[Offset], URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ); + Offset += URI_FIRST_DATA_END_LENGTH; + + memcpy( &pNDEFMessage[Offset], MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ); + Offset += MESSAGE_BEGIN_STRING_LENGTH; + memcpy( &pNDEFMessage[Offset], pSMSStruct->Message, strlen(pSMSStruct->Message) ); + Offset += strlen( pSMSStruct->Message ); + + /* Information header */ + if( pSMSStruct->Information[0] != '\0' ) + { + if( infoSize > 255 ) + { + pNDEFMessage[Offset++] = 0x41; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = infoSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0x51; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)infoSize; + } + + memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH ); + Offset += TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */ + memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH ); + Offset += ISO_ENGLISH_CODE_STRING_LENGTH; + + /* Information payload */ + memcpy( &pNDEFMessage[Offset], pSMSStruct->Information, strlen(pSMSStruct->Information) ); + Offset += strlen( pSMSStruct->Information ); + } + + *size = (uint16_t)(Offset); +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_SMS.h b/src/lib_NDEF_SMS.h new file mode 100644 index 0000000..6a54d43 --- /dev/null +++ b/src/lib_NDEF_SMS.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file lib_NDEF_SMS.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage SMS NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_SMS_H +#define __LIB_NDEF_SMS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + + +typedef struct +{ + char PhoneNumber[16]; + char Message[400]; + char Information[400]; +}sSMSInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_sms; + +uint16_t NDEF_ReadSMS( sRecordInfo_sms *pRecordStruct, sSMSInfo *pSMSStruct ); +uint16_t NDEF_WriteSMS( sSMSInfo *pSMSStruct ); +void NDEF_PrepareSMSMessage( sSMSInfo *pSMSStruct, uint8_t *pNDEFMessage, uint16_t *size ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_SMS_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Text.cpp b/src/lib_NDEF_Text.cpp new file mode 100644 index 0000000..ea3be3e --- /dev/null +++ b/src/lib_NDEF_Text.cpp @@ -0,0 +1,141 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Text.h + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage Text NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_Text.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** + * @} + */ + +/** @defgroup libEmail_Public_Functions + * @{ + * @brief This file is used to manage Email (stored or loaded in tag) + */ + +/** + * @brief This function write the text in the TAG. + * @param text : text to write. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteText( char *text ) +{ + uint16_t status = NDEF_ERROR; + uint32_t textSize, Offset = 0; + + NDEF_Buffer[0] = 0; + NDEF_Buffer[1] = 0; + Offset = FIRST_RECORD_OFFSET; + + /* TEXT : 1+en+message */ + textSize = 3 + strlen(text); + + /* TEXT header */ + NDEF_Buffer[Offset] = 0xD1; + if( textSize < 256 ) NDEF_Buffer[Offset] |= 0x10; // Set the SR bit + Offset++; + + NDEF_Buffer[Offset++] = TEXT_TYPE_STRING_LENGTH; + if( textSize > 255 ) + { + NDEF_Buffer[Offset++] = (textSize & 0xFF000000) >> 24; + NDEF_Buffer[Offset++] = (textSize & 0x00FF0000) >> 16; + NDEF_Buffer[Offset++] = (textSize & 0x0000FF00) >> 8; + NDEF_Buffer[Offset++] = textSize & 0x000000FF; + } + else + { + NDEF_Buffer[Offset++] = (uint8_t)textSize; + } + memcpy( &NDEF_Buffer[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH ); + Offset += TEXT_TYPE_STRING_LENGTH; + + /* TEXT payload */ + NDEF_Buffer[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; + memcpy( &NDEF_Buffer[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH ); + Offset += ISO_ENGLISH_CODE_STRING_LENGTH; + + memcpy( &NDEF_Buffer[Offset], text, strlen(text) ); + Offset += strlen(text); + + Offset -= 2; /* Must not count the 2 byte that represent the NDEF size */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = Offset & 0x00FF; + + status = WriteData( 0x00, Offset + 2, NDEF_Buffer ); + + return status; +} + + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Text.h b/src/lib_NDEF_Text.h new file mode 100644 index 0000000..40cd2b0 --- /dev/null +++ b/src/lib_NDEF_Text.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Text.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage Text NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_TEXT_H +#define __LIB_NDEF_TEXT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +uint16_t NDEF_WriteText( char *text ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_TEXT_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_URI.cpp b/src/lib_NDEF_URI.cpp new file mode 100644 index 0000000..d4d0e0f --- /dev/null +++ b/src/lib_NDEF_URI.cpp @@ -0,0 +1,554 @@ +/** + ****************************************************************************** + * @file lib_NDEF_URI.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file that represent URI. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_URI.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libURI_Private_Functions + * @{ + */ + +static void NDEF_Parse_WellKnowType( sRecordInfo_uri *pRecordStruct, sURI_Info* pURI ); + +/** + * @brief This function read the URI information and store data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pURI : pointer on the structure to fill. + */ +static void NDEF_Parse_WellKnowType( sRecordInfo_uri *pRecordStruct, sURI_Info* pURI ) +{ + uint32_t PayloadSize; + uint8_t Offset; + uint8_t* pPayload; + + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + switch( *pPayload ) + { + case URI_ID_0x01: + memcpy( pURI->protocol, URI_ID_0x01_STRING, strlen(URI_ID_0x01_STRING) ); + Offset = strlen( URI_ID_0x01_STRING ); + break; + + case URI_ID_0x02: + memcpy( pURI->protocol, URI_ID_0x02_STRING, strlen(URI_ID_0x02_STRING) ); + Offset = strlen( URI_ID_0x02_STRING ); + break; + + case URI_ID_0x03: + memcpy( pURI->protocol, URI_ID_0x03_STRING, strlen(URI_ID_0x03_STRING) ); + Offset = strlen( URI_ID_0x03_STRING ); + break; + + case URI_ID_0x04: + memcpy( pURI->protocol, URI_ID_0x04_STRING, strlen(URI_ID_0x04_STRING) ); + Offset = strlen( URI_ID_0x04_STRING ); + break; + + case URI_ID_0x05: + memcpy( pURI->protocol, URI_ID_0x05_STRING, strlen(URI_ID_0x05_STRING) ); + Offset = strlen( URI_ID_0x05_STRING ); + break; + + case URI_ID_0x06: + memcpy( pURI->protocol, URI_ID_0x06_STRING, strlen(URI_ID_0x06_STRING) ); + Offset = strlen( URI_ID_0x06_STRING ); + break; + + case URI_ID_0x07: + memcpy( pURI->protocol, URI_ID_0x07_STRING, strlen(URI_ID_0x07_STRING) ); + Offset = strlen( URI_ID_0x07_STRING ); + break; + + case URI_ID_0x08: + memcpy( pURI->protocol, URI_ID_0x08_STRING, strlen(URI_ID_0x08_STRING) ); + Offset = strlen( URI_ID_0x08_STRING ); + break; + + case URI_ID_0x09: + memcpy( pURI->protocol, URI_ID_0x09_STRING, strlen(URI_ID_0x09_STRING) ); + Offset = strlen( URI_ID_0x09_STRING ); + break; + + case URI_ID_0x0A: + memcpy( pURI->protocol, URI_ID_0x0A_STRING, strlen(URI_ID_0x0A_STRING) ); + Offset = strlen( URI_ID_0x0A_STRING ); + break; + + case URI_ID_0x0B: + memcpy( pURI->protocol, URI_ID_0x0B_STRING, strlen(URI_ID_0x0B_STRING) ); + Offset = strlen( URI_ID_0x0B_STRING ); + break; + + case URI_ID_0x0C: + memcpy( pURI->protocol, URI_ID_0x0C_STRING, strlen(URI_ID_0x0C_STRING) ); + Offset = strlen( URI_ID_0x0C_STRING ); + break; + + case URI_ID_0x0D: + memcpy( pURI->protocol, URI_ID_0x0D_STRING, strlen(URI_ID_0x0D_STRING) ); + Offset = strlen( URI_ID_0x0D_STRING ); + break; + + case URI_ID_0x0E: + memcpy( pURI->protocol, URI_ID_0x0E_STRING, strlen(URI_ID_0x0E_STRING) ); + Offset = strlen( URI_ID_0x0E_STRING ); + break; + + case URI_ID_0x0F: + memcpy( pURI->protocol, URI_ID_0x0F_STRING, strlen(URI_ID_0x0F_STRING) ); + Offset = strlen( URI_ID_0x0F_STRING ); + break; + + case URI_ID_0x10: + memcpy( pURI->protocol, URI_ID_0x10_STRING, strlen(URI_ID_0x10_STRING) ); + Offset = strlen( URI_ID_0x10_STRING ); + break; + + case URI_ID_0x11: + memcpy( pURI->protocol, URI_ID_0x11_STRING, strlen(URI_ID_0x11_STRING) ); + Offset = strlen( URI_ID_0x11_STRING ); + break; + + case URI_ID_0x12: + memcpy( pURI->protocol, URI_ID_0x12_STRING, strlen(URI_ID_0x12_STRING) ); + Offset = strlen( URI_ID_0x12_STRING ); + break; + + case URI_ID_0x13: + memcpy( pURI->protocol, URI_ID_0x13_STRING, strlen(URI_ID_0x13_STRING) ); + Offset = strlen( URI_ID_0x13_STRING ); + break; + + case URI_ID_0x14: + memcpy( pURI->protocol, URI_ID_0x14_STRING, strlen(URI_ID_0x14_STRING) ); + Offset = strlen( URI_ID_0x14_STRING ); + break; + + case URI_ID_0x15: + memcpy( pURI->protocol, URI_ID_0x15_STRING, strlen(URI_ID_0x15_STRING) ); + Offset = strlen( URI_ID_0x15_STRING ); + break; + + case URI_ID_0x16: + memcpy( pURI->protocol, URI_ID_0x16_STRING, strlen(URI_ID_0x16_STRING) ); + Offset = strlen( URI_ID_0x16_STRING ); + break; + + case URI_ID_0x17: + memcpy( pURI->protocol, URI_ID_0x17_STRING, strlen(URI_ID_0x17_STRING) ); + Offset = strlen( URI_ID_0x17_STRING ); + break; + + case URI_ID_0x18: + memcpy( pURI->protocol, URI_ID_0x18_STRING, strlen(URI_ID_0x18_STRING) ); + Offset = strlen( URI_ID_0x18_STRING ); + break; + + case URI_ID_0x19: + memcpy( pURI->protocol, URI_ID_0x19_STRING, strlen(URI_ID_0x19_STRING) ); + Offset = strlen( URI_ID_0x19_STRING ); + break; + + case URI_ID_0x1A: + memcpy( pURI->protocol, URI_ID_0x1A_STRING, strlen(URI_ID_0x1A_STRING) ); + Offset = strlen( URI_ID_0x1A_STRING ); + break; + + case URI_ID_0x1B: + memcpy( pURI->protocol, URI_ID_0x1B_STRING, strlen(URI_ID_0x1B_STRING) ); + Offset = strlen( URI_ID_0x1B_STRING ); + break; + + case URI_ID_0x1C: + memcpy( pURI->protocol, URI_ID_0x1C_STRING, strlen(URI_ID_0x1C_STRING) ); + Offset = strlen( URI_ID_0x1C_STRING ); + break; + + case URI_ID_0x1D: + memcpy( pURI->protocol, URI_ID_0x1D_STRING, strlen(URI_ID_0x1D_STRING) ); + Offset = strlen( URI_ID_0x1D_STRING ); + break; + + case URI_ID_0x1E: + memcpy( pURI->protocol, URI_ID_0x1E_STRING, strlen(URI_ID_0x1E_STRING) ); + Offset = strlen( URI_ID_0x1E_STRING ); + break; + + case URI_ID_0x1F: + memcpy( pURI->protocol, URI_ID_0x1F_STRING, strlen(URI_ID_0x1F_STRING) ); + Offset = strlen( URI_ID_0x1F_STRING ); + break; + + case URI_ID_0x20: + memcpy( pURI->protocol, URI_ID_0x20_STRING, strlen(URI_ID_0x20_STRING) ); + Offset = strlen( URI_ID_0x20_STRING ); + break; + + case URI_ID_0x21: + memcpy( pURI->protocol, URI_ID_0x21_STRING, strlen(URI_ID_0x21_STRING) ); + Offset = strlen( URI_ID_0x21_STRING ); + break; + + case URI_ID_0x22: + memcpy( pURI->protocol, URI_ID_0x22_STRING, strlen(URI_ID_0x22_STRING) ); + Offset = strlen( URI_ID_0x22_STRING ); + break; + + case URI_ID_0x23: + memcpy( pURI->protocol, URI_ID_0x23_STRING, strlen(URI_ID_0x23_STRING) ); + Offset = strlen( URI_ID_0x23_STRING ); + break; + + default: + Offset = 0; + /* Should not happened */ + break; + } + /* add end of string character */ + pURI->protocol[Offset] = '\0'; + + pPayload++; /* go after well know byte */ + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + PayloadSize = PayloadSize - 1; /* remove well know byte */ + + memcpy( pURI->URI_Message, pPayload, PayloadSize ); + /* add end of string character */ + pURI->URI_Message[PayloadSize] = '\0'; + +} + +/** + * @} + */ + +/** @defgroup libURI_Public_Functions + * @{ + * @brief This file is used to manage URI (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve URI information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pURI : pointer on the structure to fill. + * @retval NDEF_OK : URI information from NDEF have been retrieved. + * @retval NDEF_ERROR : Not able to retrieve URI information. + */ +uint16_t NDEF_ReadURI( sRecordInfo_uri *pRecordStruct, sURI_Info *pURI ) +{ + uint16_t status = NDEF_ERROR; + sRecordInfo_uri *pSPRecordStruct; + uint32_t PayloadSize, RecordPosition; + uint8_t* pData; + + if( pRecordStruct->NDEF_Type == WELL_KNOWN_ABRIDGED_URI_TYPE ) + { + NDEF_Parse_WellKnowType( pRecordStruct, pURI ); + status = NDEF_OK; + } + else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE ) + { + for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ ) + { + pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition]; + if( pSPRecordStruct->NDEF_Type == WELL_KNOWN_ABRIDGED_URI_TYPE ) + { + NDEF_Parse_WellKnowType( pSPRecordStruct, pURI ); + status = NDEF_OK; + } + if( pSPRecordStruct->NDEF_Type == TEXT_TYPE ) + { + PayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pSPRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pSPRecordStruct->PayloadLength1) << 8) | pSPRecordStruct->PayloadLength0; + + /* The instruction content the UTF-8 language code that is not used here */ + pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd; + PayloadSize -= *pData + 1; /* remove not usefull data */ + pData += *pData + 1; + + memcpy( pURI->Information, pData, PayloadSize ); + } + } + } + else + { + status = NDEF_ERROR; + } + + return status; +} + +/** + * @brief This function prepare the NDEF message with the URI data given in the structure. + * @param pURI : pointer on structure that contain the URI information. + * @param pNDEFMessage : pointer on the NDEF message. + * @param size : to store the size of the NDEF message generated. + */ +void NDEF_PrepareURIMessage( sURI_Info *pURI, uint8_t *pNDEFMessage, uint16_t *size ) +{ + uint32_t uriSize, totalSize, Offset = 0; + uint32_t infoSize = 0; + char type; + + /* An URI can be included in a smart poster to add text to give instruction to user for instance */ + + /* URI (smart poster) Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ /* <---- Used only if SR=0 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* We need to know the URI type in order to define if an abreviation is available */ + type = getUriType( pURI->protocol ); + + /* URI : 1+URI for abreviate protocol*/ + if( type != URI_ID_0x00 ) + uriSize = 1 + strlen(pURI->URI_Message); + else /*: 1+protocol+URI else*/ + uriSize = 1 + strlen(pURI->protocol) + strlen(pURI->URI_Message); + + /* Check if a Smart poster is needed */ + if( pURI->Information[0] != '\0' ) + { + /* Info : 1+2+info */ + infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pURI->Information); + /* Total */ + totalSize = 4 + uriSize + 4 + infoSize; + if( uriSize > 255 ) totalSize += 3; /* Normal URI size */ + if( infoSize > 255 ) totalSize += 3; /* Normal Info size */ + + /* SmartPoster header */ + if( totalSize > 255 ) + { + pNDEFMessage[Offset++] = 0xC1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = totalSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0xD1; + pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)totalSize; + } + memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH ); + Offset += SMART_POSTER_TYPE_STRING_LENGTH; + } + + /* URI header */ + pNDEFMessage[Offset] = 0x81; + if( uriSize < 256 ) pNDEFMessage[Offset] |= 0x10; // Set the SR bit + if( pURI->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit + Offset++; + + pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH; + if( uriSize > 255 ) + { + pNDEFMessage[Offset++] = (uriSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (uriSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (uriSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = uriSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = (uint8_t)uriSize; + } + memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH ); + Offset += URI_TYPE_STRING_LENGTH; + + pNDEFMessage[Offset++] = type; + if( type == URI_ID_0x00 ) // No abreviation + { + memcpy( &pNDEFMessage[Offset], pURI->protocol, strlen(pURI->protocol) ); + Offset += strlen(pURI->protocol); + } + + memcpy( &pNDEFMessage[Offset], pURI->URI_Message, strlen(pURI->URI_Message) ); + Offset += strlen(pURI->URI_Message); + + /* Information header */ + if( pURI->Information[0] != '\0' ) + { + if( infoSize > 255 ) + { + pNDEFMessage[Offset++] = 0x41; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24; + pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16; + pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8; + pNDEFMessage[Offset++] = infoSize & 0x000000FF; + } + else + { + pNDEFMessage[Offset++] = 0x51; + pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = (uint8_t)infoSize; + } + + memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH ); + Offset+=TEXT_TYPE_STRING_LENGTH; + pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */ + memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH ); + Offset += ISO_ENGLISH_CODE_STRING_LENGTH; + + /* Information payload */ + memcpy( &pNDEFMessage[Offset], pURI->Information, strlen(pURI->Information) ); + Offset += strlen(pURI->Information); + } + + *size = Offset; + +} +/** + * @brief This function write the NDEF file with the URI data given in the structure. + * @param pURI : pointer on structure that contain the URI information. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteURI( sURI_Info *pURI ) +{ + uint16_t status = NDEF_ERROR, Offset = 0; + + NDEF_PrepareURIMessage( pURI, &NDEF_Buffer[FIRST_RECORD_OFFSET], &Offset ); + + /* Write NDEF */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = Offset & 0x00FF; + + status = WriteData( 0x00, Offset + FIRST_RECORD_OFFSET, NDEF_Buffer ); + + return status; +} + +char getUriType( char *protocol ) +{ + if( !memcmp( protocol, URI_ID_0x01_STRING, strlen(URI_ID_0x01_STRING) ) ) return URI_ID_0x01; + else if( !memcmp( protocol, URI_ID_0x02_STRING, strlen(URI_ID_0x02_STRING) ) ) return URI_ID_0x02; + else if( !memcmp( protocol, URI_ID_0x03_STRING, strlen(URI_ID_0x03_STRING) ) ) return URI_ID_0x03; + else if( !memcmp( protocol, URI_ID_0x04_STRING, strlen(URI_ID_0x04_STRING) ) ) return URI_ID_0x04; + else if( !memcmp( protocol, URI_ID_0x05_STRING, strlen(URI_ID_0x05_STRING) ) ) return URI_ID_0x05; + else if( !memcmp( protocol, URI_ID_0x06_STRING, strlen(URI_ID_0x06_STRING) ) ) return URI_ID_0x06; + else if( !memcmp( protocol, URI_ID_0x07_STRING, strlen(URI_ID_0x07_STRING) ) ) return URI_ID_0x07; + else if( !memcmp( protocol, URI_ID_0x08_STRING, strlen(URI_ID_0x08_STRING) ) ) return URI_ID_0x08; + else if( !memcmp( protocol, URI_ID_0x09_STRING, strlen(URI_ID_0x09_STRING) ) ) return URI_ID_0x09; + else if( !memcmp( protocol, URI_ID_0x0A_STRING, strlen(URI_ID_0x0A_STRING) ) ) return URI_ID_0x0A; + else if( !memcmp( protocol, URI_ID_0x0B_STRING, strlen(URI_ID_0x0B_STRING) ) ) return URI_ID_0x0B; + else if( !memcmp( protocol, URI_ID_0x0C_STRING, strlen(URI_ID_0x0C_STRING) ) ) return URI_ID_0x0C; + else if( !memcmp( protocol, URI_ID_0x0D_STRING, strlen(URI_ID_0x0D_STRING) ) ) return URI_ID_0x0D; + else if( !memcmp( protocol, URI_ID_0x0E_STRING, strlen(URI_ID_0x0E_STRING) ) ) return URI_ID_0x0E; + else if( !memcmp( protocol, URI_ID_0x0F_STRING, strlen(URI_ID_0x0F_STRING) ) ) return URI_ID_0x0F; + else if( !memcmp( protocol, URI_ID_0x10_STRING, strlen(URI_ID_0x10_STRING) ) ) return URI_ID_0x10; + else if( !memcmp( protocol, URI_ID_0x11_STRING, strlen(URI_ID_0x11_STRING) ) ) return URI_ID_0x11; + else if( !memcmp( protocol, URI_ID_0x12_STRING, strlen(URI_ID_0x12_STRING) ) ) return URI_ID_0x12; + else if( !memcmp( protocol, URI_ID_0x13_STRING, strlen(URI_ID_0x13_STRING) ) ) return URI_ID_0x13; + else if( !memcmp( protocol, URI_ID_0x14_STRING, strlen(URI_ID_0x14_STRING) ) ) return URI_ID_0x14; + else if( !memcmp( protocol, URI_ID_0x15_STRING, strlen(URI_ID_0x15_STRING) ) ) return URI_ID_0x15; + else if( !memcmp( protocol, URI_ID_0x16_STRING, strlen(URI_ID_0x16_STRING) ) ) return URI_ID_0x16; + else if( !memcmp( protocol, URI_ID_0x17_STRING, strlen(URI_ID_0x17_STRING) ) ) return URI_ID_0x17; + else if( !memcmp( protocol, URI_ID_0x18_STRING, strlen(URI_ID_0x18_STRING) ) ) return URI_ID_0x18; + else if( !memcmp( protocol, URI_ID_0x19_STRING, strlen(URI_ID_0x19_STRING) ) ) return URI_ID_0x19; + else if( !memcmp( protocol, URI_ID_0x1A_STRING, strlen(URI_ID_0x1A_STRING) ) ) return URI_ID_0x1A; + else if( !memcmp( protocol, URI_ID_0x1B_STRING, strlen(URI_ID_0x1B_STRING) ) ) return URI_ID_0x1B; + else if( !memcmp( protocol, URI_ID_0x1C_STRING, strlen(URI_ID_0x1C_STRING) ) ) return URI_ID_0x1C; + else if( !memcmp( protocol, URI_ID_0x1D_STRING, strlen(URI_ID_0x1D_STRING) ) ) return URI_ID_0x1D; + else if( !memcmp( protocol, URI_ID_0x1E_STRING, strlen(URI_ID_0x1E_STRING) ) ) return URI_ID_0x1E; + else if( !memcmp( protocol, URI_ID_0x1F_STRING, strlen(URI_ID_0x1F_STRING) ) ) return URI_ID_0x1F; + else if( !memcmp( protocol, URI_ID_0x20_STRING, strlen(URI_ID_0x20_STRING) ) ) return URI_ID_0x20; + else if( !memcmp( protocol, URI_ID_0x21_STRING, strlen(URI_ID_0x21_STRING) ) ) return URI_ID_0x21; + else if( !memcmp( protocol, URI_ID_0x22_STRING, strlen(URI_ID_0x22_STRING) ) ) return URI_ID_0x22; + else if( !memcmp( protocol, URI_ID_0x23_STRING, strlen(URI_ID_0x23_STRING) ) ) return URI_ID_0x23; + else return URI_ID_0x00; // No abreviation for this protocol +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_URI.h b/src/lib_NDEF_URI.h new file mode 100644 index 0000000..b520ab3 --- /dev/null +++ b/src/lib_NDEF_URI.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file lib_NDEF_URI.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage URI NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_URI_H +#define __LIB_NDEF_URI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + +typedef struct +{ + char protocol[80]; + char URI_Message[400]; + char Information[400]; +}sURI_Info; + +typedef struct sRecordInfo sRecordInfo_uri; + +uint16_t NDEF_ReadURI(sRecordInfo_uri *pRecordStruct, sURI_Info *pURI); +uint16_t NDEF_WriteURI(sURI_Info *pURI); + +void NDEF_PrepareURIMessage( sURI_Info *pURI, uint8_t *pNDEFMessage, uint16_t *size ); +char getUriType( char *protocol ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_URI_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Vcard.cpp b/src/lib_NDEF_Vcard.cpp new file mode 100644 index 0000000..60550da --- /dev/null +++ b/src/lib_NDEF_Vcard.cpp @@ -0,0 +1,389 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Vcard.c + * @author MMY Application Team + * @version $Revision: 1330 $ + * @date $Date: 2015-11-05 10:39:11 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage NDEF file that represent Vcard. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF_Vcard.h" + +/** @addtogroup NFC_libraries + * @{ + * @brief This is the library used to manage the content of the TAG (data) + * But also the specific feature of the tag, for instance + * password, gpo... + */ + + +/** @addtogroup libNFC_FORUM + * @{ + * @brief This part of the library manage data which follow NFC forum organisation. + */ + +/** + * @brief This buffer contains the data send/received by TAG + */ +extern uint8_t NDEF_Buffer []; + +/** @defgroup libVcard_Private_Functions + * @{ + */ + + +static void NDEF_FillVcardStruct( uint8_t* pPayload, uint32_t PayloadSize, char* pKeyWord, uint32_t SizeOfKeyWord, uint8_t* pString ); +static void NDEF_ExtractVcard( sRecordInfo_vcard *pRecordStruct, sVcardInfo *pVcardStruct ); + +/** + * @brief This function fill Vcard structure with information of NDEF message. + * @param pPayload : pointer on the payload data of the NDEF message. + * @param PayloadSize : number of data in the payload. + * @param pKeyWord : pointer on the keyword to look for. + * @param SizeOfKeyWord : number of byte of the keyword we are looking for. + * @param pString : Pointer on the data string to fill. + */ +static void NDEF_FillVcardStruct( uint8_t* pPayload, uint32_t PayloadSize, char* pKeyWord, uint32_t SizeOfKeyWord, uint8_t* pString ) +{ + uint8_t* pLastByteAdd, *pLook4Word, *pEndString; + + /* First character force to NULL in case not matching found */ + *pString = 0; + + /* Interresting information are stored before picture if any */ + /* Moreover picture is not used in this demonstration SW */ + pLastByteAdd = pPayload; + while( memcmp( pLastByteAdd, JPEG, JPEG_STRING_SIZE ) && (pLastByteAdd < (pPayload + PayloadSize)) ) + { + pLastByteAdd++; + } + + pLook4Word = pPayload; + while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) ) + { + pLook4Word++; + } + + /* Word found */ + if( pLook4Word != pLastByteAdd ) + { + pLook4Word += SizeOfKeyWord; + pEndString = pLook4Word; + while( memcmp( pEndString, LIMIT, LIMIT_STRING_SIZE ) && (pEndString < pLastByteAdd) ) + { + pEndString++; + } + if( pEndString != pLastByteAdd ) + { + memcpy( pString, pLook4Word, pEndString-pLook4Word ); + /* add end of string character */ + pString += pEndString - pLook4Word; + *pString = '\0'; + } + } +} + +/** + * @brief This function read the Vcard and store data in a structure. + * @param pRecordStruct : Pointer on the record structure. + * @param pSMSStruct : pointer on the structure to fill. + */ +static void NDEF_ExtractVcard( sRecordInfo_vcard *pRecordStruct, sVcardInfo *pVcardStruct ) +{ + uint32_t PayloadSize; + uint8_t* pPayload; + + + PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3) << 24) | ((uint32_t)(pRecordStruct->PayloadLength2) << 16) | + ((uint32_t)(pRecordStruct->PayloadLength1) << 8) | pRecordStruct->PayloadLength0; + + /* Read record header */ + pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); + + NDEF_FillVcardStruct( pPayload, PayloadSize, VERSION, VERSION_STRING_SIZE, (uint8_t*)(pVcardStruct->Version) ); + if( !memcmp( pVcardStruct->Version, VCARD_VERSION_2_1, VCARD_VERSION_2_1_SIZE ) ) + { + NDEF_FillVcardStruct( pPayload, PayloadSize, FIRSTNAME, FIRSTNAME_STRING_SIZE, (uint8_t*)(pVcardStruct->FirstName) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, TITLE, TITLE_STRING_SIZE, (uint8_t*)(pVcardStruct->Title) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, ORG, ORG_STRING_SIZE, (uint8_t*)(pVcardStruct->Org) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_ADDRESS, HOME_ADDRESS_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeAddress) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_ADDRESS, WORK_ADDRESS_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkAddress) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_TEL, HOME_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeTel) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_TEL, WORK_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkTel) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, CELL_TEL, CELL_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->CellTel) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_EMAIL, HOME_EMAIL_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeEmail) ); + NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_EMAIL, WORK_EMAIL_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkEmail) ); + } + else if( !memcmp( pVcardStruct->Version, VCARD_VERSION_3_0, VCARD_VERSION_3_0_SIZE ) ) + { + /* need to be implemented */ + } + else + { + /* maybe new version but not supported in this sw */ + } + +} + +/** + * @} + */ + +/** @defgroup libVcard_Public_Functions + * @{ + * @brief This file is used to manage Vcard (stored or loaded in tag) + */ + +/** + * @brief This function read NDEF and retrieve Vcard information if any. + * @param pRecordStruct : Pointer on the record structure. + * @param pVcardStruct : pointer on the structure to fill. + * @retval NDEF_OK : Vcard information from NDEF have been retrieved. + * @retval NDEF_ERROR : Not able to retrieve Vcard information. + */ +uint16_t NDEF_ReadVcard( sRecordInfo_vcard *pRecordStruct, sVcardInfo *pVcardStruct ) +{ + uint16_t status = NDEF_ERROR; + + if( pRecordStruct->NDEF_Type == VCARD_TYPE ) + { + NDEF_ExtractVcard( pRecordStruct, pVcardStruct ); + status = NDEF_OK; + } + + return status; +} + +/** + * @brief This function write the NDEF file with the Vcard data given in the structure. + * @param pVcardStruct : pointer on structure that contain the Vcard information. + * @retval NDEF_OK : NDEF file data written in the tag. + * @retval NDEF_ERROR : not able to store NDEF in tag. + * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag. + * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present. + * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory. + * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write. + */ +uint16_t NDEF_WriteVcard( sVcardInfo *pVcardStruct ) +{ + uint16_t status = NDEF_ERROR, Offset = 0; + + NDEF_PrepareVcardMessage( pVcardStruct, &NDEF_Buffer[FIRST_RECORD_OFFSET], &Offset ); + + /* Write NDEF */ + NDEF_Buffer[0] = (Offset & 0xFF00) >> 8; + NDEF_Buffer[1] = Offset & 0x00FF; + + status = WriteData( 0x00, Offset + FIRST_RECORD_OFFSET, NDEF_Buffer ); + + return status; +} + +/** + * @brief This function write the NDEF file with the Vcard data given in the structure. + * @param pVcardStruct : pointer on structure that contain the Vcard information. + * @param pNDEFMessage : pointer on the NDEF message. + * @param size : to store the size of the NDEF message generated. + */ +void NDEF_PrepareVcardMessage( sVcardInfo *pVcardStruct, uint8_t *pNDEFMessage, uint16_t *size ) +{ + + uint32_t PayloadSize = 0; + + /* Vcard Record Header */ +/************************************/ +/* 7 | 6 | 5 | 4 | 3 | 2 1 0 */ +/*----------------------------------*/ +/* MB ME CF SR IL TNF */ /* <---- CF=0, IL=0 and SR=0 TNF=2 NFC Forum Media type*/ +/*----------------------------------*/ +/* TYPE LENGTH */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 3 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 2 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 1 */ +/*----------------------------------*/ +/* PAYLOAD LENGTH 0 */ +/*----------------------------------*/ +/* ID LENGTH */ /* <---- Not Used */ +/*----------------------------------*/ +/* TYPE */ +/*----------------------------------*/ +/* ID */ /* <---- Not Used */ +/************************************/ + + /* As we don't have embedded a jpeg encoder/decoder in this firmware */ + /* We have made the choice to manage only string content of the vCard */ + /* For demonstration purpose in order to fill the 8kB of the M24SR */ + /* We have embedded a NDEF vCard in the STM32 to be able to fill M24SR */ + + /* fill record header */ + pNDEFMessage[0] = 0xC2; /* Record Flag */ + pNDEFMessage[1] = VCARD_TYPE_STRING_LENGTH; + pNDEFMessage[2] = 0x00; /* Will be filled at the end when payload size is known */ + pNDEFMessage[3] = 0x00; + pNDEFMessage[4] = 0x00; + pNDEFMessage[5] = 0x00; + memcpy( &pNDEFMessage[6], VCARD_TYPE_STRING, VCARD_TYPE_STRING_LENGTH ); + + /* Payload is positionned in the NDEF after record header */ + PayloadSize = 6 + VCARD_TYPE_STRING_LENGTH; + + /* "BEGIN:VCARD\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], BEGIN, BEGIN_STRING_SIZE ); + PayloadSize += BEGIN_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], VCARD,VCARD_STRING_SIZE ); + PayloadSize += VCARD_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "VERSION:2.1\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], VERSION, VERSION_STRING_SIZE ); + PayloadSize += VERSION_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], VCARD_VERSION_2_1, VCARD_VERSION_2_1_SIZE ); + PayloadSize += VCARD_VERSION_2_1_SIZE; + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "FN:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], FIRSTNAME, FIRSTNAME_STRING_SIZE ); + PayloadSize += FIRSTNAME_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->FirstName, strlen(pVcardStruct->FirstName) ); + PayloadSize += strlen( pVcardStruct->FirstName ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "TITLE:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], TITLE, TITLE_STRING_SIZE ); + PayloadSize += TITLE_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Title, strlen(pVcardStruct->Title) ); + PayloadSize += strlen( pVcardStruct->Title ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "ORG:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], ORG, ORG_STRING_SIZE ); + PayloadSize += ORG_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Org, strlen(pVcardStruct->Org) ); + PayloadSize += strlen( pVcardStruct->Org ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "ADR;HOME:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], HOME_ADDRESS, HOME_ADDRESS_STRING_SIZE ); + PayloadSize += HOME_ADDRESS_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeAddress, strlen(pVcardStruct->HomeAddress) ); + PayloadSize += strlen( pVcardStruct->HomeAddress ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "ADR;WORK:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], WORK_ADDRESS, WORK_ADDRESS_STRING_SIZE ); + PayloadSize += WORK_ADDRESS_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkAddress, strlen(pVcardStruct->WorkAddress) ); + PayloadSize += strlen( pVcardStruct->WorkAddress ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "TEL;HOME:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], HOME_TEL, HOME_TEL_STRING_SIZE ); + PayloadSize += HOME_TEL_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeTel, strlen(pVcardStruct->HomeTel) ); + PayloadSize += strlen( pVcardStruct->HomeTel ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "TEL;WORK:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], WORK_TEL, WORK_TEL_STRING_SIZE ); + PayloadSize += WORK_TEL_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkTel, strlen(pVcardStruct->WorkTel) ); + PayloadSize += strlen( pVcardStruct->WorkTel ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "TEL;CELL:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], CELL_TEL, CELL_TEL_STRING_SIZE ); + PayloadSize += CELL_TEL_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->CellTel, strlen(pVcardStruct->CellTel) ); + PayloadSize += strlen( pVcardStruct->CellTel ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "EMAIL;HOME:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], HOME_EMAIL, HOME_EMAIL_STRING_SIZE ); + PayloadSize += HOME_EMAIL_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeEmail, strlen(pVcardStruct->HomeEmail) ); + PayloadSize += strlen( pVcardStruct->HomeEmail ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "EMAIL;WORK:\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], WORK_EMAIL, WORK_EMAIL_STRING_SIZE ); + PayloadSize += WORK_EMAIL_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkEmail, strlen(pVcardStruct->WorkEmail) ); + PayloadSize += strlen( pVcardStruct->WorkEmail ); + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + /* "END:VCARD\r\n" */ + memcpy( &pNDEFMessage[PayloadSize], END, END_STRING_SIZE ); + PayloadSize += END_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], VCARD, VCARD_STRING_SIZE ); + PayloadSize += VCARD_STRING_SIZE; + memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE ); + PayloadSize += LIMIT_STRING_SIZE; + + *size = (uint16_t)(PayloadSize); /* Must not count the 2 byte that represent the NDEF size */ + PayloadSize -= 6 + VCARD_TYPE_STRING_LENGTH; + + pNDEFMessage[2] = (PayloadSize & 0xFF000000) >> 24; + pNDEFMessage[3] = (PayloadSize & 0x00FF0000) >> 16; + pNDEFMessage[4] = (PayloadSize & 0x0000FF00) >> 8; + pNDEFMessage[5] = PayloadSize & 0x000000FF; + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_NDEF_Vcard.h b/src/lib_NDEF_Vcard.h new file mode 100644 index 0000000..7d7699b --- /dev/null +++ b/src/lib_NDEF_Vcard.h @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file lib_NDEF_Vcard.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to manage Vcard NDEF file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_NDEF_VCARD_H +#define __LIB_NDEF_VCARD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_NDEF.h" + + +#define VCARD_VERSION_2_1 "2.1" +#define VCARD_VERSION_2_1_SIZE 3 + +#define VCARD_VERSION_3_0 "3.0" +#define VCARD_VERSION_3_0_SIZE 3 + + +#define BEGIN "BEGIN:" +#define VCARD "VCARD" +#define VERSION "VERSION:" +#define FIRSTNAME "FN:" +#define HOME_TEL "TEL;HOME:" +#define WORK_TEL "TEL;WORK:" +#define CELL_TEL "TEL;CELL:" +#define HOME_EMAIL "EMAIL;HOME:" +#define WORK_EMAIL "EMAIL;WORK:" +#define HOME_ADDRESS "ADR;HOME:" +#define WORK_ADDRESS "ADR;WORK:" +#define TITLE "TITLE:" +#define ORG "ORG:" +#define END "END:" +#define JPEG "JPEG" + +#define LIMIT "\r\n" + +#define BEGIN_STRING_SIZE 6 +#define VCARD_STRING_SIZE 5 +#define VERSION_STRING_SIZE 8 +#define FIRSTNAME_STRING_SIZE 3 +#define HOME_TEL_STRING_SIZE 9 +#define WORK_TEL_STRING_SIZE 9 +#define CELL_TEL_STRING_SIZE 9 +#define HOME_EMAIL_STRING_SIZE 11 +#define WORK_EMAIL_STRING_SIZE 11 +#define HOME_ADDRESS_STRING_SIZE 9 +#define WORK_ADDRESS_STRING_SIZE 9 +#define TITLE_STRING_SIZE 6 +#define ORG_STRING_SIZE 4 +#define END_STRING_SIZE 4 +#define JPEG_STRING_SIZE 4 + +#define LIMIT_STRING_SIZE 2 + +typedef struct +{ + char Version [10]; + char FirstName[80]; + char Title[80]; + char Org[80]; + char HomeAddress[80]; + char WorkAddress[80]; + char HomeTel[40]; + char WorkTel[40]; + char CellTel[40]; + char HomeEmail[80]; + char WorkEmail[80]; +}sVcardInfo; + +/* Struct defined in lib_NDEF.h */ +typedef struct sRecordInfo sRecordInfo_vcard; + +uint16_t NDEF_ReadVcard( sRecordInfo_vcard *pRecordStruct, sVcardInfo *pVcardStruct ); +uint16_t NDEF_WriteVcard( sVcardInfo *pVcardStruct ); +void NDEF_PrepareVcardMessage( sVcardInfo *pVcardStruct, uint8_t *pNDEFMessage, uint16_t *size ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_NDEF_VCARD_H */ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso14443A.h b/src/lib_iso14443A.h new file mode 100644 index 0000000..90c36f7 --- /dev/null +++ b/src/lib_iso14443A.h @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * @file lib_iso14443A.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief ISO14443A common constants + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------------------------*/ +#ifndef __ISO14443A_H +#define __ISO14443A_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" +#include "stdbool.h" + +/* status and error code ---------------------------------------------------------------------- */ +#define ISO14443A_SUCCESSCODE RESULTOK +#define ISO14443A_ERRORCODE_DEFAULT 0x61 +#define ISO14443A_ERRORCODE_CRC 0x62 + +/* Anticollison levels (commands) ------------------------------------------------------------- */ +#define SEL_CASCADE_LVL_1 0x93 +#define SEL_CASCADE_LVL_2 0x95 +#define SEL_CASCADE_LVL_3 0x97 +#define COMMAND_REQA 0x26 +#define COMMAND_WUPA 0x52 +#define COMMAND_SELECT_LV1 0x93 +#define COMMAND_SELECT_LV2 0x95 +#define COMMAND_SELECT_LV3 0x97 +#define COMMAND_HLTA 0x50 + +#define COMMAND_RATS 0xE0 +#define COMMAND_PPS 0xD0 +#define COMMAND_DESELECT 0xC2 +#define COMMAND_DESELECTCID 0xCA + +/* Iblock ------------------------------------------------------------------------------------- */ +#define COMMAND_IBLOCK02 0x02 +#define COMMAND_IBLOCK03 0x03 +#define COMMAND_SBLOCK 0xC2 +#define COMMAND_NACKBLOCK_B2 0xB2 +#define COMMAND_NACKBLOCK_B3 0xB3 +#define COMMAND_ACKBLOCK 0xA2 + + +/* numbr of the cascade level ----------------------------------------------------------------- */ +#define CASCADE_LVL_1 1 +#define CASCADE_LVL_2 2 +#define CASCADE_LVL_3 3 + +#define ISO14443A_NVM_10 0x10 +#define ISO14443A_NVM_20 0x20 +#define ISO14443A_NVM_30 0x30 +#define ISO14443A_NVM_40 0x40 +#define ISO14443A_NVM_50 0x50 +#define ISO14443A_NVM_60 0x60 +#define ISO14443A_NVM_70 0x70 + +/* UID Sizes ---------------------------------------------------------------------------------- */ +#define ISO14443A_UIDSIZE_UNDEFINED -1 +#define ISO14443A_UID_PART 3 +#define ISO14443A_UID_SINGLE_SIZE 4 +#define ISO14443A_UID_DOUBLE_SIZE 7 +#define ISO14443A_UID_TRIPLE_SIZE 10 + + +/* Mask used for ATQA ------------------------------------------------------------------------ */ +#define ISO14443A_UID_MASK 0xC0 +#define ISO14443A_AC_BIT_FRAME_MASK 0x1F +#define ISO14443A_CID_MASK 0x0F +#define ISO14443A_FSDI_MASK 0xF0 + +/* Size for ISO14443A variables ------------------------------------------------------------- */ +#define ISO14443A_MAX_NAME_SIZE 50 +#define ISO14443A_MAX_UID_SIZE 10 +#define ISO14443A_ATQA_SIZE 2 + +/* SAK FLAG --------------------------------------------------------------------------------- */ +#define SAK_FLAG_ATS_SUPPORTED 0x20 +#define SAK_FLAG_UID_NOT_COMPLETE 0x04 + + +/* ATQ FLAG */ +#define ATQ_FLAG_UID_SINGLE_SIZE 0 +#define ATQ_FLAG_UID_DOUBLE_SIZE 1 +#define ATQ_FLAG_UID_TRIPLE_SIZE 2 + +typedef struct{ + /* ATQA answer to request of type A*/ + uint8_t ATQA[ISO14443A_ATQA_SIZE]; + uint8_t CascadeLevel; + /* UID : unique Identification*/ + uint8_t UIDsize; + uint8_t UID[ISO14443A_MAX_UID_SIZE]; + /* SAK : Select acknowledge*/ + uint8_t SAK; + bool ATSSupported; + bool IsDetected; + char LogMsg[120]; + uint8_t CID, + FSDI, + DRI, + NFC_DSI; +}ISO14443A_CARD; + +#ifdef __cplusplus +} +#endif + +#endif /* __ISO14443A_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso14443Apcd.cpp b/src/lib_iso14443Apcd.cpp new file mode 100644 index 0000000..c39dd01 --- /dev/null +++ b/src/lib_iso14443Apcd.cpp @@ -0,0 +1,993 @@ +/** + ****************************************************************************** + * @file lib_iso14443Apcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso14443A communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_iso14443Apcd.h" + +extern PCD_PROTOCOL TechnoSelected; +extern IC_VERSION IcVers; + +/* -------------------------------------------------- + * code templates for ISO14443A protocol + * command = Command code | Length | data(Le) + * -------------------------------------------------- */ +#define PCD_TYPEA_TIMERW 0x5A + +/****************** PCD ******************/ +/* ISO14443A */ +#define PCD_TYPEA_ARConfigA 0x01 +#define PCD_TYPEA_ARConfigB 0xDF + +static const uint8_t TOPAZ[] = {SEND_RECEIVE, 0x08, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8}; + +static u8 MultiID[200] = {0}; +static u8 MultiIDPart2[64] = {0}; +static u8 RemainingID = 0; + + +uint16_t FSC = 32; +uint16_t FWI = 4; /* Default value */ + + +ISO14443A_CARD ISO14443A_Card; +extern uint8_t u95HFBuffer [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; + +uint8_t u95HFBufferAntiCol [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; + +/* Variables for the different modes */ +extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +static void ISO14443A_InitStructure( void ); +static uint16_t FSCIToFSC(uint8_t FSCI); +static int8_t ISO14443A_REQA( uint8_t *pDataRead ); +static int8_t ISO14443A_HLTA( uint8_t *pDataRead ); +static int8_t ISO14443A_RATS( uint8_t *pDataRead ); +#if 0 +static int8_t ISO14443A_PPS( uint8_t *pDataRead ); +#endif +static int8_t ISO14443A_AC( uint8_t *pDataRead, u8 CascadeLevel ); +static int8_t ISO14443A_ACLevel1 ( uint8_t *pDataRead ); +static int8_t ISO14443A_ACLevel2 ( uint8_t *pDataRead ); +static int8_t ISO14443A_ACLevel3 ( uint8_t *pDataRead ); +static void ISO14443A_CompleteStructure ( uint8_t *pATQA ); +static int8_t ISO14443A_MultiAnticollision( void ); + + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + + /** @addtogroup ISO14443A_pcd + * @{ + * @brief This part of the library is used to follow ISO14443A. + */ + + +/** @addtogroup lib_iso14443Apcd_Private_Functions + * @{ + */ + + +/** + * @brief Reset the ISO14443A data structure + * @param void + * @return void + */ +static void ISO14443A_InitStructure( void ) +{ + /* Initializes the data structure used to store results */ + memset(ISO14443A_Card.ATQA, 0x00, ISO14443A_ATQA_SIZE); + memset(ISO14443A_Card.UID , 0x00, ISO14443A_MAX_UID_SIZE); + ISO14443A_Card.CascadeLevel = 0; + ISO14443A_Card.UIDsize = 0; + ISO14443A_Card.ATSSupported = false; + ISO14443A_Card.IsDetected = false; + +} + +/** + * @brief this functions convert FSCI to FSC + * @param FSCI : FSCI value + * @return FSC + */ +static uint16_t FSCIToFSC(uint8_t FSCI) +{ + if (FSCI == 0) return 16; + else if (FSCI == 1) return 24; + else if (FSCI == 2) return 32; + else if (FSCI == 3) return 40; + else if (FSCI == 4) return 48; + else if (FSCI == 5) return 64; + else if (FSCI == 6) return 96; + else if (FSCI == 7) return 128; + else return 256; +} + + +/** + * @brief this functions sends the REQA command to the PCD device + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_REQA( uint8_t *pDataRead ) +{ + const uint8_t ReqA[] = { 0x26, 0x07}; + int8_t status; + + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x02,ReqA,pDataRead)); + + /* retrieves the ATQA response */ + memcpy(ISO14443A_Card.ATQA, &pDataRead[PCD_DATA_OFFSET], ISO14443A_ATQA_SIZE); + /* completes the strucure according to the ATQA response */ + ISO14443A_CompleteStructure ( ISO14443A_Card.ATQA ); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + + +/** + * @brief This functions manage the anticollision + * @param *pDataRead : Pointer to the PCD response + * @param CascadeLevel : information on the current cascade level + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_AC( uint8_t *pDataRead, u8 CascadeLevel ) +{ + u8 AnticolParameter [7] = {0x00, ISO14443A_NVM_20, 0x08,0x00,0x00,0x00,0x00}; + u8 NbResponseByte = 0; + u8 NbResponseByteOrigin = 0; + u8 Collision = 0; + u8 ByteCollisionIndex = 0; + u8 BitCollisionIndex = 0; + + u8 RemainingBit = 0; + u8 NewByteCollisionIndex = 0; + u8 NewBitCollisionIndex = 0; + u8 UID[4] = {0x00,0x00,0x00,0x00}; + int8_t status; + + /* prepare command regarding cascade level on-going */ + AnticolParameter[0] = CascadeLevel; + + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x03,AnticolParameter,pDataRead)); + + NbResponseByte = pDataRead[1]; + NbResponseByteOrigin = NbResponseByte; + Collision = (pDataRead[NbResponseByte-1] & 0x80); + + ByteCollisionIndex = pDataRead[NbResponseByte]; + BitCollisionIndex = pDataRead[NbResponseByte+1]; + + /* case that should not happend, as occurs because we have miss another collision */ + if( BitCollisionIndex == 8) + { + return ISO14443A_ERRORCODE_DEFAULT; + } + + /* check for collision (Tag of different UID length at the same time not managed so far) */ + while( Collision == 0x80) + { + /* clear collision detection */ + Collision = 0x00; + + /* send the command to the PCD device*/ + AnticolParameter[1] = ISO14443A_NVM_20 + ((ByteCollisionIndex) <<4) + (BitCollisionIndex+1); + if( ByteCollisionIndex == 0) + { + AnticolParameter[2] = pDataRead[2] & ((u8)(~(0xFF<<(BitCollisionIndex+1)))); /* ISO said it's better to put collision bit to value 1 */ + AnticolParameter[3] = (BitCollisionIndex+1) | 0x40; /* add split frame bit */ + UID [0] = AnticolParameter[2]; + } + else if( ByteCollisionIndex == 1) + { + AnticolParameter[2] = pDataRead[2]; + AnticolParameter[3] = pDataRead[3] & ((u8)(~(0xFF<<(BitCollisionIndex+1)))); /* ISO said it's better to put collision bit to value 1 */ + AnticolParameter[4] = (BitCollisionIndex+1) | 0x40; /* add split frame bit */ + UID [0] = AnticolParameter[2]; + UID [1] = AnticolParameter[3]; + } + else if( ByteCollisionIndex == 2) + { + AnticolParameter[2] = pDataRead[2]; + AnticolParameter[3] = pDataRead[3]; + AnticolParameter[4] = pDataRead[4] & ((u8)(~(0xFF<<(BitCollisionIndex+1)))); /* ISO said it's better to put collision bit to value 1 */ + AnticolParameter[5] = (BitCollisionIndex+1) | 0x40; /* add split frame bit */; + UID [0] = AnticolParameter[2]; + UID [1] = AnticolParameter[3]; + UID [2] = AnticolParameter[4]; + } + else if( ByteCollisionIndex == 3) + { + AnticolParameter[2] = pDataRead[2]; + AnticolParameter[3] = pDataRead[3]; + AnticolParameter[4] = pDataRead[4]; + AnticolParameter[5] = pDataRead[5] & ((u8)(~(0xFF<<(BitCollisionIndex+1)))); /* ISO said it's better to put collision bit to value 1 */ + AnticolParameter[6] = (BitCollisionIndex+1) | 0x40; /* add split frame bit */; + UID [0] = AnticolParameter[2]; + UID [1] = AnticolParameter[3]; + UID [2] = AnticolParameter[4]; + UID [3] = AnticolParameter[5]; + } + else + return ISO14443A_ERRORCODE_DEFAULT; + + /* send part of the UID */ + PCD_SendRecv((0x03+ByteCollisionIndex+1),AnticolParameter,pDataRead); + + if(pDataRead[0] != 0x80) + return ISO14443A_ERRORCODE_DEFAULT; + + /* check if there is another collision to take into account*/ + NbResponseByte = pDataRead[1]; + Collision = (pDataRead[NbResponseByte-1]) & 0x80; + + if ( Collision == 0x80) + { + NewByteCollisionIndex = pDataRead[NbResponseByte]; + NewBitCollisionIndex = pDataRead[NbResponseByte+1]; + } + + /* we can check that non-alignement is the one expected */ + RemainingBit = 8 - (0x0F & (pDataRead[2+(NbResponseByte-2)-1])); + if( RemainingBit == BitCollisionIndex+1) + { + /* recreate the good UID */ + if( ByteCollisionIndex == 0) + { + UID [0] = ((~(0xFF << (BitCollisionIndex+1))) & AnticolParameter[2]) | pDataRead[2] ; + UID [1] = pDataRead[3]; + UID [2] = pDataRead[4]; + UID [3] = pDataRead[5]; + } + else if( ByteCollisionIndex == 1) + { + UID [1] = ((~(0xFF << (BitCollisionIndex+1))) & AnticolParameter[3]) | pDataRead[2] ; + UID [2] = pDataRead[3]; + UID [3] = pDataRead[4]; + } + else if( ByteCollisionIndex == 2) + { + UID [2] = ((~(0xFF << (BitCollisionIndex+1))) & AnticolParameter[4]) | pDataRead[2] ; + UID [3] = pDataRead[3]; + } + else if( ByteCollisionIndex == 3) + { + UID [3] = ((~(0xFF << (BitCollisionIndex+1))) & AnticolParameter[5]) | pDataRead[2] ; + } + else + return ISO14443A_ERRORCODE_DEFAULT; + } + else + return ISO14443A_ERRORCODE_DEFAULT; + + /* prepare the buffer expected by the caller */ + pDataRead[0] = 0x80; + pDataRead[1] = NbResponseByteOrigin; + pDataRead[2] = UID [0]; + pDataRead[3] = UID [1]; + pDataRead[4] = UID [2]; + pDataRead[5] = UID [3]; + pDataRead[6] = UID[0]^UID[1]^UID[2]^UID[3]; + + /* if collision was detected restart anticol */ + if ( Collision == 0x80) + { + if( ByteCollisionIndex != NewByteCollisionIndex ) + { + ByteCollisionIndex += NewByteCollisionIndex; + BitCollisionIndex = NewBitCollisionIndex; + } + else + { + ByteCollisionIndex += NewByteCollisionIndex; + BitCollisionIndex += (NewBitCollisionIndex+1); + } + } + } + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; + +} + +/** + * @brief this function carries out the first level of the anticollision + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_ACLevel1( uint8_t *pDataRead ) +{ + uint8_t *pDataToSend = &(u95HFBuffer[PCD_DATA_OFFSET]), + Length = 0, + BccByte ; + int8_t status; + + /* Perform anti-collision */ + errchk(ISO14443A_AC(pDataRead, SEL_CASCADE_LVL_1)); + + /* Saves the UID in the structure */ + if(ISO14443A_Card.UIDsize == ISO14443A_UID_SINGLE_SIZE) + { + memcpy( ISO14443A_Card.UID, &pDataRead[PCD_DATA_OFFSET], ISO14443A_UID_SINGLE_SIZE ); + } + else + { + memcpy(ISO14443A_Card.UID, &pDataRead[PCD_DATA_OFFSET+1], ISO14443A_UID_PART); + } + + /* copies the BCC byte of the card response*/ + BccByte = pDataRead[PCD_DATA_OFFSET + ISO14443A_UID_SINGLE_SIZE ]; + + /* Preparing the buffer who contains the SELECT command */ + pDataToSend[Length ++] = SEL_CASCADE_LVL_1; + pDataToSend[Length ++] = ISO14443A_NVM_70; + + /* Inserts the previous reply in the next command */ + if(ISO14443A_Card.UIDsize == ISO14443A_UID_SINGLE_SIZE) + { + memcpy(&pDataToSend[Length], ISO14443A_Card.UID, ISO14443A_UID_SINGLE_SIZE ); + Length += ISO14443A_UID_SINGLE_SIZE ; + } + else + { + pDataToSend[Length ++] = 0x88; + memcpy(&pDataToSend[Length], ISO14443A_Card.UID, ISO14443A_UID_PART ); + Length += ISO14443A_UID_PART ; + } + pDataToSend[Length ++] = BccByte; + /* Add the control byte : Append the CRC + 8 bits in first byte (standard frame)*/ + pDataToSend[Length ++] = PCD_ISO14443A_APPENDCRC | PCD_ISO14443A_A8BITSINFIRSTBYTE; + + errchk(PCD_SendRecv(Length,pDataToSend,pDataRead)); + + /* Recovering SAK byte */ + ISO14443A_Card.SAK = pDataRead[PCD_DATA_OFFSET]; + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +/** + * @brief this function carries out the second level of the anticollision + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_ACLevel2( uint8_t *pDataRead ) +{ + uint8_t *pDataToSend = &(u95HFBuffer[PCD_DATA_OFFSET]), + Length = 0, + BccByte ; + int8_t status; + + /* Perform anti-collision */ + errchk(ISO14443A_AC(pDataRead, SEL_CASCADE_LVL_2)); + //errchk(PCD_SendRecv(0x03,AnnticolParameter,pDataRead)); + + /* Copies the UID into the data structure */ + if(ISO14443A_Card.UIDsize == ISO14443A_UID_DOUBLE_SIZE) + { + memcpy(&ISO14443A_Card.UID[ISO14443A_UID_PART], &pDataRead[PCD_DATA_OFFSET], ISO14443A_UID_SINGLE_SIZE); + } + else + { + memcpy(&ISO14443A_Card.UID[ISO14443A_UID_PART], &pDataRead[PCD_DATA_OFFSET+1], ISO14443A_UID_PART); + } + + /* copies the BCC byte of the card response*/ + BccByte = pDataRead[PCD_DATA_OFFSET + ISO14443A_UID_SINGLE_SIZE ]; + + /* Preparing the buffer who contains the SELECT command */ + pDataToSend[Length ++] = SEL_CASCADE_LVL_2; + pDataToSend[Length ++] = ISO14443A_NVM_70; + + /* Copies the UID into the data structure */ + if(ISO14443A_Card.UIDsize == ISO14443A_UID_DOUBLE_SIZE) + { + memcpy(&(pDataToSend[Length]),&(ISO14443A_Card.UID[ISO14443A_UID_PART]) , ISO14443A_UID_SINGLE_SIZE); + Length += ISO14443A_UID_SINGLE_SIZE ; + } + else + { + pDataToSend[Length ++] = 0x88; + memcpy(&(pDataToSend[Length]),&(ISO14443A_Card.UID[ISO14443A_UID_PART]) , ISO14443A_UID_PART); + Length += ISO14443A_UID_PART ; + } + pDataToSend[Length ++] = BccByte; + /* Add the control byte : Append the CRC + 8 bits in first byte (standard frame)*/ + pDataToSend[Length ++] = PCD_ISO14443A_APPENDCRC | PCD_ISO14443A_A8BITSINFIRSTBYTE; + + /* emit the select command */ + errchk(PCD_SendRecv(Length,pDataToSend,pDataRead)); + + /* Recovering SAK byte */ + ISO14443A_Card.SAK = pDataRead[PCD_DATA_OFFSET]; + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + + +/** + * @brief this function carries out the second level of the anticollision + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_ACLevel3 ( uint8_t *pDataRead ) +{ + uint8_t *pDataToSend = &(u95HFBuffer[PCD_DATA_OFFSET]), + Length = 0, + BccByte ; + int8_t status; + + /* Perform anti-collision */ + errchk(ISO14443A_AC(pDataRead, SEL_CASCADE_LVL_3)); + + /* Copies the UID into the data structure */ + memcpy(&ISO14443A_Card.UID[ISO14443A_UID_PART], &pDataRead[PCD_DATA_OFFSET], ISO14443A_UID_SINGLE_SIZE); + /* copies the BCC byte of the card response*/ + BccByte = pDataRead[PCD_DATA_OFFSET + ISO14443A_UID_SINGLE_SIZE ]; + + /* Preparing the buffer who contains the SELECT command */ + pDataToSend[Length ++] = SEL_CASCADE_LVL_3; + pDataToSend[Length ++] = ISO14443A_NVM_70; + + /* Copies the UID into the data structure */ + if(ISO14443A_Card.UIDsize == ISO14443A_UID_TRIPLE_SIZE) + { + memcpy(&(pDataToSend[Length]),&(ISO14443A_Card.UID[ISO14443A_UID_PART]) , ISO14443A_UID_SINGLE_SIZE); + Length += ISO14443A_UID_SINGLE_SIZE ; + } + + pDataToSend[Length ++] = BccByte; + /* Add the control byte : Append the CRC + 8 bits in first byte (standard frame)*/ + pDataToSend[Length ++] = PCD_ISO14443A_APPENDCRC | PCD_ISO14443A_A8BITSINFIRSTBYTE; + + /* emitthe select command */ + errchk(PCD_SendRecv(Length,pDataToSend,pDataRead)); + + /* Recovering SAK byte */ + ISO14443A_Card.SAK = pDataRead[PCD_DATA_OFFSET]; + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +/** + * @brief this functions sends the HLTA command to the PCD device + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_HLTA( uint8_t *pDataRead ) +{ + const uint8_t pdata[]= { 0x50, 0x00, 0x28}; + + /* send the command to the PCD device*/ + PCD_SendRecv(0x03,pdata,pDataRead); + + return ISO14443A_SUCCESSCODE; + +} + + +/** + * @brief this functions emits the RATS command to PICC device + * @param *pDataRead : Pointer to the response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_RATS( uint8_t *pDataRead ) +{ + int8_t status; + uint8_t FSCI; + const uint8_t pdata[]= { 0xE0, 0x80, 0x28}; + + /* send the command to the PCD device*/ + errchk(PCD_SendRecv(0x03,pdata,pDataRead)); + /* check the status byte of the PCD device */ + errchk(PCD_IsReaderResultCodeOk (SEND_RECEIVE,pDataRead) ); + /* check the CRC */ + errchk(PCD_IsCRCOk (PCD_PROTOCOL_ISO14443A,pDataRead) ); + + FSCI = pDataRead[3]&0x0F; + FSC = FSCIToFSC(FSCI); + + /* Check if FWI is present */ + if( (pDataRead[3] & 0x20) == 0x20) + { + if( (pDataRead[3] & 0x10) == 0x10) + FWI = (pDataRead[5]&0xF0)>>4; + else + FWI = (pDataRead[4]&0xF0)>>4; + } + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +#if 0 +/** + * @brief Handles the WAKE_UP command + * @param *pDataRead : Pointer to the response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443A_PPS( uint8_t *pDataRead ) +{ + const uint8_t pdata[]= { 0xD0, 0x11, 0x00, 0x28}; + int8_t status; + + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x04,pdata,pDataRead)); + + /* checks the CRC */ + errchk(PCD_IsCRCOk (PCD_PROTOCOL_ISO14443A,pDataRead) ); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} +#endif + +/** + * @brief this function completes the ISO144443 type A structure according to the ATQA response + */ +static void ISO14443A_CompleteStructure ( uint8_t *pATQA ) +{ + + /* according to FSP ISO 11443-3 the b7&b8 bits of ATQA tag answer is UID size bit frame */ + /* Recovering the UID size */ + switch ((ISO14443A_Card.ATQA[0] & ISO14443A_UID_MASK)>>6) + { + case ATQ_FLAG_UID_SINGLE_SIZE: + ISO14443A_Card.UIDsize = ISO14443A_UID_SINGLE_SIZE; + ISO14443A_Card.CascadeLevel = CASCADE_LVL_1; + break; + case ATQ_FLAG_UID_DOUBLE_SIZE: + ISO14443A_Card.UIDsize = ISO14443A_UID_DOUBLE_SIZE; + ISO14443A_Card.CascadeLevel = CASCADE_LVL_2; + break; + case ATQ_FLAG_UID_TRIPLE_SIZE: + ISO14443A_Card.UIDsize = ISO14443A_UID_TRIPLE_SIZE; + ISO14443A_Card.CascadeLevel = CASCADE_LVL_3; + break; + } + +} + + +/** + * @brief Checks if a card is in the field + * @param None + * @return ISO14443A_SUCCESSCODE (Anticollision done) / ISO14443A_ERRORCODE_DEFAULT (Communication issue) + */ +static int8_t ISO14443A_MultiAnticollision( void ) +{ + uint8_t *pDataRead = u95HFBufferAntiCol; + int8_t status; + + + /* Checks if an error occured and execute the Anti-collision level 1*/ + errchk(ISO14443A_ACLevel1(pDataRead) ); + + /* UID Complete ? */ + if(ISO14443A_Card.SAK & SAK_FLAG_UID_NOT_COMPLETE) + { + /* Checks if an error occured and execute the Anti-collision level 2*/ + errchk(ISO14443A_ACLevel2(pDataRead) ); + } + /* UID Complete ? */ + if(ISO14443A_Card.SAK & SAK_FLAG_UID_NOT_COMPLETE) + { + /* Checks if an error occured and execute the Anti-collision level 3*/ + errchk(ISO14443A_ACLevel3(pDataRead) ); + } + + /* Quiet the founded tag */ + /* Send a HALT command */ + errchk(ISO14443A_HLTA(pDataRead) ); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; + +} + +/** + * @} + */ + + +/** @addtogroup lib_iso14443Apcd_Public_Functions + * @{ + */ + + +/** + * @brief this command initializes the PCD device for the IS014443A protocol + * @param none + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443A_Init(void) +{ + int8_t status; + + ISO14443A_InitStructure( ); + + /* sends a protocol Select command to the pcd to configure it */ + errchk(ISO14443A_ConfigFDTforAnticollision()); + + TechnoSelected = PCDPROTOCOL_14443A; + + /* GT min time to respect before sending REQ_A */ + delay(5); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; + +} + + +/** + * @brief Initializes the PCD device for the IS014443A protocol + * @param *pDataRead : Pointer to the PCD response + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +int8_t TOPAZ_ID( uint8_t *pDataRead) +{ + uint8_t Tag_error_check; + + if(PCD_CheckSendReceive(TOPAZ, pDataRead) != ISO14443A_SUCCESSCODE) + return ISO14443A_ERRORCODE_DEFAULT; + + Tag_error_check = pDataRead[RFTRANS_95HF_LENGTH_OFFSET]-1; + if((pDataRead[Tag_error_check] & ISO14443A_CRCMASK) == ISO14443A_CRC_ERRORCODE_TYPEA) + return ISO14443A_ERRORCODE_CRC; + + if(pDataRead[0] == SENDRECV_RESULTSCODE_OK && pDataRead[1] == 0x04) + return ISO14443A_ERRORCODE_DEFAULT; + + devicemode = PCD; + if (pDataRead[0] == 0x80) + nfc_tagtype = TT1; + else + return ISO14443A_ERRORCODE_DEFAULT; + + return ISO14443A_SUCCESSCODE; +} + + +/** + * @brief Checks if a ISO14443A card is in the field + * @return ISO14443A_SUCCESSCODE the function is succesful + * @return ISO14443A_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443A_IsPresent( void ) +{ + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + errchk(ISO14443A_REQA(pDataRead)); + + /* checks the status byte of the PCD device */ + errchk(PCD_IsReaderResultCodeOk (SEND_RECEIVE,pDataRead) ); + + ISO14443A_Card.IsDetected = true; + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + + + +/** + * @brief Checks if a card is in the field + * @param None + * @return ISO14443A_SUCCESSCODE (Anticollision done) / ISO14443A_ERRORCODE_DEFAULT (Communication issue) + */ +int8_t ISO14443A_Anticollision( void ) +{ + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + /* Checks if an error occured and execute the Anti-collision level 1*/ + errchk(ISO14443A_ACLevel1(pDataRead) ); + + /* UID Complete ? */ + if(ISO14443A_Card.SAK & SAK_FLAG_UID_NOT_COMPLETE) + { + /* Checks if an error occured and execute the Anti-collision level 2*/ + errchk(ISO14443A_ACLevel2(pDataRead) ); + } + /* UID Complete ? */ + if(ISO14443A_Card.SAK & SAK_FLAG_UID_NOT_COMPLETE) + { + /* Checks if an error occured and execute the Anti-collision level 2*/ + errchk(ISO14443A_ACLevel3(pDataRead) ); + } + + /* Checks if the RATS command is supported by the card */ + if(ISO14443A_Card.SAK & SAK_FLAG_ATS_SUPPORTED) + { + ISO14443A_ConfigFDTforRATS(); + + ISO14443A_Card.ATSSupported = true; + errchk(ISO14443A_RATS(pDataRead) ); + } + + /* Change the FDT to accept APDU */ + ISO14443A_ConfigFDT(1); + + devicemode = PCD; + /* Check the Tag type found */ + if ((ISO14443A_Card.SAK&0x60) == 0x00) /* TT2 */ + nfc_tagtype = TT2; + else if( (ISO14443A_Card.SAK & 0x20) == 0x20) + nfc_tagtype = TT4A; + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; + +} + +int8_t ISO14443A_ConfigFDTforAnticollision( void) +{ + u8 ProtocolSelectParameters [6] = {0x00, 0x00, 0x00, 0x00, 0x02, 0x02}; /* last 2 bytes since QJE version */ + u8 WriteRegisterParameters [2] = {PCD_TYPEA_TIMERW, TIMER_WINDOW_UPDATE_CONFIRM_CMD}; + u8 DemoGainParameters [2] = {PCD_TYPEA_ARConfigA, PCD_TYPEA_ARConfigB}; + u8 NbParam = 0; + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + if( IcVers >= QJE) + NbParam = 6; + else + NbParam = 4; + + errchk(PCD_ProtocolSelect((NbParam+1),PCD_PROTOCOL_ISO14443A,ProtocolSelectParameters,pDataRead)); + errchk(PCD_WriteRegister ( 0x04,TIMER_WINDOW_REG_ADD,0x00,WriteRegisterParameters,pDataRead)); + /* in order to adjust the demoduation gain of the PCD which is reseted at each protocol select */ + errchk(PCD_WriteRegister (0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,DemoGainParameters,u95HFBuffer)); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +int8_t ISO14443A_ConfigFDTforRATS( void) +{ + u8 ProtocolSelectParameters [6] = {0x00, 0x00, 0x00, 0x00, 0x03, 0x03}; /* last 2 bytes since QJE version */ + u8 WriteRegisterParameters [2] = {PCD_TYPEA_TIMERW, TIMER_WINDOW_UPDATE_CONFIRM_CMD}; + u8 DemoGainParameters [2] = {PCD_TYPEA_ARConfigA, PCD_TYPEA_ARConfigB}; + u8 NbParam = 0; + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + if( IcVers >= QJE) + NbParam = 6; + else + NbParam = 4; + + /* Change the PP:MM parameter to respect RATS timing TS-DP-1.1 13.8.1.1*/ + /* min to respect */ + /* FDT PCD = FWTt4at,activation = 71680 (1/fc) */ + /* (2^PP)*(MM+1)*(DD+128)*32 = 71680 ==> PP = 4 MM=0 DD=12*/ + /* max to respect not mandatory and as Tag has a FWT activation of 5.2us */ + /* adding 16.4ms does not make sense ... */ + /* FDT PCD = FWTt4at,activation + dela(t4at,poll) = 5286us + 16.4ms ~= 21.7ms */ + /* (2^PP)*(MM+1)*(DD+128)*32 = 21,7 ==> PP = 4 MM=0 DD=12*/ + ProtocolSelectParameters[1] = 4; // PP + ProtocolSelectParameters[2] = 0; // MM + ProtocolSelectParameters[3] = 12; // DD + errchk(PCD_ProtocolSelect((NbParam+1),PCD_PROTOCOL_ISO14443A,ProtocolSelectParameters,pDataRead)); + errchk(PCD_WriteRegister ( 0x04,TIMER_WINDOW_REG_ADD,0x00,WriteRegisterParameters,pDataRead)); + /* in order to adjust the demoduation gain of the PCD which is reseted at each protocol select */ + errchk(PCD_WriteRegister (0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,DemoGainParameters,u95HFBuffer)); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +int8_t ISO14443A_ConfigFDT( uint8_t WTXM) +{ + u8 ProtocolSelectParameters [6] = {0x00, 0x00, 0x00, 0x00, 0x03, 0x03}; /* last 2 bytes since QJE version */ + u8 WriteRegisterParameters [2] = {PCD_TYPEA_TIMERW, TIMER_WINDOW_UPDATE_CONFIRM_CMD}; + u8 DemoGainParameters [2] = {PCD_TYPEA_ARConfigA, PCD_TYPEA_ARConfigB}; + u8 NbParam = 0; + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + if( IcVers >= QJE) + NbParam = 6; + else + NbParam = 4; + + /* FWI was updated thanks to ATS, if not the case use default value FWI = 4 TS-DP-1.1 13.6.2.11 */ + /* FDT PCD = FWT PICC + deltaFWT(t4at) + "deltaT(t4at,poll)" TS-DP-1.1 13.8*/ + /* If we perform some identification: + FDT = (2^PP)*(MM+1)*(DD+128)*32/13.56 + FDT = (2^(PP))*(1)*(2*DD+256)*16/13.56 + (2^(PP))*(MM)*(2*DD+256)*16/13.56 + FDT = (256*16/fc)*2^FWI + ((2^FWI) *256*16*1/fc)*MM with PP=FWI and DD=0 + FDT = (2^FWI)*4096*1/fc + FWT*MM (EQUATION 1) + + I_ With the choice to NOT add deltaT(t4at,poll) = 16,4ms + 1) In the standard case (No extension time cmd received) we want + FDT = FWT + delta FWT(T4AT) + FDT = FWT + 49152 (1/fc) + + If we take the rules that we will never set FWI to a value less than 4. + (EQUATION 1 comes) + FDT = FWT*MM + 65536*1/fc => delta FWT(T4AT) is respected + + As a conclusion with + PP=FWI (with FWI>=4) + MM=1 + DD=0 + we are following the specification. + + 2) In the case of extension time request, M will take the WTXM value. */ + + if(FWI < 4 ) + FWI = 4; + + ProtocolSelectParameters[1] = FWI; // PP + ProtocolSelectParameters[2] = WTXM; // MM + ProtocolSelectParameters[3] = 0; // DD + + errchk(PCD_ProtocolSelect((NbParam+1),PCD_PROTOCOL_ISO14443A,ProtocolSelectParameters,pDataRead)); + errchk(PCD_WriteRegister ( 0x04,TIMER_WINDOW_REG_ADD,0x00,WriteRegisterParameters,pDataRead)); + /* in order to adjust the demoduation gain of the PCD which is reseted at each protocol select */ + errchk(PCD_WriteRegister (0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,DemoGainParameters,u95HFBuffer)); + + return ISO14443A_SUCCESSCODE; +Error: + return ISO14443A_ERRORCODE_DEFAULT; +} + +/** + * @brief Checks if cards are in the field + * @param *pNbTag: Number of tag detected + * @param *pUIDout: UIDs of detected tags (11 bytes by tag, first byte indicate UID size) + * @return ISO14443A_SUCCESSCODE (Anticollision done) / ISO14443A_ERRORCODE_DEFAULT (Communication issue) + */ +void ISO14443A_MultiTagHunting ( uint8_t *pNbTag, uint8_t *pUIDout ) +{ + + bool exit = false; + u8 loop = 0; + u8 i = 0; + + RemainingID = 0; + *pNbTag = 0; + + delay(5); + + ISO14443A_InitStructure(); /* only initialize structure */ + + while( exit == false && loop<= ISO14443A_NB_TAG_MAX ) + { + ISO14443A_InitStructure(); + if(ISO14443A_IsPresent() == RESULTOK) + { + delayMicroseconds (50); + if(ISO14443A_MultiAnticollision() == RESULTOK) + { + MultiID[0+((*pNbTag)*11)] = ISO14443A_Card.UIDsize; + for(i=0; i<10; i++) + { + MultiID[(1+i)+((*pNbTag)*11)] = ISO14443A_Card.UID[i]; + } + *pNbTag +=1; + } + } + else + { + /* no more tag */ + exit = true; + } + loop++; + } + + if( *pNbTag <= 5) + { + memcpy(pUIDout, &MultiID[0], (*pNbTag)*11 ); + } + else + { + memcpy(pUIDout, &MultiID[0], 5*11 ); + RemainingID = (*pNbTag-5); + memcpy(&MultiIDPart2[0], &MultiID[5*11] , RemainingID*11 ); + } + +} + + +void ISO14443A_MultiTagPart2 ( uint8_t *pNbTag, uint8_t *pUIDout ) +{ + memcpy(pUIDout, &MultiIDPart2[0], RemainingID*11); + *pNbTag = RemainingID; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso14443Apcd.h b/src/lib_iso14443Apcd.h new file mode 100644 index 0000000..4ae9760 --- /dev/null +++ b/src/lib_iso14443Apcd.h @@ -0,0 +1,129 @@ +/** + ****************************************************************************** + * @file lib_iso14443Apcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso14443A communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------------------------*/ +#ifndef __ISO14443APCD_H +#define __ISO14443APCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" +#include "lib_iso14443A.h" + +/* status and error code ---------------------------------------------------------------------- */ +#define ISO14443A_SUCCESSCODE RESULTOK +#define ISO14443A_ERRORCODE_DEFAULT 0x61 +#define ISO14443A_ERRORCODE_CRC 0x62 + + +/* Anticollison levels (commands) ------------------------------------------------------------- */ +#define SEL_CASCADE_LVL_1 0x93 +#define SEL_CASCADE_LVL_2 0x95 +#define SEL_CASCADE_LVL_3 0x97 +#define COMMAND_RATS 0xE0 +#define COMMAND_PPS 0xD0 + +/* Iblock ------------------------------------------------------------------------------------- */ +#define COMMAND_IBLOCK02 0x02 +#define COMMAND_IBLOCK03 0x03 +#define COMMAND_SBLOCK 0xC2 +#define COMMAND_NACKBLOCK 0xB2 +#define COMMAND_ACKBLOCK 0xA2 + + +/* numbr of the cascade level ----------------------------------------------------------------- */ +#define CASCADE_LVL_1 1 +#define CASCADE_LVL_2 2 +#define CASCADE_LVL_3 3 + +#define ISO14443A_NVM_10 0x10 +#define ISO14443A_NVM_20 0x20 +#define ISO14443A_NVM_30 0x30 +#define ISO14443A_NVM_40 0x40 +#define ISO14443A_NVM_50 0x50 +#define ISO14443A_NVM_60 0x60 +#define ISO14443A_NVM_70 0x70 + +/* UID Sizes ---------------------------------------------------------------------------------- */ +#define ISO14443A_UIDSIZE_UNDEFINED -1 +#define ISO14443A_UID_PART 3 +#define ISO14443A_UID_SINGLE_SIZE 4 +#define ISO14443A_UID_DOUBLE_SIZE 7 +#define ISO14443A_UID_TRIPLE_SIZE 10 + + +/* Mask used for ATQA ------------------------------------------------------------------------ */ +#define ISO14443A_UID_MASK 0xC0 +#define ISO14443A_AC_BIT_FRAME_MASK 0x1F +#define ISO14443A_CID_MASK 0x0F +#define ISO14443A_FSDI_MASK 0xF0 + +/* Size for ISO14443A variables ------------------------------------------------------------- */ +#define ISO14443A_MAX_NAME_SIZE 50 +#define ISO14443A_MAX_UID_SIZE 10 +#define ISO14443A_ATQA_SIZE 2 + +/* SAK FLAG --------------------------------------------------------------------------------- */ +#define SAK_FLAG_ATS_SUPPORTED 0x20 +#define SAK_FLAG_UID_NOT_COMPLETE 0x04 + +/* ATQ FLAG */ +#define ATQ_FLAG_UID_SINGLE_SIZE 0 +#define ATQ_FLAG_UID_DOUBLE_SIZE 1 +#define ATQ_FLAG_UID_TRIPLE_SIZE 2 + +/* MultiTag Huntig -------------------------------------------------------------------------- */ +#define ISO14443A_NB_TAG_MAX 10 + +/* --------------------------------------------------------------------------------- + * --- Local Functions + * --------------------------------------------------------------------------------- */ +void ISO14443A_Reset ( void ); +int8_t ISO14443A_Init ( void ); +int8_t ISO14443A_IsPresent ( void ); +int8_t ISO14443A_Anticollision ( void ); +int8_t TOPAZ_ID( uint8_t *pDataRead); + +/* To manage dynamicaly FDT */ +int8_t ISO14443A_ConfigFDTforAnticollision( void); +int8_t ISO14443A_ConfigFDTforRATS( void); +int8_t ISO14443A_ConfigFDT( uint8_t WTXM); + +void ISO14443A_MultiTagHunting ( uint8_t* pNbTag, uint8_t *pUIDout ); +void ISO14443A_MultiTagPart2 ( uint8_t *pNbTag, uint8_t *pUIDout ); + +#ifdef __cplusplus +} +#endif + +#endif /* __ISO14443A_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso14443Bpcd.cpp b/src/lib_iso14443Bpcd.cpp new file mode 100644 index 0000000..2ff7eac --- /dev/null +++ b/src/lib_iso14443Bpcd.cpp @@ -0,0 +1,415 @@ +/** + ****************************************************************************** + * @file lib_iso14443Bpcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso14443B communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_iso14443Bpcd.h" + +/* ISO14443B */ +#define PCD_TYPEB_ARConfigA 0x01 +#define PCD_TYPEB_ARConfigB 0x51 + +extern uint8_t u95HFBuffer [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; +extern IC_VERSION IcVers; + +/* Variables for the different modes */ +extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +extern PCD_PROTOCOL TechnoSelected; + +/* private variables -----------------------------------------------------------------*/ +ISO14443B_CARD ISO14443B_Card; + +static void ISO14443B_InitStructure ( void ); +static void ISO14443B_CompleteStruture ( uint8_t *pDataRead ); +static int8_t ISO14443B_WriteARConfigB ( void ); +static int8_t ISO14443B_WriteAndCheckARConfigB ( void ); +static int8_t ISO14443BReadARConfigB ( uint8_t *pDataRead ); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + + /** @addtogroup ISO14443B_pcd + * @{ + * @brief This part of the library is used to follow ISO14443B. + */ + + +/** @addtogroup lib_iso14443Bpcd_Private_Functions + * @{ + */ + +/** + * @brief this functions intializes the ISO14443B data structure + */ +static void ISO14443B_InitStructure(void) +{ + /* Initializes the data structure used to store results */ + memset(ISO14443B_Card.ATQB , 0x00, ISO14443B_ATQB_SIZE); + memset(ISO14443B_Card.PUPI , 0x00, ISO14443B_MAX_PUPI_SIZE); + ISO14443B_Card.IsDetected = false; + memset(ISO14443B_Card.LogMsg, 0x00, ISO14443B_MAX_LOG_MSG); +} + + +/** + * @brief this function complete the ISO14443B structure according to the REQB response + * @param *pDataRead : Pointer to the PCD response + */ +static void ISO14443B_CompleteStruture ( uint8_t *pDataRead ) +{ + + memcpy(ISO14443B_Card.ATQB, &pDataRead[PCD_DATA_OFFSET], ISO14443B_ATQB_SIZE); + /* retrieves the PUPI field */ + memcpy (ISO14443B_Card.PUPI, &(pDataRead[PCD_DATA_OFFSET + 1]),ISO14443B_MAX_PUPI_SIZE); + /* retrieves the Application data field */ + memcpy (ISO14443B_Card.ApplicationField,&(pDataRead[PCD_DATA_OFFSET + 1 + 0x04]),0x04); + /* retrieves the Application data field */ + memcpy (ISO14443B_Card.ProtocolInfo, &(pDataRead[PCD_DATA_OFFSET + 1 + 0x04 + 0x04]),0x04); +} + + +/** + * @brief this function writes the configuration registers according to AFE_SET_ANALOG_CONFIG command + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443B_WriteARConfigB(void) +{ + uint8_t SetAnalogConfigParameter [2] = { PCD_TYPEB_ARConfigA, PCD_TYPEB_ARConfigB }; + int8_t status; + uint8_t *pDataRead = u95HFBuffer; + + errchk(PCD_WriteRegister ( 0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,SetAnalogConfigParameter,pDataRead)); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + +/** + * @brief this function reads the configuration registers according to AFE_SET_ANALOG_CONFIG command + * @param *pDataRead : Pointer to the PCD response + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443BReadARConfigB (uint8_t *pDataRead ) +{ + int8_t status; + const uint8_t data = 0x01; + + /* Select the register */ + errchk(PCD_WriteRegister (0x03,AFE_ANALOG_CONF_REG_SELECTION,0x00,&data,pDataRead)); + /* Read the ARConfigA and B register */ + errchk(PCD_ReadRegister ( 0x03,AFE_ANALOG_CONF_REG_SELECTION,0x02,0x01,pDataRead)); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; + + +} + +/** + * @brief this function reads ARConfigB registers and check if it matches the requested values(in AFE_SET_ANALOG_CONFIG command) + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +static int8_t ISO14443B_WriteAndCheckARConfigB(void) +{ + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + + /* Set the Register index to ARConfigB index */ + errchk(ISO14443B_WriteARConfigB( )); + /* Read the register value */ + /* Set the Register index to ARConfigB index */ + errchk(ISO14443BReadARConfigB( pDataRead )); + /* Check ARConfig value */ + + if((pDataRead[PCD_DATA_OFFSET]== PCD_TYPEB_ARConfigA) && (pDataRead[PCD_DATA_OFFSET + 1 ] == PCD_TYPEB_ARConfigB ) ) + return ISO14443B_SUCCESSCODE; + else + return ISO14443B_ERRORCODE_DEFAULT; + +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + +/** + * @} + */ + + +/** @addtogroup lib_iso14443Bpcd_Public_Functions + * @{ + */ + +/** + * @brief Initializes the the PCD device for the IS014443B protocol + * @retval ISO14443B_SUCCESSCODE : the PCD device is well configured. + * @retval ISO14443B_ERRORCODE_DEFAULT : Communication issue. + */ +int8_t ISO14443B_Init( void ) +{ + uint8_t *pDataRead = u95HFBuffer; + int8_t status; + uint8_t * ProtocolSelectParameters; + const uint8_t ProtocolSelectParametersQJC[] = { + /* Parameters */ + PCD_ISO14443B_TRANSMISSION_SPEED_106K | + PCD_ISO14443B_RECEPTION_SPEED_106K | + PCD_ISO14443B_APPEND_CRC, + /* Set FDT */ + 0x02 , + 0x00 + }; + const uint8_t ProtocolSelectParametersQJE[] = { + /* Parameters */ + PCD_ISO14443B_TRANSMISSION_SPEED_106K | + PCD_ISO14443B_RECEPTION_SPEED_106K | + PCD_ISO14443B_APPEND_CRC, + /* PP MM bytes */ + 0x00, + 0x1A + + }; + const uint8_t Length = 0x04; + + if( IcVers < QJE) + { + ProtocolSelectParameters = (uint8_t*)(ProtocolSelectParametersQJC); + } + else + { + ProtocolSelectParameters = (uint8_t*)(ProtocolSelectParametersQJE); + } + + ISO14443B_InitStructure( ); + + /* sends a protocol Select command to the pcd to configure it */ + errchk(PCD_ProtocolSelect(Length,PCD_PROTOCOL_ISO14443B,ProtocolSelectParameters,pDataRead)); + TechnoSelected = PCDPROTOCOL_14443B; + /* update the AR register */ + errchk(ISO14443B_WriteAndCheckARConfigB ()); + + /* GT min time to respect before sending REQ_B */ + delayMicroseconds(5100); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + +/** + * @brief this function emits a REQB command to a PICC device + * @param *pDataRead : Pointer to the response + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443B_ReqB ( uint8_t *pDataRead ) +{ + int8_t status; + const uint8_t ReqB[] = { /* APf */ + ISO14443B_ANTICOLLISION_PREFIX_BYTE , + /* AFI */ + ISO14443B_AFI_ALL_FAMILIES , + /* Parameters */ + ISO14443B_EXTENDED_ATQB_NOT_SUPPORTED | + ISO14443B_REQB_ATTEMPT | + ISO14443B_SLOT_MARKER_1 + }; + + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x03,ReqB,pDataRead)); + /* Filling of the data structure */ + ISO14443B_Card.IsDetected = true; + /* complete the ISO 14443 type B strucure */ + ISO14443B_CompleteStruture (pDataRead); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; + +} + + +/** + * @brief this function complete the ISO14443B structure according to the AttriB response + * @param *pDataRead : Pointer to the PCD response + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443B_AttriB( uint8_t *pDataRead ) +{ + int8_t status; + uint8_t AttriB[ISO14443B_ATQB_SIZE] = { + /* Start byte */ + ATTRIB_FIRST_BYTE , + /* PUPI */ + 0x00 , + /* PUPI */ + 0x00 , + /* PUPI */ + 0x00 , + /* PUPI */ + 0x00 , + /* Parameter 1 */ + TR0_64_FS | + TR1_64_FS | + EOF_REQUIRED | + SOF_REQUIRED , + /* Parameter 2 */ + MAX_FRAME_SIZE_256_BYTES | + PCD_TO_PICC_106K | + PICC_TO_PCD_106K , + /* Parameter 3 */ + TR2_32_FS | + PICC_COMPLIANT_ISO14443_4 , + /* Parameter 4 */ + CID_0 + }; + + /* copies the PUPI field */ + memcpy(&AttriB[1], ISO14443B_Card.PUPI, ISO14443B_MAX_PUPI_SIZE); + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x09,AttriB,pDataRead)); + /* checks the CRC */ + errchk(PCD_IsCRCOk (PCD_PROTOCOL_ISO14443B,pDataRead) ); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + + +/** + * @brief this function checks if a card is in the field + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443B_IsPresent( void ) +{ + int8_t status; + uint8_t *pDataRead = u95HFBuffer; + + /* Init the ISO14443 TypeB communication */ + errchk(ISO14443B_Init( )); + + /* WakeUp attempt */ + errchk(ISO14443B_ReqB(pDataRead)); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + +/** + * @brief Anticolision state machine for ISO14443B cards + * @param void + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443B_Anticollision(void) +{ + int8_t status; + uint8_t *pDataRead = u95HFBuffer; + const uint8_t ProtocolSelectParameters[] = {PCD_ISO14443B_TRANSMISSION_SPEED_106K|PCD_ISO14443B_RECEPTION_SPEED_106K|PCD_ISO14443B_APPEND_CRC,0x04,0x3E}; + + /* ATTRIB attempt */ + errchk(ISO14443B_AttriB(pDataRead)); + + /* Change the PP:MM parameter to accept longer APDU timeout (2^PP)*(MM+1)*(DD+128)*32/13.56 ~= 304ms*/ + errchk(PCD_ProtocolSelect(0x04,PCD_PROTOCOL_ISO14443B,ProtocolSelectParameters,pDataRead)); + + devicemode = PCD; + nfc_tagtype = TT4B; + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + +/** + * @brief this function checks if a card is still in the field + * @retval ISO14443B_SUCCESSCODE : the function is successful. + * @retval ISO14443B_ERRORCODE_DEFAULT : an error occured + */ +int8_t ISO14443B_IsCardIntheField(void) +{ + uint8_t *pDataRead = u95HFBuffer; + const uint8_t Parameter = 0xB2; + int8_t status; + + /* sends the command to the PCD device*/ + errchk(PCD_SendRecv(0x01,&Parameter,pDataRead)); + + return ISO14443B_SUCCESSCODE; +Error: + return ISO14443B_ERRORCODE_DEFAULT; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso14443Bpcd.h b/src/lib_iso14443Bpcd.h new file mode 100644 index 0000000..36ebf77 --- /dev/null +++ b/src/lib_iso14443Bpcd.h @@ -0,0 +1,195 @@ +/** + ****************************************************************************** + * @file lib_iso14443Bpcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso14443B communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_ISO14443B_H +#define __LIB_ISO14443B_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" + +/* status and error code ---------------------------------------------------------------------- */ +#define ISO14443B_SUCCESSCODE RESULTOK +#define ISO14443B_ERRORCODE_DEFAULT 0x71 +#define ISO14443B_ERRORCODE_CRC 0x72 + + +/* REQB/WUPB command + * --------------------------------------------------- + * 1st byte | 2nd byte | 3rd byte | 4th, 5th bytes + * --------------------------------------------------- + * APf | AFI | PARAM | CRC + * --------------------------------------------------- + */ +#define ISO14443B_ANTICOLLISION_PREFIX_BYTE 0x05 +#define ISO14443B_REQB 0x05 + +#define ISO14443B_AFI_ALL_FAMILIES 0x00 /*Application Family Identifier(AFI)*/ + +/* REQB/WUPB PARAM (1 byte) + * ------------------------------------------------------------------------------------- + * RFU(3 bits) | Extended ATQB supported(1 bit) | REQB/WUPB(1 bit) | SLOT MARKER(3 bits) + * ------------------------------------------------------------------------------------- + */ +#define ISO14443B_EXTENDED_ATQB_SUPPORTED 1<<4 +#define ISO14443B_EXTENDED_ATQB_NOT_SUPPORTED 0 + +#define ISO14443B_WUPB_ATTEMPT 1<<3 +#define ISO14443B_REQB_ATTEMPT 0 + +#define ISO14443B_SLOT_MARKER_1 0 +#define ISO14443B_SLOT_MARKER_2 0x01 +#define ISO14443B_SLOT_MARKER_4 0x02 +#define ISO14443B_SLOT_MARKER_8 3<<1 +#define ISO14443B_SLOT_MARKER_16 0x04 + +/* ATTRIB command + * --------------------------------------------------------------------------------------------------------------- + * 1st byte | 2th to 5th bytes | 6th byte | 7th byte | 8th byte | 9th byte | 10th ... 'n'th bytes | (2 bytes) + * --------------------------------------------------------------------------------------------------------------- + * '1D' | Identifier(PUPI) | PARAM 1 | PARAM 2 | PARAM 3 | PARAM 4 | Higher Layer INF(opt) | CRC + * --------------------------------------------------------------------------------------------------------------- + */ +#define ATTRIB_FIRST_BYTE 0x1D + +/* ATTRIB PARAM 1 (1 byte) + * --------------------------------------------------------------------------------- + * Minimum TR0(2 bits) | Minimum TR1(2 bits) | EOF(1 bit) | SOF(1 bit) | RFU(2 bits) + * --------------------------------------------------------------------------------- + */ +#define TR0_64_FS 0 +#define TR0_32_FS 1<<6 +#define TR0_16_FS 1<<7 + +#define TR1_64_FS 0 +#define TR1_32_FS 1<<4 +#define TR1_16_FS 1<<5 + +#define SOF_REQUIRED 0 +#define SOF_NOT_REQUIRED 1<<2 + +#define EOF_REQUIRED 0 +#define EOF_NOT_REQUIRED 1<<3 + +/* ATTRIB PARAM 2 (1 byte) + * ------------------------------------------------------------------------------- + * PICC TO PCD SPEED(2 bits) | PCD TO PICC SPEED(2 bits) | MAX_FRAME_SIZE(2 bits) + * ------------------------------------------------------------------------------- + */ +#define MAX_FRAME_SIZE_16_BYTES 0 +#define MAX_FRAME_SIZE_24_BYTES 1 +#define MAX_FRAME_SIZE_32_BYTES 2 +#define MAX_FRAME_SIZE_40_BYTES 3 +#define MAX_FRAME_SIZE_48_BYTES 4 +#define MAX_FRAME_SIZE_64_BYTES 5 +#define MAX_FRAME_SIZE_96_BYTES 6 +#define MAX_FRAME_SIZE_128_BYTES 7 +#define MAX_FRAME_SIZE_256_BYTES 8 + +#define PCD_TO_PICC_106K 0 +#define PCD_TO_PICC_212K 1<<4 +#define PCD_TO_PICC_424K 1<<5 +#define PCD_TO_PICC_848K 3<<4 + +#define PICC_TO_PCD_106K 0 +#define PICC_TO_PCD_212K 1<<6 +#define PICC_TO_PCD_424K 1<<7 +#define PICC_TO_PCD_848K 3<<6 + +/* ATTRIB PARAM 3 (1 byte) + * ------------------------------------------------------- + * RFU(5 bits) | TR2 CODING(2 bits) | PROTOCOL TYPE(1 bit) + * ------------------------------------------------------- + * The least significant byte is used for confirmation of + * the protocol type recovered in the ATQB + */ +#define TR2_32_FS 0 +#define TR2_128_FS 1<<1 +#define TR2_256_FS 1<<2 +#define TR2_512_FS 3<<1 + +#define PICC_COMPLIANT_ISO14443_4 1 +#define PICC_NOT_COMPLIANT_ISO14443_4 0 + +/* ATTRIB PARAM 4 (1 byte) + * -------------------------- + * RFU(4 bits) | CID(4 bits) + * -------------------------- + */ +#define CID_0 0 +#define CID_1 1 +#define CID_2 2 +#define CID_3 3 +#define CID_4 4 +#define CID_5 5 +#define CID_6 6 +#define CID_7 7 +#define CID_8 8 +#define CID_9 9 +#define CID_10 10 +#define CID_11 11 +#define CID_12 12 +#define CID_13 13 +#define CID_14 14 + +/* Sizes of ISO14443B variables */ +#define ISO14443B_ATQB_SIZE 13 +#define ISO14443B_MAX_PUPI_SIZE 0x04 +#define ISO14443B_MAX_APPLI_SIZE 0x04 +#define ISO14443B_MAX_PROTOCOL_SIZE 0x04 +#define ISO14443B_MAX_LOG_MSG 60 + + +typedef struct{ + uint8_t ATQB[ISO14443B_ATQB_SIZE]; + uint8_t PUPI[ISO14443B_MAX_PUPI_SIZE], + ApplicationField[ISO14443B_MAX_APPLI_SIZE], + ProtocolInfo[ISO14443B_MAX_PROTOCOL_SIZE]; + bool IsDetected; + char LogMsg[ISO14443B_MAX_LOG_MSG]; +}ISO14443B_CARD; + + +int8_t ISO14443B_Init ( void ); +int8_t ISO14443B_ReqB ( uint8_t *pDataRead ); +int8_t ISO14443B_AttriB ( uint8_t *pDataRead ); +int8_t ISO14443B_IsPresent ( void ); +int8_t ISO14443B_IsCardIntheField ( void ); +int8_t ISO14443B_Anticollision ( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* __ISO14443B_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso15693pcd.cpp b/src/lib_iso15693pcd.cpp new file mode 100644 index 0000000..7a1adcd --- /dev/null +++ b/src/lib_iso15693pcd.cpp @@ -0,0 +1,1674 @@ +/** + ****************************************************************************** + * @file lib_iso15693pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of function defined into ISO15693 specification + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_iso15693pcd.h" + +/* ISO15693 */ +#define PCD_TYPEV_ARConfigA 0x01 +#define PCD_TYPEV_ARConfigB 0xD1 + + /** @ brief memory allocation for CR95Hf response */ +extern uint8_t u95HFBuffer [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; // buffer for SPI ou UART reception + +/* Variables for the different modes */ +extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +extern PCD_PROTOCOL TechnoSelected; + +/* Get functions --- */ +static int8_t ISO15693_GetSelectOrAFIFlag (const uint8_t FlagsByte); +static int8_t ISO15693_GetAddressOrNbSlotsFlag (const uint8_t FlagsByte); +static int8_t ISO15693_GetOptionFlag (const uint8_t FlagsByte); +static int8_t ISO15693_GetProtocolExtensionFlag (const uint8_t FlagsByte); +//static int8_t ISO15693_GetIcRef (uint8_t *IcRefOut); +/* Invotory functions --- */ +static int8_t ISO15693_Inventory(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *pResponse); +static int8_t ISO15693_InventoryOneSlot(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *pResponse); +static int16_t ISO15693_Inventory16Slots(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *NbTag, uint8_t *pResponse); +/* Command functions --- */ +static int8_t ISO15693_CreateRequestFlag (const uint8_t SubCarrierFlag,const uint8_t DataRateFlag,const uint8_t InventoryFlag,const uint8_t ProtExtFlag,const uint8_t SelectOrAFIFlag,const uint8_t AddrOrNbSlotFlag,const uint8_t OptionFlag,const uint8_t RFUFlag); +static int8_t ISO15693_StayQuiet(const uint8_t Flags,const uint8_t *UIDin); +static int8_t ISO15693_ReadSingleBlock(const uint8_t Flags, const uint8_t *UID, const uint16_t BlockNumber,uint8_t *pResponse); +static int8_t ISO15693_WriteSingleBlock(const uint8_t Flags, const uint8_t *UIDin, const uint16_t BlockNumber,const uint8_t *DataToWrite,uint8_t *pResponse); +static int8_t ISO15693_ReadMultipleBlock(const uint8_t Flags, const uint8_t *UIDin, uint16_t BlockNumber, const uint8_t NbBlock, uint8_t *pResponse); +static int8_t ISO15693_SendEOF(uint8_t *pResponse); +/* Is functions --- */ +static int8_t ISO15693_IsInventoryFlag (const uint8_t FlagsByte); +static int8_t ISO15693_IsAddressOrNbSlotsFlag(const uint8_t FlagsByte); +static int8_t ISO15693_IsATagInTheField(const uint8_t *pTagReply); +static int8_t ISO15693_IsCollisionDetected(const uint8_t *pTagReply); +/* CRC16 commands --- */ +static int16_t ISO15693_CRC16(const uint8_t *DataIn,const uint8_t Length); +static int8_t ISO15693_IsCorrectCRC16Residue(const uint8_t *DataIn,const uint8_t Length); +/* Tag functions --- */ +static uint8_t ISO15693_ReadMultipleTagData(uint8_t Tag_Density, uint8_t *Data_To_Read, uint16_t NbBlock_To_Read, uint16_t FirstBlock_To_Read); +static uint8_t ISO15693_ReadSingleTagData(uint8_t Tag_Density, uint8_t *Data_To_Read, uint16_t NbBlock_To_Read, uint16_t FirstBlock_To_Read); +static uint8_t ISO15693_TagSave(uint8_t Tag_Density, uint16_t NbByte_To_Write, uint16_t FirstByte_To_Write, uint8_t *Data_To_Save, uint8_t *Length_Low_Limit, uint8_t *Length_High_Limit); +static uint8_t ISO15693_WriteTagData(uint8_t Tag_Density, uint8_t *Data_To_Write, uint16_t NbBlock_To_Write, uint16_t FirstBlock_To_Write); + + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + + /** @addtogroup ISO15693_pcd + * @{ + * @brief This part of the library is used to follow ISO15693. + */ + + +/** @addtogroup lib_iso15693pcd_Private_Functions + * @{ + */ + + + +/** +* @brief this function returns Select Or AFI flag (depending on inventory flag) +* @param FlagsByte : Request flags on one byte +* @retval Select Or AFI +*/ +static int8_t ISO15693_GetSelectOrAFIFlag(const uint8_t FlagsByte) +{ + + if ((FlagsByte & ISO15693_MASK_SELECTORAFIFLAG) != 0x00) + return true ; + else + return false ; +} + +/** +* @brief this function returns address Or Number of slots flag (depending on inventory flag) +* @param FlagsByte : Request flags on one byte +* @retval address Or Number of slots +*/ +static int8_t ISO15693_GetAddressOrNbSlotsFlag(const uint8_t FlagsByte) +{ + + if ((FlagsByte & ISO15693_MASK_ADDRORNBSLOTSFLAG) != 0x00) + return true ; + else + return false ; +} + +/** +* @brief this function returns Option flag (depending on inventory flag) +* @param FlagsByte : the byts cantaining the eight flags +* @retval Option flag +*/ +static int8_t ISO15693_GetOptionFlag(const uint8_t FlagsByte) +{ + + if ((FlagsByte & ISO15693_MASK_OPTIONFLAG) != 0x00) + return true ; + else + return false ; +} + + +/** +* @brief this function returns Option flag (depending on inventory flag) +* @param FlagsByte : the byts cantaining the eight flags +* @retval Option flag +*/ +static int8_t ISO15693_GetProtocolExtensionFlag(const uint8_t FlagsByte) +{ + + if ((FlagsByte & ISO15693_MASK_PROTEXTFLAG) != 0x00) + return true ; + else + return false ; +} + + + +/** +* @brief this function return a Byte, which is concatenation of iventory flags +* @param SubCarrierFlag : +* @param DataRateFlag +* @param InventoryFlag +* @param ProtExtFlag +* @param SelectOrAFIFlag +* @param AddrOrNbSlotFlag +* @param OptionFlag +* @param RFUFlag +* @retval Flags byte +*/ +static int8_t ISO15693_CreateRequestFlag(const uint8_t SubCarrierFlag,const uint8_t DataRateFlag,const uint8_t InventoryFlag,const uint8_t ProtExtFlag,const uint8_t SelectOrAFIFlag,const uint8_t AddrOrNbSlotFlag,const uint8_t OptionFlag,const uint8_t RFUFlag) +{ +int32_t FlagsByteBuf=0; + + FlagsByteBuf = (SubCarrierFlag & 0x01) | + ((DataRateFlag & 0x01) << 1) | + ((InventoryFlag & 0x01) << 2) | + ((ProtExtFlag & 0x01) << 3) | + ((SelectOrAFIFlag & 0x01) << 4) | + ((AddrOrNbSlotFlag & 0x01) << 5) | + ((OptionFlag & 0x01) << 6) | + ((RFUFlag & 0x01) << 7); + + return (int8_t) FlagsByteBuf; +} + +/** +* @brief this function returns the tag AFI word +* @param AFIout : tag AFI read +* @retval status function +*/ +// static int8_t ISO15693_GetIcRef (uint8_t *IcRefOut) +// { +// int8_t FlagsByteData; +// uint8_t TagReply [ISO15693_MAXLENGTH_REPLYGETSYSTEMINFO+3]; +// int8_t status; + +// *IcRefOut = 0x00; +// FlagsByteData = ISO15693_CreateRequestFlag ( ISO15693_REQFLAG_SINGLESUBCARRIER, +// ISO15693_REQFLAG_HIGHDATARATE, +// ISO15693_REQFLAG_INVENTORYFLAGNOTSET, +// ISO15693_REQFLAG_NOPROTOCOLEXTENSION, +// ISO15693_REQFLAG_NOTSELECTED, +// ISO15693_REQFLAG_NOTADDRESSED, +// ISO15693_REQFLAG_OPTIONFLAGNOTSET, +// ISO15693_REQFLAG_RFUNOTSET); +// // select 15693 protocol +// errchk(ISO15693_Init ( )); + +// // Uid and CRC = 0x00 +// errchk(ISO15693_GetSystemInfo (FlagsByteData, +// 0x00, +// TagReply)); +// + +// *IcRefOut = TagReply[PCD_DATA_OFFSET + 12]; + + +// return ISO15693_SUCCESSCODE; + +// Error: +// return ISO15693_ERRORCODE_DEFAULT; + +// } + + +/** +* @brief this function send an inventory command to a contacless tag. +* @param Flags : Request flags +* @param AFI : AFI byte (optional) +* @param MaskLength : Number of bits of mask value +* @param MaskValue : mask value which is compare to Contacless tag UID +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_PARAMETERLENGTH : MaskLength value is erroneous +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_Inventory(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *pResponse) +{ +uint8_t NthByte = 0, + InventoryBuf [ISO15693_MAXLENGTH_INVENTORY], + NbMaskBytes = 0, + NbSignificantBits=0; +int8_t FirstByteMask, + NthMaskByte = 0, + status; + + // initialize the result code to 0xFF and length to 0 in case of error + *pResponse = SENDRECV_ERRORCODE_SOFT; + *(pResponse+1) = 0x00; + + if (MaskLength>ISO15693_NBBITS_MASKPARAMETER) + return ISO15693_ERRORCODE_PARAMETERLENGTH; + + errchk(ISO15693_IsInventoryFlag (Flags)); + + + InventoryBuf[NthByte++] = Flags; + InventoryBuf[NthByte++] = ISO15693_CMDCODE_INVENTORY; + + if (ISO15693_GetSelectOrAFIFlag (Flags) == true) + InventoryBuf[NthByte++] = AFI; + + InventoryBuf[NthByte++] = MaskLength; + + if (MaskLength !=0) + { + // compute the number of bytes of mask value(2 border exeptions) + if (MaskLength == 64) + NbMaskBytes = 8; + else + NbMaskBytes = MaskLength / 8 + 1; + + NbSignificantBits = MaskLength - (NbMaskBytes-1) * 8; + if (NbSignificantBits !=0) + FirstByteMask = (0x01 <1) + { + for (NthMaskByte = 0; NthMaskByte < NbMaskBytes - 1; NthMaskByte ++ ) + InventoryBuf[NthByte++] = MaskValue[NthMaskByte]; + } + + if (NbSignificantBits !=0) + InventoryBuf[NthByte++] = MaskValue[NthMaskByte] & FirstByteMask; + } + + errchk(PCD_SendRecv(NthByte,InventoryBuf,pResponse)); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) != ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +Error: + return ISO15693_ERRORCODE_DEFAULT; +} + + +/** +* @brief this function send an inventory command to a contactless tag. +* @brief The NbSlot flag of Request flags is set (1 value). +* @param Flags : Request flags +* @param AFI : AFI byte (optional) +* @param MaskLength : Number of bits of mask value +* @param MaskValue : mask value which is compare to Contacless tag UID +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_PARAMETERLENGTH : MaskLength value is erroneous +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_InventoryOneSlot(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *pResponse) +{ +int8_t NewFlags, + status; + + // force NbSlot Flag to 1; + NewFlags = Flags | ISO15693_MASK_ADDRORNBSLOTSFLAG; + + status = ISO15693_Inventory( + NewFlags , + AFI, + MaskLength, + MaskValue, + pResponse ); + + return status; +} + +/** +* @brief this function send an inventory command to a contacless tag. +* @brief The NbSlot flag of Request flags is reset (0 value). +* @param Flags : Request flags +* @param AFI : AFI byte (optional) +* @param MaskLength : Number of bits of mask value +* @param MaskValue : mask value which is compare to Contacless tag UID +* @param NbTag : Nbtag inventoried +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_PARAMETERLENGTH : MaskLength value is erroneous +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int16_t ISO15693_Inventory16Slots(const uint8_t Flags , const uint8_t AFI, const uint8_t MaskLength, const uint8_t *MaskValue, uint8_t *NbTag, uint8_t *pResponse) +{ +int8_t NthSlot = 0, + status, + NewFlags; +int16_t ReturnValue=0; +uint8_t pOneTagResponse [ISO15693_NBBYTE_UID+3+2]; + + // force NbSlot Flag to 0; + NewFlags = Flags & ~ISO15693_MASK_ADDRORNBSLOTSFLAG; + + *NbTag = 0; + status = ISO15693_Inventory( + NewFlags , + AFI, + MaskLength, + MaskValue, + pOneTagResponse ); + + + if (status == ISO15693_SUCCESSCODE && ISO15693_IsCollisionDetected (pOneTagResponse)== ISO15693_SUCCESSCODE) + ReturnValue = 0x0001; + else if (status == ISO15693_SUCCESSCODE) + { + memcpy(pResponse,pOneTagResponse,pOneTagResponse[PCD_LENGTH_OFFSET]+2); + (*NbTag)++; + + } + + + while (NthSlot++ <15 ) + { + delay(5); + + status = ISO15693_SendEOF(pOneTagResponse ); + + if (status == ISO15693_SUCCESSCODE && ISO15693_IsCollisionDetected (pOneTagResponse)== ISO15693_SUCCESSCODE) + ReturnValue |= (1<> 8; + } + + PCD_SendRecv(NthByte,DataToSend,pResponse); + +// if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) +// return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +} + + +/** +* @brief this function send an WriteSingleblock command and returns ISO15693_SUCCESSCODE if the command +* @brief was correctly emmiting, ISO15693_ERRORCODE_DEFAULT otherwise +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param BlockNumber : index of block to write +* @param BlockLength : Nb of byte of block length +* @param DataToWrite : Data to write into contacless tag memory +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_WriteSingleBlock(const uint8_t Flags, const uint8_t *UIDin, const uint16_t BlockNumber,const uint8_t *DataToWrite,uint8_t *pResponse ) +{ +uint8_t DataToSend[MAX_BUFFER_SIZE], + NthByte=0, + BlockLength = ISO15693_NBBYTE_BLOCKLENGTH; + + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_WRITESINGLEBLOCK; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == true) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + if (ISO15693_GetProtocolExtensionFlag (Flags) == false) + DataToSend[NthByte++] = BlockNumber; + else + { + DataToSend[NthByte++] = BlockNumber & 0x00FF; + DataToSend[NthByte++] = (BlockNumber & 0xFF00 ) >> 8; + + } + + memcpy(&(DataToSend[NthByte]),DataToWrite,BlockLength); + NthByte +=BlockLength; + + if (ISO15693_GetOptionFlag (Flags) == false) + PCD_SendRecv(NthByte,DataToSend,pResponse); + else + { PCD_SendRecv(NthByte,DataToSend,pResponse); + delay(20); + ISO15693_SendEOF (pResponse); + } + +// if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) +// return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; + +} + +/** +* @brief this function send an ReadSingleBlock command to contactless tag. +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param BlockNumber : index of block to read +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_ReadMultipleBlock(const uint8_t Flags, const uint8_t *UIDin, uint16_t BlockNumber, const uint8_t NbBlock, uint8_t *pResponse) +{ +uint8_t DataToSend[ISO15693_MAXLENGTH_READSINGLEBLOCK], + NthByte=0; + + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_READMULBLOCKS; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == true) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + BlockNumber=BlockNumber<<5; // *32 + if (ISO15693_GetProtocolExtensionFlag (Flags) == false) + DataToSend[NthByte++] = BlockNumber; + else + { + DataToSend[NthByte++] = BlockNumber & 0x00FF; + DataToSend[NthByte++] = (BlockNumber & 0xFF00 ) >> 8; + + } + + DataToSend[NthByte++] = NbBlock; + + PCD_SendRecv(NthByte,DataToSend,pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == PCD_ERRORCODE_DEFAULT) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; + + +} + +/** +* @brief this function send an EOF pulse to contactless tag. +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_SendEOF(uint8_t *pResponse ) +{ + + PCD_SendEOF(pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) != ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; + +} + + +/** +* @brief this function returns ISO15693_SUCCESSCODE is Inventorye flag is set +* @param FlagsByte : the byts cantaining the eight flags +* @retval Inventory flag +*/ +static int8_t ISO15693_IsInventoryFlag(const uint8_t FlagsByte) +{ + if ((FlagsByte & ISO15693_MASK_INVENTORYFLAG) != 0x00) + return ISO15693_SUCCESSCODE ; + else + return ISO15693_ERRORCODE_DEFAULT ; +} + +/** +* @brief this function returns ISO15693_SUCCESSCODE if address Or Number of slots flag is set (depending on inventory flag) +* @param FlagsByte : Request flag +* @retval ISO15693_SUCCESSCODE : address or Number of slots flag is set +* @retval ISO15693_ERRORCODE_DEFAULT : address Or Number of slots flag is reset +*/ +static int8_t ISO15693_IsAddressOrNbSlotsFlag(const uint8_t FlagsByte) +{ + + if ((FlagsByte & ISO15693_MASK_ADDRORNBSLOTSFLAG) != 0x00) + return ISO15693_SUCCESSCODE ; + else + return ISO15693_ERRORCODE_DEFAULT ; +} + + + /** +* @brief this function returns ISO15693_SUCCESSCODE if a tag has reply, ISO15693_ERRORCODE_DEFAULT otherwise +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : PCD returns a succesful code +* @retval ISO15693_ERRORCODE_DEFAULT : PCD returns an error code +*/ +static int8_t ISO15693_IsATagInTheField(const uint8_t *pResponse) +{ + + if ( pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_RESULTSCODE_OK) + return ISO15693_SUCCESSCODE; + // When a collision occurs between two or more tags the PCD response can be 88 00 + if ( pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_ERRORCODE_SOF) + return ISO15693_SUCCESSCODE; + // When a collision occurs between two or more tags the PCD response can be 8E 00 + if ( pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_ERRORCODE_RECEPTIONLOST) + return ISO15693_SUCCESSCODE; + + return ISO15693_ERRORCODE_DEFAULT; + +} + +/** +* @brief this function returns ISO15693_SUCCESSCODE if a collision has been detected, ISO15693_ERRORCODE_DEFAULT otherwise +* @param pResponse : pointer on PCD response +* @retval ISO15693_SUCCESSCODE : collision detected +* @retval ISO15693_ERRORCODE_DEFAULT : no collision detected +*/ +static int8_t ISO15693_IsCollisionDetected(const uint8_t *pResponse) +{ + int8_t tmp=pResponse[PCD_LENGTH_OFFSET+pResponse[PCD_LENGTH_OFFSET]]& (CONTROL_15693_CRCMASK | CONTROL_15693_COLISIONMASK); + + // if reply status is SOF invalid, a collision might be occured +// if (pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_ERRORCODE_SOF) +// return ISO15693_SUCCESSCODE; + + // if (pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_ERRORCODE_RECEPTIONLOST) +// return ISO15693_SUCCESSCODE; + + // if reply status is Ok but the CRC is invalid, a collision might be occured +// if (pResponse[READERREPLY_STATUSOFFSET] == SENDRECV_RESULTSCODE_OK && +// ISO15693_IsCorrectCRC16Residue (&(pResponse[PCD_DATA_OFFSET]),pResponse[PCD_LENGTH_OFFSET]-1)== ISO15693_ERRORCODE_DEFAULT) +// return ISO15693_SUCCESSCODE; + + // if the two last bits of control byte is egual to one, a collision occured +// if ((pResponse[PCD_LENGTH_OFFSET+pResponse[PCD_LENGTH_OFFSET]]) & (CONTROL_15693_CRCMASK | CONTROL_15693_COLISIONMASK) == 0x03) + if (tmp == 0x03) + return ISO15693_SUCCESSCODE; + + return ISO15693_ERRORCODE_DEFAULT; + +} + +/** +* @brief this function computes the CRC16 as defined by CRC ISO/IEC 13239 +* @param DataIn : input data +* @param NbByte : Number of byte of DataIn +* @retval ResCrc : CRC16 computed +*/ +static int16_t ISO15693_CRC16(const uint8_t *DataIn,const uint8_t NbByte) +{ +int8_t i, + j; +int32_t ResCrc = ISO15693_PRELOADCRC16; + + for (i=0;i0;j--) + { + ResCrc = (ResCrc & ISO15693_MASKCRC16) ? (ResCrc>>1) ^ ISO15693_POLYCRC16 : (ResCrc>>1); + } + } + + return ((~ResCrc) & 0xFFFF); + +} + +/** +* @brief this function computes the CRC16 residue as defined by CRC ISO/IEC 13239 +* @param DataIn : input to data +* @param Length : Number of bits of DataIn +* @retval ISO15693_SUCCESSCODE : CRC16 residue is correct +* @retval ISO15693_ERRORCODE_DEFAULT : CRC16 residue is false +*/ +static int8_t ISO15693_IsCorrectCRC16Residue(const uint8_t *DataIn,const uint8_t Length) +{ +int16_t ResCRC=0; + + // check the CRC16 Residue + if (Length !=0) + ResCRC=ISO15693_CRC16 (DataIn, Length); + + if (((~ResCRC) & 0xFFFF) != ISO15693_RESIDUECRC16) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +} + +/** +* @brief Save the data from a TAG block for the uncomplete block to write +* @param Tag_Density : TAG is HIGH or LOW density +* @param NbByte_To_Write : Numbre of Byte to write in the TAG +* @param FirstByte_To_Write : First Byte to write in the TAG +* @param *Data_To_Save : Data store before write the complete block of the TAG +* @param *Length_Low_Limit : Number of Byte save for the first block to write (0 =< Length_Low_Limit =< 4) +* @param *Length_High_Limit : Number of Byte save for the last block to write (0 =< Length_High_Limit =< 4) +* @retval ISO15693_ERRORCODE_DEFAULT / ISO15693_SUCCESSCODE. +*/ +static uint8_t ISO15693_TagSave (uint8_t Tag_Density, uint16_t NbByte_To_Write, uint16_t FirstByte_To_Write, uint8_t *Data_To_Save, uint8_t *Length_Low_Limit, uint8_t *Length_High_Limit) +{ + const uint8_t NbBytePerBlock = 0x04; + + uint8_t RepBuffer[32], + ReadSingleBuffer [4]={0x02, 0x20, 0x00, 0x00}; + + uint8_t Nb_Byte_To_Save_Low; + uint8_t Nb_Byte_To_Save_High; + uint16_t Num_Block_Low; + uint16_t Num_Block_High; + + +/**********Find Limit Block*****************/ + Num_Block_Low = FirstByte_To_Write / NbBytePerBlock; + Num_Block_High = (FirstByte_To_Write + NbByte_To_Write) / NbBytePerBlock; + + Nb_Byte_To_Save_Low = (FirstByte_To_Write) % NbBytePerBlock; + Nb_Byte_To_Save_High = 4-((FirstByte_To_Write + NbByte_To_Write/*+ Nb_Byte_To_Save_Low*/) % NbBytePerBlock); + +/**********Read Low Limit******************/ + if(Tag_Density == ISO15693_LOW_DENSITY) + { + ReadSingleBuffer[2] = Num_Block_Low; + PCD_SendRecv (0x03,ReadSingleBuffer,RepBuffer); + } + + + else if(Tag_Density == ISO15693_HIGH_DENSITY) + { + ReadSingleBuffer[0] = 0x0A; + ReadSingleBuffer[2] = Num_Block_Low & 0x00FF; + ReadSingleBuffer[3] = (Num_Block_Low & 0xFF00) >> 8; + PCD_SendRecv (0x04,ReadSingleBuffer,RepBuffer); + } + + if(RepBuffer[0] != 0x80) + return ISO15693_ERRORCODE_DEFAULT; + + memcpy(&Data_To_Save[0], &RepBuffer[3], Nb_Byte_To_Save_Low); + *Length_Low_Limit = Nb_Byte_To_Save_Low; + +/**********Read High Limit******************/ + if(Tag_Density == ISO15693_LOW_DENSITY) + { + ReadSingleBuffer[2] = Num_Block_High; + PCD_SendRecv (0x03,ReadSingleBuffer,RepBuffer); + } + + else if(Tag_Density == ISO15693_HIGH_DENSITY) + { + ReadSingleBuffer[0] = 0x0A; + ReadSingleBuffer[2] = Num_Block_High & 0x00FF; + ReadSingleBuffer[3] = (Num_Block_High & 0xFF00) >> 8; + PCD_SendRecv (0x04,ReadSingleBuffer,RepBuffer); + } + + if(RepBuffer[0] != 0x80) + return ISO15693_ERRORCODE_DEFAULT; + + /*Data temp*/ + memcpy(&Data_To_Save[4], &RepBuffer[3+(4-Nb_Byte_To_Save_High)], (Nb_Byte_To_Save_High)); + *Length_High_Limit = Nb_Byte_To_Save_High; + return ISO15693_SUCCESSCODE; +} + + +//#endif + +/** +* @brief Read Multiple Block in the TAG (sector size : 0x20 = 32 Blocks) +* @param Tag_Density : TAG is HIGH or LOW density +* @param *Data_To_Read : return the data read in the TAG +* @param NbBlock_To_Read : Number of block to read in the TAG +* @param FirstBlock_To_Read : First block to read in the TAG +* @retval ISO15693_ERRORCODE_DEFAULT / ISO15693_SUCCESSCODE. +*/ +static uint8_t ISO15693_ReadMultipleTagData(uint8_t Tag_Density, uint8_t *Data_To_Read, uint16_t NbBlock_To_Read, uint16_t FirstBlock_To_Read) +{ + uint8_t /*ReadMultipleBuffer [5]={0x02, 0x23, 0x00, 0x00, 0x00},*/ + RepBuffer[140], + Requestflags = 0x02; + + uint16_t NbSectorToRead = 0, + SectorStart = 0, + NthDataToRead; + + /*Convert the block number in sector number*/ + NbSectorToRead = NbBlock_To_Read/32+1; + SectorStart = FirstBlock_To_Read/32; + + // update the RequestFlags + /*if (Tag_Density == ISO15693_LOW_DENSITY) + NumSectorToRead = (NumSectorToRead*0x20) & 0x00FF; + else */if (Tag_Density == ISO15693_HIGH_DENSITY) + Requestflags = 0x0A; + /*else + return ISO15693_ERRORCODE_DEFAULT;*/ + + for ( NthDataToRead=0; NthDataToRead < NbSectorToRead; NthDataToRead++) + { + //NumSectorToRead += NthDataToRead; + + if ( ISO15693_ReadMultipleBlock (Requestflags, 0x00,NthDataToRead+SectorStart,0x1F,RepBuffer ) !=ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + /*Data Temp*/ + memcpy(&Data_To_Read[NthDataToRead*128],&RepBuffer[3],128); + } + + return ISO15693_SUCCESSCODE; +} + + + +/** +* @brief Read Single Block in the TAG +* @param Tag_Density : TAG is HIGH or LOW density +* @param *Data_To_Read : return the data read in the TAG +* @param NbBlock_To_Read : Number of block to read in the TAG +* @param FirstBlock_To_Read : First block to read in the TAG +* @retval ISO15693_ERRORCODE_DEFAULT / ISO15693_SUCCESSCODE. +*/ +static uint8_t ISO15693_ReadSingleTagData(uint8_t Tag_Density, uint8_t *Data_To_Read, uint16_t NbBlock_To_Read, uint16_t FirstBlock_To_Read) +{ + uint8_t /*ReadBuffer [4]={0x02, 0x20, 0x00, 0x00},*/ + RepBuffer[16], + Requestflags = 0x02; + uint16_t NthDataToRead= 0x0000; + uint16_t Num_DataToRead = FirstBlock_To_Read; + + // update the RequestFlags + if (Tag_Density == ISO15693_LOW_DENSITY) + Num_DataToRead &= 0x00FF; + else if (Tag_Density == ISO15693_HIGH_DENSITY) + Requestflags = 0x0A; + else + return ISO15693_ERRORCODE_DEFAULT; + + for ( NthDataToRead= 0; NthDataToRead < NbBlock_To_Read; NthDataToRead++) + { + Num_DataToRead += NthDataToRead; + +// if (Tag_Density == ISO15693_LOW_DENSITY) +// { +// Num_DataToRead &= 0x00FF; +// ReadBuffer [2] = (Num_DataToRead) & 0x00FF; +// memset (RepBuffer, 0x00,8); +// PCD_SendRecv (0x03,ReadBuffer,RepBuffer); +// } +// else if (Tag_Density == ISO15693_HIGH_DENSITY) +// { +// ReadBuffer [0] = 0x0A; +// ReadBuffer [2] = (Num_DataToRead) & 0x00FF; +// ReadBuffer [3] = ((Num_DataToRead) & 0xFF00) >> 8; +// memset (RepBuffer, 0x00,8); +// PCD_SendRecv (0x04,ReadBuffer,RepBuffer); +// } +// else +// return ISO15693_ERRORCODE_DEFAULT; + + if ( ISO15693_ReadSingleBlock (Requestflags, 0x00,Num_DataToRead,RepBuffer ) !=ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + + /*Data Temp*/ + memcpy(&Data_To_Read[NthDataToRead*4],&RepBuffer[3],ISO15693_NBBYTE_BLOCKLENGTH); + } + + return ISO15693_SUCCESSCODE; +} + +/** +* @brief Write data by blocks in the TAG +* @param Tag_Density : TAG is HIGH or LOW density +* @param *Data_To_Write : Data to write in the TAG +* @param NbBlock_To_Write : Number of block to write in the TAG +* @param FirstBlock_To_Write : First block to write in the TAG +* @retval ISO15693_ERRORCODE_DEFAULT / ISO15693_SUCCESSCODE. +*/ +static uint8_t ISO15693_WriteTagData(uint8_t Tag_Density, uint8_t *Data_To_Write, uint16_t NbBlock_To_Write, uint16_t FirstBlock_To_Write) +{ +// uint8_t WriteBuffer [8]={0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + uint8_t RepBuffer[32], + Requestflags =0x02; + uint16_t NthDataToWrite =0, + IncBlock =0; + + // update the RequestFlags + if (Tag_Density == ISO15693_LOW_DENSITY) + FirstBlock_To_Write &= 0x00FF; + else if (Tag_Density == ISO15693_HIGH_DENSITY) + Requestflags = 0x0A; + else + return ISO15693_ERRORCODE_DEFAULT; + + for ( NthDataToWrite=FirstBlock_To_Write; NthDataToWrite<(FirstBlock_To_Write+NbBlock_To_Write); NthDataToWrite++) + { +// /*Block To Write*/ +// if(Tag_Density == ISO15693_LOW_DENSITY) +// +// WriteBuffer [2] = (NthDataToWrite) & 0x00FF; + +// else if(Tag_Density == ISO15693_HIGH_DENSITY) +// { +// WriteBuffer [0] = 0x0A; +// WriteBuffer [2] = NthDataToWrite & 0x00FF; +// WriteBuffer [3] = (NthDataToWrite& 0xFF00) >> 8; +// } + +// /*Data To Write in the Block*/ +// WriteBuffer [3+Tag_Density] = Data_To_Write[0+(IncBlock)]; +// WriteBuffer [4+Tag_Density] = Data_To_Write[1+(IncBlock)]; +// WriteBuffer [5+Tag_Density] = Data_To_Write[2+(IncBlock)]; +// WriteBuffer [6+Tag_Density] = Data_To_Write[3+(IncBlock)]; + +// memset (RepBuffer, 0x00,32); +// if (Tag_Density == ISO15693_LOW_DENSITY) +// PCD_SendRecv (0x07,WriteBuffer,RepBuffer); + +// else if (Tag_Density == ISO15693_HIGH_DENSITY) +// PCD_SendRecv (0x08,WriteBuffer,RepBuffer); + if ( ISO15693_WriteSingleBlock (Requestflags, 0x00,NthDataToWrite,&Data_To_Write[NthDataToWrite<<2],RepBuffer ) !=ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + + IncBlock += 4; + } + + return ISO15693_SUCCESSCODE; +} + +/** + * @} + */ + + +/** @addtogroup lib_iso15693pcd_Public_Functions + * @{ + */ + + +/** +* @brief this function selects 15693 protocol accoording to input parameters +* @retval ISO15693_SUCCESSCODE : the function is successful +* @retval ISO15693_ERRORCODE_DEFAULT : an error occured +*/ +int8_t ISO15693_Init ( void ) +{ + uint8_t ParametersByte=0, + pResponse[PROTOCOLSELECT_LENGTH]; + int8_t status; + u8 DemoGainParameters [] = {PCD_TYPEV_ARConfigA, PCD_TYPEV_ARConfigB}; + + ParametersByte = ((ISO15693_APPENDCRC << ISO15693_OFFSET_APPENDCRC ) & ISO15693_MASK_APPENDCRC) | + ((ISO15693_SINGLE_SUBCARRIER << ISO15693_OFFSET_SUBCARRIER) & ISO15693_MASK_SUBCARRIER) | + ((ISO15693_MODULATION_100 << ISO15693_OFFSET_MODULATION) & ISO15693_MASK_MODULATION) | + ((ISO15693_WAIT_FOR_SOF << ISO15693_OFFSET_WAITORSOF ) & ISO15693_MASK_WAITORSOF) | + ((ISO15693_TRANSMISSION_26 << ISO15693_OFFSET_DATARATE ) & ISO15693_MASK_DATARATE); + + errchk(PCD_ProtocolSelect(ISO15693_SELECTLENGTH,ISO15693_PROTOCOL,&(ParametersByte),pResponse)); + TechnoSelected = PCDPROTOCOL_15693; + + /* in order to adjust the demoduation gain of the PCD*/ + errchk(PCD_WriteRegister ( 0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,DemoGainParameters,pResponse)); + +// if (PCD_IsReaderResultCodeOk (PROTOCOL_SELECT,pResponse) == ISO15693_ERRORCODE_DEFAULT) +// return ISO15693_ERRORCODE_DEFAULT; + + + return ISO15693_SUCCESSCODE; +Error: + return ISO15693_ERRORCODE_DEFAULT; +} + + +/** +* @brief this function return a tag UID +* @param UIDout: UID of a tag in the field +* @retval status function +*/ +int8_t ISO15693_GetUID (uint8_t *UIDout) +{ +int8_t FlagsByteData, status; +uint8_t TagReply [ISO15693_NBBYTE_UID+7]; +uint8_t Tag_error_check; + + + /* select 15693 protocol */ + errchk(ISO15693_Init ( )); + + FlagsByteData = ISO15693_CreateRequestFlag ( ISO15693_REQFLAG_SINGLESUBCARRIER, + ISO15693_REQFLAG_HIGHDATARATE, + ISO15693_REQFLAG_INVENTORYFLAGSET, + ISO15693_REQFLAG_NOPROTOCOLEXTENSION, + ISO15693_REQFLAG_NOTAFI, + ISO15693_REQFLAG_1SLOT, + ISO15693_REQFLAG_OPTIONFLAGNOTSET, + ISO15693_REQFLAG_RFUNOTSET); + + status = ISO15693_Inventory ( FlagsByteData, 0x00, 0x00, 0x00, TagReply ); + errchk( status ); + + Tag_error_check = TagReply[ISO15693_OFFSET_LENGTH]+1; + if((TagReply[Tag_error_check] & ISO15693_CRC_MASK) != 0x00 ) + return ISO15693_ERRORCODE_DEFAULT; + + + if (status == ISO15693_SUCCESSCODE) + memcpy(UIDout,&(TagReply[ISO15693_OFFSET_UID]),ISO15693_NBBYTE_UID); + + devicemode = PCD; + nfc_tagtype = TT5; + return ISO15693_SUCCESSCODE; +Error: + return ISO15693_ERRORCODE_DEFAULT; +} + +/** +* @brief this function send an GetSystemInfo command and returns ISO15693_SUCCESSCODE if the command +* @brief was correctly emmiting, ISO15693_ERRORCODE_DEFAULT otherwise +* @param Flags : inventory flags +* @param UID : Tag UID +* @retval ISO15693_SUCCESSCODE : the function is successful +* @retval ISO15693_ERRORCODE_DEFAULT : an error occured +*/ +int8_t ISO15693_GetSystemInfo(const uint8_t Flags, const uint8_t *UIDin, uint8_t *pResponse) +{ +uint8_t DataToSend[ISO15693_MAXLENGTH_GETSYSTEMINFO], + NthByte=0; +int8_t status; + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_GETSYSINFO; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == true) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + errchk(PCD_SendRecv(NthByte,DataToSend,pResponse)); +// if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) +// return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +Error: + *pResponse = SENDRECV_ERRORCODE_SOFT; + *(pResponse+1) = 0x00; + return ISO15693_ERRORCODE_DEFAULT; +} + +/** +* @brief this function splits inventory response. If the residue of tag response is incorrect the function returns ERRORCODE_GENERIC, otherwise ISO15693_SUCCESSCODE +* @param ReaderResponse : pointer on PCD response +* @param Length : Number of byte of Reader Response +* @param Flags : Response flags +* @param DSFIDextract: DSPID of tag response +* @param UIDoutIndex : index of UIDout of tag response +* @retval ISO15693_SUCCESSCODE : Contactless tag response validated +* @retval CR95HF_ERROR_CODE : PCD teturned an error code +* @retval ISO15693_ERRORCODE_CRCRESIDUE : CRC16 residue is erroneous +*/ +int8_t ISO15693_SplitInventoryResponse(const uint8_t *ReaderResponse,const uint8_t Length,uint8_t *Flags , uint8_t *DSFIDextract, uint8_t *UIDoutIndex) +{ + int8_t status; + + uint8_t ResultCode = ReaderResponse[PCD_DATA_OFFSET], + NbTagReplyByte =ReaderResponse[PCD_LENGTH_OFFSET]-CONTROL_15693_NBBYTE, + TagReplyIndex = PCD_DATA_OFFSET; + + /* PCD returned an error code */ + if (ResultCode != ISO15693_RESULTFLAG_STATUSOK) + return ISO15693_ERRORCODE_DEFAULT; + + errchk(ISO15693_IsCorrectCRC16Residue (&ReaderResponse[TagReplyIndex],NbTagReplyByte)); + + *Flags = ReaderResponse[TagReplyIndex+ISO15693_OFFSET_FLAGS]; + *DSFIDextract = ReaderResponse[TagReplyIndex+ISO15693_INVENTORYOFFSET_DSFID]; + + *UIDoutIndex=TagReplyIndex+ISO15693_INVENTORYOFFSET_UID; + + return ISO15693_SUCCESSCODE; +Error: + return ISO15693_ERRORCODE_CRCRESIDUE; + +} + + +/** +* @brief this function runs an anticollision sequence and returns the number of tag seen and their UID. +* @brief The protocol select command has to be send first and the Flags parameterns shall be compliant +* @brief with the parameters of the Protocol Select command. +* @param Flags : request flags +* @param AFI : AFI parameter (optional) +* @param NbTag : Number of tag seen +* @param pUIDout : pointer on tag UID +* @retval ISO15693_SUCCESSCODE : function succesful executed +* @retval ISO15693_ERRORCODE_DEFAULT : +*/ +int8_t ISO15693_RunAntiCollision(const uint8_t Flags , const uint8_t AFI,uint8_t *NbTag,uint8_t *pUIDout) +{ + int8_t status; + uint8_t MaskValue[ISO15693_NBBYTE_UID], + MaskLength = 0, + MaskStack [0x80*ISO15693_NBBYTE_UID]; // can save 16 mask. the size of a mask is ISO15693_NBBYTE_UID. + // the first byte is mask length (bit size). the orthers bytre are mask value + uint8_t RequestFlags = Flags, + offset=0, + ReplyFlag, + NbTagInventoried, + DSFIDout, + NthStackValue=1, + i=0, + Nbloop = 0, + StayQuietFlags = (Flags & ~ISO15693_MASK_INVENTORYFLAG) | ISO15693_MASK_ADDRORNBSLOTSFLAG, + UIDoutOffet = PCD_DATA_OFFSET + 2 ; + uint16_t SlotOccupancy= 0x0000 ; + + memset(MaskStack,0x00,16*ISO15693_NBBYTE_UID); + *NbTag = 0; + + + // checks if at least a tag is in the field + ISO15693_InventoryOneSlot( + RequestFlags , + AFI, + MaskLength, + MaskValue, + u95HFBuffer); + + + // no tag in the field + if (ISO15693_IsATagInTheField (u95HFBuffer) != ISO15693_SUCCESSCODE) + return ISO15693_SUCCESSCODE; + + // check TagReply CRC residue and get tag UID + status = ISO15693_SplitInventoryResponse( u95HFBuffer, + u95HFBuffer[PCD_LENGTH_OFFSET], + &ReplyFlag , + &DSFIDout, + &UIDoutOffet); + + + + // residue CRC ok (=> Only one tag in the field) + if (status == ISO15693_SUCCESSCODE) + { + *NbTag = 1; + // send a stay quiet command to the inventoried tag + ISO15693_StayQuiet(StayQuietFlags ,&(u95HFBuffer[UIDoutOffet])); + // no collision => copy DSFID + pUIDout[0] = DSFIDout ; + // no collision => copy tag UID + memcpy(&(pUIDout[1]),&(u95HFBuffer[UIDoutOffet]),ISO15693_NBBYTE_UID); + return ISO15693_SUCCESSCODE; + } + + delay(10); + + (*NbTag)=0; + + // the folowing anticollsion sequence is preorder traversal algorithm + // the UIDs can be represnt as a binary tree + do{ + + memset(MaskValue,0x00,ISO15693_NBBYTE_UID); + // unstack mask value + NthStackValue -- ; + memcpy(MaskValue,(MaskStack+NthStackValue*ISO15693_NBBYTE_UID+1),ISO15693_NBBYTE_UID); + + + // at this point : at least two tags are in the field + // => run an inventory 16 slots + + // the u95HFBuffer is MAX_BUFFER_SIZE + 3 (=256 +3 bytes) + // if a response is available in eack slot => 16 * 15 (max size of inventory reply + 3 control bytes) + // => 16 * 15 = 240 bytes < MAX_BUFFER_SIZE + 3 + SlotOccupancy =ISO15693_Inventory16Slots( + RequestFlags , + AFI, + MaskLength, + MaskValue, + &NbTagInventoried, + u95HFBuffer); + + + + offset = 0; + + // loop on tag inventoried and copy the UID, + for (i=0;i copy DSFID + pUIDout[(*NbTag)*(ISO15693_NBBYTE_UID+1)] = DSFIDout ; + // no collision => copy tag UID + memcpy((pUIDout+(1+(*NbTag)*(ISO15693_NBBYTE_UID+1))),&(u95HFBuffer[offset + UIDoutOffet]),ISO15693_NBBYTE_UID); + (*NbTag)++ ; + } + offset += u95HFBuffer[offset+PCD_LENGTH_OFFSET] + 2; + } // for (i=0;i add 4 bits to the mask + */ + + if ((SlotOccupancy & (0x01 <0 && Nbloop < 0x20); + + return ISO15693_SUCCESSCODE; + +} + + +/** +* @brief this function runs an anticollision sequence and returns the number of tag seen and their UID. +* @brief The protocol select command has to be send first and the Flags parameterns shall be compliant +* @brief with the parameters of the Protocol Select command. +* @param Flags : request flags +* @param AFI : AFI parameter (optional) +* @param NbTag : Number of tag seen +* @param pUIDout : pointer on tag UID +* @retval ISO15693_SUCCESSCODE : function succesful executed +* @retval ISO15693_ERRORCODE_DEFAULT : +*/ +int8_t ISO15693_RunInventory16slots(const uint8_t Flags , const uint8_t AFI,uint8_t *NbTag,uint8_t *pUIDout) +{ + int8_t status; + uint8_t MaskValue[ISO15693_NBBYTE_UID], + MaskLength = 0, + MaskStack [0x40*ISO15693_NBBYTE_UID]; // can save 64 masks. the size of a mask is ISO15693_NBBYTE_UID. + // the first byte is mask length (bit size). the orthers bytre are mask value + uint8_t RequestFlags = Flags, + offset=0, + ReplyFlag, + NbTagInventoried, + DSFIDout, + i=0, + UIDoutOffet = PCD_DATA_OFFSET + 2 ; + + + memset(MaskStack,0x00,16*ISO15693_NBBYTE_UID); + *NbTag = 0; + + + ISO15693_Inventory16Slots( + RequestFlags , + AFI, + MaskLength, + MaskValue, + &NbTagInventoried, + u95HFBuffer); + + + if (NbTagInventoried == 0) + { *NbTag = 0; + return ISO15693_SUCCESSCODE; + } + + + offset = 0; + // loop on tag inventoried and if there is no colission if the slot copy the UID, + // otherwise get the slot where the collision occured + for (i=0;i copy DSFID + pUIDout[(*NbTag)*(ISO15693_NBBYTE_UID+1)] = DSFIDout ; + // no collision => copy tag UID + memcpy((pUIDout+(1+(*NbTag)*(ISO15693_NBBYTE_UID+1))),&(u95HFBuffer[UIDoutOffet+offset]),ISO15693_NBBYTE_UID); + (*NbTag)++ ; + } +// } + + + offset += u95HFBuffer[offset+PCD_LENGTH_OFFSET] + 2; + } // for (i=0;i Page size read multiple 0x20 & 1 block = 4 bytes*/ + uint16_t NbBlock_To_Read = NbBytes_To_Read/4; + uint16_t FirstBlock_To_Read = FirstBytes_To_Read/4; + + /*LRiS2K don't support read multiple*/ + if(IC_Ref_Tag == ISO15693_LRiS2K) + { + NbBlock_To_Read = NbBytes_To_Read/4; + status = ISO15693_ReadSingleTagData(Tag_Density, Data_To_Read, NbBlock_To_Read, FirstBlock_To_Read); + } + + else + status = ISO15693_ReadMultipleTagData(Tag_Density, Data_To_Read, NbBlock_To_Read, FirstBlock_To_Read); + + //memcpy(Data_To_Read,&Data_To_Read[FirstBytes_To_Read], NbBytes_To_Read); + + return status; + +} + +/** +* @brief Write data by bytes in the TAG +* @param Tag_Density : TAG is HIGH or LOW density +* @param *Data_To_Write : Data to write in the TAG +* @param NbBytes_To_Write : Number of Bytes to write in the TAG +* @param FirstBytes_To_Write : First Bytes to write in the TAG +* @retval ISO15693_ERRORCODE_DEFAULT / ISO15693_SUCCESSCODE. +*/ +uint8_t ISO15693_WriteBytes_TagData(uint8_t Tag_Density, uint8_t *Data_To_Write, uint16_t NbBytes_To_Write, uint16_t FirstBytes_To_Write) +{ + /*1 block = 4 bytes*/ + uint16_t NbBlock_To_Write; + + /*Convert in Blocks the number of bytes to write*/ + uint16_t FirstBlock_To_Write = FirstBytes_To_Write/4; + + uint8_t Length_Low_Limit =0; + uint8_t Length_High_Limit = 0; + uint8_t Data_To_Save[8]; + + NbBlock_To_Write = (NbBytes_To_Write/4)+1; + + /*Save the data of the uncomplete block to write*/ + ISO15693_TagSave(Tag_Density, NbBytes_To_Write, FirstBytes_To_Write, Data_To_Save, &Length_Low_Limit, &Length_High_Limit); + + + memcpy(&Data_To_Write[-Length_Low_Limit],&Data_To_Save[0], Length_Low_Limit); + memcpy(&Data_To_Write[NbBytes_To_Write],&Data_To_Save[4], Length_High_Limit); + + if (ISO15693_WriteTagData(Tag_Density, &Data_To_Write[-Length_Low_Limit], NbBlock_To_Write, FirstBlock_To_Write) != ISO15693_SUCCESSCODE) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +} + +#ifdef ISO15693_ALLCOMMANDS + + +/** +* @brief this function send an LockSingleBlock command to contactless tag. +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param BlockNumber : index of block to read +* @param pResponse : pointer on PCD response +* @retval RESULTOK : PCD returns a succesful code +* @retval ERRORCODE_GENERIC : PCD returns an error code +*/ +int8_t ISO15693_LockSingleBlock(const uint8_t Flags, const uint8_t *UIDin, const uint8_t BlockNumber,uint8_t *pResponse) +{ + uint8_t DataToSend[ISO15693_MAXLENGTH_LOCKSINGLEBLOCK], + NthByte=0; + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_LOCKBLOCK; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == TRUE) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + DataToSend[NthByte++] = BlockNumber; + + PCD_SendRecv(NthByte,DataToSend,pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; + +} + +/** +* @brief this function send an Lock AFI command to contactless tag. +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param pResponse : pointer on PCD response +* @retval RESULTOK : PCD returns a succesful code +* @retval ERRORCODE_GENERIC : PCD returns an error code +*/ +int8_t ISO15693_LockAFI(const uint8_t Flags, const uint8_t *UIDin,uint8_t *pResponse ) +{ + uint8_t DataToSend[ISO15693_MAXLENGTH_LOCKAFI], + NthByte=0; + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_LOCKAFI; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == TRUE) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + PCD_SendRecv(NthByte,DataToSend,pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; + +} + +/** +* @brief this function send an Lock DSFID command to contactless tag. +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param pResponse : pointer on PCD response +* @retval RESULTOK : PCD returns a succesful code +* @retval ERRORCODE_GENERIC : PCD returns an error code +*/ +int8_t ISO15693_LockDSFID(const uint8_t Flags, const uint8_t *UIDin,uint8_t *pResponse) +{ + uint8_t DataToSend[ISO15693_MAXLENGTH_LOCKDSFID], + NthByte=0; + + errchk (ISO15693_IsReaderConfigMatchWithFlag (GloParameterSelected,Flags)); + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_LOCKDSFID; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == TRUE) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + PCD_SendRecv(NthByte,DataToSend,pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ISO15693_ERRORCODE_DEFAULT) + return ISO15693_ERRORCODE_DEFAULT; + + return ISO15693_SUCCESSCODE; +} + + + +/** +* @brief this function send a Get Multiple Block Secutity Status command to contactless tag. +* @param Flags : Request flags +* @param UIDin : pointer on contacless tag UID (optional) (depend on address flag of Request flags) +* @param BlockNumber : index of block to read +* @param NbBlocks : Number of blocks +* @param AppendCRC : CRC16 management. If set PCD appends CRC16. +* @param CRC16 : pointer on CRC16 (optional) in case of user has choosed to manage CRC16 (see ProtocolSelect command PCD layer) +* @param pResponse : pointer on PCD response +* @retval RESULTOK : PCD returns a succesful code +* @retval ERRORCODE_GENERIC : PCD returns an error code +*/ +int8_t ISO15693_GetMultipleBlockSecutityStatus(const uint8_t Flags, const uint8_t *UIDin, const uint8_t BlockNumber, const uint8_t NbBlocks,uint8_t *pResponse) +{ + uint8_t DataToSend[ISO15693_MAXLENGTH_GETMULSECURITY], + NthByte=0; + int8_t status; + + errchk (ISO15693_IsReaderConfigMatchWithFlag (GloParameterSelected,Flags)); + + DataToSend[NthByte++] = Flags; + DataToSend[NthByte++] = ISO15693_CMDCODE_GETSECURITYINFO; + + if (ISO15693_GetAddressOrNbSlotsFlag (Flags) == RESULTOK) + { memcpy(&(DataToSend[NthByte]),UIDin,ISO15693_NBBYTE_UID); + NthByte +=ISO15693_NBBYTE_UID; + } + + DataToSend[NthByte++] = BlockNumber; + DataToSend[NthByte++] = NbBlocks; + + + errchk(CR95HF_SendRecv(NthByte,DataToSend,pResponse)); + + if (CR95HF_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) == ERRORCODE_GENERIC) + return ERRORCODE_GENERIC; + + return RESULTOK; +Error: + *pResponse = SENDRECV_ERRORCODE_SOFT; + *(pResponse+1) = 0x00; + return ERRORCODE_GENERIC; +} + + + +#endif /*ISO15693_ALLCOMMANDS*/ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso15693pcd.h b/src/lib_iso15693pcd.h new file mode 100644 index 0000000..f0455d7 --- /dev/null +++ b/src/lib_iso15693pcd.h @@ -0,0 +1,318 @@ +/** + ****************************************************************************** + * @file lib_iso15693pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of function defined into ISO15693 specification + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_ISO15693_H +#define __LIB_ISO15693_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" + +#define RFU 0 +#define ISO15693_PROTOCOL 0x01 +#define ISO15693_SELECTLENGTH 0x02 + + +/* data rates constants fot select commands -------------------------------------------------- */ +#define ISO15693_TRANSMISSION_26 0 +#define ISO15693_TRANSMISSION_53 1 +#define ISO15693_TRANSMISSION_6 2 +#define ISO15693_TRANSMISSION_RFU 3 +// constants fot select commands ------------------------------------------------------------- */ +#define ISO15693_RESPECT_312 0 +#define ISO15693_WAIT_FOR_SOF 1 +/* modulation constants fot select commands -------------------------------------------------- */ +#define ISO15693_MODULATION_100 0 +#define ISO15693_MODULATION_10 1 +/* sub carrier constants fot select commands -------------------------------------------------- */ +#define ISO15693_SINGLE_SUBCARRIER 0 +#define ISO15693_DUAL_SUBCARRIER 1 +/* appendCrc constants fot select commands ---------------------------------------------------- */ +#define ISO15693_APPENDCRC 1 +#define ISO15693_DONTAPPENDCRC 0 + +#define ISO15693_M24LR64R 0x2C +#define ISO15693_M24LR64ER 0x5E +#define ISO15693_M24LR16ER 0x4E +#define ISO15693_M24LR04ER 0x5A +#define ISO15693_LRiS64K 0x44 +#define ISO15693_LRiS2K 0x28 +#define ISO15693_LRi2K 0x20 +#define ISO15693_LRi1K 0x40 + +#define ISO15693_LOW_DENSITY 0x00 +#define ISO15693_HIGH_DENSITY 0x01 + +#define ISO15693_NBBYTE_BLOCKLENGTH 4 + +/* mask of request flag ----------------------------------------------------------------------- */ +#define ISO15693_MASK_SUBCARRIERFLAG 0x01 +#define ISO15693_MASK_DATARATEFLAG 0x02 +#define ISO15693_MASK_INVENTORYFLAG 0x04 +#define ISO15693_MASK_PROTEXTFLAG 0x08 +#define ISO15693_MASK_SELECTORAFIFLAG 0x10 +#define ISO15693_MASK_ADDRORNBSLOTSFLAG 0x20 +#define ISO15693_MASK_OPTIONFLAG 0x40 +#define ISO15693_MASK_RFUFLAG 0x80 +/* mask of response flag ---------------------------------------------------------------------- */ +#define ISO15693_RESULTFLAG_STATUSOK 0x00 +#define ISO15693_MASK_ERRORFLAG 0x01 + +/* memmory size information ------------------------------------------------------------------- */ +#define ISO15693_MEMSIZEMASK_BLOCKSIZE 0x1F00 +#define ISO15693_MEMSIZEMASK_NBBLOCK 0x00FF +#define ISO15693_MEMSIZEOFFSET_BLOCKSIZE 0x08 + + +/* mask for information flags ----------------------------------------------------------------- */ +#define ISO15693_MASK_DSFIDFLAG 0x01 +#define ISO15693_MASK_AFIFLAG 0x02 +#define ISO15693_MASK_MEMSIZEFLAG 0x04 +#define ISO15693_MASK_ICREFFLAG 0x08 + +#define ISO15693_MASK_GETSYSINFOREPLY_MEMSIZE 0x1F + +/* command code ------------------------------------------------------------------------------ */ +#define ISO15693_CMDCODE_INVENTORY 0x01 +#define ISO15693_CMDCODE_STAYQUIET 0x02 +#define ISO15693_CMDCODE_READSINGLEBLOCK 0x20 +#define ISO15693_CMDCODE_WRITESINGLEBLOCK 0x21 +#define ISO15693_CMDCODE_LOCKBLOCK 0x22 +#define ISO15693_CMDCODE_READMULBLOCKS 0x23 +#define ISO15693_CMDCODE_WRITEMULBLOCKS 0x24 +#define ISO15693_CMDCODE_SELECT 0x25 +#define ISO15693_CMDCODE_RESETTOREADY 0x26 +#define ISO15693_CMDCODE_WRITEAFI 0x27 +#define ISO15693_CMDCODE_LOCKAFI 0x28 +#define ISO15693_CMDCODE_WRITEDSFID 0x29 +#define ISO15693_CMDCODE_LOCKDSFID 0x2A +#define ISO15693_CMDCODE_GETSYSINFO 0x2B +#define ISO15693_CMDCODE_GETSECURITYINFO 0x2C + + + + + +// request flags ------------------------------------------------------------------------------ */ +#define ISO15693_REQFLAG_SINGLESUBCARRIER 0 +#define ISO15693_REQFLAG_TWOSUBCARRIER 1 +#define ISO15693_REQFLAG_LOWDATARATE 0 +#define ISO15693_REQFLAG_HIGHDATARATE 1 +#define ISO15693_REQFLAG_INVENTORYFLAGNOTSET 0 +#define ISO15693_REQFLAG_INVENTORYFLAGSET 1 +#define ISO15693_REQFLAG_NOPROTOCOLEXTENSION 0 +#define ISO15693_REQFLAG_PROTOCOLEXTENSION 1 + // request flag 5 to 8 definition when inventory flag is not set ----------------------------- */ +#define ISO15693_REQFLAG_NOTSELECTED 0 +#define ISO15693_REQFLAG_SELECTED 1 +#define ISO15693_REQFLAG_NOTADDRESSED 0 +#define ISO15693_REQFLAG_ADDRESSED 1 +#define ISO15693_REQFLAG_OPTIONFLAGNOTSET 0 +#define ISO15693_REQFLAG_OPTIONFLAGSET 1 +#define ISO15693_REQFLAG_RFUNOTSET 0 +#define ISO15693_REQFLAG_RFUSET 1 + // request flag 5 to 8 definition when inventory flag is set -------------------------------- */ +#define ISO15693_REQFLAG_NOTAFI 0 +#define ISO15693_REQFLAG_AFI 1 +#define ISO15693_REQFLAG_16SLOTS 0 +#define ISO15693_REQFLAG_1SLOT 1 + + + +// mask for parameter byte (select command) --------------------------------------------------- */ +#define ISO15693_MASK_APPENDCRC 0x01 +#define ISO15693_MASK_SUBCARRIER 0x02 +#define ISO15693_MASK_MODULATION 0x04 +#define ISO15693_MASK_WAITORSOF 0x08 +#define ISO15693_MASK_DATARATE 0x30 +#define ISO15693_MASK_RFU 0xC0 +// bits offset for parameter byte (select command) -------------------------------------------- */ +#define ISO15693_OFFSET_APPENDCRC 0x00 +#define ISO15693_OFFSET_SUBCARRIER 0x01 +#define ISO15693_OFFSET_MODULATION 0x02 +#define ISO15693_OFFSET_WAITORSOF 0x03 +#define ISO15693_OFFSET_DATARATE 0x04 +#define ISO15693_OFFSET_RFU 0x06 + +// byte offset for tag responses -------------------------------------------------------------- */ +#define ISO15693_OFFSET_FLAGS 0x00 +#define ISO15693_OFFSET_ERRORCODE 0x01 + +#define ISO15693_OFFSET_GETSYSINFOREPLY_NBBLOCK 0x00 +#define ISO15693_OFFSET_GETSYSINFOREPLY_MEMSIZE 0x01 + +#define ISO15693_OFFSET_UID PCD_DATA_OFFSET+0x02 + + + +#define ISO15693_INVENTORYOFFSET_DSFID 0x01 +#define ISO15693_INVENTORYOFFSET_UID 0x02 +#define ISO15693_INVENTORYOFFSET_CRC16 0x05 + +#define ISO15693_GETSYSINFOOFFSET_INFOFLAGS 0x01 +#define ISO15693_GETSYSINFOOFFSET_UID 0x02 +#define ISO15693_GETSYSINFOOFFSET_DSFID 0x0A + +#define ISO15693_READSINGLEOFFSET_SECURITY 0x01 +#define ISO15693_GETMULSECURITIOFFSET_SECURITY 0x01 + + +/* number of byte of parameters ------------------------------------------------------------- */ +#define ISO15693_NBBYTE_UID 0x08 +#define ISO15693_NBBYTE_CRC16 0x02 +#define ISO15693_NBBYTE_DSFID 0x01 +#define ISO15693_NBBYTE_AFI 0x01 +#define ISO15693_NBBYTE_BLOCKSECURITY 0x01 +#define ISO15693_NBBYTE_REPLYFLAG 0x01 +#define ISO15693_NBBYTE_INFOFLAG 0x01 +#define ISO15693_NBBYTE_MEMORYSIZE 0x02 +#define ISO15693_NBBYTE_ICREF 0x01 +#define ISO15693_NBBYTE_REQUESTFLAG 0x01 + +#define ISO15693_NBBIT_INVENTORYSCANCHAIN 2+8+8+64 +#define ISO15693_NBBYTE_INVENTORYSCANCHAIN 11 // =(2+8+8+64) /8 +1 +#define ISO15693_NBBITS_MASKPARAMETER 64 + +/* success and error code --------------------------------------------------------------------- */ +#define ISO15693_SUCCESSCODE RESULTOK +#define ISO15693_ERRORCODE_DEFAULT 0xF1 +#define ISO15693_ERRORCODE_REQUESTFLAG 0xF2 +#define ISO15693_ERRORCODE_PARAMETERLENGTH 0xF3 +#define ISO15693_ERRORCODE_CRCRESIDUE 0xF4 +#define ISO15693_ERRORCODE_NOTAGFOUND 0xF5 + + + +/* command length ----------------------------------------------------------------------------- */ +#define ISO15693_MAXLENGTH_INVENTORY 13 // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_STAYQUIET 12 // 8 + 8 + 64 + 16 = 96 => 12 bytes +#define ISO15693_MAXLENGTH_READSINGLEBLOCK 13 // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_LOCKSINGLEBLOCK 13 // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_READMULBLOCK 14 // 8 + 8 + 8 + 64 + 8 + 16 = 112 bits => 14 bytes +#define ISO15693_MAXLENGTH_SELECT 12 // 8 + 8 + 64 + 16 = 96 bits => 12 bytes +#define ISO15693_MAXLENGTH_RESETTOREADY 12 // 8 + 8 + 64 + 16 = 96 bits => 12 bytes +#define ISO15693_MAXLENGTH_WRTITEAFI 13 // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_WRTITEDSFID 13 // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_LOCKAFI 12 // 8 + 8 + 64 + 16 = 96 bits => 12 bytes +#define ISO15693_MAXLENGTH_LOCKDSFID 12 // 8 + 8 + 64 + 16 = 96 bits => 12 bytes +#define ISO15693_MAXLENGTH_GETMULSECURITY 14 // 8 + 8 + 8 + 64 + 8 + 16 = 112 bits => 14 bytes +#define ISO15693_MAXLENGTH_GETSYSTEMINFO 12 // 8 + 8 + 64 + 16 = 96 => 12 bytes +// reply length +#define ISO15693_MAXLENGTH_REPLYINVENTORY 12 // 8 + 8 + 64 + 16 = 96 => 12 bytes +#define ISO15693_MAXLENGTH_REPLYSTAYQUIET 4 // No reply +#define ISO15693_MAXLENGTH_REPLYREADSINGLEBLOCK MAX_BUFFER_SIZE // 8 + 8 + 8 + 64 + 16 = 104bits => 13 bytes +#define ISO15693_MAXLENGTH_REPLYWRITESINGLEBLOCK 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYLOCKSINGLEBLOCK 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYREADMULBLOCK MAX_BUFFER_SIZE +#define ISO15693_MAXLENGTH_REPLYSELECT 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYRESETTOREADY 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYWRTITEAFI 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYWRTITEDSFID 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYLOCKAFI 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYLOCKDSFID 4 // 8 + 8 + 16 = 32 bits => 4 bytes +#define ISO15693_MAXLENGTH_REPLYGETMULSECURITY MAX_BUFFER_SIZE +#define ISO15693_MAXLENGTH_REPLYGETSYSTEMINFO 15 // 8 + 8 + 64 + 8 + 8 + 8 + 16 = 112 bits => 15 bytes + + +/* CRC parameters ----------------------------------------------------------------------------- */ +#define ISO15693_OFFSET_LENGTH PCD_LENGTH_OFFSET +#define ISO15693_CRC_MASK 0x02 +#define ISO15693_CRC_ERROR_CODE 0x02 +#define ISO15693_COLISION_MASK 0x01 +#define ISO15693_COLISION_ERROR_CODE 0x01 + +#define ISO15693_CRC_MASK_TYPE_A 0x20 +#define ISO15693_CRC_ERROR_CODE_TYPE_A 0x20 + + +#define ISO15693_MAXLENGTH_BLOCKSIZE 0x32 + +typedef struct { +int8_t DataRate , // 0 => 26k 1 => 52 k 2 => 6k 3=>RFU + WaitOrSOF , // 0 => respect 312 µs 1=> wait for SOF + ModulationDepth , // 0 => 100% modulation 1=> 10% modulation + SubCarrier , // 0 => single 1=> Dual + AppendCRC ; // 1=> append 0=> don't append +}ISO15693ConfigStruct; + +// CRC 16 constants +#define ISO15693_PRELOADCRC16 0xFFFF +#define ISO15693_POLYCRC16 0x8408 +#define ISO15693_MASKCRC16 0x0001 +#define ISO15693_RESIDUECRC16 0xF0B8 + + + +/* --------------------------------------------------------------------------------- + * --- Local Functions + * --------------------------------------------------------------------------------- */ + +/* ISO15693 functions --- */ + +/* configure the PCD --- */ +int8_t ISO15693_Init(void); + +/* ISO15693 commands --- */ +int8_t ISO15693_RunInventory16slots(const uint8_t Flags , const uint8_t AFI,uint8_t *NbTag,uint8_t *pUIDout); +int8_t ISO15693_RunAntiCollision(const uint8_t Flags , const uint8_t AFI,uint8_t *NbTag,uint8_t *pUIDout); + +// Get functions +int8_t ISO15693_GetUID(uint8_t *UIDout); +int8_t ISO15693_GetTagIdentification(uint16_t *Length_Memory_TAG, uint8_t *Tag_Density, uint8_t *IC_Ref_TAG); +int8_t ISO15693_GetSystemInfo(const uint8_t Flags, const uint8_t *UIDin ,uint8_t *pResponse); + +// Tag functions +uint8_t ISO15693_ReadBytesTagData(uint8_t Tag_Density, uint8_t IC_Ref_Tag, uint8_t *Data_To_Read, uint16_t NbBytes_To_Read, uint16_t FirstBytes_To_Read); +uint8_t ISO15693_WriteBytes_TagData(uint8_t Tag_Density, uint8_t *Data_To_Write, uint16_t NbBytes_To_Write, uint16_t FirstBytes_To_Write); + +#ifdef ISO15693_ALLCOMMANDS + +int8_t ISO15693_LockSingleBlock(const uint8_t Flags, const uint8_t *UIDin, const uint8_t BlockNumber,uint8_t *pResponse); + +int8_t ISO15693_Select(const uint8_t Flags, const uint8_t *UIDin, const uint8_t AppendCRC,const uint8_t *CRC16,uint8_t *pResponse); +int8_t ISO15693_WriteAFI(const uint8_t Flags, const uint8_t *UIDin,const uint8_t AFIToWrite,uint8_t *pResponse); +int8_t ISO15693_LockAFI(const uint8_t Flags, const uint8_t *UIDin, uint8_t *pResponse); +int8_t ISO15693_WriteDSFID(const uint8_t Flags, const uint8_t *UIDin,const uint8_t DSFIDToWrite,uint8_t *pResponse); +int8_t ISO15693_LockDSFID(const uint8_t Flags, const uint8_t *UIDin, uint8_t *pResponse); +int8_t ISO15693_GetMultipleBlockSecutityStatus(const uint8_t Flags, const uint8_t *UIDin, const uint8_t BlockNumber, const uint8_t NbBlocks,uint8_t *pResponse); +#endif /* ISO15693_ALLCOMMANDS*/ + + +int8_t ISO15693_SplitInventoryResponse(const uint8_t *ReaderResponse,const uint8_t Length,uint8_t *Flags , uint8_t *DSFIDextract, uint8_t *UIDoutIndex); + +#ifdef __cplusplus +} +#endif + +#endif /* __ISO15693_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso18092pcd.cpp b/src/lib_iso18092pcd.cpp new file mode 100644 index 0000000..5ff3b29 --- /dev/null +++ b/src/lib_iso18092pcd.cpp @@ -0,0 +1,221 @@ +/** + ****************************************************************************** + * @file lib_iso18092pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso18092 communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_iso18092pcd.h" + +/* Felica */ +#define PCD_TYPEF_ARConfigA 0x01 +#define PCD_TYPEF_ARConfigB 0x51 + +//#ifdef __cplusplus +// extern "C" { +//#endif + + /* Variables for the different modes */ +extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +extern PCD_PROTOCOL TechnoSelected; + +FELICA_CARD FELICA_Card; + +static const uint8_t REQC[] = {SEND_RECEIVE ,0x05,0x00,0x12,0xFC,0x01,0x03}; + +static int8_t FELICA_Init( uint8_t *pDataRead ); +static int8_t FELICA_REQC( uint8_t *pDataRead ); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + + /** @addtogroup ISO18092_pcd + * @{ + * @brief This part of the library is used to follow ISO18092. + */ + + +/** @addtogroup lib_iso18092pcd_Private_Functions + * @{ + */ + +/** + * @brief Initializes the xx95HF for the FELICA protocol + * @param void + * @return TRUE (if well configured) / FALSE (Communication issue) + */ +static int8_t FELICA_Init( uint8_t *pDataRead ) +{ + int8_t status; + u8 ProtocolSelectParameters [4] = {0x51, 0x13, 0x01,0x0D}; + u8 WriteAmpliGain [2] = {PCD_TYPEF_ARConfigA, PCD_TYPEF_ARConfigB}; + u8 AutoFDet [2] = {0x02,0xA1}; + + + /* sends a protocol Select command to the pcd to configure it */ + errchk(PCD_ProtocolSelect(0x05,PCD_PROTOCOL_FELICA,ProtocolSelectParameters,pDataRead)); + TechnoSelected = PCDPROTOCOL_18092; + + /* in order to adjust the demodulation gain of the PCD*/ + errchk(PCD_WriteRegister ( 0x04,AFE_ANALOG_CONF_REG_SELECTION,0x01,WriteAmpliGain,pDataRead)); + + /* in order to adjust the auto detect of the PCD*/ + errchk(PCD_WriteRegister ( 0x04,0x0A,0x01,AutoFDet,pDataRead)); + + /* GT min time to respect before sending REQ_C */ + delay(20); + delayMicroseconds(400); + + return ISO18092_SUCCESSCODE; +Error: + return ISO18092_ERRORCODE_DEFAULT; + +} + +/** + * @brief Handles the REQC command + * @param *pDataRead : Pointer on the response + * @return TRUE (if CR95HF answered ATQB) / FALSE (No ISO14443B in Field) + */ +static int8_t FELICA_REQC( uint8_t *pDataRead ) +{ + if(PCD_CheckSendReceive(REQC, pDataRead)!= ISO18092_SUCCESSCODE) + return ISO18092_ERRORCODE_DEFAULT; + + if (pDataRead[2] != 0x01) // If the answer is not an answer to REQC + return ISO18092_ERRORCODE_DEFAULT; + else + return ISO18092_SUCCESSCODE; +} + + +/** + * @} + */ + + +/** @addtogroup lib_iso18092pcd_Public_Functions + * @{ + */ + +void FELICA_Initialization( void ) +{ + uint8_t DataRead[MAX_BUFFER_SIZE]; + + /* Init the FeliCa communication */ + FELICA_Init(DataRead); +} + +/** + * @brief Checks if a FELICA card is in the field + * @param void + * @return ISO18092_SUCCESSCODE (A card is present) / ISO18092_ERRORCODE_DEFAULT (No card) + */ +int8_t FELICA_IsPresent( void ) +{ + uint8_t DataRead[MAX_BUFFER_SIZE]; + + /* Initializing buffer */ + memset(DataRead,0,MAX_BUFFER_SIZE); + + /* REQC attempt */ + if(FELICA_REQC(DataRead) != ISO18092_SUCCESSCODE ) + return ISO18092_ERRORCODE_DEFAULT; + + /* Filling of the data structure */ + FELICA_Card.IsDetected = true; + memcpy(FELICA_Card.ATQC, &DataRead[PCD_DATA_OFFSET], ATQC_SIZE); + memcpy(FELICA_Card.UID , &FELICA_Card.ATQC[1] , UID_SIZE_FELICA); + + devicemode = PCD; + nfc_tagtype = TT3; + + /* An ISO14443 card is in the field */ + return ISO18092_SUCCESSCODE; +} + +/** + * @brief Processing of the Anticolision for FELICA cards + * @param *message : contains message on the CR95HF replies + * @return ISO18092_SUCCESSCODE : the function is succesful + */ +int8_t FELICA_Anticollision( void ) +{ + /* Anticollision process done ! */ + return ISO18092_SUCCESSCODE; +} + +/** + * @brief Checks if a FELICA card is still in the field + * @param void + * @return ISO18092_SUCCESSCODE : the function is succesful + * @return ISO18092_ERRORCODE_DEFAULT : No card in the RF field + */ +int8_t FELICA_CardTest( void ) +{ + uint8_t DummyBuffer[MAX_BUFFER_SIZE]; + + if(PCD_CheckSendReceive(REQC, DummyBuffer)!= ISO18092_SUCCESSCODE) + return ISO18092_ERRORCODE_DEFAULT; + + return ISO18092_SUCCESSCODE; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso18092pcd.h b/src/lib_iso18092pcd.h new file mode 100644 index 0000000..fabdfbd --- /dev/null +++ b/src/lib_iso18092pcd.h @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * @file lib_iso18092pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso18092 communication + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __FELICA_H +#define __FELICA_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" +#include "stdbool.h" + +/* -------------------------------------------------------------------------- */ +#define ATQC_SIZE 0x20 +#define UID_SIZE_FELICA 8 + +/* command code -------------------------------------------------------------- */ +#define ISO18092_COMMAND_REQC 0x00 +#define ISO18092_RESPONSE_REQC 0x01 + +/* code status -------------------------------------------------------------------------- */ +#define ISO18092_SUCCESSCODE RESULTOK +#define ISO18092_ERRORCODE_DEFAULT 0xC1 + +typedef struct{ + uint8_t ATQC[ATQC_SIZE]; + uint8_t UID [UID_SIZE_FELICA]; + bool IsDetected; +// char LogMsg[120]; +}FELICA_CARD; + +//extern FELICA_CARD FELICA_Card; + +/* --------------------------------------------------------------------------------- + * --- Local Functions + * --------------------------------------------------------------------------------- */ +void FELICA_Initialization( void ); +int8_t FELICA_IsPresent ( void ); +int8_t FELICA_CardTest ( void ); +int8_t FELICA_Anticollision( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* __FELICA_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso7816pcd.cpp b/src/lib_iso7816pcd.cpp new file mode 100644 index 0000000..3287c3d --- /dev/null +++ b/src/lib_iso7816pcd.cpp @@ -0,0 +1,275 @@ +/** + ****************************************************************************** + * @file lib_iso7816pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso 7816 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_iso7816pcd.h" + +extern TagType_t nfc_tagtype; + +uint8_t bufferSend[MAX_BUFFER_SIZE+3], + bufferReceive[MAX_BUFFER_SIZE+3]; + +static APDU_Commands APDUcommand ; +static APDU_Responce APDUresponse; +static uint8_t BlockNumber = 0x02; + +static int8_t ISO7816_SendReceiveAPDU ( uint8_t *pDataReceived ); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + + /** @addtogroup ISO7816_pcd + * @{ + * @brief This part of the library is used to follow ISO7816. + */ + + +/** @addtogroup lib_iso7816pcd_Private_Functions + * @{ + */ + + + +/** + * @brief this function sends the APDU command to the RF transceiver and returns its response + * @return ISO7816_SUCCESSCODE : the function is succesful + * @return ISO7816_ERRORCODE_RESPONSE : the function is not succesful. The tag returns an error code + * @return ISO7816_ERRORCODE_DEFAULT : the function is not succesful. + */ +static int8_t ISO7816_SendReceiveAPDU ( uint8_t *pDataReceived ) +{ + uint8_t NthByte=0; + int8_t status; + uint8_t bufferFWI[3]; + + bufferSend[NthByte++] = BlockNumber; + BlockNumber ^= 0x01; + + // add the class byte + bufferSend[NthByte++] = APDUcommand.Header.CLA; + // add the command code + bufferSend[NthByte++] = APDUcommand.Header.INS; + // add the P1 and P2 fields + bufferSend[NthByte++] = APDUcommand.Header.P1; + bufferSend[NthByte++] = APDUcommand.Header.P2; + // add the LC field + if (APDUcommand.Body.LC) + bufferSend[NthByte++] = APDUcommand.Body.LC; + // add the datafield field + memcpy(&(bufferSend[NthByte]),APDUcommand.Body.pData,APDUcommand.Body.LC); + NthByte += APDUcommand.Body.LC; + + // add the LE field + if (APDUcommand.Body.LE || (APDUcommand.Header.P1 == 0x04 && APDUcommand.Header.P2 == 0x00)) + bufferSend[NthByte++] = APDUcommand.Body.LE; + + // control byte append CRC + 8 bits + if( nfc_tagtype == TT4A ) + bufferSend[NthByte++] = SEND_MASK_APPENDCRC | SEND_MASK_8BITSINFIRSTBYTE; + + // send the command to the RF transceiver + errchk(PCD_SendRecv(NthByte,bufferSend,pDataReceived)) + + /* Test if a time extension is required */ + if (pDataReceived[2] == 0xF2) + { + /* Modify temporarly FDT */ + ISO14443A_ConfigFDT(pDataReceived[3]); + + /* Send the same buffer in order to accept the time extension */ + memcpy(bufferFWI,&pDataReceived[2],2); + + if( nfc_tagtype == TT4A ) + { + bufferFWI[2] = SEND_MASK_APPENDCRC | SEND_MASK_8BITSINFIRSTBYTE; + PCD_SendRecv(3,bufferFWI, pDataReceived); + } + else + PCD_SendRecv(2,bufferFWI, pDataReceived); + + /* Setback FDT default value */ + ISO14443A_ConfigFDT(1); + } + + if( nfc_tagtype == TT4A ) + { + APDUresponse.SW1 = pDataReceived[pDataReceived[PCD_LENGTH_OFFSET]-5]; + APDUresponse.SW2 = pDataReceived[pDataReceived[PCD_LENGTH_OFFSET]-4]; + } + else + { + APDUresponse.SW1 = pDataReceived[pDataReceived[PCD_LENGTH_OFFSET]-3]; + APDUresponse.SW2 = pDataReceived[pDataReceived[PCD_LENGTH_OFFSET]-2]; + } + + if (APDUresponse.SW1 == 0x90 && APDUresponse.SW2 == 0x00) + return ISO7816_SUCCESSCODE; + else + return ISO7816_ERRORCODE_RESPONSE; + +Error : + return ISO7816_ERRORCODE_DEFAULT; +} + +/** + * @} + */ + +/** @addtogroup lib_iso7816pcd_Public_Functions + * @{ + */ + +/** + * @brief this function sends the Select command + * @param P1byte : P1 value + * @param P2byte : P2 value + * @param LCbyte : LC value + * @param PData : pointer of the File ID + * @return ISO7816_SUCCESSCODE : the function is successful and the tag returns a success code + * @return ISO7816_ERRORCODE_DEFAULT : the function is not successful + */ +int8_t ISO7816_SelectFile(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LCbyte ,uint8_t *pDataSel) +{ + // add the class byte + APDUcommand.Header.CLA = ISO7816_CLASS_0X00; + // add the command code + APDUcommand.Header.INS = ISO7816_SELECT_FILE; + // add the P1 and P2 fields + APDUcommand.Header.P1 = P1byte; + APDUcommand.Header.P2 = P2byte; + // add the LC field + APDUcommand.Body.LC = LCbyte; + //add the FileId field + memcpy(APDUcommand.Body.pData, pDataSel, APDUcommand.Body.LC); + // the LE field is empty + APDUcommand.Body.LE = 0x00; + + // Special case for the selectApplication + // The block number HAS TO be 0x02 + if (APDUcommand.Header.P1 == 0x04 && APDUcommand.Header.P2 == 0x00) + BlockNumber = 0x02; + + return ISO7816_SendReceiveAPDU ( bufferReceive ); +} + + +/** + * @brief this function sends a ReadBinary command + * @param P1byte : P1 value + * @param P2byte : P2 value + * @param LEbyte : LE value + * @param *pDataRead : Pointer to the data read from the tag + * @return ISO7816_SUCCESSCODE : the function is successful and the tag returns a success code + * @return ISO7816_ERRORCODE_DEFAULT : the function is not successful + */ +int8_t ISO7816_ReadBinary(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LEbyte , uint8_t *pDataRead) +{ + // add the class byte + APDUcommand.Header.CLA = ISO7816_CLASS_0X00; + // add the command code + APDUcommand.Header.INS = ISO7816_READ_BINARY; + // add the P1 and P2 fields + APDUcommand.Header.P1 = P1byte; + APDUcommand.Header.P2 = P2byte; + // the LC field is empty + APDUcommand.Body.LC = 0x00; + + APDUcommand.Body.LE = LEbyte; + + return ISO7816_SendReceiveAPDU ( pDataRead ); + +} + +/** + * @brief this function sends the UpdateBinary command. + * @param P1byte : P1 value + * @param P2byte : P2 value + * @param LCbyte : LC value + * @param *pData : Pointer to the data to write + * @return ISO7816_SUCCESSCODE : the function is successful and the tag returns a success code + * @return ISO7816_ERRORCODE_DEFAULT : the function is not successful + */ +int8_t ISO7816_UpdateBinary(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LCbyte , uint8_t *pData) +{ + + // add the class byte + APDUcommand.Header.CLA = ISO7816_CLASS_0X00; + // add the command code + APDUcommand.Header.INS = ISO7816_UPDATE_BINARY; + // add the P1 and P2 fields + APDUcommand.Header.P1 = P1byte; + APDUcommand.Header.P2 = P2byte; + // add the datafield field + APDUcommand.Body.LC = LCbyte; + // add data to write + memcpy(APDUcommand.Body.pData,pData,APDUcommand.Body.LC); + // the LE field is empty + APDUcommand.Body.LE = 0x00; + + return ISO7816_SendReceiveAPDU ( bufferReceive ); + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_iso7816pcd.h b/src/lib_iso7816pcd.h new file mode 100644 index 0000000..19e45ed --- /dev/null +++ b/src/lib_iso7816pcd.h @@ -0,0 +1,110 @@ +/** + ****************************************************************************** + * @file lib_iso7816pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Manage the iso 7816 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion --------------------------------------------------------*/ +#ifndef __LIB_ISO7816_H +#define __LIB_ISO7816_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes -------------------------------------------------------------------------------------*/ +#include "lib_iso14443Apcd.h" +#include "lib_pcd.h" + +/* status and error code ---------------------------------------------------------------------- */ +#define ISO7816_SUCCESSCODE RESULTOK +#define ISO7816_ERRORCODE_DEFAULT 0x71 +#define ISO7816_ERRORCODE_RESPONSE 0x72 +#define ISO7816_ERRORCODE_SENDERRORCODE 0x73 + +/* Iblock ------------------------------------------------------------------------------------- */ +#define ISO7816_IBLOCK02 0x02 +#define ISO7816_IBLOCK03 0x03 + +#define ISO7816_SELECT_FILE 0xA4 +#define ISO7816_UPDATE_BINARY 0xD6 +#define ISO7816_READ_BINARY 0xB0 + +#define ISO7816_CLASS_0X00 0x00 +#define ISO7816_CLASS_STM 0xA2 + +// offset of the different field of the APDU +#define ISO7816_ADPUOFFSET_BLOCK 0x00 +#define ISO7816_ADPUOFFSET_CLASS ISO7816_ADPUOFFSET_BLOCK + 1 +#define ISO7816_ADPUOFFSET_INS ISO7816_ADPUOFFSET_BLOCK + 2 +#define ISO7816_ADPUOFFSET_P1 ISO7816_ADPUOFFSET_BLOCK + 3 +#define ISO7816_ADPUOFFSET_P2 ISO7816_ADPUOFFSET_BLOCK + 4 +#define ISO7816_ADPUOFFSET_LC ISO7816_ADPUOFFSET_BLOCK + 5 +#define ISO7816_ADPUOFFSET_DATA ISO7816_ADPUOFFSET_BLOCK + 6 + +/* ADPU-Header command structure ---------------------------------------------*/ +typedef struct +{ + uint8_t CLA; /* Command class */ + uint8_t INS; /* Operation code */ + uint8_t P1; /* Selection Mode */ + uint8_t P2; /* Selection Option */ +} Header; + +/* ADPU-Body command structure -----------------------------------------------*/ +typedef struct +{ + uint8_t LC; /* Data field length */ + uint8_t pData[256]; /* Command parameters */ // pointer on the transceiver buffer = *(ReaderRecBuf[CR95HF_DATA_OFFSET + ISO7816_ADPUOFFSET_DATA]) + uint8_t LE; /* Expected length of data to be returned */ +} Body; + +/* ADPU Command structure ----------------------------------------------------*/ +typedef struct +{ + Header Header; + Body Body; +} APDU_Commands; + +/* SC response structure -----------------------------------------------------*/ +typedef struct +{ + uint8_t SW1; /* Command Processing status */ + uint8_t SW2; /* Command Processing qualification */ +} APDU_Responce; + + +int8_t ISO7816_SelectFile(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LCbyte , uint8_t *PData); +int8_t ISO7816_ReadBinary(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LEbyte , uint8_t *pDataRead); +int8_t ISO7816_UpdateBinary(const uint8_t P1byte , const uint8_t P2byte , const uint8_t LCbyte , uint8_t *pData); + +#ifdef __cplusplus +} +#endif + +#endif /* __SMARTCARD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype1pcd.cpp b/src/lib_nfctype1pcd.cpp new file mode 100644 index 0000000..39ffe27 --- /dev/null +++ b/src/lib_nfctype1pcd.cpp @@ -0,0 +1,248 @@ +/** + ****************************************************************************** + * @file lib_nfctype1pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type1 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_nfctype1pcd.h" + +extern uint8_t TT1Tag[]; +extern uint8_t TagUID[]; + +static uint8_t PCDNFCT1_ReadAll(uint8_t *pBufferRead); +static uint8_t PCDNFCT1_WriteErase(uint8_t address, uint8_t byte); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup NFC_type1_pcd + * @{ + * @brief This file is used to exchange with NFC FORUM Type1 Tag. +*/ + + +/** @addtogroup lib_nfctype1pcd_Private_Functions + * @{ + */ + + +/** + * @brief This function generates the ReadAll command + * @param pBufferRead : Pointer on the buffer which will contain the data read + * @retval PCDNFCT1_OK : Command success + * @retval PCDNFCT1_ERROR : Transmission error + */ +static uint8_t PCDNFCT1_ReadAll(uint8_t *pBufferRead) +{ + uint8_t buffer[] = {PCDNFCT1_READALL,0x00,0x00,0,0,0,0,PCDNFCT1_TOPAZ_MODE}; + + memcpy(&buffer[3], &TagUID[4],4); + + if (PCD_SendRecv(8,buffer, pBufferRead) == PCD_SUCCESSCODE) + return PCDNFCT1_OK; + else + return PCDNFCT1_ERROR; +} + +/** + * @brief This function generates the WriteErase command + * @param address : The address of the byte to write + * @param byte : The byte to write + * @retval PCDNFCT1_OK : Command success + * @retval PCDNFCT1_ERROR : Transmission error + */ +static uint8_t PCDNFCT1_WriteErase(uint8_t address, uint8_t byte) +{ + uint8_t buffer[] = {PCDNFCT1_WRITE_E,0,0,0,0,0,0,PCDNFCT1_TOPAZ_MODE}; + uint8_t bufferRead[16]; + + /* Cannot write protected sector */ + if (address < 13 || address > 102) + return PCDNFCT1_ERROR; + + buffer[1] = address; + buffer[2] = byte; + memcpy(&buffer[3], &TagUID[4],4); + + if (PCD_SendRecv(8,buffer, bufferRead) == PCD_SUCCESSCODE) + return PCDNFCT1_OK; + else + return PCDNFCT1_ERROR; +} + +/** + * @} + */ + +/** @addtogroup lib_nfctype1pcd_Public_Functions + * @{ + */ + +/** + * @brief This function reads the NDEF message from a tag type 1 and store result in the TT1Tag buffer + * @retval PCDNFCT1_OK : Command success + * @retval PCDNFCT1_ERROR : Transmission error + */ +uint8_t PCDNFCT1_ReadNDEF( void ) +{ + uint8_t status; + uint8_t buffer[NFCT1_MAX_TAGMEMORY+2]; + uint16_t NDEFposition = 16, size; + + errchk(PCDNFCT1_ReadAll(buffer)); + + if ((buffer[2] & PCDNFCT1_NDEF_CAPABLE_MSK) != 0x10) /* NDEF capable TT1 if H0 = 0x1X */ + return PCDNFCT1_ERROR_NOT_FORMATED; + if (buffer[12] != PCDNFCT1_NDEF_MNB) /* CC file with NDEF info */ + return PCDNFCT1_ERROR_NOT_FORMATED; + if (buffer[14] != 0x0E) /* Check the size (only static memory supported yet)*/ + return PCDNFCT1_ERROR_MEMORY_INTERNAL; + + // Searching for the first NDEF TLV + while (buffer[NDEFposition] != PCDNFCT1_TLV_NDEF) + { + if (buffer[NDEFposition] == PCDNFCT1_TLV_EMPTY) // Empty TLV + NDEFposition++; + else if (buffer[NDEFposition] == PCDNFCT1_TLV_LOCK || buffer[NDEFposition] == PCDNFCT1_TLV_MEM) // Lock CTRL TLV or Mem CTRL TLV + NDEFposition+=5; + else + return PCDNFCT1_ERROR; // Other TLV not supported yet (proprietary) + if (NDEFposition > NFCT1_MAX_TAGMEMORY) + return PCDNFCT1_ERROR; // EOF and no NDEF TLV found + } + + // Get the length of the message and copy it + if (buffer[NDEFposition+1] == 0xFF) // Long message (cannot happen with static memory...) + { + size = buffer[NDEFposition+2]<<8|buffer[NDEFposition+3]; + memcpy(&TT1Tag[16],&buffer[NDEFposition],size+5); + } + else // Short message + { + memcpy(&TT1Tag[16],&buffer[NDEFposition],buffer[NDEFposition+1]+3); + } + + return PCDNFCT1_OK; +Error: + return PCDNFCT1_ERROR; +} + +/** + * @brief This function writes the NDEF message to a tag type 1 from the TT1Tag buffer + * @retval PCDNFCT1_OK : Command success + * @retval PCDNFCT1_ERROR : Transmission error + * @retval PCDNFCT1_ERROR_MEMORY : Not enough memory available on the tag + */ +uint8_t PCDNFCT1_WriteNDEF( void ) +{ + uint8_t status; + uint8_t buffer[NFCT1_MAX_TAGMEMORY+2]; + uint16_t NDEFposition = 16, size, i; + + errchk(PCDNFCT1_ReadAll(buffer)); + + if ((buffer[2] & PCDNFCT1_NDEF_CAPABLE_MSK) != 0x10) /* NDEF capable TT1 if H0 = 0x1X */ + return PCDNFCT1_ERROR_NOT_FORMATED; + if (buffer[12] != PCDNFCT1_NDEF_MNB) /* CC file with NDEF info */ + return PCDNFCT1_ERROR_NOT_FORMATED; + if (buffer[14] != 0x0E) /* Check the size (only static memory supported yet)*/ + return PCDNFCT1_ERROR; + + // Searching for the first NDEF TLV + while (buffer[NDEFposition] != PCDNFCT1_TLV_NDEF) + { + if (buffer[NDEFposition] == PCDNFCT1_TLV_EMPTY) // Empty TLV + NDEFposition++; + else if (buffer[NDEFposition] == PCDNFCT1_TLV_LOCK || buffer[NDEFposition] == PCDNFCT1_TLV_MEM) // Lock CTRL TLV or Mem CTRL TLV + NDEFposition+=5; + else + return PCDNFCT1_ERROR; // Other TLV not supported yet (proprietary) + if (NDEFposition > NFCT1_MAX_TAGMEMORY) + return PCDNFCT1_ERROR; // EOF and no NDEF TLV found + } + + if (TT1Tag[15] == 0xFF) + size = (((TT1Tag[16])<<8) | (TT1Tag[17])) + 4; + else + size = TT1Tag[15]+2; + + if (size > NFCT1_MAX_TAGMEMORY-32) + return PCDNFCT1_ERROR_MEMORY_TAG; + + // Invalidate the NDEF message + PCDNFCT1_WriteErase(8,PCDNFCT1_NDEF_DISABLE); + + NDEFposition-=3; + for(i=15;i<15+size;i++,NDEFposition++) + { + errchk(PCDNFCT1_WriteErase(NDEFposition,TT1Tag[i])); + } + + // Validate the NDEF message + PCDNFCT1_WriteErase(8,PCDNFCT1_NDEF_MNB); + + return PCDNFCT1_OK; +Error: + return PCDNFCT1_ERROR; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype1pcd.h b/src/lib_nfctype1pcd.h new file mode 100644 index 0000000..4887c16 --- /dev/null +++ b/src/lib_nfctype1pcd.h @@ -0,0 +1,75 @@ +/** + ****************************************************************************** + * @file lib_nfctype1pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type1 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_NFCTYPE1PCD_H +#define _LIB_NFCTYPE1PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" + +/* Error codes */ +#define PCDNFCT1_OK PCDNFC_OK +#define PCDNFCT1_ERROR PCDNFC_ERROR +#define PCDNFCT1_ERROR_MEMORY_TAG PCDNFC_ERROR_MEMORY_TAG +#define PCDNFCT1_ERROR_MEMORY_INTERNAL PCDNFC_ERROR_MEMORY_INTERNAL +#define PCDNFCT1_ERROR_NOT_FORMATED PCDNFC_ERROR_NOT_FORMATED + +/* Command List */ +#define PCDNFCT1_READALL 0x00 +#define PCDNFCT1_WRITE_E 0x53 + +/* Mask */ +#define PCDNFCT1_NDEF_CAPABLE_MSK 0xF0 + +/* TLV */ +#define PCDNFCT1_TLV_EMPTY 0x00 +#define PCDNFCT1_TLV_LOCK 0x01 +#define PCDNFCT1_TLV_MEM 0x02 +#define PCDNFCT1_TLV_NDEF 0x03 + +#define PCDNFCT1_NDEF_MNB 0xE1 +#define PCDNFCT1_NDEF_DISABLE 0x00 + +#define PCDNFCT1_TOPAZ_MODE 0xA8 + +/* Functions */ +uint8_t PCDNFCT1_ReadNDEF( void ); +uint8_t PCDNFCT1_WriteNDEF( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_NFCTYPE1PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype2pcd.cpp b/src/lib_nfctype2pcd.cpp new file mode 100644 index 0000000..a7d2a94 --- /dev/null +++ b/src/lib_nfctype2pcd.cpp @@ -0,0 +1,344 @@ +/** + ****************************************************************************** + * @file lib_nfctype2pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type2 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "Arduino.h" +#include "lib_nfctype2pcd.h" + +extern uint8_t TT2Tag[]; + +static uint8_t PCDNFCT2_Read(uint8_t blocNbr, uint8_t *pBufferRead); +static uint8_t PCDNFCT2_Write(uint8_t blocNbr, uint8_t *pBufferWrite); +static uint8_t PCDNFCT2_SectorSelect(uint8_t sector); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup NFC_type2_pcd + * @{ + * @brief This file is used to exchange with NFC FORUM Type2 Tag. +*/ + + +/** @addtogroup lib_nfctype2pcd_Private_Functions + * @{ + */ + + +/** + * @brief This function generates the Read command + * @param blocNbr : First bloc number + * @param pBufferRead : Pointer on the buffer which will contain the data read + * @retval PCDNFCT2_OK : Command success + * @retval PCDNFCT2_ERROR : Transmission error + */ +static uint8_t PCDNFCT2_Read(uint8_t blocNbr, uint8_t *pBufferRead) +{ + uint8_t buffer[] = {PCDNFCT2_READ,0,SEND_MASK_APPENDCRC|SEND_MASK_8BITSINFIRSTBYTE}; + + buffer[1] = blocNbr; + + if (PCD_SendRecv(3,buffer, pBufferRead) == PCD_SUCCESSCODE) + return PCDNFCT2_OK; + else + return PCDNFCT2_ERROR; +} + +/** + * @brief This function generates the Write command + * @param blocNbr : First bloc number + * @param pBufferWrite : Pointer on the buffer which contains the data to write + * @retval PCDNFCT2_OK : Command success + */ +static uint8_t PCDNFCT2_Write(uint8_t blocNbr, uint8_t *pBufferWrite) +{ + uint8_t pBufferRead[32]; + uint8_t buffer[] = {PCDNFCT2_WRITE,0,0,0,0,0,SEND_MASK_APPENDCRC|SEND_MASK_8BITSINFIRSTBYTE}; + + buffer[1] = blocNbr; + memcpy(&buffer[2], pBufferWrite,4); + + PCD_SendRecv(7,buffer, pBufferRead); + return PCDNFCT2_OK; +} + +/** + * @brief This function generates the SectorSelect command + * @param sector : Sector number (0/1) + * @retval PCDNFCT2_OK : Command success + * @retval PCDNFCT2_ERROR : Transmission error + */ +static uint8_t PCDNFCT2_SectorSelect(uint8_t sector) +{ + uint8_t pBufferRead[32]; + uint8_t buffer[] = {PCDNFCT2_SECTOR_SEL,0xFF,SEND_MASK_APPENDCRC|SEND_MASK_8BITSINFIRSTBYTE}; // First part + uint8_t buffer2[] = {0,0x00,0x00,0x00,SEND_MASK_APPENDCRC|SEND_MASK_8BITSINFIRSTBYTE}; // Second part + + buffer2[0] = sector; + + PCD_SendRecv(3,buffer, pBufferRead); + if (pBufferRead[0] == 0x90 && pBufferRead[1] == 0x04 && pBufferRead[2] == 0x0A) // ACK + { + PCD_SendRecv(5,buffer2, pBufferRead); + if (pBufferRead[0] == 0x87 && pBufferRead[1] == 0x00) // Passive ACK = no answer so ST95HF send a timeout + return PCDNFCT2_OK; + else + return PCDNFCT2_ERROR; + } + else + return PCDNFCT2_ERROR; +} + +/** + * @} + */ + +/** @addtogroup lib_nfctype2pcd_Public_Functions + * @{ + */ + +/** + * @brief This function reads the NDEF message from a tag type 2 and store result in the TT2Tag buffer + * @retval PCDNFCT2_OK : Command success + * @retval PCDNFCT2_ERROR : Transmission error + * @retval PCDNFCT2_ERROR_LOCKED : The tag cannot be read (CC lock) + */ +uint8_t PCDNFCT2_ReadNDEF( void ) +{ + uint8_t status; + uint8_t bufferRead[PCDNFCT2_READ_SIZE_BUFFER]; + uint8_t buffer[NFCT2_MAX_TAGMEMORY]; + uint16_t size, totalSize, i; + uint16_t NDEFposition = 16; + + // Check if CC is present with NDEF capability + errchk(PCDNFCT2_Read(0,buffer)); + if (buffer[14] != PCDNFCT2_NDEF_MNB) + return PCDNFCT2_ERROR_NOT_FORMATED; + // Check if the tag is not protected + if ((buffer[17]&PCDNFCT2_READ_MSK) != 0x00) + return PCDNFCT2_ERROR_LOCKED; + // Read the size from CC + totalSize = buffer[16]*8; + + // Check if there is enough memory available to read the tag + if (totalSize > NFCT2_MAX_TAGMEMORY) + return PCDNFCT2_ERROR_MEMORY_INTERNAL; + + if (totalSize > PCDNFCT2_SECTOR_SIZE) + size = PCDNFCT2_SECTOR_SIZE; + else + size = totalSize; + // Read the whole memory + for (i=0;i PCDNFCT2_SECTOR_SIZE) + { + errchk(PCDNFCT2_SectorSelect(1)); + size = totalSize-PCDNFCT2_SECTOR_SIZE; + for (i=4;i totalSize) + return PCDNFCT2_ERROR; // EOF and no NDEF TLV found + } + + // Get the length of the message and copy it + if (buffer[NDEFposition+1] == 0xFF) // Long message + { + size = buffer[NDEFposition+2]<<8|buffer[NDEFposition+3]; + memcpy(&TT2Tag[16],&buffer[NDEFposition],size+5); + } + else // Short message + { + memcpy(&TT2Tag[16],&buffer[NDEFposition],buffer[NDEFposition+1]+3); + } + + return PCDNFCT2_OK; +Error: + return PCDNFCT2_ERROR; +} + +/** + * @brief This function writes the NDEF message to a tag type 2 from the TT2Tag buffer + * @retval PCDNFCT2_OK : Command success + * @retval PCDNFCT2_ERROR : Transmission error + * @retval PCDNFCT2_ERROR_LOCKED : The tag cannot be write or read (CC lock) + * @retval PCDNFCT2_ERROR_MEMORY : Not enough memory available on the tag + */ +uint8_t PCDNFCT2_WriteNDEF( void ) +{ + uint8_t status; + uint8_t bufferRead[PCDNFCT2_READ_SIZE_BUFFER]; + uint8_t buffer[NFCT2_MAX_TAGMEMORY]; + uint8_t byteSize; + uint16_t size, totalSize, i, firstBloc; + uint16_t NDEFposition = 16; + + // Check if CC is present with NDEF capability + errchk(PCDNFCT2_Read(0,buffer)); + if (buffer[14] != PCDNFCT2_NDEF_MNB) + return PCDNFCT2_ERROR_NOT_FORMATED; + // Check if the tag is not protected for read and write + if ((buffer[17]&(PCDNFCT2_READ_MSK|PCDNFCT2_WRITE_MSK)) != 0x00) + return PCDNFCT2_ERROR_LOCKED; + // Read the size from CC + totalSize = buffer[16]*8; + // Read the size of message + if (TT2Tag[17] == 0xFF) size = TT2Tag[18]<<8|TT2Tag[19]; + else size = TT2Tag[17]; + + // Check if there is enough memory available + if (size > totalSize) + return PCDNFCT2_ERROR_MEMORY_TAG; + + if (totalSize > PCDNFCT2_SECTOR_SIZE) + size = PCDNFCT2_SECTOR_SIZE; + else + size = totalSize; + // Read the whole memory + for (i=0;i PCDNFCT2_SECTOR_SIZE) + { + PCDNFCT2_SectorSelect(1); + size = totalSize-PCDNFCT2_SECTOR_SIZE; + for (i=4;i totalSize) + return PCDNFCT2_ERROR; // EOF and no NDEF TLV found + } + + // Write the message + if (TT2Tag[17] == 0xFF) + size = ((TT2Tag[18]<<8) | (TT2Tag[19])) + 5; + else + size = TT2Tag[17] +3; + + memcpy(&buffer[NDEFposition],&TT2Tag[16],size); + + // The size has to be 0 for the first write + byteSize = TT2Tag[17]; + buffer[NDEFposition+1] = 0; + + firstBloc = NDEFposition>>2; + + // To be sure to write the first sector + if (totalSize > PCDNFCT2_SECTOR_SIZE) + { + errchk(PCDNFCT2_SectorSelect(0)); + } + // Write all the blocks + for (i=firstBloc;i<=(size>>2)+firstBloc;i++) + { + errchk(PCDNFCT2_Write(i, &buffer[i*4])); + // Tag from NXP needs this delay... + delay(5); + } + + // Write the size (numBloc = (NDEFposition+1)>>2) + buffer[NDEFposition+1] = byteSize; + errchk(PCDNFCT2_Write(((NDEFposition+1)>>2), &buffer[((NDEFposition+1)>>2)*4])); + + return PCDNFCT2_OK; +Error: + return PCDNFCT2_ERROR; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype2pcd.h b/src/lib_nfctype2pcd.h new file mode 100644 index 0000000..f8b5cf5 --- /dev/null +++ b/src/lib_nfctype2pcd.h @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * @file lib_nfctype2pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type2 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_NFCTYPE2PCD_H +#define _LIB_NFCTYPE2PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" + +/* Error codes */ +#define PCDNFCT2_OK PCDNFC_OK +#define PCDNFCT2_ERROR PCDNFC_ERROR +#define PCDNFCT2_ERROR_MEMORY_TAG PCDNFC_ERROR_MEMORY_TAG +#define PCDNFCT2_ERROR_MEMORY_INTERNAL PCDNFC_ERROR_MEMORY_INTERNAL +#define PCDNFCT2_ERROR_LOCKED PCDNFC_ERROR_LOCKED +#define PCDNFCT2_ERROR_NOT_FORMATED PCDNFC_ERROR_NOT_FORMATED + +/* Command List */ +#define PCDNFCT2_READ 0x30 +#define PCDNFCT2_WRITE 0xA2 +#define PCDNFCT2_SECTOR_SEL 0xC2 + +/* Size */ +#define PCDNFCT2_READ_SIZE 16 +#define PCDNFCT2_READ_SIZE_BUFFER 18 +#ifndef PCDNFCT2_SECTOR_SIZE +// if not defined at application level, let's use 1024 for wider compatibility +// it can be reduced to lower values, e.g. 256, but with restrictions : +// issue on second sector read +#define PCDNFCT2_SECTOR_SIZE 1024 +#endif + +/* Mask */ +#define PCDNFCT2_READ_MSK 0xF0 +#define PCDNFCT2_WRITE_MSK 0x0F + +/* TLV */ +#define PCDNFCT2_TLV_EMPTY 0x00 +#define PCDNFCT2_TLV_LOCK 0x01 +#define PCDNFCT2_TLV_MEM 0x02 +#define PCDNFCT2_TLV_NDEF 0x03 + +#define PCDNFCT2_NDEF_MNB 0xE1 + +/* Functions */ +uint8_t PCDNFCT2_ReadNDEF( void ); +uint8_t PCDNFCT2_WriteNDEF( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_NFCTYPE2PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype3pcd.cpp b/src/lib_nfctype3pcd.cpp new file mode 100644 index 0000000..8b954dc --- /dev/null +++ b/src/lib_nfctype3pcd.cpp @@ -0,0 +1,349 @@ +/** + ****************************************************************************** + * @file lib_nfctype3pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type3 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_nfctype3pcd.h" + +extern FELICA_CARD FELICA_Card; +//extern uint8_t TT3Tag[]; +extern uint8_t *TT3AttribInfo, *TT3NDEFfile; + +static uint8_t PCDNFCT3_ReadAttribInfo(uint8_t *pBufferRead); +static uint8_t PCDNFCT3_WriteAttribInfo(uint8_t *pBufferWrite); +static uint8_t PCDNFCT3_ReadMessage(const uint32_t NbByteToRead, uint8_t *pBufferRead); +static uint8_t PCDNFCT3_WriteMessage(const uint32_t NbByteToWrite, uint8_t *pBufferWrite, uint8_t maxBlocWrite); +static void PCDNFCT3_UpdateCheckSum(uint8_t *bufferAttrib); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup NFC_type3_pcd + * @{ + * @brief This file is used to exchange with NFC FORUM Type3 Tag. +*/ + + +/** @addtogroup lib_nfctype3pcd_Private_Functions + * @{ + */ + + +/** + * @brief This function generates the Check command in order to read the AttribInfo field + * @param pBufferRead : Pointer on the buffer which will contain the data read + * @retval PCDNFCT3_OK : Command success + * @retval PCDNFCT3_ERROR : Transmission error + */ +static uint8_t PCDNFCT3_ReadAttribInfo(uint8_t *pBufferRead) +{ + uint8_t buffer[] = {PCDNFCT3_CHECK,0,0,0,0,0,0,0,0,0x01,PCDNFCT3_CODE_READ_LSB,PCDNFCT3_CODE_READ_MSB,0x01,PCDNFCT3_FIRST_BLOC_MSB,PCDNFCT3_FIRST_BLOC_LSB}; + + /* Write UID */ + memcpy(&buffer[1],FELICA_Card.UID,8); + + if (PCD_SendRecv(15,buffer, pBufferRead) == PCD_SUCCESSCODE) + return PCDNFCT3_OK; + else + return PCDNFCT3_ERROR; +} + +/** + * @brief This function generates the Update command in order to write the AttribInfo field + * @param pBufferWrite : Pointer on the buffer which contains the data to write + * @retval PCDNFCT3_OK : Command success + * @retval PCDNFCT3_ERROR : Transmission error + */ +static uint8_t PCDNFCT3_WriteAttribInfo(uint8_t *pBufferWrite) +{ + uint8_t buffer[31] = {PCDNFCT3_UPDATE,0,0,0,0,0,0,0,0,0x01,PCDNFCT3_CODE_WRITE_LSB,PCDNFCT3_CODE_WRITE_MSB,0x01,PCDNFCT3_FIRST_BLOC_MSB,PCDNFCT3_FIRST_BLOC_LSB}; + uint8_t bufferRead[PCDNFCT3_ATTR_SIZE]; + + /* Write UID */ + memcpy(&buffer[1],FELICA_Card.UID,8); + /* Write AttribInfo */ + memcpy(&buffer[15],pBufferWrite,PCDNFCT3_ATTR_SIZE); + + if (PCD_SendRecv(31,buffer, bufferRead) == PCD_SUCCESSCODE) + { + if (bufferRead[11] == 0 && bufferRead[12] == 0) + return PCDNFCT3_OK; + else + return PCDNFCT3_ERROR; /* Error code in reception frame */ + } + else + return PCDNFCT3_ERROR; /* Transmission error */ +} + +/** + * @brief This function generates check commands in order to read all the NDEF message + * @param NbByteToRead : Size of the NDEF message to read + * @param pBufferRead : Pointer on the buffer which will contain the data read + * @retval PCDNFCT3_OK : Command success + * @retval PCDNFCT3_ERROR : Transmission error + */ +static uint8_t PCDNFCT3_ReadMessage(const uint32_t NbByteToRead, uint8_t *pBufferRead) +{ + uint8_t nbBloc,i,j=0,maxBlocRead; + uint8_t buffer[48] = {PCDNFCT3_CHECK,0,0,0,0,0,0,0,0,0x01,PCDNFCT3_CODE_READ_LSB,PCDNFCT3_CODE_READ_MSB}; + uint8_t bufferRead[280]; + + memcpy(&buffer[1],FELICA_Card.UID,8); + + /* Check the maximum number of bloc that can be read with one command */ + maxBlocRead = TT3AttribInfo[1]; + + /* Check the total number of bloc to read */ + nbBloc = (NbByteToRead>>4)+1; + + /* Send as many commands as needed */ + while (nbBloc > maxBlocRead) + { + nbBloc-=maxBlocRead; + buffer[12] = maxBlocRead; + for(i=0;i>4)+1; + + /* Send as many commands as needed */ + while (nbBloc > maxBlocWrite) + { + nbBloc-=maxBlocWrite; + buffer[12] = maxBlocWrite; + for(i=0;i>8; + bufferAttrib[15] = checkSum&0x00FF; +} + +/** + * @} + */ + +/** @addtogroup lib_nfctype3pcd_Public_Functions + * @{ + */ + +/** + * @brief This function reads the NDEF message from a tag type 3 and store result in the TT3Tag buffer + * @retval PCDNFCT3_OK : Command success + * @retval PCDNFCT3_ERROR : Transmission error + * @retval PCDNFCT3_ERROR_LOCKED : The tag cannot be read (AttribInfo lock) + */ +uint8_t PCDNFCT3_ReadNDEF( void ) +{ + uint8_t buffer[32]; + uint8_t status; + uint32_t size; + + /* Read AttribInfo field */ + errchk(PCDNFCT3_ReadAttribInfo(buffer)); + memcpy(TT3AttribInfo,&buffer[14],PCDNFCT3_ATTR_SIZE); + /* Calculate the size */ + size = TT3AttribInfo[11]<<16|TT3AttribInfo[12]<<8|TT3AttribInfo[13]; + + // Check if there is enough memory available to read the tag + if (size > NFCT3_MAX_TAGMEMORY) + return PCDNFCT3_ERROR_MEMORY_INTERNAL; + + /* Read the NDEF message */ + errchk(PCDNFCT3_ReadMessage(size,TT3NDEFfile)); + + return PCDNFCT3_OK; +Error: + return PCDNFCT3_ERROR; +} + +/** + * @brief This function writes the NDEF message to a tag type 3 from the TT3Tag buffer + * @retval PCDNFCT3_OK : Command success + * @retval PCDNFCT3_ERROR : Transmission error + * @retval PCDNFCT3_ERROR_LOCKED : The tag cannot be write (AttribInfo lock) + * @retval PCDNFCT3_ERROR_MEMORY : Not enough memory available on the tag + */ +uint8_t PCDNFCT3_WriteNDEF( void ) +{ + uint8_t buffer[32]; + uint8_t bufferAttrib[16]; + uint8_t status; + uint32_t size, memoryAvailable; + + /* Read AttribInfo field */ + errchk(PCDNFCT3_ReadAttribInfo(buffer)); + memcpy(bufferAttrib,&buffer[14],PCDNFCT3_ATTR_SIZE); + /* Check if write is available */ + if(bufferAttrib[10] != 0x01) + return PCDNFCT3_ERROR_LOCKED; + /* Check if there is enough memory */ + memoryAvailable = ((bufferAttrib[3]<<8)|bufferAttrib[4]); + size = TT3AttribInfo[11]<<16|TT3AttribInfo[12]<<8|TT3AttribInfo[13]; + if ((size>>4) > memoryAvailable) + return PCDNFCT3_ERROR_MEMORY_TAG; + + /* Writing flag set to ON */ + bufferAttrib[9] = PCDNFCT3_WRITE_ON; + /* Update CheckSum */ + PCDNFCT3_UpdateCheckSum(bufferAttrib); + /* Write the AttribInfo */ + errchk(PCDNFCT3_WriteAttribInfo(bufferAttrib)); + + /* Write the message */ + errchk(PCDNFCT3_WriteMessage(size, TT3NDEFfile,bufferAttrib[2])); + + /* Length */ + memcpy(&bufferAttrib[11],&TT3AttribInfo[11],3); + /* Writing Flag OFF */ + bufferAttrib[9] = PCDNFCT3_WRITE_OFF; + /* CheckSum */ + PCDNFCT3_UpdateCheckSum(bufferAttrib); + /* Write the AttribInfo */ + errchk(PCDNFCT3_WriteAttribInfo(bufferAttrib)); + + return PCDNFCT3_OK; +Error: + return PCDNFCT3_ERROR; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype3pcd.h b/src/lib_nfctype3pcd.h new file mode 100644 index 0000000..59fb15b --- /dev/null +++ b/src/lib_nfctype3pcd.h @@ -0,0 +1,75 @@ +/** + ****************************************************************************** + * @file lib_nfctype3pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type3 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_NFCTYPE3PCD_H +#define _LIB_NFCTYPE3PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_iso18092pcd.h" + +#define PCDNFCT3_OK PCDNFC_OK +#define PCDNFCT3_ERROR PCDNFC_ERROR +#define PCDNFCT3_ERROR_MEMORY_TAG PCDNFC_ERROR_MEMORY_TAG +#define PCDNFCT3_ERROR_MEMORY_INTERNAL PCDNFC_ERROR_MEMORY_INTERNAL +#define PCDNFCT3_ERROR_LOCKED PCDNFC_ERROR_LOCKED + +/* Command List */ +#define PCDNFCT3_CHECK 0x06 +#define PCDNFCT3_UPDATE 0x08 + +/* Service code */ +#define PCDNFCT3_CODE_READ_MSB 0x00 +#define PCDNFCT3_CODE_READ_LSB 0x0B +#define PCDNFCT3_CODE_WRITE_MSB 0x00 +#define PCDNFCT3_CODE_WRITE_LSB 0x09 +#define PCDNFCT3_FIRST_BLOC_MSB 0x80 +#define PCDNFCT3_FIRST_BLOC_LSB 0x00 + +/* Flag */ +#define PCDNFCT3_WRITE_ON 0x0F +#define PCDNFCT3_WRITE_OFF 0x00 + +/* Size */ +#define PCDNFCT3_ATTR_SIZE 16 + +/* Functions */ +uint8_t PCDNFCT3_ReadNDEF( void ); +uint8_t PCDNFCT3_WriteNDEF( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_NFCTYPE3PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype4pcd.cpp b/src/lib_nfctype4pcd.cpp new file mode 100644 index 0000000..c1373c7 --- /dev/null +++ b/src/lib_nfctype4pcd.cpp @@ -0,0 +1,348 @@ +/** + ****************************************************************************** + * @file lib_nfctype4pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type4 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_nfctype4pcd.h" + +extern uint8_t CardNDEFfileT4A[]; +extern uint8_t CardNDEFfileT4B[]; + +/* Variables for the different modes */ +//extern DeviceMode_t devicemode; +extern TagType_t nfc_tagtype; + +extern uint16_t FSC; + +static int8_t PCDNFCT4_SelectApplication(void); +static int8_t PCDNFCT4_SelectCCfile(void); +static int8_t PCDNFCT4_SelectNDEFfile(const uint8_t NDEF_ID_MSB, const uint8_t NDEF_ID_LSB); +static uint8_t PCDNFCT4_ReadBinary(const uint16_t Offset ,const uint8_t NbByteToRead , uint8_t *pBufferRead); +static uint8_t PCDNFCT4_UpdateBinary(const uint16_t Offset ,const uint8_t NbByteToWrite , uint8_t *pBufferWrite); + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup NFC_type4_pcd + * @{ + * @brief This file is used to exchange with NFC FORUM Type4 Tag. +*/ + + +/** @addtogroup lib_nfctype4pcd_Private_Functions + * @{ + */ + + +/** + * @brief This function sends the SelectApplication command + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + */ +static int8_t PCDNFCT4_SelectApplication(void) +{ +uint8_t P1byte = 0x04, + P2byte = 0x00, + LCbyte = 0x07, + NDEFaplicationField[] = PCDNFCT4_SELECT_APPLI; + + if (ISO7816_SelectFile ( P1byte , P2byte , LCbyte ,NDEFaplicationField ) == ISO7816_SUCCESSCODE) + return PCDNFCT4_OK; + else + return PCDNFCT4_ERROR; +} + +/** + * @brief This function sends the SelectCCfile command + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + */ +static int8_t PCDNFCT4_SelectCCfile(void) +{ +uint8_t P1byte = 0x00, + P2byte = 0x0C, + LCbyte = 0x02, + FileId[] = PCDNFCT4_CC_ID; + +if (ISO7816_SelectFile ( P1byte , P2byte , LCbyte ,FileId ) == ISO7816_SUCCESSCODE) + return PCDNFCT4_OK; + else + return PCDNFCT4_ERROR; + +} + +/** + * @brief This function sends the SelectNDEF command + * @param NDEF_ID_MSB : NDEF identifier most significant bit + * @param NDEF_ID_LSB : NDEF identifier least significant bit + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + */ +static int8_t PCDNFCT4_SelectNDEFfile(const uint8_t NDEF_ID_MSB, const uint8_t NDEF_ID_LSB) +{ + uint8_t P1byte = 0x00, + P2byte = 0x0C, + LCbyte = 0x02, + FileId[2]; + + FileId[0] = NDEF_ID_MSB; + FileId[1] = NDEF_ID_LSB; + + if (ISO7816_SelectFile ( P1byte , P2byte , LCbyte ,FileId ) == ISO7816_SUCCESSCODE) + return PCDNFCT4_OK; + else + return PCDNFCT4_ERROR; +} + +/** + * @brief This function sends a read binary command + * @param Offset : first byte to read + * @param NbByteToRead : number of byte to read + * @param pBufferRead : pointer of the buffer read from the tag + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + */ +static uint8_t PCDNFCT4_ReadBinary(const uint16_t Offset ,const uint8_t NbByteToRead , uint8_t *pBufferRead) +{ + uint8_t P1byte = GETMSB(Offset), + P2byte = GETLSB(Offset), + LEbyte = NbByteToRead; + + if (ISO7816_ReadBinary ( P1byte , P2byte , LEbyte ,pBufferRead ) == ISO7816_SUCCESSCODE) + return PCDNFCT4_OK; + else + return PCDNFCT4_ERROR; + +} + +/** + * @brief This function sends a update binary command + * @param Offset : first byte to write + * @param NbByteToWrite : number of byte to write + * @param pBufferWrite : pointer of the buffer which contains data to write + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + */ +static uint8_t PCDNFCT4_UpdateBinary(const uint16_t Offset ,const uint8_t NbByteToWrite , uint8_t *pBufferWrite) +{ + uint8_t P1byte = GETMSB(Offset), + P2byte = GETLSB(Offset), + LEbyte = NbByteToWrite; + + if (ISO7816_UpdateBinary ( P1byte , P2byte , LEbyte ,pBufferWrite ) == ISO7816_SUCCESSCODE) + return PCDNFCT4_OK; + else + return PCDNFCT4_ERROR; +} + +/** + * @} + */ + +/** @addtogroup lib_nfctype4pcd_Public_Functions + * @{ + */ + +/** + * @brief This function reads the NDEF message from a tag type 4 and store result in the CardNDEFfile buffer + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + * @retval PCDNFCT4_ERROR_LOCKED : The tag cannot be read (CCfile lock) + */ +uint8_t PCDNFCT4_ReadNDEF( void ) +{ + uint8_t status, NDEF_ID_MSB, NDEF_ID_LSB; + uint8_t limit = 0; + uint16_t size, i = 0, MLe; + uint8_t buffer[PCDNFCT4_BUFFER_READ]; + uint8_t *CardNDEFfile; + + // Choose the correct buffer + if (nfc_tagtype == TT4A) + CardNDEFfile = CardNDEFfileT4A; + else + CardNDEFfile = CardNDEFfileT4B; + + // SelectAppli + errchk(PCDNFCT4_SelectApplication()); + + // SelectCC + errchk(PCDNFCT4_SelectCCfile()); + errchk(PCDNFCT4_ReadBinary(0x00, 0x0F, buffer)); + NDEF_ID_MSB = buffer[12]; + NDEF_ID_LSB = buffer[13]; + MLe = MIN((buffer[6]<<8|buffer[7]),0xF6); + // Check if read access is allowed + if (buffer[16] != PCDNFCT4_ACCESS_ALLOWED) + return PCDNFCT4_ERROR_LOCKED; + // SelectNDEF + errchk(PCDNFCT4_SelectNDEFfile(NDEF_ID_MSB,NDEF_ID_LSB)); + // Read length + errchk(PCDNFCT4_ReadBinary(0x00, 0x02, buffer)); + size = (((buffer[3])<<8) | (buffer[4])) + 2; + + // Check if there is enough memory available to read the tag + if (size > NFCT4_MAX_NDEFMEMORY) + return PCDNFCT4_ERROR_MEMORY_INTERNAL; + + /* Mle have a good chance to be bigger than FSC but just in case */ + /* FSC - PCB, SW1, SW2, CRC1, CRC2 */ + limit = MIN(MLe,(FSC-5)); + + // Read data + while (size>limit) + { + errchk(PCDNFCT4_ReadBinary(i*limit, limit, buffer)); + memcpy(&CardNDEFfile[i*limit],&buffer[PCD_DATA_OFFSET+1],limit); + size -= limit; + i++; + } + if (size > 0) + { + errchk(PCDNFCT4_ReadBinary(i*limit, size, buffer)); + memcpy(&CardNDEFfile[i*limit],&buffer[PCD_DATA_OFFSET+1],size); + } + + return PCDNFCT4_OK; +Error: + return PCDNFCT4_ERROR; +} + +/** + * @brief This function writes the NDEF message to a tag type 4 from the CardNDEFfile buffer + * @retval PCDNFCT4_OK : Command success + * @retval PCDNFCT4_ERROR : Transmission error + * @retval PCDNFCT4_ERROR_LOCKED : The tag cannot be write (CCfile lock) + * @retval PCDNFCT4_ERROR_MEMORY : Not enough memory available on the tag + */ +uint8_t PCDNFCT4_WriteNDEF( void ) +{ + uint8_t status, NDEF_ID_MSB, NDEF_ID_LSB; + uint16_t size, i = 0, MLc, memoryAvailable; + uint8_t buffer[32], bufferSize[2]; + uint8_t *CardNDEFfile; + + // Choose the correct buffer + if (nfc_tagtype == TT4A) + CardNDEFfile = CardNDEFfileT4A; + else + CardNDEFfile = CardNDEFfileT4B; + + // SelectAppli + errchk(PCDNFCT4_SelectApplication()); + // SelectCC + errchk(PCDNFCT4_SelectCCfile()); + errchk(PCDNFCT4_ReadBinary(0x00, 0x0F, buffer)); + NDEF_ID_MSB = buffer[12]; + NDEF_ID_LSB = buffer[13]; + // Check if there is enough memory available on the tag + memoryAvailable = buffer[14]<<8|buffer[15]; + size = (((CardNDEFfile[0])<<8) | (CardNDEFfile[1])) + 2; + if (size > memoryAvailable) + return PCDNFCT4_ERROR_MEMORY_TAG; + // Check if write access is allowed + if (buffer[17] != PCDNFCT4_ACCESS_ALLOWED) + return PCDNFCT4_ERROR_LOCKED; + // Chaining not supported yet... and the maximum for ST95HF is 0xF6 + MLc = MIN((buffer[8]<<8|buffer[9]),0xF6); + // SelectNDEF + errchk(PCDNFCT4_SelectNDEFfile(NDEF_ID_MSB,NDEF_ID_LSB)); + // Write NDEF + // The size must be 0 + bufferSize[0] = CardNDEFfile[0]; bufferSize[1] = CardNDEFfile[1]; + CardNDEFfile[0] = CardNDEFfile[1] = 0; + + while (size>MLc) + { + status = PCDNFCT4_UpdateBinary(i*MLc, MLc, &CardNDEFfile[i*MLc]); + // If an error occur we have to write back the size to the NDEF buffer + if (status == PCDNFCT4_ERROR) + { + CardNDEFfile[0]=bufferSize[0]; + CardNDEFfile[1]=bufferSize[1]; + return PCDNFCT4_ERROR; + } + size -= MLc; + i++; + } + if (size > 0) + { + status = PCDNFCT4_UpdateBinary(i*MLc, size, &CardNDEFfile[i*MLc]); + // If an error occur we have to write back the size to the NDEF buffer + if (status == PCDNFCT4_ERROR) + { + CardNDEFfile[0]=bufferSize[0]; + CardNDEFfile[1]=bufferSize[1]; + return PCDNFCT4_ERROR; + } + } + + // Write the size + errchk(PCDNFCT4_UpdateBinary(0,2,bufferSize)); + + return PCDNFCT4_OK; +Error: + return PCDNFCT4_ERROR; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype4pcd.h b/src/lib_nfctype4pcd.h new file mode 100644 index 0000000..a046283 --- /dev/null +++ b/src/lib_nfctype4pcd.h @@ -0,0 +1,64 @@ +/** + ****************************************************************************** + * @file lib_nfctype4pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type4 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_NFCTYPE4PCD_H +#define _LIB_NFCTYPE4PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_iso7816pcd.h" + +#define PCDNFCT4_OK PCDNFC_OK +#define PCDNFCT4_ERROR PCDNFC_ERROR +#define PCDNFCT4_ERROR_MEMORY_TAG PCDNFC_ERROR_MEMORY_TAG +#define PCDNFCT4_ERROR_MEMORY_INTERNAL PCDNFC_ERROR_MEMORY_INTERNAL +#define PCDNFCT4_ERROR_LOCKED PCDNFC_ERROR_LOCKED + +/* Command List */ +#define PCDNFCT4_SELECT_APPLI {0xD2,0x76,0x00,0x00,0x85,0x01,0x01,0x00} +#define PCDNFCT4_CC_ID {0xE1,0x03} + +/* Size */ +#define PCDNFCT4_BUFFER_READ 256 + +#define PCDNFCT4_ACCESS_ALLOWED 0x00 + +uint8_t PCDNFCT4_ReadNDEF(void); +uint8_t PCDNFCT4_WriteNDEF( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_NFCTYPE4PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype5pcd.cpp b/src/lib_nfctype5pcd.cpp new file mode 100644 index 0000000..cc06b6c --- /dev/null +++ b/src/lib_nfctype5pcd.cpp @@ -0,0 +1,234 @@ +/** + ****************************************************************************** + * @file lib_nfctype5pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type2 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_nfctype5pcd.h" + +extern uint8_t TT5Tag[]; + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup NFC_type5_pcd + * @{ + * @brief This file is used to exchange with NFC FORUM Type5 Tag. +*/ + + +/** @addtogroup lib_nfctype5pcd_Private_Functions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup lib_nfctype5pcd_Public_Functions + * @{ + */ + +/** + * @brief This function reads the NDEF message from a tag type V and store result in the TT5Tag buffer + * @retval PCDNFCT5_OK : Command success + * @retval PCDNFCT5_ERROR : Transmission error + * @retval PCDNFCT5_ERROR_LOCKED : The tag cannot be read (CC lock) + */ +uint8_t PCDNFCT5_ReadNDEF( void ) +{ + uint16_t size; + uint8_t tagDensity = ISO15693_HIGH_DENSITY; + // Try to determine the density by reading the first sector (128 bytes) + if (ISO15693_ReadBytesTagData(ISO15693_HIGH_DENSITY, ISO15693_LRiS64K, TT5Tag, 127, 0) != ISO15693_SUCCESSCODE) + { + if (ISO15693_ReadBytesTagData(ISO15693_LOW_DENSITY, ISO15693_LRiS64K, TT5Tag, 127, 0) != ISO15693_SUCCESSCODE) + return PCDNFCT5_ERROR; + tagDensity = ISO15693_LOW_DENSITY; + } + + // NDEF capable ? + if (TT5Tag[0] != 0xE1) + return PCDNFCT5_ERROR_NOT_FORMATED; + + // Check read access + if ((TT5Tag[1]&0x0C) != 0) + return PCDNFCT5_ERROR_LOCKED; + + // Get the size of the message + if (TT5Tag[5] == 0xFF) + size = (TT5Tag[6]<<8)|TT5Tag[7]; + else + size = 0x00FF&TT5Tag[5]; + + // Check if there is enough memory to read the tag + // If CC3 bit3 = 1 the size is higher than 2KB but we don't know the size... + if (size+7 > NFCT5_MAX_TAGMEMORY) + return PCDNFCT5_ERROR_MEMORY_INTERNAL; + + // Read the rest of the tag if needed + if (size > 124) + { + if (ISO15693_ReadBytesTagData(tagDensity, ISO15693_LRiS64K, &TT5Tag[128], size-128, 128) != ISO15693_SUCCESSCODE) + { + return PCDNFCT5_ERROR; + } + } + + return PCDNFCT5_OK; +} + +/** + * @brief This function writes the NDEF message to a tag type V from the TT5Tag buffer + * @retval PCDNFCT5_OK : Command success + * @retval PCDNFCT5_ERROR : Transmission error + * @retval PCDNFCT5_ERROR_LOCKED : The tag cannot be write or read (CC lock) + * @retval PCDNFCT5_ERROR_MEMORY : Not enough memory available on the tag + */ +uint8_t PCDNFCT5_WriteNDEF( void ) +{ + uint8_t RepBuffer[30]; + uint8_t firstSector[140], status; + uint16_t size, tagSize; + uint8_t tagDensity = ISO15693_HIGH_DENSITY; + // Try to determine the density by ready the first sector (128 bytes) + if (ISO15693_ReadBytesTagData(ISO15693_HIGH_DENSITY, ISO15693_LRiS64K, firstSector, 127, 0) != ISO15693_SUCCESSCODE) + { + if (ISO15693_ReadBytesTagData(ISO15693_LOW_DENSITY, ISO15693_LRiS64K, firstSector, 127, 0) != ISO15693_SUCCESSCODE) + return PCDNFCT5_ERROR; + tagDensity = ISO15693_LOW_DENSITY; + } + // NDEF capable ? + if (firstSector[0] != 0xE1) + { + /* Create the CC file */ + // We need the size + if (tagDensity == ISO15693_HIGH_DENSITY) + ISO15693_GetSystemInfo (0x0A , 0x00, RepBuffer); + else + ISO15693_GetSystemInfo (0x02 , 0x00, RepBuffer); + if (RepBuffer[14] == 0xFF) + tagSize = (((RepBuffer[15]<<8)|RepBuffer[14])+1)*(RepBuffer[16]+1); + else + tagSize = (RepBuffer[14]+1)*(RepBuffer[15]+1); + // NDEF capable + TT5Tag[0] = 0xE1; + // Version + Read/Write allowed + TT5Tag[1] = 0x40; + // Size + if (tagSize > 2040) + { + // If the size is above 2040 (0xFF) then we have to set the bit3 of CC4 + TT5Tag[2] = 0xFF; + TT5Tag[3] = 0x05; + } + else + { + TT5Tag[2] = tagSize/8; + TT5Tag[3] = 0x01; + } + } + else + { + // Copy the CC + memcpy(TT5Tag,firstSector,4); + + // Check read and write access + if ((TT5Tag[1]&0x0F) != 0) + return PCDNFCT5_ERROR_LOCKED; + } + + // Get the size of the message to write + if (TT5Tag[5] == 0xFF) + size = (TT5Tag[6]<<8)|TT5Tag[7]; + else + size = 0x00FF&TT5Tag[5]; + + // Check if the memory available on the tag is enough + // If CC3 bit3 = 1 the size is higher than 2KB but we don't know the size... + if (TT5Tag[2]*8 < size+7 && (TT5Tag[3]&0x04) == 0) + return PCDNFCT5_ERROR_MEMORY_TAG; + if ((TT5Tag[3]&0x04) != 0) // So we use get system info command + { + if (tagDensity == ISO15693_HIGH_DENSITY) + ISO15693_GetSystemInfo (0x0A , 0x00, RepBuffer); + else + ISO15693_GetSystemInfo (0x02 , 0x00, RepBuffer); + + if (RepBuffer[14] == 0xFF) + tagSize = (((RepBuffer[15]<<8)|RepBuffer[14])+1)*(RepBuffer[16]+1); + else + tagSize = (RepBuffer[14]+1)*(RepBuffer[15]+1); + + if (tagSize < size+7) + return PCDNFCT5_ERROR_MEMORY_TAG; + } + + // Write the tag + errchk(ISO15693_WriteBytes_TagData(tagDensity, TT5Tag, size+7, 0)); + + return PCDNFCT5_OK; +Error: + return PCDNFCT5_ERROR; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_nfctype5pcd.h b/src/lib_nfctype5pcd.h new file mode 100644 index 0000000..38d3191 --- /dev/null +++ b/src/lib_nfctype5pcd.h @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * @file lib_nfctype5pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief Generates the NFC type5 commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_NFCTYPE5PCD_H +#define _LIB_NFCTYPE5PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "lib_pcd.h" +#include "lib_iso15693pcd.h" + +/* Error codes */ +#define PCDNFCT5_OK PCDNFC_OK +#define PCDNFCT5_ERROR PCDNFC_ERROR +#define PCDNFCT5_ERROR_MEMORY_TAG PCDNFC_ERROR_MEMORY_TAG +#define PCDNFCT5_ERROR_MEMORY_INTERNAL PCDNFC_ERROR_MEMORY_INTERNAL +#define PCDNFCT5_ERROR_LOCKED PCDNFC_ERROR_LOCKED +#define PCDNFCT5_ERROR_NOT_FORMATED PCDNFC_ERROR_NOT_FORMATED + +/* Functions */ +uint8_t PCDNFCT5_ReadNDEF( void ); +uint8_t PCDNFCT5_WriteNDEF( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_NFCTYPE5PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_pcd.cpp b/src/lib_pcd.cpp new file mode 100644 index 0000000..85c83ee --- /dev/null +++ b/src/lib_pcd.cpp @@ -0,0 +1,769 @@ +/** + ****************************************************************************** + * @file lib_pcd.c + * @author MMY Application Team + * @version $Revision: 1334 $ + * @date $Date: 2015-11-05 10:53:37 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of firmware functions to manages the PCD device device. + * @brief The commands as defined in the PCD device datasheet + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +//#ifdef __cplusplus +// extern "C" { +//#endif + +/* Includes ------------------------------------------------------------------------------ */ +#include "lib_pcd.h" + +extern drv95HF_ConfigStruct drv95HFConfig; +extern uint8_t u95HFBuffer [RFTRANS_95HF_MAX_BUFFER_SIZE+3]; + +/* Variables for the different modes */ +//extern DeviceMode_t devicemode; +//extern TagType_t nfc_tagtype; +extern volatile bool EnableTimeOut; + +static uint8_t IsAnAvailableProtocol (uint8_t Protocol); + +PCD_PROTOCOL TechnoSelected = PCDPROTOCOL_UNKNOWN; + +/** @addtogroup _95HF_Libraries + * @{ + * @brief This is the library used by the whole 95HF family (RX95HF, CR95HF, ST95HF)
+ * You will find ISO libraries ( 14443A, 14443B, 15693, ...) for PICC and PCD
+ * The libraries selected in the project will depend of the application targetted
+ * and the product chosen (RX95HF emulate PICC, CR95HF emulate PCD, ST95HF can do both)
+ */ + +/** @addtogroup PCD + * @{ + * @brief This part of the library enables PCD capabilities of CR95HF & ST95HF. + */ + + +/** @addtogroup PCD_Device + * @{ + * @brief This set of function use the device commands to control both CR95HF & ST95HF
+ * This layer is the bridge beetween the library and the 95HF driver. + */ + + +/** @addtogroup lib_PCD_Private_Functions + * @{ + */ + +static uint32_t PCD_ComputeUARTBaudRate(const uint8_t BaudRateCommandParameter); + +/** + * @brief This function computes the UART baud rate according to Baudrate command parameter + * @param BaudRateCommandParameter : Baudrate command parameter (1 byte) + * @retval the UART baud rate value + */ +static uint32_t PCD_ComputeUARTBaudRate(const uint8_t BaudRateCommandParameter) +{ + return ((uint32_t)13.56e6/ (2*BaudRateCommandParameter+2)); +} + +/** + * @brief this functions returns PCD_SUCCESSCODE if the protocol is available, otherwise PCD_ERRORCODE_PARAMETER + * @param Protocol : RF protocol (ISO 14443 A or 14443 B or 15 693 or Fellica) + * @return PCD_SUCCESSCODE : the protocol is available + * @return PCD_ERRORCODE_PARAMETER : the protocol isn't available + */ +static uint8_t IsAnAvailableProtocol (uint8_t Protocol) +{ + switch(Protocol) + { + case PCD_PROTOCOL_FIELDOFF: + return PCD_SUCCESSCODE; + case PCD_PROTOCOL_ISO15693: + return PCD_SUCCESSCODE; + case PCD_PROTOCOL_ISO14443A: + return PCD_SUCCESSCODE; + case PCD_PROTOCOL_ISO14443B: + return PCD_SUCCESSCODE; + case PCD_PROTOCOL_FELICA: + return PCD_SUCCESSCODE; + default: return PCD_ERRORCODE_PARAMETER; + } +} + +/** + * @} + */ + + +/** @addtogroup lib_PCD_Public_Functions + * @{ + */ + +/** + * @brief this function send an EOF pulse to a contacless tag + * @param pResponse : pointer on the PCD device reply + * @retval PCD_SUCCESSCODE : the function is succesful + */ +int8_t PCD_SendEOF(uint8_t *pResponse) +{ + const uint8_t DataToSend[] = {SEND_RECEIVE ,0x00}; + + drv95HF_SendReceive(DataToSend, pResponse); + + return PCD_SUCCESSCODE; +} + + +/** + * @brief this functions turns the field off + * @param none + * @retval PCD_SUCCESSCODE : the function is succesful + */ +void PCD_FieldOff( void ) +{ + uint8_t ParametersByte=0x00; + uint8_t pResponse[10]; + + PCD_ProtocolSelect(0x02, PCD_PROTOCOL_FIELDOFF, &ParametersByte,pResponse); +} + +/** + * @brief this functions turns the field on + * @param none + * @return none + */ +void PCD_FieldOn(void) +{ + uint8_t ParametersByte=0x00; + uint8_t pResponse[10]; + + PCD_ProtocolSelect(0x02, PCD_PROTOCOL_ISO15693, &ParametersByte,pResponse); +} + +/** + * @brief this function send Echo command to the PCD device + * @param pResponse : pointer on the PCD device reply + * @return PCD_SUCCESSCODE + */ +int8_t PCD_Echo(uint8_t *pResponse) +{ + const uint8_t command[]= {ECHO}; + + drv95HF_SendReceive(command, pResponse); + + return PCD_SUCCESSCODE; +} + +/** + * @brief this function send a ProtocolSeclect command to the PCD device + * @param Length : number of byte of protocol select command parameters + * @param Protocol : RF protocol (ISO 14443 A or B or 15 693 or Fellica) + * @param Parameters: prococol parameters (see reader datasheet) + * @param pResponse : pointer on the PCD device response + * @return PCD_SUCCESSCODE : the command was succedfully send + * @return PCD_ERRORCODE_PARAMETERLENGTH : the Length parameter is erroneous + * @return PCD_ERRORCODE_PARAMETER : a parameter is erroneous + */ +int8_t PCD_ProtocolSelect(const uint8_t Length,const uint8_t Protocol,const uint8_t *Parameters,uint8_t *pResponse) +{ + uint8_t DataToSend[SELECT_BUFFER_SIZE]; + int8_t status; + + /* check ready to receive Protocol select command */ + PCD_Echo(u95HFBuffer); + + if (u95HFBuffer[0] != ECHORESPONSE) + { + /* reset the device */ + PCD_PORsequence( ); + } + + /* initialize the result code to 0xFF and length to in case of error */ + *pResponse = PCD_ERRORCODE_DEFAULT; + *(pResponse+1) = 0x00; + + /* check the function parameters */ + errchk(IsAnAvailableProtocol(Protocol)); + + DataToSend[PCD_COMMAND_OFFSET ] = PROTOCOL_SELECT; + DataToSend[PCD_LENGTH_OFFSET ] = Length; + DataToSend[PCD_DATA_OFFSET ] = Protocol; + + /* DataToSend CodeCmd Length Data */ + /* Parameters[0] first byte to emmit */ + memcpy(&(DataToSend[PCD_DATA_OFFSET +1]),Parameters,Length-1); + + /* Send the command the Rf transceiver */ + drv95HF_SendReceive(DataToSend, pResponse); + + return PCD_SUCCESSCODE; + +Error: + return PCD_ERRORCODE_PARAMETER; +} + + +/** + * @brief this function send a SendRecv command to the PCD device. the command to contacless device is embeded in Parameters. + * @param Length : Number of bytes + * @param Parameters : data depenps on protocl selected + * @param pResponse : pointer on the PCD device response + * @return PCD_SUCCESSCODE : the command was succedfully send + * @return PCD_ERRORCODE_DEFAULT : the PCD device returned an error code + * @return PCD_ERRORCODE_PARAMETERLENGTH : Length parameter is erroneous + */ +int8_t PCD_SendRecv(const uint8_t Length,const uint8_t *Parameters,uint8_t *pResponse) +{ + uint8_t DataToSend[SENDRECV_BUFFER_SIZE]; + + /* initialize the result code to 0xFF and length to 0 */ + *pResponse = PCD_ERRORCODE_DEFAULT; + *(pResponse+1) = 0x00; + +// /* check the function parameters */ +// if (CHECKVAL (Length,1,255)==false) +// return PCD_ERRORCODE_PARAMETERLENGTH; + + DataToSend[PCD_COMMAND_OFFSET ] = SEND_RECEIVE; + DataToSend[PCD_LENGTH_OFFSET ] = Length; + + /* DataToSend CodeCmd Length Data*/ + /* Parameters[0] first byte to emmit */ + memcpy(&(DataToSend[PCD_DATA_OFFSET]),Parameters,Length); + + /* Send the command the Rf transceiver */ + drv95HF_SendReceive(DataToSend, pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) != PCD_SUCCESSCODE) + { + if(*pResponse == PCD_ERRORCODE_NOTAGFOUND) + return PCD_ERRORCODE_TIMEOUT; + else + return PCD_ERRORCODE_DEFAULT; + } + return PCD_SUCCESSCODE; +} + +/** + * @brief this function send a Idle command to the PCD device + * @param Length : Number of bytes + * @param Data : pointer on data. Data depends on protocl selected + * @param pResponse : pointer on the PCD device response + * @return PCD_SUCCESSCODE : the command was succedfully send + * @return PCD_ERRORCODE_DEFAULT : the PCD device returned an error code + * @return PCD_ERRORCODE_PARAMETERLENGTH : Length parameter is erroneous + */ +int8_t PCD_Idle(const uint8_t Length, const uint8_t *Data ) +{ + uint8_t DataToSend[IDLE_BUFFER_SIZE]; + + /* check the function parameters */ + if (Length != 0x0E) + return PCD_ERRORCODE_PARAMETERLENGTH; + + DataToSend[PCD_COMMAND_OFFSET ] = IDLE; + DataToSend[PCD_LENGTH_OFFSET ] = Length; + + memcpy(&(DataToSend[PCD_DATA_OFFSET]),Data,Length ); + + drv95HF_SendSPICommand(DataToSend); + + return PCD_SUCCESSCODE; +} + +/** + * @brief this function send a RdReg command to the PCD device + * @param Length : Number of bytes + * @param Address : address of first register to read + * @param RegCount : number of register to read + * @param Flags : whether to increment address after register read + * @param pResponse : pointer on the PCD device response + * @return PCD_SUCCESSCODE : the command was succedfully send + * @return PCD_ERRORCODE_DEFAULT : the PCD device returned an error code + * @return PCD_ERRORCODE_PARAMETERLENGTH : Length parameter is erroneous + */ +int8_t PCD_ReadRegister(const uint8_t Length,const uint8_t Address,const uint8_t RegCount,const uint8_t Flags,uint8_t *pResponse) +{ + uint8_t DataToSend[RDREG_BUFFER_SIZE]; + + + DataToSend[PCD_COMMAND_OFFSET ] = READ_REGISTER; + DataToSend[PCD_LENGTH_OFFSET ] = Length; + DataToSend[PCD_DATA_OFFSET ] = Address; + DataToSend[PCD_DATA_OFFSET +1 ] = RegCount; + DataToSend[PCD_DATA_OFFSET +2 ] = Flags; + /* Send the command the Rf transceiver */ + drv95HF_SendReceive(DataToSend, pResponse); + + if (PCD_IsReaderResultCodeOk (IDLE,pResponse) != PCD_SUCCESSCODE) + return PCD_ERRORCODE_DEFAULT; + + return PCD_SUCCESSCODE; + +} + +/** + * @brief this function send a WriteRegister command to the PCD device + * @param Length : Number of bytes of WrReg parameters + * @param Address : address of first register to write + * @param pData : pointer data to be write + * @param Flags : whether to increment address after register read + * @param pResponse : pointer on the PCD device response + * @return PCD_SUCCESSCODE : the command was succedfully send + * @return PCD_ERRORCODE_PARAMETERLENGTH : Length parameter is erroneous + */ +int8_t PCD_WriteRegister(const uint8_t Length,const uint8_t Address,const uint8_t Flags,const uint8_t *pData,uint8_t *pResponse) +{ + uint8_t DataToSend[WRREG_BUFFER_SIZE]; + + DataToSend[PCD_COMMAND_OFFSET ] = WRITE_REGISTER; + DataToSend[PCD_LENGTH_OFFSET ] = Length; + DataToSend[PCD_DATA_OFFSET ] = Address; + DataToSend[PCD_DATA_OFFSET +1 ] = Flags; + + /* Parameters[0] first byte to emmit */ + memcpy(&(DataToSend[PCD_DATA_OFFSET + 2]),pData,Length - 2 ); + + /* Send the command the Rf transceiver */ + drv95HF_SendReceive(DataToSend, pResponse); + return PCD_SUCCESSCODE; +} + + +/** + * @brief This function sends POR sequence. It can be use to initialize the PCD device after a POR. + * @param none + * @return PCD_ERRORCODE_PORERROR : the POR sequence doesn't succeded + * @return PCD_SUCCESSCODE : the RF transceiver is ready + */ +int8_t PCD_PORsequence( void ) +{ + uint16_t NthAttempt=0; + + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + { + drv95HF_ResetSPI(); + } + + do{ + + /* send an ECHO command and checks the PCD device response */ + PCD_Echo(u95HFBuffer); + if (u95HFBuffer[0]==ECHORESPONSE) + return PCD_SUCCESSCODE; + + /* if the SPI interface is selected then send a reset command*/ + if(drv95HFConfig.uInterface == RFTRANS_95HF_INTERFACE_SPI) + { + drv95HF_ResetSPI(); + } + + } while (u95HFBuffer[0]!=ECHORESPONSE && NthAttempt++ <5); + +return PCD_ERRORCODE_PORERROR; +} + +/** +* @brief this function send a command to the PCD device device over SPI or UART bus and receive its response. +* @brief the returned value is PCD_SUCCESSCODE +* @param *pCommand : pointer on the buffer to send to the the PCD device ( Command | Length | Data) +* @param *pResponse : pointer on the the PCD device response ( Command | Length | Data) +* @return PCD_SUCCESSCODE : the the PCD device returns an success code +* @return PCD_ERRORCODE_DEFAULT : the the PCD device returns an error code + */ +int8_t PCD_CheckSendReceive(const uint8_t *pCommand, uint8_t *pResponse) +{ + drv95HF_SendReceive(pCommand, pResponse); + + if (PCD_IsReaderResultCodeOk (SEND_RECEIVE,pResponse) != PCD_SUCCESSCODE) + return PCD_ERRORCODE_DEFAULT; + + return PCD_SUCCESSCODE; +} + + +/** +* @brief this function returns PCD_SUCCESSCODE is the reader reply is a succesful code. +* @param CmdCode : code command send to the reader +* @param ReaderReply : pointer on the PCD device response +* @retval PCD_SUCCESSCODE : the CRC is Ok +* @retval PCD_NOREPLY_CODE : the CRC is erroenous +*/ +int8_t PCD_IsCRCOk(const uint8_t Protocol ,const uint8_t *pReaderReply) +{ +uint8_t NbByte = pReaderReply[PCD_LENGTH_OFFSET]; + + + switch (Protocol) + { + case PCD_PROTOCOL_ISO15693: + if ( (pReaderReply [PCD_DATA_OFFSET + NbByte - CONTROL_15693_NBBYTE] & CONTROL_15693_CRCMASK) == CONTROL_15693_CRCMASK ) + { + return PCD_ERRORCODE_DEFAULT; + } + else + { + return PCD_SUCCESSCODE; + } + + case PCD_PROTOCOL_ISO14443A: + if ( (pReaderReply [PCD_DATA_OFFSET + NbByte - ISO14443A_NBBYTE] & ISO14443A_CRCMASK) == ISO14443A_CRCMASK ) + { + return PCD_ERRORCODE_DEFAULT; + } + else + { + return PCD_SUCCESSCODE; + } + + case PCD_PROTOCOL_ISO14443B: + if ( (pReaderReply [PCD_DATA_OFFSET + NbByte - CONTROL_14443B_NBBYTE] & CONTROL_14443B_CRCMASK) == CONTROL_14443B_CRCMASK ) + { + return PCD_ERRORCODE_DEFAULT; + } + else + { + return PCD_SUCCESSCODE; + } + + case PCD_PROTOCOL_FELICA: + if ( (pReaderReply [PCD_DATA_OFFSET + NbByte - CONTROL_FELICA_NBBYTE] & CONTROL_FELICA_CRCMASK) == CONTROL_FELICA_CRCMASK ) + { + return PCD_ERRORCODE_DEFAULT; + } + else + { + return PCD_SUCCESSCODE; + } + + default: + return ERRORCODE_GENERIC; + } +} + +/** +* @brief this function returns PCD_SUCCESSCODE is the reader reply is a succesful code. +* @param CmdCode : code command send to the reader +* @param ReaderReply : pointer on the PCD device response +* @retval PCD_SUCCESSCODE : the PCD device returned a succesful code +* @retval PCD_ERRORCODE_DEFAULT : the PCD device didn't return a succesful code +* @retval PCD_NOREPLY_CODE : no the PCD device response +*/ +int8_t PCD_IsReaderResultCodeOk(uint8_t CmdCode, const uint8_t *ReaderReply) +{ + + if (ReaderReply[READERREPLY_STATUSOFFSET] == PCD_ERRORCODE_DEFAULT) + return PCD_NOREPLY_CODE; + + switch (CmdCode) + { + case ECHO: + if (ReaderReply[PSEUDOREPLY_OFFSET] == ECHO) + return PCD_SUCCESSCODE; + else + return PCD_ERRORCODE_DEFAULT; + + case IDN: + if (ReaderReply[READERREPLY_STATUSOFFSET] == IDN_RESULTSCODE_OK) + return PCD_SUCCESSCODE; + else + return PCD_ERRORCODE_DEFAULT; + + case PROTOCOL_SELECT: + switch (ReaderReply[READERREPLY_STATUSOFFSET]) + { + case IDN_RESULTSCODE_OK : + return PCD_SUCCESSCODE; + + case PROTOCOLSELECT_ERRORCODE_CMDLENGTH : + return PCD_ERRORCODE_DEFAULT; + + case PROTOCOLSELECT_ERRORCODE_INVALID : + return PCD_ERRORCODE_DEFAULT; + + default : return PCD_ERRORCODE_DEFAULT; + + } + + case SEND_RECEIVE: + switch (ReaderReply[READERREPLY_STATUSOFFSET]) + { + case SENDRECV_RESULTSCODE_OK : + if (ReaderReply[READERREPLY_STATUSOFFSET+1] != 0) + return PCD_SUCCESSCODE; + else + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_RESULTSRESIDUAL : + return PCD_SUCCESSCODE; + + case SENDRECV_ERRORCODE_COMERROR : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_FRAMEWAIT : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_SOF : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_OVERFLOW : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_FRAMING : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_EGT : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_LENGTH : + return PCD_ERRORCODE_DEFAULT; + + case SENDRECV_ERRORCODE_CRC : + return PCD_ERRORCODE_DEFAULT; + case SENDRECV_ERRORCODE_RECEPTIONLOST : + return PCD_ERRORCODE_DEFAULT; + + default : + return PCD_ERRORCODE_DEFAULT; + + } + + case IDLE: + switch (ReaderReply[READERREPLY_STATUSOFFSET]) + { + case IDLE_RESULTSCODE_OK : + return PCD_SUCCESSCODE; + + case IDLE_ERRORCODE_LENGTH : + return PCD_ERRORCODE_DEFAULT; + + default : return PCD_ERRORCODE_DEFAULT; + + } + + case READ_REGISTER: + switch (ReaderReply[READERREPLY_STATUSOFFSET]) + { + case READREG_RESULTSCODE_OK : + return PCD_SUCCESSCODE; + + case READREG_ERRORCODE_LENGTH : + return PCD_ERRORCODE_DEFAULT; + + default : return PCD_ERRORCODE_DEFAULT; + + } + + case WRITE_REGISTER: + switch (ReaderReply[READERREPLY_STATUSOFFSET]) + { + case WRITEREG_RESULTSCODE_OK : + return PCD_SUCCESSCODE; + + default : return PCD_ERRORCODE_DEFAULT; + + } + + case BAUD_RATE: + return PCD_ERRORCODE_DEFAULT; + + default: + return ERRORCODE_GENERIC; + + } +} + +/** + * @brief this function perform the calibration to provide the parameter require for tag detection command + * @param WU Period : Time allow between 2 tag detections + * @param pDacDataH : Value computed for DacDataH (DacDataL = DacDataH – 0x10) + * @return PCD_SUCCESSCODE : the calibration was successfully performed (DacDataH value is significant) + */ +int8_t PCD_TagDetectCalibration(const uint8_t Wuperiod, uint8_t *pDacDataH) +{ + uint8_t DataToSend[IDLE_CMD_LENTH+2] = { 0x00, 0x00, 0x03, 0xA1, 0x00, 0xF8, 0x01, 0x18, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x3F, 0x01}; + uint8_t Response[3] = {0x00}; + uint8_t AlgoStep[6] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04}; + uint8_t i=0; + + /* Insure no tag are present during calibration process */ + /* During the calibration process, DacDataL is forced to 0x00 and the software successively + varies the DacDataH value from its maximum value (0xFE) to its minimum value (0x00) */ + + DataToSend[PCD_COMMAND_OFFSET ] = IDLE; + DataToSend[PCD_LENGTH_OFFSET ] = IDLE_CMD_LENTH; + + /* modify WU Period according to user input */ + DataToSend[WU_PERIOD_OFFSET] = Wuperiod; + + /* Start 8-step calibration process */ + + /* Step 0: force wake-up event to Tag Detect (set DacDataH = 0x00) + With these conditions Wake-Up event must be Tag Detect */ + + DataToSend[DACDATAH_OFFSET] = 0x00; + drv95HF_SendReceive(DataToSend, Response); + + if( (Response[0] == 0x00) && (Response[1] == 0x01) && (Response[2] == 0x02)) + { + /* Step 1: force Wake-up event to Timeout set DacDataH = 0xFC + With these conditions, Wake-Up event must be Timeout */ + DataToSend[DACDATAH_OFFSET] = 0xFC; + drv95HF_SendReceive(DataToSend, Response); + if( (Response[0] == 0x00) && (Response[1] == 0x01) && (Response[2] == 0x01)) + { + /* Start loop + If previous Wake-up event was Timeout (0x01) we must decrease DacDataH, + If it was Tag Detect we must increase DacDataH */ + for(i=0; i<6; i++) + { + switch(Response[2]) + { + case 0x01: + DataToSend[DACDATAH_OFFSET] -= AlgoStep[i]; + break; + + case 0x02: + DataToSend[DACDATAH_OFFSET] += AlgoStep[i]; + break; + + default: + return PCD_ERRORCODE_DEFAULT; + + } + + drv95HF_SendReceive(DataToSend, Response); + } + + /* If last Wake-up event = Tag Detect (0x02), search DacDataRef = last DacDataH value + If last Wake-up event = Timeout (0x01), search DacDataRef = last DacDataH value -4 */ + /* We have founded DacDataRef, DacDataL= DacDataRef – Guard and DacDataH= DacDataRef+ Guard + where guard = 0x08 (2 DAC steps) */ + if( (Response[0] == 0x00) && (Response[1] == 0x01) && (Response[2] == 0x01)) + *pDacDataH = (DataToSend[DACDATAH_OFFSET] -0x04) + 0x08; + else + *pDacDataH = DataToSend[DACDATAH_OFFSET] + 0x08; + + return PCD_SUCCESSCODE; + + } + else + return PCD_ERRORCODE_DEFAULT; + } + else + return PCD_ERRORCODE_DEFAULT; + +} + +/** + * @brief This function wait for Tag detection to exit + * @param WU Source : Condition for exiting this function, Condition that was realized + * @param WU Period : Time allow between 2 tag detections + * @param DacDataH : value that must have been computed by calling PCD_TagDetectCalibration function + * @param NbTrials : number of trial to find tag before time out + * @return PCD_SUCCESSCODE : the calibration was succesfully performed (DacDataH value is significant) + */ +int8_t PCD_WaitforTagDetection(uint8_t *WuSource, const uint8_t WuPeriod, const uint8_t DacDataH, const uint8_t NbTrials) +{ + uint8_t DataToSend[IDLE_CMD_LENTH+2] = { 0x00, 0x00, 0x00, 0x21, 0x00, 0x79, 0x01, 0x18, + 0x00, 0x20, 0x60, 0x60, 0x00, 0x00, 0x3F, 0x01}; + uint8_t Response[3] = {0x00}; + + DataToSend[PCD_COMMAND_OFFSET ] = IDLE; + DataToSend[PCD_LENGTH_OFFSET ] = IDLE_CMD_LENTH; + + /* modify WU Period according to user input */ + DataToSend[WU_SOURCE_OFFSET] = *WuSource; + DataToSend[WU_PERIOD_OFFSET] = WuPeriod; + DataToSend[DACDATAL_OFFSET] = DacDataH-0x10; + DataToSend[DACDATAH_OFFSET] = DacDataH; + DataToSend[NBTRIALS_OFFSET] = NbTrials; + + /* In this case we need to desactivate the drv timeout */ + EnableTimeOut = false; + drv95HF_SendReceive(DataToSend, Response); + /* Set back the drv timeout */ + EnableTimeOut = true; + + if( (Response[0] == 0x00) && (Response[1] == 0x01)) + { + *WuSource = Response[2]; + return PCD_SUCCESSCODE; + } + else + return PCD_ERRORCODE_DEFAULT; + +} + +/** + * @brief this function send a BaudRate command to the PCD device + * @param BaudRate : new baudrate + * @param pResponse : pseudo reply (shall be 0x55) + * @return PCD_SUCCESSCODE : the command was succedfully send + */ +int8_t PCD_BaudRate(const uint8_t BaudRate,uint8_t *pResponse) +{ + uint8_t DataToSend[BAUDRATE_BUFFER_SIZE]; + + DataToSend[PCD_COMMAND_OFFSET ] = BAUD_RATE; + DataToSend[PCD_LENGTH_OFFSET ] = BAUDRATE_LENGTH; + DataToSend[PCD_DATA_OFFSET ] = BaudRate; + /* Send the command the Rf transceiver */ + drv95HF_SendReceive(DataToSend, pResponse); + return PCD_SUCCESSCODE; +} + +/** + * @brief This function run a process to change UARt baud rate. It'll check the baud rate is + * @brief compatible with this MCU and configurates MCU and the PCD device baud rate. + * @param *pCommand : pointer on the buffer to send to the the PCD device ( Command | Length | Data) + * @param *pResponse : pointer on the the PCD device response ( Command | Length | Data) + * @retval PCD_SUCCESSCODE : the UART baud rate has been succesfuly changed + * @retval PCD_ERRORCODE_UARTDATARATEUNCHANGED : the UART baud rate has not changed + * @retval PCD_ERRORCODE_UARTDATARATEPROCESS : command DaubRate was send to the PCD device but the MCU was not able to comunicatewith the PCD device + */ +int8_t PCD_ChangeUARTBaudRate(const uint8_t *pCommand, uint8_t *pResponse) +{ + return PCD_ERRORCODE_UARTDATARATEUNCHANGED; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +//#ifdef __cplusplus +//} +//#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_pcd.h b/src/lib_pcd.h new file mode 100644 index 0000000..c3f1dbc --- /dev/null +++ b/src/lib_pcd.h @@ -0,0 +1,269 @@ +/** + ****************************************************************************** + * @file lib_pcd.h + * @author MMY Application Team + * @version $Revision: 1333 $ + * @date $Date: 2015-11-05 10:49:42 +0100 (Thu, 05 Nov 2015) $ + * @brief This file provides set of firmware functions to manages PCD device. + * @brief The commands as defined in CR95HF datasheet + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef _LIB_PCD_H +#define _LIB_PCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "lib_95HF.h" + +#define PCD_SPI RFTRANS_95HF_SPI + +/* customs command ------------------------------------------------------------------------*/ +#define PCD_15693ANTICOL 0xA0 +#define PCD_INVENTORY16SLOTS 0xA1 +#define PCD_ISWAKEUP 0xA2 +#define PCD_GOTOTAGDETECTINGSTATE 0xA3 +#define PCD_CALIBRATETHETAGDETECTION 0xA4 + +#define PCD_READCUSTOMTAGMEMORY 0xB0 +#define PCD_READMCUBUFFER 0xB1 +#define PCD_GETHARDWAREVERSION 0xB2 +#define PCD_DOWNLOADSTM32MEM 0xB5 +#define PCD_READWHOLEMEMORY 0xB6 +#define PCD_TRANSPARENT 0xB7 +#define PCD_PULSE_POOLINGREADING 0xB8 +#define PCD_PULSE_SPINSS 0xB9 +#define PCD_GETINTERFACEPINSTATE 0xBA +#define PCD_SETUSBDISCONNECTSTATE 0xBB +#define PCD_GETMCUVERSION 0xBC +#define PCD_RESETSEQUENCE 0xBD +#define PCD_PULSE_IRQIN 0xBE + +#ifdef USE_MSD_DRIVE +#define PCD_COPYTAGTOFILE 0xC1 +#define PCD_COPYFILETOTAG 0xC2 +#endif /*USE_MSD_DRIVE*/ + +#define PCD_POR 0xC3 +#define PCD_TAG_TRAKING 0xC4 +#define PCD_CRYPTO_GENERIC 0xC5 +#define PCD_NDEF_MESSAGE 0xC6 + +#define PCD_MULTITAG 0xD0 +#define PCD_MULTITAG_EXTENDED 0xD1 + +#define SUCCESFUL_SENDS 0x80 +#define SUCCESFUL_COMMAND 0x00 +#define SUCCESFUL_COMMAND_0x80 0x80 + +/* PCD status and erroc code------------------------------------------------------ */ +#define PCD_SUCCESSCODE RESULTOK +#define PCD_ERRORCODE_DEFAULT 0x21 +#define PCD_ERRORCODE_PARAMETER 0x22 +#define PCD_NOREPLY_CODE 0x23 +#define PCD_ERRORCODE_UARTDATARATEUNCHANGED 0x24 +#define PCD_ERRORCODE_UARTDATARATEPROCESS 0x25 +#define PCD_ERRORCODE_PORERROR 0x26 +#define PCD_ERRORCODE_PARAMETERLENGTH 0x27 +#define PCD_ERRORCODE_TIMEOUT 0x28 + +/* CR95HF polling status --------------------------------------------------------- */ +#define PCD_IDLERES_LENGTH 0x01 +#define PCD_WAKEUPSOURCE_TIMEOUT 0x01 +#define PCD_WAKEUPSOURCE_TAGDETECTING 0x02 +#define PCD_WAKEUPSOURCE_IRRQINN 0x08 + +/* Nb of bytes of reader commands --------------------------------------------------------- */ +#define SELECT_BUFFER_SIZE 16 +#define SENDRECV_BUFFER_SIZE 257 +#define SEND_BUFFER_SIZE 257 +#define IDLE_BUFFER_SIZE 16 +#define RDREG_BUFFER_SIZE 5 +#define WRREG_BUFFER_SIZE 257 +#define BAUDRATE_BUFFER_SIZE 3 +#define SUBFREQRES_BUFFER_SIZE 2 +#define ACFILTER_BUFFER_SIZE 19 +#define TESTMODE_BUFFER_SIZE 4 +#define SLEEPMODE_BUFFER_SIZE 4 + +/* Nb of bytes of reader response --------------------------------------------------------- */ +#define PCD_RESPONSEBUFFER_SIZE RFTRANS_95HF_MAX_BUFFER_SIZE + +/* protocol allowed ----------------------------------------------------------------------- */ +#define PCD_PROTOCOL_FIELDOFF 0x00 +#define PCD_PROTOCOL_ISO15693 0x01 +#define PCD_PROTOCOL_ISO14443A 0x02 +#define PCD_PROTOCOL_ISO14443B 0x03 +#define PCD_PROTOCOL_FELICA 0x04 +#define PCD_PROTOCOL_ISO14443_SR 0x05 +#define PCD_PROTOCOL_TOPAZ 0x06 + + +/* RF transceiver Offset of the command and the response ---------------------------------- */ +#define PCD_COMMAND_OFFSET RFTRANS_95HF_COMMAND_OFFSET +#define PCD_STATUS_OFFSET RFTRANS_95HF_COMMAND_OFFSET +#define PCD_LENGTH_OFFSET RFTRANS_95HF_LENGTH_OFFSET +#define PCD_DATA_OFFSET RFTRANS_95HF_DATA_OFFSET + +/* Command parameter -------------------------------------------------------------------*/ +#define SEND_MASK_APPENDCRC 0x20 +#define SEND_MASK_DONTAPPENDCRC 0x00 +#define SEND_MASK_8BITSINFIRSTBYTE 0x08 + +#define PCD_TRANSPARENTCOMMAND_OFFSET 0x01 + +#define ECHOREPLY_OFFSET 0x00 + +#define PSEUDOREPLY_OFFSET 0x00 +#define PSEUDOREPLY_LENGTH 0x01 + +#define READERREPLY_STATUSOFFSET 0x00 + +#define IDN_RESULTSCODE_OK 0x00 + +/* protocol select status --------------------------------------------------------------------- */ +#define PROTOCOLSELECT_LENGTH 0x02 +#define PROTOCOLSELECT_RESULTSCODE_OK 0x00 +#define PROTOCOLSELECT_ERRORCODE_CMDLENGTH 0x82 +#define PROTOCOLSELECT_ERRORCODE_INVALID 0x83 + +/* baud rate command -------------------------------------------------------------------------- */ +#define BAUDRATE_LENGTH 0x01 +#define BAUDRATE_DATARATE_DEFAULT 57600 + +/* send receive field status ----------------------------------------------------------------- */ +#define SENDRECV_RESULTSCODE_OK 0x80 +#define SENDRECV_ERRORCODE_COMERROR 0x86 +#define SENDRECV_ERRORCODE_FRAMEWAIT 0x87 +#define SENDRECV_ERRORCODE_SOF 0x88 +#define SENDRECV_ERRORCODE_OVERFLOW 0x89 +#define SENDRECV_ERRORCODE_FRAMING 0x8A +#define SENDRECV_ERRORCODE_EGT 0x8B +#define SENDRECV_ERRORCODE_LENGTH 0x8C +#define SENDRECV_ERRORCODE_CRC 0x8D +#define SENDRECV_ERRORCODE_RECEPTIONLOST 0x8E +#define SENDRECV_RESULTSRESIDUAL 0x90 + +#define PCD_ERRORCODE_NOTAGFOUND 0x87 + +#define SENDRECV_ERRORCODE_SOFT 0xFF + +/* control byte according to protocol -------------------------------------------------------- */ +#define CONTROL_MAX_NBBYTE 0x03 +#define CONTROL_15693_NBBYTE 0x01 +#define CONTROL_15693_CRCMASK 0x02 +#define CONTROL_15693_COLISIONMASK 0x01 + +#define ISO14443A_NBBYTE 0x03 +#define ISO14443A_COLISIONMASK 0x80 +#define ISO14443A_CRCMASK 0x20 +#define ISO14443A_CRC_ERRORCODE_TYPEA 0x20 +#define ISO14443A_PARITYMASK 0x10 +#define ISO14443A_NBSIGNIFICANTBITMASK 0x0F +#define ISO14443A_FIRSTCOLISIONBITMASK 0x0F + +#define CONTROL_14443B_NBBYTE 0x01 +#define CONTROL_14443B_CRCMASK 0x02 +#define CONTROL_14443B_ERRORCODE 0x02 +#define CONTROL_14443B_COLISIONMASK 0x01 + +#define CONTROL_FELICA_NBBYTE 0x01 +#define CONTROL_FELICA_CRCMASK 0x02 +#define CONTROL_FELICA_COLISIONMASK 0x01 + +/* Command parameter -------------------------------------------------------------------*/ +#define PCD_ISO14443A_APPENDCRC 0x20 +#define PCD_ISO14443A_DONTAPPENDCRC 0x00 +#define PCD_ISO14443A_A8BITSINFIRSTBYTE 0x08 + +/* Speed parameters commom to ISO14443B protocols --------------------------------------*/ +#define PCD_ISO14443B_TRANSMISSION_SPEED_106K 0x00 +#define PCD_ISO14443B_TRANSMISSION_SPEED_212K 0x40 +#define PCD_ISO14443B_TRANSMISSION_SPEED_424K 0x80 +#define PCD_ISO14443B_TRANSMISSION_SPEED_848K 0xC0 + +#define PCD_ISO14443B_RECEPTION_SPEED_106K 0x00 +#define PCD_ISO14443B_RECEPTION_SPEED_212K 0x10 +#define PCD_ISO14443B_RECEPTION_SPEED_424K 0x20 +#define PCD_ISO14443B_RECEPTION_SPEED_848K 0x30 + +#define PCD_ISO14443B_APPEND_CRC 0x01 + +/* Error codes for Higher level */ +#define PCDNFC_OK RESULTOK +#define PCDNFC_ERROR ERRORCODE_GENERIC +#define PCDNFC_ERROR_MEMORY_TAG 2 +#define PCDNFC_ERROR_MEMORY_INTERNAL 3 +#define PCDNFC_ERROR_LOCKED 4 +#define PCDNFC_ERROR_NOT_FORMATED 5 + + +/* protocol selected for the reader -----------------------------------------------*/ +typedef enum { + PCDPROTOCOL_UNKNOWN = 0, + PCDPROTOCOL_14443A, + PCDPROTOCOL_14443B, + PCDPROTOCOL_18092, + PCDPROTOCOL_15693, + PCDPROTOCOL_NFCDEPA, + PCDPROTOCOL_NFCDEPF +}PCD_PROTOCOL; + + +/* Functions ---------------------------------------------------------------- */ +int8_t PCD_IsReaderResultCodeOk(uint8_t CmdCode,const uint8_t *ReaderReply); +int8_t PCD_IsCRCOk(const uint8_t Protocol , const uint8_t *pReaderReply); + +int8_t PCD_CheckSendReceive(const uint8_t *pCommand, uint8_t *pResponse); + +void PCD_FieldOff(void); +void PCD_FieldOn(void); + +int8_t PCD_IDN(uint8_t *pResponse); +int8_t PCD_Echo(uint8_t *pResponse); +int8_t PCD_SendEOF(uint8_t *pResponse); +int8_t PCD_ProtocolSelect(const uint8_t Length,const uint8_t Protocol, const uint8_t *Parameters, uint8_t *pResponse); +int8_t PCD_SendRecv(const uint8_t Length,const uint8_t *Parameters,uint8_t *pResponse); +int8_t PCD_Idle(const uint8_t Length,const uint8_t *Data); +int8_t PCD_ReadRegister(const uint8_t Length,const uint8_t Address,const uint8_t RegCount,const uint8_t Flags,uint8_t *pResponse); +int8_t PCD_WriteRegister(const uint8_t Length,const uint8_t Address,const uint8_t Flags,const uint8_t *pData,uint8_t *pResponse); + +int8_t PCD_PORsequence(void); +void PCD_Receive_SPI_Response(uint8_t *pData); + +int8_t PCD_TagDetectCalibration(const uint8_t Wuperiod,uint8_t *pDacDataH); +int8_t PCD_WaitforTagDetection(uint8_t *WuSource, const uint8_t WuPeriod, const uint8_t DacDataH, const uint8_t NbTrials); + +int8_t PCD_BaudRate(const uint8_t BaudRate,uint8_t *pResponse); +int8_t PCD_ChangeUARTBaudRate(const uint8_t *pCommand, uint8_t *pResponse); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_PCD_H */ + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/lib_wrapper.h b/src/lib_wrapper.h new file mode 100644 index 0000000..949e59c --- /dev/null +++ b/src/lib_wrapper.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file lib_wrapper.h + * @author MMY Application Team + * @version $Revision: 1329 $ + * @date $Date: 2015-11-05 10:34:25 +0100 (Thu, 05 Nov 2015) $ + * @brief This file help to have upper layer independent from HW + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LIB_WRAPPER_H +#define __LIB_WRAPPER_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "common.h" + + +uint16_t ReadData( uint16_t Offset, uint16_t DataSize, uint8_t* pData ); +uint16_t WriteData( uint16_t Offset, uint32_t DataSize, uint8_t* pData ); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIB_WRAPPER_H */ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ diff --git a/src/miscellaneous.h b/src/miscellaneous.h new file mode 100644 index 0000000..f29de98 --- /dev/null +++ b/src/miscellaneous.h @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * @file miscellaneous.h + * @author MMY Application Team + * @version $Revision: 1507 $ + * @date $Date: 2016-01-08 09:48:35 +0100 (Fri, 08 Jan 2016) $ + * @brief miscellaneaous functions + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2016 STMicroelectronics

+ * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * 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. + * + ****************************************************************************** + */ + +#ifndef __MISCELLANEOUS_H +#define __MISCELLANEOUS_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" +#include "stdbool.h" +#include "string.h" + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef const uint32_t uc32; /*!< Read Only */ +typedef const uint16_t uc16; /*!< Read Only */ +typedef const uint8_t uc8; /*!< Read Only */ + + +#define MAX(x,y) ((x > y)? x : y) +#define MIN(x,y) ((x < y)? x : y) +#define ABS(x) ((x)>0 ? (x) : -(x)) +#define CHECKVAL(val, min,max) ((val < min || val > max) ? false : true) + +#define GETMSB(val) ((val & 0xFF00 )>>8 ) +#define GETLSB(val) ( val & 0x00FF ) + +#define RESULTOK 0x00 +#define ERRORCODE_GENERIC 1 + +#ifndef errchk +#define errchk(fCall) if (status = (fCall), status != RESULTOK) \ + {goto Error;} else +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MISCELLANEOUS_H */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/