((C/C++)) Wie kommuniziert ein Programm mit einem Gerät?

  • Themenstarter Themenstarter n0oBz0r
  • Beginndatum Beginndatum
N

n0oBz0r

Guest
Hi,
seit ein paar Tagen habe ich die Logitech Sphere AF, das ist eine Webcam, die man mit Hilfe von einem Programm steuern/schwenken kann. Bin total glücklich, weil das echt ne spitzen Webcam ist IMHO. Nun wollte ich mal nachfragen, wie das Programm das mit dem Schwenken eigentlich macht...
Dankeschön :P
 
Hi.

Wenn man mit Geräten kommunizieren will, hat man mehrere Möglichkeiten:

- I/O Ports
- Eingeblendeter Speicher
- Interruptaufrufe
- Sonstiges

I/O Ports

Dies sind Busleitungen, die man mit einem Treiber oder einem Anwenderprogramm steuern kann. Ein I/O Port hat eine feste Adresse, auf die man mit outb() schreiben kann. Mit inb() kann man davon lesen. Dazu ein Beispiel:
Code:
#include <sys/io.h>

/* Linux - Braucht root-Rechte */

int
main(int argc, char *argv[])
{
	printf("\033[?17;103;16c"); // Blockcursor
	ioperm(0x3c8, 8, 1);
	outb(0, 0x3c8);
	ioperm(0x3c8, 8, 0);
	ioperm(0x3c9, 8, 1);
	outb(2, 0x3c9);
	outb(5, 0x3c9);
	outb(10, 0x3c9);
	ioperm(0x3c9, 8, 0);
	ioperm(0x3c8, 8, 1);
	outb(7, 0x3c8);
	ioperm(0x3c8, 8, 0);
	ioperm(0x3c9, 8, 1);
	outb(10, 0x3c9);
	outb(40, 0x3c9);
	outb(60, 0x3c9);
	ioperm(0x3c9, 8, 0);
	return 0;
}
Dieses Programm modifiziert die Farbpalette der Grafikkarte, sodaß man im Textmodus beliebige Farben haben kann, nicht nur die vordefinierten 8 Stück + blinkend. Der Port 0x3c8 erwartet eine 8bit Zahl, welche die zu ändernde Farbe in der Palette angibt (0=Schwarz, 7=Weiß), und 0x3c9 danach drei 6bit Zahlen, welche die Rot-, Grün- und Blauanteile angeben.

Wir senden hier erst eine 0 an 0x3c8 (=Ich will Farbe 0 ändern, schwarz) und danach 2, 5 und 10 an 0x3c9. Das ergibt ein zartes blau. Das gleiche machen wir mit Farbe Nr.7, sodaß wir statt weiß am Ende himmelblau haben.

Andere Sachen, die man (unter anderem) so steuern kann, sind z.B. der Parallelport, serielle Ports sowie bestimmte MIDI und Soundkarten.

Eingeblendeter Speicher

Viele Geräte haben Speicher. Grafikkarten sind da ein gutes Beispiel. Die schnellste Methode ist, direkt auf den Speicher zuzugreifen. Deshalb blenden viele Geräte ihren eigenen Speicher in den normalen Arbeitsspeicher ein. In 16bit Umgebungen (DOS) ist das ganz einfach: Der Grafikspeicher beginnt immer bei A000:0000 (Segment/Offset). Wenn man da reinschreibt, hat man irgendwas auf dem Bildschirm. In 32bit Protected Mode Umgebungen (Linux, Windows) liegt der I/O Speicher ganz am Ende des virtuellen Adressraums. Da kommt man dann aber nicht so leicht ran.

Interruptaufrufe

Das kann man sich vorstellen wie einen Funktionsaufruf in C. Der Funktionsname hat dabei eine Nummer, die Argumente übergibt man in Registern.
Code:
xor ah,ah
mov al,0x13
int 0x10
mov ah,0x4c
int 0x21
Dieser Schnipsel (DOS Assembler) ändert die Auflösung der Grafikkarte (Interrupt 0x10). Die Argumente sind:
ah - Nummer der Funktion (xor ah,ah = 0 = Auflösung ändern)
al - Auflösung (indexnummer 0x13 = 320x200 256 Farben)
Danach kommt Interrupt 0x21 (DOS) mit der Funktion 0x4c (Programm Ende).

