| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035 |
- /*
- * Adafruit PN532 library adapted to use in NRF51 and NRF52
- *
- * Software License Agreement (BSD License)
- *
- * Copyright (c) 2012, Adafruit Industries
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <stdio.h>
- #include <inttypes.h>
- #include <string.h>
- #include "adafruit_pn532.h"
- #include "adafruit_pn532_config.h"
- #include "nrf_gpio.h"
- #include "nrf_delay.h"
- #include "nrf_drv_twi.h"
- #include "app_error.h"
- #include "nordic_common.h"
- // NTAG2XX Page read/write restrictions.
- #define NTAG2XX_MAX_READ_PAGE_NUMBER 231
- #define NTAG2XX_MIN_WRITE_PAGE_NUMBER 4
- #define NTAG2XX_MAX_WRITE_PAGE_NUMBER 225
- // Lengths and offsets for specific commands and responses.
- #define COMMAND_GETFIRMWAREVERSION_LENGTH 1
- #define REPLY_GETFIRMWAREVERSION_LENGTH (5 + PN532_FRAME_OVERHEAD)
- #define COMMAND_SAMCONFIGURATION_LENGTH 4
- #define REPLY_SAMCONFIGURATION_LENGTH (1 + PN532_FRAME_OVERHEAD)
- #define COMMAND_POWERDOWN_BASE_LENGTH 2 // No GenerateIRQ parameter.
- #define REPLY_POWERDOWN_LENGTH (2 + PN532_FRAME_OVERHEAD)
- #define COMMAND_RFCONFIGURATION_MAXRETRIES_LENGTH 5
- #define COMMAND_RFCONFIGURATION_RFFIELD_LENGTH 3
- #define REPLY_RFCONFIGURATION_LENGTH (1 + PN532_FRAME_OVERHEAD)
- #define COMMAND_INLISTPASSIVETARGET_BASE_LENGTH 3
- #define REPLY_INLISTPASSIVETARGET_106A_TARGET_LENGTH (14 + PN532_FRAME_OVERHEAD)
- #define REPLY_INLISTPASSIVETARGET_106A_NBTG_OFFSET 7
- #define REPLY_INLISTPASSIVETARGET_106A_TG_OFFSET 8
- #define REPLY_INLISTPASSIVETARGET_106A_UID_LEN_OFFSET 12
- #define REPLY_INLISTPASSIVETARGET_106A_UID_OFFSET 13
- #define COMMAND_INDATAEXCHANGE_BASE_LENGTH 2
- #define REPLY_INDATAEXCHANGE_BASE_LENGTH (2 + PN532_FRAME_OVERHEAD)
- // Configuration parameters for SAMCONFIGURATION command.
- #define SAMCONFIGURATION_MODE_NORMAL 0x01
- #define SAMCONFIGURATION_MODE_VIRTUAL_CARD 0x02
- #define SAMCONFIGURATION_MODE_WIRED_CARD 0x03
- #define SAMCONFIGURATION_MODE_DUAL_CARD 0x04
- #define SAMCONFIGURATION_IRQ_ENABLED 0x01
- #define SAMCONFIGURATION_IRQ_DISABLED 0x00
- // Configuration parameters for POWERDOWN command.
- #define POWERDOWN_WAKEUP_IRQ 0x80
- #define POWERDOWN_WAKEUP_SPI 0x20
- // Configuration parameters for RFCONFIGURATION command.
- #define RFCONFIGURATION_CFGITEM_RFFIELD 0x01
- #define RFCONFIGURATION_CFGITEM_MAXRETRIES 0x05
- #define RFCONFIGURATION_RFFIELD_ON 0x01
- #define RFCONFIGURATION_RFFIELD_OFF 0x00
- // Error mask for the status mask in INDATAEXCHANGE frame.
- #define PN532_STATUS_ERROR_MASK 0x3F
- // Card specific parameters.
- #define MIFARE_MAX_DATA_EXCHANGE 16
- #define MIFARE_PAGE_SIZE 4
- // Size of the PN532 size packet.
- #define PN532_ACK_PACKET_SIZE 6
- // Default time-out for read_passive_target_id (time required for field scan).
- #define PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT 100
- // ACK frame format.
- static const uint8_t pn532_ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
- // Firmware version reply frame format (preamble to command byte).
- static const uint8_t pn532_rsp_firmware_ver[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
- static adafruit_pn532 pn532_object = {
- ._clk = 0,
- ._miso = 0,
- ._mosi = 0,
- ._ss = 0,
- ._irq = PN532_IRQ,
- ._reset = PN532_RESET,
- ._usingSPI = false,
- ._hardwareSPI = false
- };
- static const nrf_drv_twi_t m_twi_master = NRF_DRV_TWI_INSTANCE(MASTER_TWI_INST);
- static uint8_t pn532_packet_buf[PN532_PACKBUFFSIZ];
- static bool lib_initialized = false;
- /**
- * @brief Function to configure pins in host chip.
- *
- * This function configures specific pins to interact with the PN532 module.
- */
- static void adafruit_pn532_pin_setup(void)
- {
- nrf_gpio_cfg_input(pn532_object._irq, NRF_GPIO_PIN_NOPULL);
- // The reset pin in the AdaFruit NFC Shield is actually the PN532 reset indicator pin (RSTOUT_N)
- // and cannot be used to perform reset of the chip. (RSTPD_N pin, see AdaFruit NFC Shield
- // schematics).
- nrf_gpio_cfg_input(pn532_object._reset, NRF_GPIO_PIN_NOPULL);
- }
- /**
- * @brief Function to calculate the checksum byte.
- *
- * This function calculates the checksum byte, so that the sum of all verified bytes
- * and the checksum byte is equal to 0.
- *
- * @param current_sum[in] Sum of all bytes used to calculate checksum.
- *
- * @retval Value of the checksum byte.
- */
- static uint8_t adafruit_pn532_cs_complement_calc(uint8_t current_sum)
- {
- return ~current_sum + 1;
- }
- /**
- * @brief Function to check correctness of PN532 Normal information frame header.
- *
- * @param p_buffer[in] Pointer to the buffer containing frame header.
- * @param p_length[out] Pointer to the variable where the data length will be stored.
- *
- * @retval NRF_SUCCESS If the header was correct.
- * @retval NRF_ERROR_INVALID_DATA Otherwise.
- */
- static ret_code_t adafruit_pn532_header_check(uint8_t const * p_buffer, uint8_t * p_length)
- {
- // Preamble
- if ( (p_buffer[PN532_PREAMBLE_OFFSET] != PN532_PREAMBLE) ||
- (p_buffer[PN532_STARTCODE1_OFFSET] != PN532_STARTCODE1) ||
- (p_buffer[PN532_STARTCODE2_OFFSET] != PN532_STARTCODE2) )
- {
- PN532_LOG("Preamble missing\r\n");
- return NRF_ERROR_INVALID_DATA;
- }
- // Data length
- if (p_buffer[PN532_LENGTH_CS_OFFSET] !=
- adafruit_pn532_cs_complement_calc(p_buffer[PN532_LENGTH_OFFSET]))
- {
- PN532_LOG("Length check invalid: len: 0x%02x, cs: 02%02x\r\n",
- p_buffer[PN532_LENGTH_OFFSET], p_buffer[PN532_LENGTH_CS_OFFSET]);
- return NRF_ERROR_INVALID_DATA;
- }
- // Direction byte
- if ( (p_buffer[PN532_TFI_OFFSET] != PN532_PN532TOHOST) &&
- (p_buffer[PN532_TFI_OFFSET] != PN532_HOSTTOPN532) )
- {
- PN532_LOG("Invalid direction byte: %02x\r\n", p_buffer[PN532_TFI_OFFSET]);
- return NRF_ERROR_INVALID_DATA;
- }
-
- *p_length = p_buffer[PN532_LENGTH_OFFSET];
-
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_init(bool force)
- {
- uint32_t ver_data; // Variable to store firmware version read from PN532.
-
- if (lib_initialized && !(force))
- {
- PN532_LOG("Library is already initialized\r\n");
- return NRF_SUCCESS;
- }
- if (force)
- {
- PN532_LOG("Forcing library reinitialization\r\n");
- }
- if (pn532_object._usingSPI)
- {
- PN532_LOG("Communication over SPI is currently not supported!\r\n");
- return NRF_ERROR_INTERNAL;
- }
- ret_code_t err_code = adafruit_pn532_create_i2c();
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to create I2C, err_code = %d\r\n", err_code);
- return err_code;
- }
- adafruit_pn532_pin_setup();
- // Delay for PN532 to catch up with NRF.
- nrf_delay_ms(100);
- PN532_LOG("Looking for PN532\r\n");
- err_code = adafruit_pn532_get_firmware_version(&ver_data);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Didn't find PN53x board, err_code = %d\r\n", err_code);
- return err_code;
- }
- PN532_LOG("Found chip PN5%02x\r\n", (ver_data >> 24) & 0xFF);
- PN532_LOG("Firmware version %d.%d\r\n", (ver_data >> 16) & 0xFF,
- (ver_data >> 8) & 0xFF);
- err_code = adafruit_pn532_sam_config(SAMCONFIGURATION_MODE_NORMAL);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to configure SAM, err_code = %d\r\n", err_code);
- return err_code;
- }
- err_code = adafruit_pn532_set_passive_activation_retries(0xFF);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to set passive activation retries, err_code = %d\r\n", err_code);
- return err_code;
- }
- PN532_LOG("Waiting for an ISO14443A card\r\n");
- lib_initialized = true;
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_create_i2c()
- {
- PN532_LOG("Creating I2C\r\n");
- nrf_drv_twi_uninit(&m_twi_master);
- ret_code_t ret = nrf_drv_twi_init(&m_twi_master, NULL, NULL, NULL);
- if (ret != NRF_SUCCESS)
- {
- PN532_LOG("Failed to initialize TWI, err_code = %d\r\n", ret);
- return ret;
- }
- nrf_drv_twi_enable(&m_twi_master);
- return NRF_SUCCESS;
- }
- void print_hex(const uint8_t * p_data, const uint32_t len)
- {
- uint32_t i;
- for (i = 0; i < len; i++)
- {
- printf(" %02X", p_data[i]);
- }
- printf("\r\n");
- }
- void print_hex_char(const uint8_t * p_data, const uint32_t len)
- {
- uint32_t i;
- for (i = 0; i < len; i++)
- {
- printf(" %02X", p_data[i]);
- }
- printf(" ");
- for (i = 0; i < len; i++)
- {
- if ( (p_data[i] <= 0x1F) || (p_data[i] >= 0x7F) )
- {
- printf(" .");
- }
- else
- {
- printf(" %c", (char)p_data[i]);
- }
- }
- printf("\r\n");
- }
- ret_code_t adafruit_pn532_get_firmware_version(uint32_t * p_response)
- {
- PN532_LOG("Trying to get the firmware version\r\n");
- pn532_packet_buf[0] = PN532_COMMAND_GETFIRMWAREVERSION;
- ret_code_t err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- COMMAND_GETFIRMWAREVERSION_LENGTH,
- 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to send GetFirmwareVersion command, err_code = %d\r\n", err_code);
- return err_code;
- }
- // Read data packet.
- err_code = adafruit_pn532_read_data(pn532_packet_buf, REPLY_GETFIRMWAREVERSION_LENGTH);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to read data, err_code = %d\r\n", err_code);
- return err_code;
- }
- if (memcmp(pn532_packet_buf + 1, pn532_rsp_firmware_ver, sizeof(pn532_rsp_firmware_ver)))
- {
- PN532_LOG("Firmware frame doesn't match!\r\n");
- return NRF_ERROR_NOT_FOUND;
- }
- // Extract firmware version from the frame.
- int offset = PN532_DATA_OFFSET + 1;
- *p_response = pn532_packet_buf[offset++];
- *p_response <<= 8;
- *p_response |= pn532_packet_buf[offset++];
- *p_response <<= 8;
- *p_response |= pn532_packet_buf[offset++];
- *p_response <<= 8;
- *p_response |= pn532_packet_buf[offset++];
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_send_cmd(uint8_t * p_cmd, uint8_t cmd_len, uint16_t timeout)
- {
- PN532_LOG("Trying to send command\r\n");
- PN532_LOG_HEX(p_cmd, cmd_len);
- ret_code_t err_code = adafruit_pn532_write_command(p_cmd, cmd_len);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to write command, err_code = %d\r\n", err_code);
- return err_code;
- }
- // Wait for ACK
- if (!adafruit_pn532_waitready_ms(timeout))
- {
- PN532_LOG("Failed while waiting\r\n");
- return NRF_ERROR_INTERNAL;
- }
- return adafruit_pn532_read_ack();
- }
- ret_code_t adafruit_pn532_sam_config(uint8_t mode)
- {
- PN532_LOG("Attempting to configure SAM\r\n");
- ret_code_t err_code;
- if ( (mode != SAMCONFIGURATION_MODE_NORMAL)
- && (mode != SAMCONFIGURATION_MODE_VIRTUAL_CARD)
- && (mode != SAMCONFIGURATION_MODE_WIRED_CARD)
- && (mode != SAMCONFIGURATION_MODE_DUAL_CARD) )
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- pn532_packet_buf[0] = PN532_COMMAND_SAMCONFIGURATION;
- pn532_packet_buf[1] = mode;
- pn532_packet_buf[2] = 0x14; // Time-out value
- pn532_packet_buf[3] = SAMCONFIGURATION_IRQ_ENABLED;
- err_code = adafruit_pn532_send_cmd(pn532_packet_buf, COMMAND_SAMCONFIGURATION_LENGTH, 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while checking ACK! err_code = %d\r\n", err_code);
- return err_code;
- }
- err_code = adafruit_pn532_read_data(pn532_packet_buf, REPLY_SAMCONFIGURATION_LENGTH);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while reading data! err_code = %d\r\n", err_code);
- return err_code;
- }
- if (!(pn532_packet_buf[PN532_DATA_OFFSET] == PN532_COMMAND_SAMCONFIGURATION + 1))
- {
- PN532_LOG("Failed while checking SAMCONFIGURATION response, expected 0x%02x, got 0x%02x\r\n",
- PN532_COMMAND_SAMCONFIGURATION + 1, pn532_packet_buf[PN532_DATA_OFFSET]);
- return NRF_ERROR_NOT_FOUND;
- }
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_power_down(void)
- {
- PN532_LOG("Powering down the PN532\r\n");
- pn532_packet_buf[0] = PN532_COMMAND_POWERDOWN;
- pn532_packet_buf[1] = POWERDOWN_WAKEUP_IRQ;
- ret_code_t err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- COMMAND_POWERDOWN_BASE_LENGTH,
- 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while checking ACK! err_code = %d\r\n", err_code);
- return err_code;
- }
- err_code = adafruit_pn532_read_data(pn532_packet_buf, REPLY_POWERDOWN_LENGTH);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while reading data! err_code = %d\r\n", err_code);
- return err_code;
- }
- if (!(pn532_packet_buf[PN532_DATA_OFFSET] == PN532_COMMAND_POWERDOWN + 1))
- {
- PN532_LOG("Failed while checking POWERDOWN response, expected 0x%02x, got 0x%02x\r\n",
- PN532_COMMAND_POWERDOWN + 1, pn532_packet_buf[PN532_DATA_OFFSET]);
- return NRF_ERROR_NOT_FOUND;
- }
- // From PN532 user manual: "The PN532 needs approximately 1 ms to get into Power Down mode,
- // after the command response." (Rev. 02, p. 7.2.11, page 98)
- nrf_delay_ms(1);
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_wake_up(void)
- {
- ret_code_t err_code;
- if (pn532_object._usingSPI)
- {
- PN532_LOG("Communication over SPI is currently not supported!\r\n");
- return NRF_ERROR_INTERNAL;
- }
- // Wakeup procedure as specified in PN532 User Manual Rev. 02, p. 7.2.11, page 99.
- uint8_t dummy_byte = 0x55;
- err_code = nrf_drv_twi_tx(&m_twi_master, PN532_I2C_ADDRESS, &dummy_byte, 1, false);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while calling twi tx, err_code = %d\r\n", err_code);
- return err_code;
- }
- // Wait specified time to ensure that the PN532 shield is fully operational
- // (PN532 data sheet, Rev. 3.2, page 209).
- nrf_delay_ms(2);
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_set_passive_activation_retries(uint8_t max_retries)
- {
- ret_code_t err_code;
- pn532_packet_buf[0] = PN532_COMMAND_RFCONFIGURATION;
- pn532_packet_buf[1] = RFCONFIGURATION_CFGITEM_MAXRETRIES;
- pn532_packet_buf[2] = 0xFF; // MxRtyATR retries (default value)
- pn532_packet_buf[3] = 0x01; // MxRtyPSL retries (default value)
- pn532_packet_buf[4] = max_retries; // MxRtyPassiveActivation retries (user value)
- PN532_LOG("Setting MxRtyPassiveActivation to %i\r\n", max_retries);
- err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- COMMAND_RFCONFIGURATION_MAXRETRIES_LENGTH,
- 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while checking ACK! err_code = %d\r\n", err_code);
- return err_code;
- }
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_read_passive_target_id(uint8_t card_baudrate,
- uint8_t * p_uid,
- uint8_t * p_uid_len,
- uint16_t timeout)
- {
- PN532_LOG("Trying to read passive target ID\r\n");
- if (p_uid == NULL || p_uid_len == NULL)
- {
- PN532_LOG("NULL pointers passed as arguments to adafruit_pn532_read_passive_target_id.");
- return NRF_ERROR_INVALID_PARAM;
- }
-
- if (card_baudrate != PN532_MIFARE_ISO14443A_BAUD)
- {
- PN532_LOG("Only ISO14443 type A cards are supported.\r\n");
- return NRF_ERROR_INVALID_PARAM;
- }
- pn532_packet_buf[0] = PN532_COMMAND_INLISTPASSIVETARGET;
- pn532_packet_buf[1] = 1; // Maximum number of targets.
- pn532_packet_buf[2] = card_baudrate;
- ret_code_t err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- COMMAND_INLISTPASSIVETARGET_BASE_LENGTH,
- PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("No card(s) read, err_code = %d\r\n", err_code);
- return err_code;
- }
- PN532_LOG("Waiting for IRQ (indicates card presence)\r\n");
- // Give PN532 a little time to scan in case time-out is very small.
- if (timeout < PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT)
- {
- timeout = PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT;
- }
- if (!adafruit_pn532_waitready_ms(timeout))
- {
- PN532_LOG("IRQ time-out\r\n");
- return NRF_ERROR_INTERNAL;
- }
- err_code = adafruit_pn532_read_data(pn532_packet_buf,
- REPLY_INLISTPASSIVETARGET_106A_TARGET_LENGTH);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while reading data! err_code = %d\r\n", err_code);
- return err_code;
- }
- if (pn532_packet_buf[REPLY_INLISTPASSIVETARGET_106A_NBTG_OFFSET] != 1)
- {
- PN532_LOG("Failed while checking number of targets, expected 1, got %02x\r\n",
- pn532_packet_buf[REPLY_INLISTPASSIVETARGET_106A_NBTG_OFFSET]);
- return NRF_ERROR_INVALID_DATA;
- }
- if (*p_uid_len < pn532_packet_buf[REPLY_INLISTPASSIVETARGET_106A_UID_LEN_OFFSET])
- {
- PN532_LOG("Buffer length is invalid.\r\n");
- return NRF_ERROR_INVALID_LENGTH;
- }
- *p_uid_len = pn532_packet_buf[REPLY_INLISTPASSIVETARGET_106A_UID_LEN_OFFSET];
- pn532_object._inListedTag = pn532_packet_buf[REPLY_INLISTPASSIVETARGET_106A_TG_OFFSET];
- memcpy(p_uid, pn532_packet_buf + REPLY_INLISTPASSIVETARGET_106A_UID_OFFSET, *p_uid_len);
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_in_data_exchange(uint8_t * p_send,
- uint8_t send_len,
- uint8_t * p_response,
- uint8_t * p_response_len)
- {
- PN532_LOG("Trying in data exchange\r\n");
- if (send_len + 2 > PN532_PACKBUFFSIZ)
- {
- PN532_LOG("APDU length (%d) too long for packet buffer (%d)\r\n",
- send_len, PN532_PACKBUFFSIZ - 2);
- return NRF_ERROR_INTERNAL;
- }
- if (*p_response_len + REPLY_INDATAEXCHANGE_BASE_LENGTH > PN532_PACKBUFFSIZ)
- {
- PN532_LOG("Desired response length (%d) too long for packet buffer (%d)\r\n",
- *p_response_len, PN532_PACKBUFFSIZ);
- return NRF_ERROR_INTERNAL;
- }
- // Prepare command.
- pn532_packet_buf[0] = PN532_COMMAND_INDATAEXCHANGE;
- pn532_packet_buf[1] = pn532_object._inListedTag;
- memcpy(pn532_packet_buf + 2, p_send, send_len);
- ret_code_t err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- send_len + 2,
- 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Could not send ADPU, err_code = %d\r\n", err_code);
- return err_code;
- }
- if (!adafruit_pn532_waitready_ms(1000))
- {
- PN532_LOG("Response never received for ADPU\r\n");
- return NRF_ERROR_INTERNAL;
- }
- err_code = adafruit_pn532_read_data(pn532_packet_buf,
- *p_response_len + REPLY_INDATAEXCHANGE_BASE_LENGTH);
- // + 2 for command and status byte
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Could not read data, err_code = %d\r\n", err_code);
- return err_code;
- }
- uint8_t length = 0;
- err_code = adafruit_pn532_header_check(pn532_packet_buf, &length);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Invalid frame header\r\n");
- return err_code;
- }
-
- if ( (pn532_packet_buf[PN532_TFI_OFFSET] != PN532_PN532TOHOST) ||
- (pn532_packet_buf[PN532_DATA_OFFSET] != PN532_COMMAND_INDATAEXCHANGE + 1) )
- {
- PN532_LOG("Don't know how to handle this command: %02x\r\n",
- pn532_packet_buf[PN532_DATA_OFFSET]);
- return NRF_ERROR_INTERNAL;
- }
- // Check InDataExchange Status byte.
- if ((pn532_packet_buf[PN532_DATA_OFFSET + 1] & PN532_STATUS_ERROR_MASK) != 0x00)
- {
- PN532_LOG("Status code indicates an error, %02x\r\n",
- pn532_packet_buf[PN532_DATA_OFFSET + 1]);
- return NRF_ERROR_INTERNAL;
- }
- length -= 3; // Calculate the actual data length
- // Silently truncate response to fit into reply desired data size.
- if (length > *p_response_len)
- {
- length = *p_response_len;
- }
- memcpy(p_response, pn532_packet_buf + PN532_DATA_OFFSET + 2, length);
- *p_response_len = length;
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_ntag2xx_read_page(uint8_t page, uint8_t * p_buffer)
- {
- PN532_LOG("Trying to read page %u\r\n", page);
- ret_code_t err_code;
- uint8_t cmd_buf[2];
- uint8_t response_len = MIFARE_PAGE_SIZE;
- cmd_buf[0] = MIFARE_CMD_READ;
- cmd_buf[1] = page;
- err_code = adafruit_pn532_in_data_exchange(cmd_buf, 2, p_buffer, &response_len);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to read page %d\r\n", page);
- return err_code;
- }
- PN532_LOG("Page %d : ", page);
- PN532_LOG_HEX(p_buffer, MIFARE_PAGE_SIZE);
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_ntag2xx_write_page(uint8_t page, uint8_t * p_data)
- {
- if ( (page < NTAG2XX_MIN_WRITE_PAGE_NUMBER) ||
- (page > NTAG2XX_MAX_WRITE_PAGE_NUMBER) )
- {
- PN532_LOG("Page value out of range, page = %d\r\n", page);
- return NRF_ERROR_INVALID_PARAM;
- }
- PN532_LOG("Trying to write 4 uint8_t page %u\r\n", page);
- uint8_t write_buf[MIFARE_MAX_DATA_EXCHANGE];
- uint8_t response_len = MIFARE_MAX_DATA_EXCHANGE;
- write_buf[0] = MIFARE_ULTRALIGHT_CMD_WRITE;
- write_buf[1] = page;
- memcpy(write_buf + 2, p_data, MIFARE_PAGE_SIZE);
- ret_code_t err_code = adafruit_pn532_in_data_exchange(write_buf, 2 + MIFARE_PAGE_SIZE,
- write_buf, &response_len);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to write page %d\r\n", page);
- return err_code;
- }
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_ntag2xx_write_ndef_uri(uint8_t uri_id, char * p_url, uint8_t data_len)
- {
- PN532_LOG("Trying to write URI %d\r\n", uri_id);
- uint8_t page_buf[4] = {0};
- uint8_t uri_len = strlen(p_url);
- uint8_t page_header[] =
- {
- 0x00, 0x03, uri_len + 5, 0xD1,
- 0x01, uri_len + 1, 0x55, uri_id
- };
- uint8_t page_header_len = sizeof(page_header);
- if ( (uri_len < 1) || (uri_len + 1 > (data_len - page_header_len)))
- {
- PN532_LOG("URL is too long for provided data length\r\n");
- return NRF_ERROR_INVALID_PARAM;
- }
- ret_code_t err_code;
- int32_t i;
- uint8_t current_page = 4;
- for (i = 0; i < 2; i++)
- {
- memcpy(page_buf, page_header + 4*i, MIFARE_PAGE_SIZE);
- err_code = adafruit_pn532_ntag2xx_write_page(current_page, page_buf);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to write URI page %d, err_code = %d\r\n", current_page, err_code);
- return err_code;
- }
- current_page++;
- }
- char * url_ptr = p_url;
- uint8_t len_to_cpy = 0;
- while (uri_len > 0)
- {
- // Prepare length of the chunk to copy.
- if (uri_len < MIFARE_PAGE_SIZE)
- {
- len_to_cpy = uri_len;
- // If do not copy a full page, prepare the buffer.
- memset(page_buf, 0x00, MIFARE_PAGE_SIZE);
- page_buf[len_to_cpy] = 0xFE; // Terminator block.
- }
- else
- {
- len_to_cpy = MIFARE_PAGE_SIZE;
- }
- memcpy(page_buf, url_ptr, len_to_cpy);
- err_code = adafruit_pn532_ntag2xx_write_page(current_page, page_buf);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to write page %d, err_code = %d\r\n", current_page, err_code);
- return err_code;
- }
- current_page++;
- // If the last page was sent, and there was no chance to insert TLV Terminator block,
- // send another page with Terminator block in it.
- if (uri_len == MIFARE_PAGE_SIZE)
- {
- memset(page_buf, 0x00, MIFARE_PAGE_SIZE);
- page_buf[0] = 0xFE;
- err_code = adafruit_pn532_ntag2xx_write_page(current_page, page_buf);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed to write page %d, err_code = %d\r\n", current_page, err_code);
- return err_code;
- }
- current_page++;
- }
- uri_len -= len_to_cpy;
- url_ptr += len_to_cpy;
- }
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_read_ack(void)
- {
- PN532_LOG("Reading ACK\r\n");
- uint8_t ack_buf[PN532_ACK_PACKET_SIZE];
- ret_code_t err_code;
- err_code = adafruit_pn532_read_data(ack_buf, PN532_ACK_PACKET_SIZE);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("ACK read failed\r\n");
- return err_code;
- }
- // Wait for irq to be taken off.
- for (uint16_t i = 0; i < 1000; i++)
- {
- if (!adafruit_pn532_is_ready())
- {
- break;
- }
- }
- if (memcmp(ack_buf, pn532_ack, PN532_ACK_PACKET_SIZE) != 0)
- {
- PN532_LOG("Failed while comparing ACK packet\r\n");
- return NRF_ERROR_INTERNAL;
- }
- return NRF_SUCCESS;
- }
- bool adafruit_pn532_is_ready(void)
- {
- return nrf_gpio_pin_read(pn532_object._irq) == 0;
- }
- bool adafruit_pn532_waitready_ms(uint16_t timeout)
- {
- uint16_t timer = 0;
- bool result = false;
- result = adafruit_pn532_is_ready();
- while ((!result) && (timer < timeout))
- {
- timer += 1;
- nrf_delay_ms(1);
- result = adafruit_pn532_is_ready();
- }
- return result;
- }
- /// Buffer for low level communication.
- static uint8_t pn532_rxtx_buffer[PN532_PACKBUFFSIZ];
- ret_code_t adafruit_pn532_read_data(uint8_t * p_buff, uint8_t n)
- {
- if (!adafruit_pn532_waitready_ms(PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT))
- {
- return NRF_ERROR_INTERNAL;
- }
- if (pn532_object._usingSPI)
- {
- PN532_LOG("Communication over SPI is currently not supported!\r\n");
- return NRF_ERROR_INTERNAL;
- }
- if (n + 1 > PN532_PACKBUFFSIZ)
- {
- PN532_LOG("Rx buffer is too short!\r\n");
- return NRF_ERROR_INVALID_PARAM;
- }
- ret_code_t err_code;
- // In case of I2C, read the additional status byte.
- PN532_LOG("Reading: ");
- err_code = nrf_drv_twi_rx(&m_twi_master, PN532_I2C_ADDRESS, pn532_rxtx_buffer, n + 1);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while calling TWI rx, err_code = %d\r\n", err_code);
- return err_code;
- }
- memcpy(p_buff, pn532_rxtx_buffer + 1, n);
- PN532_LOG_HEX(p_buff, n);
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_write_command(uint8_t * p_cmd, uint8_t cmd_len)
- {
- ret_code_t err_code;
- uint8_t checksum;
- if (pn532_object._usingSPI)
- {
- PN532_LOG("Communication over SPI is currently not supported!\r\n");
- return NRF_ERROR_INTERNAL;
- }
- if (cmd_len + PN532_FRAME_OVERHEAD > PN532_PACKBUFFSIZ)
- {
- PN532_LOG("Tx buffer is too short!\r\n");
- return NRF_ERROR_INVALID_PARAM;
- }
- // Compose header part of the command frame.
- pn532_rxtx_buffer[0] = PN532_PREAMBLE;
- pn532_rxtx_buffer[1] = PN532_STARTCODE1;
- pn532_rxtx_buffer[2] = PN532_STARTCODE2;
- pn532_rxtx_buffer[3] = cmd_len + 1; // Data length + TFI byte.
- pn532_rxtx_buffer[4] = adafruit_pn532_cs_complement_calc(cmd_len + 1);
- pn532_rxtx_buffer[5] = PN532_HOSTTOPN532;
-
- // Copy the payload data.
- memcpy(pn532_rxtx_buffer + HEADER_SEQUENCE_LENGTH, p_cmd, cmd_len);
- // Calculate checksum.
- checksum = PN532_HOSTTOPN532;
- for (uint8_t i = 0; i < cmd_len; i++)
- {
- checksum += p_cmd[i];
- }
- checksum = adafruit_pn532_cs_complement_calc(checksum);
- // Compose checksum part of the command frame.
- pn532_rxtx_buffer[HEADER_SEQUENCE_LENGTH + cmd_len] = checksum;
- pn532_rxtx_buffer[HEADER_SEQUENCE_LENGTH + cmd_len + 1] = PN532_POSTAMBLE;
-
- PN532_LOG("Sending command\r\n");
- PN532_LOG_HEX(pn532_rxtx_buffer, cmd_len + PN532_FRAME_OVERHEAD);
-
- err_code = nrf_drv_twi_tx(&m_twi_master, PN532_I2C_ADDRESS, pn532_rxtx_buffer,
- cmd_len + PN532_FRAME_OVERHEAD, false);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while calling TWI tx 1, err_code = %d\r\n", err_code);
- return err_code;
- }
- return NRF_SUCCESS;
- }
- /** Function for enabling or disabling the PN532 RF field.
- *
- * This function sends a configuration command to the PN532, which enables or disables the RF field.
- *
- * @param field_conf A value indicating whether the RF field should be turned on or off.
- * Valid values are 1 (field on) and 0 (field off).
- *
- * @retval NRF_SUCCESS If the RF field was enabled successfully.
- * @retval NRF_ERROR_INVALID_PARAM If the value in field_conf was invalid.
- * @retval Other Otherwise.
- */
- static ret_code_t adafruit_pn532_switch_field(uint8_t field_conf)
- {
- ret_code_t err_code;
- if ( (field_conf != RFCONFIGURATION_RFFIELD_ON) && (field_conf != RFCONFIGURATION_RFFIELD_OFF) )
- {
- PN532_LOG("Invalid field configuration: 0x%02x\r\n", field_conf);
- return NRF_ERROR_INVALID_PARAM;
- }
- pn532_packet_buf[0] = PN532_COMMAND_RFCONFIGURATION;
- pn532_packet_buf[1] = RFCONFIGURATION_CFGITEM_RFFIELD;
- pn532_packet_buf[2] = field_conf;
- err_code = adafruit_pn532_send_cmd(pn532_packet_buf,
- COMMAND_RFCONFIGURATION_RFFIELD_LENGTH ,
- 1000);
- if (err_code != NRF_SUCCESS)
- {
- PN532_LOG("Failed while checking ACK! err_code = %d\r\n", err_code);
- return err_code;
- }
- if (!adafruit_pn532_waitready_ms(PN532_DEFAULT_WAIT_FOR_READY_TIMEOUT))
- {
- return NRF_ERROR_INTERNAL;
- }
- return NRF_SUCCESS;
- }
- ret_code_t adafruit_pn532_field_on(void)
- {
- return adafruit_pn532_switch_field(RFCONFIGURATION_RFFIELD_ON);
- }
- ret_code_t adafruit_pn532_field_off(void)
- {
- return adafruit_pn532_switch_field(RFCONFIGURATION_RFFIELD_OFF);
- }
|