Instrument Plugin Interfaces

I am currently working on a custom test system that will require multiple interface drivers to simplify things for our test developers.

Recently, I was asked to make it so that we can just swap in multiple different devices, but leave the plugin steps the same. That way, if a technician notices a device is malfunctioning they can replace it with any device from an approved list, and the test will not need to change.

Naturally, I created an interface for the first device, and implemented it in two different devices, and then pulled it into the plugin steps. In this case, it’s a luminance meter. One of the devices takes SCPI-like commands, and the other has its own interface, but both use a serial port. Since I already have a serial instrument interface driver, I simply hooked it up, set the package to depend on that package, and then installed my luminance meter package.

Obviously there will be a bit of setup to ensure the port is correct, but the general goal is to get the test to recognize either device. However, the first thing I realized is that using the AvailableValues decorator, I was having a lot of trouble just selecting devices that implement the interface. Once I got that working, I realized that Open and Close do not execute, so I have to execute them manually in each interface function. Finally, because Open and Close do not execute, if anything goes wrong, the port stays open.

What is the suggested method for implementing an OpenTAP instrument such that it fulfills the interface requirements, and still is capable of functioning like an OpenTAP instrument? At the moment, the only functional options I can see are rather messy and require multiple coding paths in each interface function to determine which device is being used.

Additionally, what would be the best way to implement the serial layer such that it can be used in DUTs and Instruments without having to configure a serial device in the instruments section that is consumed in the DUT section?

Hi @matthewdumas,

it sounds like the interface needs to implement the IInstrument interface. You also dont have to use the AvailableValues attribute if you do that.

The reason for that is the resource manager in OpenTAP only looks for things that implement IResource. That means if your test step does not declare something that inherits from IResource, the resource manager will ignore it.

It should look something like this:

public interface ILuminanceMeter : IInstrument{
    double MeasureLuminance();
}

public class LuminanceMeasureStep : TestStep {
    // Translates to a dropdown in the UI, since OpenTAP detects that ILuminanceMeter is an instrument and should be selected from Instrument settings.
    public ILuminanceMeter Meter{get;set;}
    public override void Run()
    {
         Results.Publish("Luminance", Meter.MeasureLuminance());
    }
}

Hello rolf!

I’ve been working on this since you suggested it, however, I cannot seem to get the Test Steps to recognize an instrument. I swapped to the AC Power Supply, since there’s only a single (SCPI type) instrument type for it currently. I have no interest in using the generic SCPI package, nor a vendor made package. Unfortunately, I can’t share the reasons why, but they are business driven.

The main issue I seem to run into is that the Step does not see the Instrument I have configured. Here’s some declarations for you that show how it is implemented:

[Display("Get Identity", Description: "Gets the full identity string.",
        Group: "AC Power Supply - Controls", Order: 9)]
    public class GetIdentity : TestStep
    {
        [Display("AC Power Supply", Order: 1)]
        public IAcPowerSupply AcSupply { get; set; }

        [Display("Read Delay", Order: 2)] public int ReadDelay { get; set; } = 500;

        [Display("Manufacturer", Order: 1, Group: "Output"), Output()]
        public string Manufacturer { get; set; } = "";

        [Display("Model", Order: 2, Group: "Output"), Output()]
        public string Model { get; set; } = "";

        [Display("Serial Number", Order: 3, Group: "Output"), Output()]
        public string SerialNumber { get; set; } = "";

        [Display("Software Version", Order: 4, Group: "Output"), Output()]
        public string SoftwareVersion { get; set; } = "";

 // ... Code here, override run
}


public interface IAcPowerSupply : IInstrument
{
// ... interface
}

public class ScpiAcPowerSupplyInstrument : Instrument, IAcPowerSupply
{
    [Display("Serial Port", Order: 1)]
    public SerialDevice SerialPort { get; set; }
    
// ... override Open(), Close(), a bunch of instrument control functions
}

The SerialDevice class is a different package:

    [Display("Serial Instrument", Description: "This is for any test instrument that uses the serial port.")]
    public class SerialDevice : Instrument
    {
        [XmlIgnore] 
        public SerialPortStream Handle { get; set; }
        public bool Rs485Mode { get; set; } = false;
        public int ReadTimeout { get; set; } = 250;
        public int WriteTimeout { get; set; } = 250;
        public int Baud { get; set; } = 9600;
        public string PortName { get; set; }
        public Parity PortParity { get; set; } = Parity.None;
        public int DataBits { get; set; } = 8;
        public StopBits PortStopBits { get; set; } = StopBits.One;
        public Handshake FlowControl { get; set; } = Handshake.None;

//...  Serial port controls, Override Open and Close
}

The SerialPortStream comes from RJCP Serial Ports library. We had issues with System.IO.Ports originally, though they may be resolved in .net 9. We haven’t upgraded to that yet.

Anyway, as I said, I cannot seem to get the steps to recognize that I have a configured device in the Instruments.xml. I already configured the port and assigned it to the device, so in theory, it should just work when it comes to the step.

When I copy you code into my solution it looks like this:

Is this not what you are getting?

With regards to the .net 9 serial port error, I think you can fix that by just adding the nuget package. There is a chapter of the developer guide dedicated to .net9 issues: Migrating to .NET 9 | OpenTAP

I don’t know what was happening, but it’s working now.

I uninstalled all of my packages and reinstalled them and now I am getting the drop-down.

As for the Serial port, our issue was well before the change to .net 9, so the solution on the migration page will probably work for us. I will have to test it.

Thank you for your help.4