LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple VISA serial port I/O architecture design

Hello again all you helpful forum-goers!

 

I am trying to rewrite my application's serial communication routine to be more efficient / simple, and I'm hoping to tap into the collective knowledge and experience of you the LabVIEW community to do so.  Smiley Happy

 

I need to read and write on multiple VISA serial ports in parallel, sometimes with a command/response pattern, and sometimes streaming a file of text.

 

Launching Multiple Instances of a Parallel Port Monitoring VI:

I currently launch 4 instances of my re-entrant serial port IO VIs via a for loop involving a static VI reference, getting that VI's path, a re-entrant Open VI Reference call, a Ctrl Val.Set call to load an index number into the local variable of that instance of that VI, and then a Run VI invoke method with Wait Until Done and Auto Dispose Ref false (see attachment snapshot).  I close those VI references when my application is exiting.  Is there an easier way to launch multiple copies of the same VI asynchronously and give them different ports to monitor?

 

VISA Reads, Writes, etc.:

Inside my COM Port IO VI I have a timed loop that runs every 10ms (the app that I am talking to executes a control frame every 20ms).  It reads a global array of available system port serial IDs and selects the one it will be using via the index number provided when it was launched.  The code is too messy to post here, but basically it flushes the I/O Buffer when it starts up, then reads the number of Bytes at Port and stores it in the input buffer, then writes any outgoing text in the output buffer.

 

I/O Buffers:

Right now the code uses global variables for the input and output buffers, which I know is the wrong answer for multiple reasons.  It has enough extra tracking logic and such that it works with no race conditions or data loss as far as I am aware, but I'd rather use a better solution.  When I look up communication between parallel loops, it looks like the standard answer is to use a queue.  However, doing that will involve (on the VISA read side) reading however many characters have come in on the port and posting those in the queue, and then on the consumer side popping all of the queue elements and concatenating those string fragments together into the entirety of the text that has come in on the port.  Is there a way to put character chunks into a buffer of some sort on the producer side, and then have the consumer be able to read the entire text that is in the buffer at once?  I haven't been able to think of any.  Maybe running a quick loop on the consumer side to pop each element and concatenate them together isn't too much processing effort.

 

As far as sharing the queue, is there any merit in creating the queue in the main VI and passing a reference to it in as part of the initial call to start my COM Port IO VI instances?  Or should I just open a reference in each VI separately, using the same queue name?  Any functional difference between those methods?

 

Message Interpretation / Decoding:

The serial communication is formatted and encoded for the most part, and I obviously want to hide those details from the majority of my application.  So there will be an additional layer above the raw stream of VISA data being read in my COM Port IO VI, so that the top-level logic can for example just ask if a particular message has been received without worrying about those details.  Is there any benefit or cost in that being a separate VI vs. a separate loop in my COM Port IO VI?  Seems like either would work really.

 

Thank you for reading this far!  I know these are relatively open-ended questions, but any suggestions or advice would be appreciated, as would any links to examples or information on VISA read/write buffering and communication between loops, or multiple asynchronous VI launching and/or communication with the resulting instances.

 

Thanks again,

 

-Joe

0 Kudos
Message 1 of 3
(4,135 Views)

Let's see if I can get at least some of the answers.

 


@jmorris wrote:
Is there an easier way to launch multiple copies of the same VI asynchronously and give them different ports to monitor?

In 2011 NI added the asynchronous call by reference node which allows you to use the connector pane to do this. There should be examples in the example finder (Help>>Find Examples). If I remember correctly you will also have to make your static reference strict by right clicking it.

 


I/O Buffers:

Right now the code uses global variables for the input and output buffers, which I know is the wrong answer for multiple reasons.  It has enough extra tracking logic and such that it works with no race conditions or data loss as far as I am aware, but I'd rather use a better solution. 


You really should. If you have multiple writers to the globals, you most likely have race conditions even if you're not aware of them. I would also suggest just passing the VISA resource directly into the subVI.

 

A queue sounds reasonable for this (I wouldn't be concerned about the performance), but you should make sure that you're not mixing data from different ports into the same queue, at least not before it's divided into distinct pieces.

 

The main functional difference in obtaining the queue reference in the main VI alone or in the subVIs as well would have to do with reference lifetime management. LV automatically cleans up references in every hierarchy which goes idle (a hierarchy is controlled by a top-level VI, which your dynamic VIs would be), but because in your case you're probably letting all the VIs live in parallel, that shouldn't matter (and it wouldn't matter anyway in this case, because the queue will live as long as there it at least one reference still open to it).

 

Another concern might be reuse - if you want to call the VI again and let it talk to another queue, then you need to provide the queue reference from outside. Personally, I would recommend that, because it would give you more flexibility.

 

 

 


Message Interpretation / Decoding:

The serial communication is formatted and encoded for the most part, and I obviously want to hide those details from the majority of my application.  So there will be an additional layer above the raw stream of VISA data being read in my COM Port IO VI, so that the top-level logic can for example just ask if a particular message has been received without worrying about those details.  Is there any benefit or cost in that being a separate VI vs. a separate loop in my COM Port IO VI?  Seems like either would work really.


Whichever is more convenient to you. Although I will say that a separate VI is probably safer in that you can have it get its data from other sources as well, such as your testing code.


___________________
Try to take over the world!
Message 2 of 3
(4,122 Views)

Thanks tst, always happy to see a response from you!

 

Regarding the async call by reference node, I am looking forward to trying it out.  All of my current experience is in LabVIEW 2010, but we just recently bought 2012, so my next update to my application is going to use that, and I can't wait to start finding some of the improvements in the last two versions!

 

Regarding multiple writers to the global I/O buffers, I don't, but they are ugly and should be replaced regardless.  And I agree about passing the VISA reference in; the less globals the better!  Smiley Wink

 

I figured I would make two queues per COM port: one for reading and one for writing.  And I agree passing them in seems like a more flexible and therefore elegant solution.

 

Separate VIs for message decoding it is!  It is definitely a benefit to make unit testing easier.  Maybe someday I'll have time to do some of that...  Smiley Embarassed

 

Thanks again for your feedback!  I am mostly the lone wolf on these projects, so I really appreciate getting an outside perspective to make sure I'm not overlooking something obvious, or re-inventing the flat tire.  Smiley Wink

 

-Joe

0 Kudos
Message 3 of 3
(4,091 Views)