2012-10-31 21 views
10

Così ho implementato l'API di Android USB Accessory in modo tale da poter collegare il mio telefono al mio portatile con linux e mette il telefono in modalità Accessori USB. Quindi posso accedere all'accessorio, aprirlo e iniziare a leggerne uno scritto. Il mio codice sembra quasi identico all'esempio in the documentation. La differenza principale è che sto usando metodi separati di lettura e scrittura e accedendo tramite JNI dal codice nativo.Lettura da Android USB Accessory getta ENODEV IOException

Ecco dove diventa interessante. Dopo aver letto/scritto correttamente per un secondo o due, il trasferimento di massa scritto dal mio portatile inizia a dare errori di timeout e quindi la chiamata di lettura all'accessorio USB in Android genera un'eccezione IOOD con il codice di errore ENODEV. Questo è con il cavo ancora connesso e UsbManager elenca ancora l'Accessorio nella lista, e ho ancora il permesso per farlo.

Per aggiungere alla stranezza di esso, ho scoperto che se metto un sonno di 100 ms nel ciclo di lettura, il problema in pratica scompare (anche se succede occasionalmente). Avere il sonno non è solo un orribile kludge, ma introduce una latenza intollerabile nella mia app. Più basso è il tempo di sonno, meno efficace è l'incisione, a cui è inefficace a 10ms di tempo di sonno.

Sto trasmettendo circa 20-30kbps di dati in tempo reale utilizzando i trasferimenti di massa (ma non così in tempo reale che un trasferimento di massa non è sufficiente) e la dimensione di trasferimento varia da 50 a 800 byte a circa 20 -30Hz. Potrebbe essere una limitazione di USB? Non ho un sacco di esperienza con esso, quindi fondamentalmente sto trattando lo stesso di una presa di rete. Devo accodare messaggi più piccoli e spedirli insieme in trasferimenti meno frequenti ma più grandi? C'è un problema con i trasferimenti di massa piccoli e di alta frequenza? Vedrò questo, ma fondamentalmente sto afferrando le cannucce qui.

Hardware:

  • computer portatile è in esecuzione Ubuntu 10.04 e utilizzando libusb 1.0.0.
  • Il telefono è Galaxy Nexus S in esecuzione Android 4.1.2.

risposta

6

Quindi, mentre ancora non capisco tutto ciò che sta succedendo, l'implementazione di uno schema di doppio buffer ha risolto il mio problema.

Ho scoperto che un'app Android Java a piena velocità non presentava problemi con il problema ENODEV, il che mi portava alla conclusione che l'interfaccia nativa di Java era la radice dei miei problemi.

Precedentemente, stavo leggendo da UsbAccessory direttamente dai metodi chiamati dal JNI in modo sondaggio. Qualcosa sulla transizione dal codice nativo a Java e poi da Java al kernel nativo di Android apparentemente ha reso tutto scontroso.

La mia correzione era di leggere/scrivere su UsbAccessory da thread Java-only (senza chiamate JNI) e quindi bufferizzare quei dati per leggere/scrivere dai metodi chiamati da JNI.

Sembra funzionare come un fascino. Prima di ricevere i timeout di invio in modo molto coerente dal lato degli accessori, e infine l'IOExeception sul lato Android come descritto sopra, e ora non ho timeout, né IOException. Sono ancora un po 'curioso di cosa causi esattamente quel comportamento, ma sospetto che sia necessario comprendere un forte JNI Kung-fu.