Jump to content

John Lokanis

Members
  • Posts

    798
  • Joined

  • Last visited

  • Days Won

    14

Everything posted by John Lokanis

  1. I have written a large test application that logs all data live to an SQL server. I am using the System.Data.SQLClient .NET assembly to interact with the database. This is working, but it seems to be a bit slow and I am wondering what the best method is out there. There are lower level drivers between this assembly and the transport layer. Has anyone written VIs to directly access those? One thing I did was write a little C#.NET code to move the record set data from .NET to LabVIEW in a single block move instead of an iterative process. This was a huge time saver, but I am wondering if there are more ways to speed things up. I realize that LabVIEW is not very speedy when calling .NET code. Would it be worthwhile to try an implementation using COM (ActiveX) instead? What about directly calling the lower level DLLs that the .NET code calls? Is there another solution entirely that I could try? All I need to be able to do is pass a SQL query to the DB and get back a record set. thanks for any help or insights. -John
  2. QUOTE (Mads @ Mar 13 2008, 02:43 AM) And an Icon that is the default LV Icon. If you are going to go to the trouble of doing all that custom graphics, then make a nice App icon (in all the various sizes and color depths) as well. That said, those are some nice FPs. Personally, my general rule for GUI design is, if another LV dev can tell it was written in LabVIEW, I have failed. For that reason, I study the style guildlines of the target OS before building my GUIs.
  3. QUOTE(Tomi Maila @ Mar 4 2008, 02:22 PM) See attached zip for an example. You will need to wire the three objects together. When you do, the connection between the second and third objects will be broken. If you save the VI, the wire will change to not broken, but if you try to create an indicator from the value output, it will be a string and not the cluster used to define the datatype. This is an extreme example, as you can see by the complexity of the datatype. But, I don't see why this should not work. I was under them impression that Xnodes were not available to devs outside of NI after 8.0. I guess you are one of the lucky ones...
  4. QUOTE(Yuri33 @ Mar 5 2008, 01:46 AM) Actually, I don't think that is true. I seem to remember reading somewhere that reading a global requires a task switch to the user interface thread, thereby causing parallel accesses to be done serially. Perhaps an NI dev can chime in on this? But, you are right, my idea using the feedback node based functional global is not a parallel design. It was not intended to be. If you need parallelism, I recommend single element queues or perhaps Tomi's new toolkit, if it supports parallel access. But in the case of an actuall LV global, it still allows write access anywhere, which was what I was trying to prevent.
  5. QUOTE(Tomi Maila @ Mar 3 2008, 11:07 PM) I gave this a try. Cool tool. It does not seem to like complex data types, however. I get a broken wire from the create to the read node. Not sure if my cluster is too complex or is because it is a typedef'd cluster. It seems to work for simple clusters. Is there a known limit to the datatypes it can support? I would be interested to know how this was built. I am assuming some sort of xnode voodoo scripting stuff that required 7.1.1 to access... -John
  6. That is an interesting solution. What you seem to have built is a pass by reference variable that can store any data. I am curious how this was implemented. I assume that the data is stored as a variant, but how do you cast the variant back to the original data type without needing a type input on the read function? Will this allow you to store ANY data type (including complex custom types) or just LV primative data types. I guess I need to download it and peek inside... -John
  7. QUOTE(tcplomp @ Mar 3 2008, 11:17 AM) A notifier or a single element queue could work, but these would allow multiple writes. My goal was to make a 'by reference static variable' This would always be initialized by the app in the beginning and then could be used anywhere in the app's VI tree. If you are working with several devs on a project, you could provide this VI as a tool for writting sub-vis that need access to the main app's FP references. The nice thing is that the number of VIs that must have an instance of the type-def'ed cluster of references is kept to a minimum. This makes it easier to maintain as you add more FP controls that others need access to. Since it is write once, you don't need to worry about it being overwritten by accident in a sub-vi. Also, I suspect that the feedback node is a very efficient way of storing and accessing this data. The implementation, therefore, is much simpler that using Queues, Notifiers or traditional functional globals, IMHO. To Jim's comment, I also use CRUDs, but mine are ACRUDs, Auto Create, Read, Update, Destroy. These use a single element queue and feedback node for storage of the queue ref. They test the queue ref to see if it is valid on each call and if not, create it. They then perform the READ, WRITE or DESTROY operation and output the queue reference back to the feedback node. I like this better than using the first call fuction because I can destroy and recreate several times within an app as needed to control memory usage. But again, the point of this tool was a STATIC variable, since FP references do not change while the app is running. -John
  8. No, not that kind of WORM! A Write Once, Read Many variable. Background: For large applications with many FP controls that you want to access and modify from sub-vis, a common means of doing this is to build a large cluster of references to all the FP controls and then pass this cluster to all the sub-vis that need access to any of these controls. While this uses the 'value' property to read and write to the FP controls, which is usually frowned upon due to speed issues, in a GUI, this usually not an issue due to the slowness of the human user. The problem with this method is needing to have this large cluster of FP controls on every sub-vi. This can take up a lot of space on the sub-vi panels and can cause problems if you update the cluster with more control refs in the future, causing it to resize and overlap with other FP objects. (obviously, the cluster of refs would be a strict type def) A Solution: So, how to solve this? Well, the need is to set all these references at the beginning of execution and then be able to read them from anywhere in the application. Sounds like a good use for a Global variable. But I don't like global variables. I won't go into all the reasons, but one of the key ones is that they can be written to by anyone anywhere in the application, which would be bad in this case. So, what I needed was a write once, read many variable that could be accessed from any VI in the application. It would be initialized only once when the EXE started. Sounds like a job for a Functional global! Well, there is a new form of functional global that is extremely simple using the feedback node. See the attached simple example. This uses only one reference. You must ensure that the first call that sets the value completes before and subsequent calls execute. Download File:post-2411-1204569204.zip What do you think? Does this seem like a good solution or is there a better one out there? Are there any pitfalls of this solution? thanks, -John
  9. QUOTE(Zalon @ Feb 25 2008, 06:14 AM) If you have a large structure that looks 'bad' as a BD constant, try instead making a sub-vi that has nothing in it except an indicator of your data type. Then when you place this on the BD, it does not take up as much space. I also recommend you name this VI something like "CONSTANT - my data.vi" and you make the datatype a type-def. For smaller cluster constants that don't look 'good' on the BD, try changing the orientation by right clicking on the border and changing the to 'arrange by - horizontal'. I always make type-defs of and data-type that is not a LV simple type. I also always make a type-def out of all enums. It is a good practice to get into.
  10. From NI Support: ---------------------- I have filed a report (4ILAJ889) with R&D for further investigation. I will update again you after the developers look into this issue. I tested your application in LabVIEW 8.2.1 and did not see this problem, so I'm assuming that something changed between LabVIEW 8.2.1 and LabVIEW 8.5. Are you aware of the built-in LabVIEW calendar that you can select from with a timestamp control? I'm still looking for a suitable workaround. Is it necessary that the calendar pop-up? I'm sorry for the delay and I can assure you that we are looking for a solution for you. -----------------
  11. Ok, so here is one idea: For each type of subsection that may be repeated N times, create a single templte. Then use this to generate several documents, one for each instance of the test. I will then need some way to merge theses docs together into one large document. Has anyone done this before? Does Word expose this functionality in it's COM interface? thanks, -John
  12. Hi, I am trying to build a complex report in Word using the Report Generation Toolkit. I am using bookmarks to insert my data into a template. This is working, but I now need to programmatically expand the report based on the data. For example, if the report is on a set of N tests, then each test needs it’s own section with its own unique set of bookmark names to insert into. So, I need a means of making a subsection template with the bookmark base names and then appending this template to the main template N number of times, while renaming the bookmarks in each appended section by adding a # to the end of them, so I can reference them later when I want to insert the data. I have no idea how to do this or if this is even possible. Has anyone else run into this and come up with a solution? Thanks for any ideas, -John
  13. NI Support has confirmed that the bug can be reproduced. If they offer a solution or issue a CAR, I wil update this thread. -John
  14. I have a set of VIs that implement the .NET MonthCalendar form to allow for date entry. I think I have found a bug in how LV registers for .NET events. My VI will work every time on the first call but it fails after 3-4 calls to the sub-vi. The problem seems to be that the .NET control is not registering it's DateSelected event every time, like it should. See the attached zip file for an example. Give it a try and let me know if you figure it out or can at least reproduce my bug. Download File:post-2411-1203050038.zip Thanks, -John
  15. There are many things about .NET in LabVIEW that are slow. Hopefully NI will put some effort into fixing this some day. But, there are work arounds. If you go look at Brian Tyler's old blog when he was at NI, there are a few good tricks for moving large data sets between .NET and LabVIEW. I have used these tricks to make a SQL interface via .NET that is 10x faster than the NI toolkit. Unfortunatly it does require writing a little C# code (but just a little ). Maybe if we all leaned on NI to improve their .NET overhead, things would get better.
  16. I read your article. I agree that to the novice, using XML in LabVIEW is not easy. You do need to understand a lot about XML features, like the schema and namespaces. But it is not impossible and can be a very powerful tool for large and complex data driven applications. Also, the best way to read and write XML from LabVIEW (in my opinion) is to use the MSXML .NET assemblies. I have tried the XML toolkit from NI as well and find it lacking compared to rolling my own with .NET calls. I am actually working on a presentation to our local LV user group about .net and using it to work with XML files. I use XML extensively in my LV applications, mainly as a universal script format to drive data driven portions of my application. I have tried many ways of parsing XML within LabVIEW. Given the tree nature of XML, my first method was to use recursion (via VI server) to walk an XML structure and then build a representation in a LabVIEW data structure. The first attempt used an array of clusters with elements to contain the node links and the data at the node. The second version used a Variant tree (via attributes) to construct the tree in the LV data space. This was a more natural representation of the data but was slow to access (due to the overhead of the variant attribute VIs, I suspect). This was before LVOOP. I understand there are better ways to represent tree structure in LV using the new OOP features but I have not explored that yet. Each of these methods required you to then translate the data into a LV structure (nested arrays of clusters) to make it usable (and the code readable) in the rest of the app. My current implementation is to parse the schema directly into a LV data structure consisting of arrays of clusters of arrays of clusters...etc... This is the fastest method so far and goes directly to a structure that can be used in the rest of your application. The downside of this approach is the structure of the schema is directly coded into the LV parsing VIs. So, if the schema changes, so must your code. For my applications this is usually not a big issue since we design schemas up front that are flexible for the design goal of the application. However, this certainly is not a good generic solution for LabVIEW and XML. I think the holy grail here is likely some sort of LVOOP implementation that can dynamically traverse an XML file and then build a representation in memory that is simple and clear to access in the rest of the application. Another approach is to use the .NET interfaces to interact with the XML file 'live' instead of preloading and parsing it into a LV structure. This may have advantages in some applications, but in my experience I have always wanted the data to be resident in memory and fast to access with standard LV array and cluster tools. One caveat with using .NET assemblies to access XML is the confounding documentation (or lack thereof) of how to do this. I have spent many an hour staring at MSDN pages trying to understand how to call or what to call to get the result I wanted. Also, there are some pitfalls to watch out for. For example, if you use the MSXML schema validation methods, you cannot simply close the reference to the XML reader when you are done. Instead you must call the CLOSE method in the XMLValidatingReader and the XMLReader before you close their references. If you don't then the OS will keep a file lock on the XML file until LV is closed. Once I complete my presentation I will try to remember to post the PowerPoint and VIs here for other to view. In the meantime, I would be happy to share my code with anyone who is interested. I also strongly recommend looking at the w3schools website (http://www.w3schools.com/xml/default.asp) to learn more about XML. Also, the best tool I have found for editing XML and creating schema is XMLSpy. It is not cheap, but it has paid for itself many times over on my projects. -John
  17. Hello? Is this just obvious to everyone else or is there just no one who cares?
  18. QUOTE(Norm Kirchner @ Dec 18 2007, 12:53 PM) I admit that I have not looked at test stand in the last 2 years, so things might have changed. But I just took another look at what is on the NI site about parallel testing and could not find a single reference to the ability to run multiple tests at the same time on the same DUT. They did show how you can run more than one DUT at once, but every example showed the tests for a given DUT running in sequence. Unfortunatly that does not meet our requirements. Also, I need to not only log test results to a database but also pull all test sequences from the database using a plan/suite concept and log the start and completion events of every test step as they happen. So, while they state their interface is customizable, I would be suprised if it could meet all those requirements. But, I could be wrong. So, if you know of some documentation or white papers that address the parallel test issues, please post the links. Maybe I could use that on my next project.
  19. Create a system multi-column listbox. Fill in several rows with some data. Set the properties Active Cell and Edit Position to a row in the middle of the ones you populated. Set the value to that same row. Set the key focus to true. Create a simple while loop to keep the VI running after all these setting are applied. Run the VI. The row you set should be selected. Use the up/down arrow keys to move to another row more than 2 rows away. Stop the VI Run the VI again. Use the arrow keys to move the selection again. Instead of moving relative to the programmatically selected row that is highlighted, it will jump to the row that was (up/down) from the row you moved to right before you last stopped the VI. Why does it do this? Why does it remember the last selection you navigated to? How can I override this so the selection I set programmatically is the one it will move relative to when the use uses the arrow keys? Is this a bug? -John Download File:post-2411-1198024019.vi
  20. QUOTE(Norm Kirchner @ Dec 17 2007, 02:31 PM) Yes, I taught myself LV back in 1993 by reverse engineering the original beta code for the first NI test executive.TestStand will not do what we want. It cannot run multiple parallel tests on multiple DUTs from the same machine simutaneously.It also cannot interface to a custom database with a specific schema for handling all test steps and data transactions.My test system is tightly integrated with our DB so if we want to know what is going on anywhere in our MFG site, the data is live in the DB.TestStand is fine for many test applications, but sometimes, you just need to roll you own. Besides, what would I do all day if I wasn't writting LV code? ;-)QUOTE(TobyD @ Dec 17 2007, 03:05 PM) Forget the book, just post the project when you're all done! I do plan to post many of the interesting bit to LAVA when I am done. Things like the .NET DB interface, XML interface, Tree data management, etc...Not sure if the final app would be of use to anyone else.Also, I plan to go back and refactor it using LVOOP once I find some time to learn LVOOP...
  21. Just an update: It was not memory fragmentation afterall but rather a resource leak cause by this little bugger: Always always ALWAYS close the reference that this thing returns! :headbang: So, in the end, as usual the problem was my own creation... Time to go drink many :beer: :beer: :beer: ....
  22. QUOTE(LV Punk @ Dec 14 2007, 04:09 AM) Sure. I am building a test executive that is capable of testing N units at the same time. Each unit under test can have N tests, all of which (in theory) can be executed at the same time. So, for a given unit under test, the test executive will spawn a test engine that handles all testing operations (including a UI that is viewable on demand in a sub panel) and will also report back status to the test executive (overall progress, time, pass/fail/etc). Each engine will get the proper test suite from a database and then will start launching tests. It will launch tests until the unit under test returns a test blocking issue (shared resource needed). It will then wait for the block to go away and will resume launching tests. Meanwhile, another thread in the engine will monitor results coming back from completed tests. Since all the tests are plug-in VIs loaded from an external library of VIs, the engine launches a handler for each test that monitors it's status, performs watchdog checking and passes the results back to the engine before self terminating. It is this handler that I am trying out the pass by queue call method. The engine is currently a VIT. All of it's subvi's are reentrant, since I need to spawn N of these engines at any given time. The hander is also reentrant, obviously. And all the tests are called reentrantly. The engine itself has 6 parallel threads (Incoming GUI, GUI Handler, Test Result Monitor, Test Launcher, Database Hander, Two independent Tree Control threads (I use two trees to display state and results)). Since the only limit to the number of tests running in parallel is the target hardware, there could be (practically) 10 tests running at once on each DUT. If I am testing 50 DUTs at the same time, that would be 50(duts)*(6(threads per engine)+(10 tests + 10 test handlers)) = 1300 parallel threads in a moderately loaded system. That is why I have dual quad core Xeons and 4G RAM in the box. Also, even though each step in the system is not super CPU intensive or time critical, the sum of all the VIs running at once is significant. So, I have needed to be vary careful about not blocking other threads and staying out of the UI thread as much as possible. For that reason, my Tree threads maintain tree state in a shift register and only update the actual tree control when the user requests to see the test details. It has been interesting to see just how far you can push this parallel programming stuff and what pitfalls are out there. Maybe I'll write a book if I ever get this project done!
  23. Thanks for the replies. The Xnode solution looks a lot like the VI I wrote to write the values directly (using option1). I am still concerned about the thread swap to the UI thread when doing this. I am launching 100s of these VIs from several instances of a reentrant VI every minute in my system and want to avoid anything that might make a bottle neck. That is why I came up with the queue idea. Here is a screen shot of the VI that gets the data: As you can see, all you end up with is the wires with the data on them, just like they had come from a FP control. I have also attached the VI that is used to send the data. -John
  24. I have been trying to figure out the best way to pass data to a dynamically spawned VI. Here is the setup The VI is reentrant. I want to have the VI run independently (don’t wait for completion), so I cannot use call by reference. I must use the Run method. I need to pass in a bunch of input parameters of varying data types. Option 1: Open a reference to the VI. Pass in input parameters by using the Ctrl Val.Set method to set the FP control values. Run the VI Option 2: Open a reference to the VI. Get the new VI’s clone name. Create a Queue of (cluster of string and variant) type using the clone name to name the queue. Fill the Queue with the input parameters (using the string for their name and variant for their value). Run the VI. Inside the VI, Obtain the queue from the clone name. Dequeue all the elements, feed them into a for loop and use the string to select a case for each value. The for loop has a shift register for each expected parameter value. In each case, set the value of the appropriate shift register using the variant. (use the Variant to Data function). It helps if you initialize all the shift registers with a constant of the expected data type. Take the output of all the shift registers and use them as the input parameters in your code. Do a Force Destroy on the clone named queue. So, why for option2 since it seems much more complex? Well, the idea was the Ctrl Val.Set method modifies FP terminals so it should/might/does cause a thread swap to the UI thread, something that is not good when speed is concerned. Also, option 2 means you have no FP terminals at all, so the VI should stay completely out of the UI thread (unless you do something else stupid). What do you all think? Am I chasing my tail or is this a good idea? -John
  25. QUOTE(LV Punk @ Nov 30 2007, 04:14 AM) I too was sorry to see Bryan go. Even though he is now living in my neck of the woods, he was a great resource to me when he was at NI. I am actually using tow of the .net techniques he bloged about in my current project. I have added to a thread on the NI forums about this issue as well. You can read it here: http://forums.ni.com/ni/board/message?boar...ssage.id=287625 Here is the workaround I have be using with some sucess and much pain: To work around this issue, you need to rewrite your VIs in 8.5. You cannot have any of the offending VIs open while fixing a VI or have ever opened them in your current session of LV8.5. Here is my process: 1. Open a bad VI. 2. Take a screen shot of the block diagram. 3. Paste the screenshot into any image editor/viewer so you can refer back to it. 4. Delete any .net nodes in the block diagram that call the GAC assemblies. Also, delete any refnum controls or indictors that you might pass in or out of the VI that refer to GAC assembly references. 5. Save the VI (it will be broken). 6. Close the VI. 7. Reopen the VI and verify you do not get the GAC warning message. 8. Close LabVIEW 8.5. (You must do this so LabVIEW 'forgets' about the GAC assemblies location. Otherwise, if you try to fix the VI now, it will just be broken again.) 9. Open LabVIEW 8.5. 10. Open the edited VI. 11. Recreate the VI components you deleted, using the snapshot as a guide. 12. Be sure to reconnect any front panel terminals to their proper points on the connector pane. 13. Save the VI. 14. Close the VI. 15. Open the VI and verify you do not get the GAC warning. 16. Test the VI (if you can test it in place). Repeat this for every VI you have that has .NET nodes and/or front panel terminals that are associated with any assemblies in the GAC. Special note: When you load a VI that calls other VIs that you already fixed, they will be re-broken in memory. After you delete the offending nodes/terminals from the parent VI, save it BUT DO NOT SAVE the sub-vis or you will re-break them. After you restart LabVIEW, to fix the parent, the sub-vi should load ok without the warnings. If you ever see the GAC warning after restarting LabVIEW to fix the VI you edited, stop what you are doing and retrace your steps. You could easily re-break everything you are doing if you are not careful. I am 2 days into my edits and about half way done. So far, so good. Fingers crossed. I have even tested some of the fixed VIs and they will now build, so I am confident in the workaround. -John
×
×
  • Create New...

Important Information

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