hooovahh Posted Tuesday at 01:04 PM Report Posted Tuesday at 01:04 PM Lets say I have a basic hardware abstraction layer for environmental chambers. Here I have the parent Chamber class, a Simulate Class which overrides the required members, a CSZ, and an Envirotronics which are two makers of chamber hardware. For this example lets say I want to distribute this as 3 different VIPM packages. I have my Hooovahh Chamber.vip, which contains the Parent, and Simulate classes, and I have two others the Hooovahh Chamber >> CSZ.vip, and Hooovahh Chamber >> Envirotronics.vip. On the palette I have the main functions all look similar to this. My main question is about how people handle the Finding and Opening functions? I want these drivers on the palette to be easy to use for my developers. At the moment when you install the main Chamber package it installs the Parent VIs you see, and the Simulate class constant on the Class Constants subpalette. Each child specific package then installs a new class constant in the subpalette. Then when a developer wants to use the Find Chambers, they must wire to it an array of classes to use. Here is an example: Here we have a Find VI that is static dispatch on the parent, with overrides insides for each of the Chamber types. It returns an array of found Chambers which is a cluster. In the cluster is the class for the chamber found, which is used in the Overrides for Open and Close. This works and is fine. But I like the idea of hiding away the class constants, and having more self contained Find VIs for each hardware type. In most cases we know the hardware we want to talk to and it isn't an array of classes on an array of COM ports, but instead the one hardware class we intend to use on the system. What I think I would prefer is some thing more like this: Here the developer gets a dedicated Find VI for each class which is a static dispatch for each child class. They all return the same array of cluster (which would be a data type from the parent) and then that array of found chambers is used in the Parent Open which has overrides for each class inside. In this design I would have the Find for each class installed on the palette under some kind of Find Hardware subpalette. In this case I imagine there would need to be some kind method of keeping each Find from only using one COM port at a time. Either through VIG or Semaphore of some kind. Admittedly this is simplified in the previous example since the Parent would be doing the finding, and would know to only pass a unique COM port to one child at a time. In all of these cases I imagine we have full control over the Parent, and all Children. If anyone develops a new child class, we would roll it into the reuse library as another package which would go through the verification process. Do developers prefer one design over the other? What pros and cons haven't I thought about? Thanks. Quote
ShaunR Posted Tuesday at 01:24 PM Report Posted Tuesday at 01:24 PM (edited) I use a polymorphic VI. It basically just wraps the class constant for this purpose.The user can then have a single VI that they can choose the implementation method from a menu and that ripples down through the class functions. It means you only need 1 VI in the palette for the Open/New/Whatever and, once placed, the the user can change implementations without creating or deleting anything. When there is a single type wired it looks much better because LabVIEW will show the class instance (see below) rather than the generic instance see (above). The drawback is quick-drop (apparently) because you cannot choose a specific instance, only the polymorphic, but I ignore people that complain about that Edited Tuesday at 01:42 PM by ShaunR Quote
hooovahh Posted Tuesday at 01:57 PM Author Report Posted Tuesday at 01:57 PM 35 minutes ago, ShaunR said: I use a polymorphic VI. It basically just wraps the class constant for this purpose.The user can then have a single VI that they can choose the implementation method from a menu and that ripples down through the class functions. It means you only need 1 VI in the palette for the Open/New/Whatever and, once placed, the the user can change implementations without creating or deleting anything. The problem I have with that is you need a polymorphic VI that has all of the instances inside it. That creates a dependency that all children are available and installed. In my situation you may only install the Chamber package, and CSZ package. Then the developer only has the parent, and that one child (well 2 there is the simulate). So now where would that polymorphic VI live? In the parent package? Then that creates a circular dependency. I did explore creating an XNode that would look at your current system and drop a VI that had whatever children were available for that target, but that got a bit messy. The reason for having separate packages, is because some child classes, only work on some targets. I may have one chamber that uses a Windows DLL to talk to it over USB. This DLL wouldn't run on Linux RT, and I need to not bring along that child class as dependencies, because that will break the deploy or build, even when that child isn't being directly called. Quote
crossrulz Posted Tuesday at 02:26 PM Report Posted Tuesday at 02:26 PM If you have a specific structure for your chambers (ie everybody is under the "Hooovahh Chamber" directory), you could do a simple lookup and use the Get LV Class Default Value to dynamically load the classes. I do something similar with my HAL already, except I dictate what class to load based on a JSON file. 1 Quote
ShaunR Posted Tuesday at 02:32 PM Report Posted Tuesday at 02:32 PM (edited) 11 minutes ago, crossrulz said: If you have a specific structure for your chambers (ie everybody is under the "Hooovahh Chamber" directory), you could do a simple lookup and use the Get LV Class Default Value to dynamically load the classes. I do something similar with my HAL already, except I dictate what class to load based on a JSON file. That's not the real problem (but the same solution as I was about to suggest). The main issue is the LabVIEW static linking. Traditionally we have gotten around it with conditional disable structures or calling CLFN's with a path. hooovahh has created a class that isn't platform independent, only device independent and is attempting to solve platform dependencies with deployment. I'll have to sleep on it. Edited Tuesday at 02:38 PM by ShaunR Quote
hooovahh Posted Tuesday at 07:45 PM Author Report Posted Tuesday at 07:45 PM 5 hours ago, crossrulz said: If you have a specific structure for your chambers (ie everybody is under the "Hooovahh Chamber" directory), you could do a simple lookup and use the Get LV Class Default Value to dynamically load the classes. I do something similar with my HAL already, except I dictate what class to load based on a JSON file. How do you deal with built applications? Your solution sounds fine on Windows, and in a development environment. But if I make an RT or Windows application, it won't know to bring along the child classes into the build if they are called dynamically. Unless I add them as an always include I guess. I think there isn't any way around having to have either a class constant of the children somewhere (like into the Find Parent VI) or to have each child class have it's own Find which is part of it's own class and brought into the builds. I suggested the XNode option just because it could read those files on your Windows disk, then plop down the constants into the generated code. That has complications like only bringing along the classes on your disk, at that time, unless on load the XNode reloads and regenerates code which is a different kind of mess I wouldn't want to deal with. But then again it could be a cool right click feature for reload, or check boxes on what libraries are installed, and which ones to load. And while that is all cool sounding, the very large majority of the time a developer just wants to plop down a single VI, that finds the hardware for that specific hardware type. And then not have to do anything extra to make builds work. Quote
ShaunR Posted 10 hours ago Report Posted 10 hours ago (edited) I'm not sure you can get away without dynamically loading. It seems you are basically wanting a plugin architecture. The problem with platform specific code is, I think, a separate issue. Note that a plugin architecture also solves your "find" since you can only find those that have been installed. The issue then becomes that you were reliant on static binding (class constants) to solve your deployment to target. This is the same as VI refnums. What do you envisage the process to be when you have a chamber that has different implementations depending on platform? Let's say that the CSZ chamber must use TCP for Linux but USB for Windows? Now you don't have a static binding problem for deployment but you still have a platform problem. Edited 10 hours ago by ShaunR Quote
hooovahh Posted 1 hour ago Author Report Posted 1 hour ago 6 hours ago, ShaunR said: I'm not sure you can get away without dynamically loading. It seems you are basically wanting a plugin architecture. The problem with platform specific code is, I think, a separate issue. Note that a plugin architecture also solves your "find" since you can only find those that have been installed. The issue then becomes that you were reliant on static binding (class constants) to solve your deployment to target. This is the same as VI refnums. I don't think plugin architecture describes what I'm looking for correctly. Ideally the developer installs packages for the hardware they have. The package can have some idea of the system they have, so like 32bit DLLs can only be installed in 32 bit LabVIEW. I do think that I'm envisioning a static class constant (or VI call) to ensure dependencies are brought along for the build. Which does bring me back to the first question. Do people prefer or use one design over the other? And by that I mean the static dispatch parent with finding classes passed in, or explicit find for each child type? 8 hours ago, ShaunR said: What do you envisage the process to be when you have a chamber that has different implementations depending on platform? Let's say that the CSZ chamber must use TCP for Linux but USB for Windows? Now you don't have a static binding problem for deployment but you still have a platform problem. For that there would either be a separate CSZ TCP, and CSZ USB children, or there would be a CSZ Parent, CSZ TCP, and CSZ USB depending on implementation details and overlap between the two types. But I do get your point. As a developer I know I have a CSZ so I install that package, then start developing. Only once I go to deploy to an RT target will the USB one tell me it isn't compatible by saying it can't bring along some DLL requirement. I guess this is something that the LVAddons might help with. I haven't dived into it yet but as I understand it, files can be made available or not in the IDE based on the target. So then you might install the CSZ USB package, but it won't be on the palette if your target is Linux RT. I actually did run into this issue recently where I was using the JKI REST API. I tested it on Windows and assumed it would work fine on RT since it the normal HTTP functions are on Linux RT. But unfortunately later versions of JKI's package uses the Advanced HTTP functions which are not available. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.