CPX Supplemental: Dem variablen Kontrollfeld auf der Spur Episode 4

Nachdem seit der Veröffentlichung der ursprünglich auf drei Teile geplanten Serie mittlerweile einige Zeit vergangen ist (wenn das ZDF eine längere Pause macht, können wir das schon lange...) und sich zwischenzeitlich diverse kleinere Fehler, Unterlassungen und ähnliches bemerkbar gemacht haben, folgt hier nun endlich die Fortsetzung.

Wie bereits im Titel angedeutet, beschäftigen wir uns dieses Mal mit der Beseitigung verschiedener kleiner Fehler in den Listings und mit der Korrektur unserer CPX-Dokumentation. Obwohl wir uns dabei natürlich um äußerste Sorgfalt bemüht hatten, sind leider mehrere kleine (und ein etwas größerer) Fehler nicht zu verhindern gewesen. „Irren ist eine menschliche Eigenschaft“, würde Spock an dieser Stelle wohl sagen; wir sind schließlich auch nur Kohlenstoffeinheiten.

„Warp 4, Mr. Sulu!“

Fangen wir also direkt einmal mit der Fehlerbeseitigung in den Listings an. Diese waren zwar recht lang (einigen Lesern höchst-wahrscheinlich sogar zu lang), was sich jedoch infolge der Funktionalität leider nicht ganz vermeiden ließ. Jedenfalls haben wir glücklicherweise trotzdem insgesamt nur zwei Fehler in allen Listings finden können, die wir hiermit beseitigen möchten. Dazu ist im Listing „BOOT.C“ aus dem zweiten Teil der Serie nach der Zeile 269 folgende Zeile einzufügen:

active.selected = inactive.selected = -1:

Außerdem müssen Sie die augenblicklichen Zeilen 1010 und 1011 ausschneiden und nach der jetzigen Zeile 1050 wieder einfügen. Zur Kontrolle hier die beiden Zeilen:

boot[TYP].ob_state&= ~SELECTED;
redraw_object(boot,TYP);

Nach diesen Änderungen sollte dann auch die Versionsnummer des CPX-Moduls BOOT.CPX auf 1.01 gesetzt werden. Das läßt sich natürlich besonders elegant mittels des CPX-Construction-Tools aus Episode 3 dieser Serie erledigen.

Die Druckfehler mit den aufeinanderfolgenden Minuszeichen wurden ja bereits im dritten Teil beseitigt, so daß wir uns an dieser Stelle darum nicht weiter zu kümmern brauchen. Wir möchten hier nur noch einmal erwähnen, daß diese Fehler aufgrund eines drucktechnischen Problems entstanden sind und nicht in unserem Einflußbereich lagen, da wir einige Leserzuschriften zu diesem Thema bekommen haben.

Phaserbriefe

Eine dieser Zuschriften stammte übrigens von Herrn Bonten aus Aachen, der uns auch auf eine Methode zur Fehlersuche in CPX-Modulen aufmerksam machte, die wir für so interessant (da unkonventionell) halten, daß wir sie Ihnen nicht vorenthalten möchten.

Da man CPX-Module ja nicht wie übliche Programme debuggen kann, hat Herr Bonten an jeder für ihn interessanten Stelle im Modul einen Cookie angelegt, dessen Name die Stelle identifiziert und dessen Wert einen an der Stelle interessierenden Wert enthält. War die Stelle durchlaufen, wurde der Cookie entfernt. Mit einem Post-Mortem-Debugger kann man dann nach einem Absturz den Cookie-Jar auslesen und die benötigten Daten untersuchen.

So interessant diese Methode auch ist, halten wir jedoch eine andere Testmethode - die auch wir zum Test unserer CPX-Module benutzt haben - für zwar nicht unbedingt besser geeignet, aber zumindest einfacher durchführbar. Man greift dazu einfach auf die alte „Vor-Source-Level-Debugger-Zeiten“-Methode zurück und setzt „printfO “-Aufrufe an die zu untersuchenden Stellen. Die einzige Hürde, die bei diesem Problem zu nehmen ist (die unserer Vermutung nach auch für obiges Testverfahren der Anlaß gewesen sein dürfte), ist die Tatsache, daß der Linker bei Verwendung von printf dann mit der Fehlermeldung „UndefinedSymbol: ‘errno’ “ abbricht, da diese Variable im bei CPX-Modulen fehlenden TOS-Header definiert wird. Die Abhilfe ist jedoch denkbar einfach: man braucht die Variable im Modul nur als globale Variable vom Typ „WORD“ bzw. „int“ zu deklarieren, und alles läuft wunderbar... - bis zum ersten Fehler, versteht sich.

Zurück in die Gegenwart