Die Interruptnummern sind dabei Indizes in einer Tabelle (Interruptvektortabelle). In der Tabelle ist dann die entsprechende Sprungadresse angegeben, an der der auszuführende Code steht. Alle INT 0x10 Funktionen sind z.B. in einem ROM der Grafikkarte gespeichert (genannt VGA BIOS), welches in den Speicher eingeblendet wird.

--

Diese hardwarenahe Programmierung wird unter 32bit Systemen (Linux, Windows, etc.) fast immer in Form von Treibern bereitgestellt. Die Treiber deklarieren dann ihrerseits Funktionen, die Anwenderprogramme aufrufen können, um das gewünschte Ziel zu erreichen. Der Treiber deiner Webcam wird (sofern du Linux benutzt) allerdings auch weniger mit I/O Ports und Interrupts rumspielen, sondern eher die USB API benutzen, die der USB Treiber des Kernels bereitstellt. Die Befehlskette könnte dabei z.B. so aussehen:

Anwenderprogramm ===> Webcam Treiber ===> USB Treiber ===> Hardware

MfG.
 
Hallo,
Sonst empfehle ich den Code, der vor kurzen in unserem IRC gepostet wurde: Klick

Nene, einfach mal in I/O Ports genauer einlesen, gibts einiges dazu im Web
 
Ich hab das auch gerade mal mit den I/O Ports versucht und hab da folgendes Problem: sys/io.h wird nicht gefunden. (auf Win2k)
Schreibe ich nur io.h, so sind ioperm und outb undeclared. Das habe ich schon bei Bloodshed und MSVC++6.0 versucht, beides das Selbe :/
Hab den I/O code von oben nur kopiert (also nichts geändert).
Weis vieleicht jemand woran das liegt?
 
ioperm() gibt's unter Windows m.E. gar nicht (ist ein Linux Systemaufruf). Die Lowlevelfunktionen haben da Unterstriche vor dem Namen (_outb() oder __outb()).

Aber allgemein bringt der Code unter Windows eigentlich gar nichts, weil man den Effekt nur im Textmodus und in bestimmten VGA Auflösungen (mit Palette) sehen kann. Ich weiß also nicht, was da unter Windows passsieren wird (wahrscheinlich eine General Protection Exception).

Das funktioniert aber hervorragend in DOSBox (ohne das ioperm(), das ist da dann unnötig).
 
die frage is nur, ob das auch mit ner usb-webcam funzt.. aber das beispiel für den guten alten mode13 is schonma nich schlecht, wusst' nich dass das noch einer macht ^^
AL auf 0x12 setzen müsste doch 640x480x4bit sein, oder? :P

mfg.
 
Ich habe ein Programm geschrieben welches Messwerte eines Solarreglers über die Serielle Schnittstelle RS232 verarbeitet. Mit .NET geht dies schon sehr einfach.
 
jah, rs232.. aber is zwischen nem normalen seriellen anschluss und usb nich nen großer unterschied? is nur ne vermutung, also lyncht mich bitte nich gleich xD

mfg.
 
Es sind zwei grundverschiedene Sachen, ist schon richtig. Zumindest aus programmiertechnischer Sicht ist RS232 viel einfacher, da der Anschluss (in PCs) über einen festen I/O Port angesprochen werden kann (also auch mit Assembler leicht zugänglich). Die meisten Betriebssysteme bilden die Schnittstelle auch irgendwie ins Dateisystem ab, unter Linux eben /dev/ttyS0, unter Windows AUX:.

Die meisten Programmiersprachen oder Libraries haben deshalb auch mehr oder weniger triviale Mittel parat, um damit was anzufangen. Bei USB ist das idR. nicht der Fall, da kommt man dann nur über das Betriebssystem dran. Die USB Geräte werden (soviel ich weiß) intern über einen Controller gesteuert, der seinerseits Speicher in den Adressraum einblendet. Das funktioniert logischerweise nur im Protected Mode.
 
Zurück
Oben