The XAcc protocol was originally designed for non-multitasking versions of GEM to allow data exchange between the main application and any number of accessories. Since the AES did not provide a function to find the application IDs (apIDs) of other applications without knowing their names, XAcc had to rely on the undocumented feature that the main application always has the apID 0. Therefore XAcc in its present (1) form does not work in a multitasking environment. However, AES 4.0 provides the new function appl_search, which allows any application to find the apIDs of all other applications running concurrently. This makes it possible to design a modified XAcc that does not use any 'dirty tricks'. This document contains a proposal for such a modified XAcc; the changes with respect to the previous definition are small and modifying an existing XAcc-based application should be a matter of minutes. Since single-tasking TOS will still be with us for a while, applications are encouraged to implement both 'traditional' and 'modern' XAcc, depending on the version number of the AES.
The GEM AES functions appl_write and appl_read can be used to exchange data between GEM applications running concurrently. In practice however, some problems need to be solved to make good use of these two functions:
There are no standard messages for exchanging data. Their
definition is the main goal of XAcc.
appl_write needs the receiver's application identifier (apID).
The only way to get this (before AES 4.0) is to call appl_find,
which needs the receiver's name. Thus communication is only possible
if the sender knows the receiver's name.
This problem is solved in AES 4.0 by the introduction of the
function appl_search.
The main application does not know when an accessory is
activated or deactivated. This would often be useful, for example if
the main application changes system variables that could affect the
accessory's behaviour. If the main application were informed before
the accessory gains control, it could reset those to their old values
and change them back after the accessory is finished.
Another advantage would be that after an accessory has been
called, the main application could check if something has been written
to the clipboard (1) or if other changes to the environment have
been made.
With multitasking GEM, the situation has changed in several
important ways. The possibility of using several 'main' applications
in parallel makes it even more undesirable to let them directly
manipulate system variables and the like; nevertheless there will
probably always remain some purposes that require such methods. On the
other hand, at least for applications using windows (the preferred
method to get the most out of a multitasking system) it is now
possible to detect changes of the active application by interpreting
the new AES messages WM_ONTOP and WM_UNTOPPED. Therefore it is not
considered necessary for XAcc to provide additional means to achieve
this.
The communications protocol described in this document solves all these problems. It was designed for two distinct purposes:
Exchanging data of standard types between programs that have no
information about each other.
Exchanging data between specific applications known to each
other. The standard protocol ensures that program combinations from
different vendors do not interfere with each other.
A potential problem caused by this protocol should be mentioned at this point: for single-tasking GEM versions, it relies on the currently undocumented fact that the main application's apID is always zero. Without this assumption there is no way to exchange data without using appl_find. Although this fact is not documented, it holds for all single-tasking versions of GEM in existence until now, both for MS-DOS and the Atari ST (this information was confirmed by Digital Research Germany). Of course the main application's apID may be different in future versions, although there is no reason to change the current behaviour for single-tasking systems. For AES 4.0 (and later) the above assumption is not needed anyway, so no compatibility problems are to be expected in the future.
A further requirement is that all programs not using this protocol must ignore its messages. This should not be a serious problem, as all GEM applications should ignore messages they do not understand. At the time of writing no programs are known to violate this rule.
The "classic" XAcc protocoll was finally defined on November 28, 1992. All known XAcc applications implement the protocol this way.
[Note: The "levels" used in previous XAcc versions have been replaced by this new concept. Compatibility issues are discussed in a special section at the end of this document.]
Both main applications and accessories can have widely different needs for communication with other programs. Therefore XAcc defines several groups of related messages (1) that deal with a certain range of data types. The message groups always indicate the messages understood by a program, not the messages it might send to other ones. If a program supports a certain message group, it must correctly respond to all corresponding messages, whether it can actually use the supplied data or not.
In addition to XAcc message groups, there are the so-called "basic messages", which must be supported by any XAcc-aware program, and program-specific so-called "special messages".
The basic messages deal solely with identification, but no real data exchange. They are already sufficient for programs that either do not exchange data with others at all or use only special messages to communicate with a number of other specific programs.
Message group 1 | specifies the exchange of ASCII-format character data.
|
Message group 2 | deals with the exchange of drawings and pictures using the GEM
metafile format and the GEM bit-image file format.
|
Future extensions might include sound or spreadsheet data. In addition, a message group could be defined to handle command interchange between applications, e.g. for a "Drag&Drop" protocol (2).
There are two kinds of XAcc messages: standard messages, which must be understood by every participating program, and special messages intended for communications between specific program combinations. The standard messages have numbers ranging from 0x400 to 0x7ff, special messages start from 0x800. The latter ones may only be sent after the receiver has been identified and is known to understand them. The following description is only concerned with standard messages. In addition to XAcc standard messages, the AES messages normally sent by the screen manager may be used. The most useful ones are AC_OPEN and MN_SELECTED; the latter one requires a knowledge of the receiver and therefore belongs to the special messages.
ACC_ID = 0x400 ACC_OPEN = 0x401 ACC_CLOSE = 0x402 ACC_ACC = 0x403 ACC_EXIT = 0x404
These messages provide XAcc initialization and organization. This is the only part of XAcc which has to be implemented in a different way for single- and multi-tasking GEM versions. Note that the procedure described for 'multitasking' actually only depends on the existence of appl_search and hence on an AES version number >= 4.0. If some future single-tasking AES supports appl_search, the 'multitasking' initialization should be used. Multitasking AES versions with a version number < 4.0 should never exist; to be on the safe side, applications should not attempt to use XAcc if such a situation is detected (1).
The communication between the main application and the accessories is initiated in the following way:
When a main application is started (or terminated), all desk
accessories receive an AC_CLOSE message from the AES screen manager. In
response they must send an identification to the main application
according to the following format:
msg[0]: ACC_ID (0x400) msg[1]: sender's apID msg[2]: length of the message - 16, giving 0 msg[3]: program version number and message groups msg[4] and msg[5]: pointer to sender's name msg[6]: menu number (menu_id) as returned by menu_register msg[7]: reserved (see ACC_ACC)
In response to an ACC_ID message the main application sends an
identification back to the accessory. The format is identical, except
that there is no menu number and thus msg[6] can be used for any other
purpose if neccessary. The same applies to msg[7].
In addition to the ACC_ID message, the main application informs
all previously registered accessories about the new one by sending
them the message
msg[0]: ACC_ACC (0x403) msg[3]: program version number and message groups msg[4] and msg[5]: pointer to accessory's name msg[6]: accessory's menu number (menu_id) msg[7]: accessory's apID
A desk accessory receiving the ACC_ACC message from the main
application sends an ACC_ID message to the thereby registered
accessory, identical to the one previously sent to the main
application.
When an accessory is activated by receiving an AC_OPEN message,
it sends the following message to the main application:
msg[0]: ACC_OPEN
Just before the accessory returns control to another program, it
sends the message
msg[0]: ACC_CLOSE
When receiving ACC_OPEN, the main application restores all system
variables it has changed to their original values (if possible and
neccessary). After receiving ACC_CLOSE, it may set them again to any
desired value.
Accessories should change system variables only after sending
ACC_OPEN and restore them before ACC_CLOSE.
There have been some problems with the implementation of
ACC_OPEN and ACC_CLOSE that should be mentioned. The system was
designed with window-less accessories in mind, i.e. accessories that
only display a dialog box. For these accessories, the above procedure
is well-defined. Accessories that use windows however have no way to
find out if they have been activated or deactivated, because they do
not receive a message to indicate this (starting from AES 4.0, this
problem is solved). Therefore such accessories must be careful with
ACC_OPEN and ACC_CLOSE. The most important thing is to guarantee that
ACC_OPEN and ACC_CLOSE always occur in pairs, and that in between no other
program gains control. How exactly this is implemented depends on the
specific application. Sometimes the best implementation is not to use
ACC_OPEN and ACC_CLOSE at all.
After initialization is completed, all participating programs know the identity of all other ones, either by receiving an ACC_ID message or by receiving an ACC_ACC message. The main application is always informed about accessory activities. If in addition it proves neccessary to inform one accessory about the activation of another one, this can be accomplished by sending special messages (starting from 0x800).
The initialization procedure is much simpler in this case. Any application, i.e. both 'standard' applications and accessories, uses appl_search to detect all currently running AES processes when it is started. To each application or accessory (i.e. everything but system processes) it sends an ACC_ID message:
msg[0]: ACC_ID (0x400) msg[1]: sender's apID msg[2]: length of the message - 16, giving 0 msg[3]: program version number and message groups msg[4] and msg[5]: pointer to sender's name msg[6]: menu number (menu_id) as returned by menu_register msg[7]: reserved
The low byte of msg[3] contains a bitmap indicating which message groups are understood by the sender. Bit zero is set for message group 1, bit one for message group 2, and so on. This is independent of the message types which the sender might itself send to others. The sender of a message must ensure that it is understood by the receiver. The high byte is used to indicate a program version number using an arbitrary encoding scheme.
The pointer to the sender's name is stored in a processor-dependent format. The name itself is a string of characters terminated by two zero bytes. To avoid name conflicts, long names are preferred to short abbreviations. The name must be available at the given address at any time, it may not be removed after initialization. It must also reside in globally accessible memory. As the version number is stored in msg[3], it should not occur again in the name. (1)
Applications using more than one menu entry must issue one ACC_ID message for each entry used. Accessories without a menu entry must use a number of -1.
When receiving an ACC_ID message, an application replies by sending a message of the same format to the original sender, the only difference being that ACC_ACC is used instead of ACC_ID. Applications with several menu entries must again send one message for each entry.
The messages ACC_OPEN and ACC_CLOSE are not used in multitasking systems.
Note: The only difference between ACC_ID and ACC_ACC for multitasking systems is that an application receiving ACC_ID sends ACC_ACC as a reply, whereas no reply is sent on receiving ACC_ACC. This prevents applications from sending ACC_ID to each other indefinitely. Obviously the name ACC_ACC has lost its original meaning and probably should be changed. But since the symbolic names do not influence the actual behaviour of any program, this is not really important at all.
Since in a multitasking environment every participating application can terminate, some means must be provided to tell other applications about this. Therefore the message ACC_EXIT has been added to the list of level 0 messages. Before terminating, any application sends
msg[0]: ACC_EXIT (0x404) msg[1]: sender's apID msg[2]: length of the message - 16, giving 0
to all applications that have ever registered themselves by sending ACC_ID or ACC_ACC.
Experience with XAcc has shown that it would often be useful to have more information about an application than specified with ACC_ID messages. For example it is sometimes useful to check for a special feature that is not unique to a single program, but to several similar ones. This was the motivation for the introduction of "extended names".
An "extended name" is a character string of the format:
'name'\0XDSC\0'string'\0'string'\0...'string'\0\0
i.e. a "standard" name followed by the string "XDSC" (for "eXtended DeSCription"), followed by a list of strings containing additional information. The end of the list is marked by an additional zero byte.
Each information string indicates by its first byte what kind of information it contains. Currently the following types are defined:
The "normal" name should be the "official" name of the program, just as it is used on the package, in the manual, and in similar places. It should be presentable to the user to let him/her decide where to send data.
Example: The address database "That's Address" identifies itself with the extended name (in C syntax)
"That's Address\0XDSC\01database\02DB\0XMM\0XSU\0",
indicating that it is a database with features "MM" and "SU". The first one indicates a special mail merge mode, the second one the possibility of retrieving data by sending the key via ACC_TEXT. (Further information on this program can be obtained from its manual.)
ACC_ACK = 0x500 ACC_TEXT = 0x501 ACC_KEY = 0x502
Transmitting text data:
msg[0]: ACC_TEXT (0x501) msg[4] and msg[5]: pointer to text
msg[0]: ACC_ACK (0x500) msg[3]: 0 if the text was simply ignored 1 if it was used in some sensible way
Simulation of a key press:
msg[0]: ACC_KEY (0x502) msg[3]: scancode of the simulated key and corresponding ASCII-code (as returned by evnt_keybd) msg[4]: state of the SHIFT keys (as returned by Kbshift)
msg[0]: ACC_ACK (0x500) msg[3]: 0 if ACC_KEY was ignored or a given command was not understood, 1 if some action was taken.
To prevent a deadlock if a program does not properly acknowledge a message, the sender should have some way to recover. An accessory could for example stop waiting for an acknowledgement after the next AC_OPEN, a main application might time out after a sufficiently long period.
ACC_META = 0x503 ACC_IMG = 0x504
These message are used to exchange drawings and pictures. Only the file formats defined in the GEM documentation are used; they are sufficient to meet most requirements, and any GEM application should be able to handle them anyway.
Sending a metafile:
msg[0]: ACC_META (0x503) msg[3]: 1 for the final part, 0 otherwise msg[4] and msg[5]: pointer to data msg[6] and msg[7]: length of data (32 bit longword)
Sending a bit image file:
msg[0]: ACC_IMG (0x504)
otherwise identical to 1.
There are two major changes with respect to the original(1) XAcc definition:
"Levels" have been replaced by "message
groups"
The motivation for this change was that the classification
according to exchangeable data types was not really a hierarchical
one; there is no reason why a programm accepting graphics should also
be able to understand text. The new scheme makes no such arbitrary
assumptions.
There is only one situation in which a possible incompatibility
could occur: an application following the "old" convention
encounters a "new" application and one of them indicates 2
in the level/message group byte. This would be interprets as
"graphics only" by one and as "graphics and text"
by the other. Since the number of level-2 applications was always
extremely small (in fact, the author(2) knows only of a single
one), this should be no problem in practice.
Extended names have been introduced
This could lead to a problem in the extremely unlikely case of
an "old" application using a name string which is
accidentally followed by "XDSC".
In any case it is expected that most applications will be converted to the new rules soon, if only to support MultiTOS.
This chapter describes developments of the XAcc protocol after "Classic XAcc" (11/28/92). Last changes have been made on June 15, 1995.
Seit der letzten offiziellen Dokumentationen zum XAcc-Protokoll haben sich einige Erweiterungen ergeben, die nun zusammengefaßt worden sind. Einige der Erweiterungen sind aus speziellen Formen des Datenaustauschs zwischen der Textverarbeitung That's Write und der Adreßverwaltung That's Address bzw. dessen Nachfolger no|Address hervorgegangen. Trotzdem sind diese Erweiterungen auch beliebigen anderen Applikationen zugänglich und die Verwendung dieser Applikationsnamen in der folgenden Dokumentation hat nur beispielhaften Charakter (That's Address = TA und That's Write = TW). Bei den Erweiterungen handelt es sich um:
MailMerge-Protokoll
Der eigentliche Seriendruck (MailMerge) des TW wird über dieses
Protokoll abgehandelt.
Remote-Mailmerge-Protokoll
Ermöglicht es einer Applikation, von sich aus einen Seriendruck
im TW zu initiieren.
Inquiry-Protokoll
Dient der Ermittlung von Informationen über den Aufbau einer
Datenbank.
Request/Reply-Protokoll
Dient dem allgemeinen Datenaustausch zwischen Applikationen.
Dieses Protokoll arbeitet aus historischen Gründen mit ACC_TEXT- Messages. Das TW schickt dem TA zuerst eine ACC_TEXT -Messages mit einem String, der mit "#I" beginnt und nach dem 'I' den SDF- Formatstring beinhaltet, der dem TA sagt, welche Teile eines Adreßdatensatzes übertragen werden sollen.
Beispiel: "#IA1,A2,A3,A4,T1" (die ersten 4 Adreßfelder und die 1. Telefonnr.).
Bei erfolgreichem Empfang dieser Nachricht wird dem TW eine ACC_TEXT- Message mit dem String "0" zurückgesendet, ansonsten ein Leerstring ".
Nun kann TW beginnen, die einzelnen Adreßdaten mittels der ACC_TEXT- Message "#N" anzufordern. Bei Empfang einer solchen Nachricht schickt TA für jedes Adreßfeld einer Adresse eine ACC_TEXT-Message und zum Abschluß eines Datensatzes einen Leerstring ".
Für dieses Protokoll gibt es zwei neue XAcc-message Typen, nämlich:
#define ACC_FORCESDF 0x520 #define ACC_GETSDF 0x521
TA sendet dem TW ein ACC_FORCESDF, wenn eine Adresse oder eine Adreßliste an das TW geschickt werden soll. Im Falle, daß es sich nur um eine Adresse handelt, steht in msg[4]+[5] ein Pointer auf das Suchwort der Adresse, bei einer Adreßliste steht in msg[4]+[5] ein Pointer auf "#L". Die ACC_FORCESDF-message muß mit einem ACC_ACK bestätigt werden (msg[3]==1 -> OK und msg[3]==0 -> ERROR).
Wenn TW ein "#L" bekommst, dann fährt TW ein ganz normales MailMerge- Protokoll (eingangs erklärt). Wenn TW ein Suchwort bekommt (max. 20 Zeichen lang), dann fordert TW beim TA diese Adresse mittels ACC_GETSDF an. Die ACC_GETSDF-message muß in msg[4]+[5] einen Pointer auf einen Buffer haben, in dem zuerst das Suchwort mit abschließendem '\0' steht und dann der XDF-Formatstring steht (Bsp.: "JÖRG\0A1,A2,A3\0").
Wenn TA die ACC_GETSDF-message verstehen kann, dann schickt es ein ACC_ACK mit msg[3]==1, ansonsten ein ACC_ACK mit msg[3]==0. Anschließend bekommt TW die Daten dieser einen Adresse wie beim normalen MailMerge- Protokoll.
TW muß in seinem XDSC-String ein "XRM" zu stehen haben, damit TA von sich aus ein Remote-Mailmerge-Protokoll startet.
TA hat jetzt folgende XDSC-Features (Bsp. ACC):
const char ta2Ident[] = "That's Address ACC\0XDSC\0" "1Adressverwaltung\0" "2DB\0" "XMM\0XSU\0XDI\0XRM\0NnoAddress ACC\0";
XMM | MailMerge
|
XSU | Suchwortübergabe (optional mit anschließendem '?')
|
XDI | Inquiry-Protokoll
|
XRM | Remote-MailMerge
|
Im Prinzip läuft das ganze Inquiry-Protokoll in 2 Stufen ab. Zuerst werden die Daten der verfügbaren Datenbanken ermittelt, und anschließend (zeitlich voneinander völlig unabhängig) werden die einzelnen Felder einer ausgewählten Datenbank erfragt.
Also Part 1 (am Beispiel von TA und TW):
TA | TW --------------------------------+------------------------------------ ACC_GETDSI <---------------------------------------- ACC_DSINFO ----------------------------------------> ACC_ACK <---------------------------------------- { ACC_FILEINFO ----------------------------------------> ACC_ACK <---------------------------------------- } /* <n> mal, wobei <n> bei ACC_DSINFO übertragen wurde */
Erklärung der einzelnen Protokollelemente:
ACC_GETDSI |
Hiermit wird das Inquiry-Protokoll initiiert. Diese Message enthält einen Pointer auf eine Variable des Typs Xacc_Dsi_Request, in dem codiert wird, welche Felder welchen Typs gewünscht sind. msg[0] = ACC_GETDSI (0x510) msg[1] = application id msg[4] und msg[5] = Pointer auf die gewünschten Feld-Typen (siehe XACC.H) |
ACC_DSINFO |
Auf ein ACC_GETDSI antwortet die angefragte Applikation mit dieser Message. Hierbei wird ein Pointer auf eine Variable des Typs Xacc_Dsinfo, wenn die Anfrage beantwortet werden kann, oder ein NULL-Pointer, wenn die Anfrage nicht beantwortet werden kann, der anfragenden Applikation übergeben. msg[0] = ACC_DSINFO (0x511) msg[4] und msg[5] = Pointer auf Xacc_Dsinfo Struktur (siehe XACC.H) oder NULL Die anfragende Applikation beantwortet alle Replys seinerseits mit einer ACC_ACK= Message: ACC_ACK: msg[0] = ACC_ACK msg[3] = 1 wenn alles OK ist = 0 wenn ein Fehler aufgetreten ist (Abbruch des Protokolls) |
ACC_FILEINFO |
Wenn die ACC_DSINFO Message von der anfragenden Applikation bestätigt wurde, so wird für jede verfügbare Datei eine ACC_FILEINFO-Message mit einem Pointer auf eine Variable des Typs Xacc_File_Info, oder ein NULL-Pointer bei einem Fehler, an die anfragende Applikation gesendet. Jede dieser Messages muß, wie oben erwähnt, mit einer ACC_ACK von der anfragenden Applikation bestätigt werden. msg[0] = ACC_FILEINFO (0x512) msg[4] und msg[5] = Pointer auf Xacc_File_Info Struktur (siehe XACC.H) oder NULL |
Wenn dieser erste Teil des Inquiry-Protokolls erfolgreich beendet wurde, dann kann die anfragende Applikation dem Anwender die Liste der verfügbaren Datenbanken und deren Information 'auf die Nase knallen' und ihn eine Auswahl treffen lassen.
Tut der Anwender dies, so läuft der 2. Part des Inquiry-Protokolls los (wieder am Beispiel von TA und TW):
TA | TW --------------------------------+------------------------------------ ACC_GETFIELDS <---------------------------------------- { ACC_FIELDINFO ----------------------------------------> ACC_ACK <---------------------------------------- } /* <n> mal, wobei <n> bei ACC_FILEINFO übertragen wurde */
Erklärung der einzelnen Protokollelemente:
ACC_GETFIELDS |
Hiermit wird von der anfragenden Applikation eine Datenbank ausgewählt (die entsprechende Datenbank-ID hat sie ja bei der ACC_FILEINFO Message in der Struktur Xacc_File_Info empfangen) und gibt der angefragten Applikation bekannt, daß nun die einzelnen Feldinformationen übertragen werden sollen. msg[0] = ACC_GETFIELDS (0x513) msg[1] = application id msg[3] = ID der gewünschte Datenbank |
ACC_FIELDINFO |
Wenn die ACC_GETFIELDS Message von der anfragenden Applikation bestätigt wurde, so wird für jedes Feld eine ACC_FIELDINFO Message mit einem Pointer auf eine Variable des Typs Xacc_Field_Info, oder ein NULL-Pointer bei einem Fehler, an die anfragende Applikation gesendet. Jede dieser Messages muß, wie oben erwähnt, mit einer ACC_ACK von der anfragenden Applikation bestätigt werden. msg[0] = ACC_FIELDINFO (0x514) msg[4] und msg[5] = Pointer auf Xacc_Field_Info Struktur (siehe XACC.H) oder NULL |
In That's / no| Address wurden im Moment die Feldtypen FT_CHAR, FT_DATE und FT_TIME implementiert.
Es werden zwei weitere Message-Typen eingeführt, um einen allgemeinen Datenaustausch zu ermöglichen:
#define ACC_REQUEST 0x480 #define ACC_REPLY 0x481
ACC_REQUEST |
Mittels dieser Nachricht fordert man bei einer anderen Applikation einen Dienst an. Der Aufbau dieser Nachricht ist folgendermaßen: msg[0]: ACC_REQUEST (0x480) msg[1]: Application-ID des Senders msg[2]: 0 msg[3]: Das high-Byte ist frei für Applikationsspezifische Informationen und im low-Byte ist der Typ der Daten codiert, die mit dieser Nachricht verschickt werden: 0x01 String, d.h. msg[4]+msg[5] ist ein Pointer auf den String 0x02 Env-String, d.h msg[4]+msg[5] ist ein Pointer auf den Env-String (mehrere durch '\0' getrennte Strings mit abschließenden doppelten '\0'-Bytes) 0x03 binär-Daten, d.h. msg[4]+msg[5] ist ein Pointer auf die binär-Daten. In diesem Fall muß der Empfänger natürlich über die Struktur Bescheid wissen! (lokale Typunterscheidung ist z.B. mittels des high-Bytes möglich) 0x04 code, d.h. msg[4] bis msg[7] enthalten direkt die Daten (sinnvoll bei Übertragung von Datenmengen bis 8 Byte) msg[4,5]: Pointer auf die Daten (außer Typ 0x04) msg[6,7]: Länge des Datenbereichs incl. eventueller '\0'-Bytes (außer Typ 0x04) Es existieren zwei verschiedene Möglichkeiten, diese Nachricht zu beantworten:
|
ACC_REPLY |
Mittels dieser Nachricht wird eine ACC_REQUEST Anforderung erfolgreich beantwortet. Der Aufbau dieser Nachricht ist folgendermaßen: msg[0]: ACC_REPLY (0x481) msg[1]: . . siehe ACC_REQUEST! . msg[7]: |
Applikationen, die oben beschriebene Protokollelemente unterstützen, müssen in ihrer XDSC-Beschreibung das Extended-Feature "RQ" enthalten haben.
Das no|Link-Accessory wurde für die Ansteuerung von Infrarotgeräten konzipiert und beinhaltet eine XAcc-Kommunikationsschicht für die Ansteuerung durch spezielle Applikationen. Zum momentanen Zeitpunkt wird das Media-Link-Interface von Catch Computer unterstützt. Eine weitere Anpassung an das no|Remote-Interface von no|Software ist in Arbeit.
Das no|Link-Accessory verwaltet alle Informationen, die zur Ansteuerung der verwendeten Infrarot- oder sonstiger Hardware benötigt werden. Jedem hardwareabhängigen Code (z.B einem Infrarotsignal) wird ein Befehl zugeordnet, und für jedes Gerät (z.B. Videorekorder) existiert eine Liste solcher Befehle.
Will nun z.B. eine Applikation für die Fernbedienung eines Videorekorders ein Infrarotsignal für die Play-Taste senden, so schickt es no|Link eine XAcc-Nachricht, in der das Kommando <senden>, das Gerät <VIDEOREKORDER> und der Befehl <PLAY> codiert sind.
Damit eine Applikation mit no|Link vollständig kommunizieren kann, muß diese das Request/Reply-Protokoll unterstützen, was als Extended- Feature in der XDSC-Beschreibung durch ein "RQ" bekannt gemacht wird. Nur so ist es möglich, die Liste der eingetragenen Geräte von no|Link erhalten zu können.
Wenn die Applikation auch Codes vom Accessory empfangen können will (nur mit entsprechender Hardware möglich), so muß als Extended-Feature in der XDSC-Beschreibung zusätzlich ein "RR" (Remote Receive) enthalten sein. Alle Applikationen, die mit noLink arbeiten wollen, müssen den XAcc-Level 1 unterstützen.
Als Application-Type enthält das no|Link-Accessory im XDSC "\2RC" (Remote Control).
Die vollständige XAcc-Identifikation von no|Link lautet zur Zeit folgendermaßen (in C-Syntax):
char xaccNoLinkIdent[] = "Infrarot Manager\0" "XDSC\0" "1Fernsteuerschnittstelle\0" "2RC\0" "XRQ\0" "NnoRci\0";
Eine denkbare XAcc-Identifikation für eine no|Link-Applikation könnte so aussehen:
char xaccIdentstring[] = "VideoControl\0" "XDSC\0" "1Video Fernbedienung\0" "XRQ\0" "Nno|Video ACC\0";
Die Kommunikation zwischen Applikation und dem no|Link-Accessory findet hauptsächlich über ACC_TEXT Messages statt.
Das Accessory versteht zur Zeit folgende Befehle, die als String mittels einer ACC_TEXT Message versendet werden müssen (<X> := <Gerät>:<Befehl>):
"S <X>" | Senden eines Befehls, z.B: "S VIDEO:PLAY".
|
"P <X>" | Präparieren eines Befehls, z.B: "P VIDEO:PLAY".
Hierbei wird der Infrarot-Hardware der Code für diesen Befehl
mitgeteilt, aber noch nicht abgeschickt.
|
"S" | Senden des zuletzt präparierten Befehls.
|
"T <X>" | Test der Existenz eines Befehls.
Insbesondere bei der Neuinstallation einer Fernsteuerungs- Applikation sollten alle Geräte und Befehle, die diese Applikation verwendet, dem Accessory mitgeteilt werden! Wenn no|Link den mitgelieferten Befehl nicht kennt, so wird der Benutzer aufgefordert, die nötige "Lernprozedur" zu tätigen bzw. dem neuen Befehl einen schon vorhandenen zuzuweisen. Es sollte in jeder Fernsteuerungsapplikation eine Funktion geben, die es dem Benutzer ermöglicht, alle unterstützten Befehle zu "testen" - am besten über einen "Anmelden"-Button. |
Die Testfunktion ist die einzige, die u.U. eine Interaktion mit dem Benutzer führt. Alle anderen vollführen keine Ausgabe.
Als Antwort erhält die Applikation eine ACC_ACK-Message, bei der in msg[3] der Erfolg der Behandlung des Befehls vermerkt ist:
1 | Operation war erfolgreich
|
0 | Gerät/Befehl ist nicht vorhanden bzw. Fehler bei der
Bearbeitung
|
Geräte- und Befehlsnamen dürfen maximal 32 Zeichen lang sein und dürfen KEINEN ':' enthalten. Es wird nicht zwischen Groß- und Kleinschreibung unterschieden.
Eine Applikation kann vom Accessory eine Liste der eingetragenen Geräte anfordern. Hierfür muß die Applikation das neue XAcc- Request/Reply-Protokoll verstehen (siehe oben bzw. XACC.H).
Um die Liste anzufordern, wird von der Applikation ein ACC_REQUEST an das Accessory geschickt, wobei diese Nachricht folgendermaßen aufgebaut sein muß:
msg[0] = ACC_REQUEST (0x480) msg[1] = apid msg[2] = 0 msg[3] = 0x04 /* Datentyp: Code */ msg[4] = 'D' /* 'D' steht für "devices" */ msg[5] = 0 msg[6] = 0 msg[7] = 0
Als Antwort erhält die Applikation, wenn ein Fehler auftrat eine ACC_ACK- Message mit msg[3] == 0, oder bei Erfolg eine ACC_REPLY- Message:
msg[0] = ACC_REPLY (0x481) msg[1] = apid von no|Link msg[2] = 0 msg[3] = 0x02 /* Datentyp: Environment-String */ msg[4]+msg[5] = Pointer auf einen global zugreifbaren Speicher, in dem die Liste der Geräte in folgendem Format steht: "DEVICEINFOS:\0Gerät1\0Gerät2\0" msg[6]+msg[7] = long-value, der die Größe des Buffers angibt (inkl. der abschließenden zwei NULL-Bytes)
Der Empfang einer ACC_REPLY-Message muß abschließend mit einer ACC_ACK- Message bestätigt werden, damit das no|Link-Accessory seine Resourcen wieder freigeben kann!
/*==================================================================*/ /* */ /* XAcc definitions (PureC syntax) */ /* */ /*==================================================================*/ #ifndef __XACC__ # define __XACC__ /*-------------------------------------------------------------------- XAcc message types --------------------------------------------------------------------*/ /* Level 0 */ # define ACC_ID 0x400 # define ACC_OPEN 0x401 # define ACC_CLOSE 0x402 # define ACC_ACC 0x403 # define ACC_EXIT 0x404 /* Level 1 */ # define ACC_ACK 0x500 # define ACC_TEXT 0x501 # define ACC_KEY 0x502 /* Level 2 */ # define ACC_META 0x503 # define ACC_IMG 0x504 /* * extended XACC Message-Types: * Diese Messages sind relativ "unabhängig" vom XACC-Level der * Applikationen, d.h. sie sollten nur verwendet werden, * wenn der Kommunikationspartner in seiner XDSC-Beschreibung * über das ensprechende Extended-Feature verfügt! */ /* Reuest/Reply Protokoll: (Extended-Feature "RQ") */ /* ACC_ACK Messages sind Teil des Protokolls und */ /* müssen deshalb verstanden werden! */ # define ACC_REQUEST 0x480 # define ACC_REPLY 0x481 /* Inquiry Protokoll: (Extended-Feature "DI") */ /* ACC_ACK Messages sind Teil des Protokolls und */ /* müssen deshalb verstanden werden! */ #define ACC_GETDSI 0x510 #define ACC_DSINFO 0x511 #define ACC_FILEINFO 0x512 #define ACC_GETFIELDS 0x513 #define ACC_FIELDINFO 0x514 /* Remote MailMerge Protokoll: (Extended-Feature "RM") */ /* ACC_ACK Messages sind Teil des Protokolls und */ /* müssen deshalb verstanden werden! */ #define ACC_FORCESDF 0x520 #define ACC_GETSDF 0x521 /*-------------------------------------------------------------------- definitions for the Request/Reply protocol --------------------------------------------------------------------*/ /* Datentypen des Request/Reply: */ #define RQREP_TYPE_STRING 1 #define RQREP_TYPE_ENVSTR 2 #define RQREP_TYPE_BIN 3 #define RQREP_TYPE_CODE 4 /*-------------------------------------------------------------------- definitions for the Inquiry protocol --------------------------------------------------------------------*/ #define DSI_VERSION 0x0100 /* field data-types: * values lower than 128 are 'human readable types' and * values greater/equal 128 are 'machine readable types' */ #define FT_CHAR 0x00 /* string */ #define FT_DATE 0x02 /* string in _IDT format. */ /* dflt: DD.MM.YY if no _IDT available */ /* For more about _IDT see MINT */ #define FT_TIME 0x03 /* string: HH:MM:SS */ #define FT_BYTE 0x80 /* 2 byte HEX-string */ #define FT_UBYTE 0x81 /* 2 byte HEX-string */ #define FT_SHORT 0x82 /* 4 byte HEX-string */ #define FT_USHORT 0x83 /* 4 byte HEX-string */ #define FT_LONG 0x84 /* 8 byte HEX-string */ #define FT_ULONG 0x85 /* 8 byte HEX-string */ #define FT_FLOAT 0x86 /* 8 byte HEX-string */ #define FT_DOUBLE 0x87 /* 20 byte HEX-string */ #define FT_ENUM 0x88 /* 4 byte HEX-string */ #define FT_BOOL 0x89 /* string: "T" or "F" */ #define FT_BITFLD 0x8A /* at 8 Bit aligned HEX-string */ #define FT_TIME_T 0x90 /* 8 byte HEX-string (time_t, see UNIX) */ typedef struct { int version; char field_types[32]; /* max. count of 256 fieldtypes are */ /* available (see definements above) */ /* Each bit in this field represents a */ /* valid field-type, where type 0 is */ /* the lowest bit of the first character */ /* and type 255 the highest bit of the */ /* last character */ } Xacc_Dsi_Request; typedef struct { int db_anz; /* count of available data bases */ } Xacc_Dsinfo; typedef struct { long db_id; /* ID of the data base */ char fname[32]; /* Filename of the data base. if you */ /* are using a GEMDOS or DOS filesystem */ /* it must have a <8.3> format. */ char title[32]; /* A max. 32 byte long description of */ /* the data base. */ time_t crea_time; /* The creation date/time of the data */ /* base file. */ time_t mod_time; /* The last modification date/time of */ /* the data base structure. */ int n_fields; /* The number of fields that are */ /* available corresponding to the */ /* requested field typs given by the */ /* ACC_GETDSI message */ } Xacc_File_Info; typedef struct { int fld_size; /* the count of bits into the field */ int n_fields; /* The count of field elements */ int elem_size; /* The length of one field element */ char field_buff[0]; /* from here the list of the <n_fields> */ /* elements follows in this format: */ /* 2 byte <bitno> and <elem_size> byte */ /* description. */ /* e.g. (<elem_size>=10): */ /* "\0\1private\0\0\0" */ /* "\0\2sex\0\0\0\0\0\0\0" */ /* "\0\4dealer\0\0\0\0" */ /* The value "06" identifies the 2nd */ /* and the 3rd element. */ /* NOTE that you can't use sizeof() */ /* because of this declaration. */ } Bitfld_Info; typedef struct { int n_enums; /* The count of enum-elements */ int elem_size; /* The length of one enum element */ char enum_buff[0]; /* from here the list of the <n_enums> */ /* elements follows in this format: */ /* 2 byte <id> and <elem_size> byte */ /* description. */ /* e.g. (<elem_size>=10): */ /* "\0Aprivate\0\0\0" */ /* "\0Bsex\0\0\0\0\0\0\0" */ /* "\0Edealer\0\0\0\0" */ /* The value "0042" identifies the 2nd */ /* element. */ /* NOTE that you can't use sizeof() */ /* because of this declaration. */ } Enum_Info; typedef union { ulong n_elems; /* for types like char,uchar this is */ /* the length of the field */ Enum_Info *enum_info; /* enum is a special type, which needs */ /* more description than the length! */ Bitfld_Info *bitfld_info; /* a bitfield like used in TA2 for the */ /* info-flags */ } Type_Desc; typedef struct { char id[8]; /* The export-identifier of the corres- */ /* ponding field, i.e. "A1" for the */ /* first address field of Clever or TA2 */ char name[16]; /* A short description */ char desc[32]; /* A long description */ int type; /* The data type. Must be one of the */ /* constants defined at the top of this */ /* file */ Type_Desc t_desc; /* This union contains either the length */ /* of the field or a pointer to a info- */ /* struct if the type is a special one */ /* like enum or other user-defined types */ } Xacc_Field_Info; #endif /* #ifndef __XACC__ */