English abstact

A minmal example for controlling a serialport using Qt for Android without the necessity of root permission.

Nutzung des Seriellport in Android mit Qt ohne Rootrechte

BILD-FEHLT Für ein Projekt musste ich mit einem Android-Tablet ein externes Gerät steuern, welches über einen USB-Seriell-Wandler an das Tablet angeschlossen werden sollte. Da ich kaum Erfahrung mit Java-Programmierung, aber umso mehr mit Qt habe, wollte ich Qt for Android nutzen. Qt unterstützt Linux und da Android auf Linux basiert, können Qt-Programme auch unter Android laufen. Die Installation der nötigen Komponenten ist zwar recht aufwändig (Android-Studio, Android NDK, Java JDK), aber es gibt dafür viele Anleitungen im Netz zu finden. Nur das Ansteuern des USB-Seriellportadapter stellte sich als großes Problem heraus, dessen Lösung ich hier der Allgemeinheit zugänglich machen möchte.

Android verweigert den Zugriff

Qt bringt seit Version 5.5 ein eigenes Seriellportmodul mit. Vor dieser Version konnte man z. B. die Bibliothek QextSerialPort nutzen, die zwar auch unter Linux läuft, aber in Verbindung mit Android das selbe Problem aufweist. Nämlich, dass Android der Programm den Zugriff auf den Port schlicht verweigert. Das Suchen und Anzeigen der vorhandenen Ports geht, wenn man aber einen öffnen will, bekommt man eine "Zugriff-verweigert-Meldung". In Internetforen wird als Lösung vorgeschlagen, das System zu "rooten" also dem Benutzer Superuser-Rechte zu geben, die er aus Sicherheitsgründen eigentlich nicht haben sollte. Das ist allerdings zum einen eine aufwändige Prozedur, die spezielle Software erfordert und zum anderen verliert man dadurch meist die Herstellergarantie des Geräts. Auch ist es nicht immer möglich. Das Tablet, das ich hatte, ließ sich mit vier verschiedenen Programmen nicht rooten. So oder so ist es keine Lösung für eine App die man einfach installieren kann und die auf Anhieb funktioniert.

Zugriff nur mit Java möglich

Es gibt allerdings einige Apps die einfach zu installieren sind, keine Rootrechte brauchen und den Seriellport nutzen. Zum Beispiel von FTDI einem Hersteller von USB-Seriell-Wandlern. Diese Apps sind allerdings alle direkt in Java geschrieben. Von allen Projekten die man im Internet dazu findet hat mich UsbSerial von felHR85 am meisten überzeugt. Denn es war das einzige bei dem sich das Beispielprogramm wirklich auf Anhieb kompilieren lies und funktionierte. Hier konnte man auch lernen wie man die Datei "AndroidManifest.xml" anpasst, so dass Android weiß, das die App auf den Seriellport zugreifen will.

Nachdem nun zumindet JAVA-Code vorhanden war der funktionierte, musste diese noch mit dem Qt-Teil des Programms verheiratet werden. Hierfür waren die Tutorials von KDAB sehr hilfreich. Vor allem Teil 5 und Teil 7. Der Autor ist derjenige, der die Android-Unterstützung von Qt entwickelt hat. Man merkt also, dass er weiß wovon er schreibt. Man lernt darin wie man aus dem Qt-Code, der ja in C++ ist, Java-Funktionen aufruft und wie man es wiederum Java-Funktionen ermöglicht, C++ Funktionen aufzurufen. In Teil 7 geht es darum wie man dabei auch noch den Thread wechselt (Der Qt-Teil des Programms läuft in einem eigenen Thread). Das war aber gar nicht nötig - die Seriellportfunktionen funktionierten auch im Qt-Thread.

Zusammenfügen und Eindampfen

Ich habe also das Funktionierne Java-Beispiel von felHR85 in ein Qt-Projekt übertragen und eine kleine Java-Klasse geschrieben, die die Grundfunktion (Suchen, Öffnen, Lesen, Schreiben, Schließen) implementiert. Dann wurde eine Qt-Klasse erstellt die Funktionen der Java-Klasse aufruft um Ports zu öffnen und Daten zu senden. Beim Empfang einer Nachricht ruft der Java-Code eine so genannte Native-Funktion im C++-Teil des Programm auf, die die Qt-Klasse dazu veranlasst ein Signal mit der Nachricht zu emitieren. Hier stellte ich fest, dass der Code des Java-Beispiels mit UTF8-Strings arbeitet was zu abstürzen führte wenn ein nicht darstellbares Zeichen gesendet oder empfangen wird. Also wurde das Ganze auf Byte-Arrays umgestellt, so wie man es bei einem Seriellport üblicherweise haben möchte.

Nachdem alles funktionierte, wurde der Code so lange reduziert bis wirklich nur noch das nötigste vorhanden war. So ist ein anschauliches Beispiel zur Lösung von exakt dem Eingangs beschriebenen Problem entstanden. Gängige Funktionen für Seriellportcode, wie das Sammeln von Zeichen bis ein Zeilenumbruch kommt, wurden bewusst weggelassen. Interessierte können hierfür z. B. den Quellcode meines CNC-Steuerungsprogramms anschauen. Der Rest wurde in ein Ziparchiv gepackt, und kann hier herunter geladen werden.

Downloads

AndroidUARTQt.apk Applikation zum installieren auf einem Androidgerät (6,62 MB)
AndroidUARTQt.zip Qt-Projekt mit Quellcode (82 kB)

Datenschutzerklärung © 2014 - 2019 Philipp Meißner