Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -0,0 +1,356 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details PN512 implementation of the transceiver interface
*/
#define __DEBUG__ 4
#ifndef __MODULE__
#define __MODULE__ "pn512.c"
#endif
#include "stack/nfc_errors.h"
#include "stdlib.h"
#include "acore/ac_buffer.h"
#include "transceiver/transceiver.h"
#include "transceiver/protocols.h"
#include "pn512_rf.h"
#include "pn512_registers.h"
#include "pn512_cmd.h"
#include "pn512_hw.h"
#include "pn512_irq.h"
#include "pn512_poll.h"
#include "pn512_transceive.h"
#include "pn512_internal.h"
#include "pn512.h"
#define DEFAULT_READER_TRANSCEIVE_TIMEOUT 100
#define DEFAULT_TARGET_TRANSCEIVE_TIMEOUT -1
//Prototypes
#include "pn512_internal.h"
/** \addtogroup PN512
* @{
* \name Transceiver
* \details Implementation of the transceiver interface
* @{
*/
//PN 512 VTABLE
static const transceiver_impl_t pn512_impl = {
.set_protocols = pn512_set_protocols,
.poll = pn512_poll,
.transceive = pn512_transceive,
.abort = pn512_abort,
.set_crc = pn512_set_crc,
.set_timeout = pn512_set_timeout,
.set_transceive_options = pn512_set_transceive_options,
.set_transceive_framing = pn512_set_transceive_framing,
.set_write = pn512_set_write,
.get_read = pn512_get_read,
.set_last_byte_length = pn512_set_last_byte_length,
.get_last_byte_length = pn512_get_last_byte_length,
.set_first_byte_align = pn512_set_first_byte_align,
.close = pn512_close,
.sleep = pn512_sleep
};
/** Initialize PN512 transceiver
* \param pPN512 pointer to pn512_t structure to initialize
* \param pTransport pointer to already initialized nfc_transport_t structure
* \return NFC_OK (0) on success or NFC_ERR_* error on failure
*/
nfc_err_t pn512_init(pn512_t *pPN512, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer)
{
////
//For Self-test
////
#if NFC_PN512_SELFTEST
const uint8_t null_array[25] = {0};
#endif
////
uint8_t r;
//Init transceiver
transceiver_init((nfc_transceiver_t *)pPN512, pTransport, pTimer);
//Init buffer
ac_buffer_builder_init(&pPN512->readBufBldr, pPN512->payload, 256);
pPN512->readFirstByteAlign = 0;
pPN512->readLastByteLength = 8;
pPN512->writeLastByteLength = 8;
//Populate functions
pPN512->transceiver.fn = &pn512_impl;
//Init variables
memset(&pPN512->config.initiators, 0, sizeof(nfc_tech_t));
memset(&pPN512->config.targets, 0, sizeof(nfc_tech_t));
pPN512->timeout = -1;
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
pn512_hw_init(pPN512);
pn512_registers_init(pPN512); //Cannot switch page now
pn512_cmd_init(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_SOFTRST);
pn512_cmd_wait_idle(pPN512, -1);
//pn512_registers_init(pPN512);
//Put into known state
pn512_registers_reset(pPN512);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_fifo_clear(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_cmd_wait_idle(pPN512, -1);
pn512_rf_field_switch_off(pPN512);
//Required for polling loop
srand(4242);
#if NFC_PN512_SELFTEST // Self test
pn512_cmd_exec(pPN512, PN512_CMD_SOFTRST);
pn512_cmd_wait_idle(pPN512, -1);
const uint8_t null_array_buf[25] = {0}; //FIXME
ac_buffer_t null_array;
ac_buffer_init(&null_array, null_array_buf, 25);
//Perform self test
pn512_fifo_write(pPN512, &null_array);
pn512_cmd_exec(pPN512, PN512_CMD_CONFIG);
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE);
pn512_register_write(pPN512, PN512_REG_AUTOTEST, 0x09);
ac_buffer_init(&null_array, null_array_buf, 1);
pn512_fifo_write(pPN512, &null_array);
pn512_cmd_exec(pPN512, PN512_CMD_CRC);
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE);
DBGX_ENTER();
NFC_DBG("Test result:");
while (pn512_fifo_length(pPN512)) {
ac_buffer_builder_t read_byte;
ac_buffer_builder_init(&read_byte, null_array_buf, 1);
pn512_fifo_read(pPN512, &read_byte);
DBGX("%02x ", null_array_buf[0]);
}
DBGX("\n");
DBGX_LEAVE();
#endif
r = pn512_register_read(pPN512, PN512_REG_VERSION);
NFC_DBG_BLOCK(
NFC_DBG("PN512 version %02x", r);
)
if ((r != 0x82) && (r != 0xB1) && (r != 0xB2)) {
return NFC_ERR_UNSUPPORTED; //PN512 not found
}
return NFC_OK;
}
/** Get pointer to nfc_transceiver_t structure
* \param pPN512 pointer to pn512_t instance
* \return pointer to initialized nfc_transceiver_t instance
*/
nfc_transceiver_t *pn512_get_transceiver(pn512_t *pPN512)
{
return &pPN512->transceiver;
}
void pn512_set_protocols(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
//If different, reconfigure
if (memcmp(&initiators, &pPN512->config.initiators, sizeof(nfc_tech_t)) || memcmp(&targets, &pPN512->config.targets, sizeof(nfc_tech_t))) {
pPN512->config.initiators = initiators;
if (memcmp(&targets, &pPN512->config.targets, sizeof(nfc_tech_t))) {
pPN512->config.targets = targets;
pn512_poll_setup(pPN512);
}
pTransceiver->initiator_ntarget = false;
memset(&pTransceiver->active_tech, 0, sizeof(nfc_tech_t));
}
pPN512->config.options = options;
}
void pn512_poll(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
pn512_poll_hw(pPN512, pn512_transceiver_callback);
}
void pn512_set_crc(nfc_transceiver_t *pTransceiver, bool crc_out, bool crc_in)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_framing_crc_set(pPN512, crc_out, crc_in);
}
void pn512_set_timeout(nfc_transceiver_t *pTransceiver, int timeout)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pPN512->timeout = timeout;
}
void pn512_set_transceive_options(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (transmit && receive) {
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
} else if (transmit && repoll) {
pPN512->nextFrameMode = pn512_transceive_mode_transmit_and_target_autocoll;
} else if (transmit) {
pPN512->nextFrameMode = pn512_transceive_mode_transmit;
} else if (receive) {
pPN512->nextFrameMode = pn512_transceive_mode_receive;
} else {
pPN512->nextFrameMode = pn512_transceive_mode_target_autocoll;
}
}
void pn512_set_transceive_framing(nfc_transceiver_t *pTransceiver, nfc_framing_t framing)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_framing_set(pPN512, framing);
//Switch NFC tech if NFC DEP
if (pTransceiver->active_tech.nfc_nfc_dep_a
|| pTransceiver->active_tech.nfc_nfc_dep_f_212
|| pTransceiver->active_tech.nfc_nfc_dep_f_424) {
//FIXME
pTransceiver->active_tech.nfc_nfc_dep_a = 0;
pTransceiver->active_tech.nfc_nfc_dep_f_212 = 0;
pTransceiver->active_tech.nfc_nfc_dep_f_424 = 0;
switch (framing) {
case nfc_framing_target_a_106:
case nfc_framing_initiator_a_106:
pTransceiver->active_tech.nfc_nfc_dep_a = 1;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
pTransceiver->active_tech.nfc_nfc_dep_f_212 = 1;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
pTransceiver->active_tech.nfc_nfc_dep_f_424 = 1;
break;
default:
break;
}
}
}
void pn512_set_write(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (pWriteBuf == NULL) {
ac_buffer_init(&pPN512->writeBuf, NULL, 0);
return;
}
ac_buffer_dup(&pPN512->writeBuf, pWriteBuf);
}
ac_buffer_t *pn512_get_read(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
return ac_buffer_builder_buffer(&pPN512->readBufBldr);
}
void pn512_set_last_byte_length(nfc_transceiver_t *pTransceiver, size_t lastByteLength)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if ((lastByteLength > 8) || (lastByteLength == 0)) {
lastByteLength = 8;
}
pPN512->writeLastByteLength = lastByteLength;
}
void pn512_set_first_byte_align(nfc_transceiver_t *pTransceiver, size_t firstByteAlign)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
firstByteAlign &= 0x7;
pPN512->readFirstByteAlign = firstByteAlign;
}
size_t pn512_get_last_byte_length(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
return pPN512->readLastByteLength;
}
void pn512_transceive(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
pn512_transceive_hw(pPN512, pPN512->nextFrameMode, pn512_transceiver_callback);
pPN512->nextFrameMode = pn512_transceive_mode_transceive;
}
void pn512_abort(nfc_transceiver_t *pTransceiver)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
nfc_scheduler_dequeue_task(&pTransceiver->scheduler, true, &pPN512->transceiver.task);
}
void pn512_close(nfc_transceiver_t *pTransceiver)
{
//pn512_t* pPN512 = (pn512_t*) pTransceiver;
(void) pTransceiver;
//TODO
return;
}
void pn512_sleep(nfc_transceiver_t *pTransceiver, bool sleep)
{
pn512_t *pPN512 = (pn512_t *) pTransceiver;
if (sleep) {
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x30); //Receiver off + soft power down
} else {
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x00);
while (pn512_register_read(pPN512, PN512_REG_COMMAND) & 0x10);
}
}
void pn512_transceiver_callback(pn512_t *pPN512, nfc_err_t ret)
{
transceiver_callback(&pPN512->transceiver, ret);
}
/**
* @}
* @}
* */

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_H_
#define PN512_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "transceiver/transceiver.h"
#include "pn512_types.h"
#include "pn512_callback.h"
typedef enum __pn512_state {
pn512_state_ready,
pn512_state_target_autocoll,
pn512_state_initiator_transceive_first_frame,
pn512_state_transceive,
pn512_state_transceive_last_frame,
} pn512_state_t;
typedef enum __pn512_transceive_mode {
pn512_transceive_mode_idle,
pn512_transceive_mode_target_autocoll,
pn512_transceive_mode_transmit,
pn512_transceive_mode_transmit_and_target_autocoll,
pn512_transceive_mode_transceive,
pn512_transceive_mode_receive,
} pn512_transceive_mode_t;
struct __pn512 {
nfc_transceiver_t transceiver;
//Impl specific
pn512_registers_t registers;
bool rf_on;
struct {
bool out;
bool in;
} crc;
int timeout;
struct {
nfc_tech_t initiators;
nfc_tech_t targets;
polling_options_t options;
} config;
//Transceive options
pn512_transceive_mode_t nextFrameMode;
nfc_framing_t framing;
uint16_t irqsEn;
uint8_t payload[256]; //Incoming buffer
ac_buffer_builder_t readBufBldr;
ac_buffer_t writeBuf;
uint8_t readFirstByteAlign;
uint8_t readLastByteLength;
uint8_t writeLastByteLength;
//Task parameters
struct {
//Polling
struct {
enum {
pn512_polling_state_start_listening,
pn512_polling_state_listen_wait_for_remote_field,
pn512_polling_state_listen_anticollision,
pn512_polling_state_listen_no_target_found,
pn512_polling_state_start_polling,
pn512_polling_state_rf_collision_avoidance, // TID + n × TRFW, n is random, TID>4096/(13.56E6) ~ 302.06us, TRFW=51/(13.56E6) ~ 37.76us
pn512_polling_state_polling_nfc_a_start,
pn512_polling_state_polling_nfc_a_gt, // guard time nfc a >= 5.0 ms
pn512_polling_state_polling_nfc_a_anticollision, // polling for nfc a
pn512_polling_state_polling_nfc_b_start,
pn512_polling_state_polling_nfc_b_gt, // guard time nfc b >= 5.0 ms
pn512_polling_state_polling_nfc_b_anticollision, // polling for nfc b
pn512_polling_state_polling_nfc_f_start,
pn512_polling_state_polling_nfc_f_gt, // guard time nfc f >= 20 ms
pn512_polling_state_polling_nfc_f_anticollision, // polling for nfc f
pn512_polling_state_finish_polling,
} state;
pn512_cb_t cb;
} poll;
struct {
pn512_cb_t cb;
pn512_transceive_mode_t mode;
} transceive;
struct {
pn512_cb_t cb;
} rf;
struct {
union {
// ISO A
struct {
bool more_targets; // Collision detected
uint8_t cascade_level;
uint8_t cln[5];
uint8_t valid_bits; // valid bits within cascade level
} iso_a;
// ISO B
struct {
bool more_targets; // Collision detected
uint8_t slots_num_exponent;
uint8_t slot_number;
bool found_one;
} iso_b;
};
pn512_cb_t cb;
} anticollision;
};
};
nfc_err_t pn512_init(pn512_t *pPN512, nfc_transport_t *pTransport, nfc_scheduler_timer_t *pTimer);
nfc_transceiver_t *pn512_get_transceiver(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_H_ */

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_callback.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef PN512_CALLBACK_H_
#define PN512_CALLBACK_H_
#include "stack/nfc_common.h"
#include "pn512_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*pn512_cb_t)(pn512_t *pPN512, nfc_err_t ret);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CALLBACK_H_ */

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_cmd.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Format and execute PN512 commands
* \internal
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_cmd.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_cmd.h"
#define PN512_FIFO_SIZE 64
#include "pn512.h"
#include "pn512_registers.h"
#include "pn512_irq.h"
#include "pn512_hw.h"
/** \addtogroup PN512
* \internal
* @{
* \name Commands
* @{
*/
/** \internal Initialize underlying pn512_cmd_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_cmd_init(pn512_t *pPN512)
{
(void) pPN512;
}
//Fifo read / write
/** \internal Write bytes to FIFO
* \param pPN512 pointer to pn512_t structure
* \param pData buffer to write
*/
void pn512_fifo_write(pn512_t *pPN512, ac_buffer_t *pData)
{
uint8_t fifo_space = pn512_fifo_space(pPN512); //Do not call this fn twice
size_t len = ac_buffer_reader_readable(pData);
len = MIN(fifo_space, len);
pn512_register_switch_page(pPN512, PN512_REG_FIFODATA);
pn512_hw_write_buffer(pPN512, PN512_REG_FIFODATA, pData, len);
}
/** \internal Read bytes from FIFO
* \param pPN512 pointer to pn512_t structure
* \param pData buffer in which to read
*/
void pn512_fifo_read(pn512_t *pPN512, ac_buffer_builder_t *pData)
{
uint8_t fifo_len = pn512_fifo_length(pPN512); //Do not call this fn twice
size_t len = ac_buffer_builder_writable(pData);
len = MIN(fifo_len, len);
pn512_register_switch_page(pPN512, PN512_REG_FIFODATA);
pn512_hw_read_buffer(pPN512, PN512_REG_FIFODATA, pData, len);
}
/** \internal Clear FIFO
* Removes any bytes left in FIFO
* \param pPN512 pointer to pn512_t structure
*/
void pn512_fifo_clear(pn512_t *pPN512)
{
pn512_register_write(pPN512, PN512_REG_FIFOLEVEL, 0x80); //Flush FIFO
}
/** \internal Get space in FIFO
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be written to FIFO
*/
size_t pn512_fifo_space(pn512_t *pPN512)
{
return PN512_FIFO_SIZE - pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Get FIFO length
* \param pPN512 pointer to pn512_t structure
* \return number of bytes that can be read from FIFO
*/
size_t pn512_fifo_length(pn512_t *pPN512)
{
return pn512_register_read(pPN512, PN512_REG_FIFOLEVEL);
}
/** \internal Execute command
* \param pPN512 pointer to pn512_t structure
* \param cmd PN512 command to execute
*/
void pn512_cmd_exec(pn512_t *pPN512, uint8_t cmd)
{
pn512_register_write(pPN512, PN512_REG_COMMAND, cmd);
}
/** \internal Wait for command completion
* \param pPN512 pointer to pn512_t structure
* \param timeout timeout in milliseconds or -1 for blocking mode
* \return NFC_OK on success or NFC_ERR_TIMEOUT on timeout
*/
nfc_err_t pn512_cmd_wait_idle(pn512_t *pPN512, int timeout)
{
(void) timeout;
while (pn512_cmd_get(pPN512) != PN512_CMD_IDLE) {
}
return NFC_OK;
}
/** \internal Read executed command
* \param pPN512 pointer to pn512_t structure
* \return PN512 command being executed
*/
uint8_t pn512_cmd_get(pn512_t *pPN512)
{
return pn512_register_read(pPN512, PN512_REG_COMMAND) & PN512_CMD_REG_MASK;
}
/**
* @}
* @}
* */

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_cmd.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_CMD_H_
#define PN512_CMD_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
#define PN512_CMD_IDLE 0x00 //No action, cancels current command execution
#define PN512_CMD_MEM 0x01 //Stores 25 bytes into the internal buffer
#define PN512_CMD_CONFIG 0x01 //Configures the PN512 for FeliCa, MIFARE and NFCIP-1 communication
#define PN512_CMD_RNDIDG 0x02 //Generates a 10-byte random ID number
#define PN512_CMD_CRC 0x03 //Activates the CRC coprocessor or performs a self test
#define PN512_CMD_TRANSMIT 0x04 //Transmits data from the FIFO buffer
#define PN512_CMD_NOCHANGE 0x07 //No command change
#define PN512_CMD_RECEIVE 0x08 //Activates the receiver circuits
#define PN512_CMD_TRANSCEIVE 0x0C //Transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
#define PN512_CMD_AUTOCOLL 0x0D //Handles FeliCa polling (Card Operation mode only) and MIFARE anticollision (Card Operation mode only)
#define PN512_CMD_MFAUTH 0x0E //Performs the MIFARE standard authentication as a reader
#define PN512_CMD_SOFTRST 0x0F //Resets the PN512
#define PN512_CMD_REG_MASK 0x0F
void pn512_cmd_init(pn512_t *pPN512);
//Fifo read / write
void pn512_fifo_write(pn512_t *pPN512, ac_buffer_t *pData);
void pn512_fifo_read(pn512_t *pPN512, ac_buffer_builder_t *pData);
//Fifo clear
void pn512_fifo_clear(pn512_t *pPN512);
//Fifo bytes read
size_t pn512_fifo_space(pn512_t *pPN512);
size_t pn512_fifo_length(pn512_t *pPN512);
//Execute command
void pn512_cmd_exec(pn512_t *pPN512, uint8_t cmd);
//Wait for command completion
nfc_err_t pn512_cmd_wait_idle(pn512_t *pPN512, int timeout);
//Read executed command
uint8_t pn512_cmd_get(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_CMD_H_ */

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_hw.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Format and execute PN512 frames
*/
#include "stack/nfc_errors.h"
#include "pn512_hw.h"
//Platform specific
#include "platform/nfc_transport.h"
/** \addtogroup PN512
* \internal
* @{
* \name Hardware
* @{
*/
/** \internal Initialize underlying pn512_hw_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_hw_init(pn512_t *pPN512)
{
//Nothing to init in this implementation
(void) pPN512;
}
/**
* @}
* @}
* */

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_hw.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_HW_H_
#define PN512_HW_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
//Utility for transport: SPI address read/write
#define PN512_SPI_ADDR_R(x) ((1<<7) | ((x) << 1))
#define PN512_SPI_ADDR_W(x) ((0<<7) | ((x) << 1))
void pn512_hw_init(pn512_t *pPN512);
/** \internal Write bytes at the specified address on the underlying transport link
* \param pPN512 pointer to pn512_t structure
* \param addr address at which to write
* \param buf buffer to write
* \param len length of buffer
*/
static inline void pn512_hw_write(pn512_t *pPN512, uint8_t addr, uint8_t *buf, size_t len)
{
nfc_transport_write(((nfc_transceiver_t *)pPN512)->pTransport, addr, buf, len);
}
/** \internal Read bytes from the specified address on the underlying transport link
* \param pPN512 pointer to pn512_t structure
* \param addr address from which to read
* \param buf buffer to read
* \param len length of buffer
*/
static inline void pn512_hw_read(pn512_t *pPN512, uint8_t addr, uint8_t *buf, size_t len)
{
nfc_transport_read(((nfc_transceiver_t *)pPN512)->pTransport, addr, buf, len);
}
static inline void pn512_hw_write_buffer(pn512_t *pPN512, uint8_t addr, ac_buffer_t *pData, size_t len)
{
while (len > 0) {
if (ac_buffer_reader_readable(pData) == 0) {
return;
}
size_t cpyLen = MIN(len, ac_buffer_reader_current_buffer_length(pData));
nfc_transport_write(((nfc_transceiver_t *)pPN512)->pTransport, addr, ac_buffer_reader_current_buffer_pointer(pData), cpyLen);
ac_buffer_read_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
static inline void pn512_hw_read_buffer(pn512_t *pPN512, uint8_t addr, ac_buffer_builder_t *pData, size_t len)
{
while (len > 0) {
if (ac_buffer_builder_writable(pData) == 0) {
return;
}
//Read payload
size_t cpyLen = MIN(len, ac_buffer_builder_space(pData));
nfc_transport_read(((nfc_transceiver_t *)pPN512)->pTransport, addr, ac_buffer_builder_write_position(pData), cpyLen);
ac_buffer_builder_write_n_skip(pData, cpyLen);
len -= cpyLen;
}
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_HW_H_ */

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_internal.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_INTERNAL_H_
#define PN512_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "transceiver/transceiver_internal.h"
#include "pn512.h"
#include "pn512_callback.h"
//Public
void pn512_set_protocols(nfc_transceiver_t *pTransceiver, nfc_tech_t initiators, nfc_tech_t targets, polling_options_t options);
void pn512_poll(nfc_transceiver_t *pTransceiver);
void pn512_set_crc(nfc_transceiver_t *pTransceiver, bool crc_out, bool crc_in);
void pn512_set_timeout(nfc_transceiver_t *pTransceiver, int timeout);
void pn512_set_transceive_options(nfc_transceiver_t *pTransceiver, bool transmit, bool receive, bool repoll);
void pn512_set_transceive_framing(nfc_transceiver_t *pTransceiver, nfc_framing_t framing);
void pn512_set_write(nfc_transceiver_t *pTransceiver, ac_buffer_t *pWriteBuf);
ac_buffer_t *pn512_get_read(nfc_transceiver_t *pTransceiver);
size_t pn512_get_last_byte_length(nfc_transceiver_t *pTransceiver);
void pn512_set_last_byte_length(nfc_transceiver_t *pTransceiver, size_t lastByteLength);
void pn512_set_first_byte_align(nfc_transceiver_t *pTransceiver, size_t firstByteAlign);
void pn512_abort(nfc_transceiver_t *pTransceiver);
void pn512_transceive(nfc_transceiver_t *pTransceiver);
void pn512_close(nfc_transceiver_t *pTransceiver);
void pn512_sleep(nfc_transceiver_t *pTransceiver, bool sleep);
void pn512_transceiver_callback(pn512_t *pPN512, nfc_err_t ret);
static inline void pn512_rf_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->rf.cb(pPN512, ret);
}
static inline void pn512_poll_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->poll.cb(pPN512, ret);
}
static inline void pn512_anticollision_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->anticollision.cb(pPN512, ret);
}
static inline void pn512_transceive_callback(pn512_t *pPN512, nfc_err_t ret)
{
pPN512->transceive.cb(pPN512, ret);
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_INTERNAL_H_ */

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_irq.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Manage PN512 interrupt requests
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_irq.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_irq.h"
#include "pn512_registers.h"
#include "pn512_hw.h"
#include "pn512.h"
/** \addtogroup PN512
* \internal
* @{
* \name Interrupts
* @{
*/
/**
* @}
* @}
* */

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_irq.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_IRQ_H_
#define PN512_IRQ_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
#include "pn512_registers.h"
#define PN512_IRQ_TX (1<<6)
#define PN512_IRQ_RX (1<<5)
#define PN512_IRQ_IDLE (1<<4)
#define PN512_IRQ_HIGH_ALERT (1<<3)
#define PN512_IRQ_LOW_ALERT (1<<2)
#define PN512_IRQ_ERR (1<<1)
#define PN512_IRQ_TIMER (1<<0)
#define PN512_IRQ_SIGIN (1<<(4+8))
#define PN512_IRQ_MODE (1<<(3+8))
#define PN512_IRQ_CRC (1<<(2+8))
#define PN512_IRQ_RF_ON (1<<(1+8))
#define PN512_IRQ_RF_OFF (1<<(0+8))
#define PN512_IRQ_NONE 0x00
#define PN512_IRQ_ALL 0x1F7F
#define PN512_REG_COMIEN_MASK 0x7F
#define PN512_REG_COMIEN_VAL 0x00
#define PN512_REG_DIVIEN_MASK 0x1F
#define PN512_REG_DIVIEN_VAL 0x80
#define PN512_REG_COMIRQ_MASK 0x7F
#define PN512_REG_COMIRQ_CLEAR 0x00
#define PN512_REG_DIVIRQ_MASK 0x1F
#define PN512_REG_DIVIRQ_CLEAR 0x00
/** \internal Set IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_set(pn512_t *pPN512, uint16_t irqs) //ORed
{
pn512_register_write(pPN512, PN512_REG_COMIEN, PN512_REG_COMIEN_VAL | (PN512_REG_COMIEN_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIEN, PN512_REG_DIVIEN_VAL | (PN512_REG_DIVIEN_MASK & (irqs >> 8)));
pPN512->irqsEn = irqs;
}
/** \internal Get IRQ enable registers
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIEN value, LSB is COMIEN value
*/
static inline uint16_t pn512_irq_enabled(pn512_t *pPN512) //ORed
{
return pPN512->irqsEn /*(pn512_register_read(pPN512, PN512_REG_COMIEN_VAL) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIEN_VAL) & PN512_REG_DIVIEN_MASK) << 8)*/;
}
/** \internal Get IRQ status registers (masked with enabled IRQ register)
* \param pPN512 pointer to pn512_t structure
* \return MSB is DIVIRQ value, LSB is COMIRQ value
*/
static inline uint16_t pn512_irq_get(pn512_t *pPN512) //ORed
{
return ((pn512_register_read(pPN512, PN512_REG_COMIRQ) & PN512_REG_COMIEN_MASK)
| ((pn512_register_read(pPN512, PN512_REG_DIVIRQ) & PN512_REG_DIVIEN_MASK) << 8)) & pPN512->irqsEn;
}
/** \internal Clear some interrupts
* \param pPN512 pointer to pn512_t structure
* \param irqs MSB is DIVIEN value, LSB is COMIEN value
*/
static inline void pn512_irq_clear(pn512_t *pPN512, uint16_t irqs)
{
pn512_register_write(pPN512, PN512_REG_COMIRQ, PN512_REG_COMIRQ_CLEAR | (PN512_REG_COMIRQ_MASK & (irqs & 0xFF)));
pn512_register_write(pPN512, PN512_REG_DIVIRQ, PN512_REG_DIVIRQ_CLEAR | (PN512_REG_DIVIRQ_MASK & (irqs >> 8)));
}
#ifdef __cplusplus
}
#endif
#endif /* PN512_IRQ_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_poll.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_POLL_H_
#define PN512_POLL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
void pn512_poll_setup(pn512_t *pPN512);
void pn512_poll_hw(pn512_t *pPN512, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_POLL_H_ */

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_registers.c
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
* \details Access to PN512 registers
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_registers.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_registers.h"
#include "pn512_hw.h"
#include "pn512.h"
#define REGISTER_PAGE(x) ((x)>>4)
#define REGISTER_ADDR(x) ((x)&0xF)
/** \addtogroup PN512
* \internal
* @{
* \name Registers
* @{
*/
static void pn512_register_switch_page_intl(pn512_t *pPN512, uint8_t page);
/** \internal Initialize underlying pn512_registers_t structure
* \param pPN512 pointer to pn512_t structure
*/
void pn512_registers_init(pn512_t *pPN512)
{
pPN512->registers.registers_page = 0;
}
#define PN512_CFG_INIT_LEN 9
static const uint8_t PN512_CFG_INIT_REGS[] = {
PN512_REG_DIVIEN,
PN512_REG_MODE,
PN512_REG_GSNOFF,
PN512_REG_RFCFG,
PN512_REG_CWGSP,
PN512_REG_MIFNFC,
PN512_REG_FELNFC2,
PN512_REG_RXSEL,
PN512_REG_TYPEB
};
static const uint8_t PN512_CFG_INIT_VALS[] = {
0x80,
0x3F,
0xF2,
0x68,
0x3F,
0x62,
0x80,
0x84,
0x00
}; //Timer: For now max prescaler, max reload value
/** \internal Switch to known (0) registers page, reset registers state
* \param pPN512 pointer to pn512_t structure
*/
void pn512_registers_reset(pn512_t *pPN512)
{
pn512_register_switch_page_intl(pPN512, 0);
for (int i = 0; i < PN512_CFG_INIT_LEN; i++) {
pn512_register_write(pPN512, PN512_CFG_INIT_REGS[i], PN512_CFG_INIT_VALS[i]);
}
}
/** \internal Write register
* \param pPN512 pointer to pn512_t structure
* \param address register address
* \param data value to write in register
*/
void pn512_register_write(pn512_t *pPN512, uint8_t address, uint8_t data)
{
NFC_DBG("Write [%02x] << %02x", address, data);
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
address = REGISTER_ADDR(address);
pn512_hw_write(pPN512, address, &data, 1);
}
/** \internal Read register
* \param pPN512 pointer to pn512_t structure
* \param address register address
* \return data value read from register
*/
uint8_t pn512_register_read(pn512_t *pPN512, uint8_t address)
{
uint8_t data;
NFC_DBG_BLOCK(
uint8_t __dbg_addr;
__dbg_addr = address; //FIXME
)
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
address = REGISTER_ADDR(address);
pn512_hw_read(pPN512, address, &data, 1);
NFC_DBG("Read [%02x] >> %02x", __dbg_addr, data);
return data;
}
void pn512_register_switch_page(pn512_t *pPN512, uint8_t address)
{
if (REGISTER_PAGE(address) != pPN512->registers.registers_page) {
pn512_register_switch_page_intl(pPN512, REGISTER_PAGE(address));
}
}
/** \internal Switch registers page
* \param pPN512 pointer to pn512_t structure
* \param page registers page
*/
void pn512_register_switch_page_intl(pn512_t *pPN512, uint8_t page)
{
uint8_t pageRegValue;
pageRegValue = (1 << 7) | page;
pn512_hw_write(pPN512, PN512_REG_PAGE, &pageRegValue, 1);
pPN512->registers.registers_page = page;
}
/**
* @}
* @}
* */

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2013-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_registers.h
* \copyright Copyright (c) ARM Ltd 2013
* \author Donatien Garnier
*/
#ifndef PN512_REGISTERS_H_
#define PN512_REGISTERS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
//Page 0 - Command and Status
#define PN512_REG_PAGE 0x00 //Selects the register page
#define PN512_REG_COMMAND 0x01 //Starts and stops command execution
#define PN512_REG_COMIEN 0x02 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_DIVIEN 0x03 //Controls bits to enable and disable the passing of Interrupt Requests
#define PN512_REG_COMIRQ 0x04 //Contains Interrupt Request bits
#define PN512_REG_DIVIRQ 0x05 //Contains Interrupt Request bits
#define PN512_REG_ERROR 0x06 //Error bits showing the error status of the last command executed
#define PN512_REG_STATUS1 0x07 //Contains status bits for communication
#define PN512_REG_STATUS2 0x08 //Contains status bits of the receiver and transmitter
#define PN512_REG_FIFODATA 0x09 //In- and output of 64 byte FIFO-buffer
#define PN512_REG_FIFOLEVEL 0x0A //Indicates the number of bytes stored in the FIFO
#define PN512_REG_WATERLEVEL 0x0B //Defines the level for FIFO under- and overflow warning
#define PN512_REG_CONTROL 0x0C //Contains miscellaneous Control Registers
#define PN512_REG_BITFRAMING 0x0D //Adjustments for bit oriented frames
#define PN512_REG_COLL 0x0E //Bit position of the first bit collision detected on the RF-interface
//Page 1 - Command
//#define PN512_REG_PAGE 0x10 //Selects the register page
#define PN512_REG_MODE 0x11 //Defines general modes for transmitting and receiving
#define PN512_REG_TXMODE 0x12 //Defines the data rate and framing during transmission
#define PN512_REG_RXMODE 0x13 //Defines the data rate and framing during receiving
#define PN512_REG_TXCONTROL 0x14 //Controls the logical behavior of the antenna driver pins TX1 and TX2
#define PN512_REG_TXAUTO 0x15 //Controls the setting of the antenna drivers
#define PN512_REG_TXSEL 0x16 //Selects the internal sources for the antenna driver
#define PN512_REG_RXSEL 0x17 //Selects internal receiver settings
#define PN512_REG_RXTHRESHOLD 0x18 //Selects thresholds for the bit decoder
#define PN512_REG_DEMOD 0x19 //Defines demodulator settings
#define PN512_REG_FELNFC1 0x1A //Defines the length of the valid range for the receive package
#define PN512_REG_FELNFC2 0x1B //Defines the length of the valid range for the receive package
#define PN512_REG_MIFNFC 0x1C //Controls the communication in ISO/IEC 14443/MIFARE and NFC target mode at 106 kbit
#define PN512_REG_MANUALRCV 0x1D //Allows manual fine tuning of the internal receiver
#define PN512_REG_TYPEB 0x1E //Configure the ISO/IEC 14443 type B
#define PN512_REG_SERIALSPEED 0x1F //Selects the speed of the serial UART interface
//Page 2 - CFG
//#define PN512_REG_PAGE 0x20 //Selects the register page
#define PN512_REG_CRCRESULT_MSB 0x21 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_CRCRESULT_LSB 0x22 //Shows the actual MSB and LSB values of the CRC calculation
#define PN512_REG_GSNOFF 0x23 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation, when the driver is switched off
#define PN512_REG_MODWIDTH 0x24 //Controls the setting of the ModWidth
#define PN512_REG_TXBITPHASE 0x25 //Adjust the TX bit phase at 106 kbit
#define PN512_REG_RFCFG 0x26 //Configures the receiver gain and RF level
#define PN512_REG_GSNON 0x27 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation when the drivers are switched on
#define PN512_REG_CWGSP 0x28 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during times of no modulation
#define PN512_REG_MODGSP 0x29 //Selects the conductance of the antenna driver pins TX1 and TX2 for modulation during modulation
#define PN512_REG_TMODE_TPRESCALERHIGH 0x2A //Defines settings for the internal timer
#define PN512_REG_TPRESCALERLOW 0x2B //Defines settings for the internal timer
#define PN512_REG_TRELOADHIGH 0x2C //Describes the 16-bit timer reload value
#define PN512_REG_TRELOADLOW 0x2D //Describes the 16-bit timer reload value
#define PN512_REG_TCOUNTERVALHIGH 0x2E //Shows the 16-bit actual timer value
#define PN512_REG_TCOUNTERVALLOW 0x2F //Shows the 16-bit actual timer value
//Page 3 - TestRegister
//#define PN512_REG_PAGE 0x30 //Selects the register page
#define PN512_REG_TESTSEL1 0x31 //General test signal configuration
#define PN512_REG_TESTSEL2 0x32 //General test signal configuration and PRBS control
#define PN512_REG_TESTPINEN 0x33 //Enables pin output driver on 8-bit parallel bus (Note: For serial interfaces only)
#define PN512_REG_TESTPINVALUE 0x34 //Defines the values for the 8-bit parallel bus when it is used as I/O bus
#define PN512_REG_TESTBUS 0x35 //Shows the status of the internal testbus
#define PN512_REG_AUTOTEST 0x36 //Controls the digital selftest
#define PN512_REG_VERSION 0x37 //Shows the version
#define PN512_REG_ANALOGTEST 0x38 //Controls the pins AUX1 and AUX2
#define PN512_REG_TESTDAC1 0x39 //Defines the test value for the TestDAC1
#define PN512_REG_TESTDAC2 0x3A //Defines the test value for the TestDAC2
#define PN512_REG_TESTADC 0x3B //Shows the actual value of ADC I and Q
void pn512_registers_init(pn512_t *pPN512);
void pn512_registers_reset(pn512_t *pPN512);
void pn512_register_write(pn512_t *pPN512, uint8_t address, uint8_t data);
uint8_t pn512_register_read(pn512_t *pPN512, uint8_t address);
void pn512_register_switch_page(pn512_t *pPN512, uint8_t address);
#ifdef __cplusplus
}
#endif
#endif /* PN512_REGISTERS_H_ */

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_rf.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_rf.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512_callback.h"
#include "pn512_rf.h"
#include "pn512_registers.h"
#include "pn512_timer.h"
#include "pn512_irq.h"
#include "pn512.h"
#include "pn512_internal.h"
#include "stdlib.h" //For rand() func
#define PN512_FRAMING_REGS 6
static const uint8_t framing_registers[] = { PN512_REG_MODE, PN512_REG_TXMODE, PN512_REG_RXMODE, PN512_REG_MODGSP, PN512_REG_RXTHRESHOLD, PN512_REG_MODWIDTH };
static const uint8_t framing_registers_mode_detector[] = { 0x3B, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_initiator_iso14443a_106k[] = { 0x3D, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_initiator_iso14443b_106k[] = { 0x3F, 0x83, 0x83, 0x04, 0x50, 0x26 };
static const uint8_t framing_registers_target_iso14443a_106k[] = { 0x3D, 0x80, 0x80, 0x3F, 0x55, 0x26 };
static const uint8_t framing_registers_felica_212k[] = { 0x3A, 0x92, 0x92, 0x12, 0x55, 0x15 };
static const uint8_t framing_registers_felica_414k[] = { 0x3A, 0xA2, 0xA2, 0x12, 0x55, 0x0A };
nfc_err_t pn512_framing_set(pn512_t *pPN512, nfc_framing_t framing)
{
if (framing == pPN512->framing) { //No need to do anything
return NFC_OK;
}
NFC_DBG("Switching to %u", framing);
const uint8_t *framing_registers_values;
switch (framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
for (int i = 0; i < PN512_FRAMING_REGS; i++) {
pn512_register_write(pPN512, framing_registers[i], framing_registers_values[i]);
}
pPN512->framing = framing;
pPN512->crc.out = true;
pPN512->crc.in = true;
//TODO initiator: PN512_REG_MODGSP
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_b_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x10); //Act as initiator
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x00); //Act as target
break;
default:
return NFC_ERR_UNSUPPORTED;
}
#if 1
if (
pPN512->framing == nfc_framing_initiator_a_106
//|| (pPN512->framing == pn512_framing_target_iso14443a_106k)
) {
//Enable 100% ASK Modulation
pn512_register_write(pPN512, PN512_REG_TXAUTO, pn512_register_read(pPN512, PN512_REG_TXAUTO) | 0x40);
} else {
pn512_register_write(pPN512, PN512_REG_TXAUTO, pn512_register_read(pPN512, PN512_REG_TXAUTO) & (~0x40));
}
#endif
return NFC_OK;
}
nfc_err_t pn512_framing_crc_set(pn512_t *pPN512, bool out, bool in)
{
const uint8_t *framing_registers_values;
switch (pPN512->framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
if (pPN512->crc.out != out) {
pn512_register_write(pPN512, framing_registers[1], (framing_registers_values[1] & 0x7F) | (out ? 0x80 : 0x00)); //TXMODE
pPN512->crc.out = out;
}
if (pPN512->crc.in != in) {
pn512_register_write(pPN512, framing_registers[2], (framing_registers_values[2] & 0x7F) | (in ? 0x80 : 0x00)); //RXMODE
pPN512->crc.in = in;
}
return NFC_OK;
}
nfc_err_t pn512_framing_rx_multiple_enable(pn512_t *pPN512)
{
const uint8_t *framing_registers_values;
switch (pPN512->framing) {
case nfc_framing_target_mode_detector:
framing_registers_values = framing_registers_mode_detector;
break;
case nfc_framing_target_a_106:
framing_registers_values = framing_registers_target_iso14443a_106k;
break;
case nfc_framing_initiator_a_106:
framing_registers_values = framing_registers_initiator_iso14443a_106k;
break;
case nfc_framing_initiator_b_106:
framing_registers_values = framing_registers_initiator_iso14443b_106k;
break;
case nfc_framing_target_f_212:
case nfc_framing_initiator_f_212:
framing_registers_values = framing_registers_felica_212k;
break;
case nfc_framing_target_f_424:
case nfc_framing_initiator_f_424:
framing_registers_values = framing_registers_felica_414k;
break;
default:
return NFC_ERR_UNSUPPORTED;
}
pn512_register_write(pPN512, framing_registers[2], (framing_registers_values[2] & 0x7F) | (pPN512->crc.in ? 0x80 : 0x00) | 0x04); //RXMODE
return NFC_OK;
}
void pn512_rf_field_switch_off(pn512_t *pPN512)
{
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x00);
pn512_register_write(pPN512, PN512_REG_TXCONTROL, 0x80);
pPN512->rf_on = false;
}
void pn512_rf_field_nfcip1_rf_collision_avoidance_complete(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
uint16_t irq_res = pn512_irq_get(pPN512);
(void) events;
pn512_timer_stop(pPN512);
pn512_timer_config(pPN512, false, 0, 0xffff); //Deactivate autostart
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
if (irq_res & PN512_IRQ_RF_ON) {
NFC_DBG("External field on");
//Clear TXAUTO register
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x00);
pPN512->rf_on = false; //External field on
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Has our RF field been switched on?
if (pn512_register_read(pPN512, PN512_REG_TXAUTO) & 0x40) { //InitialRFOn bit is cleared automatically, if the RF field is switched on
NFC_ERR("InitialRFOn bit still set");
pn512_rf_callback(pPN512, NFC_ERR_UNKNOWN);
return;
}
pPN512->rf_on = true; //Own field on and guard time ok
NFC_DBG("RF field enabled");
pn512_rf_callback(pPN512, NFC_OK);
}
void pn512_rf_field_nfcip1_rf_collision_avoidance(pn512_t *pPN512, pn512_cb_t cb)
{
pPN512->rf.cb = cb;
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
//If our field is switched on, Wait TIRFG according to NFC-IP1 = 5ms => 67800 clock edges = (3+1)*8475
pn512_timer_config(pPN512, true, 3, 8475);
pn512_irq_set(pPN512, PN512_IRQ_RF_ON /* External field switched on */
| PN512_IRQ_TIMER /* Timer reached 0 */);
//Try to enable RF field in compliance with NFC-IP1
pn512_register_write(pPN512, PN512_REG_TXAUTO, 0x0F);
//Is external RF Field already on?
if (pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x4) {
NFC_DBG("External field already on");
pPN512->rf_on = false; //External field on
//Cancel
pn512_timer_stop(pPN512);
pn512_timer_config(pPN512, false, 0, 0xffff); //Deactivate autostart
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON | PN512_IRQ_TIMER);
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, -1, pn512_rf_field_nfcip1_rf_collision_avoidance_complete, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}
void pn512_rf_field_wait_for_external_complete_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
NFC_DBG("%lu events", events);
//Wake up PN512
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x00);
while (pn512_register_read(pPN512, PN512_REG_COMMAND) & 0x10);
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
if (events & EVENT_ABORTED) {
pn512_rf_callback(pPN512, NFC_ERR_ABORTED);
return;
}
if (events & EVENT_TIMEOUT) {
NFC_DBG("Timeout");
pn512_rf_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
NFC_DBG("On");
pn512_rf_callback(pPN512, NFC_OK);
}
void pn512_rf_field_wait_for_external(pn512_t *pPN512, int timeout, pn512_cb_t cb)
{
pPN512->rf.cb = cb;
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
NFC_DBG("Wait for RF field to come up (timeout %d)", timeout);
//Is external RF Field already on?
pn512_irq_set(pPN512, PN512_IRQ_RF_ON /* External field switched on */);
if (pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x4) {
NFC_DBG("RF field already on");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RF_ON);
pn512_rf_callback(pPN512, NFC_OK);
return;
}
//Send PN512 to sleep mode
pn512_register_write(pPN512, PN512_REG_COMMAND, 0x30); //Receiver off + soft power down
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, timeout, pn512_rf_field_wait_for_external_complete_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_rf.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_RF_H_
#define PN512_RF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512_types.h"
#include "pn512_callback.h"
#include "pn512.h"
nfc_err_t pn512_framing_set(pn512_t *pPN512, nfc_framing_t framing);
nfc_err_t pn512_framing_crc_set(pn512_t *pPN512, bool out, bool in);
nfc_err_t pn512_framing_rx_multiple_enable(pn512_t *pPN512);
#define PN512_FRAMING_IS_TARGET( framing ) ((framing) <= nfc_framing_target_f_424)
void pn512_rf_field_switch_off(pn512_t *pPN512);
void pn512_rf_field_nfcip1_rf_collision_avoidance(pn512_t *pPN512, pn512_cb_t cb);
void pn512_rf_field_wait_for_external(pn512_t *pPN512, int timeout, pn512_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif /* PN512_RF_H_ */

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_timer.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#include "stack/nfc_errors.h"
#include "pn512_timer.h"
#include "pn512_registers.h"
void pn512_timer_config(pn512_t *pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value)
{
pn512_timer_stop(pPN512); //just in case...
pn512_register_write(pPN512, PN512_REG_TRELOADLOW, countdown_value & 0xFF);
pn512_register_write(pPN512, PN512_REG_TRELOADHIGH, (countdown_value >> 8) & 0xFF);
pn512_register_write(pPN512, PN512_REG_TPRESCALERLOW, prescaler & 0xFF);
pn512_register_write(pPN512, PN512_REG_TMODE_TPRESCALERHIGH, (autostart ? 0x80 : 0x00) | ((prescaler >> 8) & 0x0F));
}
void pn512_timer_start(pn512_t *pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x50);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x40);
break;
}
}
void pn512_timer_stop(pn512_t *pPN512)
{
//The control register also contains the initiator bit that we must set correctly
switch (pPN512->framing) {
case nfc_framing_initiator_a_106:
case nfc_framing_initiator_f_212:
case nfc_framing_initiator_f_424:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x90);
break;
case nfc_framing_target_mode_detector:
case nfc_framing_target_a_106:
case nfc_framing_target_f_212:
case nfc_framing_target_f_424:
default:
pn512_register_write(pPN512, PN512_REG_CONTROL, 0x80);
break;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_timer.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_TIMER_H_
#define PN512_TIMER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512_types.h"
void pn512_timer_config(pn512_t *pPN512, bool autostart, uint16_t prescaler, uint16_t countdown_value);
void pn512_timer_start(pn512_t *pPN512);
void pn512_timer_stop(pn512_t *pPN512);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TIMER_H_ */

View File

@@ -0,0 +1,441 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_transceive.c
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "pn512_transceive.c"
#endif
#include "stack/nfc_errors.h"
#include "pn512.h"
#include "pn512_transceive.h"
#include "pn512_rf.h"
#include "pn512_irq.h"
#include "pn512_cmd.h"
#include "pn512_registers.h"
#include "pn512_internal.h"
#define TIMEOUT 1000
void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start)
{
uint16_t irqs_en = pn512_irq_enabled(pPN512);
if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) {
//Fill FIFO
pn512_fifo_write(pPN512, &pPN512->writeBuf);
if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) { //Did not fit in FIFO
pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
//Has low FIFO alert IRQ already been enabled?
if (!(irqs_en & PN512_IRQ_LOW_ALERT)) {
irqs_en |= PN512_IRQ_LOW_ALERT;
pn512_irq_set(pPN512, irqs_en);
}
} else {
if (irqs_en & PN512_IRQ_LOW_ALERT) {
//Buffer has been fully sent
irqs_en &= ~PN512_IRQ_LOW_ALERT;
pn512_irq_set(pPN512, irqs_en);
}
}
}
if (start) {
if ((pPN512->transceive.mode == pn512_transceive_mode_transmit) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
//Update bitframing register
pn512_register_write(pPN512, PN512_REG_BITFRAMING,
0x00 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
//Use transmit command
pn512_cmd_exec(pPN512, PN512_CMD_TRANSMIT);
} else {
NFC_DBG("Bitframing %02X", 0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
//Update bitframing register to start transmission
pn512_register_write(pPN512, PN512_REG_BITFRAMING,
0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
}
//Reset last byte length, first byte align
pPN512->writeLastByteLength = 8;
pPN512->readFirstByteAlign = 0;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, TIMEOUT, pn512_transceive_hw_tx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
}
void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
if (events & EVENT_ABORTED) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Aborted TX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
return;
}
NFC_DBG("TX task");
if (events & EVENT_TIMEOUT) {
// Check status
NFC_DBG("Status = %02X %02X", pn512_register_read(pPN512, PN512_REG_STATUS1), pn512_register_read(pPN512, PN512_REG_STATUS2));
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Timeout on TX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
uint16_t irqs_en = pn512_irq_enabled(pPN512);
uint16_t irqs = pn512_irq_get(pPN512);
if (irqs & PN512_IRQ_RF_OFF) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
NFC_WARN("RF Off");
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
if (irqs & PN512_IRQ_TX) {
if (irqs_en & PN512_IRQ_LOW_ALERT) {
//If the transmission has been completed without us getting a chance to fill the buffer up it means that we had a buffer underflow
NFC_ERR("Buffer underflow");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_UNDERFLOW);
return;
}
//Transmission complete
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_TX | PN512_IRQ_LOW_ALERT);
//Start receiving
NFC_DBG("Transmission complete");
if (pPN512->transceive.mode != pn512_transceive_mode_transmit) {
if (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll) {
//Make sure bitframing reg is clean
pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_transceive_hw_rx_start(pPN512);
//Start autocoll
pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
} else {
pn512_transceive_hw_rx_start(pPN512);
}
return;
} else {
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
pn512_transceive_callback(pPN512, NFC_OK);
return;
}
}
if ((irqs & PN512_IRQ_LOW_ALERT) && (ac_buffer_reader_readable(&pPN512->writeBuf) > 0)) {
//Continue to fill FIFO
pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
pn512_transceive_hw_tx_iteration(pPN512, false);
return;
}
if (irqs & PN512_IRQ_IDLE) {
pn512_irq_clear(pPN512, PN512_IRQ_ERR);
NFC_ERR("Modem went to idle");
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
return;
}
//Call back function
pn512_transceive_hw_tx_iteration(pPN512, false);
}
void pn512_transceive_hw_rx_start(pn512_t *pPN512)
{
uint16_t irqs_en = PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_ERR;
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
irqs_en |= PN512_IRQ_RF_OFF;
}
pn512_irq_set(pPN512, irqs_en);
//Reset buffer except if data should be appended to this -- TODO
ac_buffer_builder_reset(&pPN512->readBufBldr);
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
&pPN512->transceiver.task);
}
void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData)
{
pn512_t *pPN512 = (pn512_t *) pUserData;
NFC_DBG("RX task");
if (events & EVENT_ABORTED) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_ERR("Aborted RX");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
return;
}
if (events & EVENT_TIMEOUT) {
NFC_WARN("Timeout");
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
return;
}
uint16_t irqs = pn512_irq_get(pPN512);
NFC_DBG("irqs %04x", irqs);
bool collision_detected = false;
if (irqs & PN512_IRQ_ERR) {
pn512_irq_clear(pPN512, PN512_IRQ_ERR);
uint8_t err_reg = pn512_register_read(pPN512, PN512_REG_ERROR);
NFC_ERR("Got error - error reg is %02X", err_reg);
// if err_reg == 0, sticky error that must have been cleared automatically, continue
if (err_reg != 0) {
//If it's a collsision, flag it but still carry on with RX procedure
collision_detected = true;
if ((err_reg == 0x08) || (err_reg == 0x0A)) { // Collision (and maybe parity) (and no other error)
irqs &= ~PN512_IRQ_ERR;
irqs |= PN512_IRQ_RX;
} else {
NFC_DBG_BLOCK(
//Empty FIFO into buffer
pn512_fifo_read(pPN512, &pPN512->readBufBldr);
NFC_DBG("Received");
ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));
NFC_DBG("Computed CRC = %02X %02X", pn512_register_read(pPN512, PN512_REG_CRCRESULT_MSB), pn512_register_read(pPN512, PN512_REG_CRCRESULT_LSB));
)
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
return;
}
}
}
if ((irqs & PN512_IRQ_RX) || (irqs & PN512_IRQ_HIGH_ALERT)) {
//Empty FIFO into buffer
pn512_fifo_read(pPN512, &pPN512->readBufBldr);
if ((ac_buffer_builder_writable(&pPN512->readBufBldr) == 0) && (pn512_fifo_length(pPN512) > 0)) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
NFC_WARN("RX buffer overflow");
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_BUFFER_TOO_SMALL);
return; //overflow
}
if (irqs & PN512_IRQ_HIGH_ALERT) {
NFC_DBG("High alert");
pn512_irq_clear(pPN512, PN512_IRQ_HIGH_ALERT);
}
if (irqs & PN512_IRQ_RX) {
pn512_irq_clear(pPN512, PN512_IRQ_RX);
size_t last_byte_length = pn512_register_read(pPN512, PN512_REG_CONTROL) & 0x7;
if (last_byte_length == 0) {
last_byte_length = 8;
}
pPN512->readLastByteLength = last_byte_length;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
NFC_DBG("Received:");
NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));)
if ((pPN512->transceive.mode == pn512_transceive_mode_target_autocoll) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
//Check if target was activated
if (!(pn512_register_read(pPN512, PN512_REG_STATUS2) & 0x10)) {
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
//PN512 switches to transceive automatically
pPN512->transceive.mode = pn512_transceive_mode_transceive;
} else if (pPN512->transceive.mode == pn512_transceive_mode_receive) {
pPN512->transceive.mode = pn512_transceive_mode_transceive;
//pn512_cmd_exec(pPN512, PN512_CMD_IDLE); //Useful?
}
if (!collision_detected) {
pn512_transceive_callback(pPN512, NFC_OK);
} else {
pn512_transceive_callback(pPN512, NFC_ERR_COLLISION);
}
return;
}
}
if (irqs & PN512_IRQ_RF_OFF) {
//Stop command
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pPN512->transceive.mode = pn512_transceive_mode_idle;
pn512_irq_set(pPN512, PN512_IRQ_NONE);
pn512_irq_clear(pPN512, PN512_IRQ_ALL);
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
//Queue task to process IRQ
task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
&pPN512->transceiver.task);
}
void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb)
{
uint16_t irqs_en;
//Store callback
pPN512->transceive.cb = cb;
//Clear FIFO
pn512_fifo_clear(pPN512);
//Clear previous IRQs if present
pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_TX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_LOW_ALERT | PN512_IRQ_ERR | PN512_IRQ_IDLE | PN512_IRQ_RF_OFF);
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
//RF off?
if (!(pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x04)) {
//Call callback
pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
return;
}
} else if ((pPN512->transceive.mode != mode) && (mode == pn512_transceive_mode_transceive)) {
pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
}
pPN512->transceive.mode = mode;
if (mode == pn512_transceive_mode_receive) {
pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
pn512_transceive_hw_rx_start(pPN512);
pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
} else if (mode == pn512_transceive_mode_target_autocoll) {
//Make sure bitframing reg is clean
pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
pn512_transceive_hw_rx_start(pPN512);
//Start autocoll
pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
return;
} else {
NFC_DBG("Sending:");
NFC_DBG_BLOCK(ac_buffer_dump(&pPN512->writeBuf);)
//Transmit a frame to remote target/initiator
irqs_en = PN512_IRQ_TX | PN512_IRQ_IDLE;
if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
irqs_en |= PN512_IRQ_RF_OFF;
}
pn512_irq_set(pPN512, irqs_en);
pn512_transceive_hw_tx_iteration(pPN512, true);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_transceive.h
* \copyright Copyright (c) ARM Ltd 2014
* \author Donatien Garnier
*/
#ifndef PN512_TRANSCEIVE_H_
#define PN512_TRANSCEIVE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
#include "pn512.h"
void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb);
void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData);
void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start);
void pn512_transceive_hw_rx_start(pn512_t *pPN512);
void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData);
#ifdef __cplusplus
}
#endif
#endif /* PN512_TRANSCEIVE_H_ */

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file pn512_types.h
* \copyright Copyright (c) ARM Ltd 2015
* \author Donatien Garnier
*/
#ifndef TRANSCEIVER_PN512_PN512_TYPES_H_
#define TRANSCEIVER_PN512_PN512_TYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stack/nfc_common.h"
typedef struct __pn512 pn512_t;
typedef struct __pn512_registers {
int8_t registers_page;
} pn512_registers_t;
#ifdef __cplusplus
}
#endif
#endif /* TRANSCEIVER_PN512_PN512_TYPES_H_ */