mirror of https://github.com/ARMmbed/mbed-os.git
Type 4 Target and dependencies implementation
parent
fdd8d0b9b6
commit
d4c29207cc
|
|
@ -30,6 +30,8 @@ namespace nfc {
|
|||
* @{
|
||||
*/
|
||||
|
||||
class Type4RemoteInitiator;
|
||||
|
||||
/**
|
||||
* This base class represents an ISO7816-4 application.
|
||||
*/
|
||||
|
|
@ -85,27 +87,34 @@ namespace nfc {
|
|||
private:
|
||||
CAPDU _command;
|
||||
RAPDU _response;
|
||||
ISO7816App* _app;
|
||||
ISO7816App* _iso7816_app;
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct ISO7816 app instance
|
||||
*/
|
||||
ISO7816App();
|
||||
|
||||
private:
|
||||
friend class Type4RemoteInitiator;
|
||||
|
||||
/**
|
||||
* Retrieve the application's identifier (AID).
|
||||
* AIDs are composed of a RID (Registered Application Provider Identifier) that needs to be registered and a custom suffix.
|
||||
*
|
||||
* @return a pointer to a const buffer containing the application's identifier (AID).
|
||||
*/
|
||||
virtual const ac_buffer_t* get_aid() const;
|
||||
virtual const ac_buffer_t* get_aid() const = 0;
|
||||
|
||||
/**
|
||||
* Called when the application is selected and before any exchange is performed.
|
||||
*/
|
||||
virtual void on_selected();
|
||||
virtual void on_selected() = 0;
|
||||
|
||||
/**
|
||||
* Called when the application is deselected (or link is lost).
|
||||
*/
|
||||
virtual void on_deselected();
|
||||
virtual void on_deselected() = 0;
|
||||
|
||||
/**
|
||||
* Called when an exchange is performed.
|
||||
|
|
@ -113,7 +122,9 @@ namespace nfc {
|
|||
*
|
||||
* @param[in] exchange an instance of the Exchange class populated with the C-APDU which was received
|
||||
*/
|
||||
virtual void on_exchange(Exchange* exchange);
|
||||
virtual void on_exchange(Exchange* exchange) = 0;
|
||||
|
||||
nfc_tech_iso7816_app_t iso7816_app;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -138,6 +138,9 @@ namespace nfc {
|
|||
nfc_err_t cancel_discovery();
|
||||
|
||||
private:
|
||||
friend class NFCRemoteEndpoint;
|
||||
friend class NFCRemoteInitiator;
|
||||
nfc_transceiver_t* transceiver() const;
|
||||
void polling_callback(nfc_err_t ret);
|
||||
|
||||
// Callbacks from NFC stack
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@ namespace nfc {
|
|||
public:
|
||||
/**
|
||||
* Construct a NFCNDEFCapable instance.
|
||||
* @param[in] buffer a bytes array used to store NDEF messages
|
||||
* @param[in] buffer_size the array size in bytes
|
||||
*/
|
||||
NFCNDEFCapable();
|
||||
NFCNDEFCapable(uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* Check if this instance actually supports NDEF content.
|
||||
|
|
@ -88,8 +90,22 @@ namespace nfc {
|
|||
*/
|
||||
void build_ndef_message(ac_buffer_builder_t& buffer_builder);
|
||||
|
||||
/**
|
||||
* Retrieve underlying NDEF message instance
|
||||
* @return pointer to NDEF message instance
|
||||
*/
|
||||
ndef_msg_t* ndef_message();
|
||||
|
||||
private:
|
||||
// Callbacks from NDEF stack
|
||||
static nfc_err_t s_ndef_encode(ndef_msg_t* pTag, buffer_builder_t* pBufferBldr, void* pUserData);
|
||||
static nfc_err_t s_ndef_decode(ndef_msg_t* pTag, buffer_t* pBuffer, void* pUserData);
|
||||
nfc_err_t ndef_encode(buffer_builder_t* pBufferBldr);
|
||||
nfc_err_t ndef_decode(buffer_t* pBuffer);
|
||||
|
||||
|
||||
Delegate* _delegate;
|
||||
ndef_msg_t _ndef_message;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,34 +29,73 @@ namespace nfc {
|
|||
* @{
|
||||
*/
|
||||
|
||||
class NFCController;
|
||||
|
||||
/**
|
||||
* This is the base class for all remote endpoints (initiators and targets)
|
||||
* addressable over the air interface.
|
||||
*/
|
||||
class NFCRemoteEndpoint {
|
||||
public:
|
||||
NFCRemoteEndpoint();
|
||||
|
||||
/**
|
||||
* The NFCRemoteEndpoint base delegate.
|
||||
*/
|
||||
struct Delegate {
|
||||
/**
|
||||
* This method is called when the endpoint is connected
|
||||
*/
|
||||
virtual void on_connected() {};
|
||||
|
||||
/**
|
||||
* This method is called when the endpoint is lost (air interface link disconnnected)
|
||||
*/
|
||||
virtual void on_lost() {};
|
||||
virtual void on_disconnected() {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the endpoint is lost.
|
||||
* @return whether the endpoint is lost
|
||||
* Connect the remote endpoint
|
||||
*
|
||||
* @return NFC_OK or an error code
|
||||
*/
|
||||
bool is_lost() const;
|
||||
virtual nfc_err_t connect() = 0;
|
||||
|
||||
/**
|
||||
* Disconnect the remote endpoint
|
||||
*
|
||||
* @return NFC_OK or an error code
|
||||
*/
|
||||
virtual nfc_err_t disconnect() = 0;
|
||||
|
||||
/**
|
||||
* Check if the endpoint is connected.
|
||||
* @return whether the endpoint is connected
|
||||
*/
|
||||
virtual bool is_connected() const = 0;
|
||||
|
||||
/**
|
||||
* Check if the endpoint is disconnected/lost.
|
||||
* @return whether the endpoint has been disconnected
|
||||
*/
|
||||
virtual bool is_disconnected() const = 0;
|
||||
|
||||
/**
|
||||
* Get the list of RF protocols supported and activated over the air interface.
|
||||
* @return a bitmask of activated protocols
|
||||
*/
|
||||
nfc_rf_protocols_bitmask_t rf_protocols() const;
|
||||
virtual nfc_rf_protocols_bitmask_t rf_protocols() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Mark endpoint as connected
|
||||
*/
|
||||
void connected();
|
||||
|
||||
/**
|
||||
* Mark endpoint as disconnected
|
||||
*/
|
||||
void disconnected();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ namespace nfc {
|
|||
* @{
|
||||
*/
|
||||
|
||||
class NFCController;
|
||||
|
||||
/**
|
||||
* This class represents a remote NFC initiator (the local controller being in target mode).
|
||||
*
|
||||
|
|
@ -40,6 +42,7 @@ namespace nfc {
|
|||
public:
|
||||
/**
|
||||
* Create a NFCRemoteInitiator.
|
||||
*
|
||||
*/
|
||||
NFCRemoteInitiator();
|
||||
virtual ~NFCRemoteInitiator();
|
||||
|
|
@ -48,15 +51,7 @@ namespace nfc {
|
|||
* The NFCRemoteInitiator delegate. Users of the NFCRemoteInitiator class need to implement this delegate's methods to receive events.
|
||||
*/
|
||||
struct Delegate : NFCEndpoint::Delegate, NFCNDEFCapable::Delegate {
|
||||
/**
|
||||
* The controller was selected by the initiator.
|
||||
*/
|
||||
virtual void on_selected() {}
|
||||
|
||||
/**
|
||||
* The controller was deselected by the initiator.
|
||||
*/
|
||||
virtual void on_deselected() {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -64,28 +59,31 @@ namespace nfc {
|
|||
*
|
||||
* @oaram[in] delegate the delegate instance to use
|
||||
*/
|
||||
void set_delegate(Delegate* delegate);
|
||||
void set_remote_initiator_delegate(Delegate* delegate);
|
||||
|
||||
/**
|
||||
* Retrieve the NFC tag type exposed by the controller to communicate with the initiator.
|
||||
*
|
||||
* @return the relevant NFC tag type
|
||||
*/
|
||||
nfc_tag_type_t nfc_tag_type() const;
|
||||
virtual nfc_tag_type_t nfc_tag_type() const = 0;
|
||||
|
||||
/**
|
||||
* Retrieve whether ISO7816 applications are supported by the underlying technology.
|
||||
*
|
||||
* @return whether ISO7816 applications are supported
|
||||
*/
|
||||
bool is_iso7816_supported() const;
|
||||
virtual bool is_iso7816_supported() const = 0;
|
||||
|
||||
/**
|
||||
* Register an ISO7816 application to be used by the initiator.
|
||||
*
|
||||
* @param[in] application a pointer to an ISO7816App instance
|
||||
*/
|
||||
void add_iso7816_application(ISO7816App* application);
|
||||
virtual void add_iso7816_application(ISO7816App* application) = 0;
|
||||
|
||||
private:
|
||||
Delegate* _delegate;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -37,18 +37,39 @@ namespace nfc {
|
|||
/**
|
||||
* This class is an implementation of the Type 4 tag application.
|
||||
*/
|
||||
class Type4RemoteInitiator : public NFCRemoteInitiator, public ISO7816App, public NFCNDEFCapable {
|
||||
class Type4RemoteInitiator : public NFCRemoteInitiator, public NFCNDEFCapable {
|
||||
private:
|
||||
Type4RemoteInitiator(nfc_transceiver_t* transceiver);
|
||||
/**
|
||||
* Create a Type4RemoteInitiator.
|
||||
*
|
||||
* @param[in] controller pointer to the NFCController instance that created this object
|
||||
*/
|
||||
Type4RemoteInitiator(NFCController* controller);
|
||||
|
||||
// NFCRemoteEndpoint implementation
|
||||
virtual nfc_err_t connect();
|
||||
virtual nfc_err_t disconnect();
|
||||
virtual bool is_connected();
|
||||
virtual bool is_disconnected();
|
||||
virtual nfc_rf_protocols_bitmask_t rf_protocols();
|
||||
|
||||
// NFCRemoteInitiator implementation
|
||||
virtual nfc_tag_type_t nfc_tag_type() const;
|
||||
virtual bool is_iso7816_supported() const;
|
||||
virtual void add_iso7816_application(ISO7816App* application);
|
||||
|
||||
// NFCNDEFCapable implementation
|
||||
virtual bool is_ndef_supported() const;
|
||||
|
||||
// ISO7816App implementation
|
||||
virtual const ac_buffer_t* get_aid() const;
|
||||
virtual void on_selected();
|
||||
virtual void on_deselected();
|
||||
virtual void on_exchange(Exchange* exchange);
|
||||
// Callbacks from NFC stack
|
||||
void disconnected_callback(bool deselected);
|
||||
static void s_disconnected_callback(nfc_tech_iso7816_t* pIso7816, bool deselected, void* pUserData);
|
||||
|
||||
NFCController* _controller;
|
||||
bool _is_connected;
|
||||
bool _is_disconnected;
|
||||
nfc_tech_iso7816_t _iso7816;
|
||||
nfc_tech_type4_target_t _type4;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ nfc_err_t NFCController::cancel_discovery()
|
|||
transceiver_abort(_transceiver);
|
||||
}
|
||||
|
||||
nfc_transceiver_t* NFCController::transceiver() const
|
||||
{
|
||||
return _transceiver;
|
||||
}
|
||||
|
||||
void NFCController::polling_callback(nfc_err_t ret)
|
||||
{
|
||||
// Polling has completed
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@
|
|||
#include "acore/buffer_reader.h"
|
||||
#include "acore/buffer_builder.h"
|
||||
|
||||
#include "ndef/ndef.h"
|
||||
|
||||
using namespace mbed;
|
||||
using namespace mbed::nfc;
|
||||
|
||||
NFCNDEFCapable::NFCNDEFCapable() : _delegate(NULL)
|
||||
NFCNDEFCapable::NFCNDEFCapable(uint8_t* buffer, size_t buffer_size) : _delegate(NULL)
|
||||
{
|
||||
|
||||
ndef_msg_init(&_ndef_message, s_encode_callback, s_decode_callback);
|
||||
}
|
||||
|
||||
void NFCNDEFCapable::set_ndef_delegate(NFCNDEFCapable::Delegate* delegate)
|
||||
|
|
@ -49,3 +51,23 @@ void NFCNDEFCapable::build_ndef_message(ac_buffer_builder_t& buffer_builder)
|
|||
ac_buffer_builder_write_n_skip(&buffer_builder, count);
|
||||
}
|
||||
}
|
||||
|
||||
nfc_err_t NFCNDEFCapable::s_ndef_encode(ndef_msg_t* pTag, buffer_builder_t* pBufferBldr, void* pUserData) {
|
||||
NFCNDEFCapable* self = (NFCNDEFCapable*)pUserData;
|
||||
self->ndef_encode(pBufferBldr);
|
||||
}
|
||||
|
||||
nfc_err_t NFCNDEFCapable::s_ndef_decode(ndef_msg_t* pTag, buffer_t* pBuffer, void* pUserData) {
|
||||
NFCNDEFCapable* self = (NFCNDEFCapable*)pUserData;
|
||||
self->ndef_decode(pBuffer);
|
||||
}
|
||||
|
||||
nfc_err_t NFCNDEFCapable::ndef_encode(buffer_builder_t* pBufferBldr) {
|
||||
build_ndef_message(buffer_builder);
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
nfc_err_t NFCNDEFCapable::ndef_decode(buffer_t* pBuffer) {
|
||||
parse_ndef_message(pBuffer);
|
||||
return NFC_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "NFCRemoteEndpoint.h"
|
||||
|
||||
#include "acore/buffer.h"
|
||||
#include "acore/buffer_reader.h"
|
||||
#include "acore/buffer_builder.h"
|
||||
|
||||
#include "stack/transceiver/transceiver.h"
|
||||
|
||||
using namespace mbed;
|
||||
using namespace mbed::nfc;
|
||||
|
||||
NFCRemoteEndpoint::NFCRemoteEndpoint(NFCController* controller) : _controller(controller), _is_lost(false) {
|
||||
|
||||
}
|
||||
|
||||
bool NFCRemoteEndpoint::is_lost() const {
|
||||
return _is_lost;
|
||||
}
|
||||
|
||||
nfc_rf_protocols_bitmask_t NFCRemoteEndpoint::rf_protocols() {
|
||||
nfc_rf_protocols_bitmask_t rf_protocols = {0};
|
||||
nfc_tech_t active_tech = transceiver_get_active_techs(_transceiver);
|
||||
if(!transceiver_is_initiator_mode(_transceiver))
|
||||
{
|
||||
// Note: We only support ISO-DEP for now
|
||||
rf_protocols.target_iso_dep = active_tech.nfc_iso_dep_a || active_tech.nfc_iso_dep_b;
|
||||
}
|
||||
|
||||
return rf_protocols;
|
||||
}
|
||||
|
||||
void NFCRemoteEndpoint::set_lost() {
|
||||
_is_lost = true;
|
||||
}
|
||||
|
||||
NFCController* NFCRemoteEndpoint::nfc_controller() const {
|
||||
return _controller;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "NFCRemoteInitiator.h"
|
||||
|
||||
#include "acore/buffer.h"
|
||||
#include "acore/buffer_reader.h"
|
||||
#include "acore/buffer_builder.h"
|
||||
|
||||
#include "stack/transceiver/transceiver.h"
|
||||
#include "stack/tech/iso7816/iso7816.h"
|
||||
#include "stack/tech/iso7816/iso7816_app.h"
|
||||
|
||||
using namespace mbed;
|
||||
using namespace mbed::nfc;
|
||||
|
||||
NFCRemoteInitiator::NFCRemoteInitiator(NFCController* controller) : NFCRemoteEndpoint(controller) {
|
||||
|
||||
}
|
||||
|
||||
NFCRemoteInitiator::~NFCRemoteInitiator() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NFCRemoteInitiator::set_remote_initiator_delegate(Delegate* delegate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
nfc_tag_type_t NFCRemoteInitiator::nfc_tag_type() const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool NFCRemoteInitiator::is_iso7816_supported() const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NFCRemoteInitiator::add_iso7816_application(ISO7816App* application)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Type4RemoteInitiator.h"
|
||||
|
||||
#include "acore/buffer.h"
|
||||
#include "acore/buffer_reader.h"
|
||||
#include "acore/buffer_builder.h"
|
||||
|
||||
#include "stack/transceiver/transceiver.h"
|
||||
#include "stack/tech/iso7816/iso7816.h"
|
||||
#include "stack/tech/iso7816/iso7816_app.h"
|
||||
#include "stack/tech/type4/type4_target.h"
|
||||
|
||||
using namespace mbed;
|
||||
using namespace mbed::nfc;
|
||||
|
||||
Type4RemoteInitiator::Type4RemoteInitiator(NFCController* controller) :
|
||||
_controller(controller), _is_connected(false) , _is_disconnected(false), _apps(NULL) {
|
||||
// Init ISO7816
|
||||
nfc_tech_iso7816_init(&_iso7816, _controller->transceiver(), &Type4RemoteInitiator::s_disconnected_callback, this);
|
||||
|
||||
// Init Type 4 app
|
||||
nfc_tech_type4_target_init(&_type4, &_iso7816, ndef_message());
|
||||
}
|
||||
|
||||
nfc_err_t Type4RemoteInitiator::connect() {
|
||||
if(_is_connected) {
|
||||
return NFC_BUSY;
|
||||
}
|
||||
|
||||
if(_is_disconnected) {
|
||||
return NFC_ERR_DISCONNECTED;
|
||||
}
|
||||
|
||||
// Connect ISO7816 stack
|
||||
nfc_tech_iso7816_connect(&_iso7816);
|
||||
|
||||
// Call callback as it's a synchronous API
|
||||
connected();
|
||||
}
|
||||
|
||||
nfc_err_t Type4RemoteInitiator::disconnect() {
|
||||
if(!_is_connected) {
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
if(_is_disconnected) {
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
// Disconnect ISO7816 stack
|
||||
nfc_tech_iso7816_disconnect(&_iso7816);
|
||||
}
|
||||
|
||||
bool Type4RemoteInitiator::is_connected() const {
|
||||
return _is_connected;
|
||||
}
|
||||
|
||||
bool Type4RemoteInitiator::is_disconnected() const {
|
||||
return _is_disconnected;
|
||||
}
|
||||
|
||||
nfc_rf_protocols_bitmask_t Type4RemoteInitiator::rf_protocols() {
|
||||
nfc_rf_protocols_bitmask_t rf_protocols = {0};
|
||||
nfc_tech_t active_tech = transceiver_get_active_techs(_transceiver);
|
||||
if(!transceiver_is_initiator_mode(_transceiver))
|
||||
{
|
||||
// We only support ISO-DEP
|
||||
rf_protocols.target_iso_dep = active_tech.nfc_iso_dep_a || active_tech.nfc_iso_dep_b;
|
||||
}
|
||||
|
||||
return rf_protocols;
|
||||
}
|
||||
|
||||
virtual nfc_tag_type_t Type4RemoteInitiator::nfc_tag_type() const {
|
||||
nfc_tech_t active_tech = transceiver_get_active_techs(_transceiver);
|
||||
if(active_tech.nfc_iso_dep_a) {
|
||||
return nfc_tag_type_4a;
|
||||
}
|
||||
else { // if(active_tech.nfc_iso_dep_b)
|
||||
return nfc_tag_type_4b;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Type4RemoteInitiator::is_iso7816_supported() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Type4RemoteInitiator::add_iso7816_application(ISO7816App* application) {
|
||||
nfc_tech_iso7816_add_app(&_iso7816, application->_iso7816_app);
|
||||
}
|
||||
|
||||
virtual bool Type4RemoteInitiator::is_ndef_supported() const {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 ndef.c
|
||||
* \copyright Copyright (c) ARM Ltd 2013
|
||||
* \author Donatien Garnier
|
||||
* \details NDEF tag abstraction
|
||||
*/
|
||||
|
||||
|
||||
#include "inc/nfc.h"
|
||||
#include "ndef.h"
|
||||
|
||||
/** \addtogroup NDEF
|
||||
* @{
|
||||
* \name Generic NDEF Tag
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Initialize NDEF tag abstraction
|
||||
* \param pNdefTag pointer to ndef_tag_t structure to initialize
|
||||
* \param encode function that will be called to generate the NDEF message before sending it to the other party
|
||||
* \param decode function that will be called to parse the NDEF message after receiving it from the other party
|
||||
* \param buffer underlying buffer to use (it should be big enough so that any NDEF message you might need could be stored inside)
|
||||
* \param buffer_size size of the underlying buffer
|
||||
* \param pImpl pointer to actual implementation
|
||||
*/
|
||||
void ndef_msg_init( ndef_msg_t* pNdef, ndef_encode_fn_t encode, ndef_decode_fn_t decode, uint8_t* data, size_t size, void* pUserData )
|
||||
{
|
||||
pNdef->encode = encode;
|
||||
pNdef->decode = decode;
|
||||
buffer_builder_init(&pNdef->bufferBldr, data, size);
|
||||
pNdef->pUserData = pUserData;
|
||||
}
|
||||
|
||||
/** Get NDEF tag implementation
|
||||
* \param pNdefTag pointer to ndef_tag_t structure
|
||||
* \return implementation
|
||||
*/
|
||||
/*
|
||||
void* ndef_tag_impl(ndef_tag_t* pNdefTag)
|
||||
{
|
||||
return pNdefTag->pImpl;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 ndef.h
|
||||
* \copyright Copyright (c) ARM Ltd 2013
|
||||
* \author Donatien Garnier
|
||||
*/
|
||||
|
||||
/** \addtogroup NDEF
|
||||
* @{
|
||||
* \name Generic NDEF Tag
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef NDEF_H_
|
||||
#define NDEF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inc/nfc.h"
|
||||
|
||||
//Generic interface for NDEF messages
|
||||
|
||||
typedef struct __ndef_msg ndef_msg_t;
|
||||
|
||||
/** Function called to generate the tag's content on read (target mode)
|
||||
* \param pTag pointer to ndef_tag_t instance
|
||||
* \param type pMem buffer in which to store the generated content
|
||||
*/
|
||||
typedef nfc_err_t (*ndef_encode_fn_t)(ndef_msg_t* pTag, buffer_builder_t* pBufferBldr, void* pUserData);
|
||||
|
||||
/** Function called to decode the tag's content on write (target mode) or read (reader mode)
|
||||
* \param pTag pointer to ndef_tag_t instance
|
||||
* \param type pMem buffer containing the tag's content
|
||||
*/
|
||||
typedef nfc_err_t (*ndef_decode_fn_t)(ndef_msg_t* pTag, buffer_t* pBuffer, void* pUserData);
|
||||
|
||||
typedef struct __ndef_msg
|
||||
{
|
||||
ndef_encode_fn_t encode;
|
||||
ndef_decode_fn_t decode;
|
||||
buffer_builder_t bufferBldr;
|
||||
void* pUserData;
|
||||
} ndef_msg_t;
|
||||
|
||||
void ndef_msg_init( ndef_msg_t* pNdef, ndef_encode_fn_t encode, ndef_decode_fn_t decode, uint8_t* data, size_t size, void* pUserData );
|
||||
|
||||
static inline nfc_err_t ndef_msg_encode(ndef_msg_t* pNdef)
|
||||
{
|
||||
if(pNdef->encode == NULL)
|
||||
{
|
||||
return NFC_OK;
|
||||
}
|
||||
return pNdef->encode(pNdef, &pNdef->bufferBldr, pNdef->pUserData);
|
||||
}
|
||||
|
||||
static inline nfc_err_t ndef_msg_decode(ndef_msg_t* pNdef)
|
||||
{
|
||||
if(pNdef->decode == NULL)
|
||||
{
|
||||
return NFC_OK;
|
||||
}
|
||||
return pNdef->decode(pNdef, buffer_builder_buffer(&pNdef->bufferBldr), pNdef->pUserData);
|
||||
}
|
||||
|
||||
static inline buffer_builder_t* ndef_msg_buffer_builder(ndef_msg_t* pNdef)
|
||||
{
|
||||
return &pNdef->bufferBldr;
|
||||
}
|
||||
|
||||
//void* ndef_tag_impl(ndef_tag_t* pNdefTag);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NDEF_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* */
|
||||
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* 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 type4_target.c
|
||||
* \copyright Copyright (c) ARM Ltd 2015
|
||||
* \author Donatien Garnier
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "type4_target.c"
|
||||
#endif
|
||||
|
||||
#include "inc/nfc.h"
|
||||
|
||||
#include "type4_target.h"
|
||||
#include "tech/iso7816/iso7816_defs.h"
|
||||
|
||||
#define TYPE4_NDEF_VERSION 2
|
||||
|
||||
#if TYPE4_NDEF_VERSION == 2
|
||||
static const uint8_t aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
|
||||
#else
|
||||
static const uint8_t aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 };
|
||||
#endif
|
||||
#define CC_FILE 0xE103 //Must not be changed
|
||||
#define NDEF_FILE 0xA443
|
||||
#define DEFAULT_FILE 0x0000
|
||||
|
||||
static void app_selected( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData );
|
||||
static void app_deselected( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData );
|
||||
static void app_apdu( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData );
|
||||
|
||||
static nfc_err_t data_read(nfc_tech_type4_target_t* pType4Target, buffer_t* pBuf, uint16_t file, size_t off, size_t len);
|
||||
static nfc_err_t data_write(nfc_tech_type4_target_t* pType4Target, buffer_t* pBuf, uint16_t file, size_t off);
|
||||
|
||||
void nfc_tech_type4_target_init(nfc_tech_type4_target_t* pType4Target, nfc_tech_iso7816_t* pIso7816, ndef_msg_t* pNdef)
|
||||
{
|
||||
buffer_builder_init(&pType4Target->ccFileBldr, pType4Target->ccFileBuf, /*sizeof(pType4Target->ccFileBuf)*/15);
|
||||
|
||||
buffer_builder_init(&pType4Target->ndefFileBldr, pType4Target->ndefFileBuf, /*sizeof(pType4Target->ndefFileBuf)*/2);
|
||||
|
||||
pType4Target->selFile = DEFAULT_FILE;
|
||||
pType4Target->pNdef = pNdef;
|
||||
pType4Target->written = false;
|
||||
|
||||
nfc_tech_iso7816_app_init(&pType4Target->app, pIso7816, aid, sizeof(aid), app_selected, app_deselected, app_apdu, pType4Target);
|
||||
|
||||
nfc_tech_iso7816_add_app(pIso7816, &pType4Target->app);
|
||||
}
|
||||
|
||||
void app_selected( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData )
|
||||
{
|
||||
nfc_tech_type4_target_t* pType4Target = (nfc_tech_type4_target_t*) pUserData;
|
||||
DBG("Selected");
|
||||
|
||||
(void) pIso7816App;
|
||||
|
||||
buffer_builder_reset(ndef_msg_buffer_builder(pType4Target->pNdef));
|
||||
|
||||
//Populate CC file
|
||||
buffer_builder_reset(&pType4Target->ccFileBldr);
|
||||
buffer_builder_write_nu16( &pType4Target->ccFileBldr, 15 ); //CC file is 15 bytes long
|
||||
#if TYPE4_NDEF_VERSION == 2
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 0x20 ); //NFC Forum Tag Type 4 V2.0 compliant
|
||||
#else
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 0x10 ); //NFC Forum Tag Type 4 V1.0 compliant
|
||||
#endif
|
||||
buffer_builder_write_nu16( &pType4Target->ccFileBldr, 256 /* Max frame size */ - 2 /* SW */ - 3 /* ISO-DEP PFB + DID + NAD */ ); //Max data size that can be read from the tag
|
||||
buffer_builder_write_nu16( &pType4Target->ccFileBldr, 256 /* Max frame size */ - 6 /* CLA INS P1 P2 LC LE */ - 3 /* ISO-DEP PFB + DID + NAD */ ); //Max data size that can be written to the tag
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 0x04 ); //NDEF File Control TLV - Type
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 6 ); //NDEF File Control TLV - Length
|
||||
buffer_builder_write_nu16( &pType4Target->ccFileBldr, NDEF_FILE ); //NDEF file id
|
||||
buffer_builder_write_nu16( &pType4Target->ccFileBldr, 2 /* length header */ + buffer_builder_writeable( ndef_msg_buffer_builder(pType4Target->pNdef) ) ); //Max size of NDEF data
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 0x00 ); //Open read access
|
||||
buffer_builder_write_nu8( &pType4Target->ccFileBldr, 0x00 ); //Open write access
|
||||
|
||||
//Encode NDEF file
|
||||
ndef_msg_encode(pType4Target->pNdef);
|
||||
|
||||
//Populate NDEF file
|
||||
buffer_builder_init(&pType4Target->ndefFileBldr, pType4Target->ndefFileBuf, /*sizeof(pType4Target->ndefFileBuf)*/2);
|
||||
|
||||
buffer_builder_write_nu16( &pType4Target->ndefFileBldr, buffer_reader_readable( buffer_builder_buffer(ndef_msg_buffer_builder(pType4Target->pNdef)) ) );
|
||||
|
||||
//Pad NDEF file with 0s
|
||||
while( buffer_builder_writeable( ndef_msg_buffer_builder(pType4Target->pNdef) ) > 0 )
|
||||
{
|
||||
buffer_builder_write_nu8(ndef_msg_buffer_builder(pType4Target->pNdef), 0);
|
||||
}
|
||||
|
||||
//No file selected
|
||||
pType4Target->selFile = DEFAULT_FILE;
|
||||
|
||||
pType4Target->written = false;
|
||||
}
|
||||
|
||||
void app_deselected( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData )
|
||||
{
|
||||
nfc_tech_type4_target_t* pType4Target = (nfc_tech_type4_target_t*) pUserData;
|
||||
|
||||
(void) pIso7816App;
|
||||
|
||||
//Reset buffers
|
||||
buffer_builder_reset(&pType4Target->ccFileBldr);
|
||||
buffer_builder_set_full(&pType4Target->ndefFileBldr); //To read length
|
||||
buffer_builder_reset(ndef_msg_buffer_builder(pType4Target->pNdef));
|
||||
|
||||
DBG("Deselected");
|
||||
|
||||
if(pType4Target->written)
|
||||
{
|
||||
DBG("New content has been written");
|
||||
//Try to parse NDEF
|
||||
//Set buffer length based on file header
|
||||
size_t length = buffer_read_nu16(buffer_builder_buffer(&pType4Target->ndefFileBldr));
|
||||
DBG("Length is %lu", length);
|
||||
if( length < buffer_builder_writeable( ndef_msg_buffer_builder(pType4Target->pNdef) ))
|
||||
{
|
||||
buffer_builder_set_write_offset( ndef_msg_buffer_builder(pType4Target->pNdef), length );
|
||||
ndef_msg_decode(pType4Target->pNdef);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Invalid length");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_apdu( nfc_tech_iso7816_app_t* pIso7816App, void* pUserData )
|
||||
{
|
||||
nfc_tech_type4_target_t* pType4Target = (nfc_tech_type4_target_t*) pUserData;
|
||||
|
||||
//Reset buffers
|
||||
buffer_builder_set_full(&pType4Target->ccFileBldr);
|
||||
buffer_builder_set_full(&pType4Target->ndefFileBldr);
|
||||
buffer_builder_set_full( ndef_msg_buffer_builder(pType4Target->pNdef) ); //Set offset to 0, size to max
|
||||
|
||||
buffer_set_next(buffer_builder_buffer(&pType4Target->ndefFileBldr), buffer_builder_buffer(ndef_msg_buffer_builder(pType4Target->pNdef)));
|
||||
|
||||
//Recover PDU
|
||||
nfc_tech_iso7816_c_apdu_t* pCApdu = nfc_tech_iso7816_app_c_apdu(pIso7816App);
|
||||
nfc_tech_iso7816_r_apdu_t* pRApdu = nfc_tech_iso7816_app_r_apdu(pIso7816App);
|
||||
|
||||
nfc_err_t ret;
|
||||
switch(pCApdu->ins)
|
||||
{
|
||||
case ISO7816_INS_SELECT:
|
||||
switch (pCApdu->p1)
|
||||
{
|
||||
case 0x00: //Selection by ID
|
||||
case 0x02: //Selection by child ID
|
||||
if ( buffer_reader_readable(&pCApdu->dataIn) != 2)
|
||||
{
|
||||
pRApdu->sw = ISO7816_SW_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t file = buffer_read_nu16(&pCApdu->dataIn);
|
||||
if ( file == NDEF_FILE )
|
||||
{
|
||||
pType4Target->selFile = NDEF_FILE;
|
||||
DBG("NDEF File selected");
|
||||
pRApdu->sw = ISO7816_SW_OK;
|
||||
}
|
||||
else if ( file == CC_FILE )
|
||||
{
|
||||
pType4Target->selFile = CC_FILE;
|
||||
DBG("CC File selected");
|
||||
pRApdu->sw = ISO7816_SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
//file = DEFAULT_FILE;
|
||||
DBG("Could not select file %04X", file);
|
||||
pRApdu->sw = ISO7816_SW_NOT_FOUND;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pRApdu->sw = ISO7816_SW_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xB0: //Read binary
|
||||
DBG("Trying to read %d bytes at offset %d from file %04x", pCApdu->maxRespLength, (pCApdu->p1 << 8) | pCApdu->p2, pType4Target->selFile);
|
||||
ret = data_read(pType4Target, &pRApdu->dataOut, pType4Target->selFile, (pCApdu->p1 << 8) | pCApdu->p2, pCApdu->maxRespLength);
|
||||
if (ret == NFC_OK)
|
||||
{
|
||||
DBG("Read %d bytes", buffer_reader_readable(&pRApdu->dataOut));
|
||||
DBG_BLOCK( buffer_dump(&pRApdu->dataOut); )
|
||||
pRApdu->sw = ISO7816_SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Failed with ret code %d", ret);
|
||||
pRApdu->sw = ISO7816_SW_WRONG_LENGTH;
|
||||
}
|
||||
break;
|
||||
case 0xD6: //Update binary
|
||||
DBG("Trying to write %d bytes at offset %d to file %04x", buffer_reader_readable(&pCApdu->dataIn), (pCApdu->p1 << 8) | pCApdu->p2, pType4Target->selFile);
|
||||
ret = data_write(pType4Target, &pCApdu->dataIn, pType4Target->selFile, (pCApdu->p1 << 8) | pCApdu->p2);
|
||||
if (ret == NFC_OK)
|
||||
{
|
||||
DBG("OK");
|
||||
pRApdu->sw = ISO7816_SW_OK;
|
||||
pType4Target->written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Failed with ret code %d", ret);
|
||||
pRApdu->sw = ISO7816_SW_WRONG_LENGTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pRApdu->sw = ISO7816_SW_INVALID_INS;
|
||||
break;
|
||||
}
|
||||
|
||||
//Send reply
|
||||
nfc_tech_iso7816_app_reply(pIso7816App);
|
||||
}
|
||||
|
||||
nfc_err_t data_read(nfc_tech_type4_target_t* pType4Target, buffer_t* pBuf, uint16_t file, size_t off, size_t len)
|
||||
{
|
||||
buffer_t* pFile;
|
||||
switch(file)
|
||||
{
|
||||
case CC_FILE:
|
||||
pFile = buffer_builder_buffer(&pType4Target->ccFileBldr);
|
||||
break;
|
||||
case NDEF_FILE:
|
||||
pFile = buffer_builder_buffer(&pType4Target->ndefFileBldr);
|
||||
break;
|
||||
default:
|
||||
return NFC_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if( off > buffer_reader_readable(pFile) )
|
||||
{
|
||||
return NFC_ERR_LENGTH;
|
||||
}
|
||||
|
||||
buffer_read_n_skip(pFile, off);
|
||||
|
||||
if( len > buffer_reader_readable(pFile))
|
||||
{
|
||||
len = buffer_reader_readable(pFile);
|
||||
}
|
||||
|
||||
buffer_split(pBuf, pFile, pFile, len);
|
||||
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
nfc_err_t data_write(nfc_tech_type4_target_t* pType4Target, buffer_t* pBuf, uint16_t file, size_t off)
|
||||
{
|
||||
buffer_t* pFile;
|
||||
switch(file)
|
||||
{
|
||||
case NDEF_FILE:
|
||||
pFile = buffer_builder_buffer(&pType4Target->ndefFileBldr);
|
||||
break;
|
||||
case CC_FILE: //Cannot write to CC file!
|
||||
default:
|
||||
return NFC_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t len = buffer_reader_readable(pBuf);
|
||||
|
||||
if( off > buffer_reader_readable(pFile) )
|
||||
{
|
||||
return NFC_ERR_LENGTH;
|
||||
}
|
||||
|
||||
buffer_read_n_skip(pFile, off);
|
||||
|
||||
if( len > buffer_reader_readable(pFile) )
|
||||
{
|
||||
len = buffer_reader_readable(pFile);
|
||||
}
|
||||
|
||||
while( len > 0 )
|
||||
{
|
||||
size_t cpy;
|
||||
buffer_builder_t builder;
|
||||
buffer_dup(buffer_builder_buffer(&builder), pFile);
|
||||
buffer_builder_from_buffer(&builder);
|
||||
cpy = buffer_builder_writeable(&builder);
|
||||
cpy = MIN(cpy, len);
|
||||
buffer_builder_copy_n_bytes(&builder, pBuf, cpy);
|
||||
pFile = buffer_next(pFile);
|
||||
len -= cpy;
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 type4_target.h
|
||||
* \copyright Copyright (c) ARM Ltd 2015
|
||||
* \author Donatien Garnier
|
||||
*/
|
||||
|
||||
#ifndef TECH_TYPE4_TYPE4_TARGET_H_
|
||||
#define TECH_TYPE4_TYPE4_TARGET_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inc/nfc.h"
|
||||
|
||||
#include "tech/iso7816/iso7816.h"
|
||||
#include "tech/iso7816/iso7816_app.h"
|
||||
#include "ndef/ndef.h"
|
||||
|
||||
typedef struct nfc_tech_type4_target nfc_tech_type4_target_t;
|
||||
|
||||
typedef void (*nfc_tech_type4_cb)(nfc_tech_type4_target_t* pType4Target, nfc_err_t ret, void* pUserData);
|
||||
|
||||
struct nfc_tech_type4_target
|
||||
{
|
||||
nfc_tech_iso7816_app_t app;
|
||||
|
||||
ndef_msg_t* pNdef;
|
||||
|
||||
uint8_t ccFileBuf[15];
|
||||
buffer_builder_t ccFileBldr;
|
||||
|
||||
uint8_t ndefFileBuf[2];
|
||||
buffer_builder_t ndefFileBldr;
|
||||
|
||||
uint16_t selFile;
|
||||
|
||||
bool written;
|
||||
};
|
||||
|
||||
void nfc_tech_type4_target_init(nfc_tech_type4_target_t* pType4Target, nfc_tech_iso7816_t* pIso7816, ndef_msg_t* pNdef);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TECH_TYPE4_TYPE4_TARGET_H_ */
|
||||
Loading…
Reference in New Issue