Jump to content

John Lokanis

Members
  • Posts

    797
  • Joined

  • Last visited

  • Days Won

    14

Posts posted by John Lokanis

  1. How do I create a generic message passing class that allows me to map specific messages to specific receivers?

    Basically, think of one of those pneumatic message tubes that used to be used to pass paperwork around a large building. The tube is generic, but the message is specific and has a specific destination.

    The Problem:

    I have an application with 7 parallel loops. Each of these loops monitors a queue and when it gets a message it de-queues it and takes the appropriate action (executes the proper case).

    Each loop can send a message to the other 6 loops.

    To make this work, I create 7 queues in the top level application and then pass all 7 queue references to each loop (they are each in their own sub-vi).

    Also, each case in each loops uses unique data. So, the data type of the queues is a cluster of an enum (the message type) and variant (the data). In each case I have to cast the variant to the proper data type before I use it.

    The Solution:

    I want to have a single class hierarchy that can handle all messages. I want each loop to have its own child class. I want each message in each loop to be a child of the loop's child class so I can use dynamic dispatch to choose the action taken.

    I want a single class wire to be sent to each loop. I will initialize the parent object to create a ‘channel’ for each loop. This must be done by passing an object of the loop's child type to a create method.

    Inside each loop sub-vi, it will call a method to get the queue reference for the ‘channel’ it is supposed to respond to. It will do this by passing an object of the loops’ child type to the get method.

    When a loop receives a message, it will de-queue it and pass it to an execute method that will dispatch to the correct action.

    To send a message, a send method will be called and the ‘action’ object (initialized with any specific data) will be passed in. This will cause it to be placed in the correct queue for the loop that responds to that type of message. (The action object is an object of one of the loop's children)

    The result will be a clean way to pass messages around the application without the need to pass large sets of references to each sub-vi. Also, there will be no need to type cast the data from a variant or use enums to set the message type.

    To add new messages, I will just need to create a new child class of the loop’s class. No need to modify any of the rest of the class hierarchy or change any typedefs.

    The Question:

    Is this even possible? If so, how do I do it? I have been trying to figure it out for a while with little progress. It seems feasible but I am just learning LVOOP and am not sure if there is an existing design pattern for this or a way to combine existing patterns. Has anyone done something similar?

    Bonus feature:

    It would be great if this would work in parallel with multiple copies of the top level VI. In other words, all the communication channels would be unique to the top level caller and not store any data in globals of any type.

    Thanks for any ideas or help with this…

    -John

  2. So if all "good" designs have a decoupled UI and a decoupled UI has to have cross platform capabilities, then I suppose I will have to settle for specializing in developing bad code.

    I don't know where you are going with this good vs bad thing. Decoupled code is not necessarily good and strongly coupled code is not necessarily bad. No one is trying to make those kind of judgments here. What we are trying to do is define what coupling is and what the benefits and pitfalls are.

    Most of the discussion has been surrounding what decoupling means. In that area, there has been some disagreement but I think we have come to a reasonable conclusion.

    For me, this has been helpful because I can now look at my designs and ask myself: "will decoupling offer any benefits to this project?" and "what steps will I need to take to decouple the UI from the rest of the code".

    Right now I have a strongly coupled design that I would like to change to a client-server architecture in the future, decoupling the UI from the functional code. From this discussion, I know that the best way to approach that is to define an API for the two to communicate that can be passed over a network. Now the fun part starts where I need to figure out how to best achieve that with the tools that LabVIEW offers.

    -John

  3. If the UI and the "logics" can run separately, they are decoupled IMO. But decoupled does not mean void of interface, obviously there has to be some interface and some communication of data or there would be two completely separate programs (of course also decoupled, but irrelevant). A close coupled program has no real interface since the UI and the "logics" are woven together, as in a typical PC LV application. So decoupled means separate programs communicating through an interface. The two programs only have to know the interface.

    I think this sums it up for me. Especially the bit about a defined interface. That is what I was going for. I would only add that the interface should be able to cross any boundary (interprocess, inter-application, internal network or internet) as dictated by the needs of the user.

  4. What I really want to achieve is a single file that contains a group of plugins and all their dependent sub-vis. I call this a library of plug-ins. And I want to be able to have multiple libraries that are installed over time and as needed. I want a single EXE that can call any plugin in any of these libraries if provided with the name of the library and the plugin within.

    The libraries should be able to be built from the same pool of source code sub-vis but once built, they must own their version of the sub-vis so there can be no cross linking at runtime. This way, we do not need to re-validate the EXE or older libraries when we release a new one with potentially updated sub-vis.

    I can currently do this using .LLBs and the OpenG builder. I am looking for a native NI solution that uses LVOOP and lvlibs or ppls or ??. I just want to understand the methods before diving into the re-architecture.

  5. Yes. I do something like this right now with Web Services. These also do not natively support a version number. My solution involves running a pre-build action in the build spec. This calls a VI that uses scripting to modify the default value of an indicator in another VI in the project. So, each time you build, the pre-build VI increments the value. You can then implement some code in your project to return the value of this indicator when you need to query the version number programatically.

    Setup your build script like this:

    post-2411-0-74344700-1301348689_thumb.pn

    Then modify the attached files to work for your project.

    Pre-Build Action.vi

    Web Service Version.vi

    Hope that helps!

    -John

  6. The module must be executable outside of the exe for debugging and development purposes with minimal wrapping.

    Explain. Executable apart from the main exe without using the LV dev environment? Or are you just saying you want to be able to test the modules without relying on the executable's code?

    The second one. I want to be able to develop modules that will be runnable in the LV environment without the presence of the exe's services. In otherwords, the module should be as decoupled from the exe as possible so that a simple wrapper can be used to allow it's execution. I need this so that many team members can create and test their modules without needing to run the main exe's code.

    Looks like I just need to caches an instance of each module class to hlod it in RAM.

    I will have to think about the rest of your responses and get back to you...

  7. I am working on an architecture to support a dynamically loaded set of test modules using LVOOP techniques. Since I am new to LVOOP, I am not sure the best way to proceed. Here are some details:

    • The exe needs to be able to call a test module from the external library using only the name of the library and the module. Assume that all libraries will be stored in a fixed location relative to the exe.
    • The exe will spawn multiple parallel processes that could each call the same module at the same time. The module therefore must be completely reentrant to allow this with no blocking or cross contamination of state data.
    • Each of the parallel processes is allow to call multiple copies of the same module simultaneously, if the module allows for this type of operation. So, each process must allow this with no blocking or cross contamination of state data.
    • The exe needs to pass information to the module in a standard format to control its execution (parameters).
    • The exe must be able to determine if the module is still running (or crashed).
    • The module must be able to monitor a set of Booleans controlled by the exe in order to respond to abort or error flags.
    • The module must be able to pass back messages to the exe while it is still running to update its status.
    • The module must be able to pass back its results to the exe and those result must remain accessible and readable after the module has completed and left memory.
    • The module must be executable outside of the exe for debugging and development purposes with minimal wrapping.
    • Each library of modules must be packaged into a single file that removes diagrams, type defs, etc.
    • Each library of modules much include all sub-vis calls by any module in the library and those must be name-spaced to prevent cross linking with similar named Vis from other modules in other libraries that might be in memory at the same time. This way a common set of source code can be used by all modules but is frozen to the version used at compile time (of the library)
    • Once a module is loaded from disk and called by the exe, a template of it will remain in memory so that future calls will not incur a disk access as long as the exe remains in memory.

    My first inclination is to make a common ancestor class for all test modules. Each test module would then be a child class of this ancestor. I could then call the module by instantiating an instance of that class. The ancestor could then have must override methods for parsing the parameter inputs and for converting the modules output into a standard format for the exe to read. Not sure how to implement the flag monitoring or status updates.

    I really have no idea how to package the modules into libraries. Packed Project Libraries? Right now in my non-LVOOP implementation I use the OpenG builder to create an LLB with the same characteristics.

    Any ideas you can offer are appreciated!

    -John

  8. As far as I know and have experienced, Open Reference in VI Server is always blocked by the root loop, regardless of what you pass to it. This makes for some interesting headaches if you have a system that uses dynamically loaded plug-in test modules that are opened as needed while a process runs. The user can effectively hit the 'pause' button by simply dropping down an menu and not making a selection. frusty.gif

    I have no idea how to work around the problem. Maybe one of the NI gurus can chime in...

  9. I have been trying to view the LVOOP Design Pattern document on the NI site for the last few days but cannot get it to load. Does this link work for anyone else?

    http://decibel.ni.com/content/docs/DOC-2875

    I know this is the right link because I have it saved from before and I have found links to the page from other pages discussing LVOOP.

    It also seems the search functions of NI.COM are down as well. frusty.gif

    -John

  10. Think of the UI as your boss and you as the core. Your boss tells you what to do but can't doing anything himself. You have to do all the work. tongue.gif

    Therefore, you are decoupled from your boss. He can be fired and a new boss brought in and you will still do the same work. If you are fired, the boss can't get anything done without you! (one of the joys of being a LV dev cool.gif)

    • Like 1
  11. Daklu - fair enough. I can agree with that.

    I am trying to architect some code where the UI will be as dumb as possible but still as decoupled as possible. In other words, with you example, the UI will send the file path to the core but the core will do all the error checking on it and send back any error messages to the UI to display. The UI code will only deal with the controls on the FP and other things that need to be displayed.

    My goal is to eventually move the UI off the computer that the core code is running on, possibly replacing it with a web interface. Also possibly replacing it with a multi client, single server paradigm.

  12. Whilst a network interface can be used to achieve decoupling. I don't think it's a requirement - just an implementation method,

    That is not my point. frusty.gif A network interface is just an example. The interface could just as easily be a queue. The point is it CAN be sent over a network if you so choose. In other words, the UI and the core engine know nothing about each other's implementation. They just pass data over a <insert generic interface here>. If you are passing references from your UI to your low level code, then you low level code must know a lot about your UI and therefore you are not decoupled.

    I'm not saying that is a bad design. I do it all the time. I am only saying that it should not be considered a decoupled UI design.

  13. Just because you passed all the reference from your FP to a sub vi does not mean you are decoupled. The sub-vis still need to know what is on the FP and how to control it.

    To be decoupled, you would need your FP to have code behind it that received data from the core engine and then decides how to display it based on your UI's layout.

    To return to a point I made awhile back, if you UI and core engine cannot be on separate computers on a network, then you are not decoupled.

  14. "There is the rub" (Hamlet, Act 1 scene 1 ?)

    Yes, but only if you app is trying to display data at high speed. If your app is some sort of automation control app, you likely are not doing anything that a 1ms delay could affect. And, in most cases it is less than that. Additionally, there are ways around this by creating a separate dedicated channel for the high speed data and having a separate UI loop handle it.

  15. Cat - Web Service support SSH, if you need it.

    And, there is no reason you need to use them for a decoupled UI. You could just as easily use a queue if you UI and core are both running on the same machine in the same app instance.

    The benefit of a decoupled UI is: can replace or change without affecting the core code. Can use message channel to automate core (headless). Can use message channel to test core and UI separately. Cna log message channel for field debugging.

    Downsides are: more code to write. Not as easy to implement, design wise. Might offer slower performance in high speed apps.

  16. I guess my original point is not getting across. How about thinking about it this way: If you UI can run on one computer and your core engine can run on another computer, with nothing between them other than the network, then your UI is decoupled.

    I am not saying that the UI portion has no code in it. In fact, I expect it to have a lot of code in it to interpret messages from the core engine then implement the data changes as UI control changes, utilize whatever methods are required. I also expect the UI code to convert user events into messages to tell the core engine what to do. That way, the only connection between the UI and the core is a bidirectional messaging system. Those messages can then travel over whatever link you desire. And you can monitor and log those messages for debugging. You can also inject messages from non-UI actors to automate your core engine and your can do the same to create test simulations for your UI. That is what IMHO a decoupled UI is. You are free to disagree but I hope you at least understand what I am trying to say.

  17. I just don't want to encourage anyone to try to decouple UI code where that approach really doesn't fit and would add unneeded complexity.

    Agreed. As I said, I don't do this normally. Just need to look into it for a particular application. I like the idea of having a channel between the UI and core that I can monitor, log and use for test injection. Also, this would make external automation very easy. All these things matter in my application.

  18. I'm not saying you should always decouple your UI from the core engine of your code. I'm just saying that if you are passing FP refs to low level code, you are not decoupled.

    I do this all the time in many application. And I know full well that I am essentially tying these two parts together in a way that would not be easy to separate in the future. So, while this might be the right approach in many cases, it cannot be called 'decoupled' if you do this.

    But, in my case I want to move to a system where the UI could be replaced without changing the core engine code. And I want to eventually change to a client-server architecture where the core server can manage several client UIs simultaneously. That requires a fully decoupled UI design.

×
×
  • Create New...

Important Information

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