.NetMF

.Net Micro Framework e regular expressions … “out of range exception” !

Sviluppando la mia libreria per l’acesso al Microsoft Azure Service Bus (event hubs, queues, topics/subscriptions) basata su AMQP (e sulla libreria AMQP .Net Lite) mi sono imbattuto in un bug nel codice delle regular expression nel .Net Micro Framework.

Il bug si è verificato per puro caso, quando mi sono ritrovato con una “connection string” all’interno della quale c’era il campo “SharedAccessSignature” che va valorizzato nel caso in cui utilizziamo la connessione AMQP con CBS (Claim Based Security) ossia quando pubblichiamo su event hubs verso un “publisher” endpoint e con sicurezza basata su un SAS token.

In questo caso, il campo suddetto assume un valore abbastanza lungo, basta vedere la “connection string” nella quale mi sono imbattuto :

"Endpoint=sb://ppatiernoeventhubs.servicebus.windows.net/;SharedAccessSignature=SharedAccessSignature sr=http%3a%2f%2fppatiernoeventhubs.servicebus.windows.net%2fnetmftesteventhub%2fPublishers%2fdevice1&sig=FttwMBQt0T1e1hPQIk0TbRSfuPohbTXAi5L8dPSQzbA%3d&se=1306887634&skn=EventSendKeyName;EntityPath=ppatiernoeventhub;Publisher=device1;TransportType=0";

Per estrarre i campi, ho scritto le seguenti righe di codice :

Regex regex = new Regex("([^=;]+)=([^;]+)");

IDictionary connectionStringParams = new Hashtable();

MatchCollection matches = regex.Matches(connectionString);
foreach (Match match in matches)
{
	connectionStringParams[match.Groups[1].Value] = match.Groups[2].Value;
}

Alla seconda iterazione ossia in corrispondenza del campo “SharedAccessSignature” mi sono ritrovato di fronte ad una OutOfRangeException … dovuta a cosa ?

 regex_netmf

Dallo screenshot si evince che il campo “Length” del match riscontrato ha un valore negativo pari a -80. Come mai ?

Ebbene, il valore del campo “SharedAccessSignature” (il SAS token) ha una lunghezza pari a 208 e facendo una semplice sottrazione 128 – 208 è proprio pari a -80.

Probabilmente nel .Net Micro Framework viene utilizzata una variabile del tipo “signed byte” per contenere tale valore che determina un ovvio overflow; la lunghezza massima di un valore in un match è stata probabilmente fissata a 128.

Purtroppo, fino alla correzione del bug che ho provveduto a segnalare, vi consiglio di evitare matching con valori più lunghi di 128 caratteri !

🙂

Netduino : la nuova “terza” generazione anche con Wi-Fi integrato

Ed ora … posso finalmente scrivere qualcosa !! 🙂

Circa due settimane fa ho ricevuto un bel regalo dalla Secret Labs (grazie a Chris Walker) … la nuova scheda Netduino 3 Wi-Fi !

WP_20150429_22_18_19_ProWP_20150429_22_18_35_Pro

Personalmente, ho iniziato la mia “carriera” con il .Net Micro Framework utilizzando le board Netudino e Netduino Plus (prima e seconda generazione), divertendomi tantissimo nello sviluppo di driver gestiti per i componenti ad esse collegati. Con l’esplosione dell’Internet of Things, ho iniziato a sviluppare la mia libreria M2Mqtt ed a testarla sulla versione della board dotata di connessione Ethernet, ma per quanto riguarda il collegamento con i servizi Azure come il Service Bus (event hubs, queues e topics/subscription) mi sono dovuto fermare a causa di un grosso problema: il mancato supporto per il protocollo SSL/TLS ! (necessario per Azure).

Ufficialmente a partire da ieri (ma poche settimane fa per me) … non abbiamo questo limite ! La “terza” generazione delle board della famiglia Netduino supporta i protocolli sicuri come SSL/TLS e quindi fornisce la possibilità di connettersi a tutti i servizi Microsoft Azure ! 🙂

Per ora, solo la versione Wi-Fi è già disponibile su Amazon qui e la versione Ethernet sarà disponibile nel mese di giugno qui.

L’hardware

