From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW Development Best Practices Documents

cancel
Showing results for 
Search instead for 
Did you mean: 

Building a basic plugin-based application with HAL using JKI SMO, MGI Solution Explorer, and LabVIEW 2020 interfaces

Overview

I came across this document, and have adapted the design for JKI SMO and LabVIEW interfaces. This work was done as a proof-of-concept to test out some new features and tech.

 

Description

The application is a simple Audio Controller, something like you might see on MS Teams where you can select your active Speaker and active Microphone in a video call. Given how much I'm using that screen nowadays, I thought it would make for a good real-world example to try and mimic.

 

I tried to keep this as SOLID as possible, let's see how I did...

 

Goals for this design:

  1. Create a Hardware Abstraction Layer that would isolate my Main Application and Device Definitions/Interfaces from the "actual" hardware being used
  2. Provide Asynchronous communication from the devices to the main application (e.g. devices should not block the main app, but the main app can be blocked while waiting on the response of a device)
  3. Each layer of the application should be packaged in its own PPL to keep project load + build times low
  4. Devices must be loaded at run-time of the top-level application, both in source and as a built exe

 

UML Diagram

 

Class Diagram.png

 

Packages

JKI SMO.lvlibp

The JKI SMO library, with some modifications to support messaging without having to subclass the parent SMO. This needed to be built into a PPL so that every dependent class would be able to have the same parents (e.g. if I didn't build this into a library, then plugins at runtime wouldn't have the same parent as the SMOs that were built into the main executable)

 

Audio Plugin.lvlibp

This library provides the definition (abstract class) and interfaces for an audio device (as defined in my application - your definition of an audio device may differ, this was just a contrived example...)

Audio Device.lvclass

The abstract class Audio Plugin holds the data that is common to all audio devices (Name, Volume, whether or not the device is muted). The write accessors use protected events to notify any subclasses (child SMOs) that the values have been changed.

Audio Interface.lvclass

This interface is used to isolate the Audio Device in most instances

Audio Out.lvclass / Audio In.lvclass

This interface extends the basic Audio Interface and adds additional functionality specific to Audio In/Out devices (e.g. playing a stream). These interfaces also have a method with a default implementation to retrieve the Audio Device given an interface. This is necessary when launching/stopping the Device SMO. The default implementation simply type casts the interface to the device. This is able to be overridden to support the Composite Device, which is not an Audio Device itself, but it composes two audio devices.

 

Basic Audio Devices.lvlibp

This library provides the definitions (abstract class) for some basic audio devices, like a speaker and a microphone.

Microphone.lvclass / Speaker.lvclass

The Microphone and Speaker are basic abstract classes that don't really do anything on their own, other than provide a layer of isolation between the Abstract Audio Device and the specific device implementations. They are more used as a definition and a common place to anchor interfaces to.

Composite Device.lvclass

The Composite device is the interesting case here. It isn't actually an Audio Device on its own, but it does contain two devices inside it. The 'Audio Out Device' and 'Audio In Device' methods from the Audio In and Audio Out interfaces are overridden here and call the accessor methods 'Read Speaker' and 'Read Microphone' to retrieve the actual audio devices.

 

Simulated Devices.lvlibp

This library extends the basic devices and provides a simple simulated version with a UI that you can interact with to demonstrate that data can flow from the main application to the devices, and vice versa.  

Simulated Microphone.lvclass / Simulated Speaker.lvclass

These are implemented as an SMO with a User Interface. When run, the UI is shown to show a speaker and a Microphone with some buttons to adjust the level and mute status.

Simulated Headset.lvclass

The Simulated Headset overrides the Read Speaker and Read Microphone accessor functions and hard-wires the simulated speaker and simulated microphone. This one class satisfies both the Audio In and Audio Out interfaces, so it appears as two devices to the client application.

 

Audio Controller Interface.lvlibp

This library contains an interface that specifies all the functions that an Audio Controller must implement, as well as provides the messages that call these functions to support asynchronous communication from devices to the controller.

 

Main Controller.lvclass

The Main Controller implements all the functions of the Audio Controller interface, so it can act as an audio controller. The UI of this allows a user to Load devices and control the volume/mute status. The Main Controller allows for one output and one input device to be active at a time.

 

Projects / MGI Solution Explorer

Each library is built in its own project, and each project is added to a solution that chains the PPL builds together:

Solution Explorer.png

  

 

Hardware and Software Requirements

  • LabVIEW 2020
  • MGI Solution Explorer
  • JKI State Machine (no need for JKI SMO, that's included in the example code included)
  • GOOP Development Suite (optional - used to view UML diagram)

 

Steps to Implement or Execute Code

  1. Open the Application.lvproj
  2. Navigate to the 'Test Directory'
  3. Launch the Test VI
  4. When the Main UI opens, Load the 'Simulated Devices' from the Builds folder

 

Nathan Murphy
Comments
Nathan-M
Member
Member
on

Application Screenshots:

 

On Launch:

Nathan-M_0-1612992733743.png

 

Load the simulated devices PPL:

Nathan-M_1-1612992790334.png

 

Select an Output Device:

Nathan-M_2-1612992819821.png

 

Adjust the Level/Mute status on either UI - see that the changes are synchronized:

Nathan-M_3-1612992882206.png

 

 

Nathan Murphy
Contributors