Chrome App e comunicazione seriale

by luca
9 comments

Introduzione

Durante lo sviluppo dei miei progetti, mi capita spesso di dover progettare una interfaccia utente (GUI) che dialoga via seriale con i dispositivi che realizzo.

In passato ho scelto di realizzare tali interfacce in C# utilizzando il Framework .Net, framework che consente uno sviluppo molto rapido, grandi possibilità di personalizzazione (come l’uso di font custom nella GUI di RTCSetup) e la capacità di accedere ai vari elementi del sistema operativo, quali la systray (vedi la GUI di Type4Me).

rtcsetup-gui

Mi sono però chiesto come poter realizzare una interfaccia cross-platform, in modo che possa essere utilizzata anche da utenti Linux e Mac. La prima possibilità è utilizzare un linguaggio di sviluppo che abbia un compilatore/interprete per ogni sistema operativo, come Java (volendo esiste anche il progetto Mono per il Framework .Net) o Phyton. Sviluppare GUI con tali linguaggi richiede però l’utilizzo di framework dedicati, spesso di terze parti. Java inoltre ha solo definito le specifiche relative alle API di comunicazione seriale (javax.comm); è quindi necessario adottare una libreria esterna (la più famosa è RxTx) che le implementi.

Oggi voglio invece presentarvi una alternativa che non richiede librerie esterne e che consente lo sviluppo di applicazioni cross-platform con le medesime tecniche di creazione di un sito web: le Chrome Apps.

L’utilizzo di una Chrome App è stata ad esempio la scelta del team di sviluppo di Cleanflight, uno dei più famosi firmware per schede di controllo di multicotteri.

Chrome App

Una Chrome App è essenzialmente una applicazione, sviluppata utilizzando le tecnologie web (HTML5, CSS, Javascript) che viene eseguita dal motore del browser Chrome.

I vantaggi rispetto ad un sito web sono:

[checklist]

  • maggiore integrazione con il desktop (no barra degli indirizzi…)
  • raggruppamento in un Launcher dedicato (vedi screenshot sotto)
  • possibilità di interfacciarsi con l’hardware (ad esempio le porte seriali)

[/checklist]

chrome-launcher

Struttura di una Chrome App

Una Chrome App è formata da 3 elementi:

  • il file manifest, che contiene i metadati della applicazione (nome, versione, descrizione…)
  • lo script di background che si occupa di creare l’interfaccia della app
  • l’interfaccia, composta da pagine HTML, librerie javascript, fogli di stile (CSS)…

Ho preparato una app di esempio che “simula” il Serial Monitor dell’IDE di Arduino. La app è disponibile sul chrome web store e il suo codice sorgente nel mio repository Github.

Vediamo gli elementi nel dettaglio.

Il manifest.json contiene i metadati. Molto importante è la dichiarazione che andremo ad utilizzare la libreria serial e il nome del nostro script di background:

chrome-manifest

Lo script di background non fa altro che creare una finestra di 600 x 500 pixels non ridimensionabile e di aprire all’interno di tale finestra la pagina window.html:

chrome-background

L’applicazione principale è quindi composta da 3 files:

  • window.html, pagina HTML di base
  • main.js, funzioni javascript
  • main.css, foglio di stile per i vari elementi grafici

Ho inoltre utilizzato la libreria jQuery e il suo plugin jQuery.simplemodal per visualizzare i vari popup.

Accedere alle porte seriali

Per accedere via javascript alle porte seriali del PC, Chrome mette a disposizione le API chrome.serial.

Iniziamo a elencare le porte seriali disponibili sul PC e ad aggiungerle ad una combobox in modo che l’utente possa selezionare quella desiderata:

chrome.serial.getDevices(function(ports) {
 
	for (var i = 0; i < ports.length; i++) {
		var portName = ports[i].path;
		var newOption = '' + portName + '';
		var newOption = '<option value="' + portName + '">' + portName + '</option>';
		$("#serial_ports_combobox").append(newOption);
	}
});

chrome-serial-choose

Il collegamento alla porta seriale scelta avviene chiamando il metodo connect:

chrome.serial.connect(selectedPort, connectionOptions, onConnect);

A tale metodo va passato un array (connectionOptions) contenente le impostazioni della porta:

var connectionOptions = {
	"bitrate": 9600,
	"dataBits": "eight",
	"parityBit": "no",
	"stopBits": "one",
	"receiveTimeout": 500,
	"sendTimeout": 500
};

Una volta collegati, è possibile inviare dati con il metodo send:

