MCUXpresso_LPC55S69/middleware/ntag_i2c_plus/HAL_NTAG/ntag_driver.c
2022-04-08 22:42:47 +08:00

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;
}