Aber zurück zum Thema: Leider hat sich auch noch ein anderer Fehler eingeschlichen, oder genauer gesagt: wir haben in den ersten zwei Teilen vergessen, etwas Wichtiges zu erwähnen. Und zwar handelt es sich dabei um die Compiler-Option „-M“ (No String Merging), die beim Compilieren der CPX-Module mit Turbo-C eingeschaltet sein muß! Ist dies nämlich nicht der Fall, kann es passieren, daß irgendwelche Eingabefelder plötzlich mit Werten anderer Felder vorbesetzt sind, weil der Compiler die entsprechenden Strings wegen Gleichheit zusammengelegt hat. Das gilt übrigens auch für alle normalen Programme, in denen eine RSH-Datei eingebunden wird. Dies haben wir leider nicht rechtzeitig gemerkt, da diese Option bei uns immer eingeschaltet ist.

The Trouble with Headers

Fangen wir mit einem einfach zu behebenden Fehler an. So einfach der Fehler auch zu beheben ist, kann er doch in der Praxis (sofern benutzt) große Auswirkungen haben. In der Header-Datei XCONTR0L.H ist in der Struktur CPX_PARAMS die Variable vdi_handle (Zeile 113) in phys_handle umzubenennen. Mit anderen Worten: um VDI-Befehle benutzen zu können, muß erst mit Hilfe des phys_handle eine virtuelle Workstation geöffnet werden. Dabei darf natürlich nicht vergessen werden, das Handle wieder freizugeben, wenn das CPX-Modul beendet wird.

Etwas schwerwiegender ist da schon die Funktion copy_bltparm() (Zeile 202). Tatsächlich tut diese Funktion etwas völlig anderes. Möchte man nämlich innerhalb eines CPX-Moduls die Form des Mauszeigers ändern, ist dies problematisch, wenn ein anderes Programm sie bereits geändert hat.

Deshalb kopiert man die aktuelle Mausform in einen Puffer und kann dann selbst eine neue Mausform setzen. Wenn die alte Mausform wiederhergestellt werden soll, muß nur die gesicherte Kopie aus dem Puffer wieder zurückgeschrieben werden. Und genau dazu dient diese Funktion, die wir daher save_mform() genannt haben. Daher ist im CPX-Header die Zeile 202 folgendermaßen zu ändern:

VOID cdecl (*save_mform)(WORD dir, MFORM *buffer);

An der Bedeutung von dir hat sich nicht viel geändert: es gibt weiterhin die Kopierrichtung an, und zwar

1: Mauszeiger in Puffer kopieren 
0: Mauszeiger aus buffer wiederherstellen

buffer ist dabei die Adresse einer MFORM-Struktur, wie sie in der Header-Datei AES.H von Turbo-C definiert ist.

Diese beiden kleinen Änderungen haben glücklicherweise keine Auswirkungen auf BOOT.CPX bzw. DISK.CPX, denn diese Module benutzten weder vdi_handle noch copy_bltparm(), so daß sie nicht neu übersetzt werden müssen.

Nach diesen Änderungen dürfen Sie auch die Versionsnummer der Header-Datei auf 1.01 setzen.

The Undiscovered Country

Nun noch ein paar kleine Ergänzungen zu unserer CPX-Dokumentation, die sich im Nachhinein noch ergeben haben.

Fangen wir an mit den CPX-eigenen Pulldown-Menüs. Enthält ein Pulldown-Menü mehr als fünf Einträge, so werden automatisch der oberste und unterste Eintrag des Menüs durch Pfeile ersetzt, so daß in dem Menü gescrollt werden kann. Dies muß also nicht von Hand erledigt werden und erlaubt die Verwendung auch längerer Menüs (wie z.B. die Baud-Rate im MODEM.CPX von ATARI).

Weiterhin muß beim Aufruf von do_pulldown() nicht unbedingt ein Eintrag als abgehakt gekennzeichnet werden. Wird im Parameter checked_item eine -1 übergeben, wird kein Eintrag abgehakt.

Bei dem neuen Dialog-Handler do_form() gibt es übrigens noch eine weitere Message, die wir nicht erwähnt haben. Da wir auch die übrigen (bzw. üblichen) Message-Typen als bekannt vorausgesetzt und daher nur im Listing verwendet hatten, hier eine vollständige Liste aller Messages, die do_form() zurückgeben kann:

AC_CLOSE    41
CT_FKEY     53
WM_CLOSED   22 
WM_REDRAW   20

Im Turbo-C-Referenz-Handbuch ist auf Seite 416 übrigens nach CT_NEWTOP mit Index 52 Schluß. Da jedoch das Präfix für die einzelnen Zehnergruppen immer gleich ist, wird auch hier wohl CT_ nicht ganz verkehrt sein, wenn auch die Funktionen der anderen „CT_“-Messages weiterhin im Dunkeln liegen.

Warum jetzt CT_FKEY? Behandelt do_form() einen Dialog, so kann zum Beispiel durch eine Funktionstaste ein vordefinierter Text in ein edierbares Textfeld eingetragen werden. do_form() generiert nämlich bei Betätigung einer Funktionstaste (oder einer anderen Taste mit nicht druckbaren Zeichen) eine CT_FKEY-Message und legt den Tastencode wie von evnt_keybd() geliefert in msgbuff[3] ab.

