Jump to content

Yair

Members
  • Posts

    2,870
  • Joined

  • Last visited

  • Days Won

    44

Everything posted by Yair

  1. I don't really like playing with event references like that, because they have unpredictable behavior under these circumstances. For example, I modified your example by adding this event and case structure before the loop: If the event structure executes (case T), the array is empty. If it doesn't (case F), it's full. Can you explain why? You're welcome to have a look here for more details (including from the horse's mouth) about the relation between reg refs and structures, but I don't pretend to safely understand all the intricacies, but that's possibly because I never had a need for such an architecture. I'll leave you guys alone to hash it out.
  2. When you unregister an event using a null reference, the queue of existing events is flushed. I'm assuming that the same happens with your code, so you would miss any events which occurred and you didn't handle before unregistering. You can fairly easily check this by firing the events, then unregistering. In any case, I don't understand where you're going with this. The reg refnum and the event refnum are two completely separate objects and they shouldn't affect each other - one is used mainly to fire the event and the other to hold a list of events an event structure currently listens to, so I don't see what kind of syncing you want to get between the two. Perhaps a more realistic example would demo it better.
  3. This is where a simple action engine would serve you quite well. You can have two basic actions (add line, read log) and because it's a single VI, it will make sure that things work in the correct order. You can use the read action to get the log and place it in an indicator. I was bored enough, so here's a simple example. It has no error handling and things like that, but it shows the basic concept of how this can be done with a class. The big advantage with this is that you can easily create a separate VI for each action and that if you want another logger, you just call the New VI again and you get a new logger object. Log Example.zip
  4. I don't use 2010, but I would have assumed that this would affect the "Name Format" right click option you get with every property node. Are you saying it doesn't do that? Also, I would guess that data name is something that you would use so that you can localize the name of the property but keep it referring to the same property. Does the documentation not say anything about these?
  5. Oh good, more manpower (or girl power, in this case) for the JKI sweatshop.
  6. I don't know if the drag events will work or not, but if not, I think you might have to do this with polling. You can use the initialization of the XControl to spawn a running VI which will use the mouse input VIs to monitor whether the mouse button is released when the VI is front most and the cursor is over the XControl. I'm assuming that if you grabbed a control, you will be able to get a reference to it using the panel's Selection List[] property. You can use the uninit code to destroy the process. See here for a similar topic -
  7. Michael, any news on this? This still happens with every message which has formatting.
  8. Go to the View Unread Content page. Find a thread which has multiple pages and where the oldest unread post is not in the last page. Click the link which brings you to the oldest unread post. Don't continue to the last page of thread. Reload the View Unread Content page again. The thread does not appear in the list even though you haven't read the last page yet. I run into this sometimes when I don't notice that there's another page. When I click the link again, the thread isn't in the list, thus causing me to miss posts.
  9. So this project was somewhat delayed, but eventually it was executed and I can say that we used the EDS4100 from Lantronix, which seems to work well so far. We had some issues, but those had to do with some of the devices we connected to it, which required some special cables.
  10. Aristos Queue once suggested using this scrolling LED XControl example which is simple in LV, interesting and can be used to highlight various aspects. In any case, I would suggest staying away from DAQ and hardware (VISA is probably included in that), as programmers don't care about drivers when being introduced to a language. Also, be sure to highlight the differences. Demonstrate race conditions. Make it clear from the outset that LV does NOT have variables in the same way that C does (this ties in to the dataflow point the others brought up).
  11. Yair

    Math doodles

    http://vihart.com/doodling/ I recommend starting with the snakes one. Also, keep your ears open, or you'll miss the fun stuff (such as the curves on a plane vs. the snakes on a plane or the knighted five-point-star snake titled "serpentagram").
  12. Have you seen this thread - ? I assume that the class properties dialog has some similarities to the general options dialog, so it might help.
  13. If they all have the Label.Text property, you can type cast the reference to a class which has it (e.g. the Control class) and use it with that. Note that type casting references can be dangerous, so if you want to be safe, I would go with trying TMSC down to each relevant class until you don't get an error or get the class ID to know which specific class it is. If you do use the type cast method, I suggest you only use it for the Label.Text property and then go back to working with the original reference.
  14. Yair

    Hax!

    There's actually a reason for this - http://forums.ni.com/t5/LabVIEW/2010-user-lib-Path-in-Executable-Changed-from-2009-1abvi3w/m-p/1389784#M544175
  15. I'm not sure what you mean by "should". I could, but I could also just do it the same way you did. It all depends on the requirements and the design decisions made based on those requirements. I agree.
  16. But you DO have wires. I happen to like the singleton which gets the reference internally as well, but in this case your one-stop shop is simply a poly VI, which is what I was referring to not needing. Incidentally, as long as the pane patterns match, you can create your poly VI with classes as well. Which, as far as I'm concerned, means they're not an integral part of the basic API (i.e. the user has to explicitly use them and they're not part of the R/W VIs). They might be an auxiliary part, but that's easily done with classes as well - all you need to do is add the VIs somewhere and have the user call them just like you do. I should also point out that this isn't necessarily a problem. It keeps the API simple and manageable and is what I was referring to earlier when talking about Daklu preferring simple APIs.
  17. That depends on how much functionality you add in the base classes. If you have all (or almost all) of your actual VIs available in the bottom level class (say UDP), there's nothing preventing you using only VIs from there. If the VIs are overriding, then changing the wire type to TCP will automatically use the other VIs. Other than that, I don't think anything more can be said - if TCP is a Transport, then you will need to know what Transport has to offer as well. Maybe if you build palettes LV will offer you the entire inheritance chain if you right click a wire, but I have no experience with that. If you really want, you could probably build a single palette with all the needed functionality including the constructors (see the next point), but I doubt I would. You can take the "constructors" from all the different classes and add them into a polymorphic VI. It would work the same way. I don't think I would do that for one main reason - I'm assuming that at one point the user of the library knows which transport they want to use. At that point, I'm OK with letting them find a specific VI. I doubt that desire can easily be realized in any way other than the one you used (unless you're willing to accept a palette as a one-stop shop). Personally, I don't feel the need for such a design, but I can see its appeal. You haven't given any example of using them and you don't have them in the actual API, so I didn't incorporate them into the API. If you just want to have the VIs as-is, there's no problem with just putting them somewhere. If you want, you could actually create two more hierarchies of classes (compression and verification) and thus use different types. Doing that, of course, is more of an undertaking which is pointless if you know that you only want blowfish and CRC. The really problematic thing would be if you wanted to change the API to add the encryption and verification - because you would presumably want to do this for all the transport, it would have to be in the transport class, which is more complicated, because it would require calling the relevant VI from the parent class in each child class or encoding the data in the parent's write VI and then getting it out of there (which can be done by keeping the data in the class data, but is still cumbersome).
  18. Actually, there I have a bigger problem. I don't require the user to drop a constant because the "constructors" don't have a class input. Instead, the user needs to select a specific VI. This has advantages in that each VI can have different inputs, but it does cause problems in the logging challenge in that there is no VI in the base class. That would mean that we would need to create a logging VI for the base class and then have every constructor call that VI. But again, this is not because of the LVOOP thing, but rather because I use separate VIs (which I would anyway, since I want different inputs on that VI).
  19. There's no disagreement that adding more features and protocols would complicate matters. I don't use the transport library at all, so I definitely don't plan on adding any more protocols to it. Let's just say that the expansion point is apparently not too relevant here and that there's not much point in discussing it. The transport library is actually one example where this is applicable - I replaced your variant+case structure with classes. The classes don't actually have more code, but they do have some overhead (more VIs, more documentation, etc.). Actually, neither of us would need to make hundreds of changes. You would just add the logging after the case structure (assuming you still have single write VI) and I would set the logging info IN THE TRANSPORT CLASS before calling the write VI. Inside the write VI (assuming I did the job properly), each VI also calls the parent implementation, so all that would be needed would be to add the logging code in one place - Transport.lvclass:Write.vi. Of course, as I mentioned originally, LVOOP makes this more cumbersome than your method, but then again, your VI with the hundred cases isn't the most ideal either.
  20. It's only UDP at the moment. What happens if you want to add more protocols. What if those protocols require additional parameters (as you pointed out for serial)? That was my point about leaking the implementation of specific protocols to the outer layer of the API. There's nothing wrong with it functionally, but it's a problem with the design of the API. I don't see it as trivial, at least not in the context of strict vs. weak typing. LV is basically a strictly typed language, for good reason, and while you can choose to use variants or strings, it means you're placing some of the burden on the user of your API and you're risking running into bugs and run-time errors. A valid decision, but which I would generally prefer to avoid. For example, imagine what would happen if every time you wanted to use the DAQmx Write VI, you would need to pass along a DBL formatted as a string and if you wanted to use the 1D version, you would need to pass along a DBL array formatted as a pipe-delimited string. It's not very convenient, is it? And although this entire point has nothing to do with LVOOP, really, I should also point out that LVOOP was also designed to replace some of the cases where you use variants for run-time typing. There was nothing forcing you to use a single VI to open the connection. You could have created a TCP Open, Serial Open, etc. Of course, with LVOOP this is somewhat easier, as the components are already broken off into classes. And just to demonstrate it, here's a simplified Serial VISA class which took less than 10 minutes to create - just drop it in the classes folder and it's ready for use. Of course, you won't be able use it in your client/server program, as that doesn't have the configuration options required for serial, but that's a problem with the program, not the API although that, of course, depends on the definition of the API. If one of the design decisions is that users can configure it with a single, simple string, then this class breaks that rule. I would think that breaking the rule would be worth it in that one point if it means that your users only need to use a single read VI and a single write VI in the rest of the code, but I'm not an actual user, so I can't say that with any certainty. Serial.zip
  21. So first, just to clarify, since it's also relevant for some of the other points (such as changing the scope on your VIs or only creating two classes) - the main design parameter for me on this one was speed - I wanted to put in as little time as possible on the refactoring, just to get the point across. It's really not the proper way to design any kind of API. Yes, but since it's only relevant for some of the transports, it's a leak. It should not have been part of the read VI which is shared by all transports unless the vast majority of them support it. To wrap all of these together, I think they are all part of the problem. Ideally, this utility should have a well defined API (where port number for TCP is a U16, for instance, so you don't have that bug) which would also require not just wrapping the primitives (which I assume is why serial wasn't implemented), but coming up with a specific API which would be relevant. If I understand him correctly, one of Daklu's points, based on his experience, is that because you don't know what's going to happen, this API should be as simple as possible and he actually doesn't particularly like extension through inheritance, because as you add features (such as the read mode on TCP), it becomes more complicated, but I'll let him expand on that.
  22. D'ya know what? I agree. Of course, some people seemed to think that's not necessarily a good thing. So, here you go. I did some one-handed bed coding and here's a basic mod of the transport library into LVOOP (2009). Some relevant comments: The transport example shows off the OOP advantage mainly through the inheritance property of OOP. This does not seem to be what your discussion was about, although the example does also reflect on your discussion. I didn't follow your API exactly. For example, your API leaked the TCP read mode enum out to the outer layer, where it's irrelevant. I didn't create a relevant equivalent in the API, since you didn't use it, but an accessor could be created for it and called before calling the Read VI. I only implemented TCP and UDP. I recreated the server and client examples (they appear under the classes in the project). You'll note that the inputs are now safer and easier to use (e.g. local port in the Open VI is now a U16 and does not mention BT). I changed the access scope on your VIs so I could use them without having to make a copy. The VIs themselves are also simpler (See the UDP Write VI, for instance. In your VI, it takes wires from all kinds of places. In my VI, it's cleaner and clearly labeled). Whenever you make a change (e.g. add a protocol), you have to recompile the code which is called by your various programs (assuming you reuse it) and you have no way of guaranteeing that you didn't break anything. With the classes version, you don't have to touch the existing classes. Code which is not recompiled does not to be verified again. I didn't like all the choices you made (such as using a string to represent either a port or a service), but I kept some of them because I was not planning on doing a whole refactoring. Also, you should note that my implementation is far from complete. Ideally, each class would also have more private data (such as which ports were used) and accessors and do things like input validation and some error handling, but I only created the most basic structure. To expand a bit on points 8 and 9 - You mentioned adding serial. That's a good example. What would happen if you now need to add serial, USB and custom-DLL-X to your protocols? You would have to touch all the existing VIs. You will be asked to recompile every single caller of the library (although with 2010 this is finally less of an issue). You would need to overload your string inputs to include even more meanings than they already do, etc. Contrast that with creating another child class and creating overrides for the relevant VIs - it becomes simpler. Also, with classes you can guarantee that no one will change the existing functionality by locking it with a password. For point 9, I would have a preferred a poly VI - one for service name and one for port. Internally, they can call a single utility VI to minimize code duplication, but for the API, you should have it as easy as possible. Currently, you place the burden of formatting the data correctly on the user of the library instead of constraining them where applicable. One example where your code will simply fail is if there's a service name which begins with a number. I have no idea if that's even possible, but if it is, your code will assume it's a port number and fail. This isn't actually an advantage of LVOOP (you could have created a poly VI using your library as well), but it would be easier in LVOOP. As you said, you could probably now compare the two by setting a series of tasks, such as adding more protocols or adding features, such as adding logging to every write and read. Actually, logging is a pretty good example. For you, adding logging is fairly simple - you add a path input to R/W VIs or you add it into the cluster. In the LVOOP code, adding an input to the R/W VIs would require touching all the classes, so I would probably do this by creating an accessor in the Transport class and simply calling it before the R/W VIs. This is one specific example where making a change to a class can be a bit more cumbersome, but it's probably worth it to avoid the other headaches. You actually have some advantage in this challenge in that you know and use the code whereas as I simply did some quick cowboy coding to adapt it, as opposed to planning the API beforehand. I also didn't do some needed stuff (see point 10). That said, the OOP version should still probably hold up, although I wouldn't unleash it as-is. Also, I doubt I will have more time to do actual coding, but I think this base is enough for some thought experiments. I should also point out that I'm more in your camp regarding the kinds of projects I work on, but that I generally agree more with Daklu in this thread. Transport with class.zip
  23. Yair

    Cosmology

    I assure you that if I hadn't done it, someone else would have. Anyway, there was a poor user on the other end of that thread who was innocently trying to help, so I didn't feel good about letting them keep at it. And, hey, at least you came out of it with a VI which simulates AN ENTIRE UNIVERSE. That's something, right?
  24. It does from where I'm looking at it. This is the relevant section - http://zone.ni.com/reference/en-XX/help/371361G-01/lvconcepts/flattened_data/ Also, the Flatten primitive has a byte order input which could have also taken care of the other issue you had. I believe it gained it in 8.0, so if you're using an older version that might also explain why you haven't seen the link (although I would have expected it there in older versions as well, since it's "obvious" that it should be there).
  25. You can also see a couple of examples here - http://decibel.ni.com/content/docs/DOC-12608
×
×
  • Create New...

Important Information

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