LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to parse string that is slowly coming in through serial port?

Hi - I'm having trouble getting "scan from string" working. What I'm trying to do is read in a large amount of ASCII formatted data coming in over the serial port. Right now I'm just trying to read in GPS data in the NMEA 0183 format, but as soon as I get that working I'll have various other formats to add as well. So far I've gotten the serial interface working properly. I have it go in a constant loop appending all new characters to a string. This string is written out on screen. This all works perfectly, as far as I can tell. Now comes the hard part. I want to parse this data. For example, here's a string sent by the GPS: $GPGGA,161938,4007.0051,N,08813.3067,W,0,00,,,M,,M,,*4C I would like to read in all that data. I've done this in C without any problems, but I can't figure out how to do it with Labview (I only started using Labview a couple weeks ago - so I'm very new to this unfortunately). I tried adding in a "scan from string" function and giving it a format string of "GPGGA,%d" which to the best of my knowledge should be just a simple signed int. But I get this error message when running it: "Error 1 occurred at Scan From String (arg 1) in Serial Test.vi Possible reason(s): LabVIEW: An input parameter is invalid. For example if the input is a path, the path might contain a character not allowed by the OS such as ? or @. ========================= NI-488: Command requires GPIB Controller to be Controller in Charge." I'm guessing that perhaps the problem stems from the the function running every single iteration, instead of running only when a complete command has been received. But I could be wrong about this. So - can anybody tell me how to do what I'm trying to do? The way I wrote in in C was something like this: 1. wait till '$' character is seen, write $ as first character in string 2. append all incoming data to string till newline character is received. 3. Check if NMEA sentence starts with GPGGA (as that was the only sentence I've been using). If it does, go to step 4, otherwise go to step 1. 4. Run sscanf on sentence. Go to step 1. Is it possible to do this in labview somehow? Thanks! -Mike
Download All
0 Kudos
Message 1 of 7
(5,359 Views)
There are a few comments I would like to make on your code.
 
1.  You say you want the format string to be "GPGGA, %d", but in you screen snap shot it is "GPGGA, %2d"
2.  You list a 4 steps about waiting for the $sign to come in and appending until the new line character comes in, but the code doesn't show any of this.  It keeps appending new characters onto the "read buffer" string.  And it tries to perform the scan from string function on every iteration of the loop.  So if the string is incomplete, the function is returning errors.  You will want to use some case structures to only execute the scan from string function once the string is complete.
3.  I would recommend moving the serial config VI outside of the loop.  You only need to do this once and not on every iteration of the loop.
4.  I would recommend changing the feedback node to a shift register.  They are much easier to read and understand.  In your screenshot, the arrow is pointing opposite of the usual way of using feedback nodes, and it is also covering over some of the wires, so it is hard to know what is going on.
0 Kudos
Message 2 of 7
(5,350 Views)
Hi - I will address your points in the same order as you wrote them 🙂
 
1. That was a typo - though it shouldn't cause the code to crash
2. The 4 steps I reffered to were when I've written code with the same functionality in C - I am not sure if the same methodology would be proper in labview.
3. Good point - I'll take care of that.
4. I will try that. Could that have been causing my crash?
 
 
Lastly - my apologies for the formatting in my first post - it looked fine when I typed it out - but it got all smashed together unfortunately.
0 Kudos
Message 3 of 7
(5,347 Views)
1.  You're correct that it shouldn't cause the code to crash.  I just noticed it and experimented with it, and I found that it gave %2d gave different results than %d.
 
2.  The methodology you wrote should work in labview as well.  It is just a matter of setting up the code to match what you want to do.  I think the code shown in the screen shot is causing the problem.  I found that I don't get error 1, but I do get error 85 if the amount of text in the input string hasn't met up with what is specified in the format string.  So if the format string is "GPGGA,%d" but only "GP" has arrived in the input string, error 85 pops up saying the input string does not contain the data in the expected format.  I certainly think this could be happening since you are reading in from the serial buffer 1 byte at a time and executing the scan from string at each iteration.  I am attaching the VI I created to experiment with your input and format strings.
 
4.  I don't think the feedback node is the cause of your problem.  I had a hard time reading the way the feed back node was drawn on the block diagram.  But assuming it was setup properly, it would be okay.  Feeback nodes and shift registers should functionally be the same.  But I think you would find out from most contributors to the forum that a shift register is much preferred over a feedback node for readability.
 
Your thread title says "parse string that is slowly coming in through serial port".  Why is it coming in slowly?  How slow is it coming in?
Why not read all of the bytes available at the port rather than 1 of a time?  I would suggest looking at the Basic Serial Read and Write Example VI found in example finder and model the read portion after that.  Only execute the read if the "bytes at port" is greater than 0.  If it is greater than 0, read all the bytes available and append them to your buffer.  Once you detect the end of line character is in your buffer, then exit the loop and perform your scan from string.  If you need to repeat, clear your buffer up to the end of line character, and let the remainder of the buffer be your initialization to the shift register for the next time you enter the while loop.
0 Kudos
Message 4 of 7
(5,334 Views)
Hi - thanks for following up - I really appreciate it.
 
I will switch over to a shift register. I agree that the way it's shown with the feedback is confusing. I just wasn't aware that that route was available.
 
As far as speed of data - it's coming in right now at 9600 baud in large chunks of varying length. Data is streamed out from the device with DMA so it comes without any break between bytes. Most chunks are about 200 or less bytes long. Right now I'm sending just 1 packet a second, with some other random packets being sent out non-periodically as reactions to specific conditions. I guess I set it to read only 1 byte at a time because of the varying packet length. Do you think this is the proper way to do it?
 
I did look at that example VI when I was making my own but I will look further to see how exactly the read functionality worked. I will also take a look at your VI when I'm in the lab tomorrow (I don't have LabView on the computer I'm presently on).
 
Thanks!
 
-Mike
0 Kudos
Message 5 of 7
(5,328 Views)
Hi - to follow up to my previous post - I finally had time to get into the lab today and do battle with this. I have come up with a working configuration! I have two shift registers - one which I use just to hold all data read in, and the other to hold only the most recent line sent. I wait for the specific string that I want ("$GPGGA") and then go into a case structure where it will run. I've run into one minor problem, however. In these senteces specific values will not be written. For example:
 
$GPGGA,181359,4007.0051,N,08813.3067,W,0,00,,,M,,M,,*4F
 
Note where there are a couple commas together near the end. There sometimes will be values in those places, and sometimes not. If I have a format string that says there will be a number there and there's only the two commas, labview gives me that error. Is there any way for it to just skip onto the next value? My only idea is to use the "search and replace string" function to replace all instances of ",," with ",0,". Are there any better ways to do this?
 
Also - this is starting to diverge from the original topic of this thread - but I figure I might as well not clutter the board up with lots of threads... The last two characters in the NMEA string are a checksum, which is just the XOR of all the previous bytes in the string. How would I compute the checksum with labview? I'm thinking maybe I should do it as the bytes come in. Or is there a better way?
 
Thanks!
 
-Mike
0 Kudos
Message 6 of 7
(5,299 Views)
I think  your best option would be to replace ,, with ,0,  assuming of course that no value means zero and that it won't confuse any thing you do with these values later on.  If anyone has a better idea, please chime in.
 
I think you will need to do the XOR function on the incoming string byte by byte.  Just be careful to reset your shift register at the start of each line to ASCII value 0 and to stop and give the results at the end of the string.  You don't want to character the XOR result from a previous line into a newly input line.  Remember to use the string to byte array functions to convert the character to something that can be put into XOR, and the byte array to string after the XOR to get it back out if necessary for comparisons.
 
One question you may want to ask is how you will handle any errors in the event the checksum's don't match.  Perhaps a dialog box that shows the incoming string and its incoming checksum as well as the calculated checksum?  Or just an indicator on the screen that clears if there are no errors.  If you do a dialog box, depending on how frequently you get errors, you could be constantly clicking OK buttons to get the program to continue just to have another pop up.  I had this problem when a noisy AC motor drive caused errors in a serial line I was trying to get data off of.
 
 
0 Kudos
Message 7 of 7
(5,295 Views)