Die Meldung AC_CLOSE sollte übrigens immer wie Anklicken des ABBRUCH-Buttons und WM_CLOSED wie ein OK behandelt werden. Das ist in unseren CPX-Modulen zwar der Fall, aber wir hatten nicht explizit darauf hingewiesen.

Noch ein paar Worte zum allgemeinen Design eines CPX-Moduls. Darauf haben wir zwar schon im dritten Teil hingewiesen, aber mittlerweile sind einige Module aufgetaucht, die sowohl von der Funktionalität als auch vom Design eher ein Accessory sind als ein CPX-Modul. So schön es auch sein mag, Utilities in CPX-Form zu bringen, damit sie ‘mal eben schnell’ eingeladen werden können, so widerspricht dies jedoch völlig der CPX-Philosophie! CPX-Module sollen ausschließlich (!) Hard- und Software konfigurieren. So ist ein Programm zum Stellen der Uhr in Ordnung, eine Uhr selbst jedoch muß als Accessory implementiert werden. Außerdem gibt es bereits Programme wie CHAMELEON, die beliebige Accessories nachladen können. Damit sollte es keinen Grund mehr geben, „CPX-Accessories“ zu schreiben.

So sollten auch die Buttons OK, ABBRUCH und SICHERN (sofern benötigt) in eigenen Modulen an das ATARI-Design der bekannten CPX-Module angelehnt werden, damit sich der Benutzer sofort zurechtfindet. Die Funktionalität des SICHERN-Buttons sollte im übrigen der eines OK-Buttons entsprechen, jedoch ohne das CPX zu verlassen.

„Engage..."

Jetzt kommen wir endlich zum Listing. Auch dieses Mal ist uns wieder eine sinnvolle Anwendung für das Kontrollfeld eingefallen, die allerdings dieses Mal hauptsächlich für Mega-STE- und TT-Anwender von Interesse ist. Wie einigen Besitzern dieser beiden Computertypen bekannt sein dürfte (und den meisten wahrscheinlich nicht...), haben diese neuen Rechner eine Reihe von winzigen Schaltern (von Fachleuten auch DIP-Schalter oder liebevoll Mäuseklavier genannt, siehe Abbildung 1), mit denen das System konfiguriert werden kann. Die Nachteile sind jedoch gewaltig: Erstens muß der halbe Rechner demontiert werden, um an diese Schalter zu gelangen (von der dabei ablaufenden Garantie ganz zu schweigen), und zweitens hat es sich als recht schwierig herausgestellt, eine Maus so abzurichten, daß sie die Schalter bedient. Ganz zu schweigen davon, daß das Rechnergehäuse auch nicht als Mäusequartier zu gebrauchen ist, denn die beiden Fenster sind vergittert und haben einen Ventilator (autsch!)...

Die Lösung (außer 42...) ist natürlich wieder einmal ein CPX. Mit unserem CPX-Modul DIPS lassen sich die DIP-Schalter einstellen, ohne den Rechner zu öffnen!!! Wie geht das? Zauberei? „Mitnichten“ (notfalls gehen auch Cousinen)! Denn das Betriebssystem liest die Einstellung der DIP-Schalter direkt im Reset in einen Cookie (den _SWI-Cookie) ein. Die acht Schalter belegen dabei die untersten acht Bits des Cookie-Langwortes. Ist der Schalter eingeschaltet, ist das korrespondierende Bit 0, andernfalls 1. Schalter 1 entspricht übrigens Bit 0 usw. Leider ist uns nur die Funktion von 2 Bits bekannt. Ist Schalter 8 aus, hat das System DMA-Sound (wird im _SND-Cookie, Bit 1 angezeigt), sonst nicht. Da der Mega STE und der TT beide den DMA-Sound haben, ist dieser Schalter hier immer aus.

Schalter 7 ist da schon interessanter. Er bestimmt, ob das System mit (mindestens) einem HD-Laufwerk ausgestattet ist. Jawohl, Sie haben richtig gelesen. Das TOS ab Version 2.05 und 3.05 hat die komplette Software zur Bedienung dieser Laufwerke eingebaut, einschließlich Stepratenumschaltung und automatischer Erkennung des Diskettentyps. Im „Formatieren“-Dialog des Desktops erscheint ein „Hohe Schreibdichte“-Button, mit dem dann auch HD-Disketten vom Desktop aus formatiert werden können. TOS 3.01 hat leider einen Fehler, weshalb sich hier der Button nicht bedienen läßt. Natürlich hat der TT (und der Mega STE) kein HD-Laufwerk eingebaut, und der Controller spielt (wie üblich) auch nicht immer mit, aber wenn Sie zufällig noch ein HD-Laufwerk übrig haben... ein Versuch schadet nicht.

Natürlich kann die Einstellung im CPX-Modul auch abgespeichert werden und wird beim nächsten CPX-Start automatisch wieder eingestellt. Hat man vergessen, wie die Schalter eigentlich eingestellt sind, kann die aktuelle Einstellung aus der Hardware mit „LESEN“ ausgelesen werden (siehe Abbildung 2).

