Jump to content

Mark Smith

Members
  • Posts

    330
  • Joined

  • Last visited

  • Days Won

    5

Everything posted by Mark Smith

  1. I'll throw out another option here - I have found the "Read Anything" and "Write Anything" VI's from MGI to be extremely easy to use for simple ini operations. All you have to do is create the cluster (a type def is best) with the controls you want to write to and read from file. Wire the cluster to the "Anything" input of the "Write Anything" VI and run the VI. There's your ini file. To read the file, wire your type def'd cluster to the "Type Of Anything" control on the "Read Anything" VI and then use the Variant To Data function to convert the returned variant to the original cluster The VIs are free at http://www.mooregoodideas.com/File/index.html Mark
  2. This sounds similar to a problem I had (about LV 8.2/8.5 - that's the latest version I was using when I worked on that project) so this info might be useful. What happened is that the exe had a call to some public member of a lvlib. So the exe build, in the interest of keeping the size down, only included the lvlib members that were called and also modified the lvlib "table" or whatever keeps the lvlib info in the executable to only include the members actually called. Then, when I included members for the same lvlib in an llb called dynamically, the exe had already read a lvlib "table" that did not include the members in the lvlib in the llb and decided that those members called were not part of the lvlib and threw a similar error. It was the kind of error that will make you absolutely crazy, since it requires knowing how the exe builder treats the lvlibs. The "fix" was to explicity include all of the lvlib members in the exe build so that "table" would recognize the ones in the dynamically called llb. Kind of breaks the "plug-in" concept since you have to know when you deploy your exe everything you might call in the future that's in a lvlib. I don't know if newer LV versions treat this the same way. Mark
  3. I know any time one makes a blanket statement about any architecture being "good" or "bad" that there's room for real disagreement - I don't use QSMs but I am sure that there are people (like Joe) who know exactly what they're good for and how to make them work so they shouldn't be dismissed out of hand. However, I will take exception to the statement about the licensing limitations of LuaVIEW (can't speak to TestStand - I don't use it). With LuaVIEW, the license is per project (or a site license, which I have). At any rate, all deployed apps built under this license are covered under the development license cost - no additional deployment license required - and all developers on the project are covered under the single license. Also, all license management is "honor system" - there's no license management software mucking things up so you don't have to worry about licenses expiring at your customer's site (or for your developers) and getting those angry phone calls. Also, the entire Lua interface is accomplished thru a CIN so there's no additional dll's or run times or anything else that needs to go with the deployment. It's really pretty simple. Mark
  4. So, to me this type of QSM is really just a huge function library where 1) the function calls are the case names 2) the queue becomes the "script" that defines what function is called The problems here are that 1) There may not be any explicit arguments (or there may be, if the queue contains variant data or such) but there are probably many implicit arguments to each function (case) and they're often hard to track down 2) There are probably no explicit return values to the function calls (if you're luck there's at least error handling) but there's lot of data generated or changed 3) The script is not immutable - the queue (script) could be changed at any point in the run sequence (at runtime) and you can't usually tell what might or did change the queue by examining the queue itself. Self-programming applications can be kind of cool but they're not typically suited to reproducible, reliable test and measurement software. So, I think the most one could do in documentation is treat this "state machine" like a function library and document what each function (case or "state") does - as you've already realized, you can't possibly document every flow thru the "states" since one could easily write code that puts functions on the queue in an endless, random loop. If that's not adequate (you have to know what the sequences will be) then throw away the code and start over. And don't let those guys use QSMs again! If you need a test sequencer, try TestStand or if you want to script your applications (which I prefer) LuaVIEW is great. Mark
  5. Well, one approach would be to make specific implementations that inherit from an interface class for everything that gets indexed in the for each loops. So, you have a parent DUT class that all of the unique types of DUTs (four?) inherit from. Then the next for each loop invokes the correct test methods on the DUT. It appears here that the TestCase would need to know what kind of device is being tested - I would propose that it might be better that each DUT (and here I mean the DUT object, not the actual physical device) knows which tests need to be performed on it and contains those tests in a collection. So the sequencer program flow would be almost the same, except it might look something like foreach deviceUnderTest in devicesUnderTestCollection foreach testCase in deviceUnderTest.TestsCollection testCase.Execute() next testCasenext deviceUnderTest The if-thens aren't really needed - if the deviceUnderTest isn't part of the collection, it doesn't get tested and if the testCase isn't part of the deviceUnderTest tests collection it doesn't get executed. Now, the test case knows that it is a member of a specific device's test collection and it can get private member data about the DUT without passing any parameters as function arguments. This could include data from the calibrations file(s). As far as data format, unless there's strenuous objections to XML (it's sometimes debatable whether or not it's "human readable"), use the LabVIEW flatten and unflatten from XML functions - these can serialize the data structures or the objects depending on what you need. Mark
  6. OH! OH! - I actually have a useful answer (as opposed to my earlier post) to this one because I do the same thing with classes. I have an ErrorLogger class that has three public methods - Start Daemon, Stop Daemon, and Enqueue Error. Any time you want to start logging errors, start the daemon, To log an error, just drop the Enqueue Error VI in the error wire. When you want to stop logging errors, just call Stop Daemon. The daemon opens a ref to the error queue and starts waiting for anything on the queue. The Start Daemon vi has controls that let the user set the path to the log file, the max error log size (it starts throwing away old messages when the max size is reached), and whether or not enable error dialogs. The Enqueue Error vi just has error in and error out terminals - it gets a ref to the error queue by name and closes it when it exits. The Stop Daemon just has error terminals (all of my VI's have error terminals) All of the other stuff (like whether or not the Start Daemon has to create a new directory to create the error log file and the daemon itself) is in the private methods of the class and the user needs never worry about any of that. The HUGE advantage of this approach over a single action engine is that the Enqueue Error vi is reentrant - one part of the code can be spewing errors and logging them (and my code often does ) while another part of the code that also could log errors isn't blocked waiting on the AE. Mark
  7. If you really don't like wires there's always C++ (ducking for cover now).....................
  8. I hope that's not what I said, because that not what I meant. I mean to say that including instructions - in the typical case - to "judge the case on the facts presented in the courtroom, and oh, by the way none of that matters if you disagree with the law that the defendant is accused of" won't help the case come to any kind of conclusion. It's just a recipe for a mistrial and more taxpayer dollars spent on retrial. This isn't an argument for more laws and government - it's just an argument for having a consistent legal system so everyone knows what to expect. Mark
  9. I think this is the crux of the matter - if a law is clearly unfair and "unjust and morally despicable" then we do have a responsibility to do the right thing and juries can and have nullified those laws. But instructing juries to consider "jury nullification" in a case such as the one mentioned in the original post to this thread, where there is no indication that the law is "unjust and morally despicable", seems ill advised. Mark
  10. I've avoided these kinds of threads until now, but I'll ignore my better judgment and offer an opinion here. There's a word for a court system that allows (and maybe even encourages) "jury nullification" - it's called anarchy. Our legal system (I'm here in the US) would completely fall apart if every jury were encouraged to "vote their conscience" when deciding guilt or innocence to a specific charge or set of charges. If a jury can effectively re-write the law whenever they see fit, then none of us can possibly know which laws we should follow, which we should ignore, and which we should expect our neighbors to follow (is it now OK for our neighbor to come "borrow" our car without permission because he might find a jury that sincerely believes all property is communal?). Our system of laws provides each of us a frame of reference in which we make choices based on expected outcomes. If this frame of reference is constantly shifting, we have no idea what to expect and cannot make intelligent predictions about the consequences of our decisions. One could extend this argument to all sorts of bizarre and admittedly unlikely scenarios but the argument is this: if a jury of 12 (or in many cases, even less) can simply ignore any law they don't like when deciding guilt or innocence there's no point in writing laws in the first place. And for the specific case given - we all read news stories about arrests and indictments that don't seem to make any sense. Often, these are a case of practicing "defensive" law enforcement like doctors have to practice "defensive" medicine. If the officer doesn't make the arrest or the prosecutor doesn't make the indictment and something terrible happens later then they will be second guessed and maybe even subject to criminal prosecution themselves. For instance, maybe this person was just taping a birthday party - or maybe they have a side business of posting and selling new release movies. That's why we have a court system - to sort these things out. Mark
  11. I'm guessing you're using the state of the action engine to save configuration state? If so, an approach I've used that works well in OO architecture is to once again use a single VI for entry into the shared resource and then create classes (could be subclasses) that expose just the stuff required for a specific test - or alternately, methods for each specific test in a common class. Each method/class can include an action engine wrapper that just maintains state for that specific test's configuration. The main entry point still maintains state for the configuration of the entire resource and the specific test wrappers just expose the properties necessary for that test. And there's still just one main VI (shared by all of the classes/methods) that acts as the "gatekeeper". Mark
  12. Don't make this problem harder than it is! This is one place where LabVIEW's dataflow and default subVI calling mechanism make things easy. Just put the access point for the shared resource in a single, non-reentrant VI (this can be a method in OO architectures) and you're home free - no other call can access the resource until the previous caller is finished with it and all the calls will wait until the resource is free and then execute (essentially queue up and wait, except that you can't be sure exactly which will get to use freed resource first). Mark
  13. I'm a little late to the party here, but I'll put in a vote for LuaVIEW. I have found this to be a very powerful tool for writing Lua scriptable applications for deployment (and I don't mean LabVIEW scripting). I use an object oriented LabVIEW framework for building code that encapsulates the test equipment (and collections of test equipment) for stimulus and measurement and includes classes for data persistence, evaluation, and reporting. I then use Lua (in the OO style calling convention) to build scripts that are specific to particular tests. The heavy lifting gets done by LabVIEW, and the scripts can be very lightweight. One huge advantage to this approach to my customers is that the deployed app is now scriptable in a language that feels mostly natural to them (most of my customers are in R&D type environments and are scientists and engineers and know languages like Python, Perl, etc). They don't need LabVIEW to modify tests or experiments - and couldn't use it any way, since they don't have the source code on the testers - and there is no additional licensing fee (there is a license fee for the development toolkit) for the deployments. So they can tinker as much as the project API allows - the API is the set of Lua callable LabVIEW functions I expose plus the Lua callable LabVIEW functions LuaVIEW exposes plus the entire native Lua 5.0 language (which is Turing complete) - without me having to worry that they mucked up my source code. Heres' an example ----------------------------- test function -------------------------- function testOne() -- create objects - uses unique names and an action engine to -- create by-val objects that are retrieved by-ref powerSupply = PowerSupply.new("powerSupply") powerMeter = RF_Power_Meter.new("powerMeter") dataSaver = DataSaver.new("dataSaver") -- configure objects - I use LabVIEW clusters/classes flattened -- to XML because they are easily embedded in a text script powerSupply:configure([[ <Cluster> <Name>UUT Power</Name> <NumElts>5</NumElts> <String> <Name>Description</Name> <Val>Configure UUT Input Power</Val> </String> <Refnum> <Name>Power Supply (Agilent E6644) VISA Resource Name</Name> --6038A <RefKind>VISA</RefKind> <Val>GPIB0::5::INSTR</Val> </Refnum> <DBL> <Name>Voltage</Name> <Val>28.00000000000000</Val> </DBL> <DBL> <Name>Current Limit</Name> <Val>2.00000000000000</Val> </DBL> <EW> <Name>foldback protection (0:off)</Name> <Choice>off</Choice> <Choice>constant voltage</Choice> <Choice>constant current</Choice> <Val>0</Val> </EW> </Cluster> ]]) powerMeter:config([[ <Cluster> <Name>RF Power Meter</Name> <NumElts>5</NumElts> <String> <Name>Description</Name> <Val>UUT Power Measurement</Val> </String> <Refnum> <Name>Agilent E4418B VISA Resource Name</Name> <RefKind>VISA</RefKind> <Val>GPIB0::13::INSTR</Val> </Refnum> <I32> <Name>Unit A (0: dBm)</Name> <Val>0</Val> </I32> <DBL> <Name>Lower Limit A (-90.00E+0)</Name> <Val>90.00000000000000</Val> </DBL> <DBL> <Name>Upper Limit A (90.00E+0)</Name> <Val>90.00000000000000</Val> </DBL> </Cluster> ]]) powerSupply:apply() -- applies power to the UUT power = powerMeter:measure() -- take a measurement - RF Power in this case dataFile:writeObjectAsXML(powerMeter) -- save the data taken by the powerMeter powerSupply:remove() -- remove power from the UUT return power ------------- end of function ----------------------------- -- the test script calls the functions --#import c:\scripts\functions result = testOne() if resultOne >= someLimit then -- if we pass the first test repeat result = someOtherTest() -- this test loops until the limit is met until (result < someOtherLimit) end ----------- end of test ------------------------------------ The XML configs can be edited in the text editor (I use SciTE since it's free and Lua syntax aware) or I have an app that parses the script, extracts the LV clusters, and loads them into their respective controls for editing. So, the specific tests become functions that get called in the main script - the main script (and functions) can have any feature of the Lua language - control structures, math functions, system calls, file IO, etc. It's powerful, flexible, and relatively easy to maintain. This approach lets LabVIEW do what it's best at (instrument control, DAQ, threading) and lets Lua do what it's best at (imperative, easy to read and follow test directions). New functions can be deployed to the API without changing the exe (plug-in style). Mostly I just wanted to present this as an alternative to TestStand (disclaimer - I have no interest in LuaVIEW other than as a satisfied user and I have very little exposure to TestStand, so maybe I've completely misinterpreted what TestStand does). And don't read this as "TestStand is bad" - I don't know TestStand but I think NI in general puts out quality products. I am a LabVIEW user, after all Mark
  14. The problem is that Firefox never gives me a chance to do any of that stuff - it just opens the .lvproj file as XML in the browser. I think one might be able to hack the Firefox .rdf file and get this to work, but that's not very useful for my customers. This type of link works fine in Internet Explorer (at least version 6 - that's the latest I've got at work) so I think that maybe this is just a bug in Firefox. It makes a decision about the data as soon as it sees the XML tag without allowing for any other interpretation. Thanks for the link, Mark
  15. Not a LabVIEW Problem!!! Read at your own risk I have created a LabVIEW application that creates an HTML page for documentation purposes (modeled after doxygen) for my LabVIEW projects. I have included links that allow the user to click the link to a VI and open the source file in the development environment. This works fine and opens the Firefox "open with" dialog and I can then use LabVIEW to open the VI. However, I also have links to the LabVIEW project and class files (.lvproj and .lvclass extensions). The .vi extension is a binary, but the .lvproj and .lvclass files are xml. Firefox opens these links as text without ever opening the "open with" dialog and giving me a chance to select the LabVIEW IDE to open them with. How do I get (can I get) Firefox to not open these as text and instead give me a chance to use the IDE to open them? Mark also posted at http://support.mozil...forum/1/509984?
  16. Maybe you don't need to convert a LabVIEW object to a .NET object. I'm not sure exactly what you need, but if you just want to use the Property Grid control in LabVIEW, that can probably be done. Check out these links http://zone.ni.com/reference/en-XX/help/371361B-01/lvhowto/create_dotnet_controls/ http://zone.ni.com/devzone/cda/pub/p/id/230 Mark
  17. Don't have any workarounds or explanations, but I can confirm that LabVIEW can be pretty annoying in the way it gets handles and never seems to let them go until you close LabVIEW. This behavior has been around as long as I can remember. I usually see it when I want to delete a folder that LabVIEW has accessed at some time and I can't do it until LabVIEW has closed. Mark
  18. ...Or any of the Colorado fourteeners. The last one I (almost) climbed is Sunshine Peak - got almost to the top but the last couple of hundred feet was just too technical for me, since I am a hiker and not a rock climber. This took a couple of days since the hike to the base of the mountain is about ten miles from however you come in. If you just want to climb steep hills (and see gorgeous views) Yosemite Falls will do the trick. The trail is essentially a 3,000 foot tall stairway! Mark
  19. To look at the TCP/IP traffic, Wireshark is the defacto standard for Windows http://www.wireshark.org/ As far as setting the IP address on the server (I think that's what you mean), you can use Control Panel->Network Connections->Local Area Connection and then right click for properties and change the IP address to a static one. Lastly, the XML-RPC project in the Code Repository http://lavag.org/ind...ads&showfile=66 has an example of a LabVIEW server. Mark
  20. Thanks once again. This does explain what is actually happening. The VI knows it's part of a library but it appears that only the library knows the VI's scope. I thought from that original snippet from AQ (from the linked thread) that the VI also would know and might be able to report its scope, but apparently my interpretation was incorrect. Mark
  21. Thank you ... LAVA to the rescue! This will let me do what I need. I'm still interested to know if could get the access scope directly from a VI ref to a class member. Mark
  22. I need to get the access scope of a VI programmatically - I'm creating a tool to produce documentation for my classes and I want to know whether or not a VI is public or private. If it's private, then I don't need to add it to the documentation since the developer will never use it directly (If someone already has a tool to do this sort of thing, I'd love to see it!) I searched the forum and found this thread http://lavag.org/top...__fromsearch__1 where AQ says "Asking a VI "are you a private VI" is easy enough -- use the VI ref to get the lib item ref and then ask for scope, which will take care of checking virtual folder settings. " Except that the Get Source Scope method also wants a source ref (type is ProjectItem). How do I get this ref? Do I need to open a project and find this particular item? Or is it exposed somewhere else? Thanks, Mark I'm using LV 8.6.1
  23. Uncle! Uncle! - I don't often use queued state machines either - it was just an example What I do use is lots of asynchronous code and lots of VI server calls to start the VIs in new threads and return - it's required by the nature of my current projects. And I never need more than one event handler per BD because the event handler always returns rather quickly. And I can leave the "Lock Front Panel Until This Event Completes" option checked and LabVIEW will prevent the user from clicking anything else until the event handler is ready - and that's all I have to do. Since I am simple-minded, I tend toward the simple solutions Mark
  24. As usual, there is no "wrong" or "right" answer - only shades of gray...... But here's a couple of reasons to consider decoupling the actual "code that does something" from the UI 1) Responsiveness - if you have any action that takes a long time and your program is capable of doing something else (safely) then it's best to let the user continue to interact rather than locking them out and making them wait. For instance, an app that takes data for a long period (more than seconds) might be quite capable of loading and displaying previously acquired data sets while it takes new data. 2) Flexibility - if you have a state machine, for example, that can be queue-driven then you can call it in many different ways. If your state machine is effectively coupled to your UI, that's about the only way you can make it run. Having the "stand-alone" state machine makes it much easier to automate, both for test and deployment. But sometimes it does make sense to just have the code in the event-driven UI, like a data viewer, for example. Here the only use case is human-driven interaction so there's no sense in mucking it up with anything complicated. But I would still argue that if you find yourself needing multiple event handlers in a UI, then the UI is trying to do too much and the program logic needs to be separated from the UI (like the Controller in Paul's example). Mark
  25. So, I think I understood the question and I still would avoid two event structures on the same BD. The reason is because every time I've gone down this rabbit hole ("Oh - we forgot to tell you we need an Abort button!") I've ended up doing your alternative two and building some sort of asynchronous message handler so the event structure never blocks. The only other thing that I've used that might be useful in your case is to launch a dialog panel on entry into the blocking case that exposes an "interrupt" button and handles queuing up the message to the state machine. This might even be as simple as adding this button to the blocking VI and then opening its front panel. Just my observations - ymmv Mark
×
×
  • Create New...

Important Information

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