Auf die Palme

Neben Handy und Laptop ist der PalmPilot beliebtestes Spielzeug Technikbegeisterter. Perl liefert den nötigen Kleber für die Verknüpfung mit Unix-Programmen.

vorlesen Druckansicht
Lesezeit: 9 Min.
Von
  • Ramon Wartala
Inhaltsverzeichnis

Wer gerne mit seinem Schreibtischverlängerungsgerät [1] experimentieren möchte, um es auch für eigene Lösungen einsetzen zu können, der sollte sich pilot-link von Kenneth Albanowski ansehen. Nur dieses Paket ermöglicht die Anbindung des Piloten an OS/2 oder Unix. Es enthält neben einigen Kommandozeilenwerkzeugen zur Synchronisierung der Pilot-Datenbanken Schnittstellen zu Perl, Python, Tcl und Java.

Per serieller Verbindung spricht der PalmPilot mit dem PC über einen ‘HotSync’ genannten Mechanismus. Dessen Details hat die iX im letzten Jahr beschrieben [1]. Zur programmgesteuerten Datenübertragung bietet sich die Perl-Schnittstelle des pilot-link Pakets an.

Das erste Perl-Skript liest die Adreßdatenbank eines Piloten und zeigt nur die Namen und Vornamen solcher Einträge, bei denen eine EMail-Adresse existiert. In Zeile 11 öffnet es die serielle Schnittstelle für alle weiteren Aktionen. accept() wartet in Zeile 15, bis der Benutzer HotSync startet. Danach versucht das Programm, die Adreßdatenbank zu öffnen (Zeile 18). Ab Zeile 26 liest es Adressen und gibt sie per print() aus.

Mehr Infos

LISTING 1

 1 #!/usr/bin/perl -w
2 # Alle Adressen der Pilot-Datenbank ausgeben,
3 # bei denen eine EMail-Anschrift existiert
4
5 use PDA::Pilot;
6 use strict;
7 # Link auf die serielle Schnittstelle
8 my $port = "/dev/pilot";
9
10 # Socket erzeugen
11 my $socket = PDA::Pilot::openPort($port);
12
13 print "HotSync aktivieren...\n";
14
15 my $dlp = PDA::Pilot::accept($socket);
16
17 # Adressdatenbank oeffnen
18 my $db = $dlp->open("AddressDB");
19
20 # ueber alle Adressfelder gehen, ggf.
21 # EMail-Adresse und den Namen und Vornamen
22 # ausgeben
23 my $i = 0;
24 my $r = undef;
25
26 while ($r = $db->getRecord($i))
27 {
28 if($r->{entry}[7]) {
29 print "Name : ",$r->{entry}[0],"\n";
30 print "Vorname: ",$r->{entry}[1],"\n";
31 print "E-Mail : ",$r->{entry}[7],"\n";
32 print "-------------------------------------\n";
33 }
34 $i++;
35 }
36
37 $db->close();

Um weitere Formen dieser Informationspiraterie zu ergründen, empfiehlt sich ein Blick in die im Perl5-Verzeichnis liegenden Skripte dump.pl und test.pl. Zu deren Ausführung ist das Modul Data::Dumper von Gurusamy Sarathy erforderlich, das erst seit Perl 5.004_7 zur Standard-Distribution gehört. Es eignet sich für weitere Experimente mit der Pilot-Schnittstelle hervorragend und hilft beim Verständnis der von den Perl-Funktionen gelieferten Strukturen. Diese sind leider in der derzeitigen pilot-link-Version nicht dokumentiert. Mit dem Data::Dumper ist es jedoch möglich, sie in Perl-Notation ausgeben zu lassen.

Mehr Infos

LISTING 2

 1 #!/usr/bin/perl -w
