NMEA parsing, serial interrupt?

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

NMEA parsing, serial interrupt?

Post by sturgessb »

Hi Guys

I have hooked up a gps to the com2 channel, and set the gps module to output only the two sentence types I need, at 5hz.

Now the question is, how can I read that data and convert into useful variables in the most efficient way?

How can I get those two sentences in one string variable in order to split up and decode? At the moment with the following code I am getting mostly stable output (i.e cleans lines of data) but every few seconds it gets out of sync and i get partial and joined sentances.

Code: Select all

Do
		GPS_in = GetQueueStr(com2RXQueue)
                Debug.print GPS_in
               call sleep(0.2)
	Loop
this is the output

Code: Select all

$GPGGA,212048.059,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*42
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212048.260,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4A
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212048.460,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4C
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212048.659,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*44
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212048.859,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4A
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212049.059,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212049.260,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4B
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212049.460,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4D
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212049.659,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*45
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212049.859,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4B
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212050.059,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4B
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212050.260,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212050.46
0,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*45
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212050.659,8960.0000,N,00000.0000,E
,0,0,,137.0,M,13.0,M,,*4D
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212050.859,8960.0000,N,00000.0000,E,0,0,,137.0
,M,13.0,M,,*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212051.059,8960.0000,N,00000.0000,E,0,0,,1
37.0,M,13.0,M,,*4A
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212051.260,8960.0000,N,00000.0000,E,0,0,,137.0,M,13
.0,M,,*42
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212051.460,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*44
$GPV
TG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,212051.659,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4C
$GPVTG,0.00,T,,
M,0.00,N,0.00,K,N*32
$GPGGA,212051.859,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*42
$GPVTG,0.00,T,,M,0.00,N,0.0
0,K,N*32
$GPGGA,212052.059,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*49
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,212052.260,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*41
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
How should I get around this problem, Can I somehow set a ISR to run when the com2 detects the start of a transfer?

Cheers

Ben[/code]
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

this seems to work, although it screw up my other tasks

Code: Select all

Do
		Call WaitForInterrupt(&H14, 2)
		Call Sleep(0.10)
		GPS_in = GetQueueStr(com2RXQueue)
		debug.print GPS_in
	Loop
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: NMEA parsing, serial interrupt?

Post by dkinzer »

sturgessb wrote:At the moment with the following code I am getting mostly stable output (i.e cleans lines of data) but every few seconds it gets out of sync and i get partial and joined sentances.
The problem that you're seeing is a result of the defined behavior of GetQueueStr(). The description of that function explains that the number of characters returned depends on several factors, one of which is the number of characters that happen to be in the queue at the time of the call. Since your code doesn't try to synchronize in any way with the expected content, it is clear that there is a chance that you're going to get a partial line/sentence returned from time to time.

There is no pre-defined way to extract a complete NEMA sentence (and only a complete sentence) from a queue. Nor is there a way to extract only complete lines.

You can work around this by examining the returned string to see if it has either 1) a partial sentence, 2) exactly a complete sentence, or 3) a complete sentence plus part of a following sentence. In the first case, you'll want to save the partial sentence somewhere and check back later, adding future sentence fragments to the saved partial sentence until you have a complete sentence. In the second case, you're good to go unless you have a previously-received partial sentence. In the third case, you'll want to separate the returned string into the complete and partial sentences and process as above.

All in all, I think you'd be better off defining a buffer that is large enough to hold the longest expected sentence and then use GetQueue() to retrieve one or more characters from the queue, placing them in the buffer, adding to previously retrieved characters. When you get a complete sentence in the buffer, you can copy it to a string using the MakeString() function and then move the remaining partial sentence, if any, to the beginning of the buffer.
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Thanks Don, ill try that.

However... how is this for strange!


If I have the following running an a task on its own...

Code: Select all

Do
      Call WaitForInterrupt(&H14, 2)
      Call Sleep(0.10)
      GPS_in = GetQueueStr(com2RXQueue)
Loop
It works great but it screws up the output on serial channel1, after a few seconds the output on com1 starts breaking up and eventually just disappears into lots of nothing being written to my screen!

BUT, if I set GPS_in to be a boundedstring(200) not a normal string (of what i think im correct is saying is 255bytes, it does not!

However even with that 'fix' in place, if i try to output any of the captured data from the gps (im splitting it into and array) on com1, it goes screwy again, com1 outputs partial data until eventualy all i get is white space being written to screen.

How odd!?

Ben
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Do Com1 and Com2 share any resources?

I have a Com1 outputting data in one task, and Com2 collecting data in another, and its causing all sorts of problems (the Com1 task starts producing gaps in the out data)
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:Do Com1 and Com2 share any resources?
They are both interrupt driven but beyond that, no.

Can you create a minimalist example that exhibits the problem?
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

a bit tricky to recreate but ill try.

Does a task stack need to be bigger than the Com Queue size if its using it in the task?

I'm occasionally getting random restarts. Is there anything else that could be causing restarts?

On further investigation, again the problem (this time the restart) is only occuring when running the following line...

Code: Select all

GPS_in = StrReplace(GetQueueStr(com2RXQueue), Chr(13)&Chr(10), "")
i.e when getting data from Com2 RX queue. Queue size is 200 and task stack is 300

Ben
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:Does a task stack need to be bigger than the Com Queue size if its using it in the task?
No. The two are independent allocations.
sturgessb wrote:On further investigation, again the problem (this time the restart) is only occuring when running the following line...
It could be that incorrect code is being generated due to the nested calls. We'll look into that. In the mean time, you can see if the situation improves if you write it as two statements, e.g.

Code: Select all

GPS_in = GetQueueStr(com2RXQueue)
GPS_in = StrReplace(GPS_in, Chr(13)&Chr(10), "")
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

No difference I'm afraid. Still rebooting every few seconds.

Any time I read that queuestr. Very odd.

However, if I change GPS_in to a boundedstring(200) it seems ok. Well it hasnt rebooted in the last 4 minutes, so im guessing its ok. Why would that be?
Last edited by sturgessb on 15 March 2009, 12:03 PM, edited 1 time in total.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:No difference I'm afraid. Still rebooting every few seconds. Any time i read that queuestr.
The fact that it works better using a BoundedString suggests that there is an issue related to allocated strings. The next step is to ascertain whether the problem lies with GetQueueStr() or StrReplace(). What happens if the line with StrReplace() is commented out?
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

With bounded string it did eventually restart about 10 mins in.

Trying now with bounded string and also removing the StrReplace....
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Seems stable without the StrReplace, running for 10 mins with no reboot yet...

I've reworked the code so i dont need the StrReplace, but I would like to know what causing all these issues so i can avoid in future. any ideas?
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:I've reworked the code so i dont need the StrReplace, but I would like to know what causing all these issues so i can avoid in future. any ideas?
As yet, no idea what is causing the problem. Until we can get a test case that reliably reproduces the problem we won't make much progress. Can you give me an idea of what you think the test case would look like?

What are the version numbers of the compiler and ZX Library that you're using?
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

compiler v2.6.9
spamiam
Posts: 739
Joined: 13 November 2005, 6:39 AM

Post by spamiam »

While you sort out the problem with the rebooting, maybe you can work on a different strategy to parsing your incoming data.

Since each GPS sentence stats with a "$", in your receive task you could pull data off the incoming queue until you hit a "$" at that point the previously recorded data must be a whole sentence, and you can transfer that string somewhere else and set a flag indicating the data is ready.

If you need to combine 2 sentences together, then you can buffer the first sentence until you get the second sentence, then combine them.

-Tony
Post Reply