mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-27 05:56:30 +00:00
6ab103e120
Added persistance of last IP used Added link to the Wiki Corrected SPI analyzer Added channel names on analysis settings
314 lines
12 KiB
C#
314 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace SharedDriver
|
|
{
|
|
public class MultiAnalizerDriver : IDisposable, IAnalizerDriver
|
|
{
|
|
Regex regVersion = new Regex(".*?(V([0-9]+)_([0-9]+))$");
|
|
LogicAnalyzerDriver[] connectedDevices;
|
|
|
|
UInt128[][]? tempCapture;
|
|
bool[]? captureFinished;
|
|
int[][]? tempChannels;
|
|
|
|
object locker = new object();
|
|
|
|
public int Channels { get { return connectedDevices.Length * 24; } }
|
|
public LogicAnalyzerDriver[] Devices { get { return connectedDevices; } }
|
|
public event EventHandler<CaptureEventArgs>? CaptureCompleted;
|
|
|
|
bool capturing = false;
|
|
private int channelCount;
|
|
private int triggerChannel;
|
|
private int preSamples;
|
|
|
|
private Action<CaptureEventArgs>? currentCaptureHandler;
|
|
|
|
public bool IsCapturing { get { return capturing; } }
|
|
public bool IsNetwork { get { return false; } }
|
|
|
|
public string DeviceVersion { get; private set; }
|
|
public AnalyzerDriverType DriverType
|
|
{
|
|
get
|
|
{
|
|
return AnalyzerDriverType.Multi;
|
|
}
|
|
}
|
|
public MultiAnalizerDriver(string[] ConnectionStrings) //First connection string must belong to the master device
|
|
{
|
|
if (ConnectionStrings == null || ConnectionStrings.Length < 2 || ConnectionStrings.Length > 5)
|
|
throw new ArgumentOutOfRangeException(nameof(ConnectionStrings), $"Invalid devices specified, 2 to 5 connection strings must be provided");
|
|
|
|
int pos = 0;
|
|
connectedDevices = new LogicAnalyzerDriver[ConnectionStrings.Length];
|
|
|
|
try
|
|
{
|
|
for (pos = 0; pos < ConnectionStrings.Length; pos++)
|
|
{
|
|
connectedDevices[pos] = new LogicAnalyzerDriver(ConnectionStrings[pos]);
|
|
}
|
|
foreach(var dev in connectedDevices)
|
|
dev.CaptureCompleted += Dev_CaptureCompleted;
|
|
|
|
|
|
} catch(Exception ex)
|
|
{
|
|
for (int buc = 0; buc < connectedDevices.Length; buc++)
|
|
{
|
|
if (connectedDevices[buc] != null)
|
|
connectedDevices[buc].Dispose();
|
|
}
|
|
|
|
throw new DeviceConnectionException($"Error connecting to device {ConnectionStrings[pos]}.", ex);
|
|
}
|
|
|
|
string? ver = null;
|
|
|
|
foreach (var device in connectedDevices)
|
|
{
|
|
var mVer = regVersion.Match(device.DeviceVersion);
|
|
|
|
if (mVer == null || !mVer.Success)
|
|
{
|
|
Dispose();
|
|
throw new DeviceConnectionException($"Invalid device version ({device.DeviceVersion}) found on device {ConnectionStrings[(int)device.Tag]}");
|
|
}
|
|
|
|
if (ver == null)
|
|
{
|
|
ver = mVer.Groups[1].Value;
|
|
|
|
if (mVer == null || !mVer.Success || !mVer.Groups[2].Success)
|
|
{
|
|
Dispose();
|
|
throw new DeviceConnectionException($"Invalid device version V{(string.IsNullOrWhiteSpace(mVer?.Value) ? "(unknown)" : mVer?.Value)}, minimum supported version: V5_0");
|
|
}
|
|
|
|
int majorVer = int.Parse(mVer.Groups[2].Value);
|
|
|
|
if (majorVer < 5)
|
|
{
|
|
Dispose();
|
|
throw new DeviceConnectionException($"Invalid device version V{mVer.Value}, minimum supported version: V5_0");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ver != mVer.Groups[1].Value)
|
|
{
|
|
Dispose();
|
|
throw new DeviceConnectionException($"Different device versions found. Master version: {ver}, device {ConnectionStrings[(int)device.Tag]} version: {mVer.Groups[1].Value}.");
|
|
}
|
|
}
|
|
}
|
|
|
|
DeviceVersion = $"MULTI_ANALYZER_{ver}";
|
|
}
|
|
public bool SendNetworkConfig(string AccesPointName, string Password, string IPAddress, ushort Port)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int LoopCount, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
public CaptureError StartPatternCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, int TriggerBitCount, UInt16 TriggerPattern, bool Fast, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
|
{
|
|
try
|
|
{
|
|
if (capturing)
|
|
return CaptureError.Busy;
|
|
|
|
if (Channels == null ||
|
|
Channels.Length == 0 ||
|
|
Channels.Min() < 0 ||
|
|
TriggerBitCount < 1 ||
|
|
TriggerBitCount > 16 ||
|
|
TriggerChannel < 0 ||
|
|
TriggerChannel > 15 ||
|
|
PreSamples < 2 ||
|
|
PostSamples < 512 ||
|
|
Frequency < 3100 ||
|
|
Frequency > 100000000
|
|
)
|
|
return CaptureError.BadParams;
|
|
|
|
int maxChannel = connectedDevices.Length * 24;
|
|
|
|
if (Channels.Max() >= maxChannel)
|
|
return CaptureError.BadParams;
|
|
|
|
int[][] channelsPerDevice = SplitChannelsPerDevice(Channels);
|
|
|
|
if (channelsPerDevice.Length > Channels.Length)
|
|
return CaptureError.BadParams;
|
|
|
|
if (channelsPerDevice[0].Length < 1)
|
|
return CaptureError.BadParams;
|
|
|
|
var captureLimits = GetLimits(Channels);
|
|
|
|
if (PreSamples > captureLimits.MaxPreSamples ||
|
|
PostSamples > captureLimits.MaxPostSamples ||
|
|
PreSamples + PostSamples > captureLimits.MinPreSamples + captureLimits.MaxPostSamples)
|
|
return CaptureError.BadParams;
|
|
|
|
double samplePeriod = 1000000000.0 / Frequency;
|
|
double delay = Fast ? TriggerDelays.FastTriggerDelay : TriggerDelays.ComplexTriggerDelay;
|
|
int offset = (int)(Math.Round((delay / samplePeriod) + 0.3, 0));
|
|
|
|
channelCount = Channels.Length;
|
|
triggerChannel = TriggerChannel;
|
|
preSamples = PreSamples;
|
|
currentCaptureHandler = CaptureCompletedHandler;
|
|
|
|
capturing = true;
|
|
|
|
int channelsCapturing = 1;
|
|
|
|
//Start capturing on all devices except master, master will be the last one to start
|
|
for (int buc = 1; buc < channelsPerDevice.Length; buc++)
|
|
{
|
|
var chan = channelsPerDevice[buc];
|
|
|
|
if (chan.Length == 0)
|
|
continue;
|
|
|
|
connectedDevices[buc].Tag = channelsCapturing;
|
|
var err = connectedDevices[buc].StartCapture(Frequency, PreSamples + offset, PostSamples - offset, 0, chan, 24, false);
|
|
|
|
if (err != CaptureError.None)
|
|
{
|
|
StopCapture();
|
|
return err;
|
|
}
|
|
|
|
channelsCapturing++;
|
|
}
|
|
|
|
connectedDevices[0].Tag = 0;
|
|
tempCapture = new UInt128[channelsCapturing][];
|
|
captureFinished = new bool[channelsCapturing];
|
|
tempChannels = channelsPerDevice.Where(c => c.Length > 0).ToArray();
|
|
|
|
var chanMaster = channelsPerDevice[0];
|
|
|
|
var errMaster = connectedDevices[0].StartPatternCapture(Frequency, PreSamples, PostSamples, chanMaster, TriggerChannel, TriggerBitCount, TriggerPattern, Fast);
|
|
|
|
if (errMaster != CaptureError.None)
|
|
{
|
|
StopCapture();
|
|
return errMaster;
|
|
}
|
|
|
|
return CaptureError.None;
|
|
}
|
|
catch { return CaptureError.UnexpectedError; }
|
|
|
|
}
|
|
private byte GetCaptureMode(int[] Channels)
|
|
{
|
|
var split = SplitChannelsPerDevice(Channels);
|
|
var maxChannel = split.Select(c => c.DefaultIfEmpty(0).Max()).DefaultIfEmpty(0).Max();
|
|
return (byte)(maxChannel < 8 ? 0 : (maxChannel < 16 ? 1 : 2));
|
|
}
|
|
private int[][] SplitChannelsPerDevice(int[] Channels)
|
|
{
|
|
List<int[]> channelsPerDevice = new List<int[]>();
|
|
|
|
for (int buc = 0; buc < connectedDevices.Length; buc++)
|
|
{
|
|
int firstChan = buc * 24;
|
|
int lastChan = (buc + 1) * 24;
|
|
|
|
int[] devChan = Channels.Where(c => c >= firstChan && c < lastChan).Select(c => c - firstChan).ToArray();
|
|
channelsPerDevice.Add(devChan);
|
|
}
|
|
|
|
return channelsPerDevice.ToArray();
|
|
}
|
|
public CaptureLimits GetLimits(int[] Channels)
|
|
{
|
|
var mode = GetCaptureMode(Channels);
|
|
return CaptureModes.Modes[mode];
|
|
}
|
|
|
|
public string? GetVoltageStatus()
|
|
{
|
|
return "UNSUPPORTED";
|
|
}
|
|
|
|
private void Dev_CaptureCompleted(object? sender, CaptureEventArgs e)
|
|
{
|
|
lock(locker)
|
|
{
|
|
int idx = (int)((sender as LogicAnalyzerDriver).Tag);
|
|
|
|
tempCapture[idx] = e.Samples;
|
|
captureFinished[idx] = true;
|
|
|
|
if (captureFinished.All(c => c))
|
|
{
|
|
UInt128[] finalSamples = new UInt128[tempCapture[idx].Length];
|
|
|
|
for(int buc = 0; buc < finalSamples.Length; buc++)
|
|
{
|
|
int bitPos = 0;
|
|
|
|
for (int devNum = 0; devNum < tempCapture.Length; devNum++)
|
|
{
|
|
int len = tempChannels[idx].Length;
|
|
|
|
UInt128 devMask = ((UInt128)1 << len) - 1;
|
|
|
|
UInt128 devSample = tempCapture[devNum][buc] & devMask;
|
|
|
|
finalSamples[buc] |= devSample << bitPos;
|
|
bitPos += len;
|
|
}
|
|
}
|
|
|
|
if (currentCaptureHandler != null)
|
|
currentCaptureHandler(new CaptureEventArgs { Samples = finalSamples, ChannelCount = channelCount, TriggerChannel = triggerChannel, PreSamples = preSamples });
|
|
else if (CaptureCompleted != null)
|
|
CaptureCompleted(this, new CaptureEventArgs { Samples = finalSamples, ChannelCount = channelCount, TriggerChannel = triggerChannel, PreSamples = preSamples });
|
|
|
|
capturing = false;
|
|
}
|
|
}
|
|
}
|
|
public bool StopCapture()
|
|
{
|
|
if(!capturing)
|
|
return false;
|
|
|
|
foreach(var dev in connectedDevices)
|
|
dev.StopCapture();
|
|
|
|
capturing = false;
|
|
|
|
return true;
|
|
}
|
|
public void Dispose()
|
|
{
|
|
foreach (var dev in connectedDevices)
|
|
dev.Dispose();
|
|
}
|
|
}
|
|
|
|
public class DeviceConnectionException : Exception
|
|
{
|
|
public DeviceConnectionException(string message) : base(message) { }
|
|
public DeviceConnectionException(string message, Exception innerException) : base(message, innerException) { }
|
|
}
|
|
}
|