Thread: Serial Port - Receive Packet

  1. #1
    Registered User
    Join Date
    Apr 2009
    Posts
    37

    Serial Port - Receive Packet

    Hi guys,

    I have a program that currently opens a serial com port on WinXP machine and sends data in a packet to an LCD screen. But some of the commands for the LCD screen require the program to receive packets from the LCD to WinXP.

    Here is my send_packet() code. It store relevant data such as command, data_length, data, crc. The packet is called outgoing_response, as defined by the LCD screen manufacturers

    Code:
    void send_packet(COMMAND_PACKET *packet)
    {
         ubyte i;
         unsigned char buffer[20];
         int index;
         index = 0;
         buffer[index++] = packet->command;
         buffer[index++] = packet->data_length;
         for(i = 0 ; i < packet->data_length ; i++)
                 buffer[index++] = packet->data[i];
         
         packet->CRC.as_word = 
         get_crc((ubyte *)&outgoing_response,outgoing_response.data_length+2,0xFFFF);
         buffer[index++] = packet->CRC.as_bytes[0];
         buffer[index++] = packet->CRC.as_bytes[1];
         
         DWORD bytes_written;
         bytes_written = 0;
         
         if(handle)
           if(TRUE != WriteFile(handle,
                                buffer,
                                index,
                                &bytes_written,
                                NULL))
           printf("WriteFile() failed!\n");
         }
    With this information can anyone help me to write afunction to receive packets from the LCD screen. the receive packet name is incoming_command as defined by the LCD manufacturer.

    Thanks

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by samuelmoneill View Post
    With this information can anyone help me to write afunction to receive packets from the LCD screen. the receive packet name is incoming_command as defined by the LCD manufacturer.
    Sure. But without knowing what the format and content of your message from the LCD screen is, it would not be possible to do [I could probably hack up a generic "receive x bytes", but not one that receives a proprietary package without knowing the format of the package].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    Sure thing Mats,

    this is what I got from the data sheet:

    0 (0x00): Ping Command
    The LCD will return the Ping Command to the host.
    type = 0x00 = 010
    valid data_length is 0 to 16
    data[0-(data_length-1)] can be filled with any arbitrary data

    The return packet is identical to the packet sent, except the type will be 0x40 (normal response, Ping Command):
    type = 0x40 | 0x00 = 0x40 = 6410
    data_length = (identical to received packet)
    data[0-(data_length-1)] = (identical to received packet)

    Hope this helps

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The basic principle is that you do the opposite of your write command. However, you may need to read a byte at a time, since for example the data-length will not be known until you have read the data length, of course. If you can be sure that the other side never sends packets on it's own, then you can possibly use a blocked read for the packet once you know it's size. But note that reading a block, you still need to make sure that if the whole packet is not received for some reason, your application doesn't continue to gobble up the next packet before it figures out that the current packet is "lost".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    Thanks Mats, should something like this do the trick? But it doesn't work? Do you know where I have gone wrong?

    Code:
    void receive_packet(COMMAND_PACKET *packet)
    {
         ubyte i;
         unsigned char buffer[20];
         int index;
         index = 0;
         buffer[index++] = packet->command;
         buffer[index++] = packet->data_length;
         for(i = 0 ; i < packet->data_length ; i++)
               buffer[index++] = packet->data[i];
         
         packet->CRC.as_word =
         get_crc((ubyte *)&incoming_command,incoming_command.data_length+2,0x0000);
         buffer[index++] = packet->CRC.as_bytes[0];
         buffer[index++] = packet->CRC.as_bytes[1];
         
         DWORD bytes_written;
         bytes_written = 0;
         
         if(handle)
           if(TRUE != ReadFile(handle,
                               buffer,
                               index,
                               &bytes_written,
                               NULL))
           printf("ReadFile() failed!\n");
           printf("%s\n", buffer);
           getchar();
           getchar();
           }

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    No, you need to get the information of "command" and "length" from reading the serial port, not stuffing it into your buffer first, then calling read. When you receive a letter by post, do you need stuff an envelope with a sheet of paper first [if that was the case, I wouldn't get ANY bills, wohoo! ]?

    You obviously also should not SET the CRC, but rather read all the data and then calculate the CRC on the data, and check that the CRC calculated is the same as the received CRC.

    Also, you may want to rename your variable "bytes_written" to "bytes_read".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    I still don't fully know how to do it?
    Do I call the readFile() function first?
    How do I get and store the information of command and legth from the packet?

    Code:
    void receive_packet(COMMAND_PACKET *packet)
    {
         ubyte i;
         unsigned char readbuf[20];
         int index;
         index = 0;
         DWORD bytes_read;
         bytes_read = 0;
         if(handle)
           if(TRUE != ReadFile(handle,
                               &readbuf,
                               MAXBUFFERSIZE,
                               &bytes_read,
                               NULL))
           printf("ReadFile() failed!\n");
         readbuf[index++] = packet->command;
         readbuf[index++] = packet->data_length;
         for(i = 0 ; i < packet->data_length ; i++)
               readbuf[index++] = packet->data[i];
         
         packet->CRC.as_word =
         get_crc((ubyte *)&incoming_command,incoming_command.data_length+2,0xFFFF);
         readbuf[index++] = packet->CRC.as_bytes[0];
         readbuf[index++] = packet->CRC.as_bytes[1];
         
       
         
    
           printf("%s\n", readbuf);
           }

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You need to read ONE character at a time to get that information - unless your packet is always MAXBUFFERSIZE bytes - in which case I don't see the point of encoding a length in the packet.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    How about this?

    Code:
    void receive_packet(COMMAND_PACKET *packet)
    {
         ubyte i;
         unsigned char readbuf[20];
         unsigned char received[20];
         int index;
         index = 0;
         DWORD bytes_read;
         bytes_read = 0;
         if(handle)
            received[index++] = ReadFile(handle,
                               &readbuf,
                               index,
                               &bytes_read,
                               NULL);
           printf("ReadFile() failed!\n");
         //readbuf[index++] = packet->command;
         //readbuf[index++] = packet->data_length;
         for(i = 0 ; i < packet->data_length ; i++)
               readbuf[index++] = packet->data[i];
         
         packet->CRC.as_word =
         get_crc((ubyte *)&incoming_command,incoming_command.data_length+2,0xFFFF);
         readbuf[index++] = packet->CRC.as_bytes[0];
         readbuf[index++] = packet->CRC.as_bytes[1];
         
       
         
    
           printf("%s\n", received);
           getchar();
           getchar();
           }

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Ehm, you probably don't want to pass index as the "number of bytes to read" - and how do you know you've read it all?

    You don't understand what you are doing, right?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    Yes you are right, I don't really know what I am doing. Can you explain it to me please?

    At this stage I know how to write a file to the Com port. One of the commands write a ping request to the LCD screen but I don't know how to read the data back from the LCD screen?

    This is the latest readFile() code that I have

    Code:
    void receive_packet(COMMAND_PACKET *packet)
    {
         int ret;
         unsigned char buf[2];
         unsigned long len;
         
         ret = ReadFile(handle,
                        buf,
                        1,
                        &len,
                        NULL);
         if(len > 0)
         {
                //if(trace == 1)
                printf("read char %d\n", (int)buf[0]);
                }
    }
    How does that look?

    But when I open a hyperterminal I know that I am not reading anything?

    these are the list of commands that I call in the main()
    Code:
    outgoing_response.command = 0; // coomand to send ping
    outgoing_response.data_length = 0;
    send_packet(&outgoing_response);
    receive_packet(&incoming_request);
    Can you tell me what I am doing wrong?

    I really dont know how to intercept or catch the response from the command?

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The latest code fragments look like you are going in the right direction - although the first thing you get back is the command, isn't it?

    My main point about the previous code is this:
    When you read a packet on a serial port, you do not know what packet you are about to receive (you may be able to fairly accurately guess, but the other end may not have received your packet correctly and send a "Huh? Please try again" message rather than the correct response - or someone may have pressed the reset/power button and switched it off, etc, etc).

    So, when receiving a packet, you need to consider the unknown part of things. Part of that is to read the packet type and length first, then get on with receiving the packet payload itself, and finally, the CRC at the end. All these reads should be done with a suitable timeout, so that if someone pulls the power-cord out, or in some other way the communication isn't working, your program continues to work correctly.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    Yes the first thing I get back should be the command.

    The packet type for this particular packet as far as I know is 0x40 as defined in the data sheet

    0 (0x00): Ping Command
    The LCD will return the Ping Command to the host.
    type = 0x00 = 010
    valid data_length is 0 to 16
    data[0-(data_length-1)] can be filled with any arbitrary data

    The return packet is identical to the packet sent, except the type will be 0x40 (normal response, Ping Command):
    type = 0x40 | 0x00 = 0x40 = 6410
    data_length = (identical to received packet)
    data[0-(data_length-1)] = (identical to received packet)

    which is a ubyte command as defined in the data structure

    Code:
    typedef struct
      {
      ubyte
        command;
      ubyte
        data_length;
      ubyte
        data[MAX_DATA_LENGTH];
      WORD_UNION
        CRC;
      }COMMAND_PACKET;
    With this information and the previous readFile function would you be able to help me to receive the dat please? Do I need to set up a thread or process to wait for bytes to be read? Could you help me write this please?

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    So, you need another read just like the one for len, to read the command in.

    Then the length, as it is now.

    Then read length number of bytes, and 2 more for the CRC.

    Calculate the CRC for the cmd, len and data, and compare with the received CRC value.

    Assuming of course none of this went wrong, you have a packet.

    Hint: I would write another function that reads a single byte.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    Apr 2009
    Posts
    37
    Hi Mats

    here is my attempt at understanding what you mean.

    Code:
    void receive_packet(COMMAND_PACKET *packet)
    {
         int ret;
         unsigned char buf[2];
         unsigned long len;
         unsigned long length;
         len = 0;
         char cmd[2];
         int d_len;
         
         while(len != NULL) {
         ret = ReadFile(handle,
                        buf,
                        1,
                        &len,
                        NULL);
         if(cmd == NULL) {
         cmd = buf;
         }
         if((cmd != NULL) && (d_len == NULL)) {
                 d_len = buf;
                 }
                 }
         if(len > 0)
         {
                //if(trace == 1)
                printf("read char %d\n", (int)buf[0]);
                }
                
         
    }
    would you mind writing a small code snippet of your solution please. I cant fathom this at all.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. serial port to poll on request
    By infineonintern in forum C++ Programming
    Replies: 2
    Last Post: 06-11-2009, 06:52 AM
  2. Can't Read From Serial Port
    By HalNineThousand in forum Linux Programming
    Replies: 14
    Last Post: 03-20-2008, 05:56 PM
  3. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 05:49 PM
  4. Send and receive through serial Port
    By overspray in forum C++ Programming
    Replies: 1
    Last Post: 07-21-2004, 04:15 PM
  5. DOS, Serial, and Touch Screen
    By jon_nc17 in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 01-08-2003, 04:59 PM