/* * 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 isodep_target.c * \copyright Copyright (c) ARM Ltd 2015 * \author Donatien Garnier */ #define __DEBUG__ 0 #ifndef __MODULE__ #define __MODULE__ "isodep_target.c" #endif #include "isodep_target.h" #include "stack/nfc_errors.h" #include "transceiver/transceiver.h" //Private defines #define RATS 0xE0 #define FSDI_TO_FSD(x) (((x)<5)?(((x)<<3) + 16):((x)<8)?(((x)<<5)-96):256) #define FSC_TO_FSCI(x) (((x)<=48)?(((x)-16)>>3):((x)<=128)?(((x)+96)>>5):8) //returns the closest lower or equal value #define DID(x) ((x) & 0x0F) #define FSDI(x) (((x) >> 4) & 0x0F) #define FSCI_TO_FSC(x) FSDI_TO_FSD(x) #define FSD_TO_FSDI(x) FSC_TO_FSCI(x) //#define DI_TO_D(x) (1 << (x)) #define DI_TO_BITRATE(x) ((RF_BITRATE)((x) + RF_BITRATE_106K)) #define GET_FRAME_TYPE(pcb) ((((pcb) & 0xF0) == 0xD0)?PPS_FRAME:(((pcb) & 0xC0) == (0x00 << 6))?I_FRAME:((((pcb) & 0xC0) == (0x2 << 6))?R_FRAME:S_FRAME)) #define I_BLOCK_PCB 0 #define R_BLOCK_PCB 2 #define S_BLOCK_PCB 3 #define PCB_TYPE(pcb) (((pcb)>>6)&0x03) #define BUILD_I_BLOCK_PCB(chaining, cid, nad, block_toggle) ( (0x0 << 6) | (((chaining)?1:0) << 4) \ | (((cid)?1:0) << 3) | (((nad)?1:0) << 2) | (1 << 1) | (((block_toggle)?1:0)) ) #define BUILD_S_BLOCK_PCB(cid, wtx_n_deselect) ( (0x3 << 6) | (((wtx_n_deselect)?0x3:0) << 4) \ | (((cid)?1:0) << 3) | (1 << 1) ) #define BUILD_R_BLOCK_PCB(cid, block_toggle, nak) ( (0x2 << 6) | (1 <<5) | (((nak)?1:0) << 4) \ | (((cid)?1:0) << 3) | (1 << 1) | (((block_toggle)?1:0)) ) #define PCB_IS_CID(pcb) (((pcb) & (1 << 3))?true:false) #define PCB_BLOCK_TOGGLE(pcb) (((pcb) & 1)?true:false) #define PCB_CHAINING(pcb) (((pcb) & 0x10)?true:false) #define PCB_NACK(pcb) (((pcb) & 0x10)?true:false) #define PCB_WTX(pcb) (((pcb)&0x30)==0x30) #define WTXM_DEFAULT 10 //Parameters #define FSC 256 //Maximum frame size the PICC (us) can receive -- TODO should be a parameter at some point -- linked to PN512 buffer #define SFGI 2 //Guard time ~ 1.2ms //#define FWI 6 //Max time before answer is ~ 19.3ms #define FWI 14 //Max time before answer is ~ 19.3ms typedef enum __dep_type dep_type_t; enum __dep_type { dep_type_information, dep_type_response, dep_type_supervisory, }; //Local functions static void dep_init(nfc_tech_isodep_target_t *pIsodepTarget); static bool dep_ready(nfc_tech_isodep_target_t *pIsodepTarget); static void dep_req_information(nfc_tech_isodep_target_t *pIsodepTarget, ac_buffer_t *pReq, bool moreInformation, uint8_t blockNumber); static void dep_req_response(nfc_tech_isodep_target_t *pIsodepTarget, bool ack, uint8_t blockNumber); static void dep_req_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool wtxNDeselect, uint8_t wtxm); static dep_type_t dep_res_type(nfc_tech_isodep_target_t *pIsodepTarget); static void dep_res_information(nfc_tech_isodep_target_t *pIsodepTarget, size_t maxLength, ac_buffer_t **ppRes, bool *pMoreInformation, uint8_t *pBlockNumber); static void dep_res_response(nfc_tech_isodep_target_t *pIsodepTarget, bool *pAck, uint8_t *pBlockNumber); static void dep_res_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool *pWtxNDeselect, uint8_t *pWtxm); static void dep_disconnected(nfc_tech_isodep_target_t *pIsodepTarget, bool deselected); static void command_init(nfc_tech_isodep_target_t *pIsodepTarget); static nfc_err_t command_ats_req(nfc_tech_isodep_target_t *pIsodepTarget); static nfc_err_t command_dep_req(nfc_tech_isodep_target_t *pIsodepTarget); static nfc_err_t command_ats_res(nfc_tech_isodep_target_t *pIsodepTarget); static nfc_err_t command_dep_res(nfc_tech_isodep_target_t *pIsodepTarget); static void command_reply(nfc_tech_isodep_target_t *pIsodepTarget, bool depWait); static void command_transceiver_cb(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData); //High-level Target functions void nfc_tech_isodep_target_init(nfc_tech_isodep_target_t *pIsodepTarget, nfc_transceiver_t *pTransceiver, ac_buffer_t *pHist, nfc_tech_isodep_disconnected_cb disconnectedCb, void *pUserData) { pIsodepTarget->pTransceiver = pTransceiver; pIsodepTarget->pHist = pHist; pIsodepTarget->disconnectedCb = disconnectedCb; pIsodepTarget->pUserData = pUserData; dep_init(pIsodepTarget); command_init(pIsodepTarget); } nfc_err_t nfc_tech_isodep_target_connect(nfc_tech_isodep_target_t *pIsodepTarget) { NFC_DBG("Connecting"); pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_CONNECTING; transceiver_set_crc(pIsodepTarget->pTransceiver, true, true); command_transceiver_cb(pIsodepTarget->pTransceiver, NFC_OK, pIsodepTarget); return NFC_OK; } void nfc_tech_isodep_target_disconnect(nfc_tech_isodep_target_t *pIsodepTarget) { // This should not be called within a callback transceiver_abort(pIsodepTarget->pTransceiver); dep_disconnected(pIsodepTarget, false); } nfc_err_t nfc_tech_isodep_target_transmit(nfc_tech_isodep_target_t *pIsodepTarget, ac_istream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData) { if (pIsodepTarget->dep.pReqStream != NULL) { return NFC_ERR_BUSY; } pIsodepTarget->dep.pResStream = pStream; pIsodepTarget->dep.resCb = cb; pIsodepTarget->dep.pResUserData = pUserData; //Do we need to start transceiving? if (pIsodepTarget->commands.state == ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD) { command_reply(pIsodepTarget, false); //Force reply } return NFC_OK; } nfc_err_t nfc_tech_isodep_target_receive(nfc_tech_isodep_target_t *pIsodepTarget, ac_ostream_t *pStream, nfc_tech_isodep_cb_t cb, void *pUserData) { if (pIsodepTarget->dep.pResStream != NULL) { return NFC_ERR_BUSY; } pIsodepTarget->dep.pReqStream = pStream; pIsodepTarget->dep.reqCb = cb; pIsodepTarget->dep.pReqUserData = pUserData; return NFC_OK; } //DEP Layer void dep_init(nfc_tech_isodep_target_t *pIsodepTarget) { //ac_buffer_init(&pIsodepTarget->dep.res, NULL, 0); pIsodepTarget->dep.pReqStream = NULL; pIsodepTarget->dep.pResStream = NULL; pIsodepTarget->dep.reqCb = NULL; pIsodepTarget->dep.pReqUserData = NULL; pIsodepTarget->dep.resCb = NULL; pIsodepTarget->dep.pResUserData = NULL; pIsodepTarget->dep.blockNumber = 1; //Rule C //pIsodepTarget->dep.pduState = ISO_DEP_TARGET_DEP_PDU_IDLE; pIsodepTarget->dep.chaining = false; pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_IDLE; } bool dep_ready(nfc_tech_isodep_target_t *pIsodepTarget) { //Anything to send back? if (pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED) { return true; } if ((pIsodepTarget->dep.pResStream != NULL)) { return true; } else { return false; } } void dep_req_information(nfc_tech_isodep_target_t *pIsodepTarget, ac_buffer_t *pReq, bool moreInformation, uint8_t blockNumber) { (void) blockNumber; pIsodepTarget->dep.blockNumber++; pIsodepTarget->dep.blockNumber %= 2; // Note: callbacks can call nfc_tech_isodep_target_transmit() - however we must make sure that we wait AFTER this routine has been processed to actually transmit // To do so, reset state to ATS_RES_SENT state pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT; if (!pIsodepTarget->dep.chaining && (pIsodepTarget->dep.pResStream != NULL)) { //Sent the full frame pIsodepTarget->dep.pResStream = NULL; pIsodepTarget->dep.resCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_OK, pIsodepTarget->dep.pResUserData); } if (pIsodepTarget->dep.pReqStream != NULL) { // Pull more ac_ostream_push(pIsodepTarget->dep.pReqStream, pReq, !moreInformation); if (!moreInformation) { //Got the full frame pIsodepTarget->dep.pReqStream = NULL; pIsodepTarget->dep.reqCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_OK, pIsodepTarget->dep.pReqUserData); } } // Update state pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED; pIsodepTarget->dep.chaining = moreInformation; } void dep_req_response(nfc_tech_isodep_target_t *pIsodepTarget, bool ack, uint8_t blockNumber) { if (blockNumber != pIsodepTarget->dep.blockNumber) { //Should be NACK pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_NACK_DIFF_BLOCK_NUMBER_RECEIVED; } else { if (ack) { pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_ACK_RECEIVED; } else { pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED; } } } void dep_req_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool wtxNDeselect, uint8_t wtxm) { (void) wtxm; if (wtxNDeselect) { if ((pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_WTX_SENT)) { NFC_WARN("Unexpected WTX frame"); } pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_WTX_RECEIVED; } else { pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED; } } dep_type_t dep_res_type(nfc_tech_isodep_target_t *pIsodepTarget) { dep_type_t depType; switch (pIsodepTarget->dep.frameState) { case ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED: depType = dep_type_supervisory; //Deselect break; case ISO_DEP_TARGET_DEP_FRAME_INFORMATION_RECEIVED: case ISO_DEP_TARGET_DEP_FRAME_WTX_RECEIVED: if (pIsodepTarget->dep.chaining) { //Need to ack? depType = dep_type_response; } else if (pIsodepTarget->dep.pResStream != NULL) { //Anything to send back? depType = dep_type_information; } else { depType = dep_type_supervisory; //WTX } break; case ISO_DEP_TARGET_DEP_FRAME_ACK_RECEIVED: if ((pIsodepTarget->dep.pResStream != NULL) && (pIsodepTarget->dep.chaining)) { depType = dep_type_information; } else { depType = dep_type_supervisory; //WTX } break; case ISO_DEP_TARGET_DEP_FRAME_NACK_DIFF_BLOCK_NUMBER_RECEIVED: depType = dep_type_response; //Should send ACK break; case ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED: depType = dep_type_information; break; default: depType = dep_type_supervisory; //ATN break; } return depType; } void dep_res_information(nfc_tech_isodep_target_t *pIsodepTarget, size_t maxLength, ac_buffer_t **ppRes, bool *pMoreInformation, uint8_t *pBlockNumber) { *pBlockNumber = pIsodepTarget->dep.blockNumber; if (pIsodepTarget->dep.frameState != ISO_DEP_TARGET_DEP_FRAME_NACK_RECEIVED) { if (pIsodepTarget->dep.pResStream != NULL) { bool lastFrame = true; ac_istream_pull(pIsodepTarget->dep.pResStream, &pIsodepTarget->dep.res, &lastFrame, maxLength); pIsodepTarget->dep.chaining = !lastFrame; } } else { //Retransmit previous frame (leave it as it is) } *ppRes = &pIsodepTarget->dep.res; *pMoreInformation = pIsodepTarget->dep.chaining; pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_INFORMATION_SENT; } void dep_res_response(nfc_tech_isodep_target_t *pIsodepTarget, bool *pAck, uint8_t *pBlockNumber) { //Continue chaining or send ACK *pAck = true; *pBlockNumber = pIsodepTarget->dep.blockNumber; pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_ACK_SENT; } void dep_res_supervisory(nfc_tech_isodep_target_t *pIsodepTarget, bool *pWtxNDeselect, uint8_t *pWtxm) { if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_RECEIVED) { *pWtxNDeselect = false; pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT; } else { *pWtxNDeselect = true; *pWtxm = WTXM_DEFAULT; pIsodepTarget->dep.frameState = ISO_DEP_TARGET_DEP_FRAME_WTX_SENT; } } void dep_disconnected(nfc_tech_isodep_target_t *pIsodepTarget, bool deselected) { //Call callbacks if needed if (pIsodepTarget->dep.pReqStream != NULL) { pIsodepTarget->dep.reqCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_ERR_DISCONNECTED, pIsodepTarget->dep.pReqUserData); pIsodepTarget->dep.pReqStream = NULL; } if (pIsodepTarget->dep.pReqStream != NULL) { pIsodepTarget->dep.resCb((nfc_tech_isodep_t *)pIsodepTarget, NFC_ERR_DISCONNECTED, pIsodepTarget->dep.pResUserData); pIsodepTarget->dep.pResStream = NULL; } if (pIsodepTarget->commands.state != ISO_DEP_TARGET_COMMANDS_DISCONNECTED) { pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DISCONNECTED; pIsodepTarget->disconnectedCb((nfc_tech_isodep_t *)pIsodepTarget, deselected, pIsodepTarget->pUserData); } } //Commands Layer void command_init(nfc_tech_isodep_target_t *pIsodepTarget) { ac_buffer_builder_init(&pIsodepTarget->commands.respBldr, pIsodepTarget->commands.respBuf, sizeof(pIsodepTarget->commands.respBuf)); pIsodepTarget->commands.pReq = NULL; // Update if/when we support DIDs //pIsodepTarget->commands.did = 0; //pIsodepTarget->commands.didUsed = false; pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DISCONNECTED; pIsodepTarget->commands.inPayloadSize = 0; } nfc_err_t command_ats_req(nfc_tech_isodep_target_t *pIsodepTarget) { //Check we are in a correct state -- this should be the first command received if (pIsodepTarget->commands.state != ISO_DEP_TARGET_COMMANDS_CONNECTING) { return NFC_ERR_PROTOCOL; } if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 2) { NFC_ERR("Payload too short"); return NFC_ERR_PROTOCOL; } ac_buffer_read_n_skip(pIsodepTarget->commands.pReq, 1); uint8_t b = ac_buffer_read_nu8(pIsodepTarget->commands.pReq); //Save DID -- not supported for now //pIsodepTarget->commands.did = DID(b); uint8_t fsdi = FSDI(b); pIsodepTarget->commands.inPayloadSize = FSDI_TO_FSD(fsdi); pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_REQ_RECVD; return NFC_OK; } nfc_err_t command_dep_req(nfc_tech_isodep_target_t *pIsodepTarget) { if (pIsodepTarget->commands.state < ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT) { return NFC_ERR_PROTOCOL; } if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 1) { NFC_ERR("Payload too short"); return NFC_ERR_PROTOCOL; } uint8_t pcb = ac_buffer_read_nu8(pIsodepTarget->commands.pReq); // Udpate if/when we support DIDs /* if( pfb & PFB_DID ) { uint8_t did = ac_buffer_read_nu8(pIsodepTarget->commands.pReq); if( pIsodepTarget->commands.did != did ) { //Not for us return NFC_ERR_PROTOCOL; } pIsodepTarget->commands.didUsed = true; } else { pIsodepTarget->commands.didUsed = false; } if( pfb & PFB_NAD ) { ac_buffer_read_nu8(pIsodepTarget->commands.pReq); //Skip NAD } */ uint8_t wtxm = 0; switch (PCB_TYPE(pcb)) { case I_BLOCK_PCB: dep_req_information(pIsodepTarget, pIsodepTarget->commands.pReq, PCB_CHAINING(pcb), PCB_BLOCK_TOGGLE(pcb)); break; case R_BLOCK_PCB: dep_req_response(pIsodepTarget, !PCB_NACK(pcb), PCB_BLOCK_TOGGLE(pcb)); break; case S_BLOCK_PCB: if (PCB_WTX(pcb)) { if (ac_buffer_reader_readable(pIsodepTarget->commands.pReq) < 1) { NFC_ERR("Payload too short"); return NFC_ERR_PROTOCOL; } wtxm = ac_buffer_read_nu8(pIsodepTarget->commands.pReq); } dep_req_supervisory(pIsodepTarget, PCB_WTX(pcb), wtxm); break; default: NFC_ERR("PCB is invalid"); return NFC_ERR_PROTOCOL; } pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD; return NFC_OK; } nfc_err_t command_ats_res(nfc_tech_isodep_target_t *pIsodepTarget) { //Send ATS back if (ac_buffer_builder_writable(&pIsodepTarget->commands.respBldr) < 5) { return NFC_ERR_BUFFER_TOO_SMALL; } ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (5 + ac_buffer_size(pIsodepTarget->pHist)) & 0xFF); //T0 ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0x7 << 4) | FSC_TO_FSCI(FSC)); //TA(1), TB(1) and TC(1) are transmitted //TA(1) //For now only 106kbps supported ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (1 << 7) | (0x0 << 4) | 0x0); //TODO when supporting other bitrates //ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 7) | (0x3 << 4) | 0x3); //106, 212, 414 kbps bitrates //TB(1) ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (FWI << 4) | SFGI); //Specify guard-time and time between frames //TC(1) ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, (0 << 1) | 0); //DID not supported, NAD not supported ac_buffer_set_next(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr), pIsodepTarget->pHist); //Queue general bytes pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_ATS_RES_SENT; //TODO PPS return NFC_OK; } nfc_err_t command_dep_res(nfc_tech_isodep_target_t *pIsodepTarget) { uint8_t pcb = 0; // If/when supporting DIDs /* if( pIsodepTarget->commands.didUsed ) { pcb |= PFB_DID; }*/ ac_buffer_t *pDepBuf = NULL; bool moreInformation = false; bool ack = false; bool wtxNDeselect = false; uint8_t wtxm = 0; uint8_t blockNumber = 0; size_t maxLength = pIsodepTarget->commands.inPayloadSize - 1; switch (dep_res_type(pIsodepTarget)) { case dep_type_information: dep_res_information(pIsodepTarget, maxLength, &pDepBuf, &moreInformation, &blockNumber); pcb = BUILD_I_BLOCK_PCB(moreInformation, false, false, blockNumber); break; case dep_type_response: dep_res_response(pIsodepTarget, &ack, &blockNumber); pcb = BUILD_R_BLOCK_PCB(0, blockNumber, !ack); break; case dep_type_supervisory: dep_res_supervisory(pIsodepTarget, &wtxNDeselect, &wtxm); pcb = BUILD_S_BLOCK_PCB(0, wtxNDeselect); break; } ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pcb); /* if( pIsodepTarget->commands.didUsed ) { ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, pIsodepTarget->commands.did); } */ if (pDepBuf != NULL) { ac_buffer_set_next(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr), pDepBuf); } else if (wtxNDeselect) { ac_buffer_builder_write_nu8(&pIsodepTarget->commands.respBldr, wtxm); } pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_DEP_RES_SENT; return NFC_OK; } void command_reply(nfc_tech_isodep_target_t *pIsodepTarget, bool depWait) { nfc_err_t ret; //Check whether we want to reply or wait for the higher layer to send us something if ((pIsodepTarget->commands.state == ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD) && depWait && !dep_ready(pIsodepTarget)) { return; } //Reply ac_buffer_builder_reset(&pIsodepTarget->commands.respBldr); switch (pIsodepTarget->commands.state) { case ISO_DEP_TARGET_COMMANDS_ATS_REQ_RECVD: ret = command_ats_res(pIsodepTarget); break; case ISO_DEP_TARGET_COMMANDS_DEP_REQ_RECVD: ret = command_dep_res(pIsodepTarget); break; default: NFC_ERR("Unknown state %d", pIsodepTarget->commands.state); //Go back to receive mode nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget); return; } if (ret) { NFC_ERR("Error %d", ret); //Go back to receive mode nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget); return; } NFC_DBG("Transceive"); if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT) { transceiver_set_transceive_options(pIsodepTarget->pTransceiver, true, false, true); } else { transceiver_set_transceive_options(pIsodepTarget->pTransceiver, true, true, false); } NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr));) //Send next frame transceiver_set_write(pIsodepTarget->pTransceiver, ac_buffer_builder_buffer(&pIsodepTarget->commands.respBldr)); nfc_transceiver_transceive(pIsodepTarget->pTransceiver, command_transceiver_cb, pIsodepTarget); NFC_DBG("Processed"); } void command_transceiver_cb(nfc_transceiver_t *pTransceiver, nfc_err_t ret, void *pUserData) { nfc_tech_isodep_target_t *pIsodepTarget = (nfc_tech_isodep_target_t *) pUserData; if (ret == NFC_ERR_ABORTED) { // Just return return; } if (pIsodepTarget->dep.frameState == ISO_DEP_TARGET_DEP_FRAME_DESELECT_SENT) { NFC_DBG("Deselect sent and re-polled: %u", ret); //We are now disconnected (deselected) //Reset status dep_init(pIsodepTarget); command_init(pIsodepTarget); transceiver_set_crc(pIsodepTarget->pTransceiver, true, true); pIsodepTarget->commands.state = ISO_DEP_TARGET_COMMANDS_CONNECTING; //Call so that we can reinit higher layer dep_disconnected(pIsodepTarget, true); //This will call us again return; } //Prepare default empty reply transceiver_set_write(pTransceiver, NULL); transceiver_set_transceive_options(pTransceiver, false, true, false); if (ret == NFC_ERR_FIELD) { NFC_WARN("Lost initiator"); dep_disconnected(pIsodepTarget, false); return; } else if (ret) { //We should ignore this error and wait for another frame NFC_WARN("Got invalid frame (error %d)", ret); nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget); return; } NFC_DBG("Reading data from initiator"); ac_buffer_t *pDataInitiator = transceiver_get_read(pTransceiver); //In buffer NFC_DBG_BLOCK(ac_buffer_dump(pDataInitiator);) //Framing is handled by transceiver if ((ac_buffer_reader_readable(pDataInitiator) < 1)) { NFC_ERR("Empty initiator message"); //Go back to receive mode nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget); return; } pIsodepTarget->commands.pReq = pDataInitiator; //Duplicate to peek on req ac_buffer_t dataInitiatorDup; ac_buffer_dup(&dataInitiatorDup, pDataInitiator); uint8_t req = ac_buffer_read_nu8(&dataInitiatorDup); switch (req) { case RATS: ret = command_ats_req(pIsodepTarget); break; default: ret = command_dep_req(pIsodepTarget); break; } if (ret) { NFC_ERR("Error %d", ret); //Go back to receive mode nfc_transceiver_transceive(pTransceiver, command_transceiver_cb, pIsodepTarget); return; } NFC_DBG("Reply"); //Reply command_reply(pIsodepTarget, true); //Make sure we send a WTX frame if we cannot respond straight away }