Jump to content

Stobber

Members
  • Posts

    213
  • Joined

  • Last visited

  • Days Won

    5

Everything posted by Stobber

  1. I have to be honest: I've never used them that way. I appreciate the tip, Phillip!
  2. In my defense, LV is structured in such a way that panel elements become diagram elements via the requirement that every subroutine have a panel. I want to design a good API that limits the potential for bad values passed in by the client, but I don't want to create a clunky coding scheme in order to do so. Using a ring is natural here. I only verbalized the XControl possibility to hopefully spur conversation about alternative approaches. I ended up just adding a utility VI to the API class that uses a case structure to translate ring values into the integer values that correspond with the ring strings. Future devs working on this class will have to know that it needs to be updated whenever the typedef is modified.
  3. I am using a ring, and it does have the baud rate as the strings. The ring values are fixed by the driver API I'm communicating with.
  4. Hi all - I'm drafting up a simple LV API for a serial-based pressure transducer. The driver interface lets me select the baud rate for communication from a list of values, and the value that I send to the transducer is an index into this list. (e.g. if I want to communicate at 9600 bps, I send the sensor '2', which corresponds to the rate of 9600. If I want 19200 bps, I send '3'.) After sending the desired rate to the device, I have to reconfigure my serial port before talking to it again. Unfortunately, I need the rate for the serial port configuration, not the index corresponding to that rate in the driver API. To solve this problem, I did the usual maneuver of creating a ring typedef for the selectable rates in the driver, then grabbing the string off the typedef and converting it back to a number to be used as an argument to the Configure Serial Port VI. I don't like this on principle, because it depends on the format of the typedef strings never changing in the future -- if they stop being legally formatted decimal numbers, this code will break -- but it worked for my proof-of-concept. Here's the VI: The string formatting dependency notwithstanding, this is also a bad idea for a hardware driver API because calling into the property node forces a thread swap to the UI execution system. This isn't a high-performance driver, but I still don't like the idea of waiting in the UI threadpool to execute a hardware call. What's a better approach to this problem? The ring seems like it's definitely the right choice for the API interface, but I need its strings as numeric values alongside the list indices that are sent off to the device. I considered creating a second typedef that holds numeric values of both things in a lookup table, but then I'd have two diagram constants (or a typedef and a lookup VI) that would have to be kept in sync every time the software is updated. I'd prefer to encapsulate all this information in a single diagram element. An X-Control seems like overkill here, though. Ideas?
  5. Yep, it is analogous, but many things common in C make no sense in a by-value dataflow language, so I want to make sure the rest of the LV expert community agrees that this is a good way to do it.
  6. I've noticed a budding trend in my LV development that I want to stop and consider. When I have a class that aggregates other classes -- meaning that the owning object has a different lifetime than the owned object(s) -- I've started putting the owned object into a DVR and holding the DVR in the owning object. The reasoning for this is that I can check for a null refnum on the DVR when I want to see whether an owned object indeed exists as a member of the owning object. It leads to extra work every time I access an owned object, but I can make merge VIs and templates for most of that. I've attached an example of this. Is this stupid, or does it make sense? Alternatives I can think of are: Store the owned object directly in the owning class. When I unbundle the owned object, compare against its default value to see whether it's actually there. There are problems with this, though. If I change defaults in the class definition, they aren't reflected in any constants I've placed on the block diagrams of calling methods. I may also need to use the defaults as a valid configuration for the owned object. Add a Boolean data member to the owning class that indicates whether an owned object has been loaded. I hate this approach though, because it's a configuration parameter, not a data member. I don't like that I have to lug a bunch of meta-information about the object around with its real data. Make every owner hold an array of owned objects, but know that the array size is limited to 1. Then I can check for an empty array when looking for the owned object. Of course, there's a memory allocation every time I add an owned object to an owner, and there are extra array operations every time I access or modify the owned object. Aggregation Discussion.zip
  7. Hey Ed. Double slashes are good; as you said, they're part of the INI syntax. Triple, quadruple, etc. slashes are bad, and that's what's showing up in the VI's output right now.
  8. I think so, yes. I haven't seen another general-use serialization class floating around NI or LAVA, so I thought I'd make my own. This is mainly a thought exercise. If it pans out well, I'll probably try to use this base class in some side projects to see how I like it.
  9. I'm trying to write an abstract class for serializable (to disk) objects, and I'd hoped to use the open-g VIs to do it. One design constraint is that I want to be able to write an object description by hand or from another application/language, given prior knowledge of the object (from a design document, etc.). If the number of escape characters in the section name varies, that becomes a lot harder to do.
  10. I've been playing around with the variant configuration palette this week, and I think I found a bug in the Write Key (Variant) VI. The VI will insert escape characters into the section and key name strings to conform with INI file syntax. I've noticed, though, that if I use a file path as the name of a section that holds a cluster, it inserts multiple escape characters at each point, instead of just one. The image below explains it (hopefully). It looks like this bug only shows up when two conditions are met: 1. The section name contains escaped characters, like ‘\’. My section names are file paths to .lvclass files. 2. The variant key contains a cluster or an array of unknown type, causing the VI to be called reentrantly. Since the VI has to be called reentrantly, I haven't thought of a workaround yet. (Well, I guess I could restructure my file to stop putting paths into the section name, but I'd rather not have to.) I can think of two approaches to fix it, though. One is to add logic that counts the recursion in the VI and ensures that only the first instance executes the Encode subVI. Another is to encapsulate the multiply executing logic into a reentrant subVI, leaving out things like the Encode subVI so they're only called once from the main Write Key (Variant) VI.
  11. Hmm...looks like I missed the fact that the \FPGACategories\ folder auto-populates its contents onto the root menu. Thanks!
  12. Hey all - I'm working on a harebrained idea for a set of reuse libraries targeted at LVFPGA development. This includes creating palettes for these VIs that only show up in LVFPGA. I have the wherewithal to do that, but unfortunately there are no auto-populating subpalettes of the LVFPGA root palette that only show up in LVFPGA. (User.lib shows up in all targets and contexts.) So I wonder if I could use Jim's dynamic palette resource from the Open G project to fill this need in LV 2010. I poked around in the code a little, but I'm not sure exactly how it works or what I would need to modify to make it display my subpalette. Can anyone point me in the right direction?
  13. I used yours on a side project last week, and I have some things I'd like to change/add in that one. (I should note that it was very easy to use and worked flawlessly!) The "Register LabVIEW User Events" function outputs an event registration refnum, which makes it impossible to register both NotifyIcon events and other user events on the same event handler. (Good ol' LV doesn't allow additional registration of new strict types on an existing event registration wire, and you can only create one dynamic registration terminal on an event structure so you only get to work with one wire.) So I broke out the user event refnum from your "Initial Event Registration" case and made an indicator from it. This lets me drop my own Register For Events node and wire as many types of user events to it as I like. As I mentioned on the NI Community page, the Disposed event doesn't fire the way I expect. Your proposed solution is to modify the order of things in the "Destroy" VI to call Dispose, then unregister the events, Of course, I'd rather handle event reg/unreg myself as explained in #1, so the real solution may be to have "Destroy" call Dispose, then exit, relying on the client to unregister events himself. The menu for my application had a subset of selections that were mutually exclusive, so they basically had to act like a menu ring. I made a little FGV that wraps your API to provide that behavior for any subset of MenuItems. I've attached it in case you think it should be added to the API. Using the name of the library to namespace the VIs is ghetto. Why not add them to an lvlib? There are few enough that load times and memory bloat won't be an issue. I'd like to see this packaged as a VIP or OGP, instead of an unversioned ZIP file. I could help you get started with that, if you like. Finally, I'd like to see that whatever blend of these two solutions we come up with is distributed on LAVAG with the BSD license, instead of NI Community with NI's very restrictive T&C. All told, this is a great LV interface to some nice .NET functionality, and I'd love to see more things like it out in the world! NotifyIcon Ring.vi NotifyIcon Ring Action.ctl
  14. I'm slowly learning OOP and have tons of questions! I've seen three or four mentions of the Strategy pattern on here, but no concrete discussions of how it should be implemented in LVOOP. I gave it a try using Daklu's interface framework here, and attached to this post is another attempt using only native LVOOP features. In the native LVOOP project, I used a parent class to dispatch the algorithms since interfaces aren't natively available. I can only see two downsides to doing it this way, though: Every algorithm's must be a descendant of the "aAlgorithm" class. I noticed that requesting a method that doesn't exist in the concrete implementation ("Algorithm2:Method3.vi") results in the parent method executing instead. That could be a pain in the rear, I guess. Are there other detriments I'm not noticing? I feel like I could work around those two pretty easily in most situations. NOTE: attachment is LV 9.0.1 Strategy Pattern (LVOOP core).zip
  15. Hey Daklu, I finally finished the SimUDuck program from the book. Writing classes in LV takes a lot of extra work: creating the byRef typedefs, making the class icon and wire style, setting inheritance....and having to do it twice for each "class pair" that makes up an interfaceable class...it really makes me consider whether having interfaces is worthwhile! I'm probably just lazy though. Got any tips to make me a more efficient LVOOP coder? Anyway, here it is. Mind taking a look at it to see whether I did it right? I wonder whether the Strategy pattern could be accomplished without needing interfaces. I know some patterns can be approximated without using classes, like using dynamic events for Observer. simuduck_lv901.zip
  16. Hi folks - Norm Kirchner created a nifty framework for building APIs that I decided to polish up and publish for everyone. I uploaded it to the NI Community forums first, but I though I'd post over here to garner discussion about it, too. Here's a little information about it: The framework uses a single LVOOP class -- your API is a child of that class -- to add several nice features to your API. It does this via two functions that are named "Obtain Session" and "Release Session" by default. Multiple instances - You can instantiate multiple unique copies of your session, each with a unique string name to identify it. So if you have a session named "Serial Waveform" and want to generate multiple different serial messages in your program, you can do so by simply creating multiple wires and naming them uniquely. Multiple accessors - Because the sessions are uniquely named, you can obtain a reference to any session that already exists from anywhere in your application space. This is analogous to the behavior provided by LV Notifiers and Queues. LV Class features - Your session is implemented as a class in LabVIEW, so you get all the nice features of classes: encapsulation and inheritance, password protection of private methods, and (in LV 2010) native property nodes Simple interface to C and TestStand - The session handle is a DVR to your class. This means that your methods, when called from TS or C/C++, only have to pass an integer (the DVR) to the caller. This is much much nicer than passing a cluster. "Obtain Session" and "Release Session" are required in your API, but you can rename them and edit most of their behavior to act however you like. I've attached a set of slides that gives the full story and list of benefits. The demo projects are also attached as examples of using the framework. The rest (slides, installers and examples) is here: ESF Document on NI Community
  17. Hi Daklu - I've been lurking on the LAVA forums without an account for a year or so, just poking my head in to learn some specific tidbit when I couldn't find the answer quickly on the NI pages. I decided at some point that my extremely limited knowledge of OOP programming -- I was raised a BSEE and kind of meandered over toward software development as my career grew -- is only holding me back. So I went off and bought a copy of Head First Design Patterns. I read the first chapter, sat down in front of my laptop with LV2009 eagerly loading, and got ready to implement the Strategy pattern from the first chapter in the book! "Oh.....wait....where do I find the interfaces in here?" So to cut this story short, I found this thread, read through it all twice, downloaded the latest copy of the framework, got a teammate who really knows LVOOP to explain it to me, read through parts of the thread again, and now I think I mostly understand how your nifty framework functions. I intend to use it on the SimUDuck example from the book in just a minute, but I have one nagging question about your class structure in the Baby Demo VI. I understand why you put your interfaceable classes' private data (Baby and CellPhone) inside a DVR that gets carried by the classes: this makes them behave like reference-based classes, which is handy when the wire has to be split to allow both the Interface methods and the interfaceable class methods to act on that data. But -- and forgive me for using my inaugural post to challenge a revered poster -- but doesn't that fundamentally change the behavior of the class wire on the client diagram? Instead of copying its private data when it is branched, as NI R&D designed it to do, it now acts as a reference to that data so the data isn't copied. It seems like any client developer who uses these interfaceable classes will have to know that they don't behave like normal classes do on the diagram. ...I suppose the alternative would be to wrap the class wire in a DVR and pass that around between methods, but then you lose dynamic dispatching and the whole thing kind of falls apart. I don't know the answer here, just thought I'd ask the question to make sure my understanding is correct. This looks like a very cool workaround for interfaces, and I'd like to start using it in my projects if I can.
×
×
  • Create New...

Important Information

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