Jump to content

Lee Robertson

Members
  • Posts

    11
  • Joined

  • Last visited

Lee Robertson's Achievements

Newbie

Newbie (1/14)

0

Reputation

  1. Hi, I posted on this topic about a year ago and Kennon Cotton gave a very good explanation of what was going on. In my built applications, I include support for various components in the form of lvlib's that get called dynamically. When the application is built, the lvlib's are sent to a destination other than the executable. The lvlib's are contributed by several different groups so there are inevitably name collisions when the application is built and all the VI's are dumped into the same folder. I tried for a while to put each library in its own destination folder but this grew too cumbersome because of all the gymnastics you have to do to the build specification when you add a new vi to a lvlib. The solution I finally adopted was to load the dynamic VI's by their name space (e.g. Library_1.lvlib:Library_2.lvlib:Libraary_3:dynamic.vi). I wrote a custom "Build Path" VI that is name space aware. It walks the XML files to construct a path to a particular VI (the entries in the lvlib (XML file) look like Item Name=dynamic.vi, URL="relative path to the VI"). This scheme has a lot of advantages because it works the same in the development environment as it does in the built application (the lvlib's and lvclass's get modified appropriately when the application is built so that it all works out in the end). The problem comes when there is a name collision between VI's in the lvlib's and/or the lvclass's. Digits get appended to the end of the VI names such that no two VI's have the same name. Unfortunately, both the Item Names and the URL's get modified by appending the digits. I have written python script to go through the lvlib's and lvclass's in the built application and "repair" the Item Name entries by changing them back to their original form. My question is: under what circumstances will this get me into trouble? I have included a lvproj file that illustrates what I am talking about along with two built versions. When you run the top level VI, enter a name space for one of the test VI's and it will display the path generated and the VI will be dynamically called (it will popup a window giving the name of the library and the name of the VI, or the message "VI not found" if the path generated is not correct). The possible name spaces are "Library_1.lvlib:Test1.vi", "Library_1.lvlib:Test2.vi", "Library_2.lvlib:Test1.vi", and "Library_2.lvlib:Test2.vi". The DefaultDir entry for the ini file needs to be set to the directory where you unzipped the example. Note that there is a name collision between Test1.vi in Libary_1 and Library_2 -- ditto for Test2. When the application is built Library_1.lvlib:Test1.vi gets renamed to Library_1.lvlib:Test10.vi and Library_1.lvlib:Test2.vi gets renamed to Library_2.lvlib:Test2.vi (both the Item Names and the URL's are changed). Therefore, when you run the exe in Test_Name_Spae_as_built, only the paths for Test1.vi and Test2.vi in Library_2.lvlib get resolved correctly. In Test_Name_Space_modified the Item Name entries in the lvlib files have been changed back to the original VI names but the corresponding URL's still point to the renamed VI's. Now all the name spaces resolve to the correct paths and the dynamic VI calls are successful. I have not tried this explicitly with lvcalsses yet, but they will be implemented soon and every single one of them will probably have an initialize method so there could be an explosion of name collisions. Once the application is built, what are the lvlib's sent to destinations other than the exe file used for? IS anything bad going to happen because the Item Name entries in the lvlib files have reverted to the original names before the name collision? Any insight on this will be appreciated. --Lee
  2. All, I am using the VI Server running as a built application on remote machines to start and stop VI's as needed. The built application is just a dummy while loop that gives me a running instance of the VI Server on the remote hosts. Some VI's I simply run using a "call bu VI reference" but others are started by a "VI class invoke node:: Run VI" and continue running until they are killed. I am trying to do something akin to a "ps -aux" on the remote machines using the VI Server to automatically kill the spawned VI's when the master control program exits (it would send a shutdown signal to the dummy program on each remote host) or when the mater program restarts after a crash, it would send a "reset" signal to the remoste hosts telling them to kill the currently spawned processes and prepare for them to be restarted. (The motivation for this is that I don't want to have to keep track of what VI's are running where.) I have been able to get this to work using a poroperty node to get the VI's in memory, and then check the "exec state" of each of those to kill the running VI's. My problem is that I often need to spawn multiple instances of the same VI (with different data) which gets me into the ralm of the clones. I can't figure out how to find all the clones and kill them. Does anyone have a good idea on how the do this? --Lee
  3. All, I have seen this discussed before but now I can't find it -- sorry for the new topic. I need a way to programmatically determine the number of cases in a case structure. I don't need to know the names or anything, just the number. The reason I need this is to fix an ugly code maintenance problem we have been experiencing. --Lee
  4. All, Now that I understand how to dynamically create an instance of a class, I am back to one of my original questions: Imagine that I am writing instrument control software for a piece of equipment that has 4 motor controllers each controlling 8 motor axes. For simplicity, let us assume that all 4 motor contrallers are of the same type. A good model for structuring the device interface part of the instrument control software would be to create a parent (base) class called device.lvclass that sits above all the supported hardware. A child of device.lvclass would be motor_controller.lvclass which would handle all the methods for the motor controller that are not specific to a particular motor axis (e.g. the IP address of the controller). There would then be a child of motor_controller.lvclass called motor_axis.lvclass that handles operations that are specific to an axis (e.g. motor speed, motor velocity, direction, etc.). One would create 4 instances of motor_controller.lvclass and 32 instances of motor_axis.lvclass. After each instance of motor_controller.lvclass is created and initialized, I give it a name and store it for future use. Now, when I create an instance of motor_axis.lvclass and initialize it, one of the parameters I read from the configuration file is the name of the motor controller that the axis is associated with. When it comes time to drive the motor that a particular instance of motor_axis.lvclass represents, the "move_motor" method of motor_axis.lvclass constructs a command to drive the motor to the erequested destination and then invokes a method on the associated motor controller to execute the command. There are two obvious ways one can do this. First, you can find the correct instance of motor_controller.lvclass using the device name of the motor controller for this axis and call the execute_command method with the correct data object wired in. Or, you can use the fact that motor_axis.lvclass is a child of motor_controller.lvclass and therefore inherits the data members of motor_controller.lvclass. This means that when an instace of motor_axis is created and the device name of the associated motor controller is read from the configuration file, once can call a method on the motor controller to populate the inherited data menebers from motor_controller.lvclass for the correct motor controller. Now when one needs to invoke a method on the motor controller for a given axis, you just have to pass up the instance of the motor axis and it will contain the data for the motor controller. Which is the preferred way to do it? For the second method: What is the best way to copy the data from the correct instance of motor_controller.lvclass into the instance of mtor_axis.lvclass? What if a motor controller parameter gets changed -- How does the change propogate to all of the child instances of motor_axis.lvclass for that motor controller? --Lee
  5. Stephen, It works!!! I studied your example and at first I could not figure out why yours worked while my code crashed and burned. I finally realozed that your "Load_Plugin" VI was coercing the offspring to the type for the "Generic" (base, parent) class. I was trying to return an object of the type for the child. Now I understand your previous comment!
  6. Hi, I finnally got around to trying out Stephen's idea for working around the problem of dynamically creating a class instance that will work with the application builder. The code runs as a built application but I do not get the results I expected. I will atempt to attach a zip file with my test project to this post. In the example I created 3 classes. The top anscestor is called 'Alpha', then there is 'Beta' which is a child of 'Aplha' and 'Gamma' which is a child of 'Beta'. Each class as a 'Create_Instance' method that just returns an object (instance) of that class. The 'Create_Instance' method for the class gets called for the chosen class (see menu control on test.vi) gets called via a 'call-by-VI-reference' node. The object returned then gets fed into a dynamic VI called 'Identify' which exisits in all 3 classes. Dynamic dispatch should now select the version of 'Identidy' that is a member of the class corresponding to the object (instance) created by the 'Create_Instance" call. Insted, you always get the version of 'Identify' corresponding to the 'strictly typed VI' used for the 'Open VI Reference'. Evidently, the object returned by the "Create_Instance' method gets coerced into an object of the type on the output terminal of the VI chosen for the strictly typed VI. How do you prevent the coercon??? I get errors about the terminal types not matchiong for the 'call-by-VI-reference' but the code still runs Thanks, --Lee Download File:post-3444-1160078682.zip
  7. Stephen, I've got it!!!! I can't thank you enough but the light bulb is on now. Thnaks to your very good C++ example code, I now see how inheritance of PRIVATE data works in LVOOP. It is completely clear. The answer is B. I tried this scheme before I entered my long post on 8SEP06. I could not get it to work becuae I was still confused about data inheritance. For the Open_VI_Reference buil-in I just picked one of the child "DefaultValue.vi"'s at random for the type specifier to get the strictly typed VI. Then when I would try to call DefaultValue.vi for a different child, I would get the error the VI invoked by "call by VI reference" didn't have the same connector terminals as the strictly typed VI. But after reading your post I realized that if I put a DefaultValue.vi method in my top level parent (Device.lvclass) then it will work becasue the data type is compatable with all of the offspring. Its too bad the children can't just inherit the DefaultValue.vi method from Device.lvclass, but if you do this the instaces created don't have the information about which child they are an instance of (sorry for the bad grammar). If I put a "DefaultValue.vi" type method in every child, then tehy all have to have unique names which might lead to trouble down the road when we merge in code developed by other groups. Thank you very much for your help. --Lee
  8. Hi, I just tried my test program in the applicaiton builder. It built OK but then barffed on the App->LVClass.Open method with an error 53 (Manager call not supported). I can't find anymore information on this error. --Lee
  9. Hi Stephen, Thanks for your reply. I have read the documents you suggested and all is much clearer now. I was quite alarmed to read the editorial comments on the "Factory Pattern" about not working with built applicaions becase the LVClass refnum us unavailable. This pattern is exactly what I came up with for dymanically creating instances of my classes based on reding a config file. I must have described it poorly since you didn't recognise it. We have a strict policy of not running from code (we use built applicaitons only) on our production machines. This couold mean that we won't be able to use LabVOOP in our application enven though it is huge (>500 VI's) and could really really benefit from OOP. The enum trick you mention would be too much of a code management nightmare. Are there any other possibilities of dynamically creating instances of a class? I have been playing with your idea of not using the DefaultInstance property but rather using the InitializeArray built-in to populate my array (liked list) of objects (class instances). I tried just creating an array of instances of the parent class, but the information needed to choose which child class to invoke from dynamic dispatch doesen't seem to be there. Maybe there is a way to typecast the parent class to be the correct .ctl type for the child -- or since I have the path to the class library from the configurations file, I can dynamically call a VI (method) in the child class (call by VI reference?) that takes no inputs but returns the default cluster (name.ctl) and use that as the instance of the class (in the spirit of a contsructor). This sould be a static method? Also, I'm still not clear on the inheritance of the data (I'm sorry, sometimes I just don't get it). Going back to my original post and the idea that an instance of a child class inherits the data clusters of its ancestors. This is implied in several places in what I have read. But is it really the case that you can't access this data in a child method but rather you need to add a method the ancestors to expose this data to the child? Perhaps I am cofused by classes only having private data in LabVOOP. --Lee
  10. Hi, I'm not clear about the distinction between LVOOP, GOOP, and OpenGOOP so please forgive me if I'm posting in the wrong place -- I am asking about LVOOP in LV8.2 in this posting. I have been programming in LabView for some time and I have a little experience with OOP in other languages (Python, C++, Java, ...) but I am a scientist with no formal training in programming -- I just figure it out as I go. I know from long experience that it is important to figure out how the LV developers intended for you to use various tools. I am experimenting with using LV8.2 classes to implement dynamically loaded support for devices. After a lot of frustration, I figured out how to dynamically create an instance of a class using the DefaultInstance member of the LVClassLibrary property (the hardest part was figuring out what to wire into it). I wire the path to the class definition (class_name.lvclass file) into the App->LVClass.Open method to get a reference used to generate the default class instance. At the top of my hierarchy (PARENT), I have Device.lvclass which defines data and methods required for every device (data = device_name, device_class, device_type, device_description,
  11. Hi, Now that LV8 is out we are using VI's with the same name but in different libraries (.lvlib's). This is a big advance for us -- multiple modules can have subVI's with the same name (i.e. initialize.vi) so long as they are in different name spaces (libraries). This avoids all sorts of problems we have been having previously with name conflicts. The modules I am speaking of are dynamically loaded at runtime by the VI Server. This all works works very well when running the development environment. When we build an application (installer) and install it on another host and run from the executable, it fails completely. If I rename the executable to a .llb and look at the contents, I see that all of the VI's are at the top level and VI's with the same name have been renamed. For example: lib1.lvlib:init.vi, lib2.lvlib:init.vi, lib3.lvlib:init.vi get renamed to init.vi, init0.vi, and init1.vi and the library XML files get updated accordingly when the executable gets built. The problem comes when we try to refer to the VI's by name to load them via the VI Server. What is the best way to sort out in what order they were renamed? I can still navigatge the library tree (XML files) and try all the possible renaming scenerios but this gets terribly complicated, especially if I already had a VI named init1.vi in one of the affected libraries. Is it generally a good idea to avoid VI's with the same name even if they are in different libraries? --Lee
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.