Jump to content
hooovahh

Create FGV Wrappers

Recommended Posts

Nice Idea,  :beer_mug:

I always have the problem with connecting this enum and unbundling what needs to be used from cluster

In one project I ended making polymorphic wrapper in similar way You did and then unbundling what is needed inside wrppers.

It takes some time doing it one by one and they all look the same so it is bit confusing but if polymorphic vi can be scripted on top of that wrappers it will be nice :)

 

Edit: added polymorphic vi generation after

Edit2: if there could be easy way to do bundling/unbundling by scripting, not by hand it would be nice :D

fgv to polly.zip

Edited by pawhan11
  • Like 1

Share this post


Link to post
Share on other sites

Hmmmm. This got me thinking (always a problematic occurrence)

 

If we combined your scripting stuff with the ideas of OMeta we could create a Requirements Spec Translator  and convert specs directly to LabVIEW like they do in the CLA exams - make all the CLAs redundant :D

Share this post


Link to post
Share on other sites

Edit: added polymorphic vi generation after

Edit2: if there could be easy way to do bundling/unbundling by scripting, not by hand it would be nice :D

That is a fantastic addition.  As you can see from the disabled code on the right I was trying to make a unique icon for each wrapper because I didn't like that every VI had the same icon.  I didn't quite get it working so I gave up, but with a polymorphic VI you can see the VI Selector which tells you which instance it is using.

 

As for the cluster idea, yeah each VI that is made can have the cluster elements it actually uses be exposed on the palette of that unique value of the method.  So if you have a cluster with a path to load and a string to write, in your Init VI just have the path be on the front panel not the cluster, then in the VI bundle that into the cluster that goes into the FGV core VI.  In this way the Init VI only has the things that are important to it on the connector pane, and it makes it easier to understand how the user is supposed to use the API, rather than throwing a bunch of controls that will be ignored on the FP.

 

Using more scripting I think you could choose which data is important for each instance, or even detect it in some cases, but that would be a ton of work.  I'd suggest just doing that manually.

Share this post


Link to post
Share on other sites

So here is a fun little nugget I worked on over the weekend.  At our local user group there was discussions about action engines, and functional global variables.  People talked about how a Action Engine, that has several cases like, Init, Read, Write, Close, will have inputs and outputs that just aren't relevant to every method of that VI.  So people said how they some times write wrappers to their FGV where each VI is a unique value for their enum.  This allows them to delete the unneeded controls and indicators, making for an easier to understand API, where only the important inputs for that method are exposed.

I do this as well.  But I take it one step further and have it all inside of a library.  I then make the Action Engine and the enum controlling it private.  This makes it so that the API is nothing but the wrapper VIs.  It helps by keeping other people away from the AE and screwing something up.

 

I can't wait to look at your code here.  Sounds like something I could possibly use.

  • Like 1

Share this post


Link to post
Share on other sites

I then make the Action Engine and the enum controlling it private.  This makes it so that the API is nothing but the wrapper VIs.

Oh this is a good idea too.  I added code to create a library and add all the members.  This works just fine but I couldn't find a way to set the access scope through scripting.  Is there a method for that?

Share this post


Link to post
Share on other sites

Oh thank you, I was trying to perform the action on the Library item, not he library itself.

 

Attached is an updated version which now makes a library, adds the core, the polymorphic VI, and the polymorphic instances, and sets the core to private.  It should probably be put in a virtual folder for Public and Private, but I was just happy to get this working, feel free to improve on it.

Main Generate VIG Wrappers With Library 2014.zip

Share this post


Link to post
Share on other sites

I added a delete feature to your latest version that will delete the controls for each case if they are not wired inside the case structure of the FGV.  Its not perfect and I had to rename the initialization constant in the example FGV so it doesn't delete the input terminal (the constant had the same name).  Anyway thought I'd throw it out there.

Generate VIG Wrappers with Delete 2014.zip

Share this post


Link to post
Share on other sites

I added a delete feature to your latest version 

This is good, but I don't think it will work for everyone.  I've seen some cases where there is only one input and it is a cluster, and then it will unbundle that and only use some elements of it in each case.  I can't remember a time I've done that so your version is perfect for what I've done.  We could try to get crazy and look into unbundleing and seeing what elements are used in each case too.

Share this post


Link to post
Share on other sites

I haven't looked at the code, but there are also other ways of doing this. If you think about an FGV, it's essentially just a way of performing different actions on the same piece of data. Your code creates a wrapper to turn the actions into VIs. If you're doing that, you can also just pull out the data and get rid of the internal FGV entirely.

 

For example, the shared data could be a cluster (or an object) in a DVR. Each action simply takes the DVR and operates on the data, so the "increment num" action could look like this:

 

post-1431-0-60808800-1437553930.png

 

It starts with a call to the GET DVR VI (inlined into the caller here for simplification) and then does the action.

 

This allows you to get rid of the enum and the FGV VI itself and the need to match the API correctly. It might make debugging more difficult, because you no longer have a single VI you can go and probe to see what's happening.

 

Share this post


Link to post
Share on other sites

I see a FGV as a singleton class, which is very similar to what Yair suggests and thanks to GDS we can create a Singleton class within 5 minutes

File IO Action Engine_class.zip

File IO Action Engine_class 2012.zip

 

What I can't do in 5 minutes is fix the scripting up so it generates that for me but I imagine that it can't be too difficult from what hooovahh started off with :)

Edited by ThomasGutzler
  • Like 1

Share this post


Link to post
Share on other sites

For example, the shared data could be a cluster (or an object) in a DVR. Each action simply takes the DVR and operates on the data, so the "increment num" action could look like this:

Interesting, I never thought of doing it this way.  Now there are a few draw backs, as you mentioned first you don't have just some central core VI that you could probe to see how everything is doing and the last states executed.  There are also times when I have more than one shift register, so that would mean either more DVRs or more practically, a cluster of the things I want.  Oh and you'll have an extra step you need to remember to close the DVR reference where a VIG is fine to just go idle.

 

For me action engines are so damn convenient.  I can make one is literally seconds, okay I have a template for a read/write VIG as a starting point so maybe that's cheating but still.  Probing is simple, execution is simple, developers of all experience levels can understand it (as long as they understand the concept of a uninitialized shift register), and adding it to a library can have some level of access protection.  I'm not saying classes aren't a more elegant solution for the same problem.

 

Oh and I love scripting by the way.  Yesterday I spent most of the my day writing scripting code, that auto generates accessing VIs, messaging VIs, and type defs for a Web Service someone wrote.  It would have taken me probably all week to do it all by hand, and there would have been lots of errors.  Now when new code is written I run my script again and all the new VIs and controls are generated.

Share this post


Link to post
Share on other sites

It's all great but there needs to be thought about the pros and cons of doing this with polymorphic VIs and classes.The fallout is, that if you take the supplied example, you go from a single VI of 30kB so several VIs totaling ~180kB with no change in functionality. That's nearly a 6x increase in code size with a 7 fold increase in the number of VIs That's why applications take 10 hrs to compile :P

 

When I choose to use a polymorphic VI, I make that choice very carefully as a trade off between user friendliness (the menus, adapt to type and terminal reduction) and code complexity and size. As I've said before, classes and polymorphic VIs bloat code and cause replication. The worst use would be to effectively just move the enum list of an AE to a poly menu "because it looks better". The tradeoff is the increase of the number of VIs and code size in proportion to the number of items in the enum list with  consequences to performance, maintenance, compile times and understanding complexity with no change in function. The gain is a subjective aesthetic for a developer, not even an end user..

 

The best use is hiding controls unused for an  enum item and logical groupings of functions.That is not easy to achieve with automatic wizards as there is no context that can be gleaned from the VI itself. It is very easy to create huge quantities of code and complexity with wizards though.

 

Why, for example does the "Return Settings" need file terminals? How could we tell the wizard to not wire and create those terminals for that enum?

Edited by ShaunR

Share this post


Link to post
Share on other sites

Why, for example does the "Return Settings" need file terminals? How could we tell the wizard to not wire and create those terminals for that enum?

 

"Return Settings" doesn't need file terminals.  If you look at the code I added to delete terminals, I use a very rudimentary approach where I check to see if the case selector tunnels are wired to anything in the case structure and delete the controls with the same name as the tunnels that are unwired.  Its crude and probably not very robust at this point.  

 

I agree with you concerns about code bloat which is why I dislike polymorphic VIs.  Would there be a generic way to do this with an Xnode FGV wrapper that goes through similar operations as hoovahs script, but self creates its inputs and outputs based on the case (enum) you selected from the Xnodes menu item?  Would it be worth it?  Or do you just transfer the complexity to the scripting environment where the potential for mistakes (and code errors) is more likely and less transparent?

Share this post


Link to post
Share on other sites

"Return Settings" doesn't need file terminals.  If you look at the code I added to delete terminals, I use a very rudimentary approach where I check to see if the case selector tunnels are wired to anything in the case structure and delete the controls with the same name as the tunnels that are unwired.  Its crude and probably not very robust at this point.  

 

I agree with you concerns about code bloat which is why I dislike polymorphic VIs.  Would there be a generic way to do this with an Xnode FGV wrapper that goes through similar operations as hoovahs script, but self creates its inputs and outputs based on the case (enum) you selected from the Xnodes menu item?  Would it be worth it?  Or do you just transfer the complexity to the scripting environment where the potential for mistakes (and code errors) is more likely and less transparent?

 

Ah. I must have missed that (the deletion). The example just created one ove every enumeration with all controls when I tried it. There are a few directories of this in my temp directory now...lol. I must have opened a slightly older one. :shifty: I'll take another look to see how you defined that that terminal had to be deleted on that VI.

 

Polymorphic VIs are very useful. I wouldn't throw the baby out with the bathwater. The pros just have to outweigh the cons. Sometimes you don;t need to do a full factorial polymorphic VI if you are just grouping individual functions that already exist into an API. There is no explosion of code then. You ae just consolidating into a single VI for convenience and labeling. It's when you do adapt to type that things get out of hand as it is basically "Save As" then make a tiny change, rinse and repeat N times.

Edited by ShaunR

Share this post


Link to post
Share on other sites

@ShaunR

You make very good points, I think all of which I agree with (is that a first :D).  Bloat in the LabVIEW can be a very big problem, many massive class and libraries loading all members, and polymorphic VIs loading all members is an issue for sure.  In a post on my Variant Repository XNode I mentioned something to this affect, where the polymorphic version has a couple hundred VIs in a couple polymorphic VIs.

 

I certainly wouldn't use this wrapper code for every FGV in my code, it would add unneeded bloat with little (in any) benefit.  But there are times when it can make an API easier for the developer to use and understand, by breaking up the possible many functions of an action engine, into easier to understand chunks.  Like you said, pros and cons, like with many design choices in software.

Share this post


Link to post
Share on other sites

I kinda like manually adding in the Action Engine wrappers (which I do religiously for FGVs and Action Engines). I create them one at a time and test them out as I flesh out the test harness.

 

Sure, takes a little bit longer (than scripting for example, or using GDS), but it gives my brain time to think about the names chosen for the enum values and the names of the wrapper VIs. Often holes in the API become obvious just when thinking about how the accessors will be used.

Edited by Neil Pate

Share this post


Link to post
Share on other sites

@ShaunR

You make very good points, I think all of which I agree with (is that a first :D).  Bloat in the LabVIEW can be a very big problem, many massive class and libraries loading all members, and polymorphic VIs loading all members is an issue for sure.  In a post on my Variant Repository XNode I mentioned something to this affect, where the polymorphic version has a couple hundred VIs in a couple polymorphic VIs.

 

I certainly wouldn't use this wrapper code for every FGV in my code, it would add unneeded bloat with little (in any) benefit.  But there are times when it can make an API easier for the developer to use and understand, by breaking up the possible many functions of an action engine, into easier to understand chunks.  Like you said, pros and cons, like with many design choices in software.

 

It is something I've said on numerous occasions. Nice someone is finally agreeing with me :)  For example. You can immediately reduce the number of VIs and code size in a LVPOOP project by between [anecdotally] 25% and 50% (50% if its just a small object with only accessors). Only by putting a boolean for get/set rather than using individual VIs for accessors. Oh, wait. We could make it a typdef enum get/set instead of a boolean to make the code more readable. Oh. Now we have an AE......Doh :D

Edited by ShaunR

Share this post


Link to post
Share on other sites

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.