Messages From The Inside
Mark Wherry takes a look at AES messages,
and how to interface your programs with them.
In modern Atari programming there is one area that is rapidly increasing in
popularity, it seems that every week there are more and more protocols and
messages for us to learn and use. However, what is even more frustrating is
not being able to use the protocols, either because you're unsure, or the
documentation is in (add an appropriate word of your choice here) German! In
this article, and perhaps others to follow, I'll de-mystify the ancient art
of the AES message.
The first step to be taken is when you appl_init() your application. It is
now really important that you store the integer that will be returned, as
this will be the unique number that identifies your application in the AES.
eg.
int ap_id; /* Application Identifier */
ap_id=appl_init();
Before you want to send a message, you must first find out the identifier of
the application you want to send the message to. This is really easy as
there is a function to do just that; use appl_find with the name of the
application, and the id will be returned. eg.
int other_id;
char *name;
other_id=appl_find(name);
It is important that the name is only 8 characters long, but if it is
shorter, you will have to pad it with spaces. So for example, if you wanted
to find the identifier for CAB, you would call appl_find like this:
cab_id=appl_find("CAB ");
If something goes wrong, the value -1 will be returned as the identifier.
This means that the program is not loaded in the memory.
The actual message is an array of eight shorts which has a standard length
of 16 bytes, declared like this:
short msg[8];
However, we now want to put something into the values but what do we do?
Well, we need to know exactly how the message we want to send is structured.
Although each message is different, there are a few conventions common to
all messages:
- msg[0] is always the message type, eg. AC_OPEN.
- msg[1] always contains the application identifier of the program sending
the message.
- msg[2] always defines the length of the message, not including the
pre-defined 16 bytes. This is usually 0.
So how do you put information into the message? Well numerical values are
easy, but what about filenames or other uses involving an array of
characters? Well they're easy too using the following code:
When sending characters you need to do it like this:
*(char**)&msg[x]=text_to_send;
x is the pointer to which part of the array the pointer will be stored.
In message definitions you will usually see something like this:
msg[3]= \Pointer to the text
msg[4]= /
For this example, x would be three, but there would be no need for any
direct definition for msg[4].
We could define the following function, to make using the above code even
more easier:
#define str2ptr(x,text) *(char**)&msg[x]=text
So now we can define a message, we send it using the appl_write function,
which is defined as:
error=appl_write(ap_id,length,msg);
ap_id is the value returned by appl_init, the identifier for your
application, length is the length of the message you are sending, which will
usually be 16 and, msg is the message itself. The error value will be
returned as 0 if everything went OK, and as a non-zero value if there was a
problem.
So that's all there is to sending a message, and here's a function from my
own GEM library to make life that bit easier! It's not exactly a mile-
stone in coding, but it helps out a little. (PS. I'm using LC5)
int SendMessage(char *apptosend, short sm0, short sm1, short sm2, short sm3,
short sm4, short sm5, short sm6, short sm7)
{
short sm_msg[8];
int error;
other_id=appl_find(apptosend);
error=other_id;
if(other_id>
=0){
sm_msg[0]=sm0;
sm_msg[1]=sm1;
sm_msg[2]=sm2;
sm_msg[3]=sm3;
sm_msg[4]=sm4;
sm_msg[5]=sm5;
sm_msg[6]=sm6;
sm_msg[7]=sm7;
error=appl_write(other_id,16,sm_msg);
}
return error;
}
The obvious gap now is, how do we receive the messages? Well, you'll be
glad to know that it's even easier than sending them. Simply use the
evnt_mesag function which you may already be familiar with from window and
accessory handling. Here is an example of how to handle messages:
while(notfalse)
{
evnt_mesag(msg);
switch(msg[0])
{
case MESSAGE_TYPE_1:
...Your handling of the message goes here...
break;
case MESSAGE_TYPE_2:
...Your handling of the message goes here...
break;
}
}
To get numerical values out of the message is as easy as putting them in,
what about extracting characters using pointers? When extracting characters
from a received message, simply do this:
text_to_retrieve=((char*)(((long)msg[x]<<
16)|(((long)msg[x+1])&0xFFFF)))
x is again the pointer to retrieve the text, so for the previous example,
x would be 3, and obviously x+1 would be 4.
We could define the following function, to make using the above code even
more easier:
#define ptr2str(x) ((char*)(((long)msg[x]<<
16)|(((long)msg[x+1])&0xFFFF)))
To round off our first expedition let's have a quick look at the popular
VA_START message as an example. The VA_START message is defined and
structured like this:
#define VA_START 0x4711
msg[0]=VA_START
msg[1]=ap_id
msg[2]=0
msg[3]= \ Pointer to filename (must include full path)
msg[4]= /
msg[5]=0
msg[6]=0
msg[7]=0
An important point to make is that when send a path using '\', you must
use two instead of one. So if you want to send "C:\HELLO\HELLO.IMG", you
would actually send "C:\\HELLO\\HELLO.IMG".
To send a VA_START message to CAB, you would:
error_return=SendMessage("CAB ",VA_START,0,0,
str2ptr(3,"C:\\HELLO\\HELLO.HTM"),0,0,0);
To receive a VA_START message you would:
evnt_mesag(msg);
if(msg[0]==VA_START){
filename=ptr2str(3);
printf("%s\n",filename);
}
I hope this will have helped you in some way, and stay tuned for more
protocols to be covered soon. If you want to contact me for help,
suggestions, chit-chat.... Please feel free!
Mark Wherry,
4 Fernpark Close,
Topsham Road,
Exeter,
Devon,
EX2 6AW
Back To ICTARI 45