1

I am receiving this frame $0,S1,B2,Kffffffffffff,T61*34 through UART with this code.

//Receive Data
for(uint8_t i = 0; i < size; i++){
    receivedFrame[i] = EUSART1_Read();
    if(receivedFrame[i] == '*'){
        size = i + 3;
    }
}

The start of the frame is always $ and the end is always * after that comes two bytes holds the check sum for the previous bytes (ex 34).

The frame length is not fixed but it has a minimum length of 26(from $ to *) + 2 bytes of check sum and maximum length of 62 and also + 2 bytes of check sum.

but it is not the best thing to use since so many scenarios could happen to make this unstable for example if the * didn't arrive, this will make every frame I read is wrong.

I searched for better way to receive data through UART but didn't manage to find any thing. I am looking for better ways to deal with receiving frames like this.

Ahmed Rifaat
  • 57
  • 2
  • 10
  • Please [edit] your question and add more details: What is the specification of the frame format? Is there a terminating character at the end? Maybe a NL or CR and NL? Does every frame start with `$`? Can a `$` occur anywhere else? Is the length of the fields fixed or variable? For example can you have `7` or `123` instead of `34` after `*`? – Bodo Dec 09 '21 at 12:28
  • Thank for your response, I will edit it now. – Ahmed Rifaat Dec 09 '21 at 12:29
  • Message looks like `NMEA 0183`, is it? – Flexz Dec 09 '21 at 12:57
  • This the first time to hear about it, but I looked it up and yes it looks like it. I took this method from a friend. – Ahmed Rifaat Dec 09 '21 at 13:03
  • 2
    If it is NMEA 0183 it should have a trailing CR and LF, according to https://en.wikipedia.org/wiki/NMEA_0183 – Bodo Dec 09 '21 at 13:05
  • *"I am receiving this frame ... through UART"* -- At the UART level, a *frame* consists of one character (of 5 to 9 bits). You're referring to a datagram or message or packet. – sawdust Dec 10 '21 at 00:52
  • 1
    If your start and end characters are unique (i.e. should not appear in the middle of the message), then scanning for complete messages is straightforward. Consider the far more difficult scan without unique symbols: https://stackoverflow.com/questions/16177947/identification-of-packets-in-a-byte-stream – sawdust Dec 10 '21 at 00:58

2 Answers2

0

This solution is based on the assumption that there is no trailing CR or LF, but it will also work in this case by skipping CR and LF until $ is found.

I suggest to combine your algorithm with a check for $ which whould reset the position to 0 and store the $ at position 0. This will ignore frames that don't contain * at the expected position.

You probably should initialize size to the maximum before entering the loop and make sure that size is not increased in case the * is received too late.

Additionally I would make sure that the first character is '$' and not increment the index if this is not true.

For this conditional incrementing of the index, a while loop is better suited.

Untested proposal:

unsigned char receivedFrame[64];
uint8_t size = sizeof(receivedFrame);
uint8_t i = 0;
while(i < size)
{
    unsigned char ch = EUSART1_Read();
    if(ch == '$')
    {
        // in case i was > 0, ignore wrong frame, start from beginning
        i = 0;
    }
    else if(receivedFrame[i] == '*'){
        uint8_t new_size = i + 3;
        if(new_size < size)
        {
            size = new_size;
        }
    }
    receivedFrame[i] = ch;
    // stay at the first position if the character is not '$'
    if((i > 0) || (ch == '$'))
    {
        i++;
    }
}

Additional hint: For testing the algorithm on a PC you could replace EUSART1_Read with fgetc or getchar. Note that these functions return an int value which should be checked for EOF before converting it to an unsigned char.

Bodo
  • 9,287
  • 1
  • 13
  • 29
0

If you are interested in special packet markers, then look for them: wait until a start ($), then record and count everything until end (*), then read two chars more.

While recording and counting, check for room in order to not overflow. Depending of how many errors you expect, it could be a nice idea to reset the count when an "*" is received, as suggested by @Bodo.

Is there a way to know if EUSART1_Read() really found a character? Or does it wait for ever (dangerous)? Better would be to not wait too much, and knowing there are more chars to read.