Weitere Erläuterungen zum Listing sind unseres Erachtens nicht notwendig, da das Programm keine „Tricks“ enthält. Außerdem ist C-Code ohnehin selbsterklärend...

„I’m a doctor, not a programmer... “

... deshalb hier eine kurze Erläuterung, wie man zum fertigen Programm kommt. Außer dem Turbo-C-Compiler wird dieses Mal auch noch der Turbo-C-Assembler benötigt. Haben Sie endlich alles in den unendlichen Tiefen Ihres Bibliothekscomputers - will sagen: Festplatte - gefunden, wird das Programm, wie die vorigen CPX-Module auch, mit der Projektdatei problemlos zu einem (nicht lauffähigen) Programm compiliert und gelinkt. Anschließend müssen Sie mit Hilfe des Programmes aus Episode 3 dieser Serie - nämlich des „CPX-Construction-Tools“ - daraus noch ein echtes CPX-Modul erstellen. Die nötigen Informationen hierzu sind aus Abbildung 3 ersichtlich.

Bleibt uns nur noch, uns (vorläufig) zu verabschieden, Star Trek hat immerhin auch sechs Teile...

Uwe Hax & Oliver Scholz

Abb. 1: Das installierte Modul DIPS.CPX

Abb. 2: So präsentiert sich das CPX-Modul nach dem Öffnen.

Abb. 3: Für DIPS.CPX sind die hier angegebenen Parameter einzustellen.


;************************************************* 
;* Datei: DIPS.PRJ                               *
;* --------------------------------------------- *
;* Modul: DIPS.CPX                  Version 1.00 *
;* (C) 1990 by MAXON Computer                    *
;* Autoren: Oliver Scholz & Uwe Hax              *
;* Projektdatei für Turbo-C 2.0                  *
;*************************************************

dips.prg
=
dips.c 
liesdips.s 
tctoslib.lib 
tcstdlib.lib 
tcgemlib.lib


;*************************************************/
/* Datei DIPS.H                     Version 1.00 */
/* --------------------------------------------- */
;* (C) 1991 by MAXON Computer                    */
;* Autoren: Oliver Scholz & Uwe Hax              */
;*************************************************/

#define SWITCHES 0      /* TREE */
#define DIP1 4          /* OBJECT in TREE #0 */
#define OK 28           /* OBJECT in TREE #0 */
#define CANCEL 29       /* OBJECT in TREE #0 */
#define SAVE 31         /* OBJECT in TREE #0 */
#define DIP2 7          /* OBJECT in TREE #0 */
#define DIP3 10         /* OBJECT in TREE #0 */
#define DIP4 13         /* OBJECT in TREE #0 */
#define DIP5 16         /* OBJECT in TREE #0 */
#define DIP6 19         /* OBJECT in TREE #0 */
#define DIP7 22         /* OBJECT in TREE #0 */
#define DIP8 25         /* OBJECT in TREE #0 */
#define READ 26         /* OBJECT in TREE #0 */
#define ERROR 1         /* TREE */
#define ERROK 1         /* OBJECT in TREE #1 */


/*************************************************/
/* Datei DIPS.RSH               Version 1.00     */
/* --------------------------------------------- */
/* (C) 1991 by MAXON Computer                    */
/* Autoren: Oliver Scholz & Uwe Hax              */
/*************************************************/

#define T0OBJ 0 
#define T1OBJ 32 
#define FREEBB 0 
#define FREEIMG 0 
#define FREESTR 27

BYTE *rs_strings[] = (
    "(C) 1991 by Oliver Scholz & Uwe Hax“,
    "DIP 1”, "1”, "DIP 2", "2", "DIP 3", "3",
    "DIP 4", "4", "DIP 5", "5", "DIP 6”, "6",
    "DIP 7", "7", "DIP 8", "8”, "Lesen", "Ok”,
    "Abbruch", "Sichern", "OK", "Es ist leider",
    "kein _SWI Cookie", "vorhanden !"};

LONG rs_frstr[] = { 0 };

BITBLK rs_bitblk[] = { 0 };

LONG rs_frimg[) = { 0 };

ICONBLK rs_iconblk[] = { 0 };

TEDINFO rs_tedinfo[] = {
    (char *)0L, (char *)1L,(char *)2L,
    5 6, 0, 0x1180, 0x0, 255, 36,1
    };