2 # Benutzerdaten mit Data::Dumper ausgeben
3 use PDA::Pilot;
4 use Data::Dumper;
5 use strict;
6 # Link auf COM-Port fuer PalmPilot
7 my $port = "/dev/pilot";
8 my $socket = PDA::Pilot::openPort($port);
9
10 print "HotSync aktivieren...\n";
11 my $dlp = PDA::Pilot::accept($socket);
12
13 my $user_info = $dlp->getUserInfo;
14 print Dumper($user_info);
15
16 # Pilot-Verbindung schliessen
17 undef $dlp;

Listing 2 illustriert das Vorgehen: Die in Zeile 14 aufgerufene Dumper-Methode erzeugt eine Perl-Struktur, die den internen Aufbau der Benutzerdaten repräsentiert. Diese sieht zum Beispiel so aus:

$VAR1 = {
‘name’ => ‘Ramon Wartala’,
‘password’ => ‘h+@,’,
‘successfulSyncDate’ => 915979518,
‘lastSyncPC’ => 17288,
‘userID’ => 9558,
‘lastSyncDate’ => -1,
‘viewerID’ => ‘0’
};

Die zurückgelieferten Daten wirken auf den ersten Blick etwas merkwürdig. Aber ein einfaches

print "Last HotSync: ",ctime($user_info->{successfulSyncDate}),"\n";

zeigt das Datum der letzten Synchronisierung in der gewohnten Form, vorausgesetzt, man hat das Perl-Modul für die Systemzeit und das Datum mit Hilfe von

use Time::localtime;

eingebunden. Um die genaue Funktionsweise des Pilot-Link Pakets zu verstehen, bedarf es allerdings etwas Zeit. Bewährt hat sich ein Vorgehen nach dem alten Unix-Leitsatz: ‘Use the Source, Luke’. Als Ausgangspunkt für die Erkundungsreise bieten sich die Dateien Pilot.pm und Pilot.xs an. Sie definieren die Perl-Schnittstellen zum pilot-link Paket. In ihnen findet man alle Funktionen zum Lesen, Speichern und Löschen von Pilot-Daten. Dabei sollte man sich ein wenig in C zu Hause fühlen. Auch die im C-Quellcode enthaltenen Beispielprogramme lohnen einen kurzen Blick, um die allgemeine Arbeitsweise zu verstehen.

Unumgänglich ist dieses Studium, möchte man nicht bloß mit Perl Daten holen, sondern welche aufspielen oder gar synchronisieren. Dabei sollte man sich darüber im klaren sein, daß jeder Programmierfehler wichtige Daten auf dem PalmPilot vernichten kann. Ein Backup ist vor allen Versuchen deshalb dringend angeraten. Dazu eignet sich pilot-xfer aus dem pilot-link-Paket (siehe ‘Quellen’).

Mehr Infos

Quellen

Das Palm-Link-Paket ist bei ftp://ryeham.ee.ryerson.ca/pub/PalmOS/ erhältlich. Die Installation verläuft nicht anders als die anderer gängiger Unix-Programme:

tar - xvzf pilot-link_0_9_0.tar.gz
configure
make
make install

Nun sollte man einen symbolischen Link auf die serielle Schnittstelle setzen, an der der Pilot hängt:

ln -s /dev/ttyS0 /dev/pilot

Um diese Anbindung allen Benutzern zur Verfügung zu stellen, ist

chmod og+rw /dev/pilot

nötig. Wer nicht sofort die hier beschriebenen Perl-Experimente nachvollziehen möchte, kann sich auch erst an die mitgelieferten Beispiele halten. Das wichtigste ist pilot-sync, mit dem man eine Sicherheitskopie der Pilot-Daten erstellen kann:

pilot-sync -b <Verzeichnis>

Vergißt der Pilot später diese Daten, lassen sie sich mit

pilot-sync -r <Verzeichnis>

wieder aufspielen.

Data::Dumper, DBI und passende Treiber für alle unterstützten Datenbanken gibt es beim Comprehensive Perl Archive Network, in Deutschland unter anderem hier:

ftp://ftp.uni-hamburg.de/pub/soft/lang/perl/CPAN/
ftp://ftp.rz.ruhr-uni-bochum.de/pub/CPAN/
ftp://ftp.leo.org/pub/comp/general/programming/languages/script/perl/CPAN/

Eine einfache Datenbank für Merkzettel, basierend auf mSQL, ist die zweite Beispielanwendung. Grundsätzlich kann fast jede beliebige Datenbank einspringen, da das Perl-Skript sie nicht über eine proprietäre Schnittstelle bedient, sondern mit Hilfe von DBI (Database Interface). Diese Schnittstelle bildet eine logische Schicht zwischen Perl und dem eigentlichen Datenbanktreiber (DBD).

Besonders einfach ist es, mit Hilfe der mSQL-Werkzeuge eine Merkzetteldatenbank MerkzDB anzulegen, die wiederum eine Tabelle Merkzettel enthält. Diese sollte folgende Felder enthalten:

Number uint
Headline char(30)
Note char(4096)
Category char(25)
ID char(10)

Allen, die noch keine Erfahrung mit einer Datenbankumgebung haben, sei ‘mSQL - Erste Hilfe’ ans Herz gelegt. Zwar wäre die gesamte Datenbankadministration durch DBI-Funktionen in Perl realisierbar, doch würde dies die Beispielanwendung unnötig komplizieren.

Mehr Infos

mSQL - Erste Hilfe

Mittlerweile liegt fast jeder Linux-Distribution die MiniSQL Datenbank der Firma Hughes bei. Nachdem sie ordnungsgemäß installiert ist [3], kann man den Datenbankserver zum Beispiel mit

/usr/local/Hughes/msql2d &

starten. Die neu zu erstellende Datenbank MerkzDB legt man mit Hilfe des Administrationsprogramms wie folgt an:

/usr/local/Hughes/msqladmin create MerkzDB

Zur Erzeugung der eigentlichen Tabelle Merkzettel kann der SQL-Monitor msql verwendet werden:

/usr/local/Hughes/msql MerkzDB

Von der Shell aus erzeugt nun die benötigte Beispieltabelle:

msql -e "CREATE TABLE Merkzettel (Number uint, \
Headline char(30), \
Note char(4096),\
Category char(25), \
ID char(10))"

Möchte man sich später den Inhalt der Datenbank ansehen, so läßt sich mit msqldump MerkzDB eine ASCII-Ausgabe auf dem Bildschirm erzeugen. Weitere nützliche SQL-Befehle enthalten [3] und [5].

MySQL-Benutzer gehen ähnlich vor. Das CREATE-Statement erfordert zwei Änderungen: Statt uint sollte Number den Typ int bekommen, und Note muß als Blob deklariert sein. Das Perl-Skript bedarf nur einer Korrektur: Der driver muß mysql heißen (statt mSQL).

Bei der Definition der Datenbanktabellen sollte man penibel auf die Größe der Attribute achten, möchte man sie später mit dem PalmPilot synchronisieren. Jeder Datensatz seiner Anwendungsdatenbank kann nur eine begrenzte Anzahl von Zeichen oder Werten aufnehmen. So darf zum Beispiel die Feldlänge in den meisten Anwendungen 255 nicht überschreiten. Ein weiterer begrenzender Faktor ist die maximale Anzahl von Datensätzen, die die mitgelieferte PalmPilot-Software für Windows darstellen kann. Diese liegt in der aktuellen Version 2.0 bei 32767.

Wer selbst Software mit dem pilot-link-Paket erstellen will, sollte sich die Datenstrukturen der unterstützten Standardprogramme im include-Verzeichnis ansehen, wenn das Schreiben in eine Datenbank auf dem Piloten geplant ist. Die meisten definieren zum Beispiel nur Character-Zeiger, deren Inhalt eine beliebige Größe annehmen kann. Vorsicht ist also geboten, wenn man solche großen Zeichenfelder wieder in den PalmPilot zurückschreiben möchte. Weitere Limitierungen der Standard PalmPilot-Applikationen sind im ‘Ultimate Guide’ [2] zu finden.

