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 :
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).
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:
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:
The presence of multiple classes implementing the PN532 chip is closely related to the fact that the latter has more communication channels for interfacing.
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 :
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.
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 :
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);
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.
View this page in another language: