Dienstag, 15. November 2016

Fix Lüftersteuerung nach Suspend

Mein Notebook ist ein Dell inspiron 7520 mit Intel i5-3210M CPU, darauf läuft ein Linux Mint 18 mit Cinnamon 64-bit. Damit bin ich grundsätzlich sehr zufrieden, nur gab es immer ein Problem mit der Lüftersteuerung. So lief der Lüfter immer mit maximaler Drehzahl, wenn das System aus dem Standby aufgeweckt wurde.

Für die Lüftersteuerung verwende ich i8kutils und laut Bugtracker liegt das Problem daran, dass die Einstellungen nach dem Suspend nicht wieder korrekt hergestellt werden und so i8kmon die Regelung nicht korrekt übernehmen kann.

Als funktionierender Workaround kann man

  • i8kmon nach dem suspend neustarten
$ sudo /etc/init.d/i8kmon restart

oder

  • mit i8kfan den/die Lüfter (links/rechts) ausschalten, anschließend funktioniert i8kmon wieder fehlerfrei.
$ i8kfan 0 0

Damit man dies nicht jedes Mal von Hand ausführen muss, kann folgendes systemd script verwendet werden.

$ sudo vi /etc/systemd/system/start_fan.service

[Unit]
Description=Run fan control
After=suspend.target

[Service]
ExecStart=/usr/bin/i8kfan 0 0

[Install]
WantedBy=suspend.target

Damit das Script auch automatisch ausgeführt wird, muss man dieses noch mit folgendem BEfehl aktivieren:

$ sudo systemctl enable start_fan.service 

Ob alles funktioniert hat, kann man nach dem Aufwecken aus dem Suspend mit journalctl kontrollieren.

$ journalctl --unit=start_fan
Nov 15 18:29:33 user-notebook systemd[1]: Started Run fan control.
Nov 15 18:29:33 user-notebook i8kfan[11161]: -1 0

Montag, 24. Oktober 2016

splitting video

avconv ist ein CLI Tool zum Umwandeln von Audio und Videodateien. Das Tool ist im Paket libav-tools enthalten und kann wie folgt installiert werden:

sudo apt-get install libav-tools

Mithilfe des folgenden Kommandos lässt sich ein video an einer Zeitmarke teilen.

avconv -ss 1:37 -t 53 -i input.m4v output.mp4
# -ss start Zeitpunkt in MM:SS
# -t Zeit in Sekunden

Video deinterlace mit avconv

avconv ist ein CLI Tool zum Umwandeln von Audio und Videodateien. Das Tool ist im Paket libav-tools enthalten und kann wie folgt installiert werden:

sudo apt-get install libav-tools

Mithilfe des Filters yadif (Yet Another DeInterlacing Filter) lässt sich ein interlace video in ein deinterlaced video umwandeln.

avconv -i "input.m4v" -vf yadif output.m4v

Samstag, 22. Oktober 2016

MagPiDownloader

MagPiDownloader

Rund um das Raspberry Pi gibt es es das MagPi Magazin, welches man sich als freie pdf Version herunterladen kann. Um smir den Download zu vereinfachen, habe ich mir ein kleines python Skript geschrieben, welches mir die PDF Dokumente herunterlädt.

Dabei holt sich das Skript den Index vom Server unter 'https://www.raspberrypi.org/magpi-issues/', vergleicht die dort aufgeführten Dokumente mit meinem lokalen Ordner und lädt nur die neuen Dokumente herunter.

Kurz gesagt mein Ordner wird mit dem Server synchronisiert.

Example output:

# download new file
./getMagpi.py 
> Found new file: Essentials_Bash_v1.pdf
> [==================================================] 2.35MB:2.35MB  
# there is no new file
./getMagpi.py 
> No new files found

Quelle

Das Skript befindet sich auf github unter folgendem Repository https://github.com/f0xd3v1lsw1ld/MagPiDownloader.git

Installation

  1. install beautifulsoup sh $ sudo pip install beautifulsoup4
  2. create folder to store the MagPi editions sh $ mkdir --parents ~/Dokumente/books/MagPi
  3. go in the new directory and clone the repository sh $ cd ~/Dokumente/books/MagPi $ git clone https://github.com/f0xd3v1lsw

Usage

go in the MagPi directory and run the script sh $ cd ~/Dokumente/books/MagPi $ ./getMagpi.py

Mittwoch, 29. Juni 2016

Bilder verkleinern mit imagemagick

Unter Linux gibt es die Toolsammlung imagemagick mit der viele Bildverarbeitungsschritte (z.b. resize, convert, flip, mirror etc.) direkt auf der Kommandozeile erledigt werden können. Für den vollen Funktionsumfang der Toolsammlung verweise ich hier auf die detaillierte Dokumentation auf https://www.imagemagick.org. Ich beschränke mich hier nur auf die resize Option. Denn durch diese bin ich auf die Toolsammlung gestoßen.

Mein Ziel war es die Bilder in der Auflösung auf 50% zu verkleinern, um diese via Cloud Dienst mit Bekannten zu teilen.

Installation

Um die Toolsammlung imagemagick zu installieren, kann folgender Befehl verwendet werden.

sudo apt-get install imagemagick

Beispiele

Durch die Installation sind die Tools convert und mogrify verfügbar. Beide bieten umfangreiche Optionen welche z.B. durch den Parameter -? angezeigt werden können.

Wenn die Bilder in der Größe verändert werden sollen, das Original aber erhalten bleiben soll, muss convert verwendet werden. Hier ein Beispiel für ein einzelnes Bild:

$ convert IMG_2016-06-26-11_10_32.jpg -resize 50% half.jpg

Wenn das Original überschrieben werden soll, kommt mogrify zum Einsatz.

$ mogrify -resize 50% IMG_2016-06-26-11_10_32.jpg

Hier noch ein Beispiel wie alle JPGs im aktuellen Verzeichnis verarbeitet werden können.

$ mogrify -resize 50% *.jpg

Dienstag, 21. Juni 2016

Update photoworkflow

Release Notes:

Source on github: https://github.com/f0xd3v1lsw1ld/photoworkflow

  • Anzeige Prozessfortschritt für Prüfsummenberechnung und Kontrolle, ob die Bilder schon in der Photosammlung sind
  • Anzeige Prozessfortschritt für Umbenennung mit exiftool   
  • Anzeige Prozessfortschritt für Import der neuen Bilder in die Photosammlung 
  • Überarbeitung der Ausgabe um Benutzerfreundlichkeit zu verbessern

Sonntag, 19. Juni 2016

Videos mit ExifTool organisieren

In einem früheren Eintrag habe ich beschrieben, wie mit Hilfe von ExifTool die eigene Fotosammlung organisiert werden kann. Neben Fotos kann man damit aber auch Videos organisieren, welche über Exif Informationen verfügen. Dies ist meistens bei den aktuellen Smartphones der Fall. Besonders wenn die durch das Smartphone aufgezeichneten Videos keine Datumsinformation im Dateinamen haben, kann dies sehr leicht mit ExifTool entsprechend umbenannt werden.

Tags anzeigen

Im ersten Schritt muss geprüft werden, ob die zu bearbeitenden Videos über Exif Informationen verfügen. Dies kann durch den Parameter -a erfolgen. Für eine Umbennenung anhand des Aufnahmezeitpunktes kann z.B. der TAG Media Create Date verwendet werden.

Hier ein Besipiel:

$exiftool -a MOV_0107.mp4

ExifTool Version Number         : 9.46
File Name                       : MOV_2016-06-07-09_38_06.mp4
Directory                       : .
File Size                       : 4.2 MB
File Modification Date/Time     : 2016:06:08 19:22:27+02:00
File Access Date/Time           : 2016:06:08 20:15:45+02:00
File Inode Change Date/Time     : 2016:06:08 20:15:28+02:00
File Permissions                : rwxr-----
File Type                       : MP4
MIME Type                       : video/mp4
Major Brand                     : MP4 v2 [ISO 14496-14]
Minor Version                   : 0.0.0
Compatible Brands               : isom, mp42
Movie Header Version            : 0
Create Date                     : 2016:06:07 09:38:06
Modify Date                     : 2016:06:07 09:38:06
Time Scale                      : 1000
Duration                        : 2.27 s
Preferred Rate                  : 1
Preferred Volume                : 100.00%
Matrix Structure                : 1 0 0 0 1 0 0 0 1
Preview Time                    : 0 s
Preview Duration                : 0 s
Poster Time                     : 0 s
Selection Time                  : 0 s
Selection Duration              : 0 s
Current Time                    : 0 s
Next Track ID                   : 3
Handler Type                    : Metadata Tags
Com Android Version             : 6.0
Track Header Version            : 0
Track Create Date               : 2016:06:07 09:38:06
Track Modify Date               : 2016:06:07 09:38:06
Track ID                        : 1
Track Duration                  : 2.27 s
Track Layer                     : 0
Track Volume                    : 0.00%
Matrix Structure                : 0 1 0 -1 0 0 0 0 1
Image Width                     : 1280
Image Height                    : 720
Media Header Version            : 0
Media Create Date               : 2016:06:07 09:38:06
Media Modify Date               : 2016:06:07 09:38:06
Media Time Scale                : 90000
Media Duration                  : 2.27 s
Handler Type                    : Video Track
Handler Description             : VideoHandle
Graphics Mode                   : srcCopy
Op Color                        : 0 0 0
Compressor ID                   : avc1
Source Image Width              : 1280
Source Image Height             : 720
X Resolution                    : 72
Y Resolution                    : 72
Bit Depth                       : 24
Pixel Aspect Ratio              : 65536:65536
Video Frame Rate                : 29.968
Track Header Version            : 0
Track Create Date               : 2016:06:07 09:38:06
Track Modify Date               : 2016:06:07 09:38:06
Track ID                        : 2
Track Duration                  : 2.23 s
Track Layer                     : 0
Track Volume                    : 100.00%
Matrix Structure                : 1 0 0 0 1 0 0 0 1
Media Header Version            : 0
Media Create Date               : 2016:06:07 09:38:06
Media Modify Date               : 2016:06:07 09:38:06
Media Time Scale                : 48000
Media Duration                  : 2.23 s
Handler Type                    : Audio Track
Handler Description             : SoundHandle
Balance                         : 0
Audio Format                    : mp4a
Audio Channels                  : 2
Audio Bits Per Sample           : 16
Audio Sample Rate               : 48000
Movie Data Size                 : 3603346
Movie Data Offset               : 810282
Avg Bitrate                     : 12.7 Mbps
Image Size                      : 1280x720
Rotation                        : 90

Video Umbennen

Um ein oder mehrer Videos entsprechend des Aufnahmezeitpunktes umzubennen, kann folgender Aufruf von ExifTool verwendet werden. In diesem Beispiel werden alle MP4 Videos in folgendes Zielformat gebracht "MOV_2016-06-07-09_38_08.mp4" Meine Videos versehe ich mit dem Prefix "MOV", gefolgt vom Aufnahmejahr, Monat, Tag, der Uhrzeit und einer laufenden Nummer. Diese verhindert Probleme bei Videos mit identischen Zeitstempeln.

exiftool -m "-filename<MediaCreateDate" -d MOV_%Y-%m-%d-%H_%M_%S%%-c.%%le *.mp4 

Erklärung:

  • "-m" weist ExifTool an kleinere Warnungen zu ignorieren
  • "-filename<MediaCreateDate" gibt an Welcher Exif Tag verwendet werden soll
  • "-d" definiert das Ausgabeformat für die Umbenennung
  • "*.mp4" Filter, damit nur Dateien mit der Endung mp4 verarbeitet werden.

Dienstag, 31. Mai 2016

GIT Server einrichten

Im vergangen Post habe ich beschrieben, wie der Umstieg von svn zu git erfolgen kann. Ich hatte bis dahin meine Projekte in einem svn Repository gepflegt, wobei einer meiner Raspberry Pis als SVN Server fungierte. In diesem Post beschreibe ich, wie ein git Server am Beispiel des Raspberry Pis eingerichtet wird.

Dafür gibt es eine grundsätzliche Vorgehensweise, auf die ich zunächst in einem "vereinfachten" Beispiel eingehen werde. Später werde ich noch eine ausführlichere Einrichtung (mit eigenen user für den Server) beschreiben.

1. einfache Konfiguration

Zunächst muss auf dem Target git installiert werden, für die Funktion als Server reich das Paket git-core.

# server
sudo apt-get install git-core

Für das einfache Beispiel arbeiten wir unter dem standard User, am Beispiel des Raspberry Pis also dem User pi. Wie man für den Server einen eigenen User anlegt und konfiguriet, beschreibe ich im Kapitel 2.

Wir wechseln also in das Home Verzeichnis und legen uns einen Stammordner für alle Repositories und darin einen Ordner für das Projekt an. Standardmäßig sollten git Projektordner immer mit *.git benannt werden, da der Pfad auch in der späteren URL verwendet wird.

# server
cd ~
mkdir git_repositories
mkdir projectname.git

Anschließend wird in das Projektverzeichnis gewechslt und ein leeres git Repositorie angelegt.

# server
cd projectname.git
git init --bare
>>Initialisierte leeres Git-Repository in /home/pi/projectname.git/

Damit ist die Server Konfiguration schon abgeschlossen und wir wechseln auf den Entwicklungsrechner.

Wenn man bereits ein vorhandes git Repositorie hat, wechselt man in dieses und fügt den neuen Server als remote hinzu. Falls man noch kein Repositorie hat, legt man dieses zunächst an. Anschließend wird der Stand auf den neuen Server gepushed. Als Beispiel verwende ich die IP meines Servers, diese muss natürlich angepasst werden.

# client
cd projectname
git remote add pi pi@192.168.1.123:/home/pi/projectname.git
git push pi master

# push all tags and branches to server
git push --all pi

Ob die Konfiguration auf dem Entwicklungsrechner korrekt ist, kann man z.b. mittels git remote -v testen. Damit wird sowohl die push als auch die fetch URL des Servers ausgegebe.

# client
$git remote -v
pi  pi@192.168.1.123:/home/pi/projectname.git (fetch)
pi  pi@192.168.1.123:/home/pi/projectname.git (push)

Abschließend kann mit folgendem Kommando das Repositorie vom neuen Server gecloned werden.

git clone pi@192.168.1.123:/home/pi/projectname.git

2. erweiterte Konfiguration

to do

Freitag, 13. Mai 2016

SVN zu Git Migration

Bis jetzt habe ich meine Projekte in einem svn Repository gepflegt. In letzter Zeit habe ich mich aber vermehrt mit git als Mittel zur Sourcecodeverwaltung beschäftigt. Daher entwickelte sich bei mir das Interesse, meine bestehenden Projekte von svn zu git zu migirieren. Eine sehr gute Dokumentation über git bietet folgende Seite git-scm.com

An dieser Stelle beschreibe ich, wie ein svn Projekt in ein git Projekt importiert werden kann. Dazu werde ich nur die einzelnen Schritte festhalten. Eine detailierte Dokumentation kann dem Kapitel 9.2 Git and Other Systems - Migrating to Git der obigen Seite entnommen werden.

Für die Migration von svn zu git wird das Paket "git-svn" benötigt. Falls dieses noch nicht vorhanden ist, kann dieses wie folgt installiert werden.

sudo apt-get update && sudo apt-get install git-svn

Jetzt kann mittels dem Befehl git svn clone "svn-url" ein svn Repository in ein git Repository umgewandelt werden. Dazu folgende Randbedingungen:

  1. Dieser Befehl klappt nur, wenn das svn Repository aus den "standard" Verzeichnissen trunk, branches und tags besteht. Wenn davon abgewichen wird, können diese mittels der Parameter -T, -b und -t angepasst werden.
  2. Weiterhin empfielt sich der Parameter --no-metadata. Damit sehen die commit Nachrichten besser aus, da die git-svn-id nicht eingetragen wird.
  3. Evtl. ist es notwendig ein Mapping der Autoren vorzunehmen. Dazu kann der Parameter --authors-file=users.txt verwendet werden. In der users.txt sind dann alle Autoren im format svn-user = git-user aufzuführen.

Für mein Beispiel Projekt ergab sich daraus folgender Befehl:

git svn clone http://192.168.2.112:8002/svn/repo/callist -T trunk -b branch -t tags --no-metadata

Durch diesen Schritt wurde aber nur der svn trunk in den git master branch überführt. Evtl. svn tags und branches bestehen noch als unschöne remote branches.

Um die Tags des SVN Repositories in git tags umzuwandeln, müssen deren Referenzen aus dem remote kopiert werden.

