I’ve got a mechanism to select any instrument of a type from a pool, based on whether it’s in use or not and then perform the relevant connections in a child step. This is a simplified version of the code…
[AllowAnyChild]
public class ExampleParent : TestStep
{
public IEnumerable<string> InstrumentNames
{
get => InstrumentSettings.Current.Select(i => i.GetType().Name);
}
[AvailableValues(nameof(InstrumentNames))]
public string InstrumentName { get; set; }
public Instrument ActualInstrument { get; private set; }
public override void Run()
{
// Set ActualInstrument at runtime
}
}
[AllowAsChildIn(typeof(ExampleParent))]
public class ExampleChild : TestStep
{
public IEnumerable<string> PortNamesOnInstrument
{
get
{
var inst = GetParent<ExampleParent>().InstrumentName;
return InstrumentSettings.Current.Where(i => i.GetType().Name == inst).First().GetConstProperties<Port>().Select(p => p.Name);
}
}
[AvailableValues(nameof(PortNamesOnInstrument))]
public string PortName { get; set; }
public override void Run()
{
var actualPort = GetParent<ExampleParent>().ActualInstrument.GetConstProperties<Port>().Single(p => p.Name == PortName);
// Do something with the port
}
}
The actual implementation has a few more properties on the test steps so you can select an instrument alias and its port along with a destination port but, hopefully, this serves for demonstration.
At the moment, I can only select one port to connect in this child step and I’d like to perform all the connections for subsequent child steps.
I was thinking a List of an embedded type to handle this, but I need to provide a reference to the step itself to get the available options. Could I create a custom collection class that I can instantiate in the ctor of the child step with a reference to itself and how can I get that working in the GUI?
Also, off the topic slightly, is there a way to ensure the parent step is present somewhere in the child step’s hierarchy but not necessarily directly above?
Hi @benstreek, I don’t really understand what you’re trying to do, or what your question is. But it seems like you want access to parent and child steps, which can be done through GetParent and RecursivelyGetChildSteps. I think some clarification would be helpful for me.
Hi @david-wsd. Yes, the question got lost a little there.
I want to modify the above so that I can select multiple ports to work with. My problem is that by wrapping my two properties in a class as per the “EmbedPropertiesAttributeExample”, I somehow need to provide a reference to the test step in order to get my list of available options.
public class ExampleChild : TestStep
{
public class EmbeddedClass
{
public IEnumerable<string> PortNamesOnInstrument
{
get
{
var inst = GetParent<ExampleParent>().InstrumentName; // Doesn't compile as this isn't a TestStep
return InstrumentSettings.Current.Where(i => i.GetType().Name == inst).First().GetConstProperties<Port>().Select(p => p.Name);
}
}
[AvailableValues(nameof(PortNamesOnInstrument))]
public string PortName { get; set; }
}
public List<EmbeddedClass> PortNames { get; set; }
public override void Run()
{
var actualPorts = GetParent<ExampleParent>().ActualInstrument.GetConstProperties<Port>().Single(p => PortNames.Select(pn => pn.PortName).Contains(p.Name));
// Do something with the ports
}
}
If I do something like the following, it will compile but Editor (understandably) doesn’t know how to deal with it.
public class ExampleChild : TestStep
{
public class EmbeddedClass
{
private TestStep testStep;
public EmbeddedClass(TestStep testStep)
{
this.testStep = testStep;
}
public IEnumerable<string> PortNamesOnInstrument
{
get
{
var inst = testStep.GetParent<ExampleParent>().InstrumentName; // Doesn't compile as this isn't a TestStep
return InstrumentSettings.Current.Where(i => i.GetType().Name == inst).First().GetConstProperties<Port>().Select(p => p.Name);
}
}
[AvailableValues(nameof(PortNamesOnInstrument))]
public string PortName { get; set; }
}
public List<EmbeddedClass> PortNames { get; set; }
public override void Run()
{
var actualPorts = GetParent<ExampleParent>().ActualInstrument.GetConstProperties<Port>().Single(p => PortNames.Select(pn => pn.PortName).Contains(p.Name));
// Do something with the ports
}
}
So that’s the specific question. Hope it makes sense but let me know if not.
The context for this (in case there’s a simpler way of doing it) is that I want to use a subset of instruments for part of a test plan that is running concurrently with other test plans.
So I have three USB to serial adapters, and 20 test runs all going at the same time. When I want to talk to the DUT, I want to just grab any serial adapter that’s not in use, connect it to the DUT via a matrix, and then let it go when I’m done with it for one of the other runs to pick up.
Thus, I have a parent step that grabs instruments of the type(s) I need and a child step that connects the appropriately named ports on whatever instrument the parent happened to get hold of.
If you want to be able to select multiple ports, you can use AvailableValuesAttribute with a list:
e.g:
[AvailableValues(nameof(PortNamesOnInstrument))]
public List<string> PortName { get; set; } = new List<string>();
Doing this you will be able to select a set of values from the PortNamesOnInstruments like this:

Is that what you meant?
Hi, @rolf_madsen. Not quite - I simplified the code for brevity, but there are actually more properties than that involved. Here are some screenshots from the real implementation.
So the “From”, “To” and “Using” properties there represent one item I’d like in my list. Then I’d want the next item to be connect the COM port of the PSU to the VIN_COM of the DUT using the MXR_PWR_COM matrix row
Hi @benstreek, thanks and I think I get it now. How about this?
private ObservableCollection<EmbeddedClass> _PortNames;
public ObservableCollection<EmbeddedClass> PortNames
{
get
{
return _PortNames;
}
set
{
_PortNames = value;
_PortNames.CollectionChanged += PortNames_CollectionChanged;
}
}
private void PortNames_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (EmbeddedClass item in _PortNames)
{
item.testStep = this;
}
}
1 Like