OBJECT rs_object[] = {
    -1, 1, 27, G_BOX, NONE, NORMAL, 0xFF1141L,
    0,0, 32,11,
    2, -1, -1, G_TEXT, NONE, NORMAL, 0x0L,
    1282,512, 1306,2560,
    5, 3, 4, G_BOX, NONE, NORMAL, 0xFF1100L,
    0,1, 1799,1027,
    4, -1, -1, G_STRING, NONE, NORMAL, 0x3L,
    257,1280, 1029,257,
    2, -1, -1, G_BUTTON, 0x41, SHADOWED, 0x4L,
    1024,3329, 1542,1,
    8, 6, 7, G_BOX, NONE, NORMAL, 0xFF1100L,
    8,1, 8,1027,
    7, -1 -1, G_STRING, NONE, NORMAL, 0x5L,
    257,1280, 1029,257,
    5, -1, -1, G_BUTTON, 0x41, SHADOWED, 0x6L,
    1024, 3329, 1542,1,
    11, 9, 10, G_BOX, NONE, NORMAL, 0xFF1100L,
    272,1, 1799,1027,
    10, -1, -1, G_STRING, NONE, NORMAL, 0x7L,
    257,1280, 1029,257,
    8, -1, -1, G_BUTTON, 0x41, SHADOWED, 0x8L,
    1024,3329, 1542,1,
    14, 12, 13, G_BOX, NONE, NORMAL, 0xFF1100L,
    280,1, 1799,1027,
    13, -1, -1, G_STRING, NONE, NORMAL, 0x9L,
    257,1280, 1029,257,
    11, -1, -1, G_BUTTON, 0x41, SHADOWED, 0xAL,
    1024,3329, 1542,1,
    17, 15, 16, G_BOX, NONE, NORMAL, 0xFF1100L, 0,1284, 1799 1027,
    16, -1, -1, G_STRING, NONE, NORMAL, 0xBL,
    257,1280 1029,257,
    14, -1, -1, G_BUTTON, 0x41 SHADOWED, 0xCL,
    1024,3329, 1542,1,
    20, 18, 19, G_BOX, NONE, NORMAL, 0xFF1100L,
    8,1284, 520,1027,
    19, -1, -1, G_STRING, NONE, NORMAL, 0xDL,
    257,1280, 1029,257,
    17, -1, -1, G_BOTTON 0x41, SHADOWED, 0xEL,
    1024,3329, 1542,1,
    23, 21 22, G_BOX, NONE, NORMAL, 0xFF1100L,
    272,1284, 1799,1027,
    22, -1, -1, G_STRING, NONE, NORMAL, 0xFL,
    257,1280, 1029,257,
    20, -1, -1, G_BUTTON, 0x41, SHADOWED, 0x10L,
    1024,3329, 1542,1,
    26, 24, 25, G_BOX, NONE, NORMAL, 0xFF1100L 280,1284, 1799,1027,
    25, -1 -1 G_STRING NONE NORMAL, 0x11L,
    257,1280, 1029,257,
    23, -1, -1, G_BUTTON, 0x41, SHADOWED, 0x12L,
    1024,3329, 1542,1,
    27, -1, -1, G_BUTTON, 0x5, NORMAL, 0x13L, 1281,3591, 8,1,
    0, 28, 30, G_BOX, NONE, NORMAL, 0xFF1100L, 0,777,32,3329,
    29, -1, -1, G_BUTTON, 0x7, NORMAL, 0x14L,
    1548,1792, 8,1,
    30, -1, -1, G_BUTTON, 0x5, NORMAL, 0x15L,
    1046,1792, 8,1,
    27, 31, 31, G_BOX, NONE, NORMAL, 0xFF1100L, 0,0, 523,3329,
    30, -1, -1, G_BUTTON, 0x25, NORMAL, 0x16L, 769,1536, 1032,513,
    -1, 1, 4, G_BOX, NONE, OUTLINED, 0x21100L, 0,0, 22,7,
    2, -1, -1, G_BUTTON, 0x7, NORMAL, 0x17L,
    7, 5, 8,1,
    3, -1, -1, G_STRING, NONE, NORMAL, 0x18L,
    5,1, 13,1,
    4, -1, -1, G_STRING, NONE, NORMAL, 0x19L,
    3,2, 16,1,
    0, -1, -1, G_STRING, LASTOB NORMAL, 0x1AL,
    6,3, 11,1
};

LONG rs_trindex[] = { 0L, 32L };

struct foobar {
    WORD dummy,
    WORD *image,
    } rs_imdope[] = { 0 };

#define NUM_STRINGS 27 
#define NUM_FRSTR 0 
#define NUM_IMAGES 0 
#define NUM_BB 0 
#define NUM_FRIMG 0 
#define NUM_IB 0 
#define NUM_TI 1 
#define NUM_OBS 37 
#define NUM_TREE 2


