[Studienarbeiten: Kommunikation zwischen PDAs]

2.3 Implementierung der IrDA-Protokolle unter EPOC32

Ein Konzept der Kommunikationsverwaltung unter EPOC32 ist das Einsetzen der RSocket Klasse. Wie in der folgenden Grafik zu sehen ist, wird durch die Socket-API nur der Zugriff auf LM-IAS, sowie LM-MUX bzw IrTinyTP erlaubt. Ein Zugriff auf IrLAP ist also nicht vorgesehen. Eine andere Möglichkeit ist der direkte Zugriff auf die serielle Schnittstelle über die Comms Server API ohne Nutzung irgendwelcher IrDA-Schichten. Ebenfalls über diese API ist der Zugriff auf IrDA IrCOMM möglich. Die folgende Grafik veranschaulicht diesen Umstand:
   

Bei der Anpassung der IrDA-Protokolle an ein Socket-System müssen natürlich Kompromisse geschlossen werden. Da die Protokolle an das ISO-OSI Modell angelehnt sind, ist eine vorgesehene request.indication Meldung grundsätzlich nur über Interrupts oder kompliziertere Programmstrukturen möglich. Wie die meisten anderen Betriebssysteme auch benutzt der Psion deshalb unter EPOC32  das explizite Warten auf eine Verbindung an einem besimmten LSAP.
LM-IAS kann über weitere Hilfsklassen genutzt werden, die im Folgenden vorgestellt werden. In der EPOC32 IrDA API gibt es keine Ableitung für die CSocket Klasse (wie z.B. eine CIrdaSocket Klasse), dafür wurde jedoch für erweiterte Funktionalität eine Ableitung der TSockAddr Klasse (die zur Bestimmung einer Adresse dient), die Klasse TIrdaSockAddr, implementiert.

Um eine Verbindung auf Ebene von IrTinyTP aufnehmen zu können, sind diese speziell für die IrDA-Schichten vorgesehenen Klassen aber nicht notwendig. Ein großer Vorteil dieses Konzepts ist die Möglichkeit einer 'relativen' Programmunabhängigkeit von dem benutzten Protokoll - durch geschicktes Implementieren und ein Verzicht auf bestimmte Vorteile von IrDA (wie LM-IAS) könnte ein Programm sowohl unter IrTinyTP als auch unter TCP/IP funktionieren.

Es folgt nun eine Beschreibung der Klassen, die für die IrDA-Kommunikation verwendet werden, sowie einige kleine Besipiele zu bestimmten Programmaufgaben.

2.3.1 Beschreibung der für IrDA wichtigen Klassen

Die wichtigste Klasse für die Kommunikation ist die RSocket Klasse. Über sie kann eine Verbundung zu einem anderen Gerät aufgebaut werden, sie kann Verbindungen anderer Geräte annehmen und über sie läuft das Austauschen der Daten. Um überhaupt eine RSocket Instanz erzeugen zu können, benötigt man unter EPOC32 eine Verbindung zum Socket Server, als Klasse implementiert als RSocketServ. Über diesen findet man auch die angebotenen Protokolle.
Zum Entdecken anderer Maschinen, das vor allem bei IrDA eine wichtige Rolle spielt, ist schließlich die RHostResolver Klasse zuständig.
Für LM-IAS werden in EPOC32 einige Hilfsklassen angeboten: TIASQuery, TIASResponse und TIASDatabaseEntry. Allgemein ist die Klasse RNetDatabase, die in diesem Fall ebenso benötigt wird.

RSocketServ

Connect() Verbindet zum Socketserver
FindProtocol() Sucht nach einem bestimmten Protokoll und liefert Informationen 
   
NumProtocols() liefert die Anzahl an verfügbaren Protokollen 
GetProtocolInfo() liefert wie FindProtocol() Informationen, jedoch über einen Index. 

 
 
Im Fall von IrDA ist der Verlauf also folgender: Über Connect() wird die Verbindung geöffnet, dann über FindProtocol() nach z.B. 'IrTinyTP' gesucht. Ist dies vorhanden, kann dann über die erhaltenen Informationen dieses Protokolls ein Open() eines RSocket durchgeführt werden.
 

RSocket

