lunedì 29 settembre 2014

Colloquiare con una porta

Forse il titolo può sembrare equivoco, ma in questo post proverò ad esporre una panoramica su come leggere i dati che arrivano da una porta USB, seriale o perfino da una scheda Arduino.
Prima di cominciare è meglio capire a che serve tutto ciò?
Immaginiamo di avere a che fare con qualcosa che è oltre il semplice leggere e scrivere file, immaginiamo di  di dover sapere il valore di un sensore: di dover sapere quanto è stato ruotato il volante di un'auto, la temperatura di un termometro, l'intensità luminosa, ecc. In questo ambito dobbiamo leggere un input che ci può arrivare al computer in vari modi, nel modo più semplice è stato analizzato e digerito e ci arriva come una stringa di informazione sulla porta USB.
Collegando la porta USB ad sistema che legge i dati, come ad esempio Arduino, il nostro computer non vede quasi nulla, non c'è un file da leggere; c'è una porta di comunicazione che spara continuamente dati e che può anche accettare dei dati
Non entrerò nella programmazione di Arduino, che esula dalle intenzioni di questo post, inoltre esistono altri sensori con porta USB oltre ad Arduino; mi accennerò ad indicarvi http://bitlash.net/ come uno dei sistemi più semplici per programmarlo.
Il comando per colloquiare con una porta è open driver device, a seconda del sistema operativo la stringa device è diversa. Sui sistemi Windows tutte le porte sono COM, quindi si può scrivere:

open driver "COM2:" for binary update

mentre su Linux le porte sono le tty (o qualcosa di simile) dentro la cartella /dev, quindi:

open driver "/dev/tty2" for binary update

su Mac è un pelo più complicato, perchè nome e posizione cambia ad ogni versione, comunque per il resto è come su Linux:

# provare una di queste: /dev/cu.usbmodem2, /dev.tty.usbmodem2, /dev.cu.usbserial2,
open driver "/dev/cu.usbmodem2" for binary update


la modalità "for binary" (dialogo in binario)  è la più utilizzata, ma potete aprirlo anche in solo testo.
Ora viene la parte complicata, leggere e scrivere. E' complicata perchè dovete capire quando cominciano e finiscono i dati.
Se il vostro segnale è singolo canale (quindi ricevete le informazioni da un solo sensore), di solito il carattere di fine informazioni è un ritorno a capo. In questo caso basta: (sostituento usbSerial con il vostro device)

read from driver usbSerial for 1 line in 100 milliseconds
put it into theInput

Come vedete bisogna indicare un tempo massimo in cui il programma si mette ad ascoltare, altrimenti se c'è un errore di trasmissione il programma si blocca perchè non gli arriva mai la fine dei dati (il ritorno a capo).
Questo comando potete ripeterlo ogni 30 millisecondi per aggiornare il valore letto.
Se volete inviare un comando al vostro sensore/trasduttore, ad esempio "sono pronto a ricevere i dati", basta usare write, ecco il codice:

write "run lsd,500" & return to driver usbSerial

Se leggete da più sensori, nella porta USB arriverà un'informazione multicanale, del tipo:

a1=22
a2=34
a3=18
...

Qui le strade sono molte e dipende in gran parte dal tempo di aggiornamento di cui avete bisogno. Prendere tutte le righe insieme e poi analizzarle è la peggiore, rischiate di perdere moltissimo tempo per capire se avete ricevuto tutti i dati. Di solito la strategia migliore è leggere una riga alla volta, analizzarla e leggere la successiva.
Lo stesso discorso vale per la scrittura.
Un altro tipico errore è di voler subito voler comunicare a velocità altissime, fate delle prove e vedete se ne avete veramente bisogno. Di solito la velocità di base della porta (9600) è più che sufficiente per quasi tutte le applicazioni. Aumentare la velocità aumenta i problemi di sincronizzazione fra lettura e scrittura, il tempo a disposizioni diminuisce e non si riesce a capire se si hanno ricevuto tutti i dati correttamente.
Per impostare la velocità c'è questo comando:

set the serialControlString to "BAUD=9600 DATA=8 STOP=1 PARITY=N xon=off to=off dtr=off rts=off "