Mehr Infos

LISTING 3

Das Kommandozeilenskript memoSync.pl tauscht Notizzettel zwischen dem Piloten und einer SQL-Datenbank aus.

  1 #!/usr/bin/perl -w
...
17 my $port = "/dev/pilot"; # Link auf COM-Port fuer PalmPilot
18 my $driver = "mSQL"; # Datenbanktreiber
19 my $database = "MerkzDB"; # Datenbankname
20 my $table = "Merkzettel"; # Tabellenname
... # Deklaration globaler Variabler
41 sub memo_open_sqlDB {
42 my ($driver,$database) = @_;
43 my $dsn = "DBI:$driver:database=$database";
... # Verbindung zur DB herstellen
47 $dbh = DBI->connect($dsn,undef,undef);
... # Fehlerbehandlung
53 }
54
55 sub memo_backup {
56 my ($port,$driver,$database,$table,$category) = @_;
57
58 # Verbindung zur SQL-Datenbank
59 &amp;memo_open_sqlDB($driver,$database);
60
61 # Existiert Tabelle &#146;Merkzettel&#146; ?
62 my $rv = $dbh->do("select * from Merkzettel where 0=1");
... # Programmabbruch, wenn nicht
68 &amp;memo_open_pilot($port);
69
70 my $sth = $dbh->prepare(&#146;INSERT INTO Merkzettel &#146;.
71 &#146;(Number, Headline, Note,&#146;.
72 &#146;Category, ID) VALUES (?, ?, ?, ?, ?)&#146;);
... # PDA: MerkzettelDB oeffnen...
75 my $memoDB = $dlp->open("MemoDB");
... # Anwendungsinformationen einlesen
78 my $memoApp = $memoDB->getAppBlock;
... # Alle Kategorie-Namen extrahieren und speichern
81 @categories = @{$memoApp->{categoryName}};

... # neuen Merkzettel lesen
117 while(my $r = $memoDB->getRecord($index)) {
118 # Datensatz aus MemoDB aufspalten
119 my $note = $r->{text};
120 my $number = $r->{"index"};
121 my $headline = substr $note,0,26;
122 my $category = $categories[$r->{category}];
123 my $id = substr $r->{id},0,9;
124 print $id,"\n";
125
126 $headline = $headline.&#146;...&#146;;
...
130 $sth->execute($number,$headline,$note,$category,$id);
131 die "Fehler: $DBI::err ... $DBI::errstr\n" if $DBI::err;
132
133 # N·chster Merkzettel
134 $index++;
135 } # while
... # Verbindungsabbau, DB schliessen
160 sub memo_add {
...
186 $index = $DBI::rows;
187 $index++;
188 my $number = $index;
189 my $note = $text;
190 my $headline = substr $note,0,26;
191 $headline = $headline.&#146;...&#146;;
192
193 my $sth = undef;
194 my $new_r = PDA::Pilot::MemoRecord->new($note,0,0,$category,0);
...
215 $sth = $dbh->prepare(&#146;INSERT INTO Merkzettel &#146;.
216 &#146;(Number, Headline, Note,&#146; .
217 &#146;Category, ID) VALUES (?, ?, ?, ?, ?)&#146;);
218 die "Fehler: $DBI::err ... $DBI::errstr\n" if $DBI::err;
219 $sth->execute($number, $headline, $note, undef, undef);
220
221 my $new_r = PDA::Pilot::MemoRecord->new($note,0,0,0,0);
222 $memoDB->setRecord($new_r);
...
224
225 $sth->finish;
226 $dbh->disconnect;
227 $memoDB->close;
228 print "fertig!\n";
229 }
230
...
244 getopts(&#146;bda:c:&#146;);
245
... # Behandlung von Kategorien
265 if($opt_b) {
266 &amp;memo_backup($port,$driver,$database,$table,undef);
267 }
268 if($opt_a) {
269 if((length $opt_a) > 4096) {
270 $text = substr $opt_a,0,4095;
271 } else {
272 $text = $opt_a;
273 }
274 &amp;memo_add($port,$driver,$database,$table,$text,undef);
275 }
276 if($opt_d) {
277 &amp;memo_clear($driver,$database,$table,undef);
...

Um die Quellen einigermaßen übersichtlich zu gestalten, fehlt eine Oberfläche, memoSync.pl ist also ein reines Kommandozeilenwerkzeug. Mit den entsprechenden Optionen kann man es für unterschiedliche Zwecke starten, ein Aufruf ohne Option liefert wie gewohnt eine kurze Erklärung zur Benutzung. Die Funktion memo_backup baut ab Zeile 58 Verbindungen zur Datenbank und zum PalmPilot auf, öffnet die Memo-Applikation und schreibt alle gelesenen Einträge mit Hilfe des SQL-Statements der Zeile 70 in die Tabelle Merkzettel der Datenbank MerkzDB. Dazu analysiert das Skript den SQL-Befehl nur einmal, um ihn innerhalb der Schleife effizienter ausführen zu können. Es bedient sich dabei des prepare- und execute-Mechanismus von Perls Datenbankschnittstelle. Für viele freie Datenbanken wie mSQL oder MySQL bringt dieses Verfahren zwar keine Vorteile, bei kommerziellen Produkten soll es jedoch die Arbeit beschleunigen.

Wichtig für die weitere Behandlung der Merkzetteleinträge sind die Kategorien. Diese liest Zeile 81 aus dem Applikationsblock der MemoDB. Mit Hilfe der Kategorien ist es beim Sichern der Merkzettel möglich, nur eine ganz bestimmte Art von Notizen auszuwählen. Nun kann das Skript die Merkzetteltabelle füllen. Sind alle Einträge heruntergeladen, schließt memoSync.pl die Datenbank und beendet die Verbindung. Zum vollständigen Löschen der Einträge in Merkzettel tritt memo_clear() auf die Bühne. Es entfernt knallhart alle Datensätze auf einen Streich.

Wie man einen neuen Tabelleneintrag nun in den PDA bekommt, läßt sich gut an der Beispielapplikation install-memo.c ergründen. Die zentrale Rolle beim Übertragen neuer Datensätze übernimmt dort die Funktion dlp_WriteRecord(). Die einzelnen Parameter sind in der Header-Datei pi-dlp.h im include-Verzeichnis des Pakets dokumentiert. Die äquivalente Perl-Subroutine ist setRecord(). Einen neuen Datensatz erzeugt man bequemerweise mit den Konstruktor PDA::Pilot::MemoRecord->new(). Dieser erwartet ähnlich wie sein C-Pendant dlp_WriteRecord einige Parameter:

"PDA::Pilot::MemoRecord->new($data,$id,$attr,$cat,$index);"

$data Beim Merkzettel-Datensatz der eigentliche
Text
$id Eine unsigned long ID, die jeder Daten-
bankeintrag auf dem PalmPilot haben muß.
Steht hier eine "0", so erzeugt der Pilot sie
selbständig.
$attr Dieser Parameter regelt unter anderem, ob
der Eintrag "geheim" oder "öffentlich" ist
$cat Hier steht eine Nummer, die die Kategorie
des Eintrags bestimmt
$index Fortlaufende Nummer der Einträge im
Piloten

Bei einem Neueintrag in die PalmPilot-Merkzettel-Datenbank kann wiederum eine definierte Kategorie ausgewählt werden. memo_add() fügt sowohl der SQL-Datenbank als auch der PalmPilot-Applikation einen neuen Eintrag hinzu. Dieses Vorgehen ist natürlich keine echte Synchronisation. Sein Nachteil liegt darin, daß jeder neuer Eintrag in der Datenbank ein HotSync erfordert. Schöner wäre ein wirklicher Abgleich der Daten in beide Richtungen. Dazu wären je nach Vorrang (Pilot überschreibt Datenbank oder umgekehrt) die einzelnen Datensätze miteinander abzugleichen. Anhand der hier vorgestellten Beispiele sollt es nicht zu schwer sein, so einen Synchronisationsmechanismus in Perl zu implementieren.

RAMON WARTALA
studiert Medizinische Informatik an der FH-Dortmund.

[1] Tilo Christ; Schreibtischverlängerungsgerät; Mobile Datenerfassung mit dem 3Com PalmPilot; iX 7/1998; S. 78 ff.

[2] David Pogue; PalmPilot: The Ultimate Guide; O’Reilly; Sebastopol 1998; ISBN 1-56592-420-7

[3] MiniSQL 2.0 User Guide

[4] Sriram Srinivasan; Advanced Perl Programming; O’Reilly; Sebastopol 1997; ISBN 1-56592-220-4

[5] Alfons Kemper, Andre Eickler; Datenbanksysteme; 2. Auflage; Oldenbourg; München 1997; ISBN 3-486-24136-2

Mehr Infos

iX-TRACT

  • Basis für die Anbindung von Unix an den PalmPilot ist das Paket pilot-link. Es enthält neben Kommandowerkzeugen zum Datenaustausch Schnittstellen für Perl, Tcl, Python und Java.
  • Die Perl-Schnittstelle ist kaum dokumentiert, das stört vor allem bei den benutzten Datentypen. Mit Hilfe des Moduls Data::Dumper läßt sich die benötigte Information gewinnen.
  • Perl erlaubt über einfachen Datenaustausch Hinausgehendes, mit dem DBI-Modul lassen sich beispielsweise SQL-Datenbanken mit dem Piloten abgleichen.
Mehr Infos

Fliegen mit Linux

Das komfortable KDE-Pendant zu Pilot-Link heißt KPilot und liegt seit längerer Zeit in der Version 3.0.2 vor. KPilot besteht aus einem grafischen Frontend, das an den PalmDesktop unter Windows erinnert. Es bietet den Umgang mit Adressen, To-Dos und Memos an. Außerdem kann es per Drag-and-Drop Programme auf dem Pilot installieren. Für die Verwaltung von Terminen wendet es sich an den zusätzlich zu installierenden KOrganizer. Im Hintergrund werkelt der PilotDaemon, der in seiner Funktionalität mit dem HotSync-Manager vergleichbar ist. Er bearbeitet Anfragen des Pilot mit Hilfe von eingebauten Routinen beziehungsweise der registrierten Conduits. Dieser Conduit-Mechanismus ist zwar von den Windows-Conduits inspiriert, aber dazu weder binär- noch sourcekompatibel. Trotz des hervorragenden äußeren Eindrucks hat das Produkt noch mit Stabilitätsproblemen zu kämpfen.

Bedauerlicherweise gibt es keine Conduits für die Anbindung von Pendragon oder Satellite Forms. Man ist also entweder zu Detektivarbeit gezwungen (das ist abgesehen von den grafischen Datentypen nicht schwer), oder man greift zu GNU C beziehungsweise CBasPad/PocketC, um eine Eigenentwicklung mit kontrolliertem Datenformat zu erstellen.

Die beiden Pakete sind übrigens nicht an die Linux-Plattform gebunden, sondern sollten auch auf Solaris, Irix und Konsorten laufen. Für CDE-basierte Systeme steht mit PilotManager noch eine hervorragende Anbindung der Pilot-Applikationen an die CDE-Applikationen bereit.

Tilo Christ

Download: Listings (ck)