Android: dai driver all’interfaccia (Seconda Parte..)

Android: dai driver all’interfaccia (Seconda Parte..)

mar 14
Android: dai driver all’interfaccia (Seconda Parte..)

Logo android
Rieccoci di nuovo qui :-)

Nella precedente discussussione abbiamo affrontato lo spinoso problema di dover scrivere dei driver a “basso” livello, per interfacciarsi con un dispositivo esterno su Android.

Il discorso in questo articolo è il medesimo: finire lo sviluppo di un driver a basso livello, ed incominciare a farlo  ”colloquiare” con il livello più alto fornito da Android.

La scorsa volta abbiamo realizzato il “core” della funzione (nel caso, l’apertura di un bus i2c e susseguente lettura/scrittura di un registro) Vediamo quindi come terminare il vero e proprio “core“!
Una volta inserita la funzione che avevamo chiamato “
get_i2c_button” è necessario che essa venga richiamata da un altro metodo, che nel nostro caso restituisca(per semplicità!) una
Stringa, che nel nostro caso conterrà lo stato dei bottoni per ogni carattere(ad esempio la stringa “1101/” ci indicherà che i bottoni 0-1-3 sono premuti, mentre il bottone 2 non è premuto. Il carattere “/” è un carattere che indica il termine della stringa.

Questa sarà la vera e propria funzione che verrà richiamata dalla interfaccia!
Di conseguenza, introduciamo la
prima grande regola da rispettare!

I nomi delle funzioni richiamate dallo strato Linux debbono chiamarsi come la funzione che richiamerà quel metodo(comprensivo di package)

E’ importante notare che la notazione per “navigare” i package è diversa. In Java si naviga con il . mentre in c utilizzeremo l’underscore _

di conseguenza, per indicare una funzione generica “getButtons” nella classe “hardware” del package “fz.test” utilizzeremo come nome del metodo: “Java_fz_test_hardware_getButtons” è importante oltretutto anteporre “Java” davanti al primo package, ad indicare che la funzione sarà utilizzata dal layer Java. Senza di essa, la funzione non sarà riconosciuta!

Come ogni buon linguaggio di programmazione, oltretutto ( :-D ) il C fornisce anche il tipo di dati che “ritornerà” questa funzione, ed i parametri di essa.
Nel nostro caso abbiamo una “Stringa” come risultato. Per scrivere la funzione finale, quindi, scriveremo:

JNIEXPORT jstring JNICALL Java_fz_test_hardware_getButtons(JNIEnv * env, jobject this)

Per gestire i dati di ritorno in java, è possibile utilizzare qualunque dei tipi di dato forniti dalle NDK, che è possibile trovare a questo indirizzo! Come “indizio” è possibile utilizzare praticamente tutti i tipi di dato primitivi, anteponendo la “j” ;-)

La lista dei parametri invece, è di “default”, quei valori infatti vengono passati a runtime in maniera trasparente al metodo, senza cioè bisogno che lo strato Android richiami il metodo getButtons(JNIEnv,jobject) bensì geButtons().

Comunque, continuiamo a descrivere la funzione. Questa avrà al suo interno una chiamata al metodo descritto nel precedente articolo, secondo il seguente esempio:

JNIEXPORT jstring JNICALL Java_fz_test_hardware_getButtons(JNIEnv * env, jobject this)

{
file = open("/dev/i2c-0", O_RDWR);
if (file<0){ //qui dobbiamo gestire l'errore in caso non si riesca ad aprire il device, inviando eventualmente una stringa contenente il problema } else{ //richiamo la funzione descritta la volta scorsa //...un po di logica qui... close(file); //non scordatevi mai di chiudere il file aperto con open, altrimenti ad ogni chiamata accumulerete un altro puntatore in memoria... return((*env)->NewStringUTF(env, result));
//è importante notare come, nel nostro caso, sia necessario ricorrere all"ambiente" per ottenere una stringa UTF da restituire al layer Java.
}

In merito all’ultimo commento, a Questo Indirizzo è possibile trovare tutti i link per i metodi disponibili sul tipo di dato Stringa.

Una volta terminato il vostro file, dovrete chiamarlo con un nome a piacere. Nel nostro caso, suggerisco “native.c” (per ricordarci che è un file nativo in c, ovviamente ;-) )

A questo punto è necessario cominciare a costruire il progetto in Java. Nel mio caso, consiglio a tutti di armarsi di ambiente di sviluppo myEclipse e di scaricare contestualmente il plugin per Android. Una volta effettuato tale lavoro dobbiamo fare

New–> Android ProjectAndroid progetto nuovo

A questo punto dovremmo avere una struttura di questo tipo:

(Cliccate sulle immagini per ingrandirle!)

Nell’ordine abbiamo:

  • src
  • gen
  • android update
  • librerie
  • assets
  • jni
  • libs
  • obj
  • res
  • AndroidManifest.xml
  • Default.properties


Nello specifico, la cartella che interessa a noi è jni(Java Native Interface), dove dovremo posizionare il “nostro lavoro” ed un file particolare (per chi ha esperienza in Linux: un MakeFile) che realizzeranno il “codice oggetto” della nostra libreria.

Nel prossimo articolo parleremo della struttura del progetto(le cartelle), di come compilare il nostro native.c in modo tale che il sistema possa richiamare la funzione nativa, e anche altre cose :-)

Stay Tuned mi raccomando! 8-)

Leave a Reply

Login with Facebook: