Arduino 1.0 esce il 30 novembre 2011, dopo sei anni di versioni 0.x la cui numerazione non diceva nulla sulla stabilità dell’API. È una release di cambiamenti piccoli ma incompatibili: certi sketch scritti per la 0023 non compilano più senza ritocchi. Conviene sapere quali, perché chi tiene aggiornate librerie e dispense dovrà metterci mano.

Contesto

Fino alla 0023 il ramo di sviluppo dell’IDE non aveva mai dichiarato un’API stabile. L’ambiente è scritto in Java e nasce da Processing; per compilare si appoggia alla toolchain avr-gcc, e per scrivere il firmware sul microcontrollore attraverso il bootloader usa avrdude. Lo sketch dell’utente, da solo, non è C++ valido: un preprocessore ci aggiunge l’#include dell’header core, genera le forward declaration delle funzioni e produce il file .cpp che poi passa al compilatore.

Per anni questo schema ha retto, ma a un prezzo: ogni release 0.x poteva cambiare nomi di funzione, firme e comportamenti senza alcun preavviso formale. La 1.0 chiude la stagione fissando un punto fermo che gli sketch successivi possono dare per assodato.

Cosa cambia nel formato sketch

Due modifiche toccano subito chiunque abbia file già scritti.

L’estensione passa da .pde a .ino. Il .pde era in comune con Processing, e nasceva confusione quando i due ambienti si ritrovavano gli stessi file in una cartella. L’IDE 1.0 apre ancora i .pde, ma salva in .ino.

L’header core cambia nome, da WProgram.h ad Arduino.h. Il cambiamento riguarda le librerie, non gli sketch: negli sketch è il preprocessore a inserire l’include giusto in automatico, mentre le librerie che facevano un #include "WProgram.h" esplicito vanno corrette. Per far girare lo stesso codice su entrambe le serie si usa una compilazione condizionale sulla macro ARDUINO:

#if ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

La macro ARDUINO esiste già nelle 0.x (valeva 22, poi 23 nelle ultime); in 1.0 vale 100. È il discriminante giusto per il codice che deve compilare sull’una e sull’altra serie.

Le rotture sull’API core

La modifica con più conseguenze pratiche riguarda Serial e, più in generale, la classe Stream, da cui Serial, Wire ed Ethernet ora derivano.

write(), print() e println() ora restituiscono un size_t con il numero di byte scritti, dove prima restituivano void (i dettagli nel riferimento in fondo). Le sottoclassi di Stream vanno adeguate, altrimenti smettono di rispettare l’interfaccia.

La rottura più insidiosa è semantica e non dà errori di compilazione: Serial.print(byte) ora stampa le cifre del numero come caratteri, e per spedire il byte grezzo serve Serial.write(). Il codice che contava sul vecchio comportamento — buttare il valore così com’è sul filo — continua a compilare ma fa un’altra cosa. È il genere di regressione che nessuno segnala finché non guardi l’output su un terminale seriale.

Sulla stessa linea, la classe String è stata riscritta (lavoro di Paul Stoffregen, con altre modifiche sopra). Alcuni metodi che prima restituivano una nuova istanza — trim(), toUpperCase() — ora modificano la stringa sul posto e restituiscono void. Il codice che assegnava il risultato di s.trim() a un’altra variabile va rivisto.

Stream guadagna anche funzioni di parsing del flusso in ingresso: find(), findUntil(), parseInt(), parseFloat(), readBytes(), readBytesUntil(). Sono aggiunte, non rotture, ma portano nel core cose che prima ognuno si riscriveva a mano.

Le librerie standard

Le librerie distribuite con l’IDE seguono lo stesso riallineamento.

Wire (il bus I2C) ora deriva da Stream: usa read(), write(), print(), println() come gli altri stream, al posto dei vecchi send()/receive(). SoftwareSerial è stata riscritta per gestire più porte. La libreria Ethernet aggiunge DHCP e DNS, così un client può prendere l’indirizzo dalla rete invece di averlo cablato nello sketch. La libreria SD ora tiene aperti più file insieme e sa iterare sulle directory.

Per chi mantiene una libreria l’impatto concreto è doppio: aggiornare l’include dell’header con la compilazione condizionale vista sopra, e controllare che le eventuali classi derivate da Stream rispettino le nuove firme di ritorno.

Punto critico

La parte fragile di questa transizione non è la 1.0 in sé, ma il fatto che le due serie convivono. Chi scrive librerie e vuole servire sia chi è rimasto su 0023 sia chi è passato a 1.0 deve far compilare lo stesso sorgente in entrambi gli ambienti, e gli strumenti che il 2011 mette a disposizione sono grezzi: una macro di versione e #if. Non c’è un gestore di dipendenze, non c’è modo di dichiarare “questa libreria richiede Arduino >= 1.0”. Installare una libreria vuol dire ancora copiare una cartella sotto libraries/, e l’incompatibilità salta fuori come errore di compilazione sullo sketch dell’utente finale, lontano da chi l’ha scritta.

Per il materiale didattico il problema è speculare. Le dispense scritte sulle 0.x che mostrano Serial.print(b) per emettere un byte ora insegnano qualcosa che dà un risultato diverso. Va riscritto l’esempio, non solo il numero di versione in copertina.

Implicazioni

Fissare un’API stabile rende col tempo: da qui in avanti uno sketch può dare per buono che digitalWrite(), analogRead(), millis() e l’interfaccia Stream restino quelli, e scrivere un tutorial, una libreria o un corso costa meno se non scade alla release dopo. È la condizione perché un ecosistema di terze parti si accumuli, invece di doversi riscrivere ogni pochi mesi.

Il conto si paga una volta sola, adesso, e lo paga chi ha codice 0.x. Rompere alla 1.0 — prima che la base installata diventi troppo grande — è la scelta più ragionevole: rimandare avrebbe solo gonfiato il numero di sketch e librerie da convertire.

Limiti

Qualcosa resta fuori dal congelamento. Il formato delle librerie non è standardizzato oltre la convenzione della cartella: manca un file di metadati che dichiari versione e dipendenze, quindi la compatibilità si verifica solo provando a compilare. Il preprocessore degli sketch continua a fare trasformazioni implicite — include automatico, forward declaration — che vanno bene nei casi comuni ma confondono quando lo sketch usa costrutti C++ che il generatore di prototipi non gestisce. E l’IDE resta single-sketch: non esiste l’idea di un progetto con più unità di compilazione gestite dall’utente. Sono limiti noti, e la 1.0 non li affronta: fissa l’API, non l’ergonomia del flusso di lavoro.


Immagine di copertina: Una scheda elettronica Arduino Uno con microcontrollore ATmega, connettore USB, jack di alimentazione e file di pin header lungo i… — foto di Osamu Iwasaki, CC BY-SA 2.0 — https://commons.wikimedia.org/wiki/File:Arduino_UNO.jpg