Jump to content

QueueYueue

Members
  • Posts

    68
  • Joined

  • Last visited

  • Days Won

    7

Everything posted by QueueYueue

  1. 1. The DVR is created in the parent's code because creating the DVR is part of the common code. For the most part, the child should never have to deal with DVRs. The parent class does all the DVR related tasks. 2. Even if the child creates the DVR, the reference's lifetime is tied to the top level VI that created it. You're going to still have to use an Async Call VI method (which will at some point call the create DVR method), so that's what will control the lifetime of the reference.
  2. I'm not exactly sure where you're having the trouble. There are a lot of ways to do this. I'd say you should first take a look at how to use Multiple Plot graphs and charts (in the detailed help of the Chart control). There are example VIs with these. Now you should be able to use the code that you already have to read from 1 serial port in a For Loop (each iteration of the for loop will read from a different serial port) to acquire all of your data. Now you just need to put the two together.
  3. This is a common issue when working with by-ref objects. The way I solve it is by making static VI called things like "MyAction" and then making a Dynamic dispatch VI named "MyAction-core". All "MyAction" does is de-reference the object, call "myAction-core" and then updates the DVR value. Also, if these are actions that HAVE to be performed, I'd just throw the common code in "MyAction", and then let the children override "MyAction-core" to implement the code that's specific to them. This eliminates the need for children to call to parent. I'm not a big fan of requiring a call to parent, because I find most of the time it matters if the child calls to parent before or after running it's code. So you end up having to put in documentation "Make sure the first thing your child code does is call to parent". This is bad. Basically what I'm saying is a lot of time when people (and I think you in this case) are checking the "Require Call to parent", what they really want is a Template Method pattern. http://en.wikipedia.org/wiki/Template_method_pattern
  4. This only addresses the AF part of this questions, but my Monitored actor tool helps with problems like this. It basically gives you a UI (in the dev environment only) that lets you see actors currently running. It also gives you some hooks to aid debugging. This lets you send stop messages to actors that you've forgotten about in your code or open a running actors Actor core instance. Checkout the package posted here https://decibel.ni.com/content/thread/18301. once installed you just need to use the "monitored actor Switcher" tool in your tools menu to change your current actors to monitored actors (note: this is just changing the inheritance. Instead of inheriting from actor, you'll now be inheriting from monitored actors(which inherits from actor). It's not changing any of your code)
  5. My gut reaction is to throw in a third item. Probably a notifier. It'd be a "something's ready" notifier. You consumer would sit idle waiting on this notifier, then when it got a notification, it'd dequeue/get notification (both with timeout 0) and figure out what was sent. When you enqueueu/send notification, you also hit the "something's ready" notifier. I think AF's priority messages handle a similar situation. I've never looked too in depth into the implementation, but it's got a bunch of queues under the hood. It'd probably be worth checking out
  6. Create a property node for the tree and set the following properties (in this order) Active Cell.Active Column Number = -2 (this selects all columns) Active Item.Row Number = -2 (this selects all rows, including the column headers) Active Cell.Background Color = Desired color You may have to play with it a bit to get everything exactly right, but this should get you started. Set Active Item.Row Number = -1 to color just the column headers. Also remember property nodes are executed top down, this is why order matters
  7. Dare ya to use a callback to handle a filter event. (save your code first) Talked to an AE about this once. He gave me a "I guess i'll file the CAR, but you shouldn't be using callbacks for LabVIEW events."
  8. Compile time: Yeah, sometimes. Hours is being a bit dramatic. I'm pretty sure this is a symptom of LVLibs, not just classes. If you watch your relationships right, you wont see this. Boiler plate etc: Sounds like you're doing it wrong. AF Do msgs have a lot of boiler plate, most OO code does not. If you find yourself with a lot of boiler plate then you need to rethink your design. Other languages file for every function: Non-OO Labview does this too. And again, Why should I care if there's a lot of files on disk? Things are organized in the project appropriately, so I really don't care how many files are in my project. Thread's drifting so hard.
  9. Just want to make sure I have this clear in my head: You have two main components in your system: Measurements and Devices. A measurement will use a device to get some data and process it, right? The rest of my post is assuming this is correct. The most important (imo) thing OO helps you enforce is encapsulation. This means you should be thinking about the interface between the two classes (measurements and devices) not exactly how it works. What does the measurement need from a device? For this example, we'll say it needs to get data from it. Ok, that means it needs a "Read Data" vi. How does it get this data? The measurement doesn't know (or care), it just knows that when it calls this method, it gets data. Perfect. There will be a top level VI that will configure all of the devices. This will do things like setting serial ports, initializing, etc. Stuff that needs to be set or run once. After it's done all this configuration, it will pass the device objects (by value) to all of the different parts of the code (meaning to measurements). Measurements aren't allowed to do things like change the serial port or close the port or whatever because there are no public methods to do this. Again, we use the access scope to limit what other pieces of code are allowed to do to the object. How the Device class will work. The device class will have a DVR in it to the data I needs to share between all measurements. When you initialize the device, you create this DVR. This DVR will never be exposed by a public method. So maybe all the "Read Data" method we defined above does is copy the data from the DVR to the measurement. Sounds OK. We'll assume somewhere else in the code is periodically calling something like "Read from Device" which is populating the DVR. This means N different measurements can all be reading the data from the same device at almost the same time. There will still be some waiting going on while the DVR is getting accessed by each "Read Data", but since only the Device has access to the DVR, we can ensure that we only do things that are quick (your Action Engine does the same thing). This means that the responsibility for ensuring that there are no deadlocks now falls on the Designer of the Device class (you), not the users of the Device class (the students). This is why encapsulation is so good. If people are also writing code for devices, I'd also give them overiddable methods (using the protected scope) for the actions that they need to implement. Again, I'd keep them from ever seeing the DVR. So now if you have two identical devices, you just instantiate and initialize two of the same classes. Give them different serial ports (or whatever data is different between the two) and then pass these device classes around. You can branch the device class wire all you want, you're still going to operate on the same data. 2 followup notes: 1. You say you're looking for an OO design pattern that works for your application. I think you're thinking of design pattern like Project Templates. Design patterns are small building blocks that you assemble as you need for your application. For example, I'd probably use the Template design pattern when implementing the "Read From Hardware" vi. Read From Hardware would be static, it would have an overridable method named "Read From Hardware core" that would output data, and I'd write that data to the DVR. Now when you implement a device, you have a small number of methods to override but you'd still get a lot of functionality. This also helps me make sure I don't give the DVR to someone who may mess it up. Maybe I'd also use the Factor pattern when building the devices in the application. I'd use the ideas from the design patterns to build up together for my specific application. 2. By ref (either with GOOP or DVRs) and Action Engines both can cause dead locks. If you want to eliminate deadlocks you have to either use global variables (which now introduces race conditions) or properly design your system. Action engines make it fairly easy to properly design it to avoid deadlocks. DVRs take a bit more thinking but get you a lot more benefit. I stay away from linking this to people, especially those new to the OO scene. It's pretty complicated, and accomplishes a very specific task. It's like teaching a new C programmer how to write a web server when they really need to learn hello world. I'll argue that you increase the number of VIs in exchange for code readability. I'd much rather see a well defined interface to a class being used versus an enum going into a case structure with a ton of cases. Add in a variant that needs casting, or a cluster-saurus where only some of the fields are valid based on the enum and classes are way easier to read. Easier to read = Easier to debug = easier to maintain. Number of VIs in the project isn't really a concern for me, and I don't see why it should be.
  10. This feels weird. Obviously I've never seen your entire codebase, but I've built some big projects with TONS of classes and I've not run into problems like that. The memory usage could be totally warranted, but this would be an avenue I'd investigate. I don't have a good suggestion of how to figure out what's using all your memory, but I'd start taking classes/modules out 1 by 1 until it built. This is only vaguely related to your original problem though. It does sound like I was correct in saying that you load classes dynamically. So you need to look at your code and see how you're picking the filepaths to load and you need to make sure that the LVClass files exist there on the new machine.
  11. My guess is there are relative paths to objects that are being loaded dynamically. The objs aren't being included in the EXE. it works fine when you're on the dev machine, but they aren't being copied to the new PC. As hooovahh said though, we don't really have enough info to answer for sure.
  12. The .NET GUID would work for sure, but here's my KISS solution. A private VI that is a functional global. I'll call it "generate GUID". All it does is store an internal counter that gets incremented every time you call it. First time you get to it you get a 0, 2nd time it's a 1, etc. Guaranteed to never give you the same value twice (until your program restarts or your counter rolls over). I find this works for 99% of my unique ID needs. Followup food for thought: if you use unique ID's you probably need to use a constructor type VI. There's no way to enforce this in LabVIEW, but it's something that you can document and check for at runtime. If you do things By reference you can enforce the constructor a little better, you get a built in Unique ID (the reference value), but now you have all the additional concerns of a by-ref architecture. Unique IDs are not enough of a reason for me to switch to By-ref, but they could be one check in the "pro" column that I would consider when designing the entire system.
  13. Yeah, I was trying to sync the CRIOs time with the connecting PC's time, so I could use "Get Date/Time in Seconds" on the CRIO. Sync'ed time was a "nice to have but not necessary" feature, so I just scrapped it.
  14. Thread stuff turned out to be a red herring. the cause of my problem as reseting the CRIO's clock while softmotion was running.
  15. Thanks for the response. Yes I'm using timed loops. Most of the time there is only 1 timed looped running, it is a loop that is responsible for broadcasting some communication values up to the PC. It's set with a low priority and it's period is 200 ms. I've recently gone back and switched my low priorty timed loops out to while loops with waits, and it doesn't seem to be helping at all (although i've only run it once or twice). Related followup question: If a timed loop only has a little bit of work to do in a longer period (2ms of work to do in a 10ms period we'll say) is this affecting my CPU more than I would think? I've done some CPU profiling with RT trace toolkit and there doesn't seem to be any spikes. I usually have a pretty healthy amount of time in the "VxWorks Null thread" Im currently investigating the possibility of a bad 9512 module (admittedly it's a longshot). I have 5 axis that I need to control. 4 of them are on an ethernet rio and all work fine, the one axis that is plugged into the CRIO is the one giving me problems.
  16. I'm having some weird behavior on RT on my softmotion application. Softmotion is throwing errors like it's not getting enough CPU to perform the needed tasks, but my CPU usage on the RIO is only in the 50% range. I have several(6-10) concurrent tasks going in my RT code, most of them are idle however, sitting on a dequeue with a -1 for the timeout. My communication manager loop is waiting for a message from the PC, and when it does it will enqueue a message to on of the concurrent tasks. The task will do a little casting as needed, then start executing a task that can take anywhere from 5 sec to 5 min. Some of these tasks involve time critical sub components. None of the time critical parts run for longer than 30 seconds. So as someone who's more experienced with desktop programming, all those dequeues look like 0% processor usage to me. And judging by the distributed system manager, the CRIO seems to agree. When there's nothing going on, my CPU usage drops down to the 15%-20% range. But I'm still getting weird softmotion errors (like -77055). So my question is: Does a dequeue with a -1 timeout tie up the CPU in RT, even though the usage doesn't seem to show it?
  17. Yes. I thought I had done this in the past and it worked well. I thought that you could use the "Default Value" of your get variant attribute node to do the casting for you. However this appears to not work. I'm less interested in my solution now, but I think it could be useful at times.
  18. I've recently started using variant attributes for this sort of thing. You can create an array of all of your controls that you'll need. Then feed that array into a for loop that will add them as variant attributes indexed by label text. Now when you need one, you give the get Variant Attribute the class type and a name and you've got your ready to go already casted reference. Obviously you're going to lose some type information when you put it in the attribute, which can result in runtime errors instead of design time errors. I've found this is usually something thats fairly easy to manange on small to medium implementations, but it's something worth thinking about.
  19. It sounds like you haven't setup your inheritance correctly. http://zone.ni.com/reference/en-XX/help/371361H-01/lvconcepts/creating_classes/ You're asking fairly vague questions that are pretty hard to answer without writing a lot. Maybe posting some code would help (it would definitly give us the answer to your first question), but really, you need to ask some more specific questions.
  20. This was the problem. I didn't realize there was an update released. Thanks a lot.
  21. I threw some more timing into everything, and here's what I found. It's the close reference after the call by reference that is taking 90% of the execution time. The situation we have is sort of like tabs with sub panels. So when the first "tab" is launched, everything goes quickly (under 200 ms), then when you start switching tabs, every other close ref takes longer. The close ref time does not continue to grow, it just shoot up the the 1 second mark and stays there. So now i guess my question is: what affects how long it takes to close the reference?
  22. I've got a huge application that is supposed to be able to do a lot of different things (i'll call these things tasks), but each different tasks is completely independent from the other. Basically, it's a one-stop-shop for an entire lab. Each of the different tasks are actors launched from a top level UI and sent a message to insert their actor core into a sub panel. There is a noticeable delay between when the user clicks the button to launch the task, and when the UI actually shows up. We're talking about about 1000ms between when the button is clicked and the UI shows up. I did some profiling and I figured out that my overridden actor cores are responsible for some of this delay (i'm doing some slow code (100ms) before I execute the call to parent in the actor core). Launch actor however is responsible for most of the delay. I took a look at the two worst ones. Their launch actors were taking on average 500 ms and 700 ms respectively (meaning actor 1 always took about 500 ms, and actor 2 always took 700 ms). That doesn't make sense to me. Why do different actors take different amount of times to boot? I took a look into what launch actor is doing, and i found one thing that could change how long each type actor took to boot: Pre-launch init. If i had slow code in pre-launch init, then it would slow down launch actor. However, in my case, both actors had identical pre-launch inits. Meaning as far as I could tell, they should have similar launch actor times. So my question is: What affects how long it takes to launch actors? Where should I look next? I won't be able to post code, and i've been unsuccessful in re-creating in a smaller project. Edit: Oh god the title. I accidentally a letter
  23. The second StraingChannel Needs to be the same object type as the parent VI. This means that instead of StrainChannel data type, it needs to be ParentOfStrainChannel Data type. My guess is you'll need to cast it to the child data type in the code you screen shotted, or you'll need to figure out another way of doing this.
  24. I like the context specific idea. Like some sort of pop up when you click a class wire. Wouldn't be that hard of a modification since I've got all of the logic. It may be a bit of a challenge to keep it on the useful side of things and not slide into the annoying side.
  25. I took a look into this. I noticed the crash when running in the tools menu. I didn't test the non-tools menu version because, well... It's slow now. There is a noticeable delay when clicking a wire. I NEED SPEED!! Yeah, this is similar to what I was describing. The problem is then the QD is basically just a separate way to launch the same tool (vs the tools menu). Which i could add, but it's still not a QD only solution. QD feels like a "Every problem is a nail...." situation to me.
×
×
  • Create New...

Important Information

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