diff --git a/SemiconductorTestLibrary.Extensions/source/InstrumentAbstraction/DCPower/Source.cs b/SemiconductorTestLibrary.Extensions/source/InstrumentAbstraction/DCPower/Source.cs index 29c3eb4c..d591d284 100644 --- a/SemiconductorTestLibrary.Extensions/source/InstrumentAbstraction/DCPower/Source.cs +++ b/SemiconductorTestLibrary.Extensions/source/InstrumentAbstraction/DCPower/Source.cs @@ -511,10 +511,7 @@ public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, doubl LevelRange = currentLevelRange, LimitRange = voltageLimitRange }; - sessionsBundle.Do(sessionInfo => - { - sessionInfo.Force(settings, sitePinInfo: null, waitForSourceCompletion); - }); + sessionsBundle.ForceCurrent(settings, waitForSourceCompletion); } /// @@ -540,8 +537,9 @@ public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, IDict LevelRange = currentLevelRange, LimitRange = voltageLimitRange }; - sessionInfo.Force(settings, sitePinInfo, waitForSourceCompletion); + sessionInfo.ConfigureAllChannelsAndInitiateGangedFollowerChannels(settings, sitePinInfo); }); + sessionsBundle.InitiateGangedLeaderAndNonGangedChannels(waitForSourceCompletion); } /// @@ -567,8 +565,9 @@ public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, SiteD LevelRange = currentLevelRange, LimitRange = voltageLimitRange }; - sessionInfo.Force(settings, sitePinInfo, waitForSourceCompletion); + sessionInfo.ConfigureAllChannelsAndInitiateGangedFollowerChannels(settings, sitePinInfo); }); + sessionsBundle.InitiateGangedLeaderAndNonGangedChannels(waitForSourceCompletion); } /// @@ -594,8 +593,9 @@ public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, PinSi LevelRange = currentLevelRange, LimitRange = voltageLimitRange }; - sessionInfo.Force(settings, sitePinInfo, waitForSourceCompletion); + sessionInfo.ConfigureAllChannelsAndInitiateGangedFollowerChannels(settings, sitePinInfo); }); + sessionsBundle.InitiateGangedLeaderAndNonGangedChannels(waitForSourceCompletion); } /// @@ -607,11 +607,22 @@ public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, PinSi /// Otherwise, the source delay amount is not directly accounted for by this method and the WaitForEvent must be manually invoked in proceeding code. public static void ForceCurrent(this DCPowerSessionsBundle sessionsBundle, DCPowerSourceSettings settings, bool waitForSourceCompletion = false) { - sessionsBundle.Do(sessionInfo => + settings.OutputFunction = DCPowerSourceOutputFunction.DCCurrent; + if (sessionsBundle.HasGangedChannels) { - settings.OutputFunction = DCPowerSourceOutputFunction.DCCurrent; - sessionInfo.Force(settings, sitePinInfo: null, waitForSourceCompletion); - }); + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + sessionInfo.ConfigureAllChannelsAndInitiateGangedFollowerChannels(settings, sitePinInfo); + }); + sessionsBundle.InitiateGangedLeaderAndNonGangedChannels(waitForSourceCompletion); + } + else + { + sessionsBundle.Do(sessionInfo => + { + sessionInfo.Force(settings, sitePinInfo: null, waitForSourceCompletion); + }); + } } /// @@ -1500,6 +1511,28 @@ private static void ConfigureChannels(this DCPowerSessionInformation sessionInfo channelOutput.Control.Commit(); } + private static void InitiateGangedLeaderAndNonGangedChannels(this DCPowerSessionsBundle sessionsBundle, bool waitForSourceCompletion = false) + { + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + if (!IsFollowerOfGangedChannels(sitePinInfo.CascadingInfo)) + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + channelOutput.InitiateChannels(waitForSourceCompletion); + } + }); + } + + private static void ConfigureAllChannelsAndInitiateGangedFollowerChannels(this DCPowerSessionInformation sessionInfo, DCPowerSourceSettings settings, SitePinInfo sitePinInfo) + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + sessionInfo.ConfigureChannels(settings, channelOutput, sitePinInfo); + if (IsFollowerOfGangedChannels(sitePinInfo.CascadingInfo)) + { + channelOutput.InitiateChannels(); + } + } + private static void InitiateChannels(this DCPowerOutput channelOutput, bool waitForSourceCompletion = false, double timeoutInSeconds = 5) { channelOutput.Control.Initiate(); diff --git a/SemiconductorTestLibrary.Extensions/tests/Unit/InstrumentAbstraction/DCPower/SourceTests.cs b/SemiconductorTestLibrary.Extensions/tests/Unit/InstrumentAbstraction/DCPower/SourceTests.cs index 00844c19..d37cb085 100644 --- a/SemiconductorTestLibrary.Extensions/tests/Unit/InstrumentAbstraction/DCPower/SourceTests.cs +++ b/SemiconductorTestLibrary.Extensions/tests/Unit/InstrumentAbstraction/DCPower/SourceTests.cs @@ -18,6 +18,7 @@ namespace NationalInstruments.Tests.SemiconductorTestLibrary.Unit.InstrumentAbst public sealed class SourceTests : IDisposable { private ISemiconductorModuleContext _tsmContext; + private const string TwoPinsGangedGroup = "TwoPinsGangedGroup"; private const string ThreePinsGangedGroup = "ThreePinsGangedGroup"; private const string FourPinsGangedGroup = "FourPinsGangedGroup"; private const string AllPinsGangedGroup = "AllPinsGangedGroup"; @@ -917,6 +918,166 @@ public void DifferentSMUDevices_ForceCurrentWithAsymmetricLimitAndRangesSucceeds sessionsBundle.ForceCurrentAsymmetricLimit(currentLevel: 0.1, voltageLimitHigh: 3, voltageLimitLow: -1, currentLevelRange: 0.5, voltageLimitRange: 5); } + [Fact] + public void DifferentSMUDevicesGanged_ForceCurrentWithSymmetricLimit_DividedCurrentForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(ThreePinsGangedGroup); + + sessionsBundle.ForceCurrent(currentLevel: 1.5, voltageLimit: 2); + + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerComplianceLimitSymmetry.Symmetric, channelOutput.Source.ComplianceLimitSymmetry); + if (sitePinInfo.CascadingInfo is GangingInfo) + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 0.5, expectedVoltageLimit: 2); + } + else + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 1.5, expectedVoltageLimit: 2); + } + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + }); + } + + [Fact] + public void DifferentSMUDevicesGanged_ForcePerPinCurrentsWithSymmetricLimit_CorrectCurrentsForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(ThreePinsGangedGroup); + + sessionsBundle.ForceCurrent(currentLevels: new Dictionary() { ["VCC1"] = 3, ["VCC2"] = 3, ["VCC3"] = 3, ["VCC4"] = 1, ["VCC5"] = 1 }, voltageLimit: 5); + + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerComplianceLimitSymmetry.Symmetric, channelOutput.Source.ComplianceLimitSymmetry); + if (sitePinInfo.CascadingInfo is GangingInfo) + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 1, expectedVoltageLimit: 5); + } + else + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 1, expectedVoltageLimit: 5); + } + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + }); + } + + [Fact] + public void DifferentSMUDevicesGanged_ForcePerSiteCurrentsWithSymmetricLimit_CorrectCurrentsForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(AllPinsGangedGroup); + + var currentLevels = new SiteData(new double[] { 1, 3 }); + sessionsBundle.ForceCurrent(currentLevels, voltageLimit: 3); + + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); + if (sitePinInfo.SiteNumber == 0) + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 0.2, expectedVoltageLimit: 3); + } + else + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 0.6, expectedVoltageLimit: 3); + } + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + }); + } + + [Fact] + public void DifferentSMUDevicesGanged_ForcePerPinPerSiteCurrentsWithSymmetricLimit_CorrectCurrentsForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(AllPinsGangedGroup); + + var currentLevels = new PinSiteData(new Dictionary>() + { + ["VCC1"] = new Dictionary() { [0] = 4, [1] = 2.5 }, + ["VCC2"] = new Dictionary() { [0] = 4, [1] = 2.5 }, + ["VCC3"] = new Dictionary() { [0] = 4, [1] = 2.5 }, + ["VCC4"] = new Dictionary() { [0] = 4, [1] = 2.5 }, + ["VCC5"] = new Dictionary() { [0] = 4, [1] = 2.5 } + }); + sessionsBundle.ForceCurrent(currentLevels, voltageLimit: 4.5); + + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); + if (sitePinInfo.SiteNumber == 0) + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 0.8, expectedVoltageLimit: 4.5); + } + else + { + AssertCurrentSettings(channelOutput, expectedCurrentLevel: 0.5, expectedVoltageLimit: 4.5); + } + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + }); + } + + [Fact] + public void DifferentSMUDevicesGangedinTwoPinGroups_ForceCurrentWithSingleSettingsObject_CorrectCurrentForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(TwoPinsGangedGroup); + sessionsBundle.GangPinGroup(ThreePinsGangedGroup); + + sessionsBundle.ForceCurrent(new DCPowerSourceSettings() { Level = 3, Limit = 3.6 }); + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); + if (sitePinInfo.PinName == "VCC4" || sitePinInfo.PinName == "VCC5") + { + AssertCurrentSettings(channelOutput, 1.5, 3.6); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4147_C1_S11/2" : "SMU_4147_C2_S10/2"); + } + else + { + AssertCurrentSettings(channelOutput, 1, 3.6); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + } + }); + } + + [Fact] + public void DifferentSMUDevicesGanged_ForceCurrentWithSingleSettingsObject_CorrectCurrentForced() + { + var sessionManager = Initialize("SMUGangPinGroup_SessionPerChannel.pinmap"); + var sessionsBundle = sessionManager.DCPower(AllPinsGangedGroup); + sessionsBundle.GangPinGroup(FourPinsGangedGroup); + + sessionsBundle.ForceCurrent(new DCPowerSourceSettings() { Level = 2, Limit = 2.6 }); + + sessionsBundle.Do((sessionInfo, sitePinInfo) => + { + var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; + Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); + if (sitePinInfo.CascadingInfo is GangingInfo) + { + AssertCurrentSettings(channelOutput, 0.5, 2.6); + } + else + { + AssertCurrentSettings(channelOutput, 2, 2.6); + } + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); + }); + } + [Theory] [Trait(nameof(HardwareConfiguration), nameof(HardwareConfiguration.GP3))] [Trait(nameof(HardwareConfiguration), nameof(HardwareConfiguration.Lungyuan))] @@ -1107,7 +1268,7 @@ public void DifferentSMUDevicesGanged_ConfigureCurrentSourceSettings_CorrectValu var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); AssertCurrentSettings(channelOutput, 1, 7); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1144,7 +1305,7 @@ public void DifferentSMUDevicesGanged_ConfigureCurrentSourceSettingsWithSiteData var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); AssertCurrentSettings(channelOutput, expectedCurrentLevel: sitePinInfo.SiteNumber == 0 ? 0.4 : 0.6, expectedVoltageLimit: sitePinInfo.SiteNumber == 0 ? 7 : 5); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1179,7 +1340,7 @@ public void DifferentSMUDevicesGanged_ConfigureCurrentSourceSettingsWithPinSiteD var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); AssertCurrentSettings(sitePinInfo, channelOutput, 0.75, 3, 6); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1219,7 +1380,7 @@ public void DifferentSMUDevicesGanged_ConfigurePerPinCurrentSourceSettings_Corre var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCCurrent, channelOutput.Source.Output.Function); AssertCurrentSettings(sitePinInfo, channelOutput, 1, 2, 7); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1243,7 +1404,7 @@ public void DifferentSMUDevicesGanged_ConfigureVoltageSourceSettings_CorrectValu var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCVoltage, channelOutput.Source.Output.Function); AssertVoltageSettings(sitePinInfo, channelOutput, 3, 0.5, 1.5); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1269,7 +1430,7 @@ public void DifferentSMUDevicesGanged_ConfigureVoltageSourceSettingsWithSiteData var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCVoltage, channelOutput.Source.Output.Function); AssertVoltageSettings(sitePinInfo, channelOutput, 4, 0.75, 3); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1303,7 +1464,7 @@ public void DifferentSMUDevicesGanged_ConfigureVoltageSourceSettingsWithPinSiteD var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCVoltage, channelOutput.Source.Output.Function); AssertVoltageSettings(sitePinInfo, channelOutput, 3, 1, 3); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -1335,7 +1496,7 @@ public void DifferentSMUDevicesGanged_ConfigurePerPinVoltageSourceSettings_Corre var channelOutput = sessionInfo.Session.Outputs[sitePinInfo.IndividualChannelString]; Assert.Equal(DCPowerSourceOutputFunction.DCVoltage, channelOutput.Source.Output.Function); AssertVoltageSettings(channelOutput, 4, 0.6); - AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02" : "SMU_4137_C5_S03"); + AssertTriggerSettings(sitePinInfo, channelOutput, sitePinInfo.SiteNumber == 0 ? "SMU_4137_C5_S02/0" : "SMU_4137_C5_S03/0"); }); } @@ -2013,10 +2174,13 @@ private void AssertTriggerSettings(SitePinInfo sitePinInfo, DCPowerOutput channe private string GetTriggerName(SitePinInfo sitePinInfo, string leaderChannelString) { var channel = sitePinInfo.IndividualChannelString; + var leaderChannel = leaderChannelString.Split('/'); + var leaderChannelSlot = leaderChannel[0]; + var leaderChannelNumber = leaderChannel[leaderChannel.Length - 1]; if (sitePinInfo.CascadingInfo is GangingInfo gangingInfo && gangingInfo.IsFollower) { - return $"/{leaderChannelString}/Engine0/SourceTrigger"; + return $"/{leaderChannelSlot}/Engine{leaderChannelNumber}/SourceTrigger"; } if (channel.Contains("SMU_4147")) { diff --git a/TestAssets/Supporting Materials/Pin Maps/SMUGangPinGroup_SessionPerChannel.pinmap b/TestAssets/Supporting Materials/Pin Maps/SMUGangPinGroup_SessionPerChannel.pinmap index 4fbadac9..be6f7d43 100644 --- a/TestAssets/Supporting Materials/Pin Maps/SMUGangPinGroup_SessionPerChannel.pinmap +++ b/TestAssets/Supporting Materials/Pin Maps/SMUGangPinGroup_SessionPerChannel.pinmap @@ -28,10 +28,7 @@ - - - - + @@ -46,6 +43,13 @@ + + + + + + +