I am trying something new for NI week 2018. I will prepare this blog post including all the demo videos ahead of time and publish it the day of the presentation. Once I edit the video of the presentation, I will add it to this blog post Video of the presentation is below this paragraph. This way you can get the material right away. This bit.ly/fabNIWeek2018DQMH takes you back to this post.
The tips and tricks cover the following areas:
- Planning a new DQMH based project
- API Testers
Planning a new DQMH based project
We will be refactoring the NI QMH Continuous Measurement and Logging sample project that ships with LabVIEW. You get to this sample project by going to Getting Started>>Create Project>>Sample Projects. Once there, select the Continous Measurement and Logging sample project. If you are not familiar with this project, the video below gives you an overview.
We are going to create a DQMH based project for the same application. Now, this is where I remind you that if all you ever want to do is an application to continuously acquire and log, this is all you need. Stop here, no need to go any further. However, in our experience, people always end up wanting a lot more than just a simple acquisition application. If you have found yourself wanting to reuse an acquisition module from one project in another project, if you have wanted to add a more complete settings editor, if you work in a team and you find it is difficult to split the work between different developers, or if you are just curious about DQMH projects… keep going.
Tip 1: Model the DQMH Modules for your App
Before you begin coding or splitting modules among your team, first draw out what modules you plan to create and what will be the DQMH Events between the modules.
For example, for the Continuous Measurement and Logging application we saw above, a DQMH diagram could look like this:
Create a table with all the DQMH events, like this one:
You can use a tool like Web Sequence Diagrams to describe different event sequences in your application.
Now, before we start coding. Did you notice something “smelly”? Are there any improvements?
We created an unnecessary dependency between the Acquisition module and the Logging module by requiring the Acquisition module to be running before the Logging module runs. What if I want to take the logging module to a different application where the data to be logged is not provided via a broadcast event?
We will create a Log Data request event for the Logger module and not have the Logger module register for the DAQ module.
Now that we have designed what DQMH modules we need, we can go ahead and create them. The video below shows step by step how the modules get created using the Tools>>Delacor>>DQMH>>Add New DQMH Module… tool.
There is a video showing the creation of all the events step by step. If you are interested in seeing this video, let me know via the comments, and I will add it to the post.
Tip 2: Use Multiple Event Handling Loops
If one of your modules is registering for the events of multiple modules and these modules are chatty, meaning they broadcast a lot of events at a high rate, what are you supposed to do? Well, a good option is to use multiple Event Handling Loops (EHL). I know what some of you are going to say “I am not supposed to have more than one event structure in my block diagram”. That is incorrect, what the LabVIEW help says is that you should not register and handle the same event in more than one event structure in your block diagram. That is a little different.
The example below shows a media player. The reason we need two event handling loops is that the one at the bottom will be getting the “time elapsed” every second. This would mean that we could miss the volume update. Also, when the volume changes, we get several events for every new value. Separating in two EHLs means that we will both get the volume updates as well as the time elapsed without each event interfering with each other. This is also how you could implement something similar to priority queues.
Tip 3: Use Helper Loops
Have you ever been in a situation where you have to flush the queue when you stop a continuous activity, for example, acquiring? The video below shows the problems when the Acquisition module self-enqueues the message “acquire”.
This is a code smell, so consider using helper loops instead. Joerg Hampel wrote an excellent blog post about helper loops. You can always leave the Message Handling Loop (MHL) just for business logic and instead use the helper loop for device control. Now let’s see a video showing a solution using a helper loop.
Tip 4: Create State Machine Inside MHL Case
Do you have a series of steps that need to be executed in a sequence and cannot be interrupted? The first instinct is to enqueue the steps as an array. However, that might cause other messages to get enqueued in between the steps. Use a State Machine instead, and make sure that the state machine is registered to stop if the Stop Module event is fired. The video below shows the steps to create a state machine to implement a calibration sequence inside an MHL case.
The key here is putting the actual states inside the Timeout event case. This is not how we normally implement state machines but ensures that the states can be interrupted only by the “Stop Module” or the “Stop Action” events or any other event that should be able to interrupt the state machine.
Tip 5: Add Classes to DQMH Modules
I have heard people say that it is not possible to inherit from a DQMH module and that they wish there was a way to use DQMH modules in combination with LVOOP. If you have situations where you want to share common code among modules where each module might implement the code differently or if you need a quick DQMH module launched by a class, there are a couple of options.
The video below shows our Delacor Test Sequencer and how we use a class within the DQMH module to implement the common actions of loading a test, running a test and shutting down a test.
The Load Test.vi method launches the DQMH module by calling the Start Module.vi followed by the Synchronize Module Events. The Shutdown Test.vi calls the DQMH Stop Module.vi. The Run Test.vi calls a DQMH Request and Wait for Reply event called “Run Test and Wait.vi”.
The other option where you can use DQMH modules in combination with LVOOP is to have a class wrap a DQMH module. One example of this is when you have a class for a device and you want to have an interactive module for the simulated child of that class. The code below is a simple test where we initialize the serial device, ask it for its RPM, its Resistance and finally, we disconnect. The methods for the hardware class are making VISA calls. For the simulated class, we call DQMH events.
In this case, the Serial Device class has a Serial Port Class. We used a DQMH module to implement the Simulated Serial Port.
Tip 6: Minimize Unscripted Code in API Tester
This tip is pretty straightforward. Anything extra the developer does in the API Tester, other developers will also have to do when they use the API. There will be occasions where you do need to do extra code on the API tester just to make the API tester work. For example, the Logger API Tester might need for you to create simulated data before you call the Log Data request event. However, this is not code that other developers will have to add because when they call the Log Data request in their application, they will actually have data to log.
A good example of code that can be eliminated in the API Tester is settings. If your application has a configurations editor, use that instead for editing the configurations/settings for your module in the API Tester. Then, all you have to do is add the code that launches the DQMH module for your Configurations Editor and the API Tester only has a button to launch the Editor. This means you don’t need to add extra inputs to your DQMH request. The module itself will already have the access to this data because the module’s settings are updated anytime the end user updates the settings via the configurations editor.
Tip 7: Use API Testers as Application Launcher
The video below describes how to create a top-level VI for your application based on the API Tester. It also shows which bookmarks you could add to your code to remind you what to do in order to make the top-level VI show or not show. You could have extra code so when you enable debugging, the top-level API Tester-like VI shows, and when debugging is not enabled, it does not show.
The key to not showing the top-level API Tester-like VI is to customize its appearance to run transparently at 100% and to not allow the end user to minimize the window. Other things to keep in mind are to limit the text on the status indicator, make sure the Close Panel event and the Stop Module event for the DQMH module always exit.
Tip 8: Use Separate EHL for Request and Wait for Reply Event Tests
Have you ever had DQMH Request and Wait for Reply events that take too long? One issue with these events is the API Tester can become unresponsive and you can no longer use it as a debugger. Remember that on tip 2 we talked about using multiple EHL in the DQMH Main.vi? Well, you can do the same in the API Tester. Just make sure you edit your event case to not lock the panel!
And that is it for now. There are other tips and tricks that we have discovered along the way. You can find more at our Best Practices and our support forum. We will continue to add blog posts with tips and tricks. If there is a specific topic you would like for us to cover, please let us know via the comments.
I hope you found these tips useful.