LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Best practice for communicating with motion controller that has a different termination character for writes and reads?

Solved!
Go to solution

Besides "don't use that motion controller". I'm kind of stuck with it sadly. A person before me bought them and they're sufficiently fancy that buying new ones is pretty cost prohibitive. The device has an RS232 interface, expects ASCII commands, uses no flow control, and has multiple nodes that are controlled by the one RS232 port. The expected command structure is as follows:

 

Writes:

[Node Number]  Command  [Argument]  CR

 

Reads:

Response  CR  LF

 

There are a couple of ways I can see how to handle this, but I'm wondering what the best practice is here. Especially because the final program will probably do tens of millions of commands through the next couple of years, so even a small speed boost should save me quite a bit of IRL time.

 

Option 1:

Because the command structure has all of the relevant info before the carriage return on the response command, I can simply do a standard write-read way more bytes than I expect with CR termination character-clear buffer to throw away the LF. This is probably the simplest option code wise, but it feels very hacky and I'm unsure of how fast it'll run in practice.

 

Option 2:

Don't use termination characters on reads. Instead, do a write-while loop-wait-check bytes at port-read bytes available-check for lf-end loop if lf is there-store in shift register if not-repeat- contenate strings after loop terminates-output result. I don't like this because it uses the bytes at port node I've only heard bad things about, and while I have a decent idea of what the pseudocode for this would look like, I don't have a full mental picture of what the program would actually be in labview. Plus, I kind of have trouble believing that this would actually be faster than simply clearing the buffer given how many more operations it involves/I'm realistically going to wait more time than you actually need to in between iterations.

 

Or is there something I'm just missing and there's an even better way to do this?

 

And as a semi related question, what's the consensus on setting the end mode for writes/reads to termination characters during port configuration? It seems like activating it would save me a little bit of coding time, but if there are compelling reasons to not use it I'd like to hear them.

Message 1 of 7
(2,127 Views)
Solution
Accepted by topic author rbercaw

Hi rbercaw,

Kudos for a well written question and including all the pertinent details. You can use the "VISA Configure Serial Port" function and wire in the termination character used for read operations (CRLF or just LF). This input only applies to read operations, no flushing will be needed. When you write to the device, make sure to append the character that the device expects at the end (CR).

 

I think your device has a well defined interface, so you should definitely use a single VISA read and wait for the termination character. Checking the bytes at a port is a hack that sometimes must be done for worse-behaving devices.

Message 2 of 7
(2,122 Views)

Gregory,

 

Thank you. I'll write some test code after lunch and see if everything works as expected.

0 Kudos
Message 3 of 7
(2,102 Views)

@rbercaw wrote:

And as a semi related question, what's the consensus on setting the end mode for writes/reads to termination characters during port configuration? It seems like activating it would save me a little bit of coding time, but if there are compelling reasons to not use it I'd like to hear them.


In regards to the end mode for writes:

I used to not really care if you used it or not.  But in this case, you actually have two different termination characters.  Therefore, you should definitely turn the termination character on a write off.  But after messing around with other things, I discovered an issue (a major one to me) where that setting is only valid for serial ports.  When I am trying to create a driver that will work with Serial, GPIB, Ethernet, or USB, that is a problem.  The other issue is there are many instruments that want to see two termination characters.  This setting only works on one character.  So I am now on the side that appears the majority are on: don't bother with that setting and just create a VI that you can reuse that appends the termination character(s) and writes the command.

 

In regards to the end mode for reads:

You should DEFINITELY be using the termination character when dealing with an ASCII formatted communication scheme.  It is the only real way to ensure you got the complete message.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 4 of 7
(2,088 Views)

[Oops, a little late by the time I finished.  Mostly redundant, but not quite completely.  Initial post below.]

--------------------------------------------------

 

My first thought:

 

Option 3:

Call VISA Configure Serial Port, enable termination character and designate it to be linefeed (hex 0A, decimal 10).  As Gregory stated, this will only apply to reads.

 

When you do a read, request a large # of bytes.  The call will return as soon as it gets the first term char (linefeed).  I'd probably then call the string function "Trim Whitespace" to lop off the trailing CR-LF.

 

For writes, I would make a very simple wrapper function around VISA Write.  All it would do is append a CR character to the input string and send the result to the native VISA Write.  At any point in development, you can search for all instances of VISA Write and make sure you didn't accidentally use it directly anywhere else.  You should only have the one instance inside your wrapper function.

 

Thinking a little further, you could take this protection a step further and build up your motor controller interactions into a .lvlib library (or maybe a class, but that might be overkill).  Then you can define a controlled public API that's supplemented by private functions that can't be called from the main app.

   The wrapper function for Write would probably be a private function, used by public functions like "Set Distance", "Start", "Stop", etc.  You might consider holding onto the VISA resource as private state data rather passing it in by wire in the public API functions.  That'll reduce the temptation to use it directly and bypass the API you made.

 

    I'll often use "VISA Find Resource" as a first step in doing auto-discovery of the COM port assignment or GPIB address of a connected device.  Then I'll loop over the results until my attempted query-response to the device lets me identify it.   This kind of approach goes together nicely with an API that has no wiring terminal for the VISA resource.

    It *can* take some extra time at startup, but it's proven to be pretty immune to people swapping out USB-to-serial converters and suchlike.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 5 of 7
(2,084 Views)

@Kevin_Price wrote:

You might consider holding onto the VISA resource as private state data rather passing it in by wire in the public API functions.  That'll reduce the temptation to use it directly and bypass the API you made.


That is the main argument to make it a class.  And then if you need to control more than 1, well, you have different instances to handle each motor.

Spoiler
I have spent WAY too much time the last couple of years developing a Hardware Abstraction Layer.

GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 6 of 7
(2,065 Views)

I kind of forgot that I posted this topic to be honest, but all the advice worked like a charm. Thanks again!

0 Kudos
Message 7 of 7
(1,994 Views)