Jump to content

Omar Mussa

Members
  • Posts

    291
  • Joined

  • Last visited

  • Days Won

    10

Posts posted by Omar Mussa

  1. QUOTE (Aristos Queue @ Feb 3 2009, 09:48 AM)

    It was going to be fixed in LV 8.6, but in LV8.5 someone (not on the LVClass feature team) wrote some new features for another part of LV that depend upon that uniqueness of name and enshrined it. Darn software -- it grows when you're not looking.

    Sound like you need to be involved in some more internal design reviews ;) I don't expect these problems to be easy to solve -- if they were, none of us would be working on them! I'm glad that LAVA provides a platform for discussing them at all :thumbup:

  2. QUOTE (Aristos Queue @ Feb 2 2009, 05:16 PM)

    I can almost never hit the run button for my class private (or public) member VIs. They often depend on data existing in the private class data -- some of that data could be queue references or other things that need to be created first. That is practically the whole point of having a unit test framework -- you can use test harnesses (setup/teardown VIs) to initialize data you want to have for each test and validate that the tests work in isolation from other tests.

    QUOTE (Aristos Queue @ Feb 2 2009, 05:16 PM)

    And if you just want to run a quick test, it should be just as easy to run the public VI that calls your private VI as it would be to run the private VI directly.

    I think the problem is one of practicality. Its hard to know a priori exactly which public VIs will call private VIs (especially for VIs that are utilities set to private) -- but we do have a well defined VI that is the 'private' VI -- so it seems like it is reasonable that if we want to test certain ranges that we know public API VIs will need, we should be able to test those ranges. The problem with adding to the Public API to do this is that I don't want my Public API to get harder to describe/more verbose than it has to be -- for example, I don't want a VI called 'TestPrivateMethodX' that is a public member of my class.

    QUOTE (Aristos Queue @ Feb 2 2009, 05:16 PM)

    When we start talking "test suites", I'm thinking nightly builds and automated testing on a regular basis. Those auto tests have no business, IMHO, running the private VIs because, as I said, a parameter sweep across them may result in false error reports or may put your object into an unexpected bad state that can never actually occur in real uses -- and I do mean *can* never occur not *should* never occur. That's the thing about privacy enforced by the compiler -- outsiders *cannot* call that VI with arbitrary values. Since this *cannot* happen, we don't have to worry about testing for it.

    Parameter sweeps across private VIs are probably not the only use case for testing private VIs. Another reason unit tests are 'useful' is for enforcing that changing your code hasn't created bugs. Since I can't unit test my private VIs properly, I can't be certain that making changes to private VIs did not create bugs in my public API (that I may not currently be testing with 100% certainty of coverage). So, IMO, these are valid requests from a unit test perspective. Otherwise, the answer is -- nothing should ever be private that you can't trust to work 100% of the time through your public API. Since I can't gaurantee I'm testing 100% of my public APIs interface with its private members, I'm basically asking for trouble. I don't like that answer from a practical perspective.

  3. QUOTE (Aristos Queue @ Feb 2 2009, 02:54 PM)

    Yes, you may find legal problems as well (I know it was badly out of context and edited but I couldn't resist :P )

    QUOTE (Daklu @ Feb 2 2009, 04:16 PM)

    I'll tell you why *I* write test cases for private vis, but I'll leave it to those smarter than me to debate the 'correctness' of doing it.
    :)

    • Many of my classes are hardware dependent and I don't always have the hardware available to test the class as a whole. Testing sub vis gives me some confidence things will work when I connect to the hardware.

    This is actually a design issue with your application that you should address. One of the great aspects of having LVOOP with inheritance is that you can create a parent class 'Rain.Abstract' and then have two children that inherit from it called 'Rain.Hardware' and 'Rain.Simulator'. This means that you can run all of your unit tests on the simulator implementation to flush out your object API and then rerun the tests when hardware exists by using the hardware implementation. This should significantly cut your bugs down -- ideally you'll only find issues where you either didn't simulate properly or you didn't imeplement the hardware (i.e. drivers) correctly.

    One thing that writing unit tests does is that it forces you to 'FIX' your applications design issues so that you CAN unit test them (especially if you are doing 'Test Driven Development').

    VI Tester can really help you with running tests of this nature -- For now, you can create a test object and in the setUp you can choose whether to create a hardware or simulator instance of your object to test. On the VI Tester roadmap is supporting test cases with inheritance so that you could create all of your unit tests in a 'Rain.Test' class and then have a 'Rain.Simulator.Test' class that creates a Rain.Simulator object in its setUp and would allow you to extend the Rain.Test class... We're still actively working on making this feature work well so that's as much as I can say for now.

  4. QUOTE (crelf @ Jan 23 2009, 03:13 PM)

    PS: yes, "Tool Suite Explorer.vi" is my top level VI.

    EDIT: Nevermind - a LabVIEW restart fixed all :)

    You're lucky restart worked... Does your project have LVOOP Classes? I've noticed that occasionally I have issues where a class wasn't saved properly so it has a missing member and other kinds of issues that sometime manifest themselves as an error that is basically un-explainable from the error dialog. I don't have a specific example at the moment or a way that I produced them -- also, I tend to develop in LV 8.2 still so some of the issues may have gone away.

  5. QUOTE (Aristos Queue @ Jan 15 2009, 10:00 AM)

    Another NI employee who read this post has just let me know that, yeah, he saw something like that once, in LV8.6. He also cannot reproduce the issue, although in his case, it happened to many classes when he did some batch processing on them.

    This isn't enough info for me to even file a CAR much less debug the problem, but I'll keep my eyes open when I'm working on other CARs related to saving and/or property editing for problematic code snippets.

    I now have a workflow to generate the problem in LabVIEW 8.2. Still not tested in 8.6 but I'm going to guess that it still exists if nobody reported it in 8.2. Here is the problem -- if you modify the child class documentation property for a class whose parent class is not in the same project, then the child class will lose its inheritance info.

    Open the attached lvproj. Open 'my method.vi' -- notice it is executable. Now change the documentation property of the class and it will break the method.

    Please post the CAR here so I can track it. Thanks!

  6. QUOTE (Aristos Queue @ Jan 15 2009, 10:00 AM)

    Another NI employee who read this post has just let me know that, yeah, he saw something like that once, in LV8.6. He also cannot reproduce the issue, although in his case, it happened to many classes when he did some batch processing on them.

    This isn't enough info for me to even file a CAR much less debug the problem, but I'll keep my eyes open when I'm working on other CARs related to saving and/or property editing for problematic code snippets.

    I now have a workflow to generate the problem in LabVIEW 8.2. Still not tested in 8.6 but I'm going to guess that it still exists if nobody reported it in 8.2. Here is the problem -- if you modify the child class documentation property for a class whose parent class is not in the same project, then the child class will lose its inheritance info.

    Open the attached lvproj. Open 'my method.vi' -- notice it is executable. Now change the documentation property of the class and it will break the method.

    Please post the CAR here so I can track it. Thanks!

  7. I'm still using LabVIEW 8.2.1 for some of my projects and I just ran into a strange LVOOP bug. If you change the class description property (right click on class-->Properties-->Documentation) and press OK to close the dialog, the class will lose its inheritance information. I haven't tried this on a more recent version of LabVIEW to see if it was fixed. Is this a known issue? Is it there in 8.6? Its annoying because it breaks a lot of class member VIs if all of a sudden they are no longer in the same class hierarchy. I'm going to avoid documenting my classes for now.

  8. I'm still using LabVIEW 8.2.1 for some of my projects and I just ran into a strange LVOOP bug. If you change the class description property (right click on class-->Properties-->Documentation) and press OK to close the dialog, the class will lose its inheritance information. I haven't tried this on a more recent version of LabVIEW to see if it was fixed. Is this a known issue? Is it there in 8.6? Its annoying because it breaks a lot of class member VIs if all of a sudden they are no longer in the same class hierarchy. I'm going to avoid documenting my classes for now.

  9. QUOTE (c.LEyen @ Jan 7 2009, 02:27 PM)

    Maybe, when would you use DIAdem and when would you not?

    First, I will qualify that I haven't used DIAdem 11, so I'm not sure exactly how the latest version applies to these comments but I believe they are valid (my last project was in DIAdem 9, I did take a look at DIAdem 10 but did not have any projects). I will only point out what I think are DIAdem's strengths for now since I don't really know enough about your project. Hopefully this will help, I recommend you use the demo version and see for yourself what kind of time investment it will take and whether that is worth it for you.

    DIAdem works well if you have a lot of different sources of data (ascii, excel, database, etc) and need to aggregate them together.

    DIAdem works well if you can have at least 1 person become 'the expert' on your team. There is (in my opinion) a fairly significant learning curve to become a DIAdem expert - so unless you have the resources to make someone and expert, it may not be worth the effort. The expert should have a good understanding of the data formats you want to support, VB/vbscript, LabVIEW (optional actually but can be useful), and ActiveX, esp. w.r.t. generating MS Office reports. It may be worth your while to get consulting help on setting up your initial architecture if you plan on doing complex reporting.

    DIAdem works great if your data is 'compatible' - meaning that the built in tools can parse your data easily -- this is not necessarily the case for complex relational databases which generally require customization on your part to get the data in how you want to see it. If your data is not 'compatible' -- for example if it is a custom binary format, you can create a 'Data Plug-in' pretty easily that makes it easy to import your binary data.

    DIAdem does have a lot of really cool tools for engineering data analysis.

    DIAdem and LabVIEW can interact - if you are comfortable in LabVIEW, I would recommend doing all of the GUIs in LabVIEW and having some kind of 'report engine' that you can call that implements any DIAdem vbs required for report generation.

    Good luck!

  10. QUOTE (c.LEyen @ Jan 7 2009, 01:05 PM)

    So DIAdem? Whaddaya think?

    Or more specifically, what would your reasons be for NOT using DIAdem?

    What is your use case? What are you trying to achieve? DIAdem is a tool so whether to use the tool depends on what you are trying to accomplish.

  11. QUOTE (Val Brown @ Dec 18 2008, 12:25 PM)

    Perhaps OpenG could be transitioned INTO the overall NI distro

    There are many examples of VIs that have been 'transitioned' into LabVIEW as a result of OpenG (fees have not been involved to my knowledge ...). So if you want to wait for NI to 'transition' VIs from OpenG, that's your choice. I, for one, am glad that I don't have to wait for NI to create every function or framework that I need or use.

  12. QUOTE (Val Brown @ Dec 18 2008, 07:47 AM)

    It seems to me that all of this inconsistency really defeats one of the core rationales for OOP within LV.

    I think that it is more like there are multiple tools (design patterns, etc) and so you can choose which tools are appropriate for the problem that you are trying to solve. I don't think this defeats any rationale for LVOOP.

  13. QUOTE (Callista @ Dec 3 2008, 12:20 PM)

    PROBLEM STATEMENT: The system consists of an upper tank

    full of water with two spigots that are initially closed. The spigots are mounted at the

    same height on the large tank at opposite sides from one another. The spigot on the upper

    tank which drains into the cylindrical tank (and appears on the left side of the upper tank

    in Figure 1) has a diameter of 0.06 ft. The spigot on the upper tank which drains into the

    rectangular prism tank (and appears on the right side of the upper tank in Figure 1) has a

    diameter of 0.08 ft. At time t=0 s, both spigots are opened and water discharges from

    each spigot at an average velocity of 4.1 ft/s. The water from the left spigot discharges

    into a cylindrical tank. The water from the right spigot discharges into a rectangular

    prism tank.

    This is probably the coolest LabVIEW homework problem I've seen! :thumbup:

    Where are you taking this class? What is the class name/instructor?

    Also, you might try using formula nodes instead of the math function nodes as it can become difficult to figure out what your formulas are doing when they are spread via the math primitives for complex operations. I usually avoid the primitives if I have to do more than 2 or 3 mathematical operations. You can consider using both too, formulas where appropriate and math primitives where it is easier -- the goal for yourself is readability -- can you look at the code and basically understand what is happening or do you have to sit and stare for a few minutes before everything becomes clear. Good luck with your project, you look like you are making great progress!

  14. Yesterday I spent a few hours chasing down a memory leak in some code. It reminded me of a few things:

    1) The value of reusable code (this VI should have been a reusable VI)

    2) The value of unit testing (I wasn't unit testing)

    3) The value of running long/overnight tests (until we ran the burn-in overnight test we didn't catch this problem).

    Basically, I was using a semaphore as a lock to some hardware resources. I accidentally used the wrong check for 'Not A Refnum' which results in creating a new semaphore every time the code executes.

    post-5746-1227290880.png?width=400

    Here is the correct way that fixes the leak:

    post-5746-1227290891.png?width=400

    Hopefully this helps someone avoid a few hours of debugging a memory leak that shouldn't exist in the first place!

    It would be nice if the 'Not a Refnum' primitive could do some kind of internal casting and checking so that both VIs would work -- but at least I won't be making this mistake again (and since I'm adding it to our company's reuse pool, hopefully nobody else will either!).

  15. QUOTE (jcarmody @ Oct 31 2008, 05:03 PM)

    There are two parts to this response...

    1) One 'feature' of the JKI State Machine is that the empty string case ("") is also the "Idle" case. This means that whenever you finish executing a macro or a series of states, the state machine will return to "Idle"

    2) Adding 'Idle' or an empty string in a 'macro', which we can define as any time that you try to queue up multiple events, can and will get you into trouble in a state machine.

    Here's a scenario assuming you have the states: Go, Wait, Idle, Stop

    Let's assume that 'Go' only happens when 'Wait' completes and that 'Stop' is only reached when the user presses a button that is handled in the 'Idle' frame.

    The Wait state contains the following logic: Wait until time elapses -- if time elapsed 'Go' else 'Idle + Wait'

    Now -- let's imagine that the 'Wait' time did not elapse (queue contains 'Idle','Wait') -- it is possible for the user to press a stop button which gets handled in the 'Idle' frame due to the event structure, and then the state machine would still proceed to 'Wait' (b/c you queued it already in the 'Idle+Wait' logic) and it is possible that the new 'Wait' state time has now elapsed so the 'GO' frame is reached. This sucks for the user -- they pressed 'Stop' but the state machine still hit a 'Go' frame... now it means you are stuck adding more logic to the 'Stop' frame to handle this scenario -- your code gets uglier, is less scalable and basically you realize that you have all kinds of potential logic problems.

    So avoid en queuing "Idle" -- let "Idle" come whenever your state flow ends.

    One way to avoid this is to have a 'flag' type of system -- Setup a Boolean called 'Waiting' and set the 'Waiting' flag whenever the user starts to Wait -- then, in the 'Idle' case, use the 'Timeout' frame of the event structure to check if you are waiting -- if you are waiting then do some work, if not, stay Idle.

    Here is an example of what I mean:

    Set the Waiting flag:

    post-5746-1225696763.png?width=400

    Check the Waiting flag:

    post-5746-1225696782.png?width=400

    Initializing and resetting the flag is left for the reader. One thing to consider -- since you have to reset the flag from at least 2 places (usually because the wait time has elapsed or 'Stop' button is pushed) -- it makes sense to have resetting the flag performed in a state (for example, based on your naming conventions -- 'Sequence: Stop Wait').

    QUOTE (jcarmody @ Oct 31 2008, 05:03 PM)

    I appreciate the time you spent on your response and I'll definitely refer back to your suggestions and take the advice.

    Good luck in writing better code! A lot of the time, good code is the result of good design. Entropy pretty much prevents good code from just being 'realized' by accident ;)

  16. QUOTE (jcarmody @ Oct 31 2008, 11:36 AM)

    :question: To the JKI folks & others that are familiar with the http://jkisoft.com/state-machine/' rel='nofollow' target="_blank">JKI State Machine, would you comment on what I've done? I've read the discussions here and on JKI's site, and I've (nearly) finished an application at work based on this (just working on getting Software Quality Assurance approval). I've gotten my feet wet and would like to learn more.

    I've added some states to let me sequence through test steps. I've added a "Sequence: Wait" step that causes the program to loop for a specified time so other operations can continue ("Sequence: Wait >> 10" will loop for ten seconds before continuing to the next step). I've added a "Sequence: Wait for button" that will wait until a named button is pressed during a particular test step. "Sequence: Wait for button >> pbx" will loop, holding this place in the sequence, until a button labeled "pbx" is pressed. I'll probably add the option to specify a final state using a command argument. It doesn't handle the event; it just waits until it's pressed. I've put a cluster of control references outside the main loop (so I can set indicators w/o resorting to local variables) and I've added target & elapsed time indicators to the Front Panel.

    Do you think I'm OK with these approaches?

    Thanks,

    Jim

    Hi Jim,

    I reviewed what you did. I have a few comments for various states in your state machine -- a lot of my comments would require re-designing the code so take try to think about them from the perspective of 'design' considerations rather than purely from an implementation perspective:

    Macro: Initialize -- While it is possible to use the state arguments for things like cycling through stations, and setting the wait times, it is not really a scalable solution. For example, let's say I want to have 100 stations -- I can't see scaling up Macro: Initialize to handle this situation -- so I'd try to redesign the code to handle N cases

    Sequence: Wait -- You may be doing too many things in this frame -- you are waiting, starting to wait and checking if wait is complete -- maybe more frames would make this easier to follow -- for example: Sequence: Start Wait, Sequence: Wait, Sequence: End Wait -- personally I don't like to have a frame do too many things or it gets hard to manage later because you have to remember what the frame is doing in a given context. You could also add a state variable boolean called 'Waiting' that could make the code easier to use in other cases... Also, generally it is a bad practice to have a state send the state machine to 'Idle' because at that point a user may click a button and your 'sequence' will get interrupted -- its better to do some work, when done, go to Idle case

    Sequence: Wait for button --This is actually not how the JKI State Machine is intended to check for button presses. You should handle all button presses in the event structure that is in the 'Idle' frame. You should be able to use the Boolean.Value Changed event to know when a button value has changed and the event will return the exact button-- set the boolean to 'Latch when released' to get the same results as what you are doing. There shouldn't be a need to 'find' the button that was pressed. For example , the Exit button (OK) is more appropriately set up.

    Sequence: Next station -- Really this is a 'Sequence: Increment station' case. Maybe a better solution is to have a 'Sequence: Set Station' case where the station can be an argument. Why limit yourself to incrementing?

    Good luck and hope this helps with future designs for your applications!

    Omar

  17. QUOTE (Aristos Queue @ Oct 22 2008, 04:11 PM)

    To help you visualize the situation... if all the green nodes in this picture are VIs under source and the red nodes are VIs under dependencies, and I ask for all the sourcenders of node E, then I should get B, C and F (marked with blue stars) as the result. There does not appear to be a word in English for these things.

    I'm not sure why B, C, F are the 'sourcenders' for node E -- I would have thought from your description that 'B, C, D' are 'sourceneders' and the word I would really use to describe them is 'intermediaries'. I'm confused why you are forced to make up words. I thought you had to be POTUS to do that ;)

×
×
  • Create New...

Important Information

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