This example runs four parallel instances of a synchronous state diagram generated by the Statechart Module. The diagrams execute on a cRIO 9074. The diagram triggers come from an XP HMI. The triggers originate from event-driven producer-consumer architecture. Triggers are sent to the cRIO using the Simple Messaging Reference Library (STM). There is an example of command-based communication that installs with STM. The STM messages are received on the cRIO and sent to one of four RT FIFOs. The RT FIFO Read pops the trigger and sends it to the diagram. Since we want each instance of the diagram to operate on different hardware resources, I use a reentrant VI as a resource LUT. I pull out the correct resource set by providing the diagram with an "instance" control.
Software Requirements: LabVIEW RT 2009, Statechart Module, NI-RIO, Simple Messaging Reference Library
Hardware Requirements: cRIO 9074, NI-9263, NI-9215
Alternate hardware may be used. The cRIO must support Scan Engine. Four AO channels are wired to four AI channels.
Host (HMI)
- The producer loop waits for UI events. The events originate from button presses on the HMI that tell the cRIO to do something (in this case, start the test). The front panel is a simple tab control, and each tab looks identical. I use the control captions instead of labels so each button can have the same name and fire distinct events. That is, when the operator clicks "Start Test" on tab 2, the Start Test 2 value change event fires, and the handler sends the Start Test command to Station 2.
- I enqueue both the station number and the command. Using type definitions allows me to scale the number of stations and the commands that I can send.
- The consumer loop waits for the package. Using a case structure allows me to scale the framework for new stations as I add them.
- To mitigate the risk of typos, I use a cluster of strings for the Name of the STM message.
- The command becomes the data for the STM message. I use the metadata to direct the command to the correct station.
Target
Resource LUT
In this reentrant VI, I define the hardware resources that will be unique to each instance of the reentrant statechart. I made the VI reentrant so none of the statechart instances would call into a shared resource. If you have other ideas of how to implement different resources in multiple instances of the same statechart, I'd like to hear them.
Communication Loop
- The communication loop waits for an incoming STM message.
- I select the case based on the STM Metadata. In this case, I use the metadata to decide which station I'm sending a command to. In a revision of this program, I would un-flatten the metadata to an enum so that I can populate more states of the case structure as I add stations (and avoid typos!).
- The data in the STM message is un-flattened to the command type definition.
- I select the RT FIFO that matches the station I want to send the command to. I write the command to the RT FIFO.
- In this application, I want to stop all loops if there's an error, and I want to stop my communication loop if all four test stations have been stopped by the HMI. The Stop FGV is specialized for these needs.
State Diagram Loops (x4)
- A command is pulled from the RT FIFO. Notice that if the command is not received in 1ms, the loop will iterate. That's because I want to iterate the statechart diagram even if there are no new commands.
- I map the commands from my HMI to triggers that I've defined in the statechart.
- I tell the statechart which instance it is. That way, I can use my resource LUT within the statechart and I don't have to pass a lot of resource data as inputs to the statechart.
- If there's an error (i.e. the RT FIFO has been destroyed) I set the Stop FGV to true. If the statechart has reached the terminal state, I increment a counter within the Stop FGV. If the counter reaches 4, then the Stop FGV asserts true. I left an input on the Stop FGV so I can change the number of stations in the program.
State Diagram
- Recall the input to the statechart? I use the station number as the input to my resource LUT. The LUT returns the IO Variable reference that this instance of the statechart will operate upon.
- In this case, I drive an analog output channel.