***********************************************
* Datei: LIESDIPS.S     Version 1.00          *
* ------------------------------------------- *
* (C) 1991 by MAXON Computer                  *
* Autoren: Oliver Scholz & Uwe Hax            *
* Einstellung der DIP-Schalter lesen (nicht   *
* die des Cookies !                           *
***********************************************

BERR        EQU 8
DIP_HW      EQU $FFFF9200
cookie_jar  EQU $5A0

            GLOBL get_switches,set_switches

get_switches:
            move.l  #$ff,switches

* in Supervisormodus wechseln
            clr.l   -(sp)
            move    #$20,-(sp) ;Super
            trap    #1
            addq.l  #6,sp
            move.l  d0,_ssp

* Rechner auf Bus-Error vorbereiten
            move.l  sp, save_sp 
            move.l  BERR,a0 
            move.l  #zurueck,BERR

* DIP-Schalter lesen
            clr.l   d0
            move.w  DIP_HW,d0
            lsr.w   #8,d0
            move.l  d0,switches

* alten Bus-Error-Vektor wiederherstellen
zurueck:    move.l  a0,BERR
            move.l  save_sp, sp 
            move.l  _ssp,-(sp) 
            move    #$20,-(sp)
            trap    #1
            addq.l  #6,sp

            move.l  switches,d0 
            rts

**********************************************
* Cookie _SWI auf gewünschten Wert setzen,   *
* falls _SWI Cookie überhaupt vorhanden ist  * 
**********************************************

set_switches:
* Parameter merken
            move.l  d0,switches

* in Supervisor-mode gehen
            clr.l   -(sp) 
            move    #$20,-(sp) 
            trap    #1 
            addq.l  #6, sp 
            move.l  d0,_ssp

* Cookie Jar vorhanden / Adresse holen
            move.l  cookie_jar,d0 
            beq exit

* _SWI suchen
            move.l  d0,a0 
loop:       move.l  (a0)+,d0
            beq     exit
            cmp.l   #'_SWI',d0 
            beq     found
            addq.l  #4,a0 
            bra     loop

* Cookie gefunden!
found:      move.l  switches,(a0)

* zurück in Usermode
exit:       move.l  _ssp,-(sp)
            move    #$20,-(sp) 
            trap    #1 
            addq.l  #6,sp 
            rts

            .data
switches:   ds.l    1
_ssp:       ds.l    1
save_sp:    ds.l    1


/***********************************************/ 
/* Datei: DIPS.C                               */
/* ------------------------------------------- */
/* Modul: DIPS CPX                Version 1.00 */
/* (C) 1991 by MAXON Computer                  */
/* Autoren: Oliver Scholz & Uwe Hax            */
/* verwendeter Compiler: Turbo-C 2.0           */
/***********************************************/ 

/* die üblichen Header-Dateien ---------------- */

#include <portab.h>
#include <aes.h>
#include <string.h>

/* Definitionen zur besseren Lesbarkeit ------- */

#define TRUE        1
#define FALSE       0
#define EOS         '\0'
#define OK_BUTTON   1
#define MESSAGE     -1      /* Message-Event */

/* globale Variablen----------------------------*/

/* Die zu sichernde Variable:                   */
/* gewünschter Status der DIP-Schalter          */

LONG Schalter = 0xFFL;      /* default alle OFF */

/* Header, die Daten erzeugen,                  */
/* erst hier einladen                           */

#include "dips.rsh"
#include "dips.h"
#include "xcontrol.h" /* darf erst nach "*.rsh" 
                         eingebunden werden */

/* sonstige globale Variablen ----------------- */

CPX_PARAMS *params, /* vom Kontrollfeld über-
                       gebener Zeiger auf die 
                       Kontrollfeld-Funktaonen */

/* Strings für Dialogbox ---------------------- */

char ein[]="Ein"; 
char aus[]="Aus"; 
char empty[]="   ";

OBJECT *switches; /* Zeiger auf Dialogboxen */ 
OBJECT *error;

/* Prototypen für Turbo-C --------------------- */

WORD cdecl main (GRECT *curr_wind) ,
CPX_INFO * cdecl init (CPX_PARAMS *params),
OBJECT *get_traddr (WORD tree_index) ,
VOID pulldown(WORD button, LONG *work_swi)
VOID redraw_object (OBJECT *tree WORD object)
VOID into_resource(LONG work)
VOID wind_center(OBJECT *tree, WORD *x, WORD *y,
                 WORD *w, WORD *h) ;

/* diese Funktionen sind im Assembler Modul -- */ 
VOID set_switches(LONG new_cookie);
LONG get_switches(VOID)

/* Funktionen —-------------------------------- */

/***+***********************************»*******/
/* Initialisierung des Moduls                  */
/* Übergabeparameter: Zeiger auf die zur       */
/*    Verfügung stehender. Funktionen          */
/* 1. Aufruf bei Laden des Headers             */
/* 2. Aufruf bei Laden des eigentlichen        */
/*    Programms                                */
/***********************************************/

CPX_INFO * cdecl init (CPX_PARAMS *par)
{
    static CPX_INFO info={ main,0L,0L,0L,0L,0L,0L,0L,0L,0L };

    if (par->booting) /* bei Laden des Headers */
    {
        /* Cookie auf gewünschten Wert setzen */ 
        set_switches(schalter);

        return((CPX_INFO *)1L); /* kein Set-Only */
    }
    else /* Aufruf bei Laden des Programms */
    {
        params=par; /* Zeiger retten! */

        /* Resource relozieren */ 
        if (!params->rsc_init)
        {
            (*(params->do_resource)) (NUM_OBS,NUM_FRSTR, 
                NUM_FRIMG, NUM_TREE, rs_object, rs_tedinfo, 
                rs_strings, rs_iconblk, rs_bitblk, rs_frstr, 
                rs_frimg, rs_trindex, rs_imdope);

            /* Adressen der Dialoge berechnen */ 
            switches=get_traddr(SWITCHES); 
            error=get_traddr(ERROR) ;
        }
        /* Adresse der CPX_INFO-Struktur zurück */ 
        return(&info),
    }
)

/**********************************************/
/* Aufruf nach Doppelclick auf das Icon im     */
/* Auswahlfenster Zeichnen der Dialogbox,      */
/* Behandlung der Buttons                      */
/* Übergabeparameter: Koordinaten des Fenster- */ 
/*                    arbeitsbereichs          */
/***********************************************/

WORD cdecl main(GRECT *curr_wind)
{
    LONG work_swi;
    WORD msg_buff[8] ;
    WORD button, x, y, w, h,
    WORD abort_flag=FALSE; 
    char swi[5]="_SWI";

    /* Koordinaten der Dialogbox setzen */ 
    switches[ROOT].ob_x=curr_wind->g_x; 
    switches[ROOT].ob_y=curr_wind->g_y;

    /* aktuellen Switch-Cookie lesen */ 
    if (!(*params->find_cookie) (*(LONG *)swi, &work_swi))
    {
        /* kein Cookie-Jar oder kein Switch-Cookie */

        wind_center (error,&x,&y,&w,&h); 
        objc_draw(error,ROOT,MAX_DEPTH,x-3,y-3,w+6,h+6); 
        form_do(error,0);
        error[ERROK].ob_state &= ~SELECTED; 
        return(FALSE); /* fertig */
    }

    /* akt Schalter in Dialogbox eintragen */ 
    into_resource(work_swi);

    /* und Dialogbox zeichnen */ 
    objc_draw(switches,ROOT,MAX_DEPTH,switches[ROOT].ob_x,
        switches[ROOT].ob_y, switches[ROOT].ob_width, switches[ROOT].ob_height);

    /* Dialogbox abarbeiten, bis ein Exit-Objekt angeklickt wurde */

    do
    {
        /* neuer form_do()-Aufruf */ 
        button=(*params->do_form) (switches,0,msg_buff);

        /* Doppelklick ausmaskieren */ 
        if (button>=0)
            button &= 0x7fff;

        /* angeklicktes Objekt auswerten */ 
        switch (button)
        {
            case SAVE:
                /* Werte übernehmen */ 
                schalter=work_swi; 
                set_switches(schalter);

                /* Parameter in CPX-Datei speichern */ 
                if ((*params->alert)(0)==OK_BUTTON) 
                    (*params->write_config)(&schalter, sizeof(LONG)); 
                switches[SAVE].ob_state &= ~SELECTED; 
                redraw_object(switches,SAVE); 
                break;

            case OK:
                /* Werte übernehmen */ 
                schalter=work_swi; 
                set_switches(schalter);

                abort_flag=TRUE; 
                break;

            case READ:
                /* DIP Schalter lesen */
                work_swi=get_switches();
                switches[READ].ob_state &= ~SELECTED; 
                into_resource(work_swi); 
                redraw_object(switches,ROOT) ,
                break;

            case CANCEL:
                abort_flag=TRUE; 
                break;

            case DIP1: 
            case DIP2: 
            case DIP3: 
            case DIP4: 
            case DIP5: 
            case DIP6: 
            case DIP7: 
            case DIP8:
                pulldown(button,&work_swi), 
                break;

            case MESSAGE:
                switch (msg_buff[0])
                {
                    case WM_REDRAW
                        break;          /* nicht notwendig */

                    case WM_CLOSED:
                        set_switches(work_swi);

                        /* für "resident" notwendig */ 
                        schalter=work_swi;

                    case AC_CLOSE: 
                        abort_flag=TRUE; 
                        break;
                }
                break;
        }
    }
    while (!abort_flag);
    switches[button].ob_state &= ~SELECTED; 

    return(FALSE);
}

/**********************************************/ 
/* Parameter in die Dialogbox eintragen       */
/* Übergabeparameter Zeiger auf Status        */
/* Rückgabe: keine                            */
/********************************************/

VOID into_resource(LONG work)
{
    WORD i,maske;
    WORD index[] = { DIP1, DIP2, DIP3, DIP4,
                     DIP5, DIP6, DIP7, DIP8 };

    maske=0x01;

    /* alle Knöpfe belegen */ 
    for(i=0; i<8; i++)
    {
        switches[index[i]].ob_spec.free_string= (work&maske) ? aus : ein; 
        maske <<= 1;
    }
}

/**************************************************/
/* Neuzeichnen eines Objekts mit Hilfe der vom    */ 
/* Kontrollfeld gelieferten Rechteck-Liste        */ 
/* Ubergabeparameter: Zeiger auf Objektbaum,      */ 
/*                    Objekt-Index                */
/* Rückgabe: keine                                */
/**************************************************/

VOID redraw_object(OBJECT *tree, WORD object)
{
    GRECT *clip_ptr,clip,xywh;

    /* absolute Objekt-Koordinaten berechnen */ 
    objc_offset(tree,object,&xywh.g_x,&xywh.g_y); 
    xywh.g_w=tree[object].ob_width; 
    xywh.g_h=tree[object].ob_height,

    /* erstes Rechteck holen */
    clip_ptr=(*params->rci_first) (&xywh);

    /* solange noch Rechtecke da sind */ 
    while (clip_ptr)
    {
        /* clip_ptr Zeiger auf lokale Variable!! */ 
        clip=*clip_ptr;     /* deshalb kopieren */

        /* Objekt, neu zeichnen */
        objc_draw(tree,object,MAX_DEPTH,clip.g_x, clip.g_y,clip.g_w,clip.g_h),

        /* nächstes Rechteck holen */ 
        clip_ptr=(*params->rci_next)();
    }
}

/************************************************/ 
/* Pulldown-Menu generieren, darstellen und     */
/* auswerten                                    */
/* Ubergabeparameter angeklickter Button,  aus  */
/*                   dem das Menü "heraus-      */
/*                   klappen" soll,             */
/*                   Zeiger auf aktuelle        */
/*                   Parameter                  */
/* Rückgabe: keine                              */
/************************************************/ 

VOID pulldown(WORD button, LONG *work_swi)
{
    WORD i;
    LONG maske;
    WORD index,checked;
    GRECT button_xywh, window_xywh; 
    char *pull_adr[2]; 
    char pull_buff[2][15];
    WORD dips[] = { DIP1, DIP2, DIP3, DIP4,
                    DIP5, DIP6, DIP7, DIP8 };

    /* Pull-Down-Menu generieren */

    /* Texte eintragen */

    strcpy(pull_buff[0],empty); 
    strcpy(pull_buff[1],empty);

    strcat(pull_buff[0],ein); 
    strcat(pull_buff[1],aus);

    strcat(pull_buff[0],empty); 
    strcat(pull_buff[1],empty);

    i=0;
    maske=1L;
    while(dips[i]!=button)
    {
        maske <<= 1; 
        i++;
    }

    if(*work_swi & maske) 
        index=1;
    else
        index=0;

    /* absolute Button-Koordinaten berechnen */ 
    objc_offset(switches,button,&button_xywh.g_x, &button_xywh g_y); 
    button_xywh.g_w=switches[button].ob_width;
    button_xywh.g_h=switches[button].ob_height;

    /* absolute Koordinaten der Dialogbox ermitteln */ 
    objc_offset(switches,ROOT,&window_xywh.g_x, &window_xywh.g_y) ; 
    window_xywh.g_w=switches[ROOT].ob_width; 
    window_xywh.g_h=switches[ROOT].ob_height;

    /* Adressen der einzelnen Einträge in das Ubergabe-Array eintragen */

    pull_adr[0]=pull_buff[0]; 
    pull_adr[1]=pull_buff[1];

    /* Pull-Down-Menu zeichnen lassen und Index des angeklickten Eintrags zuruckliefern */ 
    checked= (*params->do_pulldown)(pull_adr,2,index,IBM, &button_xywh, &window_xywh);

    /* wenn Eintrag angeklickt wurde */
    if (checked>=0)
    {
        /* dann entsprechend reagieren */ 
        if(checked==0)
            *work_swi &= ~maske; 
        else
            *work_swi |= maske;

        /* neue Werte in die Dialogbox eintragen */ 
        into_resource (*work_swi);
    }

    /* Button neu zeichnen */
    switches[button].ob_state &= ~SELECTED;
    redraw_object(switches,button);
}

/***********************************************/ 
/* Dialogbox im Fenster zentrieren             */
/* Übergabeparameter: Zeiger auf Dialogbox,    */
/*                    Koordinaten              */
/* Rückgabe: indirekt über Koordinaten         */
/***********************************************/

VOID wind_center(OBJECT *tree,WORD *x,WORD *y, WORD *w,WORD *h)
{
    tree[ROOT].ob_x=switches[ROOT].ob_x+(switches[ROOT].ob_width-tree[ROOT].ob_width)/2; 
    tree[ROOT].ob_y=switches[ROOT].ob_y+(switches[ROOT].ob_height-tree[ROOT].ob_height)/2;

    *x=tree[ROOT].ob_x;
    *y=tree[ROOT].ob_y;
    *w=tree[ROOT].ob_width;
    *h=tree[ROOT].ob_height;
}

/***********************************************/
/* Liefert Adresse einer Dialogbox             */
/* (neue rsrc_gaddr()-Routine)                 */
/* Übergabeparameter: Baum-Index               */
/* Rückgabe: Zeiger auf Dialogbox              */
/***********************************************/

OBJECT *get_traddr(WORD tree_index)
{
    WORD i,j;

    for (i=0,j=0; i<=tree_index; i++) 
        while (rs_object[j++].ob_next!=-1);

    return(&rs_object[—-j]);

}



Aus: ST-Computer 09 / 1991, Seite 99

Links

Copyright-Bestimmungen: siehe Über diese Seite