Open()  Ein Socket muß zu Beginn geöffnet werden. Hierzu ist ein Socketserver notwendig
Bind() Weist dem Socket eine Adresse zu. Im Falle von IrDA ist der Port der Adresse der LSAP-SEL
SetLocalPort() Setzt den lokalen Port. Im Falle von IrDA identisch mit der SLSAP-SEL
Connect()  Zu einer bekannten Adresse wird hiermit eine Verbindung geöffnet
Listen()  Ein Socket kann über Listen auf eine Verbindung warten
Accept() Wird benötigt, um nach einem Listen die neue Verbindung einem Socket zuzuweisen
Send()  Mit einem verbundenen Socket Daten senden
Receive()  Mit einem verbundenen Socket Daten empfangen
Shutdown() Eine Verbindung schließen
Close() Ein Socket muß nach Beendigung seiner Aufgabe geschlossen werden.
Ioctl() Führt je nach Protokoll spezielle Befehle aus
SetOpt()/GetOpt() Liest oder setzt Verbindungsoptionen (wie Baudrate etc)

 

TSockAddr

Diese Klasse zur Speicherung einer Adresse ist wichtig für RSocket::Connect() und RSocket::Bind()

SetPort() Setzt den Port der Adresse. Im Falle von IrDA den LSAP-SEL

 

TIrdaSockAddr

Diese Klasse ist eine Ableitung der TSockAddr und speziell für die Verwendung der IrDA-Protokolle gedacht. Bei der Erzeugung kann eine TSockAddr angegeben werden, die dann zur Initialisierung benutzt wird.

GetRemoteDevAddr() / SetRemoteDevAddr() Hiermit erhält man (oder setzt) die Adresse des Zielgerätes (als 4 Byte Wert)
GetFirstServiceHintByte() / SetFirstServiceHintByte Hiermit erhält man (oder setzt) das erste Hint Byte
GetSecondServiceHintByte() / SetSecondServiceHintByte() Hiermit erhält man (oder setzt) das zweite Hint Byte
GetIrlapVersion() Ergibt die IrLap Version
GetSniffStatus() / SetSniffStatus() Hiermit erhält man (oder setzt) den Sniff Status

 
 

RHostResolver

Mit dieser Klasse können andere Geräte entdeckt werden.

Open() Öffnet einen RHostResolver. Auch hierzu ist ein Socketserver notwendig
GetByName() Hiermit erhält man die Adresse einer bestimmten Maschine in Form einer TSockAddr. Wird keine angegeben, so findet GetByName() alle Geräte (zumindest im Falle von des IrDA-Protokolls)
Close() Schließt den RHostResolver.

 

RNetDatabase

RNetDatabase ist die Basisklasse für Abfrage und Eintrag in die Datenbasis.

Open() Die RNetDatabase muß auch unter Angabe eines Protokolls geöffnet werden.
Add() Fügt unter Angabe eines TIASDatabaseEntry einen Eintrag in der Datenbank hinzu
Query() Frägt einen Eintrag einer anderen Datenbank ab, benötigt einen TIASQuery und liefert einen TIASResponse
Close() Nach Beendigung der Aktionen muß die Verbindung geschlossen werden

TIASDatabaseEntry

TIASDatabaseEntry wird für Einträge in die Datenbasis bei RNetDatabase:Add() benötigt.

SetClassName() Setzt den Klassennamen
SetAttributeName() Setzt den Attributnamen
SetToInteger() Setzt den Typ auf eine Zahl und legt den Wert fest
SetToCharString() Setzt den Typ auf einen Text und legt den Wert fest
SetToOctetSeq() Setzt den Typ auf einen Bytestrom und legt den Wert fest

 

TIASQuery

Hiermit wird eine Abfrage für RNetDatabase::Query() vorbereitet

Set() Hierbei wird unter Angabe von Adresse, Klassenname und Attributname eine Abfrage vorbereitet

 

TIASResponse

Liefert bei RNetDatabase::Query() ein Ergebnis

Type()  liefert den Typ des Ergebnis
GetInteger()  liefert einen Intergerwert
GetOctetSeq()  liefert einen Bytestrom
GetCharString8()  liefert einen Text

 

2.3.2 Lösungen zu verschiedenen Programmaufgaben

Wie programmiert man einen Server?

  1. Erzeugen einer RSocketServ Instanz, diese über RSocketServ::Connect() mit dem Socket Server verbinden.
  2. Über RSocketServ::FindProtocol() nach 'IrTinyTP' suchen.
  3. Einen RSocket erzeugen und öffnen über RSocket::Open() öffnen
  4. Eine TSockAddr erzeugen und über SetPort() einen Homeport/LSAP-SEL zuweisen
  5. Die Adresse dem RSocket über Bind() zuweisen.
  6. Über IAS den gewählten Port/LSAP-SEL eintragen. (siehe auch weiter unten: IAS-Eintragungen)
  7. RSocket::Listen() aufrufen.
  8. Einen zweiten RSocket erzeugen und über RSocket::Open() als protokollungebunden öffnen.
  9. Über Accept() dem zweiten RSocket die neue Verbindung zuweisen.
  10. Ein Datenaustausch kann jetzt erfolgen über RSocket::Send() und RSocket::Receive()
  11. Am Ende die RSockets und den RSocketServ über ::Close() schließen.

