350 lines
11 KiB
C
350 lines
11 KiB
C
/*
|
|
* Copyright 2016 NXP
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
*/
|
|
/***********************************************************************/
|
|
/* INCLUDES */
|
|
/***********************************************************************/
|
|
#include "HAL_timer_driver.h"
|
|
#include "ntag_driver_intern.h"
|
|
#include "HAL_I2C_driver.h"
|
|
/***********************************************************************/
|
|
/* DEFINES */
|
|
/***********************************************************************/
|
|
#undef NTAG_DEVICE_LIST_BEGIN
|
|
#undef NTAG_DEVICE_ENTRY
|
|
#undef NTAG_DEVICE_LIST_END
|
|
|
|
#define NTAG_DEVICE_LIST_BEGIN struct NTAG_DEVICE ntag_device_list[NTAG_ID_MAX_DEVICES] = {
|
|
#ifdef HAVE_NTAG_INTERRUPT
|
|
#define NTAG_DEVICE_ENTRY(label, i2c_address, isr) \
|
|
{ \
|
|
NTAG_CLOSED, HAL_I2C_INVALID_HANDLE, i2c_address, isr, {0}, \
|
|
{ \
|
|
0 \
|
|
} \
|
|
}
|
|
#else
|
|
#define NTAG_DEVICE_ENTRY(label, i2c_address, isr) \
|
|
{ \
|
|
NTAG_CLOSED, HAL_I2C_INVALID_HANDLE, i2c_address, {0}, \
|
|
{ \
|
|
0 \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
#define NTAG_DEVICE_LIST_END \
|
|
} \
|
|
;
|
|
|
|
/***********************************************************************/
|
|
/* GLOBAL VARIABLES */
|
|
/***********************************************************************/
|
|
/* second include of device list for generation of ntag_device_list array */
|
|
NTAG_DEVICE_LIST_BEGIN
|
|
#include "ntag_device_list.h"
|
|
NTAG_DEVICE_LIST_END
|
|
/***********************************************************************/
|
|
/* GLOBAL PUBLIC FUNCTIONS */
|
|
/***********************************************************************/
|
|
|
|
BOOL NTAG_WaitForFDPinState(NTAG_HANDLE_T ntag, NTAG_FD_STATE_T state, uint32_t timeout_ms)
|
|
{
|
|
switch (state)
|
|
{
|
|
case NTAG_FD_PIN_STATE_HI:
|
|
HAL_ISR_RegisterCallback(ntag->isr, ISR_LEVEL_HI, NULL, NULL);
|
|
return HAL_ISR_SleepWithTimeout(ntag->isr, timeout_ms);
|
|
case NTAG_FD_PIN_STATE_LO:
|
|
HAL_ISR_RegisterCallback(ntag->isr, ISR_LEVEL_LO, NULL, NULL);
|
|
return HAL_ISR_SleepWithTimeout(ntag->isr, timeout_ms);
|
|
default:
|
|
break;
|
|
}
|
|
return NTAG_ERROR_INVALID_PARAM;
|
|
}
|
|
|
|
NTAG_HANDLE_T NTAG_InitDevice(NTAG_ID_T ntag_id, HAL_I2C_HANDLE_T i2cbus)
|
|
{
|
|
if (ntag_id < NTAG_ID_MAX_DEVICES)
|
|
{
|
|
if (ntag_device_list[ntag_id].status == NTAG_CLOSED)
|
|
{
|
|
ntag_device_list[ntag_id].i2cbus = i2cbus;
|
|
ntag_device_list[ntag_id].status = NTAG_OK;
|
|
|
|
return &ntag_device_list[ntag_id];
|
|
}
|
|
}
|
|
return NTAG_INVALID_HANDLE;
|
|
}
|
|
|
|
void NTAG_CloseDevice(NTAG_HANDLE_T ntag)
|
|
{
|
|
if (ntag)
|
|
{
|
|
ntag->i2cbus = HAL_I2C_INVALID_HANDLE;
|
|
ntag->status = NTAG_CLOSED;
|
|
}
|
|
}
|
|
|
|
BOOL NTAG_ReadBytes(NTAG_HANDLE_T ntag, uint16_t address, uint8_t *bytes, uint16_t len)
|
|
{
|
|
uint16_t bytes_read = 0;
|
|
|
|
if (ntag->status == NTAG_CLOSED)
|
|
return TRUE;
|
|
|
|
ntag->status = NTAG_OK;
|
|
|
|
while (bytes_read < len)
|
|
{
|
|
uint8_t current_block = (address + bytes_read) / NTAG_I2C_BLOCK_SIZE;
|
|
uint8_t begin = (address + bytes_read) % NTAG_I2C_BLOCK_SIZE;
|
|
uint8_t current_len = MIN(len - bytes_read, NTAG_I2C_BLOCK_SIZE - begin);
|
|
|
|
if (current_len < NTAG_I2C_BLOCK_SIZE)
|
|
{
|
|
size_t i = 0;
|
|
|
|
/* read block into ntag->rx_buffer only */
|
|
if (NTAG_ReadBlock(ntag, current_block, NULL, 0))
|
|
break;
|
|
|
|
/* modify rx_buffer */
|
|
for (i = 0; i < current_len; i++)
|
|
if (sizeof(ntag->rx_buffer) > (RX_START + begin + i))
|
|
bytes[bytes_read + i] = ntag->rx_buffer[RX_START + begin + i];
|
|
}
|
|
else
|
|
{
|
|
/* full block read */
|
|
if (NTAG_ReadBlock(ntag, current_block, bytes + bytes_read, NTAG_I2C_BLOCK_SIZE))
|
|
break;
|
|
}
|
|
|
|
bytes_read += current_len;
|
|
}
|
|
return ntag->status;
|
|
}
|
|
|
|
BOOL NTAG_WriteBytes(NTAG_HANDLE_T ntag, uint16_t address, const uint8_t *bytes, uint16_t len)
|
|
{
|
|
uint16_t bytes_written = 0;
|
|
|
|
if (ntag->status == NTAG_CLOSED)
|
|
return TRUE;
|
|
|
|
ntag->status = NTAG_OK;
|
|
|
|
while (bytes_written < len)
|
|
{
|
|
uint8_t current_block = (address + bytes_written) / NTAG_I2C_BLOCK_SIZE;
|
|
uint8_t begin = (address + bytes_written) % NTAG_I2C_BLOCK_SIZE;
|
|
uint8_t current_len = MIN(len - bytes_written, NTAG_I2C_BLOCK_SIZE - begin);
|
|
|
|
if (current_len < NTAG_I2C_BLOCK_SIZE)
|
|
{
|
|
size_t i = 0;
|
|
|
|
/* read block into ntag->rx_buffer only */
|
|
if (NTAG_ReadBlock(ntag, current_block, NULL, 0))
|
|
break;
|
|
|
|
/* check if it is the first Block(0x00) and not the I2C Addr */
|
|
/* be careful with writing of first byte in management block */
|
|
/* the byte contains part of the serial number on read but */
|
|
/* on write the I2C address of the device can be modified */
|
|
if (0x00 == current_block && NTAG_MEM_ADRR_I2C_ADDRESS < begin)
|
|
ntag->rx_buffer[RX_START + 0] = ntag->address;
|
|
|
|
/* modify rx_buffer */
|
|
for (i = 0; i < current_len; i++)
|
|
if (sizeof(ntag->rx_buffer) > (RX_START + begin + i))
|
|
ntag->rx_buffer[RX_START + begin + i] = bytes[bytes_written + i];
|
|
|
|
/* writeback modified buffer */
|
|
if (NTAG_WriteBlock(ntag, current_block, ntag->rx_buffer + RX_START, NTAG_I2C_BLOCK_SIZE))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* full block write */
|
|
if (NTAG_WriteBlock(ntag, current_block, bytes + bytes_written, NTAG_I2C_BLOCK_SIZE))
|
|
break;
|
|
}
|
|
|
|
bytes_written += current_len;
|
|
}
|
|
|
|
return ntag->status;
|
|
}
|
|
|
|
BOOL NTAG_ReadRegister(NTAG_HANDLE_T ntag, uint8_t reg, uint8_t *val)
|
|
{
|
|
ntag->tx_buffer[TX_START + 0] = NTAG_MEM_BLOCK_SESSION_REGS;
|
|
ntag->tx_buffer[TX_START + 1] = reg;
|
|
|
|
/* send block number */
|
|
if (HAL_I2C_OK != HAL_I2C_SendBytes(ntag->i2cbus, ntag->address, ntag->tx_buffer, 2))
|
|
{
|
|
ntag->status = NTAG_ERROR_TX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
/* receive bytes */
|
|
if (HAL_I2C_OK != HAL_I2C_RecvBytes(ntag->i2cbus, ntag->address, ntag->rx_buffer, 1))
|
|
{
|
|
ntag->status = NTAG_ERROR_RX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
*val = ntag->rx_buffer[RX_START + 0];
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL NTAG_WriteRegister(NTAG_HANDLE_T ntag, uint8_t reg, uint8_t mask, uint8_t val)
|
|
{
|
|
ntag->tx_buffer[TX_START + 0] = NTAG_MEM_BLOCK_SESSION_REGS;
|
|
ntag->tx_buffer[TX_START + 1] = reg;
|
|
ntag->tx_buffer[TX_START + 2] = mask;
|
|
ntag->tx_buffer[TX_START + 3] = val;
|
|
|
|
if (HAL_I2C_OK != HAL_I2C_SendBytes(ntag->i2cbus, ntag->address, ntag->tx_buffer, 4))
|
|
{
|
|
ntag->status = NTAG_ERROR_TX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL NTAG_ReadConfiguration(NTAG_HANDLE_T ntag, uint8_t reg, uint8_t *val)
|
|
{
|
|
#ifdef NTAG_2k
|
|
uint8_t config = NTAG_MEM_BLOCK_CONFIGURATION_2k;
|
|
#elif NTAG_1k
|
|
uint8_t config = NTAG_MEM_BLOCK_CONFIGURATION_1k;
|
|
#endif
|
|
|
|
uint8_t I2C_Buf[NTAG_I2C_BLOCK_SIZE];
|
|
if (NTAG_ReadBlock(ntag, config, I2C_Buf, NTAG_I2C_BLOCK_SIZE))
|
|
return NTAG_ERR_COMMUNICATION;
|
|
|
|
*val = I2C_Buf[reg];
|
|
return NTAG_ERR_OK;
|
|
}
|
|
|
|
BOOL NTAG_WriteConfiguration(NTAG_HANDLE_T ntag, uint8_t reg, uint8_t mask, uint8_t val)
|
|
{
|
|
#ifdef NTAG_2k
|
|
uint8_t config = NTAG_MEM_BLOCK_CONFIGURATION_2k;
|
|
#elif NTAG_1k
|
|
uint8_t config = NTAG_MEM_BLOCK_CONFIGURATION_1k;
|
|
#endif
|
|
|
|
uint8_t I2C_Buf[NTAG_I2C_BLOCK_SIZE];
|
|
if (NTAG_ReadBlock(ntag, config, I2C_Buf, NTAG_I2C_BLOCK_SIZE))
|
|
return NTAG_ERR_COMMUNICATION;
|
|
|
|
// Clear all other bits of the val
|
|
val = val & mask;
|
|
|
|
// Clear specific bit in the Buffer
|
|
I2C_Buf[reg] = I2C_Buf[reg] & ~mask;
|
|
|
|
// write bits in the Buffer
|
|
I2C_Buf[reg] = I2C_Buf[reg] | val;
|
|
|
|
if (NTAG_WriteBlock(ntag, config, I2C_Buf, NTAG_I2C_BLOCK_SIZE))
|
|
return NTAG_ERR_COMMUNICATION;
|
|
|
|
return NTAG_ERR_OK;
|
|
}
|
|
|
|
NTAG_STATUS_T NTAG_GetLastError(NTAG_HANDLE_T ntag)
|
|
{
|
|
return ntag->status;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* GLOBAL PRIVATE FUNCTIONS */
|
|
/***********************************************************************/
|
|
BOOL NTAG_ReadBlock(NTAG_HANDLE_T ntag, uint8_t block, uint8_t *bytes, uint8_t len)
|
|
{
|
|
size_t i = 0;
|
|
|
|
ntag->tx_buffer[TX_START] = block;
|
|
|
|
/* send block number */
|
|
if (HAL_I2C_OK != HAL_I2C_SendBytes(ntag->i2cbus, ntag->address, ntag->tx_buffer, 1))
|
|
{
|
|
ntag->status = NTAG_ERROR_TX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
/* receive bytes */
|
|
if (HAL_I2C_OK != HAL_I2C_RecvBytes(ntag->i2cbus, ntag->address, ntag->rx_buffer, NTAG_I2C_BLOCK_SIZE))
|
|
{
|
|
ntag->status = NTAG_ERROR_RX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
len = MIN(len, NTAG_I2C_BLOCK_SIZE);
|
|
|
|
/* write to bytes buffer */
|
|
for (i = 0; i < len; i++)
|
|
bytes[i] = ntag->rx_buffer[RX_START + i];
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL NTAG_WriteBlock(NTAG_HANDLE_T ntag, uint8_t block, const uint8_t *bytes, uint8_t len)
|
|
{
|
|
uint8_t ns_reg = 0;
|
|
uint32_t timeout = NTAG_MAX_WRITE_DELAY_MS / 5 + 1;
|
|
size_t i = 0;
|
|
|
|
ntag->tx_buffer[TX_START] = block;
|
|
|
|
len = MIN(len, NTAG_I2C_BLOCK_SIZE);
|
|
|
|
/* copy len bytes */
|
|
for (i = 0; i < len; i++)
|
|
ntag->tx_buffer[TX_START + i + 1] = bytes[i];
|
|
|
|
/* zero rest of the buffer */
|
|
for (i = len; i < NTAG_I2C_BLOCK_SIZE; i++)
|
|
ntag->tx_buffer[TX_START + i + 1] = 0;
|
|
|
|
/* send block number */
|
|
if (HAL_I2C_OK != HAL_I2C_SendBytes(ntag->i2cbus, ntag->address, ntag->tx_buffer, NTAG_I2C_BLOCK_SIZE + 1))
|
|
{
|
|
ntag->status = NTAG_ERROR_TX_FAILED;
|
|
return TRUE;
|
|
}
|
|
|
|
/* do not wait for completion when writing SRAM */
|
|
if (block >= NTAG_MEM_BLOCK_START_SRAM && block < NTAG_MEM_BLOCK_START_SRAM + NTAG_MEM_SRAM_BLOCKS)
|
|
return ntag->status;
|
|
|
|
/* wait for completion */
|
|
do
|
|
{
|
|
HAL_Timer_delay_ms(5);
|
|
if (NTAG_ReadRegister(ntag, NTAG_MEM_OFFSET_NS_REG, &ns_reg))
|
|
break;
|
|
timeout--;
|
|
} while (timeout && ns_reg & NTAG_NS_REG_MASK_EEPROM_WR_BUSY);
|
|
|
|
if (0 == timeout)
|
|
ntag->status = NTAG_ERROR_WRITE_TIMEOUT;
|
|
|
|
return ntag->status;
|
|
}
|