I'm building a GUI for the electronic load we made here on element14.

The development will be in a few incremental steps. This is the second iteration:

  • add error logging
  • make the LCD display emulation work
  • a few dedicated controls to set current and enable / disable input

 

Retrieve Instrument Status: Multiple SCPI Commands Combined

 

The screen refreshes the GUI controls based on the instrument status.

  • LCD display displays mode, set current, measured current and voltage, input on/off status.
  • "Load Active" checkbox reflects the current status of the input (you can also change the status with it.
  • Errors button shows the number of errors captured by the instrument. If there are unretrieved errors, it shows the count and turns red.

 

There are a number of SCPI commands required to get that info.

To avoid many back-and forths, and to minimise the time that the instrument is locked for other SCPI commands, all queries are combined in a composite SCPI statement.

INP?;FUNC?;CURR?;:MEAS:CURR:DC?;:MEAS:VOLT:DC?;:SYST:ERR:COUNT?

 

    //Handle timer event.
    @Override
    public void actionPerformed(ActionEvent e) {

        // get info - as much as we can together
        String s;
        s = ("INP?;FUNC?;CURR?;:MEAS:CURR:DC?;:MEAS:VOLT:DC?;:SYST:ERR:COUNT?\n");
        synchronized (instrument) {
            instrument.write(s);
            s = instrument.read();
        }

        // parse
        StringTokenizer tokenizer = new StringTokenizer(s, ";");

        // input
        if (tokenizer.hasMoreTokens()) {

 

Each command is separated by a semicolon, as specified by the SCPI standard. The eLoad understands this and can handle it.

Then I use a tokeniser to split the reply in its components.

The result string also separates the data by semicolon. A tokeniser is a convenient way to break these up into individual values.

 

All values are then gathered in a dedicated object to capture latest status

 

public class RefreshData {
    public boolean bActive;
    public String sMode;
    public String sSetValue;
    public String sI;
    public String sV;
    public String sW;
    public String sR;
    public String sErrCount;
}

 

 

       // input
        if (tokenizer.hasMoreTokens()) {
            refreshData.bActive = tokenizer.nextToken().startsWith("1");
        }
        // mode
        if (tokenizer.hasMoreTokens()) {
            refreshData.sMode = tokenizer.nextToken().replace("\"", "");
        }
        // set value
        if (tokenizer.hasMoreTokens()) {
            refreshData.sSetValue = tokenizer.nextToken().replace("\n", "");
        }
        // measured current
        if (tokenizer.hasMoreTokens()) {
            refreshData.sI = tokenizer.nextToken().replace("\n", "");
        }
        // measured voltage
        if (tokenizer.hasMoreTokens()) {
            refreshData.sV = tokenizer.nextToken().replace("\n", "");
        }
        // set error count
        if (tokenizer.hasMoreTokens()) {
            refreshData.sErrCount = tokenizer.nextToken().replace("\n", "");
        }

 

Then the GUI components are updated.

 

        // update LCD display
        jTextAreaLCD.setText("mode: "
                + (String) (refreshData.sMode.startsWith("CURRent") ? "I" : "*ERROR*")
                + " "
                + refreshData.sSetValue
                + "\nI: " + refreshData.sI + "\nV: " + refreshData.sV
                + "\nInput: O"
                + (String) (refreshData.bActive ? "n " : "ff"));


        // update Input Active control
        jCheckBoxInputActive.setSelected(refreshData.bActive);


        // update error count
        jButtonSCPIErrorClear.setText("Errors: " + refreshData.sErrCount);
        if (refreshData.sErrCount.startsWith("0")) {
            jButtonSCPIErrorClear.setBackground(Color.green);
        } else {
            jButtonSCPIErrorClear.setBackground(Color.red);
        }

 

Timed Status Refresh

 

I use a Swing timer to retrieve the values and update the controls. If a timed action updates graphic portions, it's preferred to use the Swing timer.

It works well with the Swing threading model.

 

The timer uses the main application frame as its parent. For that, the frame's declaration needs to be modified to flag that it implement's the interface that the timer uses to wake it up.

 

public class MainFrame extends javax.swing.JFrame implements ActionListener {

// ....

    /**
     * Creates new form MainFrame
     */
    public MainFrame() {
        initComponents();
        initTimer();
    }

    private void initTimer() {
        timer = new Timer(100, this);
        timer.setInitialDelay(900);
        timer.start();
    }

 

When the timer kicks in, it'll call our frame's actionPerformed method (the one shown in the previous section)

 

 

Switch Load Input On and Off

 

There's a checkbox that you can use to enable and disable the load.

In the first section you saw that it shows the current state of the device.

But it's an active control. By checking and unchecking it, you control the instrument's output.

You'll also see this reflected in the LCD display (after the next timer event).

 

    private void jCheckBoxInputActiveActionPerformed(java.awt.event.ActionEvent evt) {                                                     
        String s;
        s = "INP " + (jCheckBoxInputActive.isSelected() ? "ON\n" : "OFF\n");
        synchronized (instrument) {
            instrument.write(s);
        }
    } 

 

Error Handling

 

Each refresh, the timer checks if there are errors logged on the instrument.

If not, it colours the Error button green and labels it with "Errors: 0".

If there are errors, the button colours red and the number of errors are shown.

You can click the red button to retrieve the error messages into the log.

Upon that action, the button turns green again and shows "Errors: 0".

That's because the action of retrieving an error removes it from the instrument.

We retrieve all errors, so the backlog is clean.

Clicking that green button clears the error log on screen.

 

How can you get errors when using the GUI:

  • enter an invalid value for the constant current (a character, an under/overflow)
  • enter a wrong or unsupported SCPI command in the SCPI tab (the log shows different messages for wrong vs. unsupported)

 

TAB for Constant Current Controls and SCPI Command Prompt

 

To avoid clutter, and to present a simple interface by default, I used a TAB control where you can switch between Constant Current and SCPI control.

 

You can mix and match the two ways of controlling. The instrument doesn't know whether you used a button or typed a command .

Neither does the interface, once you did the action.

So there are no side effects (except when you use the debug level :DEVELOP: SCPI commands to directly control the DACs).

 

Minor improvement: when you press enter in an edit box, it performs the same task as the Send button next to it.

It avoids that you have to switch between keyboard and mouse.

I've used this application extensively today and it does the job. That was the objective set at the start.

NetBeans project is attached. You need to use the latest firmware for the eload, available on the project start page.

 

There's also a distro attached, ready to run with dependencies included. It has a batch file for Linux and Windows.

You need to adjust the COM port to the one the instrument is using. For Linux, make the batch file executable.

 

Related Blog
Programmable Electronic Load
Programmable Electronic Load - Java GUI Part 1: Basic Functionality
Programmable Electronic Load - Java GUI Part 2: Support for Current Mode, Input On/Off, Error Log