Anmerkung zu 4 und 5: Dies kann auch über RSocket::SetLocalPort() abgekürzt werden.
Anmerkung zu 6: Der Port, der in diesem Falle den LSAP-SEL spielt, muß einer anderen Maschine über das IAS bekanntgemacht werden, damit diese den korrekten LSAP-SEL für den Aufbau zu unserem Server benutzen kann. Natürlich könnte der LSAP-SEL auch einen festen Wert haben - dies würde aber das gleichzeitige problemlose Ablaufen von zwei IrDA-Programmen verhindern, falls diese den selben LSAP-SEL nutzen würden.

Wie programmiert man einen Client?

  1. Erzeugen einer RSocketServ Instanz, diese über RSocketServ::Connect() mit dem Socket Server verbinden.
  2. Über RSocketServ::FindProtocol() nach 'IrTinyTP' suchen.
  3. Einen RHostResolver erzeugen, öffnen und über GetByName() (ohne Angabe des Namens) alle in Frage kommenden IrDA-Geräte suchen
  4. Bei in Frage kommenden Geräten über IAS den gesuchten Port/DLSAP-SEL finden. (siehe auch weiter unten: IAS-Abfragen)
  5. Falls der LSAP-SEL gefunden wurde, einen RSocket erzeugen und über RSocket::Open() öffnen.
  6. Der durch den RHostResolver erhaltenen TSockAddr den DLSAP-SEL zuweisen über SetPort()
  7. Dem Socket über SetLocalPort() einen SLSAP-SEL zuweisen.
  8. Über RSocket::Connect() unter Angabe der TSockAddr die Verbindung öffnen.
  9. Ein Datenaustausch kann jetzt erfolgen über RSocket::Send() und RSocket::Receive()
  10. Am Ende die RSockets und den RSocketServ über ::Close() schließen.

Anmerkung zu 7: Der lokale Port muß nicht festgesetzt werden. Über einen Autobind-Mechanismus wird der nächste verfügbare Port automatisch ausgewählt. Somit darf dieser Punkt entfallen.
Anmerkung zu 3 und 4: Im Falle von IrDA kann eine gefundene TSockAddr in eine TIrdaSockAddr gewandelt werden, um somit weitere Informationen abzuleiten.

Wie wurden einige weitere Dienstelemente implementiert?

Wie funktionieren IAS-Eintragungen und IAS-Abfragen?

Für einen Datenbankeintrag sind folgende Schritte notwendig:

  1. RNetDatabase erzeugen und öffnen
  2. TIASDatabaseEntry erzeugen und Klasse, Attribut, Typ und Wert setzen
  3. Das TIASDatabaseEntry per RNetDatabase::Add() der Datenbasis hinzufügen
  4. RNetDatabase schließen

Für eine Abfrage gilt

  1. RNetDatabase erzeugen und öffnen
  2. TIASQuery erzeugen und per ::Set() die gewünschte Klasse, das Attribut und vor allem die Adresse des Zielgeräts
  3. TIASResponse erzeugen und per RNetDatabase::Query() die Abfrage durchführen
  4. TIASResponse auswerten
  5. RNetDatabase schließen

2.3.3 Was funktioniert nicht so wie es eigentlich sollte...

Erfreulicherweise scheint EPOC32 einen Großteil der IrDA-Spezifikation korrekt eingehalten zu haben. Einige vorgesehene Möglichkeiten des IrLMP-Protokolls fehlen:

Beim Testen der im Rahmen dieser Studienarbeit geschriebenen Programme gelang kein Connect-Versuch des Window CE-Geräts an den Psion. Die andere Richtung funktionierte problemlos. Woran und auf welcher Seite dieser Fehler liegt, konnte mangels weiterer Geräte nicht festgestellt werden. Das Programm des Psion stürzte bei manchen Connectversuchen komplett ab, wenn das Zielgerät während des Connects entfernt wurde und ließ sich nicht mehr beenden. Dieser Fehler trat allerdings nur äußerst selten auf.
 

[Studienarbeiten: Kommunikation zwischen PDAs]