Import Mbed OS hard-float snapshot
This commit is contained in:
356
connectivity/drivers/nfc/PN512/source/transceiver/pn512.c
Normal file
356
connectivity/drivers/nfc/PN512/source/transceiver/pn512.c
Normal 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
153
connectivity/drivers/nfc/PN512/source/transceiver/pn512.h
Normal file
153
connectivity/drivers/nfc/PN512/source/transceiver/pn512.h
Normal 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_ */
|
||||
@@ -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_ */
|
||||
148
connectivity/drivers/nfc/PN512/source/transceiver/pn512_cmd.c
Normal file
148
connectivity/drivers/nfc/PN512/source/transceiver/pn512_cmd.c
Normal 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
||||
@@ -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_ */
|
||||
54
connectivity/drivers/nfc/PN512/source/transceiver/pn512_hw.c
Normal file
54
connectivity/drivers/nfc/PN512/source/transceiver/pn512_hw.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
||||
92
connectivity/drivers/nfc/PN512/source/transceiver/pn512_hw.h
Normal file
92
connectivity/drivers/nfc/PN512/source/transceiver/pn512_hw.h
Normal 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_ */
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
108
connectivity/drivers/nfc/PN512/source/transceiver/pn512_irq.h
Normal file
108
connectivity/drivers/nfc/PN512/source/transceiver/pn512_irq.h
Normal 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_ */
|
||||
1268
connectivity/drivers/nfc/PN512/source/transceiver/pn512_poll.c
Normal file
1268
connectivity/drivers/nfc/PN512/source/transceiver/pn512_poll.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
@@ -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_ */
|
||||
329
connectivity/drivers/nfc/PN512/source/transceiver/pn512_rf.c
Normal file
329
connectivity/drivers/nfc/PN512/source/transceiver/pn512_rf.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
54
connectivity/drivers/nfc/PN512/source/transceiver/pn512_rf.h
Normal file
54
connectivity/drivers/nfc/PN512/source/transceiver/pn512_rf.h
Normal 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_ */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user