Mr. Van Loon,

> I have been using memcpy() to copy stucts (sometimes several 
> of them) into a
> buffer. I then call write() on the buffer and then the opposite
> at the other end. I think this is the same thing as calling 
> write() on a
> structure. I have been doing something like:
> 
> unsigned char *pu8to   = &buffer;
> unsigned char *pu8from = &struct; 
> 
> for(int i=0; i<sizeof(struct); i++){
>         *pu8to++ = *pu8from++
> }
> 
> write(fd, buffer, sizeof(struct));

        You could also save yourself the trouble of doing the copy with
something like:

        write(fd, (unsigned char *)&struct, sizeof(struct));

> If I understand you, this means that my code might fail when 
> both ends of a fifo
> were not compiled by the same gcc version or when both ends 
> of a network are not
> compiled by the same gcc version or are differing platforms.

        It will probably not fail with different versions of GCC, as long as
they are able to use the same version of libc.  It will probably not fail
between gcc front-end languages, e.g., objective c, c++, etc.  It will
almost certainly not fail when you compile both applications on the same
machine with the same compiler.

        The problem will come down the road when you decide to move the user
interface from your RT system to a remote system.  At this time you also
decide to add a GUI to the system using Tcl/Tk or Python or Perl/Tk.  If you
make any assumptions about the packing of the structure or the byte ordering
of the values please be prepared to be wrong.

        Because I will probably not remember these issues when I add the
additional features, or when a system is upgraded to a newer version of libc
or some such, I strongly prefer to just write the code in a bullet-resistant
manner in the first place.  To do so, I use a defined byte ordering in my
packets and pack them together myself.  This has the side benefit of
eliminating the transmission of any padding characters, though at the
expense of the time to assemble and disassemble the packets.

> I am trying to imagine some reasonable way to unpack / pack 
> structures across a
> network that does not depend upon some structure being 
> organized in the same
> manner at both ends. This is the only thing that I could come up with:
> ... scheme deleted ...

     I usually use something like the following:

// Could be enums if you like that approach.  Most of this would be hidden
in a header somewhere.
#define SHORT 0
#define LONG 1
#define FLOAT 2
#define DOUBLE 3
#define CHARS 4

sruct PACKET_DESCRIPTION {
    long start, length;
    void *data;
    long vartype;
};

// Obviously the status structure has to exist at this point.
struct PACKET_DESCRIPTION status_packet[] = {
    { 0, 4, &status.num, LONG},
    { 4, 2, &status.type, SHORT},
    { 6, 80, &status.message, CHARS },
    { 86, 8, &status.result, DOUBLE },
    { 94, 0, NULL, SHORT }
};

unsigned char stauts_buf[1024];
long index, temp_long;
short temp_short;

index = 0;
while (status_packet[index].length != 0) {
    switch (status_packet[index].vartype) {
    case LONG:  // Copy them after we set byte ordering with htonl
        memcpy(&temp_long, status_packet[index].data, 4);  
        temp_long = htonl(temp_long);
        memcpy(&status_buf[status_packet[index].start], &temp_long, 4);
        break;
    case SHORT:  // Copy them after we set byte ordering with htons
        memcpy(&temp_short, status_packet[index].data, 2);
        temp_short = htons(temp_short);
        memcpy(&status_buf[status_packet[index].start], &temp_short, 2);
        break;
    case CHARS:  // Just copy them
        memcpy(&status_buf[status_packet[index].start],
status_packet[index].data, status_packet[index].length);
        break;
    case FLOAT:
        // You are on your own here, no real network standard exists -
define something and figure it out for
        // each of your architectures.  Good luck.
        break;
    case DOUBLE:
        // You are on your own here, no real network standard exists -
define something and figure it out for
        // each of your architectures.  Good luck.
        break;
}

> This does depend upon the size of the types involved being 
> the same size at both
> ends 

        That is true.  For the sake of interoperability, the TCP/IP
standards (or are they internet standards?) for a short are 16 bits and for
a long 32 bits.  I have not found these to be too limiting.

> and I think that it requires the bytes in the types, 
> (int for example) to
> be stored in the same order at both ends.

        Nope, that is the point of using the htonl and htons functions.  Any
standard C library will include them (they are usually #defines in headers)
or they are quite simple to create yourself.  The network standard is
big-endian (most significant byte first) FYI.

        Please note that this structure also separates the concept of a
structure from a message.  You could easily include other variables in your
message from various structures.

        I hope this helps clear things up.  Again, for a quick summary, if
you are only working on one machine with one architecture and it is not a
long-term project where any changes are likely, then you can copy structs.
Otherwise, I would suggest a mechanism such as that outlined above.

Regards,

Steve

--------------------------
Stephen D. Cohen
Xybion Sensor Positioning Systems
11528 53rd Street North
Clearwater, FL 33760
Voice: (727) 299-0150
Fax: (727) 299-0804 
[EMAIL PROTECTED]
www.xybion.com
-- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
--
For more information on Real-Time Linux see:
http://www.rtlinux.org/

Reply via email to