DQMH Consortium Toolkits Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

dynamically register Broadcast and Requests

Solved!
Go to solution

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?

 

Generic Broadcasts and Events.png

 

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 🙂


Proud developer at Hampel Software Engineering where we turn '404 not found' into '200 OK'. Join us on Discord
Message 1 of 15
(5,459 Views)

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

Christopher Farmer

Certified LabVIEW Architect and LabVIEW Champion
DQMH Trusted Advisor
https://wiredinsoftware.com.au

0 Kudos
Message 2 of 15
(5,419 Views)
Solution
Accepted by AlexElb

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


Message 3 of 15
(5,412 Views)

@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:

  • The DQMH which should send generic Broadcasts implements a Obtain Default Broadcast Events.vi
  • tha VI encapsulates the module-specific Obtain Broadcast Events for Registration.vi and only returns the default broadcast event references that any HSE DQMH module features: here you've added a generic Broadcast "System Message"
  • In the DQMH which should register for that generic Broadcast you use DQMH Obtain Default Broadcast Events.vi
  • In that VI you look through all your modules in a folder and extract the references to the default broadcast events (by Calling the VI by Reference)
  • Finally you use a private Request to send that references to the EHL (Register for module events) and register the EHL to the conrete Broadcast "System Message"

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:

  • The standard DQMH way is to call two requests: Start Module.vi and Synchronize Module Events.vi.
  • Again you've encapsulates the module-specific connector panes by implementing a Load Module.vi which has the same connector panes for all modules.
  • you use a path to the module and look for the Load Module.vi
  • With a Call By Reference function you finally run the Requests

 

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.

  • Request Events must have the same connector panes to be called by reference dynamically
  • That can be achieved by a) encapsulating, if no or the same data input or output is neede or b) using a variant
  • Now we have implemented a "Do Something Request.vi" in multiple DQMHs 
  • Implement a VI "Dynamically Call Do Something Request.vi" which takes a reference to the application and a path to module as Input. There build the path to the "Do Something Request.vi" and call it by reference
  • In the DQMH which should call the Requests we need to know the modules path information and call the VI "Dynamically Call.."

 

Now to the case where a DQMH should dynamically register to multiple Broadcast Events:

  • Again: The Broadcast Events "Did Something" all must have the same connector panes
  • Implement a "Obtain Did Something Event for Registration.vi" in the multiple modules and wire out the needed reference
  • Implement a "Dynamically Call Obtain Did Something Event for Registration.vi" which takes a reference to the application and a path to module as Input. There build the path to the "Obtain Did Something Event for Registration.vi" and call it by reference, wire out the needed reference
  • In DQMH which should register for that Broadcasts:
  • Create Request Event: "Register for Did Something Event" with an array of the Broadcast reference as argument and move it to the Private folder
  • We need to know the modules path information and call the VI "Dynamically Obtain..." (in a loop thats why we need an array of references)
  • Bundle a constant of the "Did Something" Eventreferences (as an array) to the DQMH_REG_EVENTS User Event
  • Send the array of the Broadcast references to the EHL using the newly created private Request and register them to the EHL
  • we can now create a new EHL-case "Did Something User Event"

 

 Updated Sequence DiagramUpdated 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.


Proud developer at Hampel Software Engineering where we turn '404 not found' into '200 OK'. Join us on Discord
Message 4 of 15
(5,340 Views)

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


Message 5 of 15
(5,309 Views)

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


0 Kudos
Message 6 of 15
(5,308 Views)

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


Proud developer at Hampel Software Engineering where we turn '404 not found' into '200 OK'. Join us on Discord
0 Kudos
Message 7 of 15
(4,975 Views)

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.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 8 of 15
(4,972 Views)

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.

Christopher Farmer

Certified LabVIEW Architect and LabVIEW Champion
DQMH Trusted Advisor
https://wiredinsoftware.com.au

0 Kudos
Message 9 of 15
(4,953 Views)

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


Proud developer at Hampel Software Engineering where we turn '404 not found' into '200 OK'. Join us on Discord
0 Kudos
Message 10 of 15
(4,945 Views)