Thread: loading struct from UART received data

  1. #1
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83

    loading struct from UART received data

    Hi,

    I am writing an embedded application which takes in messages from a UART and loads them into a struct. I want to add each incoming char into subsequent members in my interrupt routine. Here is the bones of the code I have so far

    Code:
    IncomingMessage.control_dollar = USART_ReceiveData(USART1);
    
        if(char_counter == 0 && IncomingMessage.control_dollar != '$')
        {
            ;
        }
        else
        {
            for(char_counter = 1; char_counter <= 16; char_counter++)
            {
                // writing remaining characters to struct
                temp_data = USART_ReceiveData(USART1);        // read data register to clear flag    
            }
            
        }        
    
         char_counter = 0;
    }
    The USART_RecieveData is a device specific command which reads the data register and clears a flag, required after each char received.

    My struct is:

    Code:
    typedef struct
    {
      vu8 control_dollar;
      vu8 p;
      vu8 s;
      vu8 u;
      vu16 address;
      vu8 space;
      vu16 controlString1;
    } ControlMessage;
    The issue I have is, how do I write to subsequent members within the for loop - if I put a member name in there it will just overwrite each time the loop goes round.

    Regards
    Dave

  2. #2
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    I would believe you should have USART_ReceiveData() place its data into some buffer of defined size and then loop though this buffer to assign to your struct members as needed.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Slingerland's suggestion would work.

    There are (at least) a couple of alternatives:
    1. Instead of a for-loop, use a state machine that tracks where you are in the struct, and read the data accordingly.
    2. Make a char pointer point to the first element, and pretend that your struct is an array (beware, however, of compiler generated "holes" in structures like that - for example, "space" makes the last vu16 value be unaligned, so I would expect the compiler to pad it out with an empty byte between "space" and "controlstring1").
    3. Have an array that contains 16 pointers to the relevant data, and use the i value to fetch the pointer and store the received data into the memory given by the pointer.

    --
    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.

  4. #4
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    after a bit of thinking on this, I came up with:

    Code:
    {
        static u16 char_counter;
        u16 temp_data    
    /**************************************************************************
    * Receive characters from the USART and then load them into a struct      *
    **************************************************************************/
        
        temp_data = USART_ReceiveData(USART1);
    
        if(char_counter == 0 && IncomingMessage.control_dollar == '$')
        {
            IncomingMessage.control_dollar = temp_data;
            char_counter++;
        }
        else if ((char_counter == 1) &&  temp_data == 'p')
        {
            IncomingMessage.p = temp_data;
            char_counter++;
        }
        else if ((char_counter == 2) && temp_data == 's')
        {
            IncomingMessage.s = temp_data;
            char_counter++;
        }
        else if ((char_counter == 3) && temp_data == 'u')
        {
            IncomingMessage.u = temp_data;
            char_counter++;
        } 
    else if ((char_counter == 4) && /* other condition */)
        {
            IncomingMessage.address1 = temp_data;
            char_counter++;
        }
        else if ((char_counter == 5) && /* other condition */)
        {
            IncomingMessage.address2 = temp_data;
            char_counter++;
        }
        else if ((char_counter == 6) && temp_data == 0x20)
        {
            IncomingMessage.space = temp_data;
            char_counter++;
        }
    The comments are because I still need to work out how to parse the address. This has been read in main and stored in a variable. But the cahracters come in one at a time, so I need to work out how to correlate the two hex characters in the struct to the variable I already have saved.

    I think that it close to your suggestion (1), matsp.

    Dave

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I take it from your comments that "address" is a two hex digit value, then.

    So, you may want to check that it's 0..9 and a..f or A..F (you may only need to check either A..F or a..f).

    --
    Mats
    Last edited by matsp; 12-03-2008 at 05:35 AM.
    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.

  6. #6
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    yes it is, sorry didn't make that clear, between 0x01 and 0xFE

    dave

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by droseman View Post
    yes it is, sorry didn't make that clear, between 0x01 and 0xFE

    dave
    Sorry, I edited whilst you where replying. See my previous post.

    However, I would also consider collecting the WHOLE package without checking, and THEN check each part is correct values. The way you have it right now, it won't work if a character is lost - you'll just never get past that point until the NEXT package gets to that point (and if your packages are requiring a reply before the next can be sent, then that will never happen).

    --
    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.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    http://en.wikipedia.org/wiki/OSI_model
    I would suggest you not mix "what they are" with "what they mean" in the same function, especially an ISR.

    All you should be doing here is collecting bytes, and storing them in a buffer.

    Something else should be reading those bytes, and looking for the syncronisation to establish the message boundaries.

    A further something else should be mapping the bytes onto your structure.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Salem, how come I didn't express it that clearly [Don't bother answering that, I'm just a rambling fool sometimes].

    --
    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.

  10. #10
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    That makes sense to me. The reason for the text filtering in the char collection routine is to make sure that I don't collect any junk on the line, since I am only expecting one of three possible messages to come down the link.

    The thing which is stumping me is that in the struct I have the address as two separate characters, but in the main program, I have one variable with the address, read from the hardware.

    The trick I am trying to accomplish is to check if the contents of the struct match the saved address, then I will know whether to discard the message or not.

    Hope this makes sense

    Dave

  11. #11
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    its too late in the day....

    I posted that without reading the post from salem...

    so then, fill some sort of array from my UART, then in my main function access the array and use that to populate the struct ?

    One to think about on a fresh brain in the morning, I think

    Dave

    A follow on question - is it possible to return variables from an interrupt routine i.e. how do I get my filled array into main so that I can fill my struct?
    Last edited by droseman; 12-04-2008 at 03:43 AM. Reason: new question

  12. #12
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    so, for filling my array in the ISR, I have

    Code:
    u8 rx_array[18];
    
    for(i=0; i<=18; i++)
    {
          USART_ReceiveData(USART1) = rx_array[i];
    }
    return rx_array;
    }
    u8 is typedef for char btw

    Is this reasonable, or complete tosh?

    --dave
    Last edited by droseman; 12-04-2008 at 04:26 AM.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    I was thinking along these lines
    Code:
    static u8 buffer[SIZE];
    static int writeptr = 0;
    static int readptr = 0;
    static int nbytes = 0;
    static int error = 0;
    
    // This is your ISR
    void isr ( void ) {
        // get a lock
        if ( nbytes < SIZE ) {
            buffer[writeptr++] = USART_Read();
            // clear USART rx-data interrupt flag
            if ( writeptr == SIZE ) writeptr = 0;
            nbytes++;
        } else {
            error = 1;
        }
        // release a lock
    }
    
    // This is the lowest lever user-space function to read what's available
    void readData ( u8 *buff, int buffSize, int *amtRead ) {
        // get a lock
        // copy from buffer to buff, taking care of
        //  the size asked for
        //  wrap-around 
        // adjust readptr
        // adjust nbytes
        // maybe do something if error is set as well
        // release a lock
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Embedded in C...
    Join Date
    Sep 2008
    Location
    Basingstoke, Hampshire
    Posts
    83
    I know its been a while, but I had another task to do before xmas..

    are all the variable declarations global in the main function or defined in the ISR?

    What do you mean by 'get a lock' and 'release lock'?

    Apologies if these are stupid simplistic questions, this is my first 'real' programming project.

    --dave

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > are all the variable declarations global in the main function or defined in the ISR?
    I made them static ("global" to the source file in which they're declared)

    The user space caller of readData() passes a pointer to a buffer where they want the data to be stored.

    > What do you mean by 'get a lock' and 'release lock'?
    It means a mechanism to ensure that only ONE of the functions updates the data.
    In readData(), if you did say readptr++ and at the wrong moment the isr() was called, then there's a good chance that the readptr++ would produce the wrong result.

    How you do this depends widely on your OS, for example
    http://www.rt.com/man/semget.2.html

    Do you have an OS on your embedded platform?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. towers of hanoi problem
    By aik_21 in forum C Programming
    Replies: 1
    Last Post: 10-02-2004, 01:34 PM
  2. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  3. gcc problem
    By bjdea1 in forum Linux Programming
    Replies: 13
    Last Post: 04-29-2002, 06:51 PM
  4. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 03:58 PM
  5. Loading a struct with data from a file
    By TankCDR in forum C Programming
    Replies: 1
    Last Post: 10-28-2001, 08:58 AM