====== 11 DQMH ======
**Official DQMH Best Practices:** \\
[[https://delacor.com/dqmh-documentation/dqmh-best-practices/]]
===== Structure =====
* Nomenclature
* EHL = Event Handling Loop
* MHL = Message Handling Loop
* HL = Helper Loop
* Exclusive error range per module (see [[http://dokuwiki.hampel-soft.com/error-codes|HSE Error List]])
* Embrace the "Queued Message Handler" architecture
* Handling of incoming events is done in the EHL - the producer
* Processing of messages and data is usually done in the MHL - the consumer
* HLs can add additional producers and or consumers to a module (see below)
* Code that takes long to execute needs to be implemented in the MHL, so that the EHL always stays responsive and is never blocked.
* Simple code that executes quickly can be put into EHL to avoid unnecessary event/queue traffic
* Some framework-level events (show panel, hide panel, shown diagram, get execution status, etc.) do this
* Embrace .lvlib best practices
* Keep all VIs belonging to a module inside its .lvlib
* this avoids naming conflicts etc.
* makes it easier to reuse code
* makes it easier to understand architecture
* Scan for loose VIs in same folder as lvlib
* Create a project and add the folder
* Project structure should only show files inside lvlib and the tester(s)
* Other VIs should be either added to library or deleted from disk.
* [[https://forums.ni.com/t5/Community-Documents/Feature-Find-Non-Project-Files/ta-p/4347088|Alternative for finding non-project files on ni.com]]
* The ''Main.vi'' is the only element on the root level of the module .lvlib. All other VIs and files reside in subfolders (see below)
* Private requests to Cloneable modules should always be "local instance" unless the architecture requires a shared event.
* Usually we don't need shared events and can get rid of the "Addressed to me"-VI and lots of cases.
* When registering for a module's broadcast events, use the ''Null Broadcast Events--constant.vi'' for preparing the event data type when creating the event registration reference. Then use either the ''Start Module.vi'' or the ''Obtain Broadcast References for Registration.vi'' for actually registering the real, life references at runtime. \\
{{kb:bestpractices:codingconventions:dqmh-codconv-registerforbroadcast.png|}}
----
===== Where to place code =====
* On Disk:
* Put all manually created VIs into a ''/SubVIs'' folder and create further subfolders inside ''/SubVIs/'' as needed
* Helps separate scripted/generated VIs from self-created ones, especially when viewing changes in Source Code Control
* In the .lvlib:
* Add a ''/Private/SubVIs/'' virtual folder for any files that don't fit the following
* Place constants, errors and typedefs in the corresponding virtual subfolders in ''/Private''
* Store any resources that need to be accessible from outside the module into virtual subfolders below the ''/Public API'' virtual folder
{{:kb:bestpractices:codingconventions:where-to-place-code.png?direct|}}
* **Pre version 7.0**: Put private (VI-local) requests into a virtual folder called "Private API" and either "Request" or "Broadcast" virtual subfolder (similar to the "Public API" folder)
* make the folder private
* add a "private" key glyph to the request VI's icon
=== "Initialize" Case ===
* Do not place any code before ''Synchronize Caller Events.vi''
* For HSE, the "Initialize" case of a DQMH module's MHL is a framework function. We make a point of not adding any business logic to it. This is similar to an object's constructor never failing, thus guaranteeing a successful launch ([[https://forums.ni.com/t5/DQMH-Consortium-Toolkits/How-to-enqueue-initialisation-steps-without-self-enqueuing/m-p/4414267/highlight/true#M3159|quoting Dhakkan]]). Instead, we use a "Configure" case.
* Every HSE module implements a "Configure" request which is triggered externally telling the module to go find and load its configuration, and potentially also do more, depending on the nature of the module.
* In our HSE Application Template, that "Configure" request is executed automatically by the framework.
* If the module needs to connect to hardware, a database, etc, we will implement a separate "Connect" request (ie that's neither part of the initialize nor of the configure case).
=== Outside MHL/EHL/HL ===
* Be careful when adding code outside of the EHL/MHL/HLs, especially code that executes before the main Error Structure of the Main.vi and might delay running ''Synchronize Caller Events.vi'' inside the "Initialize" MHL case. If that code takes too long to execute, the module initialisation will time out and the //Start Module.vi// will throw error 403683 ("Module was unable to synchronise events").
See **[[kb:labview-frameworks:dqmh:starting-modules#implications|Starting DQMH Modules - Implications]]** for more details and background information on why placing code outside or before EHL/MHL/HL might lead to timeouts.
----
===== Parent/Child Modules =====
* Make sure that if a module (parent) starts another module (child), it also takes care of stopping it again.
* Ensure that for any module that's started, there is a place collecting status and error information from that module. Usually, the module starting another module (parent) registers for that other module's (child) broadcast events and handles or forwards at the very least the "Error Reported" broadcast accordingly.
* Start and stop your modules inside the MHL, EHL or HL, do **not** start them before entering the EHL or MHL.
* prevents synchronization errors if starting the modules should take too long
* gives you control over when exactly to start modules
* lets you restart modules during runtime
* conveys intent through the code itself
See **[[kb:labview-frameworks:dqmh:starting-modules#starting_child_modules|Starting Child Modules]]** for more details and variations of starting modules.
----
===== Helper Loops =====
//DQMH 7.0 introduces support for Helper Loop scripting, which makes the manual creation obsolete.//
* When coding a repetitive operation, use a helper loop that is registered to the ''Stop Module'' event and does the repetitive operation inside its timeout case.
* There's [[https://forums.ni.com/t5/Delacor-Toolkits-Discussions/Helper-loops-for-active-repetitive-tasks/td-p/3752169|a discussion thread on the NI Forums]]
* You can find [[https://www.hampel-soft.com/blog/dqmh-actors-self-messaging-or-helper-loops/|a whole article about Helper Loops on our blog]]
* If a Helper Loop has its own "Task" that is unrelated to the Message Handling Loop (MHL), all public requests can be directly addressed to the HL via scripting. However, if the HL and MHL are interrelated, and only part of the code is executed in the HL, public requests should go through the MHL. Within the MHL, a private request can then be made to call the HL. This approach helps to ensure readability.
== Helper Loop Style==
* HLs need to have their enclosing while loop coloured
* All Request VIs communicating exclusively with/to the HL need to have a ribbon in the same / similar color on their icon
* If a HL must not be manipulated from outside the VI, make sure to only register Private Requests to the HL
{{:kb:bestpractices:codingconventions:helper-loop-color.png?400|}}
----
===== Style =====
* In MHL, leave "Variant to data" and optional "Send Notification" on block diagram of main.vi, outside subVIs
* separate DQMH code from module-specific code
* DQMH modules have to have a coloured Icon badge so VIs are better discernable
* see **colors** section in [[kb:bestpractices:codingconventions|Coding Conventions]]
* Broadcast VIs get a specific glyph on their icon to separate them from request VIs
* see **glyphs** section in [[kb:bestpractices:codingconventions|Coding Conventions]]
* Store data inside the MHL's data cluster on the shift registers, do not create FGVs for data internal to the module
* Remove the ''#DQMH Code Recommended'' comments once the code has been added (or if no code is to be added)
----
**[[https://createbettersoftware.com|The HSE Way of Working]]:** \\
A set of guidelines that recommend programming style, better practices, and methods for all our LabVIEW projects. We ask all our peers to follow these guidelines to help improve the readability of our shared source code and make software maintenance easier.
|< 100% 50% >|
|[[kb:bestpractices:codingconventions:lvoop|<< 06 LVOOP]] | [[kb:bestpractices:codingconventions:statemachines|21 State Machines >>]]|
Contributors for this page: #teamhampelsoft, Darren Nattinger