Leandro Lima
Leandro Lima

Reputation: 1170

Best practice in read data from buffer

I would like to receive ideas about how to read data from an UART buffer. Being more precisely, I need a way to find some string pattern in the buffer. The problem is that if I wait to search this string, the buffer is written again, the counter changes, and the data can have the pattern or not. Well, I think that this explanation is a little hard to understand, so feel free to ask anything else.

void f(char * buffer) {

char * p;
p = strstr(buffer, "abc");

printf(p);
}

I think the UART, in my case, is written by blocks and not char by char and there's no way to say that data finished because it's a continuous stream. To better illustrate, it is a code that reads GPS data in NMEA protocol and try to get information from these data.

Best regards

Upvotes: 0

Views: 4329

Answers (3)

Nan Xiao
Nan Xiao

Reputation: 17487

Could you receive all the data then processing the string? I think the code likes this:

char *p_uart = read_from_uart();

void search_string(char *p_uart)
{
    static char last_remain_char[20];
    char new_data[1000] = {0};
    char *p = NULL;
    int n = 0;

    n = snprintf(new_data, sizeof(new_data), "%s%s", last_remain_char, p_uart);
    p = strstr(new_data, "abc");

    strcpy(last_remain_char, new_data + (n - (strlen("abc") - 1)));
}

Upvotes: 0

paddy
paddy

Reputation: 63481

Your question is not clear, but I've seen a lot of people misunderstand how buffers work, so I think I can help.

By what you're saying, you are expecting to read data into a buffer, and are worried that it will partially match your search string. Then when you read the rest of it, you overwrite the first lot of data.

So, this comes down to how you process your data. You don't need to read into the same part of memory every time. The whole point of a buffer is it gives you space that you can fill up, shuffle around if necessary and then discard.

There are many ways to use buffers effectively. I'll give you the simplest one to understand, although it might not be the most efficient:

When you read into the buffer, you maintain an index (let's call it tail) so you know where the last byte is. You can read up to N bytes where N is the size of your buffer. When it comes to processing the data, you can check bytes up to tail.

To track what you have already processed, maintain a head index. Once you have determined that you need to read more data, you take everything between head and tail and move it to the beginning of the buffer (use memmove, NOT memcpy). You set head = 0, and tail = tail-head. Now you can read up to N - tail more bytes. Naturally, you read into a position in the buffer beginning after the tail index.

If you want to be able to test the entire match string as consecutive bytes, this is the easiest buffering approach.

If you want to go a step further, it doesn't take much imagination to realise that you don't need to move the data at all. You can just have head chase tail around and around. This is called a ring (or circular) buffer. The difficulty with this is you can't use ordinary string matching, but it doesn't take much to roll your own.

Hope this is helpful.

Upvotes: 0

perreal
perreal

Reputation: 98118

You can receive each character and accumulate them (copy) in a regular buffer for comparing later. Or, a better way is to receive each character and keep a state variable to tell you how far you are in the match:

size_t state = 0;
while( c=get_char_uart() ) {
    if (str_to_match[state] == c)  {
        state++;
        if (state == strlen(str_to_match)) {
            /* success */
        }
    }
    else 
        state = 0;
}

if you are expecting a repeating sequence of characters ("abcabd") it gets trickier. In this case if you fail at d you might need to look for c. Be warned.

Upvotes: 0

Related Questions