chrome.serial.send(connectionId, convertStringToArrayBuffer(textToSend), function(sendInfo) {
	if(sendInfo.error) $.modal('<div id="title">Unable to send data: ' + sendInfo.error + '</div>')
});

In caso di errore viene valorizzato sendInfo.error ed è quindi possibile gestirlo (nell’esempio sopra viene visualizzato un popup di errore).

Chi programma in javascript sa che una caratteristica fondamentale di tale linguaggio è l’essere asincrono. La ricezione di dati dalla seriale segue proprio questo paradigma. Per prima cosa è necessario aggiungere un listener (una nostra funzione) all’evento onReceive:

chrome.serial.onReceive.addListener(onReceive);

La funzione onReceive() sarà quindi chiamata ogni volta che un nuovo dato è ricevuto sulla porta seriale:

function onReceive(info) {
 
	if (info.connectionId == connectionId &amp;&amp; info.data) {
 
		var str = convertArrayBufferToString(info.data);
		$("#receive_textarea").append(str);
		$("#receive_textarea").scrollTop($("#receive_textarea")[0].scrollHeight);
	}
}

La funzione verifica se effettivamente sono stati ricevuti dati e in caso affermativo converte l’oggetto ArrayBuffer in una stringa e la aggiunge alla textArea.

Test

E’ possibile provare una Chrome App semplicemente attivando la Developer mode nelle impostazioni di Chrome e successivamente cliccando su Load unpacked extension…

chrome-test

Selezionando la cartella che contiene l’app in fase di sviluppo, questa viene caricata da Chrome ed è possibile eseguirla.

Per quanto riguarda la distribuzione delle applicazioni, è possibile crearne un pacchetto installabile con la funzione Pack extension… o – in alternativa – esse possono essere caricate sul chrome web store previa iscrizione al programma Chrome Developer.

Conclusioni

In questo tutorial vi ho mostrato come si possa, grazie alle Chrome Apps, realizzare facilmente applicazioni cross-platform. In tal modo possiamo dotare i nostri progetti elettronici di una comoda interfaccia utente fruibile da chi utilizza Windows, Linux o MacOS (e in maniera sperimentale anche su Android e iOS).

Qual è la vostra scelta quando si tratta di realizzare GUI per i vostri progetti? Ditemelo nei commenti!

Related Posts

9 comments

Dustin 8 giugno 2016 - 17:31

“Creating a Chrome App was for example the choice of the developing team of Cleanflight, one of the most famous firmware for multicopter’s flight control boards.”

It is somewhat disrespectful to attribute this decision to anyone working on Cleanflight considering Cleanflight was a hostile fork of Baseflight and its GUI where the author who did all of the work on building the Chrome App (who also did work on other Chrome apps with USB backends).

The choice to use Chrome was made long before Cleanflight was created, and the person who actually made the decision to use Chrome was unhappy about the Cleanflight team copying his work.

Reply
luca 9 giugno 2016 - 07:54

Hi Dustin! Thanks for your comment, I really wasn’t aware of this “cleanflight-vs-baseflight” war. I did a small research on google and found a lot of different versions and point of views about the story. Let’s keep it simple: if Cleanflight / Baseflight and also Multiwii (the “father”) has a Chrome App GUI, the technology works pretty well and it’s worth a try!

Reply
mat 12 giugno 2016 - 06:25

Will this work on a Rapsberry Pi?

Reply
luca 13 giugno 2016 - 08:29

Hi Mat, yes Chrome Apps do work under Raspbian

Reply
Sarb 11 agosto 2016 - 18:34

Hey Luca do you have a github with the complete source code provided? Im trying to build the same thing and am having trouble linking the html elements to the corresponding js parts.

Reply
luca 14 settembre 2016 - 08:27

Hi, of course the source is on Github (as explained in the article…)

Reply
Pascal 18 ottobre 2016 - 10:49

Thanks for sharing this – this tutorial was really helpful to get me started with tweaking Chrome Apps

Reply
Giuseppe 1 novembre 2018 - 17:43

Ho provato la webapp con un convertitore seriale RS232-USB Prolific in Chrome sia in Mac che in Win7 e funziona correttamente. Se apro in Chrome (sia Mac che Win) la pagina window.html non rileva alcuna porta seriale e il menu a tendina rimano non popolato e non funzionante. Come mai?

Reply
luca 2 novembre 2018 - 10:53

Giuseppe è normale, Chrome ha un diverso livello di sicurezza se esegui una “app” o se carichi a mano la pagina html… in questo secondo caso non sono disponibili le API per accedere alle porte seriali

Reply

Rispondi a luca Cancel Reply

quindici − 14 =