von Michael Christoph
Bereits im letzten Teil wurden Devices kurz angesprochen.
In der Regel findet man sie als Schnittstelle zu Hardware-Komponenten. Beispiele
dafür sind etwa das serial.device oder das parallel.device. Das ide.device
bzw. das scsi.device kümmern sich um die Festplatte. Zum anderen gibt
es aber auch noch das console.device oder das clipboard.device, die eher
als logische Einheiten anzusehen sind. Das timer.device fällt auch
eher in diese Kategorie, verwendet aber auch ICs zur Zeitmessung. Nicht
immer ist die Hardware sichtbar, wie ein Drucker oder Modem.
Generell kann man sagen, dass Devices immer dort eingesetzt werden, wo eine asynchrone Verarbeitung von Daten stattfindet. Liest man Daten von der Festplatte (IDOS->Read) stehen diese nach Rückkehr von der Funktion auch sofort zur Verfügung. Das gilt für fast alle Funktionen aus den Libraries. Anders sieht es aus, wenn Daten von der seriellen Schnittstelle gelesen werden. Solange dort keine Daten anliegen, würde das Programm auf die Rückkehr des Funktionsaufrufes warten. In der Zeit wäre dann auch das komplette GUI aus Anwendersicht »tot« und würde nicht mehr auf Eingaben reagieren. Darum ist hier eine asynchrone Verarbeitung notwendig. Hier soll es nun um die Nutzung von Devices gehen. Im Speziellen mit dem timer.device, da man in den verschiedenen Programmen damit konfrontiert wird. Die Kommunikation mit den Devices erfolgt über das Message-Prinzip, wobei so genannte IO-Requests zum Einsatz kommen. Diese Struktur wird gefüllt und mittels SendIO() die Abarbeitung gestartet. Aber alles der Reihe nach. Das
timer.device nutzen Das timer.device stellt fünf logische Einheiten zur Verfügung, über die auch die Genauigkeit des Timers festgelegt wird. Von Bedeutung ist dabei, ob nur kurze Intervalle gewartet werden sollen (im Sekundenbereich) oder länger (z.B. über Stunden). Zu finden sind die Units in der Tabelle »Die Timer Units«. Das timer.device stellt drei eigene Kommandos zur Verfügung. Über TR_ADDREQUEST kann eine definierbare Zeit gewartet werden, TR_GETSYSTIME und TR_SETSYSTIME erfragen bzw. ändern die Systemzeit (nicht zu verwechseln mit der Hardware-Zeit aus dem Uhrenchip). Um also eine Sekunde zu warten, genügen die folgenden vier Zeilen wie in Listing 2. Da das Programm nach SendIO sofort zurückkehrt, wird normalerweise in einem Message-Loop gewartet, bis Ereignisse eintreffen. Das kann z.B. das Ablaufen des Timers sein, aber auch Benutzeraktionen, wie z.B. die Auswahl eines Menüpunktes oder das Betätigen eines Buttons (Listing 3). Auf keinen Fall darf die aus dem Port geholte Message mittels ReplyMsg() beantwortet werden, wie dies z.B. bei IDCMP-Nachrichten der Fall ist. Die Nachricht ist nämlich nichts anderes, als unser zuvor weggeschickter ioreq. Der Vorteil der asynchronen Verarbeitung ist auch, dass diese jederzeit abgebrochen werden kann. Kommen z.B. keine Daten über den seriellen Port, kann der Benutzer entscheiden, dass nicht länger gewartet werden soll. Dazu dient das Kommando AbortIO(). Mit WaitIO() muss noch gewartet werden, bis auch die interne Verarbeitung abgebrochen wurde (Listing 4). Die Funktion WaitIO macht dabei nichts anderes, als auf das Ende der Kommando-Abarbeitung zu warten. Es ist also eine Kombination aus Wait() und GetMsg(). Beachtet werden sollte, dass beide Kommandos nur dann verwendet werden dürfen, wenn zuvor ein SendIO() erfolgt ist. Bei WaitIO() besteht auch die Gefahr, dass das Programm hier ewig wartet, solange das Kommando nicht abgeschlossen ist. Natürlich lässt sich so auch ein ausstehender Timer abbrechen. Auf diese Weise ist es möglich, dass eine Minute auf eine Benutzerreaktion gewartet wird und danach automatisch mit dem Programm fortgefahren wird. Der Messageloop muss nur überprüfen, ob zuerst eine Benutzeraktion erfolgt ist (IDCMP-Nachricht) oder der Timer abgelaufen ist (IORequest-Nachricht). Vor allem bei Batch-Programmen die z.B. über Nacht laufen wäre es ärgerlich, wenn das Programm die ganze Nacht auf eine Benutzereingabe wartet. Natürlich lassen sich nicht alle Rückfragen mit dieser Methode behandeln, aber einfache Rückmeldungen oder Fehlerausgaben, könnten auch einfach in der Shell erfolgen. Wie schon aus den anderen Teilen bekannt, müssen beim Programmende auch wieder alle angelegten Resourcen freigegeben werden. Das wäre zuerst das Schließen des Devices, dann das Freigeben des IORequest und schließlich die Freigabe des MessagePorts (Listing 5). Ein komplettes Beispiel finden Sie im Beispielprogramm »StopUhr.c« auf der nächsten Heft-CD bzw. auf unserer Internetseite. Library-Funktionen
im timer.device Die Kombination aus timer.device, Library-Funktion und einem Reaction-GUI kommt im Beispielprogramm »WinClock.c« zum Einsatz. Auf Grund des asynchronen Timers wird jede Sekunde die aktuelle Uhrzeit abgefragt und per IUtility->Amiga2Date() zur Ausgabe umgewandelt und in einem normalen Readonly-String-Gadget angezeigt. Zusätzlich reagiert das Programm auch auf Aktionen des Anwenders, die sich jedoch in diesem Beispiel auf das Fenster-Schließsymbol beschränken. In der nächsten Ausgabe gehen wir weiter auf den Einsatz des timer.device ein. Dann geht es um die Programmierung von Dockies. Mit diesen Elementen lassen sich Programme in die AmiDock-Leiste einbinden und für vielfältige Aufgaben verwenden. lb
|
|
Download: | enthält: |
---|---|
StopUhr : Shellprogramm einer Stopuhr WinClock : GUI-Programm mit Uhrzeitabfrage und anzeige |
|
os4prog-11-timerdev-src.lha, 63.460 bytes |
Kommentare, Fragen, Korrekturen und Kritik bitte an Webmaster
AMIGA schicken.
Zuletzt aktualisiert am 23. Juli 2005, Michael Christoph.