Discovering NFC Tags

This tutorial describes how to detect specific NFC Forum tags using NFC Discovery API.

Context

The NFC Discovery API provides a mechanism to discover NFC tags at the device's near field using the CNfcTagDiscovery class.

Prerequisites

Before you begin, refer to the following:

Steps

  1. Create a class that inherits from the MNfcTagConnectionListener and CBase classes. For example,

    class CMyTagInitializer : public CBase, public MNfcTagConnectionListener                  
  2. Register for receiving notifications when the specified tag is detected in the proximity of the device using the CNfcTagDiscovery::AddTagConnectionListener() method.

    Note: Only one listener can be added at a time.

    CNfcTagDiscovery* iNfcTagDiscovery;
    iNfcTagDiscovery = CNfcTagDiscovery::NewL( aServer );
    iNfcTagDiscovery->AddTagConnectionListener( MNfcTagConnectionListener&  aListener);
    
  3. Subscribe to the NFC server using the CNfcTagDiscovery::AddTagSubscriptionL() method by specifying the interested tag type.

    iSubscription = CNfcTagSubscription::NewL(); 
    iSubscription->AddConnectionModeL(TNfcConnectionInfo::ENfcType1);
    iNfcTagDiscovery->AddTagSubscriptionL( *iSubscription );
    

    When the tag of the interested type is detected, MNfcTagConnectionListener::TagDetected() is called back. The returned tag is used to open the connection.

    The sequence diagram below illustrates how the tag discovery works:

Example

The following example illustrates how to detect and open a connection to the NFC Forum Type 2 tag.

#include <nfctag.h>
#include <nfctagsubscription.h>
#include <nfctagconnectionlistener.h>
#include <nfcconnectioninfo.h>

// FORWARD DECLARATIONS
class CNfcTagDiscovery;
class MNfcConnection;
class RNfcServer;
class CMyTagInitializer;
class CNfcType2Connection;


// CLASS DECLARATION
// A Class that waits for a tag and then opens a connection to it.
class CMyTagInitializer : public CBase, public MNfcTagConnectionListener
  {
public:
    
    static CMyTagInitializer* NewL( RNfcServer& aServer );
    static CMyTagInitializer* NewLC( RNfcServer& aServer );
    virtual ~CMyTagInitializer();
    
    /*
     * @param aConnection Connection variable that is initialized and opened.
     * @param aMode Type of connection mode that is to be initialized.
     */
    TInt InitConnectionL( MNfcConnection* aConnection, 
                         TNfcConnectionInfo::TNfcConnectionMode aMode );
    
public:
		// From MNfcTagConnectionListener
    
    void TagDetected( MNfcTag* aNfcTag );  
    void TagLost();
    
private:
    
    CMyTagInitializer( RNfcServer& aServer );
    void ConstructL( RNfcServer& aServer );
    
    CActiveScheduler* iScheduler;
    CNfcTagDiscovery* iNfcTagDiscovery;    
    MNfcConnection* iTagConnection;
    CNfcTagSubscription* iSubscription;
    RNfcServer& iServer;
    TNfcConnectionInfo::TNfcConnectionMode iMode;
    MNfcTag* iNfcTag;
   
    };

void CMyTagInitializer::ConstructL( RNfcServer& aServer )
    {
    iScheduler = new (ELeave) CActiveScheduler();
    CActiveScheduler::Install( iScheduler );
    
    iNfcTagDiscovery = CNfcTagDiscovery::NewL( aServer );
    // Add tag connection listener.
    iNfcTagDiscovery->AddTagConnectionListener( *this );
    
    iSubscription = CNfcTagSubscription::NewL();    
    }

TInt CMyTagInitializer::InitConnectionL( MNfcConnection* aConnection,
    TNfcConnectionInfo::TNfcConnectionMode aMode )
    {    
    iTagConnection = aConnection;
    iSubscription->AddConnectionModeL( aMode, 100 );
    // Add tag subscription.
    iNfcTagDiscovery->AddTagSubscriptionL( *iSubscription );

    CActiveScheduler::Start();
    
    return KErrNone; 
    }

void CMyTagInitializer::TagDetected( MNfcTag* aNfcTag )
    {
    iNfcTag = aNfcTag;
    // Open connection to the tag.
    iNfcTag->OpenConnection( *iTagConnection );
    
    CActiveScheduler::Stop();
    }

void CMyTagInitializer::TagLost()
    {
    // No step required here, next attempt to use the connection will fail with an error
    }

CMyTagInitializer::CMyTagInitializer( RNfcServer& aServer ) : 
        iScheduler( NULL ),
        iNfcTagDiscovery( NULL),        
        iTagConnection( NULL ),
        iSubscription( NULL ),
        iServer( aServer ),
        iNfcTag( NULL )
    {    
    }

CMyTagInitializer* CMyTagInitializer::NewL( RNfcServer& aServer )
    {
    CMyTagInitializer* self = NewLC( aServer );
    CleanupStack::Pop( self );  
    return self;
    }
CMyTagInitializer* CMyTagInitializer::NewLC( RNfcServer& aServer )
    {
    CMyTagInitializer* self = new (ELeave) CMyTagInitializer( aServer );
    CleanupStack::PushL( self );
    self->ConstructL( aServer );
    return self;
    }

CMyTagInitializer::~CMyTagInitializer()
    {
    if ( iNfcTagDiscovery )
        {
        iNfcTagDiscovery->RemoveTagConnectionListener();
        iNfcTagDiscovery->RemoveTagSubscription();
        }

    delete iNfcTag;
    delete iSubscription;
    delete iNfcTagDiscovery;
    delete iScheduler;
    }


void mainDoL()
    {
    // Open handle to NFC server
    RNfcServer server;
    server.Open();
    CleanupClosePushL( server );
    
    // Create and start TagConnectionInitializer. Implementation below.
    CMyTagInitializer* initializer = CMyTagInitializer::NewLC( server );
    CNfcType2Connection* connection = CNfcType2Connection::NewLC( server );
	 
    initializer->InitConnectionL( connection, TNfcConnectionInfo::ENfcType2);
    
    //
    // In this point of execution the connection is open and can be used.
    //
    
    CleanupStack::PopAndDestroy( connection );
    CleanupStack::PopAndDestroy( initializer );
    CleanupStack::PopAndDestroy(); // server
    }

TInt E32Main()
    {
    CTrapCleanup* cleanup = CTrapCleanup::New();
    TRAPD( err, mainDoL() );
    delete cleanup;
    
    return err;
    }

Related concepts

Related tasks