LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Dr. Damien's Development - Running Top Level VIs IV - A Tale of Two Servers

A server is a VI with no visible GUI, running top–level, that is used to process commands and store data. Communication with the server is typically handled with queues or user events, but notifiers, rendezvous, and other "signalling" communication protocols may also be used. The communication protocol should have some sort of blocking mechanism so your server does not have to poll for the next command. Any one server is not limited to a single protocol, either. I typically use both queues and user events, as in the examples below.

 

A server contains data and methods — sounds like an object. So I wrote a server as a LabVIEW object, attempting to make it easy to derive new server classes from it. See the example below. Unfortunately, to derive a new server from this object, you need to rewrite almost the entire thing, making the fact that it is an object almost useless. The basics of server design are there, however. Open ServerCore.vi in SimpleServer.lvclass (inside SimpleServer.zip). The object references are present solely to support dynamic switching of the VI. Queue and event inputs are used for communication.

 

Opening the block diagram shows a simple task handler (top loop) and a bare event structure used only to signal and exit. Since this was meant to be a template, it only exits. It supports two modes of exit — an Exit command and an exit user event. The former is used when the server is to be specifically shut down. The latter is used as part of the shutdown sequence for a large set of freely running VIs. An example would be a main application with a string server for localization, error server for error handling, and multiple non–modal windows/dialogs which may or many not be up at exit time. User events make a good non–lossy broadcast mechanism (unlike notifiers, which are lossy). Both the event structure and the command loop contain code to exit the other structure in the event of receiving and exit command/event.

 

You can test this server using the test VI bundled with it. So why is there another example? Under use, there are a few problems with this object–oriented approach.

 

  1. Notice that there is a wrapper VI called Server.vi. This VI is not dynamically dispatched. This is necessary to allow the VI to be called dynamically — something required of a server.
  2. The commandQ and responseQ controls are strict typedefs. As such, Server.vi would need to change for an actual application to account for these changes. But it cannot since it is not dynamically dispatched.
  3. The queue references cannot be be part of the object for newer versions of LabVIEW than the 8.2.1 I wrote this object in. This produces a circular reference which breaks the object.

 

Using this template to create a new server by deriving it from the original object just will not work. The whole server could be refactored to make it work, but is it worth the effort? I thought not, so looked at creating a simple template based on a single–element queue data object. The result is in the ServerTemplate.lvlib attached below. Note that the core code is still there and operates the same way. However, the data is now a safe global, so can be updated asynchronously. Making a new server is as easy as copying the code to a new location and adding functionality. Next time, I will demonstrate this with a string server used for localization. Until then, happy holidays!

 

Previous Installments

Download All
Message 1 of 37
(8,097 Views)

That sounds like you have creaed an "active object" (one that once created stick around and does stuff on it own while also serving method invokation) !

 

Nice.

 

I had to invent that pattern myself and the lack of support for "vit's" in a class bit me when I tried as an exe.

 

I have some time off next week and will try your code (if it is LV 8.5 or below) and will share my notes comparing your approach and mine.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 2 of 37
(8,070 Views)
The code is in LabVIEW 8.2.1.  Should have mentioned that.  I try to post in the lowest supported version of LabVIEW, unless I need a new feature.
0 Kudos
Message 3 of 37
(8,037 Views)

DFGray wrote:
The code is in LabVIEW 8.2.1.  Should have mentioned that.  I try to post in the lowest supported version of LabVIEW, unless I need a new feature.

 

Cool!

 

I just sent an e-mail to my wife asking her to nag me about the follow-thru on this one while I am off, I guess I should get a case a beer while I am at it. Smiley Happy

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 4 of 37
(7,998 Views)

Thank you for this very valuable post.

 

I was using the same design succesfully in a mission critical task some years ago (the main difference was: I didn't use OOP but an AE to keep the queues).

 

Here are the lessons learned:

The server is a continous running program in parallel to the main program. As the class developer (let's use these OO terms for this), you want to hide the parallelism of your server app from the class user (maybe a less experienced programer, at least someone who does not want/need to take care about your server code). All you need to provide is a set of vi's/methods, of which the 'Launch' needs to be executed in the beginning and the 'Exit' in the end of the main program. This design pattern provides an excellent encapsulation, and therefore an easy to use API for your server apps.

 

Concerning the LVOOP design problems, the Server.vi (see 1. on post#1) cries for a way to have an abstract class/method declaration (forcing the class developer to overwrite the method for the concrete implementation). There even could be a private method 'launch server vi' which only requires the VI path or refnum (preferable because of strict conpane type) in order to maximize reusability. But I'm still to new to LVOOP to get all the implications of these design concepts.

 

I want to finish with a question: Damien, can you please go into more details on (3. queue ref/circular ref)?

 

Felix

0 Kudos
Message 5 of 37
(7,940 Views)

F. Schubert wrote:

...

 

I want to finish with a question: Damien, can you please go into more details on (3. queue ref/circular ref)?

 

Felix


That sorta matches with something I tried early on.

 

Say i have a class used by my server called Server_Class.

 

Inside Server_Class I could store queue refs that server uses to accept method request and posibly return the results of those methods.

 

Those queues inside Server_Class can not be of type "Server_Class" otherwise updting the Server-Class data results in the queue being updated and if the queues is updated then the class data "Server_Class needs updated...

 

I got around this by flatening to a string to push it thru the queu and unflatten on the other side.

 

I hope this helps and is not another one of my "what the hEL$ is he talking about now!" posts. Smiley Wink

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 6 of 37
(7,930 Views)

Thanks Ben, I got it.

Still I need to breed over the implications. Is true for all by-ref types as they can hold a ref to the 'class data' (that is an object, isn't it?)?

 

Felix

0 Kudos
Message 7 of 37
(7,924 Views)
When I ran into this issue before, I solved it by moving the queue refs outside the object and encapsulating the whole thing into a library.  It was an unsatisfying solution, however, since the namespacing gets long and the development code had two layers that looked somewhat redundant.  I am still looking for a good design pattern that works for this kind of thing (and probably should be using a newer version of LabVIEW).  As Felix said, this situation is almost the classic object-oriented paradigm.
0 Kudos
Message 8 of 37
(7,885 Views)

Thanks Dr.Damien,

 

Excellent post and thanks for the example.

 

I'll be exploring this during the cold winter months.  It's always good to expand our knowledge of LabVIEW.

 

Merry Christmas & Happy New Year!  

Season's Greetings.

 

🙂

 

RayR

0 Kudos
Message 9 of 37
(7,876 Views)

Like I said I'd look into this, BUT before I let myself cheat by looking at the posted code I forced myself to do one of my own*.

 

In the proces I ran into bit of a problem that may be another manifestation of Dr. Damien's point #3.

 

Here is my personal challange

Create a generic Active Object Class that had all of the functions required to manage and interact with an unknown number and clients.

 

1) For the time being a Tester.VI executes an Open operation (method).

Tester.PNG 

 

2) The Open Launches a template as shown below. Note: Setting the "Class" control using the method "Ctrl Val.Set" lets me choose the personality of the

server I am creating.

 

Launch_Template.PNG

 

3) The template itself is is a simple and (latter hopefully) robust generic server that once intitalized, performs some function and responds to commands (methods) invoked by one or more clients. Since it only uses Dynamic dispatched VIs, Children of this class will be able to over-ride any or all of the states as required.

 

Template.PNG

 

Challenge!

 

Create a set of queues that allow two process to communicate with out knowing the connection at development time.

 

I wanted two queues, one to send commands (methods, like Start Stop Pause...) and another to reports status and respond to commands (methods like Paused, Running, Error_Exit) as well as return responses from commands. The other thing I wanted to support was to have multiple clients supported by the Server so that I could develop Server Classes (childern of what I am working on) that could serve a serial DAQ device (I use a design based on Bruce Chubb's design from the late 70's).

 

This presented a little bit of a challenge. Unlike the Command queue which would be emptied by a single VI (in this case the Template), the multiple

clients should each have their own Response Queue so the right reply gets back to the person (client) who asked.

 

 

This post will be continued in the next post

 

Ben

 

* While on vacation I also commeted to starting the re-write of my model railroad using LVOOP. I figured the work would be an excellent way to increase

my LVOOP skills etc. Since a model railraod has a lot of independent processes that share the same hardware resources but are indepenedent otherwise, a

generic "Active Object" class who's decendents inherited the ability to run as independent top-level VIs would be a nice start that I could latter use in

my work to do Data loggers, PID controls, etc.

 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 10 of 37
(7,439 Views)