Jump to content

ShaunR

Members
  • Posts

    4,856
  • Joined

  • Days Won

    293

Posts posted by ShaunR

  1. Just wondering if anyone has attempted?

    I think there are a couple of network Publisher/Subscriber examples kicking around the CR. I'm not sure if they qualify for an "Observer" pattern since some people seem to use both terms interchangeably whilst others use it specifically for events. I think also the "Top-Level Baseline" might qualify too.

  2. I used the Constant Refnum for Constant instead of BooleanConstant but didn't add all types of constants to the Case Selector. I could search for "Constant" in the Class Name, but I'd just be moving the Case Structure. The other cases include Control, Node, Wire, Control Terminal and While Loop. I'd like to make it generic without specifying every possible type. I'm stuck...

    Ahhh. IC. Don't bother with PassaMak then 'cos it's mainly UI focused. You have to find the parent that has the attribute you want to cover as many types as possible. Unfortunately, you still have to cast, but you can reduce the cases required.

  3. I played around a bit further hoping to make it more general by searching for GObjects instead of each specific type. I came up with this, but it requires adding cases for every type of object you want to address. Perhaps it's not the worst solution...

    post-7534-0-31409500-1292938289_thumb.pn

    If you search for "Constant" on the class name you won't need a case for each type as they all have labels.

  4. Hi friends,

    I've got an interesting project( atleast for me :thumbup1: ).

    I have a set of of equipents which are controlled by a webpage(html with button and slide bars..etc). We can also control the devices using modbus- I am using my labview code here.

    And we can read back the status of the device (in labview or any other modbus software) registers even if the devices are controlled from web page controls.

    What I would like to know is that, Is it possible for us to load the webpage in labview and push the webpage button from labview(automatically or manually) and read back the status registers? :wacko: Interesting? :oops:

    I did browse thru' NI website but I couldnot find anything related to that.:frusty:

    Please help me...!!!! :worshippy:

    Regards,

    Sharon

    Well. The easiest way (If using windows) is probably to load an active X or .net browser into a labview container and when a DocumentComplete event occurs; scrape the page for the info you want.

  5. 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.

    I did say "similar" wink.gif. The point I was making is that I prefer to simplify and modularise. The ideal result (for me) is a single VI with a multitude of uses but a simple (2 or 3 parameter) interface rather than a number of VI's, specifically tasked towards specific functions. A ploy is a half-way house to that goal.

    I've already commented on the singleton (anti?) pattern; many moons ago in an earlier post. They are just irrelevant for classic labview and required to get round a problem of your own making (not specifically you, POOPers in general)

    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.

    There is no auxiliary, or basic. there is just API. My definition of that is that it's a collection of functions to facilitate the execution of a task(s) based around a common theme. Perhaps yours is more strict. But I prefer not to restrict myself with semantics

    Indeed you can just implement as I do, but for classes that would seem, well, a hack, since you should really be creating an "Encryption" object and passing that as an argument to be used by your read/write VI's.

    Well. I think we've come to the end of this little exercise and I thank you for your participation in the absence of the OP. People can draw from it what they will, but I think it was a fair example given that it was very suited to both approaches without prejudice.

    so. Only one other thing to say:

    .

    Shopping.Create;Shopping. Alcohol := 10  /* litres */Shopping.Food:=20  /* kg */Merry.Create (Shopping);Merry. Happiness = Shopping.Food * Shopping. Alcoholxmas.Create (Merry);

    biggrin.gif

  6. 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.

    I think going down that route there actually wouldn't be much benefit over using the in-built prototypes from the users point of view. He has a load of VI's in his palette which some of which are interface dependent, some aren't. I think I would want a bit more than just amalgamating the read,write and close VIs for the different interfaces considering the amount of code I have to write.

    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.

    Perhaps it's a personal preference. But I see it as more modular. I've done similar things with queues and notifiers so that I don't have wires all over the diagram and can safely call it from anywhere without much thought. I strive very hard for this type of "node" and it serves me well.

    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).

    Indeed. there isn't an example, but I only really released the library because it's used by other applications in the CR.

    The encryption is in the API. But I never found a "native" labview compression algorithm and didn't want dependencies on dlls (I'm still looking as I'd like that feature and the stubs are in there). I'm not expecting you to write any more code since I think there is enough to discuss the differences. But I've moded the examples to show you how it works with my implementation. I didn't include CRC as I don't think there would be much mileage as it's unlikely that new CRC algorithms are required and it's not really relevant to all the protocols. But it is a useful utility. The CRC is used in a similar way as the Pack/Unpack instances as a separate entity.

    As you can see. It's up to the user to use them rather than embedding support at the protocol level. I did toy with the idea of making this transparent too. But that would have severely complicated the ability to turn it on and off on-the-fly. This way, the user decides if he wants to support encryption and only needs to switch by supplying a password or not.

    However, classes tend to make you think of embedding to conform to the class hierarchy, so making it a stand-alone module isn't the first thought, (although ultimately preferable I think). That's why I asked the question. I cannot immediately see an intuitive way to combine it into your architecture without a lot of work.

  7. 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).

    It does have something to do with LVOOP since the ease of use is basically derived from overriding a base class. Rather than the user having one VI (or class) that he/she is choosing VIs from, They now have to pick some from the base class and some from the other classes. This doesn't sit well for me as it (in my mind) it breaks encapsulation. What would you suggest to mitigate that?

    Lets look at it a slightly different way in that: what would happen if I too wanted to make different inputs as you want to do?. I would have to split out the "Listener" and "Open" cases into single VIs (one for each interface) and wrap them in a polymorphic VI. The advantage here for me is that the users choice of interface is decided by what type of control and where it is wired. I'm no worse off than classes but I have more VIs to maintain and test

    However, that causes me an additional problem in that I can no longer distil all the functionality into one "Transport.VI" that the user simply chooses a function from a menu. I need to split out read, write, close open and listener into separate VIs since you cannot nest polymorphs (read, write etc are separate anyway, but the user doesn't see that). I am, basically, requiring the user to do do the same as you, They have to manipulate a number of VI's instead of just one. OK, I could group them in a Virtual folder but as I add the CRC and packinging VI's I'm getting further from a one-stop shop for comms. So in this case, I have sacrificed the encapsulation derived from my top level polymorph for the ability to type the inputs. Although my Virtual folder is now looking remarkably like your base class.

    How would you start to add the CRC and packing VIs? They don't fit with the base class template so would you add a new class for each?

  8. 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.

    That's an interesting comment, since it is usually proposed as one of the greatest advantages to using classes. In this case, however, I agree. There is not much point because both implementations are complicated to the same degree. The goal of this exercise is to look at functionally identical implementations and discuss the differences. You have gone a long way towards that so that we can. (and it is appreciated).

    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.).

    Indeed. The difference is adding or modifying cases or VIs. The latter, I would wager, is the reason for Daklus excessive load times.But you also left out that new VIs also require new test harnesses (or modification of an existing one depending how pedantic you are about "white-box" testing) to exercise all the inputs and outputs and that can be quite an additional overhead. The cases only require additions to the input parameters of the same harness so can be scripted (not LV scripted, good ol' fashioned text scripted). The only real difference is how we realise the tasks. You switch by overriding and invoking a VI,. I switch by cases.

    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.

    You're right. I'll have to lay off the mulled winewink.gif In this case it is the same. It won't always be, but we have agreed that (for this) it is irrelevant.

    If we expand further by saying we also want to log opening/closing and listener info. I think you would probably decide to add the definitions to the virtual class for "Open" and "Listener" and would make the implementations completely synonymous (unless of course you want to modify all the open and listener VIs for every class). The difficulty here though is that you (or rather the user) still needs to tell it which one to invoke by laying down a class constant. I did something similar in the beginning using refnums (i.e using type to choose the interface), but rejected it in favour of a ring control as I perceive it easier for he user.

  9. 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.

    Well. thats the crux of the differences in argument position, isn't it.wink.gif I never try to make all singing, all dancing APIs that will be all things to all men with a view to abstracting all current and future interfaces. I don't want to add more protocols, nor will I ever at this level. I just want to make it easier to use those ones. I've looked at how I, and others use them and simplified it to a couple of parameters,unified the inputs, and implemented a client server relationships for those that don't have it (UDP). If other interfaces are required, then they will build on this API at the next higher level (similar to what you have done with the UDP). TCP, UDP, Bluetooth and IR have been modularised and simplified.

    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?

    The only burden I'm placing on the user is to use a properly formatted string (which doesn't have a huge amount of restrictions) This is no different from VISA for example.I would in fact say that the the class implementation burdens the user more since now he/she has to cope with multiple VI's depending on what which interfaces he wants to use and supply different parameters depending on the use. This will get worse if you do require the API to support more interfaces that take different parameters and allthough it's easy for you to keep adding classes, the user is getting more and more interface to contend with. I have attempted to simplify and the classes are putting it back in again.

    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.

    If you mean replacing a variant primitive with a class acting like a variant. then possibly. I don't know what the intention was, but if it involves me writing more code; then I'm not a fan.

    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.

    It's not quite ready because it needs a client/server emulation the same as the UDP. But that's not the point. I could also add (in 10 mins) serial, but it would basically be the same as yours (without classes) requiring the user to wire up additional controls. The only difference would be I'd be adding cases instead of VIs.

    But I disagree that It's a problem with the program. The program is able to write and read data which is it's only purpose. If the API can get the required configuration options from a single input. then the program will work. I experimented with mine and I could do things like make the string a comma-delimited config or pass it a file name to load the settings, but that doesn't translate well to the other interfaces, is very unintuitive and well. Just plain crap. Anything else needsd more controls and requires the user to treat serial differently so that doesn't fit with the remit.

    But user/component boundaries aside.

    The really interesting thing for me is that. If (hypothetical because it won't happen) I were to add more interfaces that did fit with my remit for single parameter config. I would only be editing 4 VI's. If there were 100 interfaces; I only need to take care of 4 VI's. My maintenance-base doesn't change. However for classes each new interface requires the addition of 4-5 VIs no matter how similar the interface is. So in this hypothetical case of 100 interfaces, I only have make 400 changes as opposed to oooh... thousands for the addition of your logging example. Classes in LV are replication which isn't conducive to maintenance.

  10. "Create Sub-vi" function.

    Saves hours if time when prototyping by allowing hierarchy realisation, easy modularisation and, of course, cleaning up diagrams. All in one step thumbup1.gif. Imagine what you would have to go through if you wanted to replace some code with a sub-vi if we didn't have it worshippy.gif

  11. 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.

    Of course

    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.

    It's only UDP that doesn't so its 75% which I would count as the vast majority. I could have left it out completely and probably 1 in 50 programmers wouldn't have noticed.

    A leak means something different to me. I don't consider a NO OP a leak.

    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)

    Detecting whether there are any a-Z chars will fix that and it will work as intended. It's a trivial point.

    The port number change is the sacrifice I was talking about. You have sacrificed the user having to write more code to deal with it (as you have done in the example) for your preference for strict typing and partitioning.. That's a design decision.. But they didn't create the "Variant" type for nothing and I use strings like variants.

    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.

    That's not the reason. But good effort. The main reason is that a serial interface cannot be configured just by a single parameter as all the others can (a port or a service name). It takes many more parameters to make anything useful. Therefore it would have considerably complicated the users interface to the API in that he would no longer have to supply a single string but things like baud rate, term char, parity etc just for that one interface. It is much more appropriate to add that to a layer up, which is outside the scope of the current API implementation.

    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.

    Well. No-one has a crystal ball. You code to the requirements and try to mitigate where you can (usually based on experience). Anything else is just blowing in the wind.

  12. Good point! I was thinking of something else but... It is still a nice feature that is handy.

    Don't you like it?

    Ben

    I neither like nor dislike. I don't really use it much since I tend to get one control just how I like it then copy it. What I do love though is that you can select a load of controls and make them exactly the same size at the click of a button.

  13. Yes, almost.

    Shame. The problem is you don't have access to the command window reference so you can't even send it a Ctr-C, exit or terminate it directly. You could do it if you invoked a command prompt using api calls though.. And you could probably do it with a batch file or script. But none of that is portable.

  14. After search in Labjack documentation i have find this :

    "

    <snip>

    "

    Can you agree that i can modify UI tread option to Any thread option.?

    I would say (tentatively) no.

    It says "Because of this Add, Go, and Get must be called from the same thread"

    If you set the nodes to any thread you cannot gurantee that that won't happen since you don't know (from call to call) what will run in what thread. So Add might be in one, while Get might be in another depending on what labview feels like doing.

  15. The difference is whether the DLL is "Thread Safe" or not. Orange means it runs in a single thread (the UI Thread and there is only 1). Nicotine coloured and it can be run in any thread that LV decides it wants too.

    It's best to use the UI thread if you are not sure. Side effects can be anything from crashes, strange behaviour, or erroneous calculation errors under certain conditions.

  16. Hi everybody,

    I'm acquiring data and saving that on my disk as .dat.

    Now I want to later open and analyse the data.

    So I'm busy with writing a VI thats read the .dat file. The VI is going to be a .exe file.

    This results in that I can set all my .dat files to that executable.

    The problem is:

    When I run my .exe, it still want me to select the .dat file I want to open.

    But I want it to read the path of the .dat file i'm opening

    Hopes my problem is clear ;)

    ____________

    Michael ten Den

    If you mean you want it to remember a fixed location. then you will have to either save the path somewhere (and load it when tha app starts), hard-wire a path into the file open, or save a control as a default value (right click on control then select "Data operations>>Make Current Value Default")..

    The reason it is asking you is because you have not specified a path into the file open (bear in mind that controls are reset to defaults when you open a vI or exe for the first time).

×
×
  • Create New...

Important Information

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