Type 4 Target and dependencies implementation

pull/7822/head
Donatien Garnier 2018-08-15 15:35:55 +01:00
parent fdd8d0b9b6
commit d4c29207cc
15 changed files with 906 additions and 32 deletions

View File

@ -29,6 +29,8 @@ namespace nfc {
* @addtogroup 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;
};
/**

View File

@ -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

View File

@ -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;
};
/**

View File

@ -28,6 +28,8 @@ namespace nfc {
* @addtogroup nfc
* @{
*/
class NFCController;
/**
* This is the base class for all remote endpoints (initiators and targets)
@ -35,28 +37,65 @@ namespace nfc {
*/
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
*/
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
*/
bool is_lost() const;
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();
};
/**

View File

@ -30,6 +30,8 @@ namespace nfc {
* @addtogroup 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;
};
/**

View File

@ -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;
};
/**

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)
{
}

View File

@ -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;
}

View File

@ -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;
}
*/
/**
* @}
* @}
* */

View File

@ -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_ */
/**
* @}
* @}
* */

View File

@ -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;
}

View File

@ -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_ */