- Business e performance
- 19.11.2020
Come migliorare le prestazioni della tua web app grazie ai Web Worker
Iniziamo una conversazione
100% 0% 5% 35% 100%
Da grande fan della saga di Lucas non posso non essere possessore del mitico R2D2 che Sphero ha rilasciato sul mercato da quasi 2 anni! Il famoso droide che salva sempre i nostri eroi da ormai più di 40 anni, rivive oggi in questa edizione quasi tascabile che può muoversi, ruotare e animarsi come nel film utilizzando una semplice app che lo comanda tramite Bluetooth (nello specifico BLE Bluetooth Low Energy). C'è poco da dire, è per me una grande soddisfazione averlo e non nascondo sia stato divertente usarlo, soprattutto come target di caccia per il mio gatto, ma adesso vorrei davvero farci qualcosa di più divertente, ovvero provare a far muovere il nostro droide con del codice.
La prima cosa che ho fatto è cercare se da qualche parte c'era una libreria che potesse essermi d'aiuto: niente da fare.
Secondo tentativo: qualcuno sul web avrà provato a far muovere il nostro eroe con del codice? Una sola risposta, un solo articolo che spiega un po' il processo ma non arriva fino in fondo al funzionamento del nostro R2D2. Ci resta solo una cosa: fare del sano reverse engineering!
Cosa vuol dire reverse engineering? Si tratta sostanzialmente di una pratica piuttosto diffusa dove analizzando un sistema si riproduce il suo esatto funzionamento. Lo scopo di questo tutorial sarà capire quali messaggi Bluetooth si scambiano la app e il droide e provare a decifrarli e replicarli con del codice!
Una sola cosa ci viene in aiuto: per fortuna Sphero ha rilasciato una documentazione del protocollo di comunicazione tra device e droide, niente di specifico per il nostro amico ma è un buon punto di partenza!
Armiamoci di tutto ciò che serve per questo esperimento! Ovviamente noi qua parliamo di R2D2 ma potete utilizzare la stessa tecnica anche per altri device che vengono controllati tramite Bluetooth!
La prima cosa da fare è installare Wireshark e Android Developer tools sul PC
Una volta settato il PC è il turno del telefono: le cose da fare sono due:

Usando questa funzionalità è possibile salvare la comunicazione del telefono con i vari dispositivi Bluetooth, esattamente quello che ci serve
Una volta abilitata la funzione bisogna aprire l'app e giocare un po' con il nostro droide. Dopodiché è possibile reperire il file di log con tutta la comunicazione Bluetooth utilizzando adb:
adb pull /sdcard/btsnoop_hci.log /dest/path
Questo file generalmente viene salvato nella path /sdcard/btsnoop_hci.log e può essere ispezionato con Wireshark.
Questa è la parte più interessante del progetto! Aprendo Wireshark è possibile avere la lista completa di tutti i messaggi scambiati, quindi sarà semplice capire come ricreare il comportamento della app. Questo è quello che ho ottenuto dopo la mia prima sessione: ci sono un sacco di pacchetti di richiesta di informazioni tra il nostro Android device (localhost) e il droide che non ci interessano (il mio droide è quello con indirizzo d7:1b:52:17:7b:d6) ma dopo un po' di scroll finalmente arriva la prima richiesta di scrittura da parte della app (write request)!

Come si può vedere dall'inspector di Wireshark il primo messaggio che la app manda al droide è: “usetheforce. ..band”. Siamo sulla strada giusta :)
Un'altra informazione importante da salvare è il Service UUID e la Characteristic UUID, valori da annotare per sapere dove mandare il messaggio "usetheforce. ..band"!
Adesso bisogna sapere come continuare a spulciare il nostro file di log! Dalla documentazione otteniamo una grande informazione utile, la struttura del pacchetto:

