====== 12 Starting DQMH Modules ======
===== Launching a module =====
There are two ways of launching a module:
=== Internally ===
* By clicking the //Run// arrow of the module's ''Main.vi''.
* The module is the top level of the execution and needs to take care of any resources, errors etc by itself.
=== Externally ===
* By using the module's ''Start Module.vi'' and ''Synchronize Module Events.vi'' API functions.
* The module is not at the top level of the execution as it is being started by another VI which might or might not be a DQMH module itself. If the VI starting the module is a DQMH module itself, we refer to the module being started as a **child module** and the module starting it as the **parent module**.
//The following sections discuss aspects and ways of launching modules externally//.
----
===== Startup / Synchronization =====
The DQMH Framework helps developers write reliable and robust code by taking care of various aspects like reference lifetime and synchronization of actions. When starting a module, the module itself creates all required resources like event references to own them and dictate their lifetime.
To ensure that the code starting the module receives any resources only after they've been created, and to make sure that the code only continues execution once the module is ready to receive requests, the DQMH Framework provides the process described in this section.
{{:kb:labview-frameworks:dqmh:dqmh_starting_modules_sync_steps.png?direct|}}
==== Process ====
== 1. Start and Obtain Broadcasts ==
* The calling VI executes ''Start Module.vi''
* ''Start Module.vi''...
* uses //Start Asynchronous Call// to run the module's ''Main.vi''
* continues to ''Wait on Module Sync.vi'', which waits until a second task arrives at the "Module Sync" rendezvous **[A]**
**[A]** Start Module.vi needs to wait until the broadcast event references have been created by the module.
* ''Main.vi''
* executes ''Init Module.vi'', which creates both the module's broadcast event references and the request event references
== 2. Continue to MHL ==
* ''Main.vi'' continues to start Event Handling Loop (EHL), Message Handling Loop (MHL), and any Helper Loops (HL; optional)
== 3. Sync with Caller ==
* ''Main.vi'' enters the "Initialize" case of the MHL
* executes ''Synchronize Caller Events.vi''
* ''Wait on Module Sync.vi'' adds the second task to the "Module Sync" rendezvous
* ''Start Module.vi'' now continues execution
* ''Wait on Event Sync.vi'' waits until a second task arrives at the "Event Sync" rendezvous **[B]**
**[B]** The module needs to wait until the calling code has registered for the broadcast events.
* ''Start Module.vi'' returns the Broadcast event references
== 4. Register for Broadcasts ==
* The calling VI registers for the broadcast events
* The caller will receive any broadcast sent from this point (creation of the registration) in time onwards
== 5. Sync with Main.vi ==
* The calling VI executes ''Synchronize Module Events.vi''
* ''Wait on Event Sync.vi'' adds the second task to the "Event Sync" rendezvous
* In the ''Main.vi'''s "Initialize" MHL case, ''Synchronize Caller Events.vi'' now continues execution
* Both rendezvous references are now closed.
//The caller is now finished with starting the child module//
== 6. Sync with Caller ==
* In the "Initialize" MHL case of the ''Main.vi'', ''Synchronize Caller Events.vi'' now returns and the rest of the code in that case is executed.
== 7. Module Did Init ==
* Once the code in the "Initialize" MHL case has finished executing, the ''Module Did Init.vi'' broadcast is sent.
//The child module is now finished with starting//
* The Caller can choose to register to this broadcast for added synchronization.
@startuml
skin rose
title "Child module startup"
skinparam ParticipantPadding 10
box "Calling code"
participant "Synchronize Module Events.vi" as SyncModuleEventsVI
participant "Start Module.vi" as StartVI
participant "Caller.vi" as CallerVI
endbox
box "Module code"
participant "Main.vi" as MainVI
participant "Init Module.vi" as InitVI
participant MHL
participant "Synchronize Caller Events.vi" as SyncCallerEventsVI
endbox
CallerVI -> StartVI : Call "Start Module.vi"
activate StartVI
StartVI -> MainVI : Start asynchronous call
StartVI -> StartVI : Wait on Module Sync
MainVI -> InitVI : Call "Init Module.vi"
activate InitVI
InitVI -> MainVI : Returns events refs
deactivate InitVI
MainVI -> MainVI : Start EHL/MHL/HLs
MainVI -> MHL : Execute MHL's Initialize case
MHL -> SyncCallerEventsVI : Call for synchronization
activate SyncCallerEventsVI
SyncCallerEventsVI -> SyncCallerEventsVI : Wait on Module Sync
SyncCallerEventsVI -> StartVI : Module Sync Done
SyncCallerEventsVI -> SyncCallerEventsVI : Wait on Event Sync
StartVI -> CallerVI : Returns broadcasts refs
deactivate StartVI
CallerVI -> CallerVI : Register for broadcasts
CallerVI -> SyncModuleEventsVI : Call for synchronization
activate SyncModuleEventsVI
SyncModuleEventsVI -> SyncModuleEventsVI : Wait on Event Sync
SyncModuleEventsVI -> SyncCallerEventsVI : Event Sync Done
SyncModuleEventsVI -> CallerVI : Module started
deactivate SyncModuleEventsVI
SyncCallerEventsVI -> MHL : Continue Initialize case
deactivate SyncCallerEventsVI
MHL -> MHL : Send Module Did Init broadcast
CallerVI -> CallerVI : Receive Module Did Init broadcast
MHL -> MHL : Module initialized
@enduml
==== Implications ====
Any rendezvous functions mentioned above will wait for the module timeout defined in ''Module Timeout--constant.vi'' (default = 5s) before returning an error.
It becomes apparent that **2. Continue to MHL** in the schema shown above is the critical path. If any code is placed before the MHL starts (i.e. before ''Synchronize Caller Events.vi'' inside the "Initialize" case) which takes longer to execute than the module timeout, the startup process of the module will fail.
==== Caveat ====
Be careful when adding code outside of the EHL/MHL/HLs, especially code that needs to execute before entering the EHL/MHL/HLs and might therefore delay entering the "Initialize" MHL case. If it takes too long to reach the "Initialize" case, the module synchronisation will time out and fail, and the //Start Module.vi// will throw error 403683 ("Module was unable to synchronise events").
----
===== Starting Child Modules =====
Make sure to also browse our [[kb:bestpractices:codingconventions:dqmh#parentchild_modules|HSE Coding Conventions on Parent/Child Modules]].
==== 1. From a Simple VI =====
* Ie not from another DQMH Module. One example is the API Tester.
{{:kb:labview-frameworks:dqmh:start-dqmh_01.png?direct|}}
----
==== 2. At Module Start ====
* Child module is started automatically when starting the parent module
* Adding code outside of EHL/MHL ([[#caveat|see Caveat above]])
* Risk of timeouts -> not recommended by HSE
{{:kb:labview-frameworks:dqmh:start-dqmh_02.png?direct|}}
----
==== 3. In the EHL ====
* Child module is started via a request [[#when_to_start|[1]]] by adding code to the EHL
* EHL (producer) now contains code that should ideally be placed in MHL (consumer)
* Code potentially blocking the EHL -> not recommended by HSE
{{:kb:labview-frameworks:dqmh:start-dqmh_03.png?direct|}}
----
==== 4.1 In the MHL - Variant 1 ====
* Child module is started inside MHL, can be triggered via request or simple Queue message [[#when_to_start|[1]]]
* Forking the registration reference wire so we can update the event registration of the EHL in the MHL
* Potential confusion about forked registration wire - not recommended by HSE
{{:kb:labview-frameworks:dqmh:start-dqmh_04a.png?direct|}}
----
==== 4.2 In the MHL - Variant 2 ====
* Child module is started inside MHL, can be triggered via request or simple Queue message [[#when_to_start|[1]]]
* Using a private request and wait for reply to let the EHL register while executing the MHL case
* More implementation work but little technical debt -> recommended by HSE
{{:kb:labview-frameworks:dqmh:start-dqmh_04b.png?direct|}}
----
===== When to start =====
The concept of placing the code for starting modules inside EHL/MHL and having a request or Queue message trigger the starting of child modules gives control and flexibility over when and from where modules are actually (re)started. It does beg the question, though, of where and when to actually send the request or message triggering the start.
* HSE modules with the need for automated sequential steps usually feature a [[code:dqmh:state-machine|State Machine]].
* Our [[code:dqmh:hse-application-template|HSE Application Template]] calls the "Configure" request automatically for any module it starts, which is another potential place for sending such a request (usually in combination with a state machine, though)
----
===== Better Practices =====
Our better practices section on [[kb:bestpractices:codingconventions|Coding Conventions]] contains a page on DQMH®: \\
**[[kb:bestpractices:codingconventions:dqmh|DQMH Coding Conventions]]**