mbed-os5 only for TYBLE16
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
features/nfc/stack/transceiver/pn512/pn512.c
- Committer:
- kenjiArai
- Date:
- 2019-12-31
- Revision:
- 1:9db0e321a9f4
- Parent:
- 0:5b88d5760320
File content as of revision 1:9db0e321a9f4:
/* * 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); } /** * @} * @} * */