diff --git a/source/TS.NET.Engine/EngineManager.cs b/source/TS.NET.Engine/EngineManager.cs
index 466a75f..d94eff6 100644
--- a/source/TS.NET.Engine/EngineManager.cs
+++ b/source/TS.NET.Engine/EngineManager.cs
@@ -188,21 +188,25 @@ public bool TryStart(string settingsFile, string calibrationFile, string deviceS
{
logger?.LogInformation($"Calibration loaded from path: {calibrationFile}");
loadedCalibration = Calibration.FromJsonFile(calibrationFile);
+ ts.SetCalibration(loadedCalibration);
}
else if (ThunderscopeNonVolatileMemory.TryReadUserCalibration(ts, out var userCalibration))
{
logger?.LogInformation($"Calibration loaded from user calibration memory");
loadedCalibration = userCalibration!;
+ ts.SetCalibration(loadedCalibration);
}
else if (ThunderscopeNonVolatileMemory.TryReadFactoryCalibration(ts, out var factoryCalibration))
{
logger?.LogInformation($"Calibration loaded from factory calibration memory");
loadedCalibration = factoryCalibration!;
+ // Factory Calibration loaded by tslitex
}
else if (File.Exists("thunderscope-calibration.json"))
{
logger?.LogInformation($"Calibration loaded from thunderscope-calibration.json");
loadedCalibration = Calibration.FromJsonFile("thunderscope-calibration.json");
+ ts.SetCalibration(loadedCalibration);
}
else
{
@@ -225,7 +229,7 @@ public bool TryStart(string settingsFile, string calibrationFile, string deviceS
initialHardwareConfiguration.ExtSyncMode = ThunderscopeExtSyncMode.Disabled;
initialHardwareConfiguration.RefClockMode = ThunderscopeRefClockMode.Disabled;
initialHardwareConfiguration.RefClockFrequencyHz = 10_000_000;
- ts.Configure(initialHardwareConfiguration, loadedCalibration, thunderscopeSettings.HardwareRevision);
+ ts.Configure(initialHardwareConfiguration);
ts.StartMonitoring();
thunderscope = ts;
break;
diff --git a/source/TS.NET.Sequences/Singletons/Instruments.cs b/source/TS.NET.Sequences/Singletons/Instruments.cs
index 0709250..55fa968 100644
--- a/source/TS.NET.Sequences/Singletons/Instruments.cs
+++ b/source/TS.NET.Sequences/Singletons/Instruments.cs
@@ -89,7 +89,7 @@ public string Initialise()
hardwareConfig.Frontend[3] = ThunderscopeChannelFrontend.Default();
thunderScope = new Driver.Libtslitex.Thunderscope(loggerFactory, 1024 * 1024);
thunderScope.Open(0);
- thunderScope.Configure(hardwareConfig, Calibration.Default(), "");
+ thunderScope.Configure(hardwareConfig);
// Need to set manual control on all channels so that SetRate doesn't run normal logic
var manualControl = new ThunderscopeChannelFrontendManualControl() { Coupling = ThunderscopeCoupling.DC, Termination = ThunderscopeTermination.OneMegaohm, Attenuator = 0, DAC = 2000, DPOT = 50, PgaLadderAttenuation = 0, PgaFilter = ThunderscopeBandwidth.Bw20M, PgaHighGain = 0 };
thunderScope.SetChannelManualControl(0, manualControl);
@@ -144,10 +144,10 @@ public void SetThunderscopeChannel(int[] enabledChannelIndices)
{
if (!enabledChannelIndices.SequenceEqual(cachedChannelIndices))
{
- thunderScope?.SetChannelEnable(0, enabledChannelIndices.Contains(0), updateFrontends: false);
- thunderScope?.SetChannelEnable(1, enabledChannelIndices.Contains(1), updateFrontends: false);
- thunderScope?.SetChannelEnable(2, enabledChannelIndices.Contains(2), updateFrontends: false);
- thunderScope?.SetChannelEnable(3, enabledChannelIndices.Contains(3), updateFrontends: false);
+ thunderScope?.SetChannelEnable(0, enabledChannelIndices.Contains(0));
+ thunderScope?.SetChannelEnable(1, enabledChannelIndices.Contains(1));
+ thunderScope?.SetChannelEnable(2, enabledChannelIndices.Contains(2));
+ thunderScope?.SetChannelEnable(3, enabledChannelIndices.Contains(3));
cachedSampleRateHz = 0;
cachedChannelIndices = enabledChannelIndices;
}
diff --git a/source/TS.NET/Drivers/Libtslitex/Interop/Interop.cs b/source/TS.NET/Drivers/Libtslitex/Interop/Interop.cs
index cbbb816..ea425ed 100644
--- a/source/TS.NET/Drivers/Libtslitex/Interop/Interop.cs
+++ b/source/TS.NET/Drivers/Libtslitex/Interop/Interop.cs
@@ -87,35 +87,99 @@ public struct tsScopeState_t
public byte acq_power_good;
}
+ [StructLayout(LayoutKind.Sequential)]
+ public struct tsAfePathCalibration_s
+ {
+ public double bufferInputVpp;
+ public double trimOffsetDacZeroC;
+ public double trimOffsetDacZeroM;
+ public double trimOffsetDacScale;
+ public uint trimDPot;
+ }
+
[StructLayout(LayoutKind.Sequential)]
public struct tsChannelCalibration_t
{
- public int buffer_uV;
- public int bias_uV;
- public int attenuatorGain1M_mdB;
- public int attenuatorGain50_mdB;
- public int bufferGain_mdB;
- public int trimRheostat_range;
- public int preampLowGainError_mdB;
- public int preampHighGainError_mdB;
+ public double attenuatorScale;
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 11)]
+ public tsAfePathCalibration_s[] highPgaPathCal;
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 11)]
+ public tsAfePathCalibration_s[] lowPgaPathCal;
+
+ public tsChannelCalibration_t() {
+ highPgaPathCal = new tsAfePathCalibration_s[11];
+ lowPgaPathCal = new tsAfePathCalibration_s[11]; }
+ }
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
- public int[] preampAttenuatorGain_mdB;
- public int preampOutputGainError_mdB;
- public int preampLowOffset_uV;
- public int preampHighOffset_uV;
- public int preampInputBias_uA;
+ [StructLayout(LayoutKind.Sequential)]
+ public struct tsAdcLoad_t
+ {
+ public uint rate;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public double[] scale;
- public tsChannelCalibration_t() { preampAttenuatorGain_mdB = new int[11]; }
+ public tsAdcLoad_t() { scale = new double[4];}
}
-
+
[StructLayout(LayoutKind.Sequential)]
- public struct tsAdcCalibration_t
+ public struct tsAdcLoadCal_t
+ {
+ public uint channels;
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
+ public tsAdcLoad_t[] conf;
+
+ public tsAdcLoadCal_t() {
+ conf = new tsAdcLoad_t[8];
+ for (var cal = 0; cal < 8; cal++)
+ {
+ conf[cal] = new tsAdcLoad_t();
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct tsAdcGain_t
{
+ public uint rate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] branchFineGain;
+ public byte[] gain;
- public tsAdcCalibration_t() { branchFineGain = new byte[8]; }
+ public tsAdcGain_t() { gain = new byte[8];}
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct tsAdcGainCal_t
+ {
+ public uint channels;
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
+ public tsAdcGain_t[] conf;
+
+ public tsAdcGainCal_t() {
+ conf = new tsAdcGain_t[8];
+ for (var cal = 0; cal < 8; cal++)
+ {
+ conf[cal] = new tsAdcGain_t();
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct tsAdcCalibration_t
+ {
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 11)]
+ public tsAdcLoadCal_t[] loadCal;
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 11)]
+ public tsAdcGainCal_t[] branchFineGain;
+
+ public tsAdcCalibration_t() {
+ loadCal = new tsAdcLoadCal_t[11];
+ branchFineGain = new tsAdcGainCal_t[11];
+ for (var cal = 0; cal < 11; cal++)
+ {
+ loadCal[cal] = new tsAdcLoadCal_t();
+ branchFineGain[cal] = new tsAdcGainCal_t();
+ }
+ }
}
public enum tsSampleFormat_t
@@ -171,7 +235,10 @@ public enum tsSampleFormat_t
public static unsafe partial int UserDataWrite(nint ts, byte* buffer, uint offset, uint writeLen);
[DllImport(library, EntryPoint = "thunderscopeChanCalibrationSet")] // Use runtime marshalling for now. Custom marshalling later.
- public static extern int SetCalibration(nint ts, uint channel, in tsChannelCalibration_t cal);
+ public static extern int SetAFECalibration(nint ts, uint channel, in tsChannelCalibration_t cal);
+
+ [DllImport(library, EntryPoint = "thunderscopeAdcCalibrationGet")] // Use runtime marshalling for now. Custom marshalling later.
+ public static extern int GetAFECalibration(nint ts, uint channel, out tsChannelCalibration_t cal);
[DllImport(library, EntryPoint = "thunderscopeAdcCalibrationSet")] // Use runtime marshalling for now. Custom marshalling later.
public static extern int SetAdcCalibration(nint ts, in tsAdcCalibration_t cal);
@@ -194,6 +261,9 @@ public struct tsChannelCtrl_t
[LibraryImport(library, EntryPoint = "thunderscopeCalibrationManualCtrl")]
public static unsafe partial int SetChannelManualControl(nint ts, uint channel, in tsChannelCtrl_t ctrl);
+
+ [LibraryImport(library, EntryPoint = "thunderscopeCalibrationManualAdcFineGain")]
+ public static unsafe partial int SetAdcManualFineGain(nint ts, in byte[] ctrl);
public enum tsEventType_t
{
diff --git a/source/TS.NET/Drivers/Libtslitex/Thunderscope.cs b/source/TS.NET/Drivers/Libtslitex/Thunderscope.cs
index 8bf9b0e..97b2ac2 100644
--- a/source/TS.NET/Drivers/Libtslitex/Thunderscope.cs
+++ b/source/TS.NET/Drivers/Libtslitex/Thunderscope.cs
@@ -2,7 +2,17 @@
namespace TS.NET.Driver.Libtslitex;
-public record ThunderscopeLiteXDevice(uint DeviceID, uint HardwareRev, uint GatewareRev, uint LitexRev, string DevicePath, string Identity, string Serial, string BuildConfiguration, string BuildDate, string ManufacturingSignature);
+public record ThunderscopeLiteXDevice
+ (uint DeviceID,
+ uint HardwareRev,
+ uint GatewareRev,
+ uint LitexRev,
+ string DevicePath,
+ string Identity,
+ string Serial,
+ string BuildConfiguration,
+ string BuildDate,
+ string ManufacturingSignature);
public class Thunderscope : IThunderscope
{
@@ -16,6 +26,7 @@ public class Thunderscope : IThunderscope
private bool[] channelManualOverride;
private Calibration calibration;
private ThunderscopeChannelFrontend[] channelFrontend;
+ private ThunderscopeLiteXDevice tsInfo;
uint cachedSampleRateHz = 1_000_000_000;
AdcResolution cachedSampleResolution = AdcResolution.EightBit;
@@ -50,12 +61,19 @@ public Thunderscope(ILoggerFactory loggerFactory, int dmaBufferSize)
channelManualOverride = new bool[4];
calibration = new Calibration();
channelFrontend = new ThunderscopeChannelFrontend[4];
+ tsInfo = new ThunderscopeLiteXDevice(0, 0, 0, 0, "", "", "", "", "", "");
}
public void Open(uint devIndex)
{
if (open)
Close();
+
+ if (0 == Interop.ListDevices(devIndex, out var devInfo))
+ {
+ tsInfo = new ThunderscopeLiteXDevice(devInfo.deviceID, devInfo.hw_id, devInfo.gw_id, devInfo.litex, devInfo.devicePath, devInfo.identity, devInfo.serialNumber, devInfo.buildConfig, devInfo.buildDate, devInfo.mfgSignature);
+ beta = (devInfo.hw_id & (1 << 9)) == 0; // ID Valid in bit [9] is not set for Beta hardware builds
+ }
tsHandle = Interop.Open(devIndex, false);
@@ -64,47 +82,36 @@ public void Open(uint devIndex)
open = true;
}
- public void Configure(ThunderscopeHardwareConfig initialHardwareConfiguration, Calibration calibration, string hardwareRevision)
+ public void SetCalibration(Calibration calibration)
{
CheckOpen();
- if (hardwareRevision.Equals("Rev4.1", StringComparison.InvariantCultureIgnoreCase))
- beta = true;
-
- //SetAdcCalibration(initialHardwareConfiguration.AdcCalibration);
- //for (int chan = 0; chan < 4; chan++)
- //{
- // SetChannelCalibration(chan, initialHardwareConfiguration.Calibration[chan]);
- //}
+ SetAdcCalibration(calibration.Adc);
+ for (int chan = 0; chan < 4; chan++)
+ {
+ SetChannelCalibration(chan, calibration.Frontend[chan]);
+ }
this.calibration = calibration;
+ }
+ public void Configure(ThunderscopeHardwareConfig initialHardwareConfiguration)
+ {
+ CheckOpen();
+
GetStatus();
for (int chan = 0; chan < 4; chan++)
{
channelFrontend[chan] = initialHardwareConfiguration.Frontend[chan];
var chanEnabled = ((initialHardwareConfiguration.Acquisition.EnabledChannels >> chan) & 0x01) > 0;
- SetChannelEnable(chan, chanEnabled, updateFrontends: false);
+ SetChannelEnable(chan, chanEnabled);
}
- SetSampleMode(initialHardwareConfiguration.Acquisition.SampleRateHz, initialHardwareConfiguration.Acquisition.Resolution, updateFrontends: false);
+ SetSampleMode(initialHardwareConfiguration.Acquisition.SampleRateHz, initialHardwareConfiguration.Acquisition.Resolution);
UpdateFrontends();
SetExtSyncMode(initialHardwareConfiguration.ExtSyncMode);
SetRefClockMode(initialHardwareConfiguration.RefClockMode);
SetRefClockFrequency(initialHardwareConfiguration.RefClockFrequencyHz);
- var temperature = GetStatus().FpgaTemp;
- var frontend = calibration.Frontend[0];
- foreach (var path in frontend.Path)
- {
- Frontend.CalculateAllowableOffsetRangeV(logger, frontend, path, attenuator: false, temperature, out var minOffsetV, out var maxOffsetV);
- logger.LogDebug($"Input range: {path.BufferInputVpp:F3}Vpp, input offset: {minOffsetV:F3}V to {maxOffsetV:F3}V [{path.PgaPreampGain}, {path.PgaLadder}, attenuator off]");
- }
-
- foreach (var path in frontend.Path)
- {
- Frontend.CalculateAllowableOffsetRangeV(logger, frontend, path, attenuator: true, temperature, out var minOffsetV, out var maxOffsetV);
- logger.LogDebug($"Input range: {path.BufferInputVpp * frontend.AttenuatorScale:F3}Vpp, input offset: {minOffsetV:F3}V to {maxOffsetV:F3}V [{path.PgaPreampGain}, {path.PgaLadder}, attenuator on]");
- }
}
public void Close()
@@ -243,42 +250,29 @@ public ThunderscopeChannelFrontend GetChannelFrontend(int channelIndex)
{
CheckOpen();
- //var channel = new ThunderscopeChannelFrontend();
- //var tsChannel = new Interop.tsChannelParam_t();
-
- //var retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
- //if (retVal < 0)
- // throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
-
- //channel.RequestedVoltFullScale = requestedChannelVoltScale[channelIndex];
- //channel.ActualVoltFullScale = (double)tsChannel.volt_scale_uV / 1000000.0;
- //channel.RequestedVoltOffset = requestedChannelVoltOffset[channelIndex];
- //channel.ActualVoltOffset = (double)tsChannel.volt_offset_uV / 1000000.0;
- //channel.Coupling = (tsChannel.coupling == 1) ? ThunderscopeCoupling.AC : ThunderscopeCoupling.DC;
- //channel.Termination = (tsChannel.term == 1) ? ThunderscopeTermination.FiftyOhm : ThunderscopeTermination.OneMegaohm;
- //channel.Bandwidth = (tsChannel.bandwidth == 750) ? ThunderscopeBandwidth.Bw750M :
- // (tsChannel.bandwidth == 650) ? ThunderscopeBandwidth.Bw650M :
- // (tsChannel.bandwidth == 350) ? ThunderscopeBandwidth.Bw350M :
- // (tsChannel.bandwidth == 200) ? ThunderscopeBandwidth.Bw200M :
- // (tsChannel.bandwidth == 100) ? ThunderscopeBandwidth.Bw100M :
- // (tsChannel.bandwidth == 20) ? ThunderscopeBandwidth.Bw20M :
- // ThunderscopeBandwidth.BwFull;
-
- //return channel;
-
-
- var channel = channelFrontend[channelIndex];
- //var tsChannel = new Interop.tsChannelParam_t();
-
- //var retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
- //if (retVal < 0)
- // throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
- //channel.Termination = tsChannel.term switch
- //{
- // 0 => ThunderscopeTermination.OneMegaohm,
- // 1 => ThunderscopeTermination.FiftyOhm,
- // _ => throw new NotImplementedException()
- //};
+ var channel = new ThunderscopeChannelFrontend();
+ var tsChannel = new Interop.tsChannelParam_t();
+
+ var retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
+
+ channel.RequestedVoltFullScale = channelFrontend[channelIndex].RequestedVoltFullScale;
+ channel.ActualVoltFullScale = (double)tsChannel.volt_scale_uV / 1000000.0;
+ channel.RequestedVoltOffset = channelFrontend[channelIndex].RequestedVoltOffset;
+ channel.ActualVoltOffset = (double)tsChannel.volt_offset_uV / 1000000.0;
+ channel.Coupling = (tsChannel.coupling == 1) ? ThunderscopeCoupling.AC : ThunderscopeCoupling.DC;
+ channel.RequestedTermination = channelFrontend[channelIndex].RequestedTermination;
+ channel.ActualTermination = (tsChannel.term == 1) ? ThunderscopeTermination.FiftyOhm : ThunderscopeTermination.OneMegaohm;
+ channel.Bandwidth = (tsChannel.bandwidth == 750) ? ThunderscopeBandwidth.Bw750M :
+ (tsChannel.bandwidth == 650) ? ThunderscopeBandwidth.Bw650M :
+ (tsChannel.bandwidth == 350) ? ThunderscopeBandwidth.Bw350M :
+ (tsChannel.bandwidth == 200) ? ThunderscopeBandwidth.Bw200M :
+ (tsChannel.bandwidth == 100) ? ThunderscopeBandwidth.Bw100M :
+ (tsChannel.bandwidth == 20) ? ThunderscopeBandwidth.Bw20M :
+ ThunderscopeBandwidth.BwFull;
+
+
return channel;
}
@@ -327,15 +321,42 @@ private ThunderscopeAcquisitionConfig GetAcquisitionConfig()
return acquisitionConfig;
}
- //public ThunderscopeChannelCalibration GetChannelCalibration(int channelIndex)
- //{
- // CheckOpen();
+ public FrontendCalibration GetChannelCalibration(int channelIndex)
+ {
+ CheckOpen();
+
+ var afeCalibration = FrontendCalibration.Default(channelIndex);
+ var tsCal = new Interop.tsChannelCalibration_t();
- // if (channelIndex >= 4 || channelIndex < 0)
- // throw new ThunderscopeException($"Invalid Channel Index {channelIndex}");
+ if (channelIndex >= 4 || channelIndex < 0)
+ throw new ThunderscopeException($"Invalid Channel Index {channelIndex}");
+
+ var retVal = Interop.GetAFECalibration(tsHandle, (uint)channelIndex, out tsCal);
+
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to get libtslitex AFE{channelIndex} Calibration ({GetLibraryReturnString(retVal)})");
- // return channelCalibration[channelIndex];
- //}
+ for (int i = 0; i < 11; i++)
+ {
+ afeCalibration.Path[i].PgaPreampGain = PgaPreampGain.High;
+ afeCalibration.Path[i].PgaLadder = (byte)i;
+ afeCalibration.Path[i].TrimDPot = (byte)tsCal.highPgaPathCal[i].trimDPot;
+ afeCalibration.Path[i].TrimDacScale = tsCal.highPgaPathCal[i].trimOffsetDacScale;
+ afeCalibration.Path[i].TrimDacZeroC = tsCal.highPgaPathCal[i].trimOffsetDacZeroC;
+ afeCalibration.Path[i].TrimDacZeroM = tsCal.highPgaPathCal[i].trimOffsetDacZeroM;
+ afeCalibration.Path[i].BufferInputVpp = tsCal.highPgaPathCal[i].bufferInputVpp;
+
+ afeCalibration.Path[11 + i].PgaPreampGain = PgaPreampGain.Low;
+ afeCalibration.Path[11 + i].PgaLadder = (byte)i;
+ afeCalibration.Path[11 + i].TrimDPot = (byte)tsCal.lowPgaPathCal[i].trimDPot;
+ afeCalibration.Path[11 + i].TrimDacScale = tsCal.lowPgaPathCal[i].trimOffsetDacScale;
+ afeCalibration.Path[11 + i].TrimDacZeroC = tsCal.lowPgaPathCal[i].trimOffsetDacZeroC;
+ afeCalibration.Path[11 + i].TrimDacZeroM = tsCal.lowPgaPathCal[i].trimOffsetDacZeroM;
+ afeCalibration.Path[11 + i].BufferInputVpp = tsCal.lowPgaPathCal[i].bufferInputVpp;
+ }
+ afeCalibration.AttenuatorScale = tsCal.attenuatorScale;
+ return afeCalibration;
+ }
public ThunderscopeLiteXStatus GetStatus()
{
@@ -365,7 +386,7 @@ public ThunderscopeLiteXStatus GetStatus()
public void SetRate(ulong sampleRateHz)
{
- SetSampleMode(sampleRateHz, cachedSampleResolution, updateFrontends: true);
+ SetSampleMode(sampleRateHz, cachedSampleResolution);
}
public void SetResolution(AdcResolution resolution)
@@ -374,108 +395,203 @@ public void SetResolution(AdcResolution resolution)
if (resolution == AdcResolution.TwelveBit && sampleRateHz > 660_000_000)
sampleRateHz = 660_000_000;
- SetSampleMode(sampleRateHz, resolution, updateFrontends: true);
+ SetSampleMode(sampleRateHz, resolution);
}
public void SetChannelFrontend(int channelIndex, ThunderscopeChannelFrontend channel)
{
CheckOpen();
- //var tsChannel = new Interop.tsChannelParam_t();
- //var retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
+ var tsChannel = new Interop.tsChannelParam_t();
+ var retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
- //if (retVal < 0)
- // throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
- //tsChannel.volt_scale_uV = (uint)(channel.RequestedVoltFullScale * 1000000);
- //tsChannel.volt_offset_uV = (int)(channel.RequestedVoltOffset * 1000000);
- //tsChannel.coupling = (channel.Coupling == ThunderscopeCoupling.DC) ? (byte)0 : (byte)1;
- //tsChannel.term = (channel.Termination == ThunderscopeTermination.OneMegaohm) ? (byte)0 : (byte)1;
- //tsChannel.bandwidth = channel.Bandwidth switch
- //{
- // ThunderscopeBandwidth.BwFull => 900,
- // ThunderscopeBandwidth.Bw750M => 750,
- // ThunderscopeBandwidth.Bw650M => 650,
- // ThunderscopeBandwidth.Bw350M => 350,
- // ThunderscopeBandwidth.Bw200M => 200,
- // ThunderscopeBandwidth.Bw100M => 100,
- // ThunderscopeBandwidth.Bw20M => 20,
- // _ => throw new NotImplementedException()
- //};
+ tsChannel.volt_scale_uV = (uint)(channel.RequestedVoltFullScale * 1000000);
+ tsChannel.volt_offset_uV = (int)(channel.RequestedVoltOffset * 1000000);
+ tsChannel.coupling = (channel.Coupling == ThunderscopeCoupling.DC) ? (byte)0 : (byte)1;
+ tsChannel.term = (channel.RequestedTermination == ThunderscopeTermination.OneMegaohm) ? (byte)0 : (byte)1;
+ tsChannel.bandwidth = channel.Bandwidth switch
+ {
+ ThunderscopeBandwidth.BwFull => 900,
+ ThunderscopeBandwidth.Bw750M => 750,
+ ThunderscopeBandwidth.Bw650M => 650,
+ ThunderscopeBandwidth.Bw350M => 350,
+ ThunderscopeBandwidth.Bw200M => 200,
+ ThunderscopeBandwidth.Bw100M => 100,
+ ThunderscopeBandwidth.Bw20M => 20,
+ _ => throw new NotImplementedException()
+ };
- //retVal = Interop.SetChannelConfig(tsHandle, (uint)channelIndex, in tsChannel);
+ logger.LogInformation($"Configure channel {channelIndex}: scale {tsChannel.volt_scale_uV}uVpp, offset {tsChannel.volt_offset_uV}uV, term {tsChannel.term}");
- //if (retVal < 0)
- // throw new ThunderscopeException($"Failed to set channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
+ retVal = Interop.SetChannelConfig(tsHandle, (uint)channelIndex, in tsChannel);
- //requestedChannelVoltScale[channelIndex] = channel.RequestedVoltFullScale;
- //requestedChannelVoltOffset[channelIndex] = channel.RequestedVoltOffset;
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to set channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
- var loadScales = Frontend.GetAllLoadScales(calibration, channelsEnabled, cachedSampleRateHz);
- SetChannelFrontend(channelIndex, channel, loadScales[channelIndex]);
+
+ retVal = Interop.GetChannelConfig(tsHandle, (uint)channelIndex, out tsChannel);
+
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to get channel {channelIndex} config ({GetLibraryReturnString(retVal)})");
+
+ channelFrontend[channelIndex].ActualTermination = (tsChannel.term == 0) ? ThunderscopeTermination.OneMegaohm : ThunderscopeTermination.FiftyOhm;
+ channelFrontend[channelIndex].ActualVoltFullScale = tsChannel.volt_scale_uV * 1000000.0;
+ channelFrontend[channelIndex].ActualVoltOffset = tsChannel.volt_offset_uV * 1000000.0;
+ channelFrontend[channelIndex].RequestedVoltFullScale = channel.RequestedVoltFullScale;
+ channelFrontend[channelIndex].RequestedVoltOffset = channel.RequestedVoltOffset;
+ channelFrontend[channelIndex].RequestedTermination = channel.RequestedTermination;
+ channelFrontend[channelIndex].Bandwidth = channel.Bandwidth;
+ channelFrontend[channelIndex].Coupling = channel.Coupling;
+
+ channelManualOverride[channelIndex] = false; // SetChannelManualControl sets to true, so immediately set to false
}
public void SetAdcBranchGainManualControl(byte[] branchGain)
{
CheckOpen();
- var tsCal = new Interop.tsAdcCalibration_t();
- tsCal.branchFineGain[0] = branchGain[0];
- tsCal.branchFineGain[1] = branchGain[1];
- tsCal.branchFineGain[2] = branchGain[2];
- tsCal.branchFineGain[3] = branchGain[3];
- tsCal.branchFineGain[4] = branchGain[4];
- tsCal.branchFineGain[5] = branchGain[5];
- tsCal.branchFineGain[6] = branchGain[6];
- tsCal.branchFineGain[7] = branchGain[7];
-
- Interop.SetAdcCalibration(tsHandle, in tsCal);
- }
-
- //public void SetChannelCalibration(int channelIndex, ThunderscopeChannelCalibration channelCalibration)
- //{
- // CheckOpen();
-
- // if (channelIndex >= 4 || channelIndex < 0)
- // throw new ThunderscopeException($"Invalid Channel Index {channelIndex}");
-
- // var tsCal = new Interop.tsChannelCalibration_t
- // {
- // //buffer_uV = (int)(channelCalibration.BufferOffset * 1000000),
- // //bias_uV = (int)(channelCalibration.BiasVoltage * 1000000),
- // //attenuatorGain1M_mdB = (int)(channelCalibration.AttenuatorGain1MOhm * 1000),
- // //attenuatorGain50_mdB = (int)(channelCalibration.AttenuatorGain50Ohm * 1000),
- // //bufferGain_mdB = (int)(channelCalibration.BufferGain * 1000),
- // //trimRheostat_range = (int)channelCalibration.TrimResistorOhms,
- // //preampLowGainError_mdB = (int)(channelCalibration.PgaLowGainError * 1000),
- // //preampHighGainError_mdB = (int)(channelCalibration.PgaHighGainError * 1000),
- // //preampLowOffset_uV = (int)(channelCalibration.PgaLowOffsetVoltage * 1000000),
- // //preampHighOffset_uV = (int)(channelCalibration.PgaHighOffsetVoltage * 1000000),
- // //preampOutputGainError_mdB = (int)(channelCalibration.PgaOutputGainError * 1000),
- // //preampInputBias_uA = (int)channelCalibration.PgaInputBiasCurrent,
- // };
- // //tsCal.preampAttenuatorGain_mdB[0] = (int)channelCalibration.PgaAttenuatorGain0;
- // //tsCal.preampAttenuatorGain_mdB[1] = (int)channelCalibration.PgaAttenuatorGain1;
- // //tsCal.preampAttenuatorGain_mdB[2] = (int)channelCalibration.PgaAttenuatorGain2;
- // //tsCal.preampAttenuatorGain_mdB[3] = (int)channelCalibration.PgaAttenuatorGain3;
- // //tsCal.preampAttenuatorGain_mdB[4] = (int)channelCalibration.PgaAttenuatorGain4;
- // //tsCal.preampAttenuatorGain_mdB[5] = (int)channelCalibration.PgaAttenuatorGain5;
- // //tsCal.preampAttenuatorGain_mdB[6] = (int)channelCalibration.PgaAttenuatorGain6;
- // //tsCal.preampAttenuatorGain_mdB[7] = (int)channelCalibration.PgaAttenuatorGain7;
- // //tsCal.preampAttenuatorGain_mdB[8] = (int)channelCalibration.PgaAttenuatorGain8;
- // //tsCal.preampAttenuatorGain_mdB[9] = (int)channelCalibration.PgaAttenuatorGain9;
- // //tsCal.preampAttenuatorGain_mdB[10] = (int)channelCalibration.PgaAttenuatorGain10;
-
- // this.channelCalibration[channelIndex] = channelCalibration;
- // Interop.SetCalibration(tsHandle, (uint)channelIndex, in tsCal);
- //}
-
- public void SetChannelEnable(int channelIndex, bool enabled) => SetChannelEnable(channelIndex, enabled, updateFrontends: true);
+ var tsCal = new byte[8];
+ tsCal[0] = branchGain[0];
+ tsCal[1] = branchGain[1];
+ tsCal[2] = branchGain[2];
+ tsCal[3] = branchGain[3];
+ tsCal[4] = branchGain[4];
+ tsCal[5] = branchGain[5];
+ tsCal[6] = branchGain[6];
+ tsCal[7] = branchGain[7];
+
+ Interop.SetAdcManualFineGain(tsHandle, in tsCal);
+ }
+
+ public void SetChannelCalibration(int channelIndex, FrontendCalibration channelCalibration)
+ {
+ CheckOpen();
+
+ if (channelIndex >= 4 || channelIndex < 0)
+ throw new ThunderscopeException($"Invalid Channel Index {channelIndex}");
+
+ var tsCal = new Interop.tsChannelCalibration_t();
+
+ if (channelIndex >= 4 || channelIndex < 0)
+ throw new ThunderscopeException($"Invalid Channel Index {channelIndex}");
+
+
+
+ foreach (var path in channelCalibration.Path)
+ {
+ if (path.PgaPreampGain == PgaPreampGain.High)
+ {
+ tsCal.highPgaPathCal[path.PgaLadder].trimDPot = path.TrimDPot;
+ tsCal.highPgaPathCal[path.PgaLadder].trimOffsetDacZeroC = path.TrimDacZeroC;
+ tsCal.highPgaPathCal[path.PgaLadder].trimOffsetDacZeroM = path.TrimDacZeroM;
+ tsCal.highPgaPathCal[path.PgaLadder].trimOffsetDacScale = path.TrimDacScale;
+ tsCal.highPgaPathCal[path.PgaLadder].bufferInputVpp = path.BufferInputVpp;
+ }
+ else
+ {
+ tsCal.lowPgaPathCal[path.PgaLadder].trimDPot = path.TrimDPot;
+ tsCal.lowPgaPathCal[path.PgaLadder].trimOffsetDacZeroC = path.TrimDacZeroC;
+ tsCal.lowPgaPathCal[path.PgaLadder].trimOffsetDacZeroM = path.TrimDacZeroM;
+ tsCal.lowPgaPathCal[path.PgaLadder].trimOffsetDacScale = path.TrimDacScale;
+ tsCal.lowPgaPathCal[path.PgaLadder].bufferInputVpp = path.BufferInputVpp;
+ }
+ }
+
+ tsCal.attenuatorScale = channelCalibration.AttenuatorScale;
+
+ var retVal = Interop.SetAFECalibration(tsHandle, (uint)channelIndex, in tsCal);
+ if (retVal < 0)
+ throw new ThunderscopeException($"Failed to set libtslitex AFE{channelIndex} Calibration ({GetLibraryReturnString(retVal)})");
+
+ }
+
+ public void SetAdcCalibration(AdcCalibration adcCalibration)
+ {
+ CheckOpen();
+
+ var tsAdcCal = new Interop.tsAdcCalibration_t();
+ for (int i = 0; i < adcCalibration.LoadScale.Length; i++)
+ {
+ tsAdcCal.loadCal[i].channels = (uint)adcCalibration.LoadScale[i].Channel.Aggregate(0, (current, chan) => 1 << chan);
+ for (int j = 0; j < adcCalibration.LoadScale[i].RateScale.Length; j++)
+ {
+ tsAdcCal.loadCal[i].conf[j].rate = adcCalibration.LoadScale[i].RateScale[j].Rate;
+ for (int k = 0; k < adcCalibration.LoadScale[i].RateScale[j].Scale.Length; k++)
+ tsAdcCal.loadCal[i].conf[j].scale[k] = adcCalibration.LoadScale[i].RateScale[j].Scale[k];
+ }
+ }
+ for (int i = 0; i < adcCalibration.BranchGain.Length; i++)
+ {
+ tsAdcCal.branchFineGain[i].channels = (uint)adcCalibration.BranchGain[i].Channel.Aggregate(0, (current, chan) => 1 << chan);
+ for (int j = 0; j < adcCalibration.BranchGain[i].RateGain.Length; j++)
+ {
+ tsAdcCal.branchFineGain[i].conf[j].rate = adcCalibration.BranchGain[i].RateGain[j].Rate;
+ for (int k = 0; k < adcCalibration.BranchGain[i].RateGain[j].Gain.Length; k++)
+ tsAdcCal.branchFineGain[i].conf[j].gain[k] = (byte)adcCalibration.BranchGain[i].RateGain[j].Gain[k];
+ }
+ }
+ }
+
+ public AdcCalibration GetAdcCalibration()
+ {
+ var adcCal = AdcCalibration.Default();
+ var tsAdcCal = new Interop.tsAdcCalibration_t();
+ if (0 == Interop.GetAdcCalibration(tsHandle, out tsAdcCal))
+ {
+ // Convert Load Scale calibration
+ for (int load = 0; load < 11; load++)
+ {
+ var channelCount = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if ((tsAdcCal.loadCal[load].channels & (1 << i)) != 0)
+ {
+ adcCal.LoadScale[load].Channel[channelCount] = i;
+ channelCount++;
+ }
+ }
+ for (int rateIdx = 0; rateIdx < 8; rateIdx++)
+ {
+ adcCal.LoadScale[load].RateScale[rateIdx].Rate = tsAdcCal.loadCal[load].conf[rateIdx].rate;
+ for (int i = 0; i < channelCount; i++)
+ {
+ adcCal.LoadScale[load].RateScale[rateIdx].Scale[i] = tsAdcCal.loadCal[load].conf[rateIdx].scale[i];
+ }
+ }
+ }
+ // Convert Branch Fine Gain calibration
+ for (int gain = 0; gain < 11; gain++)
+ {
+ var channelCount = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if ((tsAdcCal.branchFineGain[gain].channels & (1 << i)) != 0)
+ {
+ adcCal.BranchGain[gain].Channel[channelCount] = i;
+ channelCount++;
+ }
+ }
+ for (int rateIdx = 0; rateIdx < 8; rateIdx++)
+ {
+ adcCal.BranchGain[gain].RateGain[rateIdx].Rate = tsAdcCal.branchFineGain[gain].conf[rateIdx].rate;
+ for (int i = 0; i < 8; i++)
+ {
+ adcCal.BranchGain[gain].RateGain[rateIdx].Gain[i] = tsAdcCal.branchFineGain[gain].conf[rateIdx].gain[i];
+ }
+ }
+ }
+ }
+
+ return adcCal;
+ }
///
/// Intended for use by testbench/calibration routines that use SetChannelManualControl
///
- public void SetChannelEnable(int channelIndex, bool enabled, bool updateFrontends)
+ public void SetChannelEnable(int channelIndex, bool enabled)
{
CheckOpen();
@@ -505,10 +621,6 @@ public void SetChannelEnable(int channelIndex, bool enabled, bool updateFrontend
channelsEnabled = channelsEnabled.Where(c => c != channelIndex).ToArray();
}
- // There is a channel-count vs. scale relationship so update frontends
- if (updateFrontends)
- UpdateFrontends();
-
if (restart)
Start();
@@ -669,35 +781,16 @@ public int FactoryDataRead(uint tag, Span buffer)
}
}
- private void SetChannelFrontend(int channelIndex, ThunderscopeChannelFrontend channel, double channelLoadScale)
- {
- CheckOpen();
-
- lastFrontendUpdateTemp = GetStatus().FpgaTemp;
- var frontend = calibration.Frontend[channelIndex];
-
- var calculatedChannel = Frontend.CalculateFrontend(logger, channelIndex, channel, frontend, channelLoadScale, cachedSampleRateHz, lastFrontendUpdateTemp, beta, out var manualControl);
- SetChannelManualControl(channelIndex, manualControl);
- channelManualOverride[channelIndex] = false; // SetChannelManualControl sets to true, so immediately set to false
- channelFrontend[channelIndex] = calculatedChannel;
- }
-
private void UpdateFrontends()
{
- GetStatus(); // Update cachedSampleRateHz & cachedSampleResolution
-
- var loadScales = Frontend.GetAllLoadScales(calibration, channelsEnabled, cachedSampleRateHz);
- for (int i = 0; i < channelFrontend.Length; i++)
+ for (int channelIndex = 0; channelIndex < 4; channelIndex++)
{
// Update all frontends that aren't under manual override, even for disabled channels (so relays actuate when expected)
- if (!channelManualOverride[i])
+ if (!channelManualOverride[channelIndex])
{
- //Console.WriteLine($"Updating channel {i} frontend with load scale {loadScales[i]:F3}");
- SetChannelFrontend(i, channelFrontend[i], loadScales[i]);
+ SetChannelFrontend(channelIndex, channelFrontend[channelIndex]);
}
}
- var branchGains = Frontend.GetAdcBranchGain(calibration, channelsEnabled, cachedSampleRateHz);
- SetAdcBranchGainManualControl(branchGains);
}
private void CheckOpen()
@@ -720,7 +813,7 @@ private static string GetLibraryReturnString(int retValue)
};
}
- private void SetSampleMode(ulong sampleRateHz, AdcResolution resolution, bool updateFrontends)
+ private void SetSampleMode(ulong sampleRateHz, AdcResolution resolution)
{
CheckOpen();
@@ -737,9 +830,6 @@ private void SetSampleMode(ulong sampleRateHz, AdcResolution resolution, bool up
};
var retVal = Interop.SetSampleMode(tsHandle, (uint)sampleRateHz, format);
- // There is a rate vs. scale relationship so update frontends
- if (updateFrontends)
- UpdateFrontends();
if (retVal == -2)
logger.LogTrace($"Failed to set sample rate ({sampleRateHz}): {GetLibraryReturnString(retVal)}");
@@ -770,11 +860,8 @@ private void MonitoringLoop(ILogger logger, CancellationToken cancelToken)
if (diff > tempDelta)
{
- for (int channelIndex = 0; channelIndex < 4; channelIndex++)
- {
- var frontend = GetChannelFrontend(channelIndex);
- SetChannelFrontend(channelIndex, frontend); // Updates lastFrontendUpdateTemp
- }
+ UpdateFrontends();
+ lastFrontendUpdateTemp = currentTemp;
}
}
diff --git a/source/TS.NET/Drivers/Simulation/Thunderscope.cs b/source/TS.NET/Drivers/Simulation/Thunderscope.cs
index 75ee107..35b0c78 100644
--- a/source/TS.NET/Drivers/Simulation/Thunderscope.cs
+++ b/source/TS.NET/Drivers/Simulation/Thunderscope.cs
@@ -167,5 +167,22 @@ public void SetPeriodicEventSync(uint period_us)
{
throw new NotImplementedException();
}
+ public FrontendCalibration GetChannelCalibration(int channelIndex)
+ {
+ throw new NotImplementedException();
+ }
+ public void SetChannelCalibration(int channelIndex, FrontendCalibration channelCalibration)
+ {
+ throw new NotImplementedException();
+ }
+
+ public AdcCalibration GetAdcCalibration()
+ {
+ throw new NotImplementedException();
+ }
+ public void SetAdcCalibration(AdcCalibration adcCalibration)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/source/TS.NET/IThunderscope.cs b/source/TS.NET/IThunderscope.cs
index 27de239..d6c9fd9 100644
--- a/source/TS.NET/IThunderscope.cs
+++ b/source/TS.NET/IThunderscope.cs
@@ -6,10 +6,12 @@ public interface IThunderscope
void Stop();
bool Running();
ThunderscopeChannelFrontend GetChannelFrontend(int channelIndex);
- //ThunderscopeChannelCalibration GetChannelCalibration(int channelIndex);
+ FrontendCalibration GetChannelCalibration(int channelIndex);
+ AdcCalibration GetAdcCalibration();
void SetChannelEnable(int channelIndex, bool enabled);
void SetChannelFrontend(int channelIndex, ThunderscopeChannelFrontend channel);
- //void SetChannelCalibration(int channelIndex, ThunderscopeChannelCalibration channelCalibration);
+ void SetChannelCalibration(int channelIndex, FrontendCalibration channelCalibration);
+ void SetAdcCalibration(AdcCalibration adcCalibration);
void Read(ThunderscopeMemory data);
bool TryRead(Span data, out ulong sampleStartIndex, out int sampleLengthPerChannel);
ThunderscopeHardwareConfig GetConfiguration();