Ogni pacchetto scambiato tra app e R2D2 parte con un byte SOP (Start of packet) e un byte EOP (End of packet), rispettivamente di valore 0x8D e 0xD8, perciò bisogna stare molto attenti a tutti i pacchetti che hanno questa forma, saranno loro le azioni che la app dice di eseguire al droide. Ci sono altri byte interessanti da tenere a mente:
SEQ (Sequence Number): un numero sequenziale che viene incrementato ogni volta che la app manda un pacchetto al droide
DATA (Message Data): una serie di dati (ad esempio se il carrello deve star fuori o dentro)
CHK (Checksum): la somma di tutti i byte (esclusi SOP and EOP) modulo 256, e con i bit invertiti (qui una funzione per calcolarlo)
Andando più avanti nel log vediamo che il primo pacchetto che rispetta questa struttura è:
0x8D 0x0A 0x13 0x0D 0x00 0xD5 0xD8

Cambiano Service UUID e Characteristic UUID e il byte SEQ è ovviamente 0x00 essendo il primo!
N.B. Da adesso in poi tutti i messaggi andranno verso quest'ultima Characteristic, che chiameremo MAIN_CHAR.
Un altro utile pacchetto da salvare è l'ultimo inviato dalla app prima di chiudersi, il pacchetto che spegne il droide e che ovviamente potete trovare alla fine del file di log:
0x8D 0x0A 0x13 0x01 0x20 0xC1 0xD8

Ogni volta che mandiamo questi messaggi dobbiamo sempre aspettarci una risposta!
Seguendo la documentazione vediamo che la risposta a comando avvenuto è di nuovo uno stream di byte con SOP e EOP identici, questa volta però con il byte ERR non vuoto, ma di valore 0x00 se tutto è andato per il verso giusto, altrimenti con un codice di errore specifico che sta ad indicare cosa è andato storto. Qui una lista completa dei vari codici di errore
Ci sono inoltre alcuni comandi, come ad esempio quello per le animazioni, che inviano un secondo messaggio di risposta ad azione avvenuta, molto utile per capire quando un'animazione ha finito la sua esecuzione.
Seguendo lo stesso procedimento che abbiamo adottato per trovare i messaggi per inizializzare e spegnere il droide, cerchiamo adesso quei messaggi per fargli eseguire qualche azione! In questo modo possiamo mandare attraverso il codice questi messaggi e leggere le risposte dal droide.
Per scrivere e leggere i dati via Bluetooth solitamente vengono usate delle apposite librerie che permettono la connessione ai dispositivi, le funzioni per mandare dati verso una specifica caratteristica e leggere le risposte.
Il codice sostanzialmente deve fare le seguenti cose:
1. Connetti il droide specificando il suo indirizzo 2. Manda il messaggio "usetheforce.. .band" 3. Cerca l'oggetto Characteristic e salvalo (MAIN_CHAR) 4. Manda a MAIN_CHAR il messaggio di iniziazione (SEQ = 0)
Ogni volta che vien scritto un pacchetto verso una data Characteristic:
1. Crea la sequenza di byte calcolando il byte CHK e il SEQ incrementato di 1. 2. Manda questa sequenza di byte a MAIN_CHAR. 3. Attendi una o più risposte e controlla il byte ERR se tutto è andato ok
Qui potete trovare il codice che utilizza Noble una libreria per Node.js per comunicare con i device BLE.
Se volete proseguire nel dettaglio di come è stato fatto tutto il processo di reverse engineering vi consiglio caldamente l'articolo specifico, corredato di codice e richiami alla documentazione, dove potete trovare come ruotare la parte superiore di R2D2, aprire il carrello e animarlo. La Saga continuerà con un secondo episodio che spiegherà come far muovere il droide e lavorare con i sensori di collisione.
Per i frettolosi smanettoni vi rimando al codice su Github
Buone feste e che la Forza sia con voi!
Credits dell'immagine di copertina: Artwork by Snowmarite (CC)
Scopri di più
Idee Idee Idee
Come migliorare le prestazioni della tua web app grazie ai Web Worker
L’organizzazione di eventi tech sul territorio
Come creare un blog Jamstack multilingua con Nuxt.js e Strapi CMS