Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pn512_transceive.c Source File

pn512_transceive.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2014-2018, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 /**
00018  * \file pn512_transceive.c
00019  * \copyright Copyright (c) ARM Ltd 2014
00020  * \author Donatien Garnier
00021  */
00022 
00023 #define __DEBUG__ 0
00024 #ifndef __MODULE__
00025 #define __MODULE__ "pn512_transceive.c"
00026 #endif
00027 
00028 #include "stack/nfc_errors.h"
00029 
00030 #include "pn512.h"
00031 #include "pn512_transceive.h"
00032 #include "pn512_rf.h"
00033 #include "pn512_irq.h"
00034 #include "pn512_cmd.h"
00035 #include "pn512_registers.h"
00036 #include "pn512_internal.h"
00037 
00038 
00039 #define TIMEOUT 1000
00040 
00041 void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start)
00042 {
00043     uint16_t irqs_en = pn512_irq_enabled(pPN512);
00044 
00045     if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) {
00046         //Fill FIFO
00047         pn512_fifo_write(pPN512, &pPN512->writeBuf);
00048 
00049         if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) { //Did not fit in FIFO
00050             pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
00051             //Has low FIFO alert IRQ already been enabled?
00052             if (!(irqs_en & PN512_IRQ_LOW_ALERT)) {
00053                 irqs_en |= PN512_IRQ_LOW_ALERT;
00054                 pn512_irq_set(pPN512, irqs_en);
00055             }
00056         } else {
00057             if (irqs_en & PN512_IRQ_LOW_ALERT) {
00058                 //Buffer has been fully sent
00059                 irqs_en &= ~PN512_IRQ_LOW_ALERT;
00060                 pn512_irq_set(pPN512, irqs_en);
00061             }
00062         }
00063     }
00064 
00065 
00066     if (start) {
00067         if ((pPN512->transceive.mode == pn512_transceive_mode_transmit) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
00068             //Update bitframing register
00069             pn512_register_write(pPN512, PN512_REG_BITFRAMING,
00070                                  0x00 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
00071 
00072             //Use transmit command
00073             pn512_cmd_exec(pPN512, PN512_CMD_TRANSMIT);
00074         } else {
00075             NFC_DBG("Bitframing %02X", 0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
00076             //Update bitframing register to start transmission
00077             pn512_register_write(pPN512, PN512_REG_BITFRAMING,
00078                                  0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7));
00079         }
00080 
00081         //Reset last byte length, first byte align
00082         pPN512->writeLastByteLength = 8;
00083         pPN512->readFirstByteAlign = 0;
00084     }
00085 
00086     //Queue task to process IRQ
00087     task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, TIMEOUT, pn512_transceive_hw_tx_task, pPN512);
00088     nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task);
00089 }
00090 
00091 void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData)
00092 {
00093     pn512_t *pPN512 = (pn512_t *) pUserData;
00094 
00095     if (events & EVENT_ABORTED) {
00096         //Stop command
00097         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00098         pPN512->transceive.mode = pn512_transceive_mode_idle;
00099 
00100         NFC_ERR("Aborted TX");
00101 
00102         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00103         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00104 
00105         pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
00106         return;
00107     }
00108 
00109     NFC_DBG("TX task");
00110     if (events & EVENT_TIMEOUT) {
00111         // Check status
00112         NFC_DBG("Status = %02X %02X", pn512_register_read(pPN512, PN512_REG_STATUS1), pn512_register_read(pPN512, PN512_REG_STATUS2));
00113 
00114         //Stop command
00115         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00116         pPN512->transceive.mode = pn512_transceive_mode_idle;
00117 
00118         NFC_ERR("Timeout on TX");
00119 
00120         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00121         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00122 
00123         //Call callback
00124         pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
00125         return;
00126     }
00127 
00128     uint16_t irqs_en = pn512_irq_enabled(pPN512);
00129     uint16_t irqs = pn512_irq_get(pPN512);
00130 
00131     if (irqs & PN512_IRQ_RF_OFF) {
00132         //Stop command
00133         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00134         pPN512->transceive.mode = pn512_transceive_mode_idle;
00135 
00136         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00137         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00138         NFC_WARN("RF Off");
00139         pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
00140         return;
00141     }
00142     if (irqs & PN512_IRQ_TX) {
00143         if (irqs_en & PN512_IRQ_LOW_ALERT) {
00144             //If the transmission has been completed without us getting a chance to fill the buffer up it means that we had a buffer underflow
00145             NFC_ERR("Buffer underflow");
00146             pn512_irq_set(pPN512, PN512_IRQ_NONE);
00147             pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00148 
00149             pn512_transceive_callback(pPN512, NFC_ERR_UNDERFLOW);
00150             return;
00151         }
00152 
00153         //Transmission complete
00154         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00155         pn512_irq_clear(pPN512, PN512_IRQ_TX | PN512_IRQ_LOW_ALERT);
00156 
00157         //Start receiving
00158         NFC_DBG("Transmission complete");
00159         if (pPN512->transceive.mode != pn512_transceive_mode_transmit) {
00160             if (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll) {
00161                 //Make sure bitframing reg is clean
00162                 pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
00163 
00164                 pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00165                 pn512_transceive_hw_rx_start(pPN512);
00166 
00167                 //Start autocoll
00168                 pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
00169             } else {
00170                 pn512_transceive_hw_rx_start(pPN512);
00171             }
00172             return;
00173         } else {
00174             pn512_irq_set(pPN512, PN512_IRQ_NONE);
00175             pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
00176 
00177             pn512_transceive_callback(pPN512, NFC_OK);
00178             return;
00179         }
00180     }
00181     if ((irqs & PN512_IRQ_LOW_ALERT) && (ac_buffer_reader_readable(&pPN512->writeBuf) > 0)) {
00182         //Continue to fill FIFO
00183         pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT);
00184 
00185         pn512_transceive_hw_tx_iteration(pPN512, false);
00186         return;
00187     }
00188 
00189     if (irqs & PN512_IRQ_IDLE) {
00190         pn512_irq_clear(pPN512, PN512_IRQ_ERR);
00191 
00192         NFC_ERR("Modem went to idle");
00193 
00194         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00195         pPN512->transceive.mode = pn512_transceive_mode_idle;
00196 
00197         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00198         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00199         pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
00200         return;
00201     }
00202 
00203     //Call back function
00204     pn512_transceive_hw_tx_iteration(pPN512, false);
00205 }
00206 
00207 void pn512_transceive_hw_rx_start(pn512_t *pPN512)
00208 {
00209     uint16_t irqs_en = PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_ERR;
00210     if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
00211         irqs_en |= PN512_IRQ_RF_OFF;
00212     }
00213 
00214     pn512_irq_set(pPN512, irqs_en);
00215 
00216     //Reset buffer except if data should be appended to this -- TODO
00217     ac_buffer_builder_reset(&pPN512->readBufBldr);
00218 
00219     //Queue task to process IRQ
00220     task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
00221               pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
00222     nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
00223                              &pPN512->transceiver.task);
00224 }
00225 
00226 void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData)
00227 {
00228     pn512_t *pPN512 = (pn512_t *) pUserData;
00229 
00230     NFC_DBG("RX task");
00231     if (events & EVENT_ABORTED) {
00232         //Stop command
00233         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00234         pPN512->transceive.mode = pn512_transceive_mode_idle;
00235 
00236         NFC_ERR("Aborted RX");
00237 
00238         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00239         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00240 
00241         pn512_transceive_callback(pPN512, NFC_ERR_ABORTED);
00242         return;
00243     }
00244 
00245     if (events & EVENT_TIMEOUT) {
00246         NFC_WARN("Timeout");
00247         //Stop command
00248         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00249         pPN512->transceive.mode = pn512_transceive_mode_idle;
00250 
00251         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00252         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00253 
00254         //Call callback
00255         pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT);
00256         return;
00257     }
00258 
00259     uint16_t irqs = pn512_irq_get(pPN512);
00260     NFC_DBG("irqs %04x", irqs);
00261     bool collision_detected = false;
00262     if (irqs & PN512_IRQ_ERR) {
00263         pn512_irq_clear(pPN512, PN512_IRQ_ERR);
00264 
00265         uint8_t err_reg = pn512_register_read(pPN512, PN512_REG_ERROR);
00266         NFC_ERR("Got error - error reg is %02X", err_reg);
00267         // if err_reg == 0, sticky error that must have been cleared automatically, continue
00268         if (err_reg != 0) {
00269             //If it's a collsision, flag it but still carry on with RX procedure
00270             collision_detected = true;
00271 
00272             if ((err_reg == 0x08) || (err_reg == 0x0A)) { // Collision (and maybe parity) (and no other error)
00273                 irqs &= ~PN512_IRQ_ERR;
00274                 irqs |= PN512_IRQ_RX;
00275             } else {
00276                 NFC_DBG_BLOCK(
00277                     //Empty FIFO into buffer
00278                     pn512_fifo_read(pPN512, &pPN512->readBufBldr);
00279 
00280                     NFC_DBG("Received");
00281                     ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));
00282 
00283                     NFC_DBG("Computed CRC = %02X %02X", pn512_register_read(pPN512, PN512_REG_CRCRESULT_MSB), pn512_register_read(pPN512, PN512_REG_CRCRESULT_LSB));
00284 
00285                 )
00286 
00287                 //Stop command
00288                 pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00289                 pPN512->transceive.mode = pn512_transceive_mode_idle;
00290 
00291                 pn512_irq_set(pPN512, PN512_IRQ_NONE);
00292                 pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00293 
00294                 //Call callback
00295                 pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM);
00296                 return;
00297             }
00298         }
00299     }
00300     if ((irqs & PN512_IRQ_RX) || (irqs & PN512_IRQ_HIGH_ALERT)) {
00301         //Empty FIFO into buffer
00302         pn512_fifo_read(pPN512, &pPN512->readBufBldr);
00303 
00304         if ((ac_buffer_builder_writable(&pPN512->readBufBldr) == 0) && (pn512_fifo_length(pPN512) > 0)) {
00305             //Stop command
00306             pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00307             pPN512->transceive.mode = pn512_transceive_mode_idle;
00308 
00309             NFC_WARN("RX buffer overflow");
00310 
00311             pn512_irq_set(pPN512, PN512_IRQ_NONE);
00312             pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00313             //Call callback
00314             pn512_transceive_callback(pPN512, NFC_ERR_BUFFER_TOO_SMALL);
00315             return; //overflow
00316         }
00317 
00318         if (irqs & PN512_IRQ_HIGH_ALERT) {
00319             NFC_DBG("High alert");
00320             pn512_irq_clear(pPN512, PN512_IRQ_HIGH_ALERT);
00321         }
00322 
00323         if (irqs & PN512_IRQ_RX) {
00324             pn512_irq_clear(pPN512, PN512_IRQ_RX);
00325 
00326             size_t last_byte_length = pn512_register_read(pPN512, PN512_REG_CONTROL) & 0x7;
00327             if (last_byte_length == 0) {
00328                 last_byte_length = 8;
00329             }
00330             pPN512->readLastByteLength = last_byte_length;
00331 
00332             pn512_irq_set(pPN512, PN512_IRQ_NONE);
00333             pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT);
00334 
00335             NFC_DBG("Received:");
00336             NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));)
00337 
00338             if ((pPN512->transceive.mode == pn512_transceive_mode_target_autocoll) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) {
00339                 //Check if target was activated
00340                 if (!(pn512_register_read(pPN512, PN512_REG_STATUS2) & 0x10)) {
00341                     pPN512->transceive.mode = pn512_transceive_mode_idle;
00342 
00343                     pn512_irq_set(pPN512, PN512_IRQ_NONE);
00344                     pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00345                     //Call callback
00346                     pn512_transceive_callback(pPN512, NFC_ERR_PROTOCOL);
00347                     return;
00348                 }
00349                 //PN512 switches to transceive automatically
00350                 pPN512->transceive.mode = pn512_transceive_mode_transceive;
00351             } else if (pPN512->transceive.mode == pn512_transceive_mode_receive) {
00352                 pPN512->transceive.mode = pn512_transceive_mode_transceive;
00353                 //pn512_cmd_exec(pPN512, PN512_CMD_IDLE); //Useful?
00354             }
00355 
00356             if (!collision_detected) {
00357                 pn512_transceive_callback(pPN512, NFC_OK);
00358             } else {
00359                 pn512_transceive_callback(pPN512, NFC_ERR_COLLISION);
00360             }
00361 
00362             return;
00363         }
00364     }
00365     if (irqs & PN512_IRQ_RF_OFF) {
00366         //Stop command
00367         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00368         pPN512->transceive.mode = pn512_transceive_mode_idle;
00369 
00370         pn512_irq_set(pPN512, PN512_IRQ_NONE);
00371         pn512_irq_clear(pPN512, PN512_IRQ_ALL);
00372 
00373         //Call callback
00374         pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
00375         return;
00376     }
00377 
00378     //Queue task to process IRQ
00379     task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT,
00380               pPN512->timeout, pn512_transceive_hw_rx_task, pPN512);
00381     nfc_scheduler_queue_task(&pPN512->transceiver.scheduler,
00382                              &pPN512->transceiver.task);
00383 }
00384 
00385 void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb)
00386 {
00387     uint16_t irqs_en;
00388 
00389     //Store callback
00390     pPN512->transceive.cb = cb;
00391 
00392     //Clear FIFO
00393     pn512_fifo_clear(pPN512);
00394 
00395     //Clear previous IRQs if present
00396     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);
00397 
00398     if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
00399         //RF off?
00400         if (!(pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x04)) {
00401             //Call callback
00402             pn512_transceive_callback(pPN512, NFC_ERR_FIELD);
00403             return;
00404         }
00405     } else if ((pPN512->transceive.mode != mode) && (mode == pn512_transceive_mode_transceive)) {
00406         pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
00407     }
00408 
00409     pPN512->transceive.mode = mode;
00410 
00411     if (mode == pn512_transceive_mode_receive) {
00412         pn512_cmd_exec(pPN512, PN512_CMD_IDLE);
00413         pn512_transceive_hw_rx_start(pPN512);
00414         pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE);
00415     } else if (mode == pn512_transceive_mode_target_autocoll) {
00416         //Make sure bitframing reg is clean
00417         pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00);
00418 
00419         pn512_transceive_hw_rx_start(pPN512);
00420 
00421         //Start autocoll
00422         pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL);
00423         return;
00424     } else {
00425         NFC_DBG("Sending:");
00426         NFC_DBG_BLOCK(ac_buffer_dump(&pPN512->writeBuf);)
00427 
00428         //Transmit a frame to remote target/initiator
00429         irqs_en = PN512_IRQ_TX | PN512_IRQ_IDLE;
00430         if (PN512_FRAMING_IS_TARGET(pPN512->framing)) {
00431             irqs_en |= PN512_IRQ_RF_OFF;
00432         }
00433 
00434         pn512_irq_set(pPN512, irqs_en);
00435 
00436         pn512_transceive_hw_tx_iteration(pPN512, true);
00437     }
00438 }
00439 
00440 
00441