mit MenuetOS programmieren
1) Anwendungsprogrammierung
1a) Struktur einer Anwendung
1b) Assembler Beispiel
1c) einheitliche Systemfarben benutzen
1d) freie Fensterform
1e) Threads
1f) Real-Time Daten
1) ANWENDUNGSPROGRAMMIERUNG FÜR MENUET-OS
========================================
1a) Struktur einer Anwendung
===============================
Für Menuet zu programmieren ist so leicht, als wenn du als erstes
die Basisstruktur einer Anwendung lernst. An diesem Punkt nehme ich
an, dass du einige Erfahrungen in der Assemblersprache hast.
Die MenuetOS API (Application Programming Interface) ist ein einfach-zu-
lernender Funktionssatz mit praktisch keinem Hierarchichem Zugriff.
Das arbeiten einer Anwendung basiert auf Ereignissen.
Die Anwendung wird mit dem Ereignistyp und der entsprechenden Anwendungshandlung
beim OS registriert. Es gibt 3 Ereignistypen die eine Anwendung erwartet
Standard-Handles: Fenster neuzeichnen, Tastendruck und Buttondruck.
Flussdiagramm und Struktur einer Anwendung mit Standardereignissen:
;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; HEADER DATEN ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;
START:
call draw_window
;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; WARTEN AUF EREIGNIS ; <--------------------------------------------------I
; ; I
;;;;;;;;;;;;;;;;;;;;;;;;; I
I I
;;;;;;;;;;;;;;;;;;;;;;;;; I
; ; neuzeichnen -> call draw_window -> I
; EREIGNISTYP AUSLESEN ; -> Taste -> read keypress -> process -> I
; ; Button -> read buttonpress -> process -> I
;;;;;;;;;;;;;;;;;;;;;;;;;
draw_window:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
;ZEICHNE STATISCHE FENSTERTEILE;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ret
DATEN-BEREICH:
;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; STATISCHE DATEN ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;
(Ende des Bildes)
1b) Assembler Beispiele
=======================
Eine stark kommentierte Realisierung der Assemblersprache von der oberen Struktur (1a).
Menuet Systemaufrufe werden mit dem 'int 0x40' Kommando mit der Funktions-
Nummer im Register eax und anderen Registern, wenn notwendig, ausgeführt.
Details von allen im moment Verfügbaren Systemaufrufen sind in der Sektion
(1g) Systemfunktionen.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; BEISPIELANWENDUNG ;
; ;
; Compiliere mit FASM für Menuet ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Der Header
use32 ; Compiler um 32 Bit Instructions zu verwenden
org 0x0 ; Die Basisadresse des Codes, immer 0x0
db 'MENUET01' ; 8 Byte ID für Anwendung
dd 0x01 ; Header Version
dd START ; Start der Ausführung
dd I_END ; größe des Bildes
dd 0x100000 ; zu benutzende Speichermenge
; Du hast Zugriff auf den Speicher von 0x0 bis
; zu dem hier definierten Wert. Die Verlegung
; des Codes wird mit den Selektoren erledigt
; die vom OS gesetzt werden.
dd 0x7fff0 ; Stack-Position im Speicherbereich
dd 0x0 ; Parameter passiert Wert
; wenn der Wert was anderes als 0 ist, werden
; die möglichen Parameter beim Start gesendet.
dd 0x0 ; Reserviert für Icon
; Der Code-Bereich
START: ; Start der Ausführung
call draw_window ; zeichnen des Fensters
; Nachdem das Fenster gezeichnet ist, ist es praktisch eine Hauptschleife zu haben.
; Ereignisse werden von hier aus verteilt.
event_wait:
mov eax,10 ; Funktion 10 : warte auf Ereignis
int 0x40
; Ereignistyp wird in eax zurückgegeben
cmp eax,1 ; Ereignis Anfrage auf neuzeichnen?
je red ; Erkl.: Es gab Aktivitäten auf dem Bildschirm und
; teile der Anwendung müssen neu gezeichnet werden.
cmp eax,2 ; Ereignis Taste im Puffer ?
je key ; Erkl.: Benutzer hat eine Taste gedrückt während die
; Anwendung im Vordergrund war.
cmp eax,3 ; Ereignis Button im Puffer ?
je button ; Erkl.: Benutzer hat einen der
; Anwendungs-Buttons gedrückt.
jmp event_wait
; Der nächste Abschnitt liest die Ereignisse und verarbeitet die Daten.
red: ; Ereignishandler: neuzeichnen
call draw_window ; Wir rufen die window_draw Funktion auf und
jmp event_wait ; springen zurück zu event_wait
key: ; Ereignishandler: Tastendruck
mov eax,2 ; Die Taste wird in ah zurückgegeben. Die Taste muss
int 0x40 ; ausgelesen und von der Systemwarteschlange gelöscht werden.
jmp event_wait ; Lies die Taste aus, ignoriere es und springe zu
; event_wait.
button: ; Ereignishandler: Buttondruck
mov eax,17 ; Die Button-Nummerdie in window_draw definiert ist
int 0x40 ; wird in ah zurückgegeben.
cmp ah,1 ; Button ID=1 ?
jne noclose
mov eax,-1 ; Funktion -1 : schließe dieses Programm
int 0x40
noclose:
jmp event_wait ; Dies wird für ignorierte Ereignisse verwendet,
; nützlich für Entwicklung
; *************************************************
; ****** FENSTER-DEFINITIONEN UND ZEICHNEN ******
; *************************************************
;
; Die statischen Fensterteile werden in dieser Funktion gezeichnet. Auf die Fensterleinwand
; kann später von jedem teil des Codes (Threads) aus zugegriffen werden um z.B. Prozesse oder
; aufgenommene Daten anzuzeigen.
;
; Die statischen Teile *müssen* innerhalb der Funktionsnummer 12 platziert werden,
; ebx = 1 und ebx = 2.
draw_window:
mov eax,12 ; Funktion 12: dem OS mitteilen, dass Fenster gezeichnet werden soll
mov ebx,1 ; 1, zeichnen starten
int 0x40
; ZEICHNE FENSTER
mov eax,0 ; Funktion 0 : definiere und zeichne Fenster
mov ebx,100*65536+300 ; [x start] *65536 + [x gr��e]
mov ecx,100*65536+120 ; [y start] *65536 + [y gr��e]
mov edx,0x02ffffff ; Farbe des Arbeitsbereichs RRGGBB
; 0x02000000 = Fenstertyp 2
mov esi,0x808899ff ; Farbe der Titelleiste RRGGBB
; 0x80000000 = Farbverlauf
mov edi,0x008899ff ; Rahmenfarbe RRGGBB
int 0x40
; FENSTERBEZEICHNUNG
mov eax,4 ; Funktion 4 : schreibe Text zum Fenster
mov ebx,8*65536+8 ; [x start] *65536 + [y start]
mov ecx,0x00ddeeff ; Textfarbe RRGGBB
mov edx,labelt ; Zeiger auf Textanfang
mov esi,labellen-labelt ; Textlänge
int 0x40
; BUTTON SCHLIE�EN
mov eax,8 ; Funktion 8 : definiere und zeichne Button
mov ebx,(300-19)*65536+12 ; [x start] *65536 + [x größe]
mov ecx,5*65536+12 ; [y start] *65536 + [y größe]
mov edx,1 ; Button ID
mov esi,0x6677cc ; Buttonfarbe RRGGBB
int 0x40
mov ebx,25*65536+35 ; zeichne Info-Text mit der Funktion 4
mov ecx,0x224466
mov edx,text
mov esi,40
newline: ; Text vom DATENBEREICH
mov eax,4
int 0x40
add ebx,10
add edx,40
cmp [edx],byte 'x'
jne newline
mov eax,12 ; Funktion 12: dem OS über das Fensterzeichnen informieren
mov ebx,2 ; 2, Ende des zeichnens
int 0x40
ret
; *********************************************
; ************* DATENBEREICH ****************
; *********************************************
;
; Daten können frei mit dem Code jeden teils des Images vermischt werden.
; Nur die Header-Informationen wird am Anfang des Images benötigt.
text: db 'DIES IST EIN BEISPIELPROGRAMM, DASS DU '
db 'BENUTZEN KANNST, A:\EXAMPLE.ASM CODE IST KOMMENTIERT '
db 'UND KLAR. SYSTEMFUNKTIONEN SIND IN DER DATEI '
db 'SYSFUNCS.TXT UND KOMMANDOS IN CMD.TXT '
db 'x <- ENDMARKIERUNG, NICHT LÖSCHEN '
labelt: db 'BEISPIELANWENDUNG'
labellen:
I_END:
; Der Bereich nach I_END frei als Anwendungsspeicher zu benutzen,
; vermeide den Stack.
;
; Struktur des Anwendungsspeicher, aufgrund des benutzten Headers, 1MB.
;
; 0x00000 - Beginn des compilierten Images
; I_END - Ende des compilierten Images
;
; + Frei zur Nutzung in der Anwendung
;
; 0x7ff00 - Beginn des Stack-Bereichs
; 0x7fff0 - Ende des Stack-Bereichs - definiert im Header
;
; + Frei zur Nutzung in der Anwendung
;
; 0xFFFFF - Ende des frei nutzbaren Speichers - definiert im Header
;
; Die ganzen Bereiche können mit einer direkten Referenz innerhalb
; der Anwendung modifiziert werden.
; Zum Beispiel, mov [0x80000], Byte 1 bewegt ein Byte über den Stack-Bereich.
Menuet's Anwendungsstruktur ist nicht für die Assemblerprogrammierung
reserviert, der Header kann praktisch in jeder anderen Sprache erzeugt
werden. Jedenfalls ist das allgemeine Anwendungsprogrammierdesign für
32 Bit Assemblerprogrammierung vorgesehen. Die GUI ist extrem einfach
mit einer besonderen Assemblersprache zu Handlen.
1c) einheitliche Systemfarben benutzen
======================================
Während die vorigen Beispiele sich auf eine Basisanwendung konzentriert haben,
wird in dieser Sektion mehr Wert auf das aussehen des Fensters gelegt.
Du kannst einheitliche Desktopfarben benutzen die von einem Farbsetup definiert wurden.
Die neue Funktion in diesem Beispiel ist get_system_colours.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; BEISPIEL EINHEITLICHE SYSTEMFARBEN ;
; ;
; Compiliert mit FASM für Menuet ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Der Header
use32 ; compiler um 32 Bit Instruktionen zu nutzen
org 0x0 ; Die Basisadresse für den Code, immer 0x0
db 'MENUET01' ; 8 Byte ID für Anwendung
dd 0x01 ; Header Version
dd START ; Start der Ausführung
dd I_END ; größe des Images
dd 0x100000 ; zu benutzende Speichermenge
; Du hast Zugriff auf den Speicher von 0x0 bis
; zu dem hier definierten Wert. Die Verlegung
; des Codes wird mit den Selektoren erledigt
; die vom OS gesetzt werden.
dd 0x7fff0 ; Stack-Position im Speicherbereich
dd 0x0 ; Parameter passiert Wert
; wenn der Wert was anderes als 0 ist, werden
; die möglichen Parameter beim Start gesendet.
dd 0x0 ; Reserviert für Icon
; Der Code-Bereich
window_size_X equ 300
window_size_Y equ 150
START: ; Ausführungsstart
call draw_window ; Fenster zeichnen
; Nachdem das Fenster gezeichnet ist, ist es praktisch eine Hauptschleife zu haben.
; Ereignisse werden von hier aus verteilt.
event_wait:
mov eax,10 ; Funktion 10 : auf ein Ereignis warten
int 0x40
; Ereignistyp wird in eax zurückgegeben
cmp eax,1 ; Ereignis Anfrage auf neuzeichnen?
je red ; Erkl.: Es gab Aktivitäten auf dem Bildschirm und
; teile der Anwendung müssen neu gezeichnet werden.
cmp eax,2 ; Ereignis Taste im Puffer ?
je key ; Erkl.: Benutzer hat eine Taste gedrückt während die
; Anwendung im Vordergrund war.
cmp eax,3 ; Ereignis Button im Puffer ?
je button ; Erkl.: Benutzer hat einen der
; Anwendungs-Buttons gedrückt.
jmp event_wait
; Der nächste Abschnitt liest die Ereignisse und verarbeitet die Daten.
red: ; Ereignishandler: neuzeichnen
call draw_window ; Wir rufen die window_draw Funktion auf und
jmp event_wait ; springen zurück zu event_wait
key: ; Ereignishandler: Tastendruck
mov eax,2 ; Die Taste wird in ah zurückgegeben. Die Taste muss
int 0x40 ; ausgelesen und von der Systemwarteschlange gelöscht werden.
jmp event_wait ; Lies die Taste aus, ignoriere es und springe zu
; event_wait.
button: ; Ereignishandler: Buttondruck
mov eax,17 ; Die Button-Nummerdie in window_draw definiert ist
int 0x40 ; wird in ah zur�ckgegeben.
cmp ah,1 ; Button ID=1 ?
jne noclose
mov eax,-1 ; Funktion -1 : schließe dieses Programm
int 0x40
noclose:
jmp event_wait ; Dies wird für ignorierte Ereignisse verwendet,
; nützlich für Entwicklung
get_system_colours:
pusha
mov eax,48 ; Funktionsnummer 48: Systemfarben
mov ebx,3 ; Unter-Funktionsnummer 3: ermitteln
mov ecx,app_colours ; Zeiger auf Rückkehrbereich
mov edx,10*4 ; Anzahl der zurückzugebenden Bytes
int 0x40
popa
ret
app_colours: ; SYSTEMFARB-TABELLE
w_frames dd 0x0 ; - Rahmen
w_grab dd 0x0 ; - GRAB-Bereich
w_grab_button dd 0x0 ; Grab-Bereich Button
w_grab_button_text dd 0x0 ; Grab-Bereich Buttontext
w_grab_text dd 0x0 ; Grab-Bereich Text
w_work dd 0x0 ; - Arbeitsbereich
w_work_button dd 0x0 ; Arbeitsbereich Button
w_work_button_text dd 0x0 ; Arbeitsbereich Buttontext
w_work_text dd 0x0 ; Arbeitsbereich Text
w_work_graph dd 0x0 ; Arbeitsbereich Grafiken
; *************************************************
; ****** FENSTER-DEFINITIONEN UND ZEICHNEN ******
; *************************************************
;
; Die statischen Fensterteile werden in dieser Funktion gezeichnet. Auf die Fensterleinwand
; kann später von jedem teil des Codes (Threads) aus zugegriffen werden um z.B. Prozesse oder
; aufgenommene Daten anzuzeigen.
;
; Die statischen Teile *müssen* innerhalb der Funktionsnummer 12 platziert werden,
; ebx = 1 und ebx = 2.
draw_window:
mov eax,12 ; Funktion 12: dem OS mitteilen, dass Fenster gezeichnet werden soll
mov ebx,1 ; 1, zeichnen starten
int 0x40
; ZEICHNE FENSTER
mov eax,0 ; Funktion 0 : definiere und zeichne Fenster
mov ebx,100*65536+300 ; [x start] *65536 + [x größe]
mov ecx,100*65536+120 ; [y start] *65536 + [y größe]
mov edx,0x02ffffff ; Farbe des Arbeitsbereichs RRGGBB
; 0x02000000 = Fenstertyp 2
mov esi,0x808899ff ; Farbe der Titelleiste RRGGBB
; 0x80000000 = Farbverlauf
mov edi,0x008899ff ; Rahmenfarbe RRGGBB
int 0x40
; FENSTERBEZEICHNUNG
mov eax,4 ; Funktion 4 : schreibe Text zum Fenster
mov ebx,8*65536+8 ; [x start] *65536 + [y start]
mov ecx,0x00ddeeff ; Textfarbe RRGGBB
mov edx,labelt ; Zeiger auf Textanfang
mov esi,labellen-labelt ; Textlänge
int 0x40
; BUTTON SCHLIEßEN
mov eax,8 ; Funktion 8 : definiere und zeichne Button
mov ebx,(300-19)*65536+12 ; [x start] *65536 + [x größe]
mov ecx,5*65536+12 ; [y start] *65536 + [y größe]
mov edx,1 ; Button ID
mov esi,0x6677cc ; Buttonfarbe RRGGBB
int 0x40
mov ebx,25*65536+35 ; zeichne Info-Text mit der Funktion 4
mov ecx,0x224466
mov edx,text
mov esi,40
newline: ; Text vom DATENBEREICH
mov eax,4
int 0x40
add ebx,10
add edx,40
cmp [edx],byte 'x'
jne newline
mov eax,12 ; Funktion 12: dem OS über das Fensterzeichnen informieren
mov ebx,2 ; 2, Ende des zeichnens
int 0x40
ret
; *********************************************
; ************* DATENBEREICH ****************
; *********************************************
;
; Daten können frei mit dem Code jeden teils des Images vermischt werden.
; Nur die Header-Informationen wird am Anfang des Images benötigt.
text: db 'DIES IST EIN BEISPIELPROGRAMM, DASS DU '
db 'BENUTZEN KANNST, A:\EXAMPLE.ASM CODE IST KOMMENTIERT '
db 'UND KLAR. SYSTEMFUNKTIONEN SIND IN DER DATEI '
db 'SYSFUNCS.TXT UND KOMMANDOS IN CMD.TXT '
db 'x <- ENDMARKIERUNG, NICHT LÖSCHEN '
labelt: db 'BEISPIELANWENDUNG'
labellen:
I_END:
1d) Freiform Fenster
====================
In diesem Beispiel konzentrieren wir uns auf die Gestaltung der Fenster vom Rechteck
über jede Form die der Programmierer wünscht. Die neue Funktion in diesem Beispiel
ist shape_window.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; FREIFORM BEISPIELANWENDUNG ;
; ;
; Compiliert mit FASM für Menuet ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Der Header
use32 ; compiler um 32 Bit Instruktionen zu nutzen
org 0x0 ; Die Basisadresse für den Code, immer 0x0
db 'MENUET01' ; 8 Byte ID für Anwendung
dd 0x01 ; Header Version
dd START ; Start der Ausführung
dd I_END ; größe des Images
dd 0x100000 ; zu benutzende Speichermenge
; Du hast Zugriff auf den Speicher von 0x0 bis
; zu dem hier definierten Wert. Die Verlegung
; des Codes wird mit den Selektoren erledigt
; die vom OS gesetzt werden.
dd 0x7fff0 ; Stack-Position im Speicherbereich
dd 0x0 ; Parameter passiert Wert
; wenn der Wert was anderes als 0 ist, werden
; die möglichen Parameter beim Start gesendet.
dd 0x0 ; Reserviert für Icon
START: ; Ausführungsstart
call shape_window ; Funktion für die Gestaltung
call draw_window ; zuerst, zeichne das Fenster
still:
mov eax,10 ; hier auf Ereignisse warten
int 0x40
cmp eax,1 ; neuzeichnen Anfrage ?
je red
cmp eax,2 ; Taste im Puffer ?
je key
cmp eax,3 ; Button im Puffer ?
je button
jmp still
red: ; neuzeichnen
call draw_window
jmp still
key: ; Taste
mov eax,2 ; nur auslesen und ignorieren
int 0x40
jmp still
button: ; Button
mov eax,17 ; ID ermitteln
int 0x40
cmp ah,1 ; Button-ID=1 ?
jne noclose
mov eax,-1 ; schließe dieses Programm
int 0x40
noclose:
jmp still
shape_window:
pusha
mov eax,50 ; den Referenzbereich angeben
mov ebx,0
mov ecx,shape_reference
int 0x40
mov eax,50 ; die Skalierung angeben 32 x 32 -> 128 x 128
mov ebx,1 ; Dies musst du nicht angeben, Skalierung ist Standardmäßig 1:1
mov ecx,2 ; Sklalierung ist auf 2^ecx gesetzt
int 0x40
popa
ret
shape_reference: ; 32 x 32 ( window_size_X + 1 ) * ( window_size_Y + 1 )
db 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0
db 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
db 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
db 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
db 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
db 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
db 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
db 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
db 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
db 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
; **********************************************
; ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
; **********************************************
draw_window:
mov eax,12 ; Funktion 12: dem OS über Fensterzeichnen informieren
mov ebx,1 ; 1, zeichnen starten
int 0x40
; FENSTER ZEICHNEN
mov eax,0 ; Funktion 0: definiere und zeichne Fenster
mov ebx,100*65536 ; [x start] *65536 + [x größe]
mov ecx,100*65536 ; [y start] *65536 + [y größe]
mov bx,word [x_gr��e]
mov cx,word [y_gr��e]
mov edx,0x00cccc00 ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
mov esi,0x00cccc00 ; Farbe der Titelleiste RRGGBB,8->Farbverlauf
mov edi,0x00cccc00 ; Rahmenfarbe RRGGBB
int 0x40
; SCHLIEßEN-BUTTON
mov eax,8 ; Funktion 8: definiere und zeichne Button
mov ebx,78*65536+12 ; [x start] *65536 + [x größe]
mov ecx,20*65536+12 ; [y start] *65536 + [y größe]
mov edx,1 ; Button-ID
mov esi,0x5599cc ; Buttonfarbe RRGGBB
int 0x40
mov eax,12 ; Funktion 12: dem OS über Fensterzeichnen informieren
mov ebx,2 ; 2, Ende des zeichnens
int 0x40
ret
; DATEN
x_size dd 127
y_size dd 127
I_END:
1e) Threads
===========
MenuetOS Assembler-Threading hat einige großartige vorteile gegenüber
Hochsprachen. Wenn du alle Variablen in Registern lässt, kannst du
soviele Threads im selben Code starten wie du möchtest, solange kein
Speicher berührt wird und nicht gespeichert werden muss. Die Register
werden in den Task-Switch Segmenten von MenuetOS gespeichert. Alles
was du tun musst, ist einen neuen Stack anzulegen.
Threads haben keinen unterschied mit dem Hauptprozess und benutzen
denselben Speicherbereich wie der Prozess der ihn gestartet hat. Sie
können ihre eigenen unabhängigen Fenster usw. haben. Beim beenden
der Anwendung, müssen alle Threads mit dem Standard-Systemaufruf
(eax = -1) beendet werden.
Die neue Funktion in diesem Beispiel ist create_thread.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; THREAD BEISPIEL ;
; ;
; Compiliert mit FASM für Menuet ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
use32
org 0x0
db 'MENUET01' ; 8 Byte ID
dd 0x01 ; Header Version
dd START ; Beginn des Codes
dd I_END ; größe des Images
dd 0x100000 ; Speicher für die Anwendung
dd 0x80000 ; esp
dd 0x0 , 0x0 ; I_Param , I_Icon
START: ; Beginn der Ausführung
call draw_window ; zuerst, zeichne das Fenster
event_wait:
mov eax,10 ; hier auf Ereignis warten
int 0x40
cmp eax,1 ; neuzeichnen Anfrage ?
je red
cmp eax,2 ; Taste im Puffer ?
je key
cmp eax,3 ; Button im Puffer ?
je button
jmp event_wait
red: ; neuzeichnen
call draw_window
jmp event_wait
key: ; Taste
mov eax,2 ; auslesen und ignorieren
int 0x40
jmp event_wait
button: ; Button
mov eax,17 ; ID ermitteln
int 0x40
cmp ah,1 ; Button-ID=1 ?
jne noclose
mov eax,-1 ; schließe dieses Programm (Thread)
int 0x40
noclose:
cmp ah,2 ; create_thread aufrufen
jne no_thread
call create_thread
jmp event_wait
no_thread:
jmp event_wait
; THREAD ERZEUGEN
;
; Alles was wir tun müssen, ist, die Thread-Einstiegsadresse mit der
; Funktion eax=51, ebx=1 in ecx und eine neue Stack-Position in edx
; anzugeben
create_thread:
cmp [thread_stack],0xf0000
jge no_new_thread
add [thread_stack],0x1000
mov eax,51 ; thread_create Systemaufruf
mov ebx,1
mov ecx,START
mov edx,[thread_stack]
int 0x40
no_new_thread:
ret
thread_stack dd 0x80000
; **********************************************
; ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
; **********************************************
draw_window:
mov eax,12 ; Funktion 12: Das OS über das Fensterzeichnen informieren
mov ebx,1 ; 1, zeichnen starten
int 0x40
; FENSTER ZEICHNEN
mov eax,0 ; Funktion 0: definiere und zeichne Fenster
mov ebx,10*65536+300 ; [x start] *65536 + [x gr��e]
mov ecx,10*65536+140 ; [y start] *65536 + [y gr��e]
mov esi,[thread_stack]
sub esi,0x80000
shr esi,11
shl esi,16
add ebx,esi
add ecx,esi
mov edx,0x02ffffff ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
mov esi,0x808899ff ; Farbe der Titelleiste RRGGBB,8->Farbverlauf
mov edi,0x008899ff ; Farbe des Rahmens RRGGBB
int 0x40
; FENSTERBEZEICHNUNG
mov eax,4 ; Funktion 4: schreibe Text zum Fenster
mov ebx,8*65536+8 ; [x start] *65536 + [y start]
mov ecx,0x00ddeeff ; Textfarbe RRGGBB
mov edx,labelt ; Zeiger auf Textanfang
mov esi,labellen-labelt ; Textlänge
int 0x40
; SCHLIEßEN-BUTTON
mov eax,8 ; Funktion 8: definiere und zeichne Button
mov ebx,(300-19)*65536+12 ; [x start] *65536 + [x größe]
mov ecx,5*65536+12 ; [y start] *65536 + [y größe]
mov edx,1 ; Button-ID
mov esi,0x6677cc ; Buttonfarbe RRGGBB
int 0x40
mov eax,8 ; NEUER THREAD-BUTTON
mov ebx,25*65536+128
mov ecx,88*65536+20
mov edx,2
mov esi,0x6677cc
int 0x40
mov ebx,25*65536+35 ; zeichne Infotext mit der Funktion 4
mov ecx,0x224466
mov edx,text
mov esi,40
newline:
mov eax,4
int 0x40
add ebx,10
add edx,40
cmp [edx],byte 'x'
jne newline
mov eax,12 ; Funktion 12: OS über Fensterzeichnen informieren
mov ebx,2 ; 2, Ende des zeichnens
int 0x40
ret
; DATEN-BEREICH
text:
db 'DIESES BEISPIEL ERZEUGT THREADS INDEM ES '
db 'DENSELBEN CODE MEHRMALS AUSFÜHRT. ALLES WAS '
db 'WIR BRAUCHEN IST EIN NEUER STACK FÜR JEDEN THREAD.'
db 'ALLE THREADS TEILEN SICH DENSELBEN SPEICHER. '
db ' '
db ' '
db ' NEUEN THREAD ERZEUGEN '
db 'x <- ENDMARKIERUNG, NICHT LÖSCHEN '
labelt:
db 'THREADBEISPIEL'
labellen:
I_END:
1f) Echtzeit-Daten
==================
Das folgende Beispiel konzentriert sich auf das Echtzeit Daten-holen und -verarbeiten.
Die Anwendung informiert das OS über alle Ports und Datentypen die an einem
bestimmten IRQ gelesen werden.
Schritte:
1) reserviere I/O Port-Bereich
2) reserviere IRQ
3) Programm-IRQ
4) Programm-EREIGNIS-Liste für den gewünschten IRQ
5) Laufzeit Verarbeitung der Daten
6) zurück zu den Standardereignissen - freier IRQ von der EREIGNIS-Liste
7) freier IRQ
8) freier Port-Bereich
9) beende Programm
Nachdem die IRQ's programmiert sind, hat die Anwendung ein neues Ereignis
für die Hauptereignisschleife, Nummer (IRQ+16).
Wenn die Anwendung dieses Ereignis empfängt, hat das OS die Daten für die
Anwendung aufgenommen um sie zu verarbeiten.
Die untere Tabelle zeigt die Hauptstruktur der zu verarbeitenden Echtzeit-Daten.
Die ganzen Schritte links vom (A) werden vom OS verarbeitet und die
Schritte rechts vom (A) sind von der Anwendung verarbeitet.
IRQ BESITZER => REC DATEN (A) SYS_EVENT => DATEN LESEN => PROZESS
0 TIMER SYS
1 TASTATUR SYS
2 frei ->
3 COM MAUS SYS/frei ?>
4 COM MAUS SYS/frei ?>
5 SOUND BL. SYS
6 DISKETTE SYS
7 frei ->
8 frei ->
9 frei ->
10 frei ->
11 frei ->
12 PS2 MAUS SYS/frei ?>
13 MATH PR. SYS
14 IDE SYS
15 IDE SYS
Ein Beispiel wie man Echtzeit-Daten verarbeitet:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; ECHTZEIT-DATEN ;
; ;
; Compiliert mit FASM für Menuet ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
use32
org 0x0
db 'MENUET00' ; 8 Byte ID
dd 56 ; benötigt OS
dd START ; Programm Start
dd I_END ; Programm Image größe
dd 0x100000 ; benötigte Speichermenge
; esp = 0x7FFF0
dd 0x00000000 ; reserviert=kein erweiterter Header
START: ; Beginn der Ausführung
call draw_window ; zuerst, zeichne das Fenster
call program_real_time_data ; Programmiere das OS um Echtzeit-Daten zu empfangen
call program_com_port ; Programmiere den COM-Port für ein spezifisches Gerät
event_wait:
mov eax,10 ; hier auf ein Ereignis warten
int 0x40
cmp eax,1 ; neuzeichnen Anfrage ?
je red
cmp eax,2 ; Taste im Puffer ?
je key
cmp eax,3 ; Button im Puffer ?
je button
cmp eax,16+4 ; RT: Neues Ereignis für die gewünschten IRQ-Daten (16+IRQ)
je read_rt
jmp event_wait
; Die nächste Sektion liest die Ereignisse und verarbeitet die Daten.
read_rt: ; RT Daten
mov eax,42 ; Funktion 42 gibt die Daten für IRQ 4 zur�ck
mov ebx,4 ;
int 0x40 ; OS gibt die aufgenommenen Daten zurück.
; eax restliche Anzahl an Bytes im Puffer
; bl Daten
; ecx 0 = erfolg, andere = keine Daten im Puffer
call process_data
jmp event_wait
red: ; neuzeichnen
call draw_window
jmp event_wait
key: ; Taste
mov eax,2 ; lesen und ignorieren
int 0x40
jmp event_wait
button: ; Button
mov eax,17 ; ID ermitteln
int 0x40
cmp ah,1 ; Button-ID=1 ?
jne noclose
call free_real_time_data
mov eax,-1 ; schließe dieses Programm
int 0x40
noclose:
jmp event_wait
program_real_time_data:
; holen der Echtzeit-Daten programmieren
;
; 1) reserviere I/O Port-Bereich
; 2) reserviere IRQ
; 3) Programmiere IRQ
; 4) Programmiere EREIGNIS-Liste für den gewünschten IRQ
;
pusha
mov eax,46 ; reserviere Ports 0x3f0 - 0x3ff
mov ebx,0
mov ecx,0x3f0
mov edx,0x3ff
int 0x40
mov eax,45 ; reserviere IRQ 4
mov ebx,0
mov ecx,4
int 0x40
mov eax,44 ; setze lese-Ports für IRQ 4
mov ebx,irqtable
mov ecx,4
int 0x40
mov eax,40 ; ermittle COM1 Daten mit IRQ 4
mov ebx,0000000000010000b shl 16 + 111b ; nachdem wir das neue Ereignis
; haben (16+4)
int 0x40
popa
ret
irqtable:
dd 0x3f8+0x01000000 ; 3f8 = Port zum lesen : 01 =Byte lesen, 02 =Wort lesen
dd 0x0 ; 0x0 = beendet lesen über IRQ Ereignis
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
dd 0x0
free_real_time_data:
; genutzte Resourcen freigeben
;
; 1) Standardereignisse ermitteln
; 2) IRQ mit Funktion 45,1 freimachen
; 3) Port-Bereich mit Funktion 46,1 freimachen
;
pusha
mov eax,40 ; Standardereignisse - IRQ 4 Ereignisse deaktivieren
mov ebx,111b
int 0x40
mov eax,45 ; IRQ freigeben
mov ebx,1
mov ecx,4
int 0x40
mov eax,46 ; Ports 0x3f0-0x3ff freigeben
mov ebx,1
mov ecx,0x3f0
mov edx,0x3ff
int 0x40
popa
ret
; Die folgenden Funktionen sind zur Verarbeitung von Gerätespezifischen Daten.
process_data:
cmp ebx,80
jne nocd
mov eax,19
mov ebx,cdplayer
mov ecx,0
int 0x40
nocd:
push ebx
mov eax,[pos]
add eax,1
cmp eax,10*20+1
jb noeaxz
mov esi,text+10*4
mov edi,text
mov ecx,10*21*4
cld
rep movsb
mov eax,13
mov ebx,20*65536+260
mov ecx,22*65536+220
mov edx,[wcolor]
int 0x40
mov eax,10*19+1
noeaxz:
mov [pos],eax
pop ebx
and ebx,0xff
call draw_data
ret
draw_data:
pusha
xchg eax,ebx
mov ecx,10
shl ebx,2
mov esi,3
newnum:
xor edx,edx
div ecx
add edx,48
mov [ebx+text-1],dl
dec ebx
dec esi
jnz newnum
call draw_text
popa
ret
draw_text:
pusha
mov ebx,25*65536+35 ; zeichne den Info-Text mit Funktion 4
mov ecx,0xffffff
mov edx,text
mov esi,40
mov edi,20
newline:
mov eax,4
int 0x40
add ebx,10
add edx,40
dec edi
jne newline
popa
ret
program_com_port:
; Die folgende Sequenz programmiert den COM-Port für einen Infrarot-Empfänger
mov cx,0x3f3+8
mov bl,0x80
mov eax,43
int 0x40
mov cx,0x3f1+8
mov bl,0
mov eax,43
int 0x40
mov cx,0x3f0+8
mov bl,0x30 / 4
mov eax,43
int 0x40
mov cx,0x3f3+8
mov bl,3
mov eax,43
int 0x40
mov cx,0x3f4+8
mov bl,0xB
mov eax,43
int 0x40
mov cx,0x3f1+8
mov bl,1
mov eax,43
int 0x40
mov eax,5
mov ebx,100
int 0x40
mov cx,0x3f8
mov bl,'I'
mov eax,43
int 0x40
mov eax,5
mov ebx,10
int 0x40
mov cx,0x3f8
mov bl,'R'
mov eax,43
int 0x40
ret
; **********************************************
; ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
; **********************************************
draw_window:
mov eax,12 ; Funktion 12: OS über das Fensterzeichnen informieren
mov ebx,1 ; 1, zeichnen beginnen
int 0x40
; FENSTER ZEICHNEN
mov eax,0 ; Funktion 0: definiere und zeichne Fenster
mov ebx,100*65536+300 ; [x start] *65536 + [x größe]
mov ecx,100*65536+250 ; [y start] *65536 + [y größe]
mov edx,[wcolor] ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
mov esi,0x8099bbff ; Farbe der Titelleiste RRGGBB,8->Farbverlauf
mov edi,0x00ffffff ; Farbe des Rahmens RRGGBB
int 0x40
; FENSTERBEZEICHNUNG
mov eax,4 ; Funktion 4: schreibe Text zum Fenster
mov ebx,8*65536+8 ; [x start] *65536 + [y start]
mov ecx,0x00ffffff ; Textfarbe RRGGBB
mov edx,labelt ; Zeiger auf den Textanfang
mov esi,labellen-labelt ; Textlänge
int 0x40
; SCHLIEßEN-BUTTON
mov eax,8 ; Funktion 8: definiere und zeichne Button
mov ebx,(300-19)*65536+12 ; [x start] *65536 + [x größe]
mov ecx,5*65536+12 ; [y start] *65536 + [y größe]
mov edx,1 ; Button-ID
mov esi,0x5599cc ; Button-Farbe RRGGBB
int 0x40
call draw_text
mov eax,12
mov ebx,2
int 0x40
ret
; DATEN-BEREICH
wcolor dd 0x0
pos dd 0x0
cdplayer db 'CDPLAY '
labelt db 'INFRAROT-EMPFÄNGER FÜR IRMAN AN COM1'
labellen:
text:
I_END:
eof