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