cp -Rf .git/refs/remotes/tags/* .git/refs/tags/

Anschließend können diese gelöscht werden.

rm -Rf .git/refs/remotes/tags

Diesen Schritt kann man mit dem Befehl git tag kontrollieren. Damit sollten nun alle Tags des svn Repositories auch im git Repository aufgelistet werden.

Um die Referenzen der Branches zu übernehmen, werden auch diese kopiert und anschließend aus dem remote gelöscht.

cp -Rf .git/refs/remotes/* .git/refs/heads/
rm -Rf .git/refs/remotes

Um die übernommen Branches zu kontrollieren, können diese mittels git branch -av aufgelistet werden. Dabei wird auffallen, dass auch für den svn trunk ein Branch angelegt wurde. Da sich dieser mit dem master Branch doppelt, kann er gelöscht werden.

git branch -d trunk

Damit ist die Migration von svn zu git abgeschlossen.

Wenn man möchte kann das so erzeugte lokale Repository noch auf einem Server gepusht werden. Dazu muss dieser als remote hinzugefügt werden und alle branches und tags gepusht werden.

git remote add orogin user@server_ip:repo_name.git
git push origin --all
git push origin --tags

Python logging modul Beispiel

Bei Python ist auch ein recht umfangreiches Logging Modul enthalten. Hier möchte ich ein einfaches Beispiel aufführen, wie dieses verwendet werden kann. Die sehr ausführliche Dokumentation zum Thema Python und Logging kann unter folgender SeitePython Logging How to nachgelesen werden.

Das Logging Modul ist sehr mächtig und bietet eine vielzahl von Konfigurationsmöglichkeiten. Ich beschränke mich hier nur auf ein grundlegendes Beispiel. Um das Logging Modul zu verwenden, muss dieses Eingebunden werden und eine initiale Konfiguration angelegt werden.

import logging
# Festlegung des Lognames, z.b. Name der Applikation
logger = logging.getLogger('example_logger')
# Festlegung des Loglevels
logger.setLevel(logging.DEBUG)

Zwei der am häufigsten verwendeten Logging Ausgaben sind das Loggen auf die Konsole und in ein Logfile. Für diese Umsetzung muss ein entsprechender Logging Handler erzeugt und hinzugefügt werden.

# Für das Loggen auf die Konsole wird ein StreamHandler benötigt
ch = logging.StreamHandler()
# Für das Loggen in eine Datei wird wiederum ein FileHandler benötigt
fh = logging.FileHandler("example.log")

Wie bei der initialen Konfiguration bereits angegeben, unterstützt das Logging Modul verschiedene Logging Level. Diese haben hinsichtlich ihres Schweregrads folgende, aufsteigende Abstufung. - DEBUG - INFO - WARNING - ERROR - CRITICAL

Das Logging Modul bietet die Möglichkeit für jeden Logging Handler ein separates Level festzulegen. Dadurch erfolgt eine Filterung der Logs, bezüglich ihrer Ausgabe, bezogen auf das Logging Medium

# Auf der Konsole werden nur Logs mit Level INFO oder höher ausgegeben
ch.setLevel(logging.INFO)
# In das Logfile werden auch die Debug Logs geschrieben
fh.setLevel(logging.DEBUG)

Neben dem Loglevel kann auch das Logformat festgelegt werden. Für dieses Beispiel ist jeder Logeintrag wie folgt aufgebaut: "Zeitpunkt [Loglevel] Logname: Lognachricht"

formatter = logging.Formatter('%(asctime)s [%(levelname)s]: %(name)s: %(message)s')
# Die Formatierung muss noch den Handlern zugewiesen werden
ch.setFormatter(formatter)
fh.setFormatter(formatter)

Im letzten Schritt müssen die konfigurierten Logging Handler noch dem Logger hinzugefügt werden. Anschließend kann über den Loger in die Datei und auf die Konsole geloggt werden.

# add both handler to logger
logger.addHandler(ch)
logger.addHandler(fh)
#start logging, only in the logfile
logger.debug("start")

Hier noch einige Beispiele mit der zugehörigen Ausgabe:

#this will be printed on the console and to the logfile
self.logger.critical("This is a critical message")
#this will be printed on the console and to the logfile
self.logger.error("This is an error message")
#this will be printed on the console and to the logfile
self.logger.warning("This is a warning message")
#this will be printed on the console and to the logfile
self.logger.info("This is an info message")
#this will be printed only on the console
self.logger.debug("This is a debug message")
$cat example.log
2016-05-13 20:26:52,497 [DEBUG]: example_logger: start
2016-05-13 20:26:52,497 [CRITICAL]: example_logger: This is a fatal message
2016-05-13 20:26:52,497 [ERROR]: example_logger: This is an error message
2016-05-13 20:26:52,498 [WARNING]: example_logger: This is a warning message
2016-05-13 20:26:52,498 [INFO]: example_logger: This is an info message
2016-05-13 20:26:52,498 [DEBUG]: example_logger: This is a debug message

Den Code zu diesem Beispiel gibt es in meinem github Repository.

Donnerstag, 5. Mai 2016

raspberry pi als host für mehrere webseiten

Motivation

In meinem letzten Post Zusammenspiel von lighttpd und pelican habe ich beschrieben, wie eine eigene Webseite (am Beispiel meines Blogs) mit Hilfe von lighttpd vom Raspberry Pi gehostet werden kann. Wenn man sich einmal diese Mühe gemacht hat, will man evtl. auch weitere Seiten im lokalen Netz verfügbar haben. Dafür ist es aber nicht notwendig für jede Seite ein eigens Board einzurichten. Mit lighttpd kann man mehrere Seiten von einem Host zur Verfügung stellen.

Installation

Für die grundlegene Installation von lighttpd verweise ich an dieser Stelle auf meinen Post: Zusammenspiel von lighttpd und pelican

Konfiguration

Damit mit lighttpd mehrere Seiten gehosted werden können, gibt es verschiedene Möglichkeiten. Wenn man danach sucht, findet man am häufigsten das Modul mod_simple_vhost. Diese Konfiguration beruht aber auf der Grundlage, das der Server über eine Domäne (z.B. example.org) oder eine Subdomäne (mail.example.org) erreichbar ist. Dies ist für meinen Zweck zu viel Aufwand, da hierfür ein Nameserver für das eigene LAN aufgesetzt werden muss. Mir reicht es, wenn ich den Server via IP (z.b. 192.168.1.123) ansprechen kann.

Eine weitaus einfacher Möglicheit bietet daher das Modul mod_alias. Mit diesem kann für ein url-subset (z.b. /example) ein eigenes Dokumenten Root Verzeichnis hinterlegt werden. Hier mein Beispiel:

<IP>  => Zeigt auf meinem Blog, mit root-dir /var/www/html/blog
<IP>/one   => Zeigt auf eine zweite Seite, mit root-dir /var/www/html/one/pages
<IP>/two   => Zeigt auf eine dritte Seite, mit root-dir /var/www/html/two/pages

Im ersten Schritt müssen die root-Verzeichnisse angelegt werden.

mkdir /var/www/html/blog
mkdir /var/www/html/one/pages
mkdir /var/www/html/two/pages

Jetzt wird für jede Seite eine index.html (oder der entsprechende Inhalt) angelegt.

echo "Blog" >/var/www/html/blog/index.html
echo "one" >/var/www/html/one/index.html
echo "two" >/var/www/html/two/index.html

Anschließend kann die Konfiguration von lighttpd vorgenommen werden. Begonnen wird mit der Aktivierung des Moduls mod_alias. Hierfür muss das Modul in die Liste der aktvierten Servermodule eingetragen werden. Dazu muss die lighttpd.conf wie folgt bearbietet werden.

$sudo  vi /etc/lighttpd/lighttpd.conf 
...
# "mod_alias" unter server.modules eintragen
server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
        "mod_status",
)
...

Die weitere Konfiguration kann auch in dieser Datei erfolgen. Zuerst muss man sich dafür entscheiden, welche Seite bei einfacher Eingabe der IP als Default angezeigt werden soll. Ich habe mich für meinen Blog entschieden. Dafür muss folgende Zeile eingetragen/angepasst werden.

server.document-root        = "/var/www/html/blog"

Für die beiden weiteren Seiten, müssen die folgenden Zeilen ergänzt werden. Diese leiten bei Eingabe des IP/url-subset an das entsprechende Root Verzeichnis der Seite.

alias.url = ( "/one" => "/var/www/html/one/pages" )
alias.url += ( "/two" => "/var/www/html/two/pages" )

Abschließend wird die Datei gespeichert und mit folgenden Kommando die Syntax geprüft.

$lighttpd -t -f /etc/lighttpd/lighttpd.conf
Syntax OK

Ist alls OK, kann lighttpd neugestartet werden, damit die neue Konfiguration aktiv wird.

sudo service lighttpd restart

Jetzt kann man im Browser die drei Seiten durch Eingabe der IP und dem url-subset aufrufen.

<IP>     => blog Seite als default
<IP>\one => Seite one
<IP>\two => Seite two

Donnerstag, 28. April 2016

Zusammenspiel von lighttpd und pelican

Motivation

Seit kurzen schreibe ich meinen Blog mit Hilfe von markdown und dem Weseitengenerator pelican. Das funktioniert auch ganz gut. Pelican rendert aus den Posts eine HTML Seite, welche ich mittels markdown geschreiben habe. Diese muss ich dann nur noch bei blogger "hinein" kopieren. Alternativ möchte ich meinen Blog auch in meinem lokalen Netz (von einem Raspberry Pi) gehostet haben. Dies bietet mir die Möglichkeit, schnell mal etwas zu probieren und noch nicht fertige Posts vorab schon einmal zu begutachten. Grundsätzlich geht das auch mit dem bei pelican enthalten "develop_server.sh" Skript, aber nur auf dem Rechner wo ich pelicaninstalliert habe.

Als Webserver verwende ich daher lighttpd. Dieser ist ein Ressourcen sparender Webserver, ideal geeignet für statische Seiten und für das Raspberry Pi.

Installation

Der Webserver kann direkt aus den Paketquellen installiert werden.

sudo apt-get install lighttpd

Anschließend ist er direkt unter der IP des Servers und Port 80 erreichbar. Dazu einfach die IP in den Browser eingeben und die "Placeholder page" erscheint. Darin sind folgende Informationen dokumentiert:

  • Die Readme liegt unter /etc/lighttpd/conf-available/README
  • Die Konfigurations Datein befinden sich in /etc/lighttpd
  • Das Dokumenten root Verzeichnis liegt in /var/www/html

Standardmäßig läuft der Webserver unter dem User/Group www-data, d.h. dieser muss zumindes Leserechte für das Dokumenten root Verzeichnis haben. Für meine Zwecke habe ich die Rechte wie folgt gesetz:

#Besitzer des Dokumenten root ist der www-data user und dessen Gruppe
$sudo chown -R www-data:www-data html/
#die Zugriffsrechte habe ich wie folgt gesetz
$sudo chmod -R 750 /var/www/html/
#damit ich in das Verzeichnis schreiben kann, füge ich den user (am Beispiel pi) der Gruppe www-data hinzu
$sudo usermod -g www-data pi
#und gebe allen Gruppenmitgliedern Schreibrechte für den Ordner
$sudo chmod -R g+w /var/www/html/
#Ergebnis
$ls -l /var/www
drwxrwx--- 2 www-data www-data 4096 Apr 26 23:21 html

Konfiguration

Die Konfiguration von lighttpd erfolgt durch :die Datei /etc/lighttpd/lighttpd.conf. Ich habe für diesen Anwendungszweck keine weitere Konfiguration vorgenommen.

Deployment

Auf dem host und dem target muss rsync installiert sein bzw. werden.

sudo apt-get install rsync

Anschließend wechselt man in das Projektverzeichnis von pelican und kopiert den Inhalt des von pelican erzeugten output Ordners auf dem Server in das Dokumenten root Verzeichnis. Hier das Beispiel für meine Konfiguration

cd ~/myblog
rsync -rvzc output/ user@ip:/var/www/html/

Um diesen Prozess zu vereinfachen bietet pelican die Möglichkeit das Deployment via Makefile zu übernehmen. Dazu muss die Server Zugangsdaten wie folgt eingetragen werden:

$vi Makefile
SSH_HOST=<IP>
SSH_PORT=22
SSH_USER=<USER>
SSH_TARGET_DIR=/var/www/html

Der Upload zum Server kann anschließend mit

make rsync_upload

erfolgen. Neben dieser Möglichkeit wird auch der Upload via ssh, dropbox, ftp oder github angeboten.

Weiterhin kann für das dadurch erfolgende Veröffentlichen der Seite die zugehörige pelican Konfiguration angepasst werden. In dieser kann z.B. die Generierung von Feeds eingestellt werden. Dies erfolt in der Datei publishconf.py. Die zugehörige Dokumentation gibt es auf der Projektseite.

Sonntag, 24. April 2016

Backup SD-Karte

Zielstellung

Erstelung eines Backups einer SD-Karte am Beispiel Raspberry Pi. Reduzierung des benötigten Speicherplatzes auf dem Host.

Ergebnis

Device Größe in GB Größe in 1M-Blöcke
SD-Karte 15G 56M + 14484M
backup.img 15G 14840M
backup.tar.gz 5.0G 5019M
backup.img(1) 7.5G 7598M
backup.tar.gz(1) 4.5G 4601M

(1) Mit verkleinerter rootfs Partition.

Zur Anzeige der Größe in 1M-Blöcken, wurden folgende Kommandos verwendet.

#für Verzeichnisse
ls --block-size=M -l
#für Device X
df --block-size=M /dev/sdbX

Hintergrund

Eine SD-Karte für das Raspberry Pi enthält zwei Partitionen. Die Erste ist die s.g. Boot Partition, welche den Bootloader, das Kernel Image usw. enthält. Die Zweite enthält das Rootfs mit den eigentlichen Daten. Mit dem tool raspi-config, kann die zweite Partition auf die Größe der verwendeten SD-Karte erweitert werden. Die folgende Ausschrift wurde mittels fdisk (vom HOST aus) erstellt und enthält den Inhalt einer 16GB SD-Karte, welche hier als Beispiel genommen wird.

#das verwendete device muss an das eigene System angepasst werden
$sudo fdisk -l /dev/sdb
Disk /dev/sdb: 15.6 GB, 15560867840 bytes
64 Köpfe, 32 Sektoren/Spur, 14840 Zylinder, zusammen 30392320 Sektoren
Einheiten = Sektoren von 1 × 512 = 512 Bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Festplattenidentifikation: 0x00092fac

   Gerät  boot.     Anfang        Ende     Blöcke   Id  System
/dev/sdb1            8192      122879       57344    c  W95 FAT32 (LBA)
/dev/sdb2          122880    30392319    15134720   83  Linux

Mit dem Tool df kann der freie Speicherplatz angezeigt werden.

$df -h /dev/sdb1
Dateisystem    Größe Benutzt Verf. Verw% Eingehängt auf
/dev/sdb1        56M     23M   34M   40% /media/boot
$df -h /dev/sdb2
Dateisystem    Größe Benutzt Verf. Verw% Eingehängt auf
/dev/sdb2        15G    6,8G  6,8G   51% /media/rootfs

Wie man sieht wurde das rootfs auf die volle Größe der SD-Karte erweitert und ist zur Hälfte befüllt.

Backup erstellen

Um das Backup zu erstellen, kann am einfachsten auf dd zurückgegriffen werden. Dieses erzeugt ein vollständiges Abbild der gesamten SD-Karte, d.h. es wird ein Image mit der selben Größe wie die der SD-Karte angelegt, egal ob das rootfs auf die gesamte Größe erweitert wurde. Zum Lesen des SD-Karten Devices werden root Rechte benötigt, um das Image anschließend zu bearbeiten, müssen die Rechte entsprechend geändert werden.

#das verwendete device muss an das eigene System angepasst werden
$sudo dd if=/dev/sdb of=backup.img
$sudo chown user:usergroup backup.img

Standardmäßig zeigt dd keinen Fortschritt an, dies kann aber wie folgt "ergänzt" werden. Hiermit wird dd zyklisch ein Signal gesendet, in Folge dessen es den aktuellen Stand des Kopierprozesses ausgibt.

$ sudo dd if=/dev/sdb of=backup.img&
[1] pid
$ sudo watch --interval 10 kill -USR1 pid
Alle 10,0s: kill -USR1 6068
...
5121777+0 Datensätze ein
5121776+0 Datensätze aus
2622349312 Bytes (2,6 GB) kopiert, 54,0639 s, 48,5 MB/s
...
#Am Ende muss watch noch mit STRG+C beendet werden.

Schaut man sich jetzt die Größe des Backups an, sieht man das es wie die SD-Karte 15GB groß.

Speicherplatz reduzieren

Der erste Ansatz die Größe des Backups zu reduzieren, ist das Image zu komprimieren.

tar -czf backup.tar.gz backup.img

Als Ergebnis reduziert sich die Größe von 15GB auf 5GB. Wenn das ausreichend ist, kann an dieser Stelle aufgehört werden.

Optimierung

Wenn man die komprimierte Größe weiter reduzieren möchte, können folgende Punkte berücksichtigt werden.

Rootfs Partition verkleinern

Um ein SD-Karten Image unter Linux mit gparted zu bearbeiten, muss zuvor ein loop device angelegt werden. Dazu wird das tool losetup benötigt. Falls das loop modul als ladbares Kernel Modul verwendet wird, muss dieses zunächst geladen werden. Dieser Ansatz kann auch dafür verwendet werden, wenn man das Image auf einer kleineren SD-Karte (z.b. 16GB -> 8GB) verwenden möchte.

sudo modprobe loop

Als Zweites muss das erste freie loop device herausgesucht werden.

sudo losetup -f

Angenommen das erste freie loop device ist /dev/loop0, wird dieses verwendet, um dieses mit dem SD-Karten Image einzurichten.

sudo losetup /dev/loop0 backup.img

Im Nächsten Schritt wird die Partitions Tabelle des loop devices (eigentlich des SD-Karten Images) dem System bekannt gemacht.

sudo partprobe /dev/loop0

Jetzt können die Partitionen des SD-Card images mit gparted geändert (verkleinert/vergrößert) werden. Dazu die neue Größe so anlegen, dass diese etwas Größer ist, als der belegte Speicher des rootfs. An der Größe der boot Partition darf NICHTS geändert werden.

sudo gparted /dev/loop0

Am Ende kann das loop device mit folgendem Befehl wieder gelöscht werden.

sudo losetup -d /dev/loop0

Bis jetzt hat sich aber an der Image Größe noch Nichts geändert, nur die Partition des rootfs ist jetzt kleiner geworden. Das Ergebnis kann man sich wieder mittels fdisk ansehen.

$fdisk -l backup.img 

Disk backup.img: 15.6 GB, 15560867840 bytes
255 Köpfe, 63 Sektoren/Spur, 1891 Zylinder, zusammen 30392320 Sektoren
Einheiten = Sektoren von 1 × 512 = 512 Bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Festplattenidentifikation: 0x00092fac

     Gerät  boot.     Anfang        Ende     Blöcke   Id  System
backup.img1            8192      122879       57344    c  W95 FAT32 (LBA)
backup.img2          122880    15560703     7718912   83  Linux

Um jetzt auch das Image zu verkleinern, kann dieses mit truncate auf die geänderte Größe der Partionen angepasst werden.

#truncate --size=$[(Ende+1)*sector size] backup.img
truncate --size=$[15560704*512] backup.img 

In meinem Beispiel konnte die Größe des Image auf 7.5GB und komprimiert auf 4.5GB reduziert werden. Außerdem besteht so die Möglichkeit das Image ggfls. auch auf einer 8GB SD-Karte zu verwenden.

Rootfs aufräumen

Ein recht einfacher Weg die Größe zu reduzieren, ist nicht benötigte Daten zu löschen. Zuerst wird wie im Schritt "Rootfs Partition verkleinern" beschrieben, ein loop device angelegt, welches anschließend gemounten und bearbeitet werden kann.

mkdir rootfs
sudo mount /dev/loop0p2 rootfs
#löschen nicht benötigter Daten etc.
sudo umount rootfs

Komprimierung verbesseren

Zur Verbesserung der Komprimierung, kann der freie Speicherplatz mit NULL beschrieben werden, dazu kann das Tool zerofree verwendet werden. Dies ist Notwendig, da gelöschte Daten nicht physikalisch gelöscht werden, sondern nur der Eintrag im Dateisystem. Dies führt bei der Komprimierung dazu, dass dieser Bereich nicht optimal verkleinert werden kann. Wie stark der Effekt ist, hängt natürlich vom verwendeten Image ab. Be

Zuerst, wie im Schritt "Rootfs Partition verkleinern" beschrieben ein loop device anlegen, dann zerofree anwenden und am Ende das Image komprimieren.

sudo zerofree -n /dev/loop0p2

Powered by Pelican. Theme blueidea, inspired by the default theme.

Mittwoch, 20. April 2016

Raspberry Pi Benchmarks - Ein Vergleich der Generationen

Hardware Gegenüberstellung

Generation Architektur CPU SDRAM
RPi 1 ARMv6 BCM2835, single core 256/512 MB
RPi 2 ARMv7, Cortex-A7 BCM2836, quad core 1 GB
RPi 3 ARMv8, Cortex-A53 BCM2837, quad core 2 GB

Trotz 64bit Architektur wird der RPi 3 aus kompatibilitäts Gründen als 32 CPU betrieben.

Benchmarks

coremark

Coremark ist ein Performance Benchmark für embedded CPUs. Daher eignet er sich gut, um die drei Pi Generationen zu vergleichen. Nähere Details, weitere Ergebnisse und den Quellcode findet man auf der Webseite der Entwickler von EMBC.

Durchführung

Der Benchmark wurde per Skript mehrfach als Performance Run (ITERATIONS=160000) durchgeführt und die Ergebnisse gemittelt. Folgende compiler Schalter wurden dafür verwendet:

RPi1: export CC="gcc -march=armv6 -mfloat-abi=hard -mfpu=vfp"

RPi2/3: export CC="gcc -march=armv7-a --mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4"

Ergebnisse

CoreMark 1.0 : siehe Tabelle/ GCC4.9.2 -O2 -DPERFORMANCE_RUN=1 -lrt / Heap

Generation Ergebnis Ergebnis/MHz
RPi 1 900MHz 1849.1032 2.054
RPi 2 1000MHz 2315.0526 2.315
RPi 3 1200MHz 3164.2406 2.637

whetstone

Der whetstone Benchmark gehört zu den klassischen CPU Benchmarks. Ich habe hier die Version von der Roy Longbottom's PC Benchmark Collection verwendet. Auf dieser Seite wurden auch Ergebnisse für das Raspberry Pi veröffentlicht und es gibt weitere Details zu dem Benchmark.

Durchführung

Zur Durchführung habe ich den code wie folgt kompiliert.

  • RPI1: Single Precision C Benchmark Opt 3 32 Bit gcc whets.c cpuidc.c -lm -lrt -O3 -march=armv6 -mfloat-abi=hard -mfpu=vfp -o whetstonePiA6

  • RPi2/3: Single Precision C Benchmark vfpv4 32 Bit gcc whets.c cpuidc.c -lm -lrt -O3 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -o whetstonePiA7

Ergebnisse

Generation MFLOPS MFLOPS/MHz
RPi 1 900MHz 303.817 0.3376
RPi 2 1000MHz 486.357 0.4864
RPi 3 1200MHz 711.297 0.5927

dhrystone

Wie der whetstone handelt es sich beim dhrystone auch um einen klassischen Benchmark. Ich habe hier wieder die Version von der Roy Longbottom's PC Benchmark Collection verwendet. Auf dieser Seite gibt es auch die Hintergrundinformationen zu dem dhrystone Benchmark.

Durchführung

Zur Durchführung habe ich den code wie folgt kompiliert.

  • RPi1: gcc dhry_1.c dhry_2.c cpuidc.c -lm -lrt -O3 -march=armv6 -mfloat-abi=hard -mfpu=vfp -o dhrystonePiA6

  • RPI2/3: gcc dhry_1.c dhry_2.c cpuidc.c -lm -lrt -O3 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -o dhrystonePiA7

Ergebnisse

Generation VAX MIPS rating VAX MIPS rating/MHz
RPi 1 900MHz 1118.51 1.243
RPi 2 1000MHz 1833.64 1.834
RPi 3 1200MHz 1245.41 1.038 (todo: freq scaling prüfen)

UnixBench

Beim UnixBench handelt es sich um eine Sammlung von einzelnen Benchmarks, welche nacheinander durchgeführt werden. Am Ende des Tests werden die Einzelergebnisse und als Zusammenfassung ein Index Score zur Bewertung des Systems in einer HTML ausgegeben. Ich habe den Benchmark in der Version 5.1.3 ausgeführt.

Durchführung

Der Benchmark wird durch ausführen des enthaltenden RUN Skriptes gestartet. Die HTML mit den Ergebnissen wird in das Verzeichnis results geschrieben. Folgende Tests werden durchgeführt:

  • Dhrystone
  • Whetstone
  • Execl Throughput
  • File Copy
  • Pipe Throughput
  • Pipe-based Context Switching
  • Process Creation
  • Shell Scripts
  • System Call Overhead

Ergebnisse

Die folgende Tabelle enthält zur Gegenüberstellung der Pi Generationen nur den Index Score als Ergebnis.

Benchmark Run: 1 CPU; 1 parallel process

Generation System Benchmarks Index Score
RPi 1 900MHz 100
RPi 2 1000MHz 154.5
RPi 3 1200MHz 171.8

Benchmark Run: 4 CPUs; 4 parallel process

Generation System Benchmarks Index Score
RPi 1 900MHz -
RPi 2 1000MHz 266.7
RPi 3 1200MHz 361.8

sysbench

Bei sysbench handelt es sich um einen Systembenchmark bei dem verschiedene Anwendungsfälle untersucht werden können. Der Benchmark wurde in Version sysbench 0.4.12 durchgeführt und enthält folgende Tests:

  • CPU performance benchmark
  • memory operations speed test
  • file IO performance

Durchführung/Ergebnisse

Die Installation erfolgte mittels

$sudo apt-get install sysbench

CPU performance benchmark

$sysbench --test=cpu --cpu-max-prime=10000 --num-threads=1 run >cpu_single_thread.txt
$sysbench --test=cpu --cpu-max-prime=10000 --num-threads=4 run >cpu_multi_thread.txt

Maximum prime number checked in CPU test: 10000

Generation single thread 4 threads
RPi 1 900MHz 389.4594s 390.2572s
RPi 2 1000MHz 261.8984s 107.4812s
RPi 3 1200MHz 183.8759s 88.8605s

memory operations speed test

$sysbench --test=memory --memory-block-size=1M --memory-total-size=10G --num-threads=1 run >memory_single_thread.txt
$sysbench --test=memory --memory-block-size=1M --memory-total-size=10G --num-threads=4 run >memory_multi_thread.txt

Memory block size: 1024K

Memory transfer size: 2048M

Memory operations type: write Memory scope type: global

Generation single thread 4 threads
RPi 1 900MHz 4.5108s 4.5222s
RPi 2 1000MHz 1.6497s 2.0846s
RPi 3 1200MHz 1.8262s 0.9973s

file IO

ToDo: Dieser Test muss mit einer größeren file-size wiederholt werden, damit der Einfluss des RAM Cache minimiert wird.

#vor test start
$sysbench --test=fileio --file-test-mode=rndwr --file-total-size=16MB --num-threads=1 prepare 
#am testende
$sysbench --test=fileio --file-total-size=16MB cleanup

random write

$sysbench --test=fileio --file-test-mode=rndwr --file-total-size=16MB --max-requests=1000 --num-threads=1 run >random_write_single_thread.txt
$sysbench --test=fileio --file-test-mode=rndwr --file-total-size=16MB --max-requests=1000 --num-threads=4 run >random_write_multi_thread.txt
Generation single thread 4 threads
RPi 1 900MHz 145.4520s 150.9156s
RPi 2 1000MHz 133.6695s 147.7475s
RPi 3 1200MHz 135.9898s 130.1161s

random read

$sysbench --test=fileio --file-test-mode=rndrd --file-total-size=16MB --max-requests=10000 --num-threads=1 run >random_read_single_thread.txt
$sysbench --test=fileio --file-test-mode=rndrd --file-total-size=16MB --max-requests=10000 --num-threads=4 run >random_read_multi_thread.txt
Generation single thread 4 threads
RPi 1 900MHz 0.5942s 0.7321s
RPi 2 1000MHz 0.2888s 0.2670s
RPi 3 1200MHz 0.2822s 0.0835s

From File /proc/cpuinfo

Zum Abschluss noch eine Übersicht über Systeminformationen der Pi Generationen.

Raspberry Pi 1

processor   : 0
model name  : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS    : 2.57
Features    : half thumb fastmult vfp edsp java tls 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xb76
CPU revision    : 7

Hardware    : BCM2708
Revision    : 000e
Serial      : 00000000e8b7b357

Raspberry Pi 2

processor   : 0
model name  : ARMv7 Processor rev 5 (v7l)
BogoMIPS    : 38.40
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xc07
CPU revision    : 5

processor   : 1
model name  : ARMv7 Processor rev 5 (v7l)
BogoMIPS    : 38.40
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xc07
CPU revision    : 5

processor   : 2
model name  : ARMv7 Processor rev 5 (v7l)
BogoMIPS    : 38.40
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xc07
CPU revision    : 5

processor   : 3
model name  : ARMv7 Processor rev 5 (v7l)
BogoMIPS    : 38.40
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : Linux version 4.1.19-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #858 SMP Tue Mar 15 15:56:00 GMT 2016

Raspberry Pi 3

processor   : 0
model name  : ARMv7 Processor rev 4 (v7l)
BogoMIPS    : 76.80
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 1
model name  : ARMv7 Processor rev 4 (v7l)
BogoMIPS    : 76.80
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 2
model name  : ARMv7 Processor rev 4 (v7l)
BogoMIPS    : 76.80
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 3
model name  : ARMv7 Processor rev 4 (v7l)
BogoMIPS    : 76.80
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
CPU implementer : 0x41
CPU architecture: 7
CPU vLinux version 4.1.19-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #858 SMP Tue Mar 15 15:56:00 GMT 2016

Dienstag, 12. April 2016

Raspberry Pi Bootperformance - Ein Vergleich der Generationen

Zielstellung

Vergleich der Bootperformance eines Raspberry Pi 1 im Vergleich zur 2. und 3. Generation.

Rahmenbedingungen

Für den Test wurde ein raspbian-jessie-lite vom 18.03.2016 verwendet. Dieses wurde auf eine 8GB SanDisk mSDHC geflasht. Für alle drei Pi Generationen wurde die selbe Karte verwendet, beim RPi 1 wurde zusätzlich der SanDisk Adapter benötigt. Als Tool zur Zeitmessung wurde systemd-analyze (siehe Tools zur Bootanalyse) genutzt. Gemessen wurde die Zeit zwischen Anschluss der Spannungsversorgung und dem login prompt auf der Kommandozeile.

Durchführung

Die Bootperformance habe ich wie folgt gemessen:
  • Die mSDHC wurde in das Raspberry Pi gesteckt und das Board durch Zuführung der Spannungsversorgung gestartet.
  • Jetzt habe ich für die einzelnen Versuche die CPU Clocks in der /boot/config.txt konfiguriert.
  • Wie unter Tools zur Bootanalyse beschrieben, wurde bootchart installiert. Dieser Dienst hat natürlich (minimalen) Einfluss auf die Bootzeit des Systems.
  • Anschließend wurde das Board mit
$ sudo shutdown -h now
ausgeschaltet und durch einem Power Cycle neugestartet.
  • Nachdem der Login Prompt erscheint, wurde sich angemeldet und die Bootgrafiken mit
$ bootchart
$ systemd-analyze plot >systemd.svg
erzeugt.
  • Als Bootzeit wurde die Summe aus kernel + userspace (siehe systemd-analyze plot) in Sekunden der drei Generationen gegenübergestellt.
  • Anschließend wurde der Test für eine weitere Clock Konfiguration wiederholt. Die Ergebnisse wurden durch mehrfache Durchführung validiert.

Ergebnis

Die folgenden Tabellen enthält die Bootzeiten der drei RPi Generationen für verschiedene Konfigurationen.
SUMME
Raspberry Pi 700MHz 800MHz 900MHz 1000MHz 1200MHz 1200MHz BT disabled
RPi 1 21.848s (1) 18.540s 18.117s - - -
RPi 2 - - 11.068s (1) 8.813s - -
RPi 3 - - - - 13.482s 8.332s
kernel
Raspberry Pi 700MHz 800MHz 900MHz 1000MHz 1200MHz 1200MHz BT disabled
RPi 1 4.147s (1) 2.732s 2.732s - - -
RPi 2 - - 3.043s (1) 2.528s - -
RPi 3 - - - - 2.978s 2.971s
userspace
Raspberry Pi 700MHz 800MHz 900MHz 1000MHz 1200MHz 1200MHz BT disabled
RPi 1 17.701s(1) 15.808s 15.393s - - -
RPi 2 - - 8.025s (1) 6.285s - -
RPi 3 - - - - 10.504s 5.361s
(1) default Einstellung in /boot/config.txt
Hier ein Auszug aus dieser Konfigurationsdatei, mit den Stellen wo die CPU Clock eingetragen werden kann.
[pi1]
#Frequency of the ARM CPU in MHz.
arm_freq=900
[pi2]
#Frequency of the ARM CPU in MHz.
arm_freq=1000
[pi3]
#Frequency of the ARM CPU in MHz.
arm_freq=1200

Interpretation und Optimierung

Wie man den Tabellen entnehmen kann, ist Generationsübergreifend die CPU Clock ein wesentlicher Faktor zur Reduzierung der Bootzeit. Ein weiterer Faktor ist die Multicore Architektur (ab RPi2) in Kombination mit der ARMv7 Architektur (ebenfalls im RPi2). Dies wird besonders in der Gegenüberstellung RPi1 und RPi2 für 900MHz deutlich.
Auf den ersten Blick sehr erstaunlich ist, dass das RPi3 trotz 1200MHz langsamer bootet (~4.4s) als das RPi2. Durch Analyse der systemd-analyze Ausgabe wird ersichtlich, dass die Ursache im hciuart.service liegt. Dieser initialisiert beim Start das im RPi3 enthaltende Bluetooth Modul. Wird dieser Service durch
sudo systemctl disable hciuart.service 
deaktiviert, bootet der RPi3 (etwas) schneller als der RPi2. Das der Unterschied nicht größer Ausfällt liegt vermutlich daran, dass nicht die Geschwindigkeit der CPU, sondern die Bandbreite der SD-Card Schnittstelle der begrenzende Faktor ist. Gestützt wird diese Vermutung auch durch folgenden Auszug der zugehörigen bootchart Grafik:

Powered by Pelican. Theme blueidea, inspired by the default theme.

Samstag, 9. April 2016

Tools zur Bootanalyse

Auf dieser Seite möchte einige Tools dokumentieren, mit denen der Bootvorgang eines Linux Systems detailiert analysiert werden kann.

1. Bootchart

Bootchart ist ein Tool zur Analyse und Visualisierung der Performance des Linux boot processes. Die Analyse basiert darauf, dass während des Bootens zusätzliche Informationen gesammelt werden und diese anschließend ausgewertet werden können. So kann aus den Logfiles ein Zeitdiagram des Bootprozesses erzeugt werden.

Installation

Um das Tool nutzen zu können, muss dieses zunächst über den Paketmanager installiert werden.
$ sudo apt-get install bootchart

Einrichtung

Anschließend muss der bootchart daemon so eingerichtet werden, dass dieser beim init gestartet wird. Dies ist notwendig, um die benötigten Informationen beim Booten zu sammeln. Diese werden im RAM gehalten und nach Beendigung des Bootvorgangs gespeichert. Dazu muss wie folgt die Kernel command line angepasst werden.
#add init=/sbin/bootchartd add end of line
$ sudo vi /boot/cmdline.txt

Analyse Ablauf

  • Als Erstes muss wie beschrieben bootchart installiert und eingerichtet werden.
  • Anschließend muss ein System - Neustart durchgeführt werden. (z.b. per reboot oder via power cycle)
$ sudo shutdown -h now
# Power cycle durchführen
  • Nachdem das System erneut gebootet hat, sollte zuerst geprüft werden, ob bootchart eine Logdatei (/var/log/bootchart.tgz) angelegt hat.
  • Wenn diese Logdatei angelegt wurde, kann aus dieser wie folgt ein Chart generiert werden, das Bild liegt anschließend im aktuellen Verzeichnis. Das default Format ist svg.
$ bootchart
  • Jetz kann man sich das Bild anzeigen lassen und mit der Analyse beginnen.
Anbei ein Beispiel für das Raspberry Pi 3 mit raspbian-jessie-lite in der Version vom 18.03.2016.

2. systemd-analyze

Für Systeme welche mit systemd beim Booten gestartet werden, kann das bei systemd enthaltene Analyse Tool benutzt werden. Dieses erzeugt aus den beim Bootvorgang erstellten Logfiles eine Grafik, welche anschließend analysiert werden kann.

Einrichtung

Für die Einrichtung muss im Normalfall nichts unternommen werden. Wenn das System auf systemd basiert, sollte systemd-analyze bereits installiert sein.

Analyse Ablauf

  • Als erstes muss ein System - Neustart durchgeführt werden. (z.b. per reboot oder via power cycle)
$ sudo shutdown -h now
# Power cycle durchführen
  • Nachdem das System gebootet hat, kann die grafische Darstellung des Bootvorgangs mit systemd, wie folgt erstellt werden.
$systemd-analyze plot >systemd.svg
  • Jetz kann man sich das Bild anzeigen lassen und mit der Analyse beginnen.
Anbei ein Beispiel für das Raspberry Pi 3 mit raspbian-jessie-lite in der Version vom 18.03.2016.

Sonntag, 13. März 2016

OpenCV Dokumentation erzeugen

In meinem Eintrag OpenCV 3.1 Linux Mint 17.3 Cinnamon 64-bit habe ich beschrieben, wie man sich aus den Quellen OpenCV selber bauen kann. Hier erkläre ich, wie man aus diesen die offline Dokumentation für OpenCV zu erzeugen kann.

Zuerst laden wir uns die Quellen wie hier beschrieben herunter. Im nächsten Schritt erzeugen wir uns ein build Verzeichnis und installieren uns die benötigten Pakete.

$ wget https://github.com/Itseez/opencv/archive/3.1.0.zip
$ unzip 3.1.0.zip
cd opencv-3.1.0
mkdir build
sudo apt-get install doxygen pybtex

Jetzt können wir ins build Verzeichnis wechseln und konfiguieren OpenCv mit cmake, damit die Dokumentation für die Release Version gebaut wird.

cmake -D BUILD_DOCS=ON -D CMAKE_BUILD_TYPE=RELEASE ..

Die Dokumentation wird anschließend mit

make doxygen

erstellt. Die erzeugte Doku findet man im buildverzeichnis unter doc/doxygen/html. Durch öffnen der index.html kann man sich die Dokumentation im Browser ansehen. Natürlich kann man sich die Dokumentation auch in ein beliebiges Verzeichnis kopieren und z.b. mittels eines Webservers verfügbar machen.

Beispiel:

cp -r doc/doxygen/html ~/opencv_docu
firefox ~/opencv_docu/index.html

Powered by Pelican. Theme blueidea, inspired by the default theme.

Samstag, 12. März 2016

Linux gut zu wissen

Hier entsteht eine kleine Sammlung mit kurzen und hilfreichen CLI Schnipseln

Linux Output top level directory size only

du -h --max-depth=1

User einer Gruppe hinzufgen

sudo usermod -g "gruppe" "user"

komprimiertes Archiv erstellen

tar -czf archiv-tar.gz file1 file2

Konvertierung eines VirtualBox dynamische Images in ein statisches

Convert dynamic VirtualBox VDI volume to static

VBoxManage clonehd dynamic.vdi static.vdi --format VDI --variant Fixed

reset UUID

VBoxManage internalcommands sethduuid test.vdi

Samstag, 5. März 2016

OSMC - manuelles Update


Eines meiner Raspberry Pis verwende ich als Mediacenter am Wohnzimmer TV. Auf diesem ist das freie open source Mediacenter OSMC installiert. Dieses bietet u.A. auch eine automatische Update Funktion, welche bei mir teilweise nicht richtig will, daher verwende ich meist die manuelle Methode. Um diese anzuwenden, muss man sich zuerst am Pi per ssh anmelden und dann das Update Skript ausführen.
$ ssh osmc@<IP>
osmc@osmc:~$ sudo systemctl start manual-update
Anschließend beginnt das Update.


Powered by Pelican. Theme blueidea, inspired by the default theme.

Hacking Conrad WebKey

Auf der diesjährigen Embedded World gab es wieder einige mehr oder wenige sinnvolle Werbegeschenke. Eines davon ist der USB-WebKey der Fa. Conrad.
Dieser funktioniert so: Nachdem er an den PC angeschlossen wurde, meldet er sich als HID an und nach dem er betätigt wurde, sendet er einige vorgefertige Tastaturcodes an den PC. Ziel ist es, dass mit dem Standard Browser die Webseite "www.community.conrad.com" angezeigt wird.

Erster Test, unter Linux Mint

Kurz gesagt, der WebKey funktioniert unter meinem Linux Mint nicht.
Nach kurzer Internet Recherche sieht es so aus, dass dies beabsichtigt ist. Grund ist sehr wahrscheinlich, dass Sicherheitsrisiko, was mit diesem WebKeys einhergeht. Schließlich ist vorab nicht abzusehen, was dieser alles so anstellen.
Wenn bei geöffnetem Terminal der Key betätigt wird, erscheint nur Kauderwelsch.
11911911946991111091091171101051161214699111110114971004699111109 r


Zumindest lässt sich unter Linux einges mehr über das Gerät herausfinden.

dmesg

Schauen wir uns zuerst an, als was sich der WebKey im System anmeldet. Dazu folgender dmesg Auszug:
[  183.980631] usb 1-4: new low-speed USB device number 3 using xhci_hcd
[  184.170001] usb 1-4: New USB device found, idVendor=05ac, 
idProduct=020b
[  184.170009] usb 1-4: New USB device strings: Mfr=1, Product=2, 
SerialNumber=0
[  184.170012] usb 1-4: Product: WebKey
[  184.170015] usb 1-4: Manufacturer: WebKey
[  184.170318] usb 1-4: 
ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
[  184.174468] input: WebKey WebKey as /devices/pci0000:00/0000:00:14.0/
usb1/1-4/1-4:1.0/0003:05AC:020B.0003/input/input15
[  184.229367] hid-generic 0003:05AC:020B.0003: input,hidraw2: USB HID 
v1.10 Keyboard [WebKey WebKey] on usb-0000:00:14.0-4/input0


Wie man sieht handelt es sich um einen WebKey (ID 05AC:020B) und dieser wird als USB HID Keyboard im System registriert.

lsusb

Um Details über dieses USB-Device herauszufinden, schauen wir uns das Ergbnis von lsusb an
Bus 001 Device 012: ID 05ac:020b Apple, Inc. Pro Keyboard [Mitsumi, 
A1048/US layout]


In der Ausgabe suchen wir nach der ID des WebKey und sehen, dass es sich angeblich um eine Apple Tastatur handeln soll.

showkey

Die dritte Möglichkeit, welche ich ausprobiert habe, ist showkey. Mit diesem kleinen Tool kann man sich die Keycodes einer Tastatur ansehen.
$ showkey -a

Drücken Sie eine Taste - Strg+D beendet das Programm

r   114 0162 0x72
^[OH     27 0033 0x1b
     79 0117 0x4f
     72 0110 0x48
^?  127 0177 0x7f
1    49 0061 0x31
1    49 0061 0x31
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
9    57 0071 0x39
4    52 0064 0x34
6    54 0066 0x36
9    57 0071 0x39
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
0    48 0060 0x30
9    57 0071 0x39
1    49 0061 0x31
0    48 0060 0x30
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
7    55 0067 0x37
1    49 0061 0x31
1    49 0061 0x31
0    48 0060 0x30
1    49 0061 0x31
0    48 0060 0x30
5    53 0065 0x35
1    49 0061 0x31
1    49 0061 0x31
6    54 0066 0x36
1    49 0061 0x31
2    50 0062 0x32
1    49 0061 0x31
4    52 0064 0x34
6    54 0066 0x36
9    57 0071 0x39
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
0    48 0060 0x30
1    49 0061 0x31
1    49 0061 0x31
4    52 0064 0x34
9    57 0071 0x39
7    55 0067 0x37
1    49 0061 0x31
0    48 0060 0x30
0    48 0060 0x30
4    52 0064 0x34
6    54 0066 0x36
9    57 0071 0x39
9    57 0071 0x39
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
1    49 0061 0x31
0    48 0060 0x30
9    57 0071 0x39
     32 0040 0x20
^M   13 0015 0x0d
^D    4 0004 0x04


Wie man erkennt, erkennt man nichts. Es bleibt der gleiche Kauderwelsch.

usbutils und usb-devices

Die letzte Möglichkeit die mir eingefallen ist, bietet usbutils und das darin enthaltende Skript usb-devices. Wird dieses ausgeführt, werden zu jedem USB Device diverse Informationen und der verwendete Treiber, für den WebKey ist es usbhid, angezeigt. Genau dieser wäre auch der erste Ansatzpunkt, um herauszufinden warum der Webkey unter Mint nur Kauderwelsch ausgibt.
$ usb-utils
...
T:  Bus=01 Lev=01 Prnt=01 Port=03 Cnt=03 Dev#= 12 Spd=1.5 MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=05ac ProdID=020b Rev=03.01
S:  Manufacturer=WebKey
S:  Product=WebKey
C:  #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=32mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
...


Zur weiteren Analyse im Linux Mint sollte man sich also mal den usbhid driver ansehen.

Zweiter Test, unter Windows 8.1

So nachdem ich unter Linux schon einige Details erfahren konnte, habe ich den WebKey auch unter Windows probiert. Hier funktioniert dieser auch wie er sollte. Nach Betätigung öffnet sich das Ausführen Fenster und die vorgesehene URL wird eingetragen. Daraus schließe ich das der WebKey am Anfang zumindest WIN+R zum öffnen des Ausführen Fensters sendet, daran anschließend die URL und abschließend einen Zeilenumbruch sendet.

Hardware Analyse

Jetzt wo die Funktion des WebKeys bekannt ist und dieser zumindest unter Windows funktioniert, bin ich neugierig auf den Inhalt geworden. Dazu die drei kleinen Schrauben auf der Rückseite gelöst und man kann sich die kleine PCB im Inneren ansehen. Viel gibt es aber dabei nicht zu sehen. Das Teil ist sehr simmple aufgebaut. Unter der Versiegelung befindet sich ein kleiner Controller, zentral angeordnet die (ohne Deckel sehr helle) weiße LED und die beiden Button. Interresanter ist der kleine achtbeinige Käfer mit der Aufschrift T24C02A neben dem Anschluß der USB Leitungen. Bei diesem handelt es sich um einen 256 Byte großen I2C EEprom, wie es ihn z.B. von der Fa. Atmel gibt. In diesem ist die URL abgelegt, welche nach der Betätigung angezeigt werden soll.
Um den EEprom auszulesen und zu Beschreiben muss dieser an einen externen Controller angeschlossen werden, welcher über eine I2C Schnittstelle und laut EEprom Datenblatt über 3,3V oder 5V Stromversorgung verfügen muss.

WebKey und Raspberry Pi

Funktionstest

Für solche kleinen Bastelein eignet sich hervorragend das Raspberry Pi. Ich nehme dafür mein Model A.
Aber bevor ich mich mit dem EEprom beschäftige, wird der WebKey natürlich auch im Raspbian geteset.
Mt laufenden Desktop funktioniert er nicht, es wird war "Ausführen" geöffnet, aber es erfolgt keine Eingabe der URL. Dies geht aber auch Prinzip bedingt nicht, da eine einfache Eingabe der URL nicht den Browser öffnet. Dazu müsste der Browser mit der Webseite als Paramter aufgerufen werden z.B. epiphany www.raspberrypi.org
Wird Raspbian ohne Desktop gestartet erfolgt zumindest die Ausgabe der URL (www.community.conrad.de). Der scheinbar unter Mint vorgesehende Schutz ist im Raspbian nicht enthalten.

Anschluß

Damit das RPi mit dem EEprom kommunizieren kann, müssen beide zuerst miteinander kontaktiert werden. Im folgenden Bild ist die Anschlussbelegung dargestellt.












Dafür müssen folgende Schritte ausgeführt werden:

1. Raspberry Pi und WebKey ausschalten und von der Stromversorgung trennen.

2. Anschlussleitungen an den EEprom anlöten

3. Raspberry Pi Stiftleiste via Breadboard und Breadboardkabel mit dem vorbereiteten WebKey verbinden

4. Raspberry Pi anschalten

5. Auf das Raspberry PI i2c-tools installieren

$ sudo apt-get install i2c-tools


6. I2C aktivieren, dazu folgendes in die /boot/config.txt eintragen

$ sudo vi /boot/config.txt
dtparam=i2c0=on
dtparam=i2c1=on
dtparam=i2c_arm=on


6. Anschließend müssen noch die I2C Treiber für Linux und den Broadcom Chip geladen werden

$ sudo modprobe i2c_dev
$ sudo modprobe i2c-bcm2708


um dies permanent zu machen kann auch folgendes
- i2c_dev und
- i2c-bcm2708
in /etc/modules eingetragen werden.

7. Die I2C Adresse des WebKeys kann mittles i2cdetect herausgefunden werden.

$ i2cdetect -y 1 #(-y 1 entspricht I2C Bus 1)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --


Die 7-bit Adresse des EEproms lautet also 0x50.

8. Zur Kommunikation mit dem EEprom können folgende Tools verwendet werden

  • Lesen: i2cget -y 1
  • Schreiben: i2cset -y 1
  • Speicherauszug des EEprom anzeigen i2cdump -y1
WICHTIG: Zum Schreiben muss dasWrite Protection (WP) Pin auf Masse gezogen werden

EEprom überschreiben

Nachdem jetzt das EEprom Layout bekannt ist, wird dieses ersteinmal gesichert. Dazu einfach die Ausgabe von i2cdump in eine Datei umleiten:
$ i2cdump -y 1 0x50 >eeprom_dump.txt
$ cat eeprom_dump.txt
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
10: 54 4f 4e 54 45 58 7e 05 77 77 77 2e 63 6f 6d 6d    TONTEX~?www.comm
20: 75 6e 69 74 79 2e 63 6f 6e 72 61 64 2e 63 6f 6d    unity.conrad.com
30: 08 77 77 77 2e 63 6f 6d 6d 75 6e 69 74 7a 2e 63    ?www.communitz.c
40: 6f 6e 72 61 64 2e 63 6f 6d 00 13 a0 ff ff ff ff    onrad.com.??....
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff 00 ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................


Wie man dem Dump entnehmen kann beginnt der inhalt ab der Adresse 0x10. Was Dabei die ASCII Repräsentation (TONTEX) der ersten Bytes bedeutet ist mir nicht klar. Die eigentliche URL beginnt ab 0x18. Anschließend wird ist diese zweimal im Speicher gehalten, unterbrochen von einem 0x08 (Backspace?) und abgeschlossen von 0x00 0x13 und 0xA0. Wobei 0x00 wahrscheinlich das Textende signalisiert. Was die beiden letzten Bytes bedeuten ist mir noch nicht klar. Zumindest entspricht 0xA0 keinem ASCII Symbol mehr.
Um den EEprom zu beschreiben habe ich nicht i2cset verwendet, sondern ich habe mir mit hilfe des smbus Modules ein python Skript geschrieben. Dafür muss aber zuerst muss dafür aber das Python Module mit folgendem Befehl installiert werden.
$ sudo apt-get install python-smbus


Anschließend kann dieses Modul verwendet werden um lesend und schreibend via I2C auf den EEprom zuzugreifen. Anhand des ausgelesenden EEprom Inhalts wird die conrad URL durch die URL "www.raspberrypi.org" ersetzt. Ohne weitere Details zu dem Füllbyte (0x08) und den abschließenden Bytes (0x00, 0x13 und 0xA0) werden diese übernommen.
  1. Am Begin werden die verwendeten Module (sys, time und smbus) eingebunden. Anschließend wird der verwendete I2C Bus (i2c_dev 1) und die 7-bit Addresse des EEproms 0x50 festgelegt. Darauf folgende werden zwei Hilfsvariablen reg (Laufvariable für das EEprom Register) und ret für die Rückgabewerte initialisiert. Im Letzten Schritt wird eine Instanz von SMBus mit dem verwendeten I2C Bus angelegt.
import sys, time, smbus
#define used iic bus of rpi
iic_bus = 1
#define chip addrss, get with i2cdetect -y 1
iic_addr = 0x50
#EErom register
reg=0x00
#return value
ret=[]
#init smbus
eeprom = smbus.SMBus(iic_bus)


  1. Der zweite Abschnitt beginnt mit der Definition der Startadresse im EEprom (0x18, siehe eeprom_dump.txt). Anschließend wird ein array bestehend aus der hexadezialen Repräsentation der URL "www.raspberrypi.org" angelegt. Die beiden weiteren Variablen enthalten das Füllbyte und die drei abschließenden Bytes.
start=0x18
#data="www.raspberrypi.org"
data = [0x77,0x77,0x77,0x2e,0x72,0x61,0x73,0x70,0x62,0x65,0x72,0x72,0x70,
0x69,0x2e,0x6f,0x72,0x67]
data1 =0x08
data2=[0x00, 0x13, 0xA0]


  1. Im dritten Abschnitt wird der EEprom beschrieben, dazu wird zuerst die verwendete I2C-Adresse ausgegeben. Anschließend wird in einer Schleife der Inhalt des data Arrays (enthält die URL) beginnend bei der Startadresse in das EEprom geschrieben. Um den EEprom Zeit zu geben, wird nach jedem Byte 100ms gewartet. (Die Zeit habe ich wilkürlich gewählt, ohne Pause gibt es aber einen IO-Error.) Nach Abschluss der ersten Schleife wird das Füllbyte (0x08) und darauffolgende die URL in der zweiten Schleife in das EEprom geschrieben. Das Startbyte für die Zweite Adresse habe ich aus dem original EEprom dump entnommen. Auch ein direktes aneinander fügen, führte zum gleichen Ergebnis.
    Am Ende werden noch die drei abschließenden Bytes ins EEprom geschrieben.
print("Try to write to eeprom 0x%02X" % iic_addr)

try:
 #first loop for url
 for i in range(len(data)):
   eeprom.write_byte_data(iic_addr,start+i,data[i])
   time.sleep(0.1)

 eeprom.write_byte_data(iic_addr,start+len(data),data1)
 time.sleep(0.1)

 start = 0x31  #start+len(data)+1
 #second loop
 for i in range(len(data)):
   eeprom.write_byte_data(iic_addr,start+i,data[i])
   time.sleep(0.1)

 start = start+len(data)

 for i in range(len(data2)):
   eeprom.write_byte_data(iic_addr,start+i,data2[i])
   time.sleep(0.1)

except IOError, err:
  print("Error during communication with Device: 0x%02X" % iic_addr)
  exit(-1)
time.sleep(0.1)


  1. Im vierten Abschnitt wird der neubeschriebene Inhalt nocheinmal ausgelesen und ausgegeben.
for i in range(0,255):
 try:
  ret.append(eeprom.read_byte_data(iic_addr, reg+i))
 except IOError, err:
  print("Error during communication with Device: 0x%02X" % iic_addr)
  exit(-1)

print(ret)
out=""
for item in ret:
 out+="%c"%item

print(out)


Zur Kontroller nocheinmal den Inhalt des EEprom ausgeben.
$ i2cdump -y 1 0x50 >new_eeprom_dump.txt
$ cat new_eeprom_dump.txt
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
10: 54 4f 4e 54 45 58 7e 05 77 77 77 2e 72 61 73 70    TONTEX~?www.rasp
20: 62 65 72 72 70 69 2e 6f 72 67 08 77 77 77 2e 72    berrpi.org?www.r
30: 61 73 70 62 65 72 72 70 69 2e 6f 72 67 00 13 a0    aspberrpi.org.??
40: 6f 6e 72 61 64 2e 63 6f 6d 00 13 a0 ff ff ff ff    onrad.com.??....
50: 00 13 a0 ff ff ff ff ff ff ff ff ff ff ff ff ff    .??.............
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff 00 ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
pi@noopi:~$


Ergebnis

Nachdem das EEprom nun einen neuen Inhalt erhalten hat, muss natürlch versucht werden, ob diese URl auch ausgegeben wird. Dazu den WebKey mit den angelöteten Leitungen vom Raspberry Pi trennen und via USB anschließen.
Kurz den Button betätigt und ... die Ernüchterung folgt. Es erfolgt folgende Ausgabe
$http--
-bash: http--: command not found


Das erste Fazit lautet also, ein einfaches Überschreiben der URL im EEprom führt nicht dazu, dass diese korrekt ausgegeben wird. Dabei ist es egal ob die beiden URLs die selbe Startadressen wie im Original haben, oder direkt aneinander gekettet ins EEprom geschrieben werden. Es ist also noch etwas Analyseaufwand hinsichtlich der Funktionsweise nötig, evtl. handelt es sich bei den letzten beiden Bytes um eine Prüfsumme (z.b. crc16) oder Ähnliches.
Dazu fehlt mir aktuell aber die Zeit. Sobald ich aber etwas neues probiert habe, werde ich es hier aufschreiben.
Gut zu Wissen ist zumindest, dass man vor diesen "Geschenken" unter Linux (vorerst) gut geschützt ist.

Powered by Pelican. Theme blueidea, inspired by the default theme.