NUC200LE3AN_Card/lib/pn512/src/pn512.c

113 lines
3.2 KiB
C

#include "pn512.h"
/**
* About register bits
* Higher 8 bits is page number, e.g. 0x8100 -> Page 1 addr 0
* Bit 15 is always 1 since we use page select.
*/
#define PN512_REG_COMMAND 0x8001U
#define PN512_REG_PAGE_SELECT 0x8000U
#define PN512_REG_VERSION 0x8337U
/**
* Command List
*/
#define PN512_CMD_SOFT_RESET 0x0F
#define PN512_REG_PAGE(x) ((uint8_t)(x >> 0x08U))
#define PN512_REG_ADDR(x) ((uint8_t)(x & 0xFFU))
/**
* @brief Switch register page to the same page as
* specified by `reg`.
*
* @param nfc: pointer to pn512_t struct
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
*/
static pn512_ret_t pn512_switch_register_page(pn512_t *nfc, uint16_t reg) {
pn512_ret_t ret = PN512_OK;
if (PN512_REG_PAGE(reg) != nfc->info.current_page) {
/* Select page */
uint8_t payload = PN512_REG_PAGE(reg);
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U);
if (ret != PN512_OK) return ret;
nfc->info.current_page = PN512_REG_PAGE(reg);
}
return ret;
}
/**
* @brief Read a register, except FIFO register.
*
* @param nfc: pointer to pn512_t struct
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
* @param value: [OUT] value to be read
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
*/
static pn512_ret_t pn512_read_register(pn512_t *nfc, uint16_t reg, uint8_t *value) {
pn512_ret_t ret = PN512_OK;
ret = pn512_switch_register_page(nfc, reg);
if (ret != PN512_OK) return ret;
/* Issue read operation */
ret = nfc->ops.read(nfc->ops_handle, PN512_REG_ADDR(reg), value, 1U);
return ret;
}
/**
* @brief Write a register, except FIFO register.
*
* @param nfc: pointer to pn512_t struct
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
* @param value: value to be written
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
*/
static pn512_ret_t pn512_write_register(pn512_t *nfc, uint16_t reg, uint8_t value) {
pn512_ret_t ret = PN512_OK;
ret = pn512_switch_register_page(nfc, reg);
if (ret != PN512_OK) return ret;
/* Issue read operation */
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(reg), &value, 1U);
return ret;
}
/**
* @brief Soft reset PN512 by sending an SoftReset command.
*
* @param nfc: pointer to pn512_t struct
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
*/
static pn512_ret_t pn512_soft_reset(pn512_t *nfc) {
return pn512_write_register(nfc, PN512_REG_COMMAND, PN512_CMD_SOFT_RESET);
}
pn512_ret_t pn512_init(pn512_t *nfc) {
pn512_ret_t ret = PN512_OK;
/* Reset chip */
ret = nfc->ops.reset(nfc->ops_handle);
if (ret != PN512_OK) return ret;
/* Set current page to 0 */
uint8_t payload = 0x80;
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U);
if (ret != PN512_OK) return ret;
nfc->info.current_page = 0; /* Synchronize status */
ret = pn512_soft_reset(nfc);
if (ret != PN512_OK) return ret;
// Read chip version.
ret = pn512_read_register(nfc, PN512_REG_VERSION, &nfc->info.version);
return ret;
}