After the previous two articles describing the SPI and I2C buses and their use with the .Net Micro Framework, it is now finally time to see a practical application with my latest project available on CodePlex : uNFC – NFC library for .Net platforms !

Introduction : software and hardware support

This library allows to use NFC integrated circuit connected to your PC (via serial) or to embedded system based on Windows Embedded Compact or .Net Micro Framework.

It supports all three types of .Net Framework :

  • .Net Framework 4.0 for PC based on Windows 7 / 8 or embedded systems based on Windows Embedded Standard 7 and Windows Embedded 8 Standard;
  • .Net Compact Framework 3.5 / 3.9 for embedded systems based on Windows Embedded Compact 7 and Windows Embedded Compact 2013;
  • .Net Micro Framework 4.2 and 4.3 for embedded systems like Netduino boards and .Net Gadgeteed boards;

The library supports NXP PN532 chip but it also defines a little framework so that you can develop a managed driver for a new chip and change it without modifying the upper layers and interface to the user application. The support for PN532 chip provides all three possible communication channels for it : I2C, SPI and HSU. Tipically the HSU (High Speed UART) channel is used for connecting to a serial port on PC or Windows Embedded Compact based system. I2C and SPI connections are better for .Net Micro Framework based boards.

The development and testing was made using RFID/NFC Breakout board from Elecfreaks available at following link; The reference for PN532 managed driver is the official NXP user manual available  here. For connection to a PC, you obviously need a converter USB - Serial TTL (such as the FTDI) with their drivers to interface to the reader always through a serial port (in this case virtual).

NFC-Module

Software architecture

The managed driver for the chip PN532 is implemented by the PN532 class that has a reference to an instance of the communication layer that must implement the IPN532CommunicationLayer interface. In this way, we have the ability to choose which channel to use by providing an instance of a concrete class that implements this interface to the PN532 class constructor. The classes available are the following:

  • PN532CommunicationI2C : I2C channel;
  • PN532CommunicationSPI : SPI channel;
  • PN532CommunicationHSU : HSU channel;

The reader based on this chip is implemented through the NfcPN532Reader class that has a reference to the instance of the PN532 class. This class implements the INfcReader interface. This means that if we want to use another chip, we have to follow these steps:

  • Implement a class for the driver (such as PN532);
  • Implement a class for the reader that has a reference to the aforementioned drivers and implements the INfcReader interface;

The presence of multiple classes implementing the PN532 chip is closely related to the fact that the latter has more communication channels for interfacing.

ClassDiagram1

Firstly, it should create an instance of one of the classes related to the communication channel and each of them is closely tied to the board on which we are working. Later that instance be provided to the constructor of the PN532 class and the latter must be passed to the constructor of the NfcPN532Reader class.

The INfcReader interface that it implements, exposes :

  • the Open() method to initialize the reader, specifying the type of NFC tag that we expect to be able to recognize;
  • the Close() method to close the connection to the reader;
  • the WriteRead() method  to write and read to / from the reader;
  • TadDetected event that is raised when a tag is recognized by the reader;
  • TagLost event that is raised when the reader loses the connection with the tags recognized;

Using the last two events, you can register an event handler for each of them so that you can handle the recognition of a tag by the reader in and out of the tag itself.

IMG_20140104_093307

