NFC

Channel9 : libreria NFC per tutte le piattaforme Windows Embedded su Coding4Fun

2548.Cattura_thumb_20B302B0

Questa volta Creg Duncan ha dovuto dare più spiegazioni del solito per giustificare la prima presenza molto assidua sul blog Coding4Fun !

“Today’s Hardware Friday post is another project from our Friend of the Blog, Paolo Patierno (yeah, yeah, I know, it seems like I’m posting his stuff all the time, but hey, it’s cool stuff) !”

Sono contento che i miei “piccoli” progetti open source riscuotano un discreto successo e questa volta è toccato alla libreria uNFC che implementa il supporto al chip NFC PN532 della NXP per tutte le piattaforme Windows Embedded (dal .Net Micro Framework a Windows Embedded 8 passando per Windows Embedded Compact).

A proposito…questa libreria domani sarà protagonista alla Microsoft Embedded Conference a Napoli in una demo di Smart Home & Smart Factory System !

Come sempre….è un piacere esserci !!

🙂

uNFC library : NFC con le piattaforme Windows Embedded

Dopo i due articoli precedenti che descrivevano il bus SPI ed I2C ed il loro utilizzo nel .Net Micro Framework, è giunto finalmente il momento di vederne un’applicazione pratica con il mio ultimo progetto disponibile su CodePlex : uNFC – NFC library for .Net platforms !

Introduzione : supporto software ed hardware

Questa libreria permette di utilizzare un chip NFC collegato al nostro PC (via seriale) oppure ad un qualsiasi sistema embedded che sia basato su Windows Embedded Compact / Windows Embedded Standard o .Net Micro Framework.

Essa supporta tutti le piattaforme .Net Framework disponibili :

  • .Net Framework 4.0 per PC con Windows 7/8 oppure sistemi embedded basati su Windows Embedded Standard 7 e Windows Embedded 8 Standard;
  • .Net Compact Framework 3.5 / 3.9 per sistemi embedded basati su Windows Embedded Compact 7 e Windows Embedded Compact 2013;
  • .Net Micro Framework 4.2 e 4.3 per sistemi embedded come le board Netduino e .Net Gadgeteer;

Per quanto riguarda l’hardware, essa attualmente supporta il chip NFC PN532 della NXP ma definisce un “piccolo framework” grazie al quale è possibile sviluppare un managed driver per un chip differente senza modificare tutti i livelli superiori che si interfacciano con l’applicazione utente. Il supporto al chip PN532 è garantito con tutti e tre i possibili canali di comunicazione previsti per esso : I2C, SPI ed HSU.

Tipicamente il canale HSU (High Speed UART) viene utilizzato per il collegamento alla porta seriale di un PC o di un sistema basato su Windows Embedded Compact. Le connessioni I2C ed SPI rappresentano le soluzioni migliori nel caso di board basate su .Net Micro Framework.

Lo sviluppo ed il testing è stato effettuato mediante la breakout board RFID/NFC della Elecfreaks e disponibile al seguente link, così come il datasheet ufficiale di riferimento del chip NXP PN532 è disponibile qui. Per il collegamento ad un PC è ovviamente necessario un convertitore USB – Seriale TTL (come questi della FTDI) con i relativi driver, in modo da interfacciarsi al lettore sempre attraverso una porta seriale (in questo caso virtuale).

8664.NFC-Module_thumb_16FC890B

Architettura software

Il managed driver per il chip PN532 è implementato dalla classe PN532 che ha un riferimento ad un’istanza del layer di comunicazione che deve implementare l’interfaccia IPN532CommunicationLayer. In questo modo, abbiamo la possibilità di scegliere il canale da utilizzare fornendo l’istanza di una classe concreta che implementa questa interfaccia al costruttore della classe PN532. Le classe disponibili sono le seguenti :

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

Il lettore basato su questo chip è implementato attraverso la classe NfcPN532Reader che ha un riferimento all’istanza della PN532. Questo classe implementa l’interfaccia INfcReader. Ciò vuol dire che se vogliamo utilizzare un altro chip, dobbiamo seguire questi passi :

  • Realizzare una classe per il driver (come la PN532);
  • Realizzare una classe relativa al lettore che ha un riferimento al driver suddetto ed implementa l’interfaccia INfcReader;

L’esistenza di più classi nell’implementazione per il chip PN532 è strettamente legata al fatto che quest’ultimo disponga di più canali di comunicazione per l’interfacciamento.

5554.ClassDiagram1_thumb_1D435F99

In primo luogo va creata un’istanza di una delle classi relative al canale di comunicazione e ciascuna di esse è strettamente legata alla board sulla quale stiamo lavorando. Successivamente tale istanza va fornita al costruttore della classe PN532 e quest’ultima va passata al costruttore della classe del lettore NfcPN532Reader.

L’interfaccia INfcReader, che essa implementa, espone :

  • il metodo Open() per l’inizializzazione del lettore, specificando il tipo di tag NFC che ci aspettiamo di poter riconoscere;
  • il metodo Close() per chiudere la connessione al lettore;
  • il metodo WriteRead() per scrivere e leggere verso/da il lettore;
  • l’evento TadDetected che viene sollevato quando un tag è riconosciuto dal lettore;
  • l’evento TagLost che viene sollevato quando il lettore perder la connessione con il tag riconosciuto;

Utilizzando gli ultimi due eventi, è possibile registrare un event handler per ciascuno di essi in modo da poter gestire il riconoscimento di un tag da parte del lettore e la disconnessione del tag stesso.

