/** ****************************************************************************** * @file m24sr.c * @author MCD Application Team * @brief This file provides a set of functions to interface with the M24SR * device. ****************************************************************************** * @attention * *

© Copyright (c) 2017 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "string.h" #include "m24sr.h" /** @addtogroup BSP * @{ */ /** @addtogroup Components * @{ */ /** @addtogroup M24SR * @{ * @brief This folder contains the driver layer of M24SR family (M24SR64, M24SR16, M24SR04, M24SR02) */ /** @defgroup M24SR_Private_Types M24SR Driver Private Types * @{ */ /** * @brief Synchronization Mechanism structure */ typedef enum{ M24SR_WAITINGTIME_UNKNOWN= 0, M24SR_WAITINGTIME_POLLING, M24SR_WAITINGTIME_TIMEOUT, M24SR_WAITINGTIME_GPO, M24SR_INTERRUPT_GPO }M24SR_WAITINGTIME_MGMT; /** * @brief APDU-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 */ } C_APDU_Header; /** * @brief APDU-Body command structure */ typedef struct { uint8_t LC; /* Data field length */ uint8_t *pData ; /* Command parameters */ uint8_t LE; /* Expected length of data to be returned */ } C_APDU_Body; /** * @brief APDU Command structure */ typedef struct { C_APDU_Header Header; C_APDU_Body Body; } C_APDU; /** * @brief SC response structure */ typedef struct { uint8_t *pData ; /* Data returned from the card */ /* pointer on the transceiver buffer = ReaderRecBuf[CR95HF_DATA_OFFSET ]; */ uint8_t SW1; /* Command Processing status */ uint8_t SW2; /* Command Processing qualification */ } R_APDU; /** * @brief GPO state structure */ typedef enum{ HIGH_IMPEDANCE= 0, SESSION_OPENED, WIP, I2C_ANSWER_READY, INTERRUPT, STATE_CONTROL }M24SR_GPO_MGMT; /** * @} */ /** @defgroup M24SR_Private_Constants M24SR Driver Private Constants * @{ */ /** * @brief M24SR_Private_Code_Status */ #define UB_STATUS_OFFSET 4 #define LB_STATUS_OFFSET 3 #define M24SR_NBBYTE_INVALID 0xFFFE /** * @brief M24SR_Private_File_Identifier */ #define SYSTEM_FILE_ID 0xE101 #define CC_FILE_ID 0xE103 #define NDEF_FILE_ID 0x0001 /** * @brief M24SR_Private_Command_Management */ /* special M24SR command ----------------------------------------------------------------------*/ #define M24SR_OPENSESSION 0x26 #define M24SR_KILLSESSION 0x52 /* APDU Command: class list -------------------------------------------*/ #define C_APDU_CLA_DEFAULT 0x00 #define C_APDU_CLA_ST 0xA2 /*------------------------ Data Area Management Commands ---------------------*/ #define C_APDU_SELECT_FILE 0xA4 #define C_APDU_GET_RESPONCE 0xC0 #define C_APDU_STATUS 0xF2 #define C_APDU_UPDATE_BINARY 0xD6 #define C_APDU_READ_BINARY 0xB0 #define C_APDU_WRITE_BINARY 0xD0 #define C_APDU_UPDATE_RECORD 0xDC #define C_APDU_READ_RECORD 0xB2 /*-------------------------- Safety Management Commands ----------------------*/ #define C_APDU_VERIFY 0x20 #define C_APDU_CHANGE 0x24 #define C_APDU_DISABLE 0x26 #define C_APDU_ENABLE 0x28 /*-------------------------- Gpio Management Commands ------------------------*/ #define C_APDU_INTERRUPT 0xD6 /* Length ----------------------------------------------------------------------------------*/ #define M24SR_STATUS_NBBYTE 2 #define M24SR_CRC_NBBYTE 2 #define M24SR_STATUSRESPONSE_NBBYTE 5 #define M24SR_DESELECTREQUEST_NBBYTE 3 #define M24SR_DESELECTRESPONSE_NBBYTE 3 #define M24SR_WATINGTIMEEXTRESPONSE_NBBYTE 4 #define M24SR_PASSWORD_NBBYTE 0x10 /* Command structure ------------------------------------------------------------------------*/ #define M24SR_CMDSTRUCT_SELECTAPPLICATION 0x01FF #define M24SR_CMDSTRUCT_SELECTCCFILE 0x017F #define M24SR_CMDSTRUCT_SELECTNDEFFILE 0x017F #define M24SR_CMDSTRUCT_READBINARY 0x019F #define M24SR_CMDSTRUCT_UPDATEBINARY 0x017F #define M24SR_CMDSTRUCT_VERIFYBINARYWOPWD 0x013F #define M24SR_CMDSTRUCT_VERIFYBINARYWITHPWD 0x017F #define M24SR_CMDSTRUCT_CHANGEREFDATA 0x017F #define M24SR_CMDSTRUCT_ENABLEVERIFREQ 0x011F #define M24SR_CMDSTRUCT_DISABLEVERIFREQ 0x011F #define M24SR_CMDSTRUCT_SENDINTERRUPT 0x013F #define M24SR_CMDSTRUCT_GPOSTATE 0x017F /* Command structure Mask -------------------------------------------------------------------*/ #define M24SR_PCB_NEEDED 0x0001 /* PCB byte present or not */ #define M24SR_CLA_NEEDED 0x0002 /* CLA byte present or not */ #define M24SR_INS_NEEDED 0x0004 /* Operation code present or not*/ #define M24SR_P1_NEEDED 0x0008 /* Selection Mode present or not*/ #define M24SR_P2_NEEDED 0x0010 /* Selection Option present or not*/ #define M24SR_LC_NEEDED 0x0020 /* Data field length byte present or not */ #define M24SR_DATA_NEEDED 0x0040 /* Data present or not */ #define M24SR_LE_NEEDED 0x0080 /* Expected length present or not */ #define M24SR_CRC_NEEDED 0x0100 /* 2 CRC bytes present or not */ #define M24SR_DID_NEEDED 0x08 /* DID byte present or not */ /** * @brief M24SR_Private_Offset_and_masks */ /* Offset ----------------------------------------------------------------------------------*/ #define M24SR_OFFSET_PCB 0 #define M24SR_OFFSET_CLASS 1 #define M24SR_OFFSET_INS 2 #define M24SR_OFFSET_P1 3 /* mask ------------------------------------------------------------------------------------*/ #define M24SR_MASK_BLOCK 0xC0 #define M24SR_MASK_IBLOCK 0x00 #define M24SR_MASK_RBLOCK 0x80 #define M24SR_MASK_SBLOCK 0xC0 /** * @} */ /** @defgroup M24SR_Private_Variables M24SR Private Global Variables * @{ */ static C_APDU Command; static uint8_t DataBuffer[0xFF]; uint8_t uM24SRbuffer [0xFF]; static uint8_t uDIDbyte =0x00; uint8_t uSynchroMode = M24SR_WAITINGTIME_POLLING; uint8_t uGpoMode = M24SR_GPO_POLLING; volatile uint8_t GPO_Low = 0; /** * @} */ /** @defgroup M24SR_Private_Macros M24SR Private Macros * @{ */ /** @brief Get Most Significant Byte * @param val: number where MSB must be extracted * @retval MSB */ #define GETMSB(val) ( (uint8_t) ((val & 0xFF00 )>>8) ) /** @brief Get Least Significant Byte * @param val: number where LSB must be extracted * @retval LSB */ #define GETLSB(val) ( (uint8_t) (val & 0x00FF )) /** @brief Used to toggle the block number by adding 0 or 1 to default block number value * @param val: number to know if incrementation is needed * @retval 0 or 1 if incrementation needed */ #define TOGGLE(val) ((val != 0x00)? 0x00 : 0x01) /** * @} */ /** @defgroup M24SR_Private_FunctionsPrototypes M24SR Private FunctionsPrototypes * @{ */ static uint16_t M24SR_UpdateCrc ( uint8_t ch, uint16_t *lpwCrc); static uint16_t M24SR_ComputeCrc ( uint8_t *Data, uint8_t Length); static uint16_t M24SR_IsCorrectCRC16Residue ( uint8_t *DataIn,uint8_t Length); static void M24SR_BuildIBlockCommand ( uint16_t CommandStructure, C_APDU Command, uint16_t *NbByte , uint8_t *pCommand); static uint16_t IsSBlock ( uint8_t *pBuffer); static uint16_t M24SR_FWTExtension ( uint16_t DeviceAddr, uint8_t FWTbyte); static void M24SR_SetI2CSynchroMode ( uint8_t WaitingMode ); static uint16_t M24SR_IsAnswerReady ( uint16_t DeviceAddr); /** * @} */ /** @defgroup M24SR_Private_Functions M24SR Private Functions * @{ */ /** * @brief This function updates the CRC * @param None * @retval None */ static uint16_t M24SR_UpdateCrc (uint8_t ch, uint16_t *lpwCrc) { ch = (ch^(uint8_t)((*lpwCrc) & 0x00FF)); ch = (ch^(ch<<4)); *lpwCrc = (*lpwCrc >> 8)^((uint16_t)ch << 8)^((uint16_t)ch<<3)^((uint16_t)ch>>4); return(*lpwCrc); } /** * @brief This function returns the CRC 16 * @param Data : pointer on the data used to compute the CRC16 * @param Length : number of byte of the data * @retval CRC16 */ static uint16_t M24SR_ComputeCrc(uint8_t *Data, uint8_t Length) { uint8_t chBlock; uint16_t wCrc; wCrc = 0x6363; /* ITU-V.41 */ do { chBlock = *Data++; M24SR_UpdateCrc(chBlock, &wCrc); } while (--Length); return wCrc ; } /** * @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 Status (SW1&SW2) : CRC16 residue is correct * @retval M24SR_ERROR_CRC : CRC16 residue is false */ static uint16_t M24SR_IsCorrectCRC16Residue (uint8_t *DataIn,uint8_t Length) { uint16_t ResCRC=0; /* check the CRC16 Residue */ if (Length !=0) ResCRC= M24SR_ComputeCrc (DataIn, Length); if ( ResCRC == 0x0000) { /* Good CRC, but error status from M24SR */ return( ((DataIn[Length-UB_STATUS_OFFSET]<<8) & 0xFF00) | (DataIn[Length-LB_STATUS_OFFSET] & 0x00FF) ); } else { ResCRC=0; ResCRC= M24SR_ComputeCrc (DataIn, 5); if ( ResCRC != 0x0000) { /* Bad CRC */ return M24SR_ERROR_CRC; } else { /* Good CRC, but error status from M24SR */ return( ((DataIn[1]<<8) & 0xFF00) | (DataIn[2] & 0x00FF) ); } } } /** * @brief This functions creates an I block command according to the structures CommandStructure and Command. * @param Command : structue which contains the field of the different parameter * @param CommandStructure : structure that contain the structure of the command (if the different field are presnet or not * @param NbByte : number of byte of the command * @param pCommand : pointer of the command created */ static void M24SR_BuildIBlockCommand ( uint16_t CommandStructure, C_APDU Command, uint16_t *NbByte , uint8_t *pCommand) { uint16_t uCRC16; static uint8_t BlockNumber = 0x01; (*NbByte) = 0; /* add the PCD byte */ if ((CommandStructure & M24SR_PCB_NEEDED) !=0) { /* toggle the block number */ BlockNumber = TOGGLE ( BlockNumber ); /* Add the I block byte */ pCommand[(*NbByte)++] = 0x02 | BlockNumber; } /* add the DID byte */ if ((BlockNumber & M24SR_DID_NEEDED) !=0) { /* Add the I block byte */ pCommand[(*NbByte)++] = uDIDbyte; } /* add the Class byte */ if ((CommandStructure & M24SR_CLA_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Header.CLA ; } /* add the instruction byte byte */ if ( (CommandStructure & M24SR_INS_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Header.INS ; } /* add the Selection Mode byte */ if ((CommandStructure & M24SR_P1_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Header.P1 ; } /* add the Selection Mode byte */ if ((CommandStructure & M24SR_P2_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Header.P2 ; } /* add Data field lengthbyte */ if ((CommandStructure & M24SR_LC_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Body.LC ; } /* add Data field */ if ((CommandStructure & M24SR_DATA_NEEDED) !=0) { memcpy(&(pCommand[(*NbByte)]) ,Command.Body.pData,Command.Body.LC ) ; (*NbByte) += Command.Body.LC ; } /* add Le field */ if ((CommandStructure & M24SR_LE_NEEDED) !=0) { pCommand[(*NbByte)++] = Command.Body.LE ; } /* add CRC field */ if ((CommandStructure & M24SR_CRC_NEEDED) !=0) { uCRC16 = M24SR_ComputeCrc (pCommand,(uint8_t) (*NbByte)); /* append the CRC16 */ pCommand [(*NbByte)++] = GETLSB (uCRC16 ) ; pCommand [(*NbByte)++] = GETMSB (uCRC16 ) ; } } /** * @brief This function return M24SR_STATUS_SUCCESS if the pBuffer is an s-block * @param pBuffer : pointer of the data * @retval M24SR_STATUS_SUCCESS : the data is a S-Block * @retval M24SR_ERROR_DEFAULT : the data is not a S-Block */ static uint16_t IsSBlock (uint8_t *pBuffer) { if ((pBuffer[M24SR_OFFSET_PCB] & M24SR_MASK_BLOCK) == M24SR_MASK_SBLOCK) { return M24SR_STATUS_SUCCESS; } else { return M24SR_ERROR_DEFAULT; } } /** * @brief This function sends the FWT extension command (S-Block format) * @param DeviceAddr: I2C address of the device * @param FWTbyte : FWT value * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ static uint16_t M24SR_FWTExtension (uint16_t DeviceAddr, uint8_t FWTbyte) { uint8_t pBuffer[M24SR_STATUSRESPONSE_NBBYTE]; uint16_t status ; uint16_t NthByte = 0, uCRC16; /* create the response */ pBuffer[NthByte++] = 0xF2 ; pBuffer[NthByte++] = FWTbyte ; /* compute the CRC */ uCRC16 = M24SR_ComputeCrc (pBuffer,0x02); /* append the CRC16 */ pBuffer [NthByte++] = GETLSB (uCRC16 ) ; pBuffer [NthByte++]= GETMSB (uCRC16 ) ; /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NthByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ if ( NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @} */ /** @defgroup M24SR_Exported_Functions M24SR Exported Functions * @{ */ /** * @brief This function initialize the M24SR device * @param DeviceAddr: I2C address of the device * @param GpoMode: M24SR_GPO_POLLING / M24SR_GPO_SYNCHRO / M24SR_GPO_INTERRUPT * @retval None */ void M24SR_Init(uint16_t DeviceAddr, uint8_t GpoMode) { uGpoMode = GpoMode; /* Global variable initialization */ if(uGpoMode == M24SR_GPO_INTERRUPT) { NFC_IO_Init(0x1); } else { NFC_IO_Init(0x0); } /* build the command */ Command.Header.CLA = 0x00; Command.Header.INS = 0x00; /* copy the offset */ Command.Header.P1 = 0x00 ; Command.Header.P2 = 0x00 ; /* copy the number of byte of the data field */ Command.Body.LC = 0x00 ; /* copy the number of byte to read */ Command.Body.LE = 0x00 ; Command.Body.pData = DataBuffer; if((uGpoMode == M24SR_GPO_SYNCHRO) || (uGpoMode == M24SR_GPO_INTERRUPT)) { if( M24SR_KillSession(DeviceAddr) == M24SR_ACTION_COMPLETED) { M24SR_ManageI2CGPO(DeviceAddr, I2C_ANSWER_READY); M24SR_Deselect (DeviceAddr); } } } /** * @brief This function initialize the M24SR device * @retval None */ void M24SR_GPO_Callback( void ) { if( uSynchroMode == M24SR_INTERRUPT_GPO) { GPO_Low = 1; } } /** * @brief This function sends the GetSession command to the M24SR device * @param DeviceAddr: I2C address of the device * @retval M24SR_ACTION_COMPLETED : the function is succesful. * @retval Status (SW1&SW2) : if operation does not complete. */ uint16_t M24SR_GetSession (uint16_t DeviceAddr) { uint8_t Buffer = M24SR_OPENSESSION; if (NFC_IO_WriteMultiple(DeviceAddr, &Buffer, 0x01 ) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* Insure no access will be done just after open session */ /* The only way here is to poll I2C to know when M24SR is ready */ /* GPO can not be use with GetSession command */ if (NFC_IO_IsDeviceReady(DeviceAddr, NFC_IO_TRIALS) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } return M24SR_ACTION_COMPLETED; } /** * @brief This function sends the KillSession command to the M24SR device * @param DeviceAddr: I2C address of the device * @retval M24SR_ACTION_COMPLETED : the function is succesful. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_KillSession (uint16_t DeviceAddr) { uint8_t pBuffer[] = {M24SR_KILLSESSION}; if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, 0x01) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* Insure no access will be done just after open session */ /* The only way here is to poll I2C to know when M24SR is ready */ /* GPO can not be use with KillSession command */ if (NFC_IO_IsDeviceReady(DeviceAddr, NFC_IO_TRIALS) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } return M24SR_ACTION_COMPLETED; } /** * @brief This function sends the Deselect command (S-Block format) * @param DeviceAddr: I2C address of the device * @retval M24SR_ACTION_COMPLETED : the function is succesful. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_Deselect (uint16_t DeviceAddr) { uint8_t pBuffer[] = {0xC2,0xE0,0xB4} ; uint16_t status ; /* send the request */ if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, M24SR_DESELECTREQUEST_NBBYTE) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* flush the M24SR buffer */ if (NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_DESELECTREQUEST_NBBYTE) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } return M24SR_ACTION_COMPLETED; } /** * @brief This function sends the SelectApplication command * @param DeviceAddr: I2C address of the device * @retval M24SR_ACTION_COMPLETED : the function is succesful. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_SelectApplication (uint16_t DeviceAddr) { uint8_t *pBuffer = uM24SRbuffer , NbByteToRead = M24SR_STATUSRESPONSE_NBBYTE; uint8_t uLc = 0x07, pData[] = {0xD2,0x76,0x00,0x00,0x85,0x01,0x01}, uLe = 0x00; uint16_t status ; uint16_t uP1P2 =0x0400, NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_SELECT_FILE; /* copy the offset */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; /* copy the number of byte of the data field */ Command.Body.LC = uLc ; /* copy the data */ memcpy(Command.Body.pData, pData, uLc); /* copy the number of byte to read */ Command.Body.LE = uLe ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_SELECTAPPLICATION, Command, &NbByte , pBuffer); /* send the request */ if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ if (NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead); return status; } /** * @brief This function sends the SelectCCFile command * @param DeviceAddr: I2C address of the device * @retval M24SR_ACTION_COMPLETED : the function is succesful. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. * @retval Status (SW1&SW2) : if operation does not complete for another reason. */ uint16_t M24SR_SelectCCfile (uint16_t DeviceAddr) { uint8_t *pBuffer = uM24SRbuffer , NbByteToRead = M24SR_STATUSRESPONSE_NBBYTE; uint8_t uLc = 0x02; uint16_t status ; uint16_t uP1P2 =0x000C, uNbFileId =CC_FILE_ID, NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_SELECT_FILE; /* copy the offset */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; /* copy the number of byte of the data field */ Command.Body.LC = uLc ; /* copy the File Id */ Command.Body.pData[0] = GETMSB (uNbFileId ) ; Command.Body.pData[1] = GETLSB (uNbFileId ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_SELECTCCFILE, Command, &NbByte , pBuffer); /* send the request */ if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ if (NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead); return status; } /** * @brief This function sends the SelectSystemFile command * @param DeviceAddr: I2C address of the device * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_SelectSystemfile (uint16_t DeviceAddr) { uint8_t *pBuffer = uM24SRbuffer , NbByteToRead = M24SR_STATUSRESPONSE_NBBYTE; uint8_t uLc = 0x02; uint16_t status ; uint16_t uP1P2 =0x000C, uNbFileId =SYSTEM_FILE_ID, NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_SELECT_FILE; /* copy the offset */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; /* copy the number of byte of the data field */ Command.Body.LC = uLc ; /* copy the File Id */ Command.Body.pData[0] = GETMSB (uNbFileId ) ; Command.Body.pData[1] = GETLSB (uNbFileId ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_SELECTCCFILE, Command, &NbByte , pBuffer); /* send the request */ if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ if (NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead); return status; } /** * @brief This function sends the SelectNDEFfile command * @param DeviceAddr: I2C address of the device * @param NDEFfileId: NDEF identification to select NDEF in M24SR * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_SelectNDEFfile (uint16_t DeviceAddr, uint16_t NDEFfileId) { uint8_t *pBuffer = uM24SRbuffer , NbByteToRead = M24SR_STATUSRESPONSE_NBBYTE; uint8_t uLc = 0x02; uint16_t status ; uint16_t uP1P2 =0x000C, NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_SELECT_FILE; /* copy the offset */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; /* copy the number of byte of the data field */ Command.Body.LC = uLc ; /* copy the offset */ Command.Body.pData[0] = GETMSB (NDEFfileId ) ; Command.Body.pData[1] = GETLSB (NDEFfileId ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_SELECTNDEFFILE, Command, &NbByte , pBuffer); /* send the request */ if (NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ if (NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead); return status; } /** * @brief This function sends a read binary command * @param DeviceAddr: I2C address of the device * @param Offset : first byte to read * @param NbByteToRead : number of byte to read * @param pBufferRead : pointer of the buffer read from the M24SR device * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_ReadBinary (uint16_t DeviceAddr, uint16_t Offset ,uint8_t NbByteToRead , uint8_t *pBufferRead) { uint8_t *pBuffer = uM24SRbuffer ; uint16_t status ; uint16_t NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_READ_BINARY; /* copy the offset */ Command.Header.P1 = GETMSB (Offset ) ; Command.Header.P2 = GETLSB (Offset ) ; /* copy the number of byte to read */ Command.Body.LE = NbByteToRead ; M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_READBINARY, Command, &NbByte , pBuffer); status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead + M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead+ M24SR_STATUSRESPONSE_NBBYTE); /* retrieve the data without SW1 & SW2 as provided as return value of the function */ memcpy(pBufferRead ,&pBuffer[1],NbByteToRead); return status; } /** * @brief This function sends a ST read binary command (no error if access is not inside NDEF file) * @param DeviceAddr: I2C address of the device * @param Offset : first byte to read * @param NbByteToRead : number of byte to read * @param pBufferRead : pointer of the buffer read from the M24SR device * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_STReadBinary (uint16_t DeviceAddr, uint16_t Offset, uint8_t NbByteToRead, uint8_t *pBufferRead) { uint8_t *pBuffer = uM24SRbuffer ; uint16_t status ; uint16_t NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_ST; Command.Header.INS = C_APDU_READ_BINARY; /* copy the offset */ Command.Header.P1 = GETMSB (Offset ) ; Command.Header.P2 = GETLSB (Offset ) ; /* copy the number of byte to read */ Command.Body.LE = NbByteToRead ; M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_READBINARY, Command, &NbByte , pBuffer); status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, NbByteToRead + M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer,NbByteToRead+ M24SR_STATUSRESPONSE_NBBYTE); /* retrieve the data without SW1 & SW2 as provided as return value of the function */ memcpy(pBufferRead ,&pBuffer[1],NbByteToRead); return status; } /** * @brief This function sends a Update binary command * @param DeviceAddr: I2C address of the device * @param Offset : first byte to read * @param NbByteToWrite : number of byte to write * @param pBufferRead : pointer of the buffer read from the M24SR device * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_UpdateBinary (uint16_t DeviceAddr, uint16_t Offset ,uint8_t NbByteToWrite,uint8_t *pDataToWrite) { uint8_t *pBuffer = uM24SRbuffer ; uint16_t status ; uint16_t NbByte; /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_UPDATE_BINARY; /* copy the offset */ Command.Header.P1 = GETMSB (Offset ) ; Command.Header.P2 = GETLSB (Offset ) ; /* copy the number of byte of the data field */ Command.Body.LC = NbByteToWrite ; /* copy the File Id */ memcpy(Command.Body.pData ,pDataToWrite, NbByteToWrite ); M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_UPDATEBINARY, Command, &NbByte , pBuffer); status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* if the response is a Watiting frame extenstion request */ if (IsSBlock (pBuffer) == M24SR_STATUS_SUCCESS) { /*check the CRC */ if (M24SR_IsCorrectCRC16Residue (pBuffer , M24SR_WATINGTIMEEXTRESPONSE_NBBYTE) != M24SR_ERROR_CRC) { /* send the FrameExension response*/ status = M24SR_FWTExtension (DeviceAddr, pBuffer [M24SR_OFFSET_PCB+1]); } } else { status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); } return status; } /** * @brief This function sends the Verify command * @param DeviceAddr: I2C address of the device * @param uPwdId : PasswordId ( 0x0001 : Read NDEF pwd or 0x0002 : Write NDEF pwd or 0x0003 : I2C pwd) * @param NbPwdByte : Number of byte ( 0x00 or 0x10) * @param pPwd : pointer on the passwaord * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_Verify (uint16_t DeviceAddr, uint16_t uPwdId, uint8_t NbPwdByte ,uint8_t *pPwd) { uint8_t *pBuffer = uM24SRbuffer ; uint16_t status = 0x0000 ; uint16_t NbByte; /*check the parameters */ if (uPwdId > 0x0003) { return M24SR_ERROR_PARAMETER; } if ( (NbPwdByte != 0x00) && (NbPwdByte != 0x10)) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_VERIFY; /* copy the Password Id */ Command.Header.P1 = GETMSB (uPwdId ) ; Command.Header.P2 = GETLSB (uPwdId ) ; /* copy the number of byte of the data field */ Command.Body.LC = NbPwdByte ; if (NbPwdByte == 0x10) { /* copy the password */ memcpy(Command.Body.pData, pPwd, NbPwdByte); /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_VERIFYBINARYWITHPWD, Command, &NbByte , pBuffer); } else { /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_VERIFYBINARYWOPWD, Command, &NbByte , pBuffer); } /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* wait for answer ready */ status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function sends the ChangeReferenceData command * @param DeviceAddr: I2C address of the device * @param uPwdId : PasswordId ( 0x0001 : Read NDEF pwd or 0x0002 : Write NDEF pwd or 0x0003 : I2C pwd) * @param pPwd : pointer on the passwaord * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_ChangeReferenceData (uint16_t DeviceAddr, uint16_t uPwdId, uint8_t *pPwd) { uint8_t *pBuffer = uM24SRbuffer; uint16_t status ; uint16_t NbByte; /*check the parameters */ if (uPwdId > 0x0003) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_CHANGE; /* copy the Password Id */ Command.Header.P1 = GETMSB (uPwdId ) ; Command.Header.P2 = GETLSB (uPwdId ) ; /* copy the number of byte of the data field */ Command.Body.LC = M24SR_PASSWORD_NBBYTE ; /* copy the password */ memcpy(Command.Body.pData, pPwd, M24SR_PASSWORD_NBBYTE); /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_CHANGEREFDATA, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function sends the EnableVerificationRequirement command * @param DeviceAddr: I2C address of the device * @param uReadOrWrite : enable the read or write protection ( 0x0001 : Read or 0x0002 : Write ) * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_EnableVerificationRequirement (uint16_t DeviceAddr, uint16_t uReadOrWrite) { uint8_t *pBuffer = uM24SRbuffer; uint16_t status ; uint16_t NbByte; /*check the parameters */ if ( (uReadOrWrite != 0x0001) && (uReadOrWrite != 0x0002)) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_ENABLE; /* copy the Password Id */ Command.Header.P1 = GETMSB (uReadOrWrite ) ; Command.Header.P2 = GETLSB (uReadOrWrite ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_ENABLEVERIFREQ, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* The right access to be updated in EEPROM need at least 6ms */ status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function sends the DisableVerificationRequirement command * @param DeviceAddr: I2C address of the device * @param uReadOrWrite : enable the read or write protection ( 0x0001 : Read or 0x0002 : Write ) * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_DisableVerificationRequirement (uint16_t DeviceAddr, uint16_t uReadOrWrite) { uint8_t *pBuffer = uM24SRbuffer; uint16_t status ; uint16_t NbByte; /*check the parameters */ if ( (uReadOrWrite != 0x0001) && (uReadOrWrite != 0x0002)) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_DEFAULT; Command.Header.INS = C_APDU_DISABLE; /* copy the Password Id */ Command.Header.P1 = GETMSB (uReadOrWrite ) ; Command.Header.P2 = GETLSB (uReadOrWrite ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_DISABLEVERIFREQ, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } /* The right access to be updated in EEPROM need at least 6ms */ status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function sends the EnablePermananentState command * @param DeviceAddr: I2C address of the device * @param uReadOrWrite : enable the read or write protection ( 0x0001 : Read or 0x0002 : Write ) * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_EnablePermanentState (uint16_t DeviceAddr, uint16_t uReadOrWrite ) { uint8_t *pBuffer = uM24SRbuffer; uint16_t status ; uint16_t NbByte; /*check the parameters */ if ( (uReadOrWrite != 0x0001) && (uReadOrWrite != 0x0002)) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_ST; Command.Header.INS = C_APDU_ENABLE; /* copy the Password Id */ Command.Header.P1 = GETMSB (uReadOrWrite ) ; Command.Header.P2 = GETLSB (uReadOrWrite ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_ENABLEVERIFREQ, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function sends the DisablePermanentState command * @param DeviceAddr: I2C address of the device * @param uReadOrWrite : enable the read or write protection ( 0x0001 : Read or 0x0002 : Write ) * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_DisablePermanentState (uint16_t DeviceAddr, uint16_t uReadOrWrite ) { uint8_t *pBuffer = uM24SRbuffer; uint16_t status ; uint16_t NbByte; /*check the parameters */ if ( (uReadOrWrite != 0x0001) && (uReadOrWrite != 0x0002)) { return M24SR_ERROR_PARAMETER; } /* build the command */ Command.Header.CLA = C_APDU_CLA_ST; Command.Header.INS = C_APDU_DISABLE; /* copy the Password Id */ Command.Header.P1 = GETMSB (uReadOrWrite ) ; Command.Header.P2 = GETLSB (uReadOrWrite ) ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_DISABLEVERIFREQ, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function generates a interrupt on GPO pin * @param DeviceAddr: I2C address of the device * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_SendInterrupt (uint16_t DeviceAddr) { uint8_t *pBuffer = uM24SRbuffer; uint16_t uP1P2 =0x001E; uint16_t status ; uint16_t NbByte; status = M24SR_ManageI2CGPO(DeviceAddr, INTERRUPT); /* build the command */ Command.Header.CLA = C_APDU_CLA_ST; Command.Header.INS = C_APDU_INTERRUPT; /* copy the Password Id */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; Command.Body.LC = 0x00 ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_SENDINTERRUPT, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function force GPO pin to low state or high Z * @param DeviceAddr: I2C address of the device * @param uSetOrReset : select if GPO must be low (reset) or HiZ * @retval Status (SW1&SW2) : Status of the operation to complete. * @retval M24SR_ERROR_TIMEOUT : The I2C timeout occured. */ uint16_t M24SR_StateControl (uint16_t DeviceAddr, uint8_t uSetOrReset ) { uint8_t *pBuffer = uM24SRbuffer; uint16_t uP1P2 =0x001F; uint16_t status ; uint16_t NbByte; /*check the parameters */ if ( (uSetOrReset != 0x01) && (uSetOrReset != 0x00)) { return M24SR_ERROR_PARAMETER; } status = M24SR_ManageI2CGPO(DeviceAddr, STATE_CONTROL); /* build the command */ Command.Header.CLA = C_APDU_CLA_ST; Command.Header.INS = C_APDU_INTERRUPT; /* copy the Password Id */ Command.Header.P1 = GETMSB (uP1P2 ) ; Command.Header.P2 = GETLSB (uP1P2 ) ; Command.Body.LC = 0x01 ; /* copy the data */ memcpy(Command.Body.pData , &uSetOrReset, 0x01 ); //Command.Body.LE = 0x00 ; /* build the I²C command */ M24SR_BuildIBlockCommand ( M24SR_CMDSTRUCT_GPOSTATE, Command, &NbByte , pBuffer); /* send the request */ status = NFC_IO_WriteMultiple(DeviceAddr, pBuffer, NbByte); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsAnswerReady (DeviceAddr); if (status != M24SR_STATUS_SUCCESS) { return status; } /* read the response */ status = NFC_IO_ReadMultiple (DeviceAddr , pBuffer, M24SR_STATUSRESPONSE_NBBYTE); if (status != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } status = M24SR_IsCorrectCRC16Residue (pBuffer, M24SR_STATUSRESPONSE_NBBYTE); return status; } /** * @brief This function configure GPO purpose for I2C session * @param DeviceAddr: I2C address of the device * @param GPO_I2Cconfig: GPO configuration to set * @retval Status (SW1&SW2) : Status of the operation to complete. */ uint16_t M24SR_ManageI2CGPO(uint16_t DeviceAddr, uint8_t GPO_I2Cconfig) { uint16_t status; uint8_t GPO_config; uint8_t DefaultPassword[16]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if( GPO_I2Cconfig > STATE_CONTROL) { return M24SR_ERROR_PARAMETER; } /* we must not be in interrupt mode for I2C synchro as we will change GPO purpose */ M24SR_SetI2CSynchroMode(M24SR_WAITINGTIME_POLLING); M24SR_SelectApplication(DeviceAddr); M24SR_SelectSystemfile(DeviceAddr); M24SR_ReadBinary (DeviceAddr, 0x0004 , 0x01 , &GPO_config ); /* Update only GPO purpose for I2C */ GPO_config = (GPO_config & 0xF0) | GPO_I2Cconfig; M24SR_SelectSystemfile(DeviceAddr); M24SR_Verify(DeviceAddr, M24SR_I2C_PWD ,0x10 ,DefaultPassword ); status = M24SR_UpdateBinary (DeviceAddr, 0x0004 ,0x01, &(GPO_config) ); /* if we have set interrupt mode for I2C synchro we can enable interrupt mode */ if (GPO_I2Cconfig == I2C_ANSWER_READY && status == M24SR_ACTION_COMPLETED) { if(uGpoMode == M24SR_GPO_SYNCHRO) { M24SR_SetI2CSynchroMode(M24SR_WAITINGTIME_GPO); } else { M24SR_SetI2CSynchroMode(M24SR_INTERRUPT_GPO); } } return status; } /** * @brief This function configure GPO purpose for RF session * @param DeviceAddr: I2C address of the device * @param GPO_RFconfig: GPO configuration to set * @retval Status (SW1&SW2) : Status of the operation to complete. */ uint16_t M24SR_ManageRFGPO(uint16_t DeviceAddr, uint8_t GPO_RFconfig) { uint16_t status; uint8_t GPO_config; uint8_t DefaultPassword[16]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if( GPO_RFconfig > STATE_CONTROL) { return M24SR_ERROR_PARAMETER; } M24SR_SelectApplication(DeviceAddr); M24SR_SelectSystemfile(DeviceAddr); M24SR_ReadBinary (DeviceAddr, 0x0004 , 0x01 , &GPO_config ); /* Update only GPO purpose for I2C */ GPO_config = (GPO_config & 0x0F) | (GPO_RFconfig<<4); M24SR_SelectSystemfile(DeviceAddr); M24SR_Verify(DeviceAddr, M24SR_I2C_PWD ,0x10 ,DefaultPassword ); status = M24SR_UpdateBinary (DeviceAddr, 0x0004 ,0x01, &(GPO_config)); return status; } /** * @brief This functions returns M24SR_STATUS_SUCCESS when a response is ready * @param DeviceAddr: I2C address of the device * @retval M24SR_STATUS_SUCCESS : a response of the M24LR is ready * @retval M24SR_ERROR_DEFAULT : the response of the M24LR is not ready */ static uint16_t M24SR_IsAnswerReady (uint16_t DeviceAddr) { uint32_t retry = 0xFFFFF; uint8_t stable = 0; uint8_t PinState; switch (uSynchroMode) { case M24SR_WAITINGTIME_POLLING : if(NFC_IO_IsDeviceReady(DeviceAddr, NFC_IO_TRIALS) != NFC_IO_STATUS_SUCCESS) { return M24SR_ERROR_TIMEOUT; } break; case M24SR_WAITINGTIME_TIMEOUT : /* M24SR FWI=5 => (256*16/fc)*2^5=9.6ms but M24SR ask for extended time to program up to 246Bytes. */ NFC_IO_Delay(M24SR_ANSWER_TIMEOUT); break; case M24SR_WAITINGTIME_GPO : /* mbd does not support interrupt for the moment with nucleo board */ do { NFC_IO_ReadState(&PinState); if( PinState == 0) /* RESET */ { stable ++; } retry --; } while(stable < M24SR_ANSWER_STABLE && retry>0); if(!retry) { return M24SR_ERROR_TIMEOUT; } break; case M24SR_INTERRUPT_GPO : /* Check if the GPIO is not already low before calling this function */ NFC_IO_ReadState(&PinState); if(PinState == 1) /* SET */ { while (GPO_Low == 0); } GPO_Low = 0; break; default : return M24SR_ERROR_DEFAULT; } return M24SR_STATUS_SUCCESS; } /** * @brief This function enable or disable RF communication * @param OnOffChoice: GPO configuration to set * @retval Status (SW1&SW2) : Status of the operation to complete. */ void M24SR_RFConfig( uint8_t OnOffChoice) { /* Disable RF */ if ( OnOffChoice != 0 ) { NFC_IO_RfDisable(0); /* PIN RESET */ } else { NFC_IO_RfDisable(1); /* PIN SET */ } } /** * @brief this functions configure I2C synchronization mode * @param WaitingMode : interruption or polling * @retval None */ static void M24SR_SetI2CSynchroMode( uint8_t WaitingMode) { if((uGpoMode == M24SR_GPO_SYNCHRO) || (uGpoMode == M24SR_GPO_INTERRUPT)) { uSynchroMode = WaitingMode; } else /* GPO_POLLING */ { if(WaitingMode == M24SR_WAITINGTIME_GPO || WaitingMode == M24SR_INTERRUPT_GPO) uSynchroMode = M24SR_WAITINGTIME_POLLING; /* Force Polling */ else uSynchroMode = WaitingMode; } } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /******************* (C) COPYRIGHT STMicroelectronics *****END OF FILE****/