Below, an example of application with the Netduino Plus board on which we can use all available communication channels in PN532 but it is obviously possible to instantiate and use only one channel at a time (in the picture above as well as the Netduino Plus and the NFC board, there is also a logic analyzer used during development).

   1: static private INfcReader nfc;
   2:  
   3: public static void Main()
   4: {
   5:     // write your code here
   6:  
   7:     
   8:     // HSU Communication layer
   9:     // MOSI/SDA (TX) --> DIGITAL 0 (RX COM1)
  10:     // SCL/RX (RX) --> DIGITAL 1 (TX COM1)
  11:     IPN532CommunicationLayer commLayer = new PN532CommunicationHSU(SerialPorts.COM1);
  12:  
  13:     // SPI Communication layer
  14:     // SCK --> DIGITAL 13
  15:     // MISO --> DIGITAL 12
  16:     // MOSI/SDA --> DIGITAL 11
  17:     // SCL/RX -> DIGITAL 10
  18:     // IRQ --> DIGITAL 8
  19:     //IPN532CommunicationLayer commLayer = new PN532CommunicationSPI(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D10, Pins.GPIO_PIN_D8);
  20:  
  21:     // I2C Communication layer
  22:     // MOSI/SDA --> ANALOG 4 (SDA)
  23:     // SCL/RS --> ANALOG 5 (SCL)
  24:     // IRQ --> DIGITAL 8
  25:     //IPN532CommunicationLayer commLayer = new PN532CommunicationI2C(Pins.GPIO_PIN_D8);
  26:                 
  27:     nfc = new NfcPN532Reader(commLayer);
  28:     nfc.TagDetected += nfc_TagDetected;
  29:     nfc.TagLost += nfc_TagLost;
  30:     nfc.Open(NfcTagType.MifareUltralight);
  31:  
  32:     InterruptPort button = new InterruptPort(Pins.ONBOARD_SW1, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
  33:     button.OnInterrupt += button_OnInterrupt;
  34:     
  35:     Thread.Sleep(Timeout.Infinite);
  36: }
  37:  
  38: static void button_OnInterrupt(uint data1, uint data2, DateTime time)
  39: {
  40:     nfc.Close();
  41: }

In both events, the NfcTagEventArgs instance exposes some information on the tag recognized (the type) and a reference to the connection to the tag. This connection is represented by an instance of a class that derives from the NfcTagConnection abstract class. Currently, NfcMifareTagConnection and NfcMifareUITagConnection classes are available for the handling the Mifare Ultralight and Mifare Classic tags.

The abstract class has :

  • ID property (NFC ID tag);
  • a reference to INfcReader interface that will point to the NfcPN532Reader instance used to activate the reader. Through this instance, the connection object  is able to use the WriteRead() method seen before to write and read to / from the reader;

ClassDiagram2

Returning to the previous example, through the two event handlers we can show the ID of the tag that is recognized and maybe perform read-write operations on the basis of the type recognized due to the corresponding NfcTagConnection object.

The example shows that a distinction is needed between tag types (although both Mifare), as the Mifare Classic provides an authentication on the block to be accessed (block 8 in the example) that is not provided by the Mifare Ultralight; the two tags are different also in terms of the structure of the internal memory.

   1: static void nfc_TagLost(object sender, NfcTagEventArgs e)
   2: {
   3:     Debug.Print("LOST " + HexToString(e.Connection.ID));
   4: }
   5:  
   6: static void nfc_TagDetected(object sender, NfcTagEventArgs e)
   7: {
   8:     Debug.Print("DETECTED " + HexToString(e.Connection.ID));
   9:  
  10:     byte data;
  11:  
  12:     switch (e.NfcTagType)
  13:     {
  14:         case NfcTagType.MifareClassic1k:
  15:             
  16:             NfcMifareTagConnection mifareConn = (NfcMifareTagConnection)e.Connection;
  17:             mifareConn.Authenticate(MifareKeyAuth.KeyA, 0x08, new byte { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
  18:             mifareConn.Read(0x08);
  19:  
  20:             data = new byte[16];
  21:             for (byte i = 0; i < data.Length; i++)
  22:                 data[i] = i;
  23:  
  24:             mifareConn.Write(0x08, data);
  25:  
  26:             mifareConn.Read(0x08);
  27:             break;
  28:  
  29:         case NfcTagType.MifareUltralight:
  30:  
  31:             NfcMifareUlTagConnection mifareUlConn = (NfcMifareUlTagConnection)e.Connection;
  32:  
  33:             for (byte i = 0; i < 16; i++)
  34:             {
  35:                 byte read = mifareUlConn.Read(i);
  36:             }
  37:  
  38:             mifareUlConn.Read(0x08);
  39:  
  40:             data = new byte[4];
  41:             for (byte i = 0; i < data.Length; i++)
  42:                 data[i] = i;
  43:  
  44:             mifareUlConn.Write(0x08, data);
  45:  
  46:             mifareUlConn.Read(0x08);
  47:             break;
  48:  
  49:         default:
  50:             break;
  51:     }
  52: }

Conclusion

The project is just beginning and I hope to have many feedback from those who will use it to improve it. The ability to build a driver for a different NFC chip architecture and integrate it without altering the higher levels, it can be a strength.

The reading and writing NFC tags is "raw" and there is no support for NDEF (NFC Data Exchange Format) but do not worry ! The Mopius team added me as a developer to the NDEF Library project and my goal is to realize the porting on .Net Micro Framework.