/******************************************************************************
* \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:
*
* 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.
*
******************************************************************************/
/*
* PROJECT: ST25R3911 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Ulrich Herrmann
*
* \brief Implementation of ST25R3911 communication.
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3911_com.h"
#include "st25r3911.h"
#include "utils.h"
/*
******************************************************************************
* LOCAL DEFINES
******************************************************************************
*/
#define ST25R3911_WRITE_MODE (0U) /*!< ST25R3911 SPI Operation Mode: Write */
#define ST25R3911_READ_MODE (1U << 6) /*!< ST25R3911 SPI Operation Mode: Read */
#define ST25R3911_FIFO_LOAD (2U << 6) /*!< ST25R3911 SPI Operation Mode: FIFO Load */
#define ST25R3911_FIFO_READ (0xBFU) /*!< ST25R3911 SPI Operation Mode: FIFO Read */
#define ST25R3911_CMD_MODE (3U << 6) /*!< ST25R3911 SPI Operation Mode: Direct Command */
#define ST25R3911_CMD_LEN (1U) /*!< ST25R3911 CMD length */
#define ST25R3911_BUF_LEN (ST25R3911_CMD_LEN+ST25R3911_FIFO_DEPTH) /*!< ST25R3911 communication buffer: CMD + FIFO length */
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
#ifdef ST25R391X_COM_SINGLETXRX
static uint8_t comBuf[ST25R3911_BUF_LEN]; /*!< ST25R3911 communication buffer */
#endif /* ST25R391X_COM_SINGLETXRX */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static inline void st25r3911CheckFieldSetLED(uint8_t value)
{
if ((ST25R3911_REG_OP_CONTROL_tx_en & value) != 0U)
{
#ifdef PLATFORM_LED_FIELD_PIN
platformLedOn( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN );
}
else
{
platformLedOff( PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN );
#endif /* PLATFORM_LED_FIELD_PIN */
}
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void st25r3911ReadRegister(uint8_t reg, uint8_t* value)
{
#ifdef ST25R391X_COM_SINGLETXRX
uint8_t* buf = comBuf;
#else /* ST25R391X_COM_SINGLETXRX */
uint8_t buf[2];
#endif /* ST25R391X_COM_SINGLETXRX */
platformProtectST25R391xComm();
platformSpiSelect();
buf[0] = (reg | ST25R3911_READ_MODE);
buf[1] = 0;
platformSpiTxRx(buf, buf, 2);
if(value != NULL)
{
*value = buf[1];
}
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
void st25r3911ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length)
{
#if !defined(ST25R391X_COM_SINGLETXRX)
uint8_t cmd = (reg | ST25R3911_READ_MODE);
#endif /* !ST25R391X_COM_SINGLETXRX */
if (length > 0U)
{
platformProtectST25R391xComm();
platformSpiSelect();
#ifdef ST25R391X_COM_SINGLETXRX
ST_MEMSET( comBuf, 0x00, MIN( (ST25R3911_CMD_LEN + (uint32_t)length), ST25R3911_BUF_LEN ) );
comBuf[0] = (reg | ST25R3911_READ_MODE);
platformSpiTxRx(comBuf, comBuf, MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); /* Transceive as a single SPI call */
ST_MEMCPY( values, &comBuf[ST25R3911_CMD_LEN], MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); /* Copy from local buf to output buffer and skip cmd byte */
#else /* ST25R391X_COM_SINGLETXRX */
/* Since the result comes one byte later, let's first transmit the adddress with discarding the result */
platformSpiTxRx(&cmd, NULL, ST25R3911_CMD_LEN);
platformSpiTxRx(NULL, values, length);
#endif /* ST25R391X_COM_SINGLETXRX */
platformSpiDeselect();
platformUnprotectST25R391xComm();
}
return;
}
void st25r3911ReadTestRegister(uint8_t reg, uint8_t* value)
{
#ifdef ST25R391X_COM_SINGLETXRX
uint8_t* buf = comBuf;
#else /* ST25R391X_COM_SINGLETXRX */
uint8_t buf[3];
#endif /* ST25R391X_COM_SINGLETXRX */
platformProtectST25R391xComm();
platformSpiSelect();
buf[0] = ST25R3911_CMD_TEST_ACCESS;
buf[1] = (reg | ST25R3911_READ_MODE);
buf[2] = 0x00;
platformSpiTxRx(buf, buf, 3);
if(value != NULL)
{
*value = buf[2];
}
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
void st25r3911WriteTestRegister(uint8_t reg, uint8_t value)
{
#ifdef ST25R391X_COM_SINGLETXRX
uint8_t* buf = comBuf;
#else /* ST25R391X_COM_SINGLETXRX */
uint8_t buf[3];
#endif /* ST25R391X_COM_SINGLETXRX */
platformProtectST25R391xComm();
platformSpiSelect();
buf[0] = ST25R3911_CMD_TEST_ACCESS;
buf[1] = (reg | ST25R3911_WRITE_MODE);
buf[2] = value;
platformSpiTxRx(buf, NULL, 3);
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
void st25r3911WriteRegister(uint8_t reg, uint8_t value)
{
#ifdef ST25R391X_COM_SINGLETXRX
uint8_t* buf = comBuf;
#else /* ST25R391X_COM_SINGLETXRX */
uint8_t buf[2];
#endif /* ST25R391X_COM_SINGLETXRX */
if (ST25R3911_REG_OP_CONTROL == reg)
{
st25r3911CheckFieldSetLED(value);
}
platformProtectST25R391xComm();
platformSpiSelect();
buf[0] = reg | ST25R3911_WRITE_MODE;
buf[1] = value;
platformSpiTxRx(buf, NULL, 2);
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
void st25r3911ClrRegisterBits( uint8_t reg, uint8_t clr_mask )
{
uint8_t tmp;
st25r3911ReadRegister(reg, &tmp);
tmp &= ~clr_mask;
st25r3911WriteRegister(reg, tmp);
return;
}
void st25r3911SetRegisterBits( uint8_t reg, uint8_t set_mask )
{
uint8_t tmp;
st25r3911ReadRegister(reg, &tmp);
tmp |= set_mask;
st25r3911WriteRegister(reg, tmp);
return;
}
void st25r3911ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value)
{
st25r3911ModifyRegister(reg, valueMask, (valueMask & value) );
}
void st25r3911ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask)
{
uint8_t tmp;
st25r3911ReadRegister(reg, &tmp);
/* mask out the bits we don't want to change */
tmp &= ~clr_mask;
/* set the new value */
tmp |= set_mask;
st25r3911WriteRegister(reg, tmp);
return;
}
void st25r3911ChangeTestRegisterBits( uint8_t reg, uint8_t valueMask, uint8_t value )
{
uint8_t rdVal;
uint8_t wrVal;
/* Read current reg value */
st25r3911ReadTestRegister(reg, &rdVal);
/* Compute new value */
wrVal = (rdVal & ~valueMask);
wrVal |= (value & valueMask);
/* Write new reg value */
st25r3911WriteTestRegister(reg, wrVal );
return;
}
void st25r3911WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length)
{
#if !defined(ST25R391X_COM_SINGLETXRX)
uint8_t cmd = (reg | ST25R3911_WRITE_MODE);
#endif /* !ST25R391X_COM_SINGLETXRX */
if ((reg <= ST25R3911_REG_OP_CONTROL) && ((reg+length) >= ST25R3911_REG_OP_CONTROL))
{
st25r3911CheckFieldSetLED(values[ST25R3911_REG_OP_CONTROL-reg]);
}
if (length > 0U)
{
/* make this operation atomic */
platformProtectST25R391xComm();
platformSpiSelect();
#ifdef ST25R391X_COM_SINGLETXRX
comBuf[0] = (reg | ST25R3911_WRITE_MODE);
ST_MEMCPY( &comBuf[ST25R3911_CMD_LEN], values, MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) );
platformSpiTxRx( comBuf, NULL, MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) );
#else /*ST25R391X_COM_SINGLETXRX*/
platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN );
platformSpiTxRx( values, NULL, length );
#endif /*ST25R391X_COM_SINGLETXRX*/
platformSpiDeselect();
platformUnprotectST25R391xComm();
}
return;
}
void st25r3911WriteFifo(const uint8_t* values, uint8_t length)
{
#if !defined(ST25R391X_COM_SINGLETXRX)
uint8_t cmd = ST25R3911_FIFO_LOAD;
#endif /* !ST25R391X_COM_SINGLETXRX */
if (length > 0U)
{
platformProtectST25R391xComm();
platformSpiSelect();
#ifdef ST25R391X_COM_SINGLETXRX
comBuf[0] = ST25R3911_FIFO_LOAD;
ST_MEMCPY( &comBuf[ST25R3911_CMD_LEN], values, MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) );
platformSpiTxRx( comBuf, NULL, MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) );
#else /*ST25R391X_COM_SINGLETXRX*/
platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN );
platformSpiTxRx( values, NULL, length );
#endif /*ST25R391X_COM_SINGLETXRX*/
platformSpiDeselect();
platformUnprotectST25R391xComm();
}
return;
}
void st25r3911ReadFifo(uint8_t* buf, uint8_t length)
{
#if !defined(ST25R391X_COM_SINGLETXRX)
uint8_t cmd = ST25R3911_FIFO_READ;
#endif /* !ST25R391X_COM_SINGLETXRX */
if(length > 0U)
{
platformProtectST25R391xComm();
platformSpiSelect();
#ifdef ST25R391X_COM_SINGLETXRX
ST_MEMSET( comBuf, 0x00, MIN( (ST25R3911_CMD_LEN + (uint32_t)length), ST25R3911_BUF_LEN ) );
comBuf[0] = ST25R3911_FIFO_READ;
platformSpiTxRx( comBuf, comBuf, MIN( (ST25R3911_CMD_LEN + length), ST25R3911_BUF_LEN ) ); /* Transceive as a single SPI call */
ST_MEMCPY( buf, &comBuf[ST25R3911_CMD_LEN], MIN( length, ST25R3911_BUF_LEN - ST25R3911_CMD_LEN ) ); /* Copy from local buf to output buffer and skip cmd byte */
#else /*ST25R391X_COM_SINGLETXRX*/
platformSpiTxRx( &cmd, NULL, ST25R3911_CMD_LEN );
platformSpiTxRx( NULL, buf, length );
#endif /*ST25R391X_COM_SINGLETXRX*/
platformSpiDeselect();
platformUnprotectST25R391xComm();
}
return;
}
void st25r3911ExecuteCommand( uint8_t cmd )
{
uint8_t tmpCmd; /* MISRA 17.8 */
#ifdef PLATFORM_LED_FIELD_PIN
if ( (cmd >= ST25R3911_CMD_TRANSMIT_WITH_CRC) && (cmd <= ST25R3911_CMD_RESPONSE_RF_COLLISION_0))
{
platformLedOff(PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN);
}
#endif /* PLATFORM_LED_FIELD_PIN */
tmpCmd = (cmd | ST25R3911_CMD_MODE);
platformProtectST25R391xComm();
platformSpiSelect();
platformSpiTxRx( &tmpCmd, NULL, ST25R3911_CMD_LEN );
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
void st25r3911ExecuteCommands(const uint8_t *cmds, uint8_t length)
{
platformProtectST25R391xComm();
platformSpiSelect();
platformSpiTxRx( cmds, NULL, length );
platformSpiDeselect();
platformUnprotectST25R391xComm();
return;
}
bool st25r3911IsRegValid( uint8_t reg )
{
if( !(( (int16_t)reg >= (int16_t)ST25R3911_REG_IO_CONF1) && (reg <= ST25R3911_REG_CAPACITANCE_MEASURE_RESULT)) && (reg != ST25R3911_REG_IC_IDENTITY) )
{
return false;
}
return true;
}
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/