5047.IMG_20140104_093307_thumb_3566C9F4

Di seguito, un esempio di applicazione per la board Netduino Plus sulla quale possiamo utilizzare tutti i canali di comunicazione disponibili nel PN532 ma è ovviamente possibile istanziare ed utilizzare un solo canale alla volta (nella foto in alto oltre al Netduino Plus ed alla board dell’NFC, c’è anche un analizzatore logico usato durante lo sviluppo).

static private INfcReader nfc;

public static void Main()
{
 // write your code here

 // HSU Communication layer
 // MOSI/SDA (TX) --> DIGITAL 0 (RX COM1)
 // SCL/RX (RX) --> DIGITAL 1 (TX COM1)
 IPN532CommunicationLayer commLayer = new PN532CommunicationHSU(SerialPorts.COM1);

 // SPI Communication layer
 // SCK --> DIGITAL 13
 // MISO --> DIGITAL 12
 // MOSI/SDA --> DIGITAL 11
 // SCL/RX -> DIGITAL 10
 // IRQ --> DIGITAL 8
 //IPN532CommunicationLayer commLayer = new PN532CommunicationSPI(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D10, Pins.GPIO_PIN_D8);

 // I2C Communication layer
 // MOSI/SDA --> ANALOG 4 (SDA)
 // SCL/RS --> ANALOG 5 (SCL)
 // IRQ --> DIGITAL 8
 //IPN532CommunicationLayer commLayer = new PN532CommunicationI2C(Pins.GPIO_PIN_D8);

 nfc = new NfcPN532Reader(commLayer);
 nfc.TagDetected += nfc_TagDetected;
 nfc.TagLost += nfc_TagLost;
 nfc.Open(NfcTagType.MifareUltralight);

 InterruptPort button = new InterruptPort(Pins.ONBOARD_SW1, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
 button.OnInterrupt += button_OnInterrupt;

 Thread.Sleep(Timeout.Infinite);
}

static void button_OnInterrupt(uint data1, uint data2, DateTime time)
{
 nfc.Close();
}

In entrambi gli eventi, l’istanza NfcTagEventArgs espone alcune informazioni sul tag riconosciuto (il tipo) ed un riferimento alla connessione al tag. Tale connessione è rappresentata da un’istanza di una classe che deriva dalla classe astratta NfcTagConnection. Attualmente sono disponibili le classi NfcMifareTagConnection e NfcMifareUITagConnection per la gestione rispettivamente del tag Mifare Classic e Mifare Ultralight.

La classe astratta ha a disposizione :

  • la property ID, ossia l’NFC ID del tag;
  • un riferimento all’interfaccia INfcReader che punterà all’istanza NfcPN532Reader utilizzata per attivare il lettore. Attraverso questa istanza, l’oggetto relativo alla connection è in grado di utilizzare il metodo WriteRead() visto prima per scrivere e leggere verso/da il lettore;

0576.ClassDiagram2_thumb_6DA5410C

Tornando all’esempio precedente, attraverso i due event handler possiamo mostrare l’ID del tag riconosciuto e magari effettuare delle operazioni di lettura scrittura sulla base del tipo riconosciuto grazie al corrispondente oggetto NfcTagConnection.

L’esempio mostra che è necessaria una distinzione tra i tipi di tag (anche se entrambi Mifare), in quanto il Mifare Classic prevede un’operazione di autenticazione sul blocco a cui accedere (blocco 8 nell’esempio) che non è prevista dal Mifare Ultralight; i due tag sono diversi anche in termini di struttura della memoria interna.

static void nfc_TagLost(object sender, NfcTagEventArgs e)
{
 Debug.Print("LOST " + HexToString(e.Connection.ID));
}

static void nfc_TagDetected(object sender, NfcTagEventArgs e)
{
 Debug.Print("DETECTED " + HexToString(e.Connection.ID));

 byte[] data;

 switch (e.NfcTagType)
 {
 case NfcTagType.MifareClassic1k:

 NfcMifareTagConnection mifareConn = (NfcMifareTagConnection)e.Connection;
 mifareConn.Authenticate(MifareKeyAuth.KeyA, 0x08, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
 mifareConn.Read(0x08);

 data = new byte[16];
 for (byte i = 0; i < data.Length; i++)
 dataIdea = i;

 mifareConn.Write(0x08, data);

 mifareConn.Read(0x08);
 break;

 case NfcTagType.MifareUltralight:

 NfcMifareUlTagConnection mifareUlConn = (NfcMifareUlTagConnection)e.Connection;

 for (byte i = 0; i < 16; i++)
 {
 byte[] read = mifareUlConn.Read(i);
 }

 mifareUlConn.Read(0x08);

 data = new byte[4];
 for (byte i = 0; i < data.Length; i++)
 dataIdea = i;

 mifareUlConn.Write(0x08, data);

 mifareUlConn.Read(0x08);
 break;

 default:
 break;
 }
}

Conclusioni

Il progetto è appena all’inizio e spero di avere numerosi feedback da coloro che lo utilizzeranno per poterlo migliorare. La possibilità di realizzare un driver per un chip NFC differente ed integrarlo nell’architettura senza alterare i livelli superiori, può essere un punto di forza.

La lettura e la scrittura dei tag NFC è di tipo “raw” e non c’è supporto per NDEF (NFC Data Exchange Format) ma non c’è da preoccuparsi ! Il team di Mopius mi ha aggiunto come developer al progetto NDEF Library ed il mio obiettivo è quello di realizzarne il porting anche su .Net Micro Framework.