I am writing a LV 2015 program that controls and queries 4 instruments. My hope is to write a program that is capable of running any combination of these four instruments. For example, run the program with istrument 1,2,3,4 or run the program with only instrument 2.
Currently my program tries to connect to all four devices, one after the other, and if it fails, opens a pop-up that asks if the user wants to go on anyway without this particular device. If the user selects "yes, continue anyway" the program should run with all other connected devices.
How do I best implement this? The problem I see is that the instrument handles are passed through the entire program (which is based on a state machine, i.e. the instrument handles are passed through shift registers). So whenever a subvi calls a disconnected instruments, the program crashes, expectedly, as no such device exists.
Rewriting the entire program so that the state machine sits inside a case structure with cases for every possible combination of instruments seems excessive, no? That would need to be 15 cases, plus a case for no instrument being connected at all, with all cases having similar code...
Ideally I am looking for a way to just ignore the disconnected instruments (i.e do not throw an error, just skip this).
- what about having a (separate) statemachine for each device? So you can handle device connected/disconnected in the low level part of your program! (Use states like "init/connect", "disconnected", "connected", …)
- what about having some kind of marker, set by the low-level device handling statemachine and read by your UI loop, which tells the connect-state of your devices? Then you can disable certain features in the UI based on those markers…
One example: I had to create an application (for PXI RT) which handles arbitrary number of Keithley picoampere meters via GPIB. The requirement was to have "hot-swap" operability, so the operator can connect or disconnect any GPIB unit on the fly.
I just used a single state machine (Qeued state machine with a command loop as producer of commands coming from network, plus two consumer loops one the DAQ the other for data logging), with the following states of the DAQ state machine:
The requirement in this case was to have only manual re-init (via a Siemens PLC on the same network) if a unit needs to be replaced due to malfunction, or if a new unit was added to the daisy chain, etc. In the 1. state I just check all available GPIB addresses (in my case 14 addresses) and request response from the units. I used an array of typedef clusters, the typdef cluster having three elements: GPIB address (this could have spared and use just the array index, but this way more visual), sub-model type (Keithley 6485 or 6487?), Error status (standard error cluster).
In the Init cases when a Keithley GPIB address is not responding, or responding with a Keihtley error code, I just bundle these info into the array of clusters, and I erase the error. In this way I can get "native" error info produced by LabVIEW (like when no device is present on that particular GPIB address) and also error info coming from the Keithley driver.
During the measurement state I only use those GPIB addresses which did not produce any error. Also, if a unit produces any error, it will be exluded from the active unit list. The user via the network can see all the error states of the GPIB address range. When the problem fixed, like the operator replaces the Keithley unit, the operator can "re-init" that particular GPIB address, and the new error info (no error) will be bundled into the cluster array, so this unit will do measurement again.