12-03-2019 04:04 AM
Hello out there,
I didn't come up with a solution, so may be you have some clever ways for the following problem. Lets say we have n modules which all should implement a few common methods, which should be triggered by another module. How do you solve that?
My thought is, that they register themselves with a generic Broadcast Event and the other module "Main" stores some references in an array. Then it can call dynamically the methods of the modules by using the references of the requests...
So, can I implement the Requests "do something" and "do something else" and just copy the refnum out of the Obtain Request Events.vi and pass those as the Broadcast data? When adding modules, I don't want to manually add Requests.vis to "Main".
And how would I register for the generic "Register Module" Broadcast Event? In "Main" I don't want to start Module1 and Module2. Also I only want only one generic EHL-Case for all n modules.
Thanks in advance for any suggestions 🙂
Solved! Go to Solution.
12-03-2019 02:59 PM
Consider having a "n Modules Manager" module sitting above n Modules, to be your "single EHL" that looks after n Modules, and also launches the n Modules.
One thing I've observed from recent projects is that if we make a module a cloneable, then there still needs to a management layer sitting above it to handle the fact that we have more than one clone doing things, and the application needs to know about how to use these cloneables properly (whether that is in the form of another module, or just a bunch of Sub-VIs in the application).
12-03-2019 04:42 PM
Maybe you can draw some inspiration from how we start and register modules (and call their API dynamically) in our application template: https://gitlab.com/hampel-soft/dqmh/hse-application-template
DSH Pragmatic Software Development Workshops (Fab, Steve, Brian and me)
Release Automation Tools for LabVIEW (CI/CD integration with LabVIEW)
HSE Discord Server (Discuss our free and commercial tools and services)
DQMH® (Developer Experience that makes you smile )
12-05-2019 08:33 AM
@joerg.hampel wrote:
Maybe you can draw some inspiration from how we start and register modules (and call their API dynamically) in our application template: https://gitlab.com/hampel-soft/dqmh/hse-application-template
Hey Jörg, thanks for the tipp. There is a lot of code to go through in that template. What I've found is the following in the Event Manager:
That seems pretty clever to me. And if I would use a template for my DQMHs it wouldn't make too much effort...
Okay, if I've got that right, that would work for the first part of my problem: How to register for generic Broadcast events.
Now, how to call dynamically some request events:
Your're using a similar way to start your Modules dynamically:
While writing this post I've learned a lot. So I'll try to sum it up in general and start with the easier case:
One module wants to call dynamically the same Requests to multiple DQMHs.
Now to the case where a DQMH should dynamically register to multiple Broadcast Events:
Updated Sequence Diagram
Please correct me, if I've missed some important points
When creating the user event referencesand the VI references, do I have to consider something? Can I just create them in one Module and use the for the other too? Unless they are not stricty type def...?
What is the difference between dynamic and generic? What should be in my mind when designing a solution?
I think what I am doing in this diagram is only dynamic: At edit time the Dynamic Module doesn't know which Modules it will call and to which Modules it will react. Though having a Dynamically Call Obtain Did Something Event for Registration.vi is very specific. So Dynamic Module doesn't know which modules, but it knows exactly which Events are involved. Is this good or bad?
Are you doing something more generic with your System Message in the template?
Thanks Christopher for your hints concerning the cloneables. Until now I was speaking about multiple Singletons. That problem will probably come later to my mind, when I'll start using clonables.
12-06-2019 07:11 PM
Blimey, that is one elaborate answer / write-up! I'll ditch our documentation and just link to your post 😉
Regarding the template application: The TEMPLATE_Source/startup.vi reads the list of modules to load from TEMPLATE_Config/config.ini. It starts the User Manager (the module comprising the UI frame of the application) and the Event Manager (used for debugging mainly), starts all the modules as defined in the config file, then hands over the list of modules to UI Manager and Event Manager. And then some more stuff.
More information is available in our Dokuwiki:
https://dokuwiki.hampel-soft.com/code/dqmh/hse-flavour
https://dokuwiki.hampel-soft.com/code/dqmh/hse-application-template
Coming back to your questions: For creating the references, I made sure to have dedicated template VIs and typedefs in a shared library to avoid any unwanted dependencies.
Dynamic in this case to me means "not static", as in no static dependencies. Not so much "not knowing who to call at develop time". That rather falls into the category of "generic", meaning to me "not catering to a specific situation", i.e. a high level of reusability.
And yes, "System Message" itself is generic. We use it both generically (eg forwarding networked messages without knowing about sender, receiver or content) and specifically (eg for communicating specific commands to the UI Manager).
DSH Pragmatic Software Development Workshops (Fab, Steve, Brian and me)
Release Automation Tools for LabVIEW (CI/CD integration with LabVIEW)
HSE Discord Server (Discuss our free and commercial tools and services)
DQMH® (Developer Experience that makes you smile )
12-06-2019 07:13 PM
It's quite late and I don't know the specifics of your use case, but maybe switching requests and broadcasts would be an option? It sounds like you want to call multiple requests with the same message type - could that be a broadcast?
Also, you could look into sending objects instead of variants, to alleviate the loss of strict data typing.
DSH Pragmatic Software Development Workshops (Fab, Steve, Brian and me)
Release Automation Tools for LabVIEW (CI/CD integration with LabVIEW)
HSE Discord Server (Discuss our free and commercial tools and services)
DQMH® (Developer Experience that makes you smile )
04-20-2020 08:31 AM
Hey there,
weeks go by and if you don't use it, you forget it...
So here I am once again thinking about a similar question. May be it is already solved with the approaches in this thread, or with the generic System Message Jörg implements in his HSE Templates...?
Lets say I have three modules for a real world example:
HW_Aquisition_Real and HW_Aquisition_Simulated both implement a Broadcast "New Data Aquired"
HW_GUI should register for the Broadcast to display the data
Now there is a starter module, which starts the GUI either with the real or with the simulated module. We want loose coupling, so the three modules should know as less as possible from each other. So the GUI could register itself with kind of a placeholder "new data aquired" broadcast. It would then not have any VIs of _Real or _Simulated inside. But then, one of these two would have to send a request "Register for Event" to the GUI, so that the GUI could update to a valid reference. So the dependency would only have switched, because _Real and _Simulated would now both have a VI of the GUI inside.
The only way to avoid that seems to be to use a "call by reference" node, or how would you solve this? Hey, what about that starter module I mentioned? I've not actually thought about! It should be the one, who would be allowed to "know" about every module, wouldn't that be a good place to start of?
Thanks in advance
04-20-2020 08:44 AM
I don't have any example handy, but basically you could use an OOP factory pattern and dynamic dispatch.
Settle on a common set of messages for all your HW devices (real and simulated). Create an abstract class with a method for each message. This resides outside of any DQMH module.
Then for each HW module, wrap its messages in a child of your abstract class.
Use a factory in the main which outputs an object (type is your abstract class)
The Main module depends on the abstract class and so do each of your HW modules. But there is no dependency between the HW modules and the Main.
To make things easier create a HW template that already has all the messages in it and already has them wrapped with a child of your abstract class. Then when you create a new module, the class will already be in place. All you would have to do then is fill in the MHL code.
04-20-2020 06:15 PM
Hi AlexElb,
For an application we did recently, we did something similar.
We had a Launcher module (your Starter module)
We had a Gui module
We had an XNET module
The Launcher module launched both the Gui and the XNET modules. The Gui and XNET modules did not know about each other. However the Launcher depends on both the Gui and the XNET. The Launcher is the glue of this application. The Launcher can call Gui or XNET requests, and can receive broadcasts from either the Gui or Xnet. The Launcher module in fact does not actually have to be a DQMH module - it can just be a VI, because there are no public requests to it, and it does not need to broadcast to anything.
The typical way our application runs, is that the XNET reads in CAN data, and broadcasts it to the Launcher. The Launcher upon receiving the broadcasts, turns around and calls requests of the Gui to update the Gui. There might be controls on the Gui which the operator can adjust (say change the read rate of the XNET), which would then send a broadcast up to the Launcher, and then the Launcher would turn around and request of the XNET to update its settings.
This PROs to this approach is that the Gui and XNET modules are not dependent on anything, so they can be developed as their own modules in isolation. It is also very easy to test each of these modules.
The CON is that the Launcher is essentially a middle man and so you're doubling up in all of your messages. Also, it is a potential bottleneck, in cases where you might have multiple GUIs and multiple devices.
04-21-2020 01:21 AM - edited 04-21-2020 02:24 AM
Thank you for your suggestions.
Sam, to be hones I cannot follow. When speaking about classes I see methods - but don't know what kind of messages you are talking about.
Lets say a have three classes: HW_Abstract, HW_Real, HW_Simulated and both child classes implement the abstract method "aquire new data". Then we have a HW_Factory which either gives the GUI a real- or a simulated-hw-module. So far so good.
But I don't get the connection to the DQMH-Communication-World. How do the child classes communicate the "New Data Aquired" Broadcast? You're not talking about wrapping a whole DQMH-Module in a class aren't you?
Christopher, I get it, and I like it! I just tried that slightly changed: The lancher starts the GUI and either one of the HW-module. The GUI implements a Request "Register for New Data Aquired Broadcast". Since the launcher knows, which HW-module is running, it obtains the valid refnum to its Broadcasts and calls the request of the GUI. After that, the GUi is directly listening to the Broadcast Event of the correct HW-module. So there is no need for the Launcher to send each received Broadcast as a Request again down the line, reducing the responsibility of the middle man from "communication bottleneck" to some "orchestration" of the modules. Do you see any CONS in this approach?
EDIT: First CON detected: How do you test? In the tester.vi of the GUI I would like to test the Request "Register for .... Broadcast". To do so, the tester has to start one of the hw-modules. So again, now the tester has a dependency to the hw_modules.To avoid that we could have a "integration tester". When I want to reuse the GUI in another project, I would copy everything except that integration tester and my new project shouldn't have any dependencies loaded...