Parlando della Netduino 3 Wi-Fi, questa scheda ha un STM32 MCU (microcontrollore a 32 bit) Cortex-M4 a 168Mhz con 2 MB di Flash dual-bank e 256 KB di RAM. Naturalmente, a causa del .Net Micro Framework TinyCLR abbiamo fino a 1408 KB per il nostro codice applicativo (in Flash) e circa 164 KB di RAM disponibile. Per me, si tratta di enormi quantità di memoria per le applicazioni embedded complesse !

netduino3wifi

Abbiamo lo stesso pulsante ed il led come le schede precedenti e tutti i pin, 22 pin digitali e analogici come GPIO, che possono essere utilizzate con le seguenti caratteristiche specifiche :

  • Porte UART
  • Segnali PWM
  • Porte SPI
  • Porte I2C

La grande differenza con le schede precedenti è la presenza di 3 porte GoBus 2.0 e sembra che la Secret Labs stia sviluppando nuovi componenti da connettere ad essi. Se volete sapere che cosa è GoBus, potete approfondire con il seguente articolo : sembra essere una caratteristica simile a .Net Gadgeteer ma ha molteplici differenze.

Il modulo Wi-Fi è una grande caratteristica in più perché è completamente integrato sulla scheda senza la necessità di un dispositivo esterno. Il chip è un TI CC3100 (Texas Instruments), con tutte le certificazioni necessarie e supporta 802.11 b/g  n con SSL/TLS ed i tre livelli di sicurezza: aperto, WEP e WPA2.

Ultima caratteristica ma non meno importante è il connettore microSD (fino a 2 GB) per la memorizzazione dei dati.

Il software

Naturalmente le nuove schede Netduino sono tutti basate sulla più recente versione del .Net Micro Framework (4.3 QFE2-RTM) e tutto il codice è open source: si può trovare il porting per Netduino su GitHub.

Una grande differenza con il passato è il Netduino.IP: il nuovo stack TCP/IP per .Net Micro Framework. Come sappiamo, uno dei grandi problemi del .Net Micro Framework è lo stack di rete che non è molto affidabile. Per questo motivo, Secret Labs ha deciso di iniziare il nuovo progetto di cui sopra con lo sviluppo di uno stack TCP/IP completamente gestito ed avere il pieno controllo su di esso. Naturalmente, questo nuovo “nato” è ancora in Technical Preview e sotto test ogni giorno per migliorare le sue featues e prestazioni. La buona notizia è che ha supporta per le classi standard in System.Net  (Socket, HttpWebRequest, …) per garantire retrocompatibilità ed utilizza solo 4 KB di RAM. Come progetto open source, è disponibile su GitHub per due chip Ethernet: il solito Microchip ENC28J60 e Asix AX88796C.

Per quanto riguarda il supporto Wi-Fi, lo stack TCP/IP per il TI CC3100 è in un altro progetto (che sarà assimilato nel Netduino.IP) disponibile qui. In questo caso, abbiamo il pieno supporto per la classe SslStream per SSL/TLS 1.2. Questo progetto è in fase di sviluppo ed ha alcune alcune limitazioni relative al numero di socket aperte simultaneamente e buffer. Le prestazioni potrebbero essere superiori perché la versione corrente usa l’UART per comunicare con il chip ma il supporto SPI arriverà presto.

Dal punto di vista degli sviluppatori, abbiamo Visual Studio 2013 ma è già pronto il supporto per Visual Studio 2015.

Infinite possibilità

Con questa nuova terza generazione, ora abbiamo molte possibilità nell’ambito dell’Internet of Things con la famiglia delle board Netduino. Il grande vantaggio è l’accesso a tutti i servizi Microsoft Azure come Event Hubs (e tutti gli altri servizi del Service Bus) e di tutti i servizi on-line che hanno bisogno di supporto SSL (le Twitter APIs per esempio). Ho già provato la mia board nelle ultime due settimane ed ho avuto buoni risultati usando la libreria AMQP Net Lite per la connessione al Service Bus e con la mia libreria M2Mqtt con un broker MQTT nell’iinviare e ricevere molteplici messaggi. Tutti i miei test sono correlati al lato client dell’uso della board poichè non concordo nell’avere un server su un dispositivo embedded per motivi di sicurezza, quindi non ho approfondito le funzionalità disponibili per sviluppare un server HTTP(S) a bordo. La scheda con tutti i relativi stack software sembra essere affidabile ma la performance potrebbero essere migliorate. So che Chris lavorerà duramente nei prossimi mesi per fornire nuove funzionalità e miglioramenti per darci un prodotto migliore per collegare le “nostre” cose all’Internet degli oggetti in rete.

Quail : una nuova board basata su .Net Micro Framework … in città !

C’è una nuova board per .Net Micro Framework in città !

Negli ultimi mesi, MikroElektronika ha rilasciato la Quail board come una soluzione per la creazione di prototipi hardware utilizzando tutte le migliori caratteristiche del .Net Micro Framework e le relative schede, note come “click” board, per differenti tipi di dispositivi esterni, come i sensori (umidità, temperatura , …), modulo WiFi, OLED e così via.

quail_board

La Quail board si basa sul sull’MCU STM32F427, un Cortex-M4 a 180 Mhz con 2 MB di Flash e 256 KB di RAM con il relativo porting di .Net Micro Framework 4.3. Insieme alla MCU possiamo trovare 8 MB di Flash esterna, una porta USB per una memoria di massa esterna (oltre che alla porta USB per il debug e l’alimentazione della scheda da PC) e 24 “morsetti a vite” (per evitare di utilizzare una “click” board e collegare un dispositivo direttamente alla scheda).
Per semplificare la prototipazione, ha quattro socket su cui è possibile utilizzare a quattro “click” board, senza necessità di saldare i componenti. Queste socket non sono come i socket .NET Gadgeteer che conosciamo ma MikroElektronika ha sviluppato un nuovo tipo di socket standard chiamato MikroBUS.

mikroBUS

Una socket MikroBUS è costituita da due collettori femmina entrambe con 8 pin relativi alle funzioni più utilizzate della MCU :

  • SPI, UART e I2C pin per la comunicazione con altri componenti come sensori e così via;
  • Pins con funzione singola come PWM, interrupt, ingresso analogico, Reset e Chip Select;
  • Pins per l’alimentazione di dispositivi esterni con + 5V, + 3.3V e la massa;

Tutte le schede fornite da MikroElektronika che supportano il MikroBUS sono chiamate “click” board (circa 50 finora) perché è così semplice collegarli alla Quail … con un semplice “click”!

L’idea di questa nuova scheda con il relativo supporto per il .Net Micro Framework è partita grazie ad una collaborazione tra MikroElektronika e un team di professionisti di software e hardware dalla Francia chiamato MikroBUS.Net. Grazie a questa squadra abbiamo a disposizione un SDK per l’utilizzo del MikroBUS a bordo della Quail (come altri SDK per schede Netduino e .Net Gadgeteer) e il codice sorgente (in C#) dei driver scritti per tutte le “click” board.

Oltre alle “click” board è possibile riutilizzare i moduli .NET Gadgeteer (da GHI Electronics), grazie ai G-Adapters che sono in grado di adattare la socket .Net Gadgeteer con la socket MikroBUS. Fino ad oggi non tutti i driver sono disponibili per tutti i moduli, ma il team sta ancora lavorando su di essi. Un’altra caratteristica interessante è la “Virtual Soscket”: è possibile collegare un componente alla scheda utilizzando i morsetti a vite senza usare il MikroBUS. In questo modo è possibile utilizzare il driver fornito, anche se non si ha il componente montato su una “click” board.

Naturalmente è possibile sviluppare le applicazioni utilizzando un IDE di prima classe come Visual Studio 2013 (anche la Community Edition) ed in codice gestito con C # come linguaggio.

Questa è solo una breve introduzione, ma in futuro entreremo nel dettaglio per capire come utilizzare e sviluppare con questa interessantissima scheda !

MQTT & Eclipse Paho : nuove versioni per il client M2Mqtt ed il broker GnatMQ !!

Finalmente la nuova versione M2Mqtt 4.1 è stata rilasciata !

Negli ultimi mesi, la mia libreria è stata messa sotto pressione grazie ai miei amici Olivier Vigliengo (Adeneo) e Nicolas Besson (Microsoft MVP su Windows Embedded, Adeneo). Essi hanno usato il client MQTT per i loro progetti hobbistici, stressandolo non poco !

Dopo un fitto scambio di email e letture di log traces, ho risolto una serie di bug ed aggiunto degli miglioramenti :

  • L’evento di “published” fornisce la flag IsPublished (nell’event args) grazie alla quale poter capire se il messaggio è stato realmente pubblicato oppure no a causa del timeout (l’evento viene sollevato lo stesso);
  • Alcuni cambi “interni” per la gestione degli eventi;
  • Fixato un bug su timeout negativo;
  • Migliorata la stabilità della libreria in condizioni di rete poco affidabile;
  • Fixato un bug sulla gestione delle sessioni;
  • Aggiunte le informazioni di trace sul “queueing” dei messaggi;

Ovviamente, questi cambiamenti hanno avuto il loro impatto anche sul broker GnatMQ che è ancora in Beta ma che mi piacerebbe rilasciare al più presto : spero che le persone che lo usino mi diano dei feedback (sembra che il team di XSocket lo stia usando per fornire il supporto MQTT alla loro piattaforma) 🙂

Come sempre potete trovare M2Mqtt nel progetto Eclipse Paho, su CodePlex e su Nuget. Il broker GnatMQ è disponibile solo su CodePlex. Infine, ho aggiornato anche il progetto M2Mqtt4CE (per Windows Embedded Compact 2013) su CodePlex.

Internet of Things : dal “cos’è” al “come” con le tecnologie Microsoft

IoT_dotnetcampania

Il nuovo portale della community DotNetCampania, di cui faccio parte, è online da qualche settimana e la sezione degli articoli si arricchisce ogni giorno di nuovi contenuti con gli argomenti più svariati, dallo sviluppo web e mobile all’ALM, dai patterns all’Internet Of Things.

Ovviamente, la sezione a cui partecipo più attivamente è quella relativa all’IoT per la quale ad oggi ho scritto i due seguenti articoli :

Nel primo, un’introduzione su cosa sia l’Internet of Things e come i sistemi embedded rientrano in questo nuovo business. Nel secondo, tutte quelle che sono le tecnologie che Microsoft mette a disposizione per la realizzazione di una soluzione IoT completa, dai device (le “cose”) al “Cloud”.

Buona lettura !

🙂

Una nuova casa per il .Net Micro Framework … GitHub !!

netmf_github

Il primo passo “visibile” del nuovo .Net Micro Framework è stato compiuto … finalmente il repository ufficiale delle future versioni è GitHub; viceversa le precedenti versioni del framework rimarrano su CodePlex così come il forum. Ogni bug/issue riportata su CodePlex verrà valutata ed inserita come “work item” in GitHub.

Ricordando la natura da “interprete” del runtime, il progetto è stato battezzato proprio “.Net Micro Framework Interpreter” ma contiene l’interprete, la BCL (Base Class Library) ed il codice nativo per il porting.

Dal punto di vista delle funzionalità, le principali novità della versione 4.4 (Beta) sono :

  • miglioramento della stack di rete con maggiore stabilità nelle connessioni;
  • miglioramenti nel deploy e nel debug (non passerà più un’eternità tra uno step e l’altro);

Per chi lo volesse provare, non è disponibile l’SDK pronto da scaricare ma è necessario ricompilare i sorgenti. Inoltre, non è nemmeno più necessario il Porting Kit (a parte) come nelle versioni precedenti.

Cosa si prospetta per il futuro ?

Si parla di supporto per Visual Studio 2015, introduzione delle API WinRT ed .. udite … udite … supporto per AllJoyn !!

Il meccanismo di “string interning” nel .Net Micro Framework

Consideriamo la seguente semplicissima applicazione console in C# …

 static void Main(string[] args)
 {
   string s1 = "Hello world";
   string s2 = "Hello world";

   Console.WriteLine(s1.Equals(s2));
   Console.WriteLine(ReferenceEquals(s1, s2));
   Console.WriteLine(s1 == s2);

   string s3 = String.Intern(Console.ReadLine());

   Console.WriteLine(s1.Equals(s3));
   Console.WriteLine(ReferenceEquals(s1, s3));
   Console.WriteLine(s1 == s3);

   Console.ReadKey();
 }

Il cui output è il seguente …

string_intern_net

Come sappiamo il metodo Equals() e l’operatore “==” verificano che se le due stringhe contengono lo stesso valore pur avendo un reference diverso (s1 ed s2), per cui è ovvio il risultato “True”. Ma come mai la ReferenceEquals() continua a fornire “True” e non “False” considerando che i due riferimenti sono diversi ?

Bene ! Essi non sono diversi in realtà !

Il .Net Framework fornisce un meccanismo di “string interning” ossia un pool all’interno del quale gestisce le stringhe che hanno il medesimo valore evitando di allocare inutilmente ulteriore memoria. Per questo motivo, s1 ed s2 sono in realtà il medesimo riferimento !

E’ ovvio che, quando una stringa viene acquisita dall’esterno ciò non accade ed è quindi necessario chiedere esplicitamente al framework di cercare la stringa acquisita prima nel pool interno ed eventualmente allocarne una nuova se essa non esiste … questo è l’obiettivo dell’istruzione String.Intern().

Proviamo ora ad eseguire il medesimo codice (a meno di alcune modifiche) sul .Net Micro Framework …

 public static void Main()
 {
    string s1 = "Hello world";
    string s2 = "Hello world";
 
    Debug.Print(s1.Equals(s2).ToString());
    Debug.Print(ReferenceEquals(s1, s2).ToString());
    Debug.Print((s1 == s2).ToString());

    string s3 = String.Intern("Hello world");
    
    Debug.Print(s1.Equals(s3).ToString());
    Debug.Print(ReferenceEquals(s1, s3).ToString());
    Debug.Print((s1 == s3).ToString());
 }

con il seguente risultato …

string_intern_netmf

In questo caso il ReferenceEquals() ci conferma che i due reference sono diversi nel primo caso ma anche utilizzando String.Intern() … come mai ?

Il motivo è semplice … il .Net Micro Framework non supporta il meccanismo di “string interning” e non fornisce un pool interno di stringhe e la risposta è come sempre nell’implementazione nativa. Guardando nel file String.cs, troviamo :

 public static String Intern(String str)
 {
   // We don't support "interning" of strings. So simply return the string.
   return str;
 }

 public static String IsInterned(String str)
 {
   // We don't support "interning" of strings. So simply return the string.
   return str;
 }

Un esplicito commento ci dice che questa funzionalità non è supportata !

Regex portabile fra .Net e .Net Micro Framework … fate attenzione !

Sviluppando su tutte le versioni del .Net Framework (full, compact e micro) mi capita sempre di dover affrontare il problema della portabilità, evitando di utilizzare metodi che non siano disponibili in uno dei tre framework oppure utilizzando le direttive di precompilazione.

Non mi è mai capitato, però, un caso in cui il metodo esista in tutti i framework ma i parametri abbiano un significato diverso … siano addirittura invertiti !!

Il metodo in questione è l’overload di Regex.Split(String, String, RegexOptions) !

La firma è praticamente la stessa confrontando il .Net Framework ed il .Net Micro Framework ma …. con una notevole differenza nei primi due parametri.

Dalla documentazione MSDN del .Net Framework si legge che il primo parametro è la stringa da splittare mentre il secondo è il pattern da applicare.

01

Viceversa, nella documentazione MSDN del .Net Micro Framework si legge che il primo è il pattern ed il secondo è la stringa di input !!

02

Per assicurarmi che l’errore non fosse nella documentazione, ho cercato il codice sorgente del .Net Micro Framework in cui è implementato questo metodo ma purtroppo è arrivata la conferma !

 /// <summary>
 /// Splits the input string at the positions defined by a specified regular expression pattern. Specified options modify the matching operation.
 /// </summary>
 /// <param name="pattern">The pattern to match against</param>
 /// <param name="split">The string to split</param>
 /// <param name="options">The options to utilize during matching</param>
 /// <returns>The result of splitting the input string against the pattern</returns>
 public static string[] Split(string pattern, string split, RegexOptions options)
 {
   return new Regex(pattern, options).Split(split);
 }

Assolutamente strano … anche questa volta ho deciso di aprire una issue sul sito ufficiale del .Net Micro Framework su CodePlex !

Codifica Base64 non standard nel .Net Micro Framework

Come sappiamo, per poter accedere ai servizi Azure, in molti casi è prevista la SAS (Shared Access Signature) Authentication mediante l’invio di un token attraverso il quale otteniamo i diritti per poter eseguire specifiche operazioni.

Tale token si ottiene mediante la costruzione di una stringa contenente una serie di informazioni tra cui l’URI a cui accedere e la scadenza (expiry time) sulla quale calcolare un HMAC (Hash Massage Authentication Code) con SHA256. Il risultato di questa operazione di hashing viene codificato in Base64 ed il risultato ottenuto viene inserito all’interno del token (Shared Access Signature) con un opportuno formato.

L’obiettivo di questo post non è quello di descrivere precisamente la procedura per la determinazione del token ma di mettere in guardia chi utilizza le funzioni di conversione in Base64 messe a disposizione dal .Net Micro Framework.

Eseguendo i miei test con una board FEZ Spider per la connessione al Service Bus, ho riscontrato molte volte la condizione di accesso non autorizzato a causa di un token non correttamente calcolato. Eseguendo la stessa procedura sul PC, tutto funzionava correttamente. Come mai ?

Inizialmente ho pensato ad un errore nel calcolo della firma (HMAC) e solo dopo ho capito che c’era qualcosa che non andava nella codifica Base64.

Sono finalmente riuscito ad estrarre un caso di errore a seguito della firma rappresentata attraverso i seguenti bytes :

byte[] hmac = { 0x16, 0x01, 0x70, 0x76, 0xec, 0xc8, 0xdb, 0x01, 0xf0, 0x6a, 0x60, 0x9a, 0x89, 0x68, 0x6f, 0xef, 0x68, 0x9a, 0xad, 0x10, 0xe7, 0x92, 0x9b, 0xef, 0xfa, 0x10, 0x86, 0x24, 0xf1, 0x72, 0xa6, 0x69 };

Se proviamo a codificare in Base64 l’array di bytes suddetto con il metodo  Convert.ToBase64String(hmac) su PC, il risultato è il seguente :

FgFwduzI2wHwamCaiWhv72iarRDnkpvv+hCGJPFypmk=

Se proviamo ad eseguire la medesima operazione con il .Net Micro Framework, la codifica è la seguente :

FgFwduzI2wHwamCaiWhv72iarRDnkpvv!hCGJPFypmk=

In rosso ed in grassetto ho evidenziato la differenza tra le due codifiche ma … qual’è il motivo ?

Come sempre, la risposta è nell’implementazione nativa del .Net Micro Framework e questa volta nel file Convert.cs all’interno del quale si evincono due “alfabeti” per la codifica Base64 : l’alfabeto standard RFC4648 ed un alfabeto non standard.

 /// <summary>
 /// Conversion array from 6 bit of value into base64 encoded character.
 /// </summary>
 static char[] s_rgchBase64EncodingDefault = new char[]
 {
 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 12 */
 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 24 */
 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 36 */
 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 48 */
 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 60 */
 '8', '9', '!', '*' /* 64 */
 };

 static char[] s_rgchBase64EncodingRFC4648 = new char[]
 {
 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 12 */
 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 24 */
 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 36 */
 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 48 */
 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 60 */
 '8', '9', '+', '/' /* 64 */
 };

 static char[] s_rgchBase64Encoding = s_rgchBase64EncodingDefault;

Questi due alfabeti differiscono per gli ultimi due caratteri che sono “+” e “/” nel primo ma “!” e “*” nel secondo. A quanto pare il carattere “!” è relativo alla codifica Base64 nelle regular expressions mentre “*” é relativo alla medesima codifica nel privacy-enhanced mail.

Dal codice si evince che l’alfabeto di default (s_rgchBase64Encoding) che viene utilzzato non è quello standard !!

Come è possibile risolvere il problema ?

Per fortuna, la classe Convert fornisce la proprietà statica UseRFC4648Encoding che va impostata a true e grazie alla quale viene utilizzato l’alfabeto standard RFC4648 per ogni codifica Base64.

La mia opinione è che sarebbe opportuno invertire la logica in modo che la codifica di default sia quella standard e per questo motivo ho già aperto una issue sul sito ufficiale del .Net Micro Framework su CodePlex.

Voi cosa ne pensate ?

TimeService e .Net Micro Framework : importanza della data ed dell’ora nell’IoT

Nell’ambito dell’Internet of Things e soprattutto quando abbiamo intenzione di proteggere i dati trasmessi da un sistema embedded da occhi indiscreti attraverso gli algoritmi di criptazione (AES, DES, 3DES, RSA, …) e con relativi protocolli di rete (SSL, TLS, DTLS, …), assume un ruolo fondamentale l’impostazione della data ed dell’ora sulla nostra board.

Infatti, gli algoritmi di criptazione si basano fortemente sui generatori di numeri pseudocasuali (PRNG, Pseudo-Random Number Generator), la cui inizializzazione prevede molto spesso l’utilizzo della data ed dell’ora corrente come “seme” della generazione. Essendo generatori pseudo-casuali e non reali è importante che ad ogni avvio il “seme” risulti diverso altrimenti la sequenza generata è la medesima dell’avvio precedente e quindi prevedibile.

Inoltre, nel caso in cui dobbiamo accedere ad un servizio nel cloud per il quale si rende necessaria l’autenticazione attraverso un token (es. accesso SAS, Shared Access Signature, al Microsoft Azure Service Bus), è importante che la richiesta contenga anche un timestamp relativo alla scadenza del token (es. nel caso di un SWT, Simple Web Toke); il timestamp va ovviamente calcolato in base alle proprie esigenze e rispetto ad una data ed ora correttamente impostati nel sistema.

RTC ed (S)NTP server

Le modalità con cui è possibile impostare ed aggiornare la data e l’ora in un sistema embedded sono tipicamente due :

  • L’utilizzo di un RTC (Real Time Clock) che può essere a bordo del microcontrollore oppure una periferica esterna collegata a quest’ultimo mediante un opportuno protocollo (in molti casi I2C);
  • La connessione ad un (S)NTP server (Simple Network Time Protocol) e la relativa sincronizzazione con quest’ultimo con una certa cadenza oppure su richiesta esplicita;

Nel primo caso, l’RTC ha il compito di salvare e fornire al sistema la data e l’ora aggiornati anche con successivi riavvii; nel secondo caso, il sistema si connette al server per ricavare una data ed ora aggiornati senza avere però la possibilità di ritrovarsi con le informazioni corrette al successivo riavvio.

Ovviamente le due modalità possono anche essere utilizzate insieme : al primo avvio il sistema si sincronizza con un server (S)NTP e salva la data nell’RTC a disposizione. All’avvio successivo, essendo l’RTC dotato tipicamente di una batteria al litio, il sistema potrà chiedere ad esso la data e l’ora senza la necessità di una connessione al server (S)NTP. In un qualsiasi momento, si può richiedere la sincronizzazione con relativo aggiornamento della data ed ora del server con l’RTC in locale.

TimeService e .Net Micro Framework

Sviluppando con il .Net Framework, siamo tutti abituati a ricavare la data e l’ora utilizzando la proprietà DateTime.Now; se eseguiamo questa operazione all’avvio su una board con il .Net Micro Framework non avremo sicuramente la data e l’ora corretti !!

L’utilizzo di un RTC non viene fornito nativamente dal framework ma per fortuna abbiamo a disposizione la classe TimeService che ci aiuta nell’utilizzo di un (S)NTP server.

Questa classe mette a disposizione una serie di proprietà, metodi ed eventi i cui principali sono :

  • Settings : proprietà del tipo (TimeServiceSettings) che permette di definire le principali impostazioni del servizio (indirizzi di un server primario e secondario a cui connettersi, intervallo di refresh, sincronizzazione forzata ad ogni avvio, …);
  • SystemTimeChangedTimeSyncFailed : eventi sollevati rispettivamente quando la data e l’ora sono cambiati a seguito di una corretta sincronizzazione oppure quando la sincronizzazione è fallita (es. mancata connessione);
  • SetTimeZoneOffset : metodo per l’impostare l’offset della nostra timezone rispetto a UTC/GMT;
  • Start/Stop : metodi per avviare ed arrestare il servizio di sincronizzazione;
  • UpdateNow : metodo per forzare una sincronizzazione immediata;

Ovviamente, queste rappresentano solo una minima parte di tutte le caratteristiche e funzionalità della classe TimeService.

Una strana anomalia sui settings : un occhio al codice nativo

La classe statica TimeService espone tutte le impostazioni mediante la proprietà Settings che a sua volta contiene una serie di proprietà per le impostazioni stesse. Per poterle impostare, saremo portati ad eseguire un codice di questo tipo

TimeService.Settings.RefreshTime = 10;
TimeService.Settings.ForceSyncAtWakeUp = true;

I valori di default per le proprietà RefreshTime e ForceSyncAtWakeUp sono 50000 e false. Se proviamo ad eseguire il codice appena visto, vedremo che subito dopo le due istruzioni, i valori non sono assolutamente cambiati in 10 e true. Perchè ?

TimeServiceSettings

Il motivo di questo comportamente è l’implementazione nativa del “get” della proprietà Settings. Nel codice sorgente del .Net Micro Framework troviamo :

HRESULT Library_spot_Time_native_Microsoft_SPOT_Time_TimeService::get_Settings___STATIC__MicrosoftSPOTTimeTimeServiceSettings( CLR_RT_StackFrame& stack )
{
 TINYCLR_HEADER(); 

 TimeService_Settings settings;
 CLR_RT_HeapBlock& top = stack.PushValueAndClear();
 CLR_RT_HeapBlock* managedSettings = NULL;

 TINYCLR_CHECK_HRESULT(TimeService_LoadSettings(&settings)); 

 TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex( top, g_CLR_RT_WellKnownTypes.m_TimeServiceSettings ));
 managedSettings = top.Dereference();

 managedSettings[ ManagedSettings::FIELD__PrimaryServerIP ].SetInteger( settings.PrimaryServerIP );
 managedSettings[ ManagedSettings::FIELD__AlternateServerIP ].SetInteger( settings.AlternateServerIP );
 managedSettings[ ManagedSettings::FIELD__RefreshTime ].SetInteger( settings.RefreshTime );
 managedSettings[ ManagedSettings::FIELD__Tolerance ].SetInteger( settings.Tolerance );
 managedSettings[ ManagedSettings::FIELD__ForceSyncAtWakeUp ].SetBoolean( 0 != (settings.Flags & TimeService_Settings_Flags_ForceSyncAtWakeUp) );
 managedSettings[ ManagedSettings::FIELD__AutoDayLightSavings ].SetBoolean( 0 != (settings.Flags & TimeService_Settings_Flags_AutoDST) );

 TINYCLR_NOCLEANUP();
}

Come possiamo notare, la funzione crea una variabile locale “settings” all’interno della quale carica le impostazioni globali. Successivamente, essa copia i campi della variabile locale alla variabile managed da ritornare al nostro codice (attraverso lo stack e per riferimento) … ciò vuol dire che non stiamo impostando i settings globali della classe TimeService ma una copia di una variabile locale di una funzione ! Non so dirvi se può essere considerato un bug o un comportamento voluto ma per impostare i settings correttamente è necessario creare una istanza della classe TimeServiceSettings ed assegnarla alla proprietà Settings di TimeService.

TimeServiceSettings settings = new TimeServiceSettings();
settings.RefreshTime = 10; // every 10 seconds
settings.ForceSyncAtWakeUp = true;
TimeService.Settings = settings;

Un esempio completo

In definitiva, per poter utilizzare in maniera corretta la classe TimeService, possiamo utilizzare il seguente codice.

void ethernetJ11D_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
{
     TimeServiceSettings settings = new TimeServiceSettings();
     settings.RefreshTime = 10; // every 10 seconds
     settings.ForceSyncAtWakeUp = true;
            
     TimeService.SystemTimeChanged += TimeService_SystemTimeChanged;
     TimeService.TimeSyncFailed += TimeService_TimeSyncFailed;
     TimeService.SetTimeZoneOffset(60);

     IPHostEntry hostEntry = Dns.GetHostEntry("time.nist.gov");
     IPAddress[] address = hostEntry.AddressList;
     if (address != null)
         settings.PrimaryServer = address[0].GetAddressBytes();
                
     hostEntry = Dns.GetHostEntry("time.windows.com");
     address = hostEntry.AddressList;
     if (address != null)
         settings.AlternateServer = address[0].GetAddressBytes();
                
     TimeService.Settings = settings;

     TimeService.Start();
}

void TimeService_TimeSyncFailed(object sender, TimeSyncFailedEventArgs e)
{
     Debug.Print("DateTime Sync Failed");
}

void TimeService_SystemTimeChanged(object sender, SystemTimeChangedEventArgs e)
{
     Debug.Print("DateTime = " + DateTime.Now.ToString());
}

Sulla base dell’intervallo di tempo impostato in RefreshTime, verrà sollevato periodicamente l’evento SystemTimeChanged potremmo essere certi che la proprietà DateTime.Now sarà quella correttamente sincronizzata con il server.

Va sottolineato che la classe TimeService basa il suo funzionamento su una parte di codice nativo che è incluso nel firmware delle board della GHI Electronics (FEZ Spider, FEZ Raptor, …) ma non nel firmware del Netduino, per il quale è necessario l’utilizzo di una classe di terze parti che implementi un client (S)NTP.