Hallo zusammen,
vor einiger Zeit habe ich einen 7"-Touchscreen geschenkt bekommen - ja, ich bin immer noch der, der die Raspberry Pi's inkl. Zubehör geschenkt bekommt.
Nachdem der Touch-Screen projektbedingt ein paar Wochen liegen blieb, habe ich ihn dann doch mal ausgepackt und angeschlossen.
Die Touch-Funktionalität lässt sich nur nach Compilierung der Kernel implementieren. =(
Nun denn... ein paar Anleitungen
http://
http://
dazu habe ich gefunden - aber zum Ziel haben sie mich alle nicht geführt. Nach jedem Scheitern habe ich die Vorgehensweise analysiert. Bei jeder Anleitung haben sich Fehler eingeschlichen, die man nur bei äußerst gewissenhafter Anwendung vermeiden kann. Außerdem empfinde ich die Kombination von schier endlosen Terminal-Eingaben, die an sich schon fehlerträchtig sind, und die Nutzung graphischer Anwendungen für gewöhnungsbedürftig.
Kurzum, in mir kam der Wunsch auf, den Prozess zu automatisieren UND von der Qualität des Anwenders unabhängig zu machen.
Die Idee des Linux-Compilator war geboren.
Anleitung zur Bedienung
Dieses Programm setzt Folgendes voraus:
- Auf einem PC befindet sich das Betriebssystem Ubuntu (auf meinem System Ubuntu 14.04 LTS - es sollte aber auch jedes andere Ubuntu laufen, wahrscheinlich läuft es auf jedem Linux-System)
- Der Ubuntu-PC ist an ein Netzwerk angeschlossen
- Der Raspberry Pi ist an das gleiche Netzwerk angeschlossen
- Raspberry Pi und Ubuntu-PC sind hochgefahren
- Auf dem Ubuntu-PC läuft der Kernel-Compilator
- Der USB-Stecker des 7"-Touch-Screens ist in einer USB-Buchse des Ubuntu-PC eingesteckt
Benutzeroberfläche
Das Programm besteht aus einer Benutzeroberfläche, die dem Anwender die Informationen aus der Nase zieht. Immer dort, wo ein Bedienelement blassgrün erscheint, darf man etwas eingeben oder eine Aktion starten.
Ich stelle jetzt die einzelnen Funktionsbereiche vor.
1. Funktionsbereich Eingabe im Terminal des Raspberry Pi:
Im oberen Text-Eingabefeld ist die IP-Adresse des Raspberry Pi einzugeben.
a) Wer sie auswendig weiß :thumbs1:, der kann sie gern dort eintragen und mit Enter bestätigen.
b) Wer sie nicht auswendig kennt, der kann im Terminal des Raspberry Pi eingeben:
Kommen mehrere IP-Adressen, dann entscheide Dich für eine davon. Diese Daten werden dann in das Texteingabefeld des Kernel-Compilator eingetragen.
c) Da beim Eingeben verhängnisvolle Fehler passieren können, habe ich mir überlegt, wie der Ubuntu-PC bzw. das Programm Kernel-Compilator diese Info herausbekommen kann. Mit Folgendem war ich dann zufrieden:
if pipe := open("hostname -I", "p") then
{ ip := read(pipe)
VSetState(vidgets["text_input7"], ip)
punkte := []
every put(punkte, find(".", ip))
p1 := ip[1:punkte[1]]
p2 := ip[punkte[1]+1:punkte[2]]
p3 := ip[punkte[2]+1:punkte[3]]
p4 := ip[punkte[3]+1:0]
close(pipe)
}
ip_list := []
ip1_3 := p1 || "." || p2 || "." || p3 || "."
if pipe := open("nmap -sP " || ip1_3 || "0/24 | grep report", "p") then
{ while ip := read(pipe) do
{ ip := ip[find(ip1_3, ip):if find(")",ip) then -1 else 0]
put(ip_list, ip[*(ip1_3)+1:0])
}
}
VSetItems(vidgets["list3"], ip_list)
Alles anzeigen
Nach Drücken der Scaltfläche RPi im LAN/WLAN suchen wird eine Pipe geöffnet, die mittels
die IP-Adresse des Ubuntu-PC liefert. Also kann die IP-Adresse des Raspberry Pi so unterschielich auch ncht sein, da sie ja zum gleichen Netzwerkbereich gehören muss. Mit Hilfe des Befehls
werden alle IP-Adressen des Netzwerkbereiches gescannt - diejenigen, die tatsächlich existieren, werden im rechts befindlichen Listenfeld ausgegeben. Der Anwender braucht jetzt nur noch die richtige IP-Adresse (bzw. die vierte Zahl davon) anzuklicken. Die "fertige" IP-Adressen steht dann im Texteingabefeld.
Im mittleren Texteingabefeld wird die Kernel-Version (aktuell ist etwas wie 3.12) eingetragen.
a) Wer sie auswendig weiß, der kann sie gern dort eintragen und mit Enter bestätigen. :thumbs1:
b) Wer sie nicht auswendig kennt, der kann im Terminal des Raspberry Pi eingeben:
c) Da beim Eingeben verhängnisvolle Fehler passieren können, habe ich mir überlegt, wie der Ubuntu-PC bzw. das Programm Kernel-Compilator diese Info herausbekommen kann. Mit Folgendem war ich dann zufrieden:
executor("ssh -f pi@" || vidgets["text_input7"].data)
if uname := open("uname -a | awk {'print $3'}","p") then
{ version := read(uname)
version := version[1:find(".", version, 4)]
VSetState(vidgets["text_input4"], version)
close(uname)
}
Nach Drücken der Schaltfläche via SSH ausführen wird ein SSH-Zugang zu der vorher festgelegten IP-Adresse ermöglicht. Die Version des Linux-Kernels wird automatisch in das Texteingabefeld eingetragen. Danach wird der Raspberry Pi mittels
sicher heruntergefahren. Die SD-Karte wird entnommen und in einen passenden Slot des Ubuntu-PC oder in einen geeigneten USB-Kartenleser eingesetzt und am USB-Port des Ubuntu-PC eingesteckt.
Im unteren Eingabefeld werden Informationen über den Touch-Screen eingetragen. Hierzu wird im Prinzip die Linux-Pipe gestartet:
2. Im Funktionsbereich Pfad auf Ubuntu-PC werden Pfade für dieses Projekt gesetzt, sowie ein Verzeichnis für den Quellcode des Linux-Kernels eingerichtet. OK, ich hätte jetzt meinen File-Requestor einbinden können - aber ein wenig kann der Anwender auch mal machen.
3. Im Funktionsbereich Verzeichnisse auf dem Ubuntu-PC wird der Pfad eingetragen, unter der die SD-Karte des Raspberry Pi dem Ubuntu-System nun bekannt ist. Da hier auch wieder Fehler entstehen können, macht der Kernel-Compilator im daruterstehenenden Listenfeld Vorschläge, von denen der Anwender sich das Passende aussucht (anklickt) - und schon steht es im Texteingabefeld.
Der gleiche Vorgang wiederholt sich für die große Partition der SD-Karte.
Für Interessierte der Programmcode:
boot_list := []
big_list := []
if df := open("df | grep /media/*/boot", "p") then
{ while pfad := read(df) do put(boot_list, pfad)
close(df)
}
if df := open("df | grep /media/", "p") then
{ while pfad := read(df) do
{ #Notice(pfad)
if pfad ~== boot_list[1] then put(big_list, pfad)
}
close(df)
}
if *boot_list = 0 then
{ Bg("red")
boot_list := big_list := ["Keine SD-Karte gefunden!"]
}
else
{ Bg("green")
push(boot_list, "Filesystem 1K-blocks Used Available Use% Mounted on")
push(big_list, "Filesystem 1K-blocks Used Available Use% Mounted on")
}
VSetItems(vidgets["list1"], boot_list)
VSetItems(vidgets["list2"], big_list)
Alles anzeigen
Und durch den folgenden Code wird auf die Auswahl der Listenfelder reagiert:
procedure list_boot(vidget, value)
VSetState(vidgets["text_input3"], value[find("/media/", value):0])
end
procedure list_big(vidget, value)
VSetState(vidgets["text_input8"], value[find("/media/", value):0])
end
wodurch die Auswahl aus dem Listenfeld in die vorgesehenen Texteingabefelder übertragen werden.
4. Im Funktionsbereich Herunterladen werden alle Informationen angeboten, die im Falle einer Kernel-Compilierung benötigt werden könnten. Beim ersten Aufrufen dieses Programmes sollten im Zweifelsfall alle Optionen aktiviert werden.
a) Download Linux-Kernel. Hier wird der Linux-Kernel (in der festgelegten Version) in das Projektverzeichnis geladen. Dies geschieht durch folgende Zeilen:
procedure aktion(n)
case n of
{1: { executor("mkdir " || vidgets["text_input1"].data)
chdir(image(vidgets["text_input1"].data))
executor("wget https://github.com/raspberrypi/linux/archive/rpi-" || vidgets["text_input4"].data || ".y.tar.gz")
executor("tar -zxvf rpi-" || vidgets["text_input4"].data || ".y.tar.gz")
}
b) Bibliotheken herunterladen. Diese sind erforderlich, damit der Kernel-Quellcod später auch fehlerfrei in lauffähigen Code umgewandelt werden kann.
2: { executor("sudo apt-get install git libncurses5 libncurses5-dev qt4-dev-tools qt4-qmake pkg-config build-essential")
}
c) Python installieren. Später wird ein Skript eingesetzt, das in der Sprache Python geschrieben ist.
d) ARM-Cross-Compiler installieren. Auf dem Ubuntu-PC ist ein anderer Prozessor verbaut als auf dem Raspberry Pi. Wenn wir den Compiler ohne weitere Optionen des Cross-Compilierens einsetzen würden, dann würde der erhaltene Linux-Kernel auf dem Raspberry Pi nicht laufen können. Das Compilieren eines Quellcodes für das System A auf einem System B nennt man daher Cross-Compilieren. Für einige Sprachen gibt es Cross-Compiler-Pakete, die beim Compiler-Aufruf mit anzugeben sind, damit die Sache erfolgreich verlaufen kann.
e) GIT-Tools herunterladen. Für das Projekt benötigen wir einige Werkzeuge aus der GIT-Werkzeugkiste (GIT-Tools). Diese werden mittels der folgnden Codezeilen heruntergeladen:
f) Firmware herunterladen.
11: { chdir("..")
executor("wget https://github.com/raspberrypi/firmware/archive/next.tar.gz")
executor("tar -zxvf next.tar.gz")
}
5. Im Funktionsbereich Kernel: Konfigurator, Cross-Compiler werden dann die eigentlichen Compilierungen des Linux-Kernels sowie die Compilierung und der Aufruf des Linux-Konfigurators durchgeführt. Im einzelnen handelt es sich um folgende Aktionen:
a) Source-Code bereinigen. Die heruntergeladenen Quellcode-Dateien werden empfehlungsgemäß mit Mr. Proper gereinigt. Folgende Codezeilen führen dies durch:
b) Kernel-Konfigurator. Der Kernel-Konfigurator ist ein Programm, das wir uns durch Compilieren erst selbst herstellen:
6: { executor("mkdir ../kernel" || vidgets["text_input4"].data)
executor("make O=../kernel" || vidgets["text_input4"].data || "/ ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- bcmrpi_cutdown_defconfig")
Notice( "Im Kernel-Konfigurator bitte Folgendes auswählen:",
"- Device Drivers",
" - input device support",
" - Touchscreens",
" Option Touchscreen aktivieren",
" Option USB Touchscreen Driver aktivieren",
"",
"Speichern",
"Schließen")
executor("make O=../kernel" || vidgets["text_input4"].data || "/ ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- xconfig")
}
Alles anzeigen
Hier werden folgende Eingaben vorgenommen:
- Device Drivers
- inpt device support
- Touchscreens
- Option Touchscreen aktivieren
- Option USB Touchscreen Driver aktivieren
Speichern
Schließen
c) Kernel compilieren. Hier wird die Kernaufgabe dieses Programmes erledigt, nämlich das Cross-Compilieren für den ARM-Prozessor:
7: { executor("make O=../kernel" || vidgets["text_input4"].data || "/ ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- k-k -j" || vidgets["text_input6"].data)
}
d) Kernel-Image erstellen. Hier kommt das bereits erwähnte Python-Skript zum Einsatz:
9: { chdir("tools/mkimage")
executor(".imagetool-uncompressed.py ../../kernel" || vidgets["text_input4"].data || "/arch/arm/boot/image")
}
e) Module erstellen. Module sind ein Verzeichnis auf der BOOT-Partition der SD-Karte. Diese werden mit dem folgenden Code-Ausschnitt erstellt:
11: { chdir("..")
executor("wget https://github.com/raspberrypi/firmware/archive/next.tar.gz")
executor("tar -zxvf next.tar.gz")
}
f) SD-Karte aktualisieren. Zunächst werden die alten Dateien gesichert - um im Fall, dass die ganze Aktion nicht funktioniert, alles wieder leicht rückgängig machen zu können. Dann werden die betreffenden neuen Dateien auf die SD-Karte kopiert, einige davon auf die kleine BOOT-Partition, einiges auf die große Partition der SD-Karte in das Verzeichnis /lib. Die folgnde Codezeilen erledigen das:
12: { if media := open("df | grep media | awk {'print $6'}", "p") then
{ SD := read(media)
SD := read(media)
close(media)
}
if /media | /SD then Notice("Keine SD-Karte")
else
{ vidgets["text_input3"].data := SD
# Sichern von Dateien der SD-Karte
executor("mv " || SD_Boot || "/boot.code.bin " || SD_Boot || "/boot.code.bin_old")
executor("mv " || SD_Boot || "/start.elf " || SD_Boot || "/start.elf_old")
executor("mv " || SD_Boot || "/kernel.img " || SD_Boot || "/kernel.img_old")
executor("mv " || SD_RPI || "/lib/firmware " || SD_RPI || "/lib/firmware_old")
executor("mv " || SD_RPI || "/lib/modules " || SD_RPI || "/lib/modules_old")
executor("mv " || SD_RPI || "/opt/vc " || SD_RPI || "/opt/vc_old")
# executor("mv " || SD_RPI || "/lib/firmware" || SD_RPI || "/lib/firmware_old")
#executor("mv " || SD_Boot || "/boot.code.bin " || SD_Boot || "/boot.code.bin_old")
chdir(SD_RPI)
executor("sudo cp " || vidgets["text_input1"].data || "/firmware-next/boot/boot_code.bin " || SD_Boot || "/")
executor("sudo cp " || vidgets["text_input1"].data || "/firmware-next/boot/start.elf " || SD_Boot || "/")
executor("sudo cp " || vidgets["text_input1"].data || "/firmware-next/boot/boot_code.bin " || SD_Boot)
executor("sudo cp -R " || vidgets["text_input1"].data || "/modules/lib/firmware/ lib/firmware")
executor("sudo cp -R " || vidgets["text_input1"].data || "/modules/lib/modules/ lib/modules")
executor("sudo cp -R " || vidgets["text_input1"].data || "/firmware-next/gardfp/opt/vc opt/vc")
executor("sync")
executor("umount " || SD_Boot)
executor("umount " || SD_RPI)
Notice("Die SD-Karte emtnehmen und in einen Raspberry Pi einsetzen!")
Notice("Raspberry Pi booten!")
Notice("Nach Hochfahren die IP-Adresse des Raspberry Pi ermitteln: ifconfig | grep inet")
}
}
Alles anzeigen
Nach Abschuss dieses Funktionsbereichs wird die SD-Karte entnommen, in den Raspberry Pi eingesetzt und dieser damit gebootet.
6. Im Funktionsbereich Kalibrierung des Touch-Screen wird die Durchfühung der Kalibierung unterstützt.
a) SSH-Verbindung auf Raspberry Pi. Eine SSH-Verbindung auf den Raspberry wird hergstellt, um das Kalibrator-Programm zu installieren und zu starten.
b) Kalibrator-Programm installieren. Das Kalibrator-Programm wird installiert.
14: { executor("sudo apt-get install libx11-dev libxext-dev libxi-dev x11proto-input-dev")
executor("wget http://github.com/downloads/tias/xinput_calibrator/xinput_calibrator-0.7.5.tar.gz")
executor("tar -zxvf xinput_calibrator-0.7.5")
executor("ls")
chdir("~/xinput_calibrator-0.7.5")
executor("./configure")
executor("make")
executor("sudo make install")
executor("sudo apt-get install Bildschirm-Tastatur")
}
c) Touch-Scren kalibrieren. Der Touch-Screen wird nach Anleitung durchgeführt. Die Ausgabe des KAlibrators wird in der vorgegebenen Datei gespeichert, um auch nach einem Neustart gültig zu bleiben.
15: { executor("xinput_calibrator")
Notice("Nach Anweisung kalibrieren!")
executor("sudo mkdir /etc/X11/xorg.conf.d")
Notice("Ausgabe kopieren nach Vorgabe der Ausgabe")
executor("sudo nano /etc/X11/xorg.conf.d/99-calibration.conf")
Notice("Ausgabe einfügen und speichern!")
Notice("Video prüfen, ob die kopierte Ausgabe nur in einer einzigen Konfigurationsdatei gespeichert werden soll!")
executor("sudo reboot")
Notice("Einloggen!")
Notice("startx bzw. startxfce4 eingeben!")
}
}
Alles anzeigen
d) Bildschirmtastatur installieren. Tja, jetzt haben wir einen Touchscreen inkl. Touch-Funktionalität - aber keine Bildschirmtastatur. Wer hier drauf klickt, hat dann eine Bildschirmtastatur.
e) Rückgängig machen. Tja, wenn's mal nicht funktioniert haben sollte, kann man hier die ganze Sache rückgängig machen und den Zustand vor Einsatz dieses Programmes herstellen.
Den abschließenden Quellcode stelle ich im Verlauf der Woche hier ein - wenn denn das Programm mehrere Mal von verschiedenen Anwendern fehlerfrei durchläuft - und der Einsatz am Raspberry Pi jeweils Erfolg hat.
Beste Grüße
Andreas
P.S.: Bitte keine Kommentare, falls Ihr Bedenken zu irgendwelchen Code-Ausschnitten habt. Ein Teil läuft recht gut , der andere wird es noch tun.