Jump to content

Serial read until CR/LF combo


Aaron L

Recommended Posts

Okay, I just don't know the right search term to figure out what should be amazingly easy. :headbang:

All I want to do is wait until I receive a CR/LF combo from a serial port, 9600/8/N/1, then execute the rest of my code. I looked at the example codes built into LV 8.5 to no avail. They have reads, simple and complex, but all of them time out rather than stopping on my CR/LF character combo. Really, all I need is the LF character. It can't be this difficult, right?

I'm receiving a simple string from a photometer that ends in a CR/LF. I've tried setting the Enable termination, setting Status, but to no avail. I know what the length of the string is and have terminated on that, but if something goes wrong in the transmission, I don't want to get out of sync by just counting characters. It's important that I catch the LF character and halt on that, as this is a 6 hour operation. I can tollerate one bad message but the system can't tollerate getting out of synch.

Thanks!

Link to comment

QUOTE(Aaron L @ Mar 5 2008, 07:21 PM)

All I want to do is wait until I receive a CR/LF combo from a serial port, 9600/8/N/1, then execute the rest of my code. I looked at the example codes built into LV 8.5 to no avail. They have reads, simple and complex, but all of them time out rather than stopping on my CR/LF character combo. Really, all I need is the LF character. It can't be this difficult, right?

Years ago I had to do this and wound up reading the serial port then buffering the string. I've not looked to see if there are newer tools that can do this, but I'm suspicious that's what you're going to be doing.

Link to comment

QUOTE(Phillip Brooks @ Mar 6 2008, 01:11 PM)

Why not just do this?

http://lavag.org/old_files/monthly_03_2008/post-3076-1204806507.png' target="_blank">post-3076-1204806507.png?width=400

"10" is the ASCII value for Linefeed.

You can also set the termination condition seperately for both in and out directions (Bottom enums). These are found under the "Serial Settings" for the Serial Instr reference type. All others are found under "Message Based Settings".

Shane

Link to comment

QUOTE(shoneill @ Mar 6 2008, 07:30 AM)

Why not just do this?

http://lavag.org/old_files/monthly_03_2008/post-3076-1204806507.png' target="_blank">post-3076-1204806507.png?width=400

"10" is the ASCII value for Linefeed.

You can also set the termination condition seperately for both in and out directions (Bottom enums). These are found under the "Serial Settings" for the Serial Instr reference type. All others are found under "Message Based Settings".

Shane

I'd go with Shane recomendation shown above IF you be sure that "LF" never appears in your data stream. If LF is a valid character (aprt from the termination sequence) then I have cracked that nut by reading all bytes at port and buffering them in a SR. Afeter each read from the port, parse the buffered data for a frame that starts with CR/LF and ends with CR/LF. Toss anything that comes before the first cr/LF and decode what in-between for your data.

Ben

Link to comment

QUOTE(neB @ Mar 6 2008, 02:36 PM)

I'd go with Shane recomendation shown above IF you be sure that "LF" never appears in your data stream. If LF is a valid character (aprt from the termination sequence) then I have cracked that nut by reading all bytes at port and buffering them in a SR. Afeter each read from the port, parse the buffered data for a frame that starts with CR/LF and ends with CR/LF. Toss anything that comes before the first cr/LF and decode what in-between for your data.

Ben

True, True. It would of course be required to check and received string for a proper \cr\lf combination, otherwise buffer until both are found......

I personally prefer the half-half approach of leaving the buffering to the OS and just taking string by string (or sub-string by sub-string if some buffering is required). Generally though, any element of a termination character should NOT be present in the transmission data. It's just good design. OTOH, much in life is simply beyond our control..... :(

Shane

Link to comment

QUOTE(ASTDan @ Mar 6 2008, 05:19 PM)

Dan,

slightly off topic here, but How do you get them to work? I've tried them in the past, but I can NOT get them to work......

On the other hand, isn't this basically what the VISA read does in the background with "ASRLEndIn" set to "TermChar" ?

You're also not guaranteed that the string read at this time is only up to the TermChar. Timing effects (especially at hugh Baud) mean you still have to deal with reading more characters than you want and buffering and so on.....

Shane.

Link to comment

QUOTE(ASTDan @ Mar 6 2008, 08:19 AM)

Dan,

I was able to take your example and get it to work. This is the first code that seems to do what I want. I'll have to try it at full speed to see how it handles things. Attached is a VI with the basic program.

Thanks!

Link to comment

QUOTE(shoneill @ Mar 6 2008, 04:30 AM)

Why not just do this?

http://lavag.org/old_files/monthly_03_2008/post-3076-1204806507.png' target="_blank">post-3076-1204806507.png?width=400

"10" is the ASCII value for Linefeed.

You can also set the termination condition seperately for both in and out directions (Bottom enums). These are found under the "Serial Settings" for the Serial Instr reference type. All others are found under "Message Based Settings".

Shane

Shane,

I built up the code you suggested but the system still doesn't halt on a LF character, it only passes right through to the VISA read. Perhaps I'm missing something? I've attached a pic of the code and attached the code itself. I believe this is likely a more proper way to do this than event driven action, but I have yet to crack this one. Any suggestions?

Link to comment
QUOTE(shoneill @ Mar 6 2008, 12:39 PM)
I don't know how I got them to work. You might want to try setting the TermChar to True in the Init VISA. This enables VISA to be able to recognize TermChar. Also the default is LF to change to CR do the following. There are also some other interesting events that my be applicable i.e. Serial break 0xA is the hex equivalent of a linefeed character (\n). Change the termination char to 0xD for message strings that terminate with a carriage return (\r). On the other hand, isn't this basically what the VISA read does in the background with "ASRLEndIn" set to "TermChar" ?Events allow VISA to trigger a Read. The "ASRLEndIn" set to "TermChar" tells VISA where to stop reading.I would aggree you may have to do some buffering on a high baud serial comunication.What I like about Events is I can trigger my read on something usefull. Not just reading whatever is on the serial port every x seconds. This can save parsing headaches.My $0.02DanQUOTE(Aaron L @ Mar 6 2008, 02:11 PM)

Dan,I was able to take your example and get it to work. This is the first code that seems to do what I want. I'll have to try it at full speed to see how it handles things. Attached is a VI with the basic program.Thanks!

You don't need that wait before enabling the event. When you create the event that is telling VISA to wait until it sees a Term Char on the serial port.Dan

Link to comment

@Dan

Thanks for the reply. IIRC I never actually tried setting the TermChar and ASRLEndIn AND using events. That's probably my problem.

@AAronL

Set the number of Bytes to read to the maximum you should ever receive. I typically set it to double my maximum packet size. The reason is that the VISA read will terminate whenever the number of bytes was read OR the termination character is received, whichever comes first. So we remove the limitation of our Nr. of Bytes by telling it to read s silly amount of data. Then it will quit when it receives the LF Character. Of course, don't set the Nr of characters to read TOO high, otherwise you'll be risking locking up your program......

Also, set the termchar options immediately after opening the port, before the wait. Otherwise it'll miss the first X events.

This actually seems to be a downside of my approach. With user-controlled Buffering, blocked programs can be avoided nicely. Is there a way to trigger an event on the serial port? Preferebly without OS calls? I suppose a break might do it, huh?

Shane.

Link to comment

QUOTE(shoneill @ Mar 6 2008, 11:56 AM)

@Dan

Thanks for the reply. IIRC I never actually tried setting the TermChar and ASRLEndIn AND using events. That's probably my problem.

@AAronL

Set the number of Bytes to read to the maximum you should ever receive. I typically set it to double my maximum packet size. The reason is that the VISA read will terminate whenever the number of bytes was read OR the termination character is received, whichever comes first. So we remove the limitation of our Nr. of Bytes by telling it to read s silly amount of data. Then it will quit when it receives the LF Character. Of course, don't set the Nr of characters to read TOO high, otherwise you'll be risking locking up your program......

Also, set the termchar options immediately after opening the port, before the wait. Otherwise it'll miss the first X events.

This actually seems to be a downside of my approach. With user-controlled Buffering, blocked programs can be avoided nicely. Is there a way to trigger an event on the serial port? Preferebly without OS calls? I suppose a break might do it, huh?

Shane.

Shane,

Great, that worked! Thank you. It's attached in this post so when people like myself need to find the solution to this problem, there are multiple available here. I'll go with this method for my application.

Aaron

Link to comment

Here's the ultimate version that writes a command out, reads back the data:

OK00, AAA45.678<CR><LF>

And is immediately ready with another command. The VI ping pongs very well. The loop doesn't have to wait an arbitrary hold time, so it's ready as soon as the <LF> is received.

Thanks all for your help and I hope this helps someone in the future.

Link to comment

QUOTE(Aaron L @ Mar 7 2008, 12:29 AM)

Here's the ultimate version that writes a command out, reads back the data:

OK00, AAA45.678<CR><LF>

And is immediately ready with another command. The VI ping pongs very well. The loop doesn't have to wait an arbitrary hold time, so it's ready as soon as the <LF> is received.

Thanks all for your help and I hope this helps someone in the future.

Aaron,

The setting of the TermChar settings should be done only once immediately after you open a reference to the serial port. There's no need to call it in every loop. It might even have detrimental effects.

Shane.

PS Glad to be of help.

Link to comment
  • 3 weeks later...

QUOTE (shoneill @ Mar 7 2008, 02:27 AM)

The setting of the TermChar settings should be done only once immediately after you open a reference to the serial port. There's no need to call it in every loop. It might even have detrimental effects.

Shane,

Interestingly enough, when you take out the TermChar from the Instr, the system does not respond immediately, but waits for the time out period to happen from the VISA serial origination. I'm not sure why this happens. The setup still works, but the communication rate is limited to whatever the time out period is.

Thanks!

Aaron

Link to comment

QUOTE (Aaron L @ Mar 27 2008, 07:50 PM)

Shane,

Interestingly enough, when you take out the TermChar from the Instr, the system does not respond immediately, but waits for the time out period to happen from the VISA serial origination. I'm not sure why this happens. The setup still works, but the communication rate is limited to whatever the time out period is.

Thanks!

Aaron

What do you mean with "take out the TermChar"? If you don't set the option at all, then it's expected that the Read will wait until timeout. This is because we're telling it to read too many bytes, which it can't do. Hence the timeout. The TermChar option simply gives the Read an earlier Termination option.

A Read has three main options for termination:

TermChar

Timeout

Bytes to read

In order to make sure we stop at the "Termchar", we need to set this as a termination option. Otherwise the other two remain active, and by setting the "Bytes to Read "too high, the Timeout becomes the only real termination option left. If you lower the "Bytes to Read" (without TermChar) then at some stage (Length of your received message) the "Bytes to Read" termination option will prevail and the timeout will become irrelevant. A Read always stops when the FIRST termination option is fulfilled.

For giggles, set the Timeout to -1, no "TermChar" and a huge "Bytes to Read" and you've got a VI which hangs. By doing this you've effectively removed any termination option available. There's always the otion of a Reboot :throwpc:

Shane.

Link to comment
  • 7 years later...

I posted an idea on the NI forums about a year ago that is long overdue; the ability to define a regex for VISA message termination.

 

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Add-regex-based-termination-string-option-to-NI-VISA/idi-p/2859152

 

I had the idea after tinkering with a .NET library called SSH.NET. One of the methods of a stream is Expect.

 

http://forums.ni.com/t5/LabVIEW/Plink-PuTTY-works-30-of-the-time-using-System-Exec-vi/m-p/3006795#M860452

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.