Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by QueueYueue

  1. The following VIs aren't reentrant but should be: - JSONtext.lvlib:Format JSON Array Text.vi - JSONtext.lvlib:Parsing Error.vi - JSONtext.lvlib:Format JSON Object.vi - JSONtext.lvlib:Get all Object Items.vi - JSONtext.lvlib:Get Array Elements.vi - JSONtext.lvlib:Parsing Error in converting to LabVIEW type.vi
  2. This is opposite of what I would expect to see. Fundamentally if I give you a cluster with named items (who cares about the data type), I expect the JSON output to an object with fields matching the names of the clusters. All of this "variants have names" discussion is optimizing of weird LabVIEW shenanigans instead of a primary use case. +1
  3. Hey, Derek here. Stoked to see GPM came up. Couple of things I want to mention. The current GPM release is still a beta release. If you find bugs or want to request features, add them to the issue tracker. https://gitlab.com/mgi/gpm/gpm @ShaunR Theres a CLI and a GUI. The CLI will probably be used by CI setups, the GUI will be used by people. Eventually (though not currently) anything that you can do in one you can do in the other.(the "commands" that the CLI and GUI execute are just two different ways of executing the exact same business logic.) I know it needs to support distributing things like quickdrop plugins. I haven't quite decided how I'd like to do it, but I definitely realize it's something that's needed before a full on release. https://gitlab.com/mgi/gpm/gpm/issues/18 Yeah, @David_L I agree, +1 to the number of package managers sucks. Sorry :/ Back to the OP's topic: One of GPM's goals was to answer this question. If you have code that you want to give out for free, I think it should be trivially easy to do so. Using GPM, you just fill out the meta data, create an account on https://gpackage.io/ and then click publish. Once the command has finished executing you're good to go. It's published on the internet so anyone can download it. Someone who wants to use your code just needs to install it using GPM. If your code depends on other packages they'll be installed at the same time. It should be super easy (let me know if it's not!) Additionally, GPM package meta data has all of the fields needed to properly index your stuff and link back to your repo. This makes it easy for people to find your code, and contribute to it as needed. Happy to answer any more questions (or argue about design decisions =P)
  4. Use this snippet as your base if you need to do an arbitrary amount of cluster items. I can never remember how to do it, so I always crack open Ready Anything (from MGI's Read/Write anything) to see how we did it there.
  5. I've made some pretty cool changes to Monitored Actor that help expand it's capabilities. The main being the ability to override the UI. This lets you do cool things like create a web based actor monitor, or run the monitor window in the runtime environment. I also added Actor Labels to help you identify running actors. Check out our Monitored Actor 2.0 article for more info! If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Monitored Actor as well as some other tips for developers of large application (like MGI Solution Explorer, Class Method Browser and Actor Framework Message Maker)
  6. Good news, we've got a major update to the MGI Solution Explorer. You can now create custom solution items, which allows us to do cool thinks like create self extracting zip, or help deploy your solution. Check out our MGI Solution Explorer 2.0 article for more info! If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Solution Explorer as well as some other tips for developers of large application (like Monitored Actor, Class Method Browser and Actor Framework Message Maker)
  7. I gave a presentation at the America's CLA summit this year where I introduced the MGI Solution Explorer. Here's the link to the presentation information and some documentation (that will be expanded) for the tool. MGI Solution Explorer Info Feel free to post feedback here.
  8. I put together a series of articles while working on an AF 101 presentation for our local CLD summit. Check them out and let me know what you think or if you have any questions/improvements. Part 1 – The Background Part 2 – The Actor Part 3 – Launching and Communicating Part 4 – Being Productive With Actors Basic Walkthrough – Creating a Logger
  9. It's possible to use the path control to do what you want, but it's a little hack-ey. You end up making the path control transparent, then only making it visible when the mouse is outside the VI's front panel. See http://digital.ni.com/public.nsf/allkb/81D867F8C6A1376D86257347001BE936
  10. Helper loops are an essential part of any AF project. Helper loops do all of the heavy lifting of your actor, while messages are just the public interface for the actor. There are times when you can get away with just doing things in messages (like a file logger for example), but anything that's doing anything meaningful will probably need to happen in helper loops. The reason you don't create nested actors is because you need finer control of things like timing or execution order or whatever. With a helper loop you can make sure that the Idle message stops any PID messages, or that the PID checking happens every X ms or whatever.
  11. You definitely do not want to have you PID timing based on time delayed send or AF messages in general. Remember, a message is guaranteed to get there, but it's not guaranteed to be handled in any time. So if you have a "Check PID" message, but the "Log data" message gets in there before it, the log data will happen first, then the "Check PID" will happen as soon as it can after the logging is done. This could introduce a lot of jitter. Another design principal that you should follow when writing actors is that messages shouldn't take too long to execute. Obviously "long" is very subjective, but in general you shouldn't have a message for something like "Wait for pressure to build" since it probably takes a handful of seconds at minimum. This means that you Actor's thread is locked for that time. So you cant send it an abort message if needed, you cant stop the actor, etc. The easiest way to do long running tasks or time dependent tasks using the AF is to have helper loops. To do this you override actor core, and drop another loop on the block diagram. Now you need to create some communication mechanism (regular old Qs, notifiers, etc) to communicate between the message handler Q (which is what the Parent's actor core is) and your new helper loop. You'll probably store a copy of this reference in your private data so Messages can communicate with your helper loop. You're probably already done something similar to this when writing UI Actors. Your helper loops will probably look very similar to a traditional state machine. The only difference is this additional communication mechanism.
  12. I get what you're saying, and I think it is neither pre-alloc or shared re-entrancy. You want a hybrid. I think there would be a lot of design decisions to be made with what you're suggesting. I feel like this would end up with new clones being allocated when you didn't expect it, sometimes a new clone wouldn't get allocated when expected, etc. Rather than forcing us to learn there rules (it's already hard enough with two re-entrancy types) it's just not available. You can do this on your own however. You can make all of the somewhat-arbitrary design decisions on your own, just follow drjdpowell's advice from earlier: But i'm telling you, you're setting yourself up for confusion and memory leaks. I think my pattern is better.
  13. Zyl, You're close to understanding it correctly. Here's how I think about re-entrancy. Pre-allocate -> VI is allocated during compile time. Shared -> VI is allocated during run time. So..... Correct. I don't understand what you mean by this. Re-entrancy does concern the way you launch an execution AND how you manage the memory allocated with the previous launch. Shared clones are launched from a clone pool. So when execution needs a clone, it asks the clone pool for one. If there is one available, it gets it. If there isn't one available, the clone pool creates one for you. When you're done you return the clone to the pool. You have no control over which instance you get from the clone pool, it decides. This is why the uninitialized shift registers don't work as expected. You're expecting to get the same clone back every time, but the clone pool manager gives you back the first available clone. With pre-allocate you're linking to specific instance of the clone. There is no clone pool stuff because you're saying "I know I'll need this here so create it up during compile to save some execution time" So why can't you pre-allocate a dynamic dispatch VI? Because to pre-allocate you need to link to a specific instance of the VI right? To know the specific instance you need to know the runtime data type of the class coming in, which we don't know. To make pre-allocated work you'd need to allocate (at compile time) memory for every possible VI that could be called. This means that if you had a 2 child classes you'd need to allocate memory for 3 VIs (one for the parent and one for each child). Now what do you do if one of the child VIs calls the parent's implementation? maybe that should be allocated up front? Now what happens if you dynamically load a class in a plug in architecture? You're code would need to be recompiled to add the memory for that new class? See how we're running into all of these weird situations, all of which would required allocating a bunch more memory? Maybe it's possible, but it's not efficient, and it'd possibly introduce a whole slew of other complicated design decisions. So that's why you're not allowed to do it.
  14. You're in a race-condition. You get shared clones instantiated as needed. That means if you have two objects that both call the same VI, sometimes they'll get the first instantiation of the VI, sometimes they'll get the second. LV decides which. Take a look at the example it illustrates it. The VI who's ref you create is going to have a common connector pane across all classes. This means that if you have a child class, the input terminal will have to be of the parent's type. so you'll have to do a cast if you want to access any of the child's data. Either that or you'll have to use "Set control by name" invoke nodes, which I avoid at all costs. Attached is a 2012 version of my example. Pealloc Testing 2012.zip
  15. Ohh man, lots going on here. I made an example using references. Calling NI's VIs by ref is what I'm talking about. There's no difference in newer versions of LabVIEW. The reason you cannot call a dynamic dispatch VI by reference is because a reference points to one VI. Dynamic Dispatch, however, means you don't know what VI you're calling until runtime (and by runtime I mean right before the VI is called). What if you open a reference to Class A's Implementation of a method, then you wire Class B to the input? They both have the same connector pane. What if you open a reference to the parent's implementation, but then wire in a child? You need to call the Child's method, but you have a reference to the parent's. There's a bunch of situations where you'd be trying to call the wrong implementation on the wrong class, so that's why you get a broken run arrow. In response to the number of references: Who cares? Store all of the references inside the class data, and then give that class a "cleanup" method. Done. Opening a lot of references is no big deal as long as you close them. It'll work, but I'm pretty sure you'd have to do some casting to get the control panels to line up. See my posted example for a cleaner (IMO) implementation that's pretty similar to what you're suggesting. This has almost nothing to do with LVOOP. If you called a pre-allocated VI inside of a shared clones VI in any instance you'd have this problem. This is an advanced feature that needs some extra thought by the programmer. About the example: Open "Test VI.vi" and run it with "Call By Ref?" set to False and run the VI. Notice string 1 and string 2 are changing. They will flip flop based on which instance they happen to get (it's a race!) Stop the VI by clicking the stop button. Now set "Call By Ref?" to True and run the VI. String 1 and String 2 will now get their own values that stay the same. Take a look at the code, most of the magic happens in "Test Class.lvclass:Test VI.vi" (note: This is the re-entrant shared clones VI). On first call (for that object) it opens a new ref to the pre-allocated VI, and on subsequent calls it just uses the reference it already has open. Let me know if you have questions. Pealloc Testing.zip
  16. You're right. You can't use un-initialized shift registers like you want inside a shared clone VI. This does mean that if you put any of NI's VIs which use pre-allocated re-entrancy inside your shared clone VI you will be screwed. And since you're forced to use shared clones with Dynamic Dispatch VIs, you're double screwed. All and all, this means that data that needs to be stored between calls needs to be placed in the object's private data. It will now live on the shift register and the clone will just use the data, instead of storing the data. If you were writing the code from scratch, this would be no big deal, but since you're using NI's code, it becomes a pain. What I ended up doing is writing my own version of NI's VIs (typically started by coping and pasting) that strips out all of the shift registers. I think (I've not tested this way) you could also open a VI reference to the VI, then use a call by reference, and store the reference in the objects private data. I'd have to play around with this way though. It's annoying, and honestly, I think that NI should go back and give us a version of their VI's that don't have shift registers in them. Obviously this is a lot of work without much return, so I don't blame NI for not doing it. And that kids, is why you don't use globals unless you're 100% sure you need them and there's no other way.
  17. Two ways to do what the OP is asking. 1. VI Server world: Children have a static link to their parents and Parents have a dynamic link to their children. This means that once a class is loaded into memory, the parent knows about the child. According to the documentation this will NOT work in the runtime environment, but i've used this several times when making IDE Tools. 2. Runtime Reflection: The following code will also give you an array of all of the children loaded in memory, but this time it uses less VI Server so it will work in the runtime environment. I use this when using a plugin architecture. I've not done a lot of performance testing with it, but on a medium-ish size project (one with ~150 classes) it only takes about 50 ms to run, so it's worked well for me so far. Having given you those solutions, I still think your best bet is to use a statically defined array. This will ensure things are loaded into memory when their needed and such. My solutions really only become worth it once you're dynamically loading classes.
  18. Thanks for the help. The 32 bit/64 bit registry is what was throwing me off.
  19. I'm working on an automated builder. I'd like to be able to know all of the installed versions of labview on the system. I can use the "Get Installed Software" VI in nisysconfg.lvlib, but that gives me names and ID and stuff, and what I really need is executable paths and VI Server ports. Anyone have ideas? What good is this ID GUID-looking value?
  20. Two things: 1. Webservices changed a lot in between LV2012 and LV2013. I think you're looking at a tutorial for LV2012, but you're working in LV2013. That's why you're not seeing the webservice option in the build specs. 2. It sounds like you'd like to consume a webservice from labview. The tutorial you're looking is for hosting web services in labview. To consume restuful webservices in labview you should be using the HTTP Client
  21. I'm not sure I fully understand your setup, but if you have a .NET assembly compiled as a dll, you should be able to call that using the normal labview .NET interface on the connectivity pallet. Checkout https://decibel.ni.com/content/docs/DOC-9138 for a quick example.
  22. I have an application that records video and DAQ data at the same time. The user clicks the record button, then does their stuff, then clicks the stop button. Now I want to generate an output AVI that displays the graph data side by side with the recorded video. (I have the DAQ data in a TDMS and the video saved in a temp AVI). My problem is, how do I get an image of the graph? Here are the solutions I've come up with: 1. Have a graph control in a separate VI. Set the graph to the DAQ output, then use the "Get Image" invoke node to get an image Pros: Looks great. Easy Cons: Heavily uses the UI thread. 2. Have a graph control in a separate VI. Set the graph to the DAQ output, then use the "Export Image" invoke node to get an image Pros: Slightly faster than option 1. Easy Cons: Heavily uses the UI thread, Doesn't look particularly great (but not bad). Only slightly faster than option 1 3. Use the Picture plot toolkit Pros: Does not use the UI thread Cons: Looks terrible. A lot of work to get looking decent. Looks like no one at NI has looked at these in a long time (they use deprecated subvis). VIs aren't reentrant so cannot parallelize. Here's what I want: A decent looking plotting package that I can run in a paralleized for loop. I'm currently using option 1, and it takes forever to generate the video (2x-3x the length of the video @ 15 FPS). I can't paralellize it because it uses the UI thread. It also noticeably affects the program when running in the background. Does anyone know of another LabVIEW way to accomplish this? My only other idea would be using the .NET, which would step up the difficulty significantly, but maybe get me the performance I need.
  23. I'm not gonna lie, I found this and read it, but I must have gotten confused because everything is named so similarly.
  24. If you want to go the NI route.... I've recently been dealing with the headache that is Vision related licensing. Here is what I understand it to be. The terminology is VERY confusing, so you'll have to deal with me. IMAQ VIs - These are VIs used to get images/video off of NI cameras. These are free to use (development and runtime), but again, they only work with NI hardware. IMAQdx VIs - These are VIs used to get images/video off of ALL other cameras. Your webcam falls into this category. This requires the Vision Acquisition Software (VAS) license to develop AND Deploy. These cost money Other IMAQ VIs - some of these VIs are free to use without any license (such as IMAQ Create), others are not (such as ImageToImage). The licensed VIs require the Vision Development Module to use in Dev mode, and the Vision Development Module Runtime Engine (I like the way they got development and runtime in the same title) to use in Runtime mode. These both cost money. I don't know of a good list that says X vi needs a license and Y vi doesn't. There are times when you buy one license and get another for free, but I don't stand of chance of figuring out what's what. It's best to call NI support or talk to your local sales guy for help. http://digital.ni.com/public.nsf/allkb/F1699570F78FECBB86256B5200665134 tldr (for the NI route); There is no free way to get images from a webcam into labview. The non-NI route.... I've gotten images from a webcam into labview using non-NI code. OpenCV is a popular one, but I've never used it. Basically my strategy was "how would a C# programmer access a webcam". I found some code on the internet that I was able to modify into a C# DLL that I could call from labview. I did this a few years ago at another company, so I can't give you and example or much more info. I'd describe this as a pretty advanced task, and not something that I'd recommend to someone who was new to labview, unless they had a good amount of C# experience. The only reason I did it was because we needed to put webcams on 100+ machines, so that means it would have cost $50000+ in licensing. I was able to put something together that did our super small set of tasks in about a week or two. If you're only doing this for 1 machine, just pay NI.
  25. Yes you can. You just have to use a template method pattern AQ has written a lot of good info here about why you can't (and wont be able to in the near future) have dynamic dispatch DVR terminals http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Have-Dynamic-Dispatching-terminals-accept-Data-Value-references/idi-p/1054410 ParentChild DVR.zip
  • Create New...

Important Information

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