mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-23 03:56:28 +00:00
QOL improvements
This commit is contained in:
parent
3918633682
commit
7f96804d3e
|
@ -1,19 +1,9 @@
|
|||
{
|
||||
"AppName": "Avalonia.Designer.HostApp, Version=0.10.16.0, Culture=neutral, PublicKeyToken=c8d484a7012f9a8b",
|
||||
"AppName": "LogicAnalyzer, Version=3.5.0.1, Culture=neutral, PublicKeyToken=null",
|
||||
"WindowSettings": {
|
||||
"LogicAnalyzer.Dialogs.CreateSamplesDialog": {
|
||||
"Width": 800.0,
|
||||
"Height": 600.0,
|
||||
"Position": {
|
||||
"$type": "Avalonia.PixelPoint, Avalonia.Visuals",
|
||||
"X": 0,
|
||||
"Y": 0
|
||||
},
|
||||
"WindowState": 0
|
||||
},
|
||||
"LogicAnalyzer.MainWindow": {
|
||||
"Width": 1024.0,
|
||||
"Height": 800.0,
|
||||
"Width": 1837.0,
|
||||
"Height": 1083.0,
|
||||
"Position": {
|
||||
"$type": "Avalonia.PixelPoint, Avalonia.Visuals",
|
||||
"X": 0,
|
||||
|
@ -22,13 +12,23 @@
|
|||
"WindowState": 0
|
||||
},
|
||||
"LogicAnalyzer.Dialogs.SignalComposerDialog": {
|
||||
"EditorFontSize": 14.0,
|
||||
"Width": 640.0,
|
||||
"Height": 480.0,
|
||||
"EditorFontSize": 19.0,
|
||||
"Width": 973.0,
|
||||
"Height": 415.0,
|
||||
"Position": {
|
||||
"$type": "Avalonia.PixelPoint, Avalonia.Visuals",
|
||||
"X": 0,
|
||||
"Y": 0
|
||||
"X": 1280,
|
||||
"Y": 1016
|
||||
},
|
||||
"WindowState": 0
|
||||
},
|
||||
"LogicAnalyzer.Dialogs.CreateSamplesDialog": {
|
||||
"Width": 800.0,
|
||||
"Height": 600.0,
|
||||
"Position": {
|
||||
"$type": "Avalonia.PixelPoint, Avalonia.Visuals",
|
||||
"X": 1665,
|
||||
"Y": 1233
|
||||
},
|
||||
"WindowState": 0
|
||||
},
|
||||
|
@ -37,8 +37,8 @@
|
|||
"Height": 450.0,
|
||||
"Position": {
|
||||
"$type": "Avalonia.PixelPoint, Avalonia.Visuals",
|
||||
"X": 0,
|
||||
"Y": 0
|
||||
"X": 1629,
|
||||
"Y": 793
|
||||
},
|
||||
"WindowState": 0
|
||||
}
|
||||
|
|
BIN
Software/LogicAnalyzer/Artwork/Logo40.jpg
Normal file
BIN
Software/LogicAnalyzer/Artwork/Logo40.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 278 KiB |
|
@ -6,7 +6,7 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationIcon>window.ico</ApplicationIcon>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.5.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace CLCapture
|
|||
public string? AddressPort { get; set; }
|
||||
[Value(1, Required = true, HelpText = "Desired sampling frequency.")]
|
||||
public int SamplingFrequency { get; set; }
|
||||
[Value(2, Required = true, HelpText = "List of channels to capture (channels sepparated by comma).")]
|
||||
[Value(2, Required = true, HelpText = "List of channels to capture (channels sepparated by comma, can contain a name adding a semicolon after the channel number, no spaces allowed).")]
|
||||
public string? Channels { get; set; }
|
||||
[Value(3, Required = true, HelpText = "Number of samples to capture before the trigger.")]
|
||||
public int PreSamples { get; set; }
|
||||
|
|
49
Software/LogicAnalyzer/CLCapture/CLChannel.cs
Normal file
49
Software/LogicAnalyzer/CLCapture/CLChannel.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CLCapture
|
||||
{
|
||||
public class CLChannel
|
||||
{
|
||||
public CLChannel(string Definition)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(Definition))
|
||||
throw new ArgumentNullException("Missing channel definition.");
|
||||
|
||||
var inputParts = Definition.Trim().Split(":");
|
||||
|
||||
if (inputParts.Length < 1)
|
||||
throw new ArgumentException("Invalid channel definition");
|
||||
|
||||
if (inputParts.Length == 1)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (!int.TryParse(inputParts[0], out value))
|
||||
throw new ArgumentException("Invalid channel definition, channel must be defined in decimal form.");
|
||||
|
||||
ChannelNumber = value;
|
||||
ChannelName = $"Channel {value}";
|
||||
}
|
||||
else if (inputParts.Length == 2)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (!int.TryParse(inputParts[0], out value))
|
||||
throw new ArgumentException("Invalid channel definition, channel must be defined in decimal form.");
|
||||
|
||||
ChannelNumber = value;
|
||||
ChannelName = inputParts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid channel definition, too many parts.");
|
||||
}
|
||||
}
|
||||
public int ChannelNumber { get; set; }
|
||||
public string ChannelName { get; set; }
|
||||
}
|
||||
}
|
|
@ -39,15 +39,27 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int[]? channels = opts.Channels?.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => int.Parse(c)).ToArray();
|
||||
CLChannel[]? channels;
|
||||
|
||||
if (channels == null || channels.Any(c => c < 1 || c > 24))
|
||||
try
|
||||
{
|
||||
|
||||
//int[]? channels = opts.Channels?.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => int.Parse(c)).ToArray();
|
||||
channels = opts.Channels?.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => new CLChannel(c)).ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channels == null || channels.Any(c => c.ChannelNumber < 1 || c.ChannelNumber > 24))
|
||||
{
|
||||
Console.WriteLine("Specified capture channels out of range.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int maxChannel = channels.Max();
|
||||
int maxChannel = channels.Max(c => c.ChannelNumber);
|
||||
int channelMode = maxChannel <= 8 ? 0 : (maxChannel <= 16 ? 1 : 2);
|
||||
|
||||
int channelCount = maxChannel <= 8 ? 8 : (maxChannel <= 16 ? 16 : 24);
|
||||
|
@ -163,13 +175,13 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
|
||||
captureCompletedTask = new TaskCompletionSource<CaptureEventArgs>();
|
||||
|
||||
channels = opts.Channels.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => int.Parse(c) - 1).ToArray();
|
||||
int[] nChannels = channels.Select(c => c.ChannelNumber - 1).ToArray();
|
||||
|
||||
if (opts.Trigger.TriggerType == CLTriggerType.Edge)
|
||||
{
|
||||
Console.WriteLine("Starting edge triggered capture...");
|
||||
var resStart = driver.StartCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples,
|
||||
channels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished);
|
||||
nChannels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished);
|
||||
|
||||
if (resStart != CaptureError.None)
|
||||
{
|
||||
|
@ -209,7 +221,7 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
}
|
||||
|
||||
var resStart = driver.StartPatternCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples,
|
||||
channels, opts.Trigger.Channel - 1, bitCount, triggerPattern, opts.Trigger.TriggerType == CLTriggerType.Fast, CaptureFinished);
|
||||
nChannels, opts.Trigger.Channel - 1, bitCount, triggerPattern, opts.Trigger.TriggerType == CLTriggerType.Fast, CaptureFinished);
|
||||
|
||||
if (resStart != CaptureError.None)
|
||||
{
|
||||
|
@ -246,7 +258,7 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
var file = File.Create(opts.OutputFile);
|
||||
StreamWriter sw = new StreamWriter(file);
|
||||
|
||||
sw.WriteLine(String.Join(',', channels.Select(c => $"Channel {c + 1}").ToArray()));
|
||||
sw.WriteLine(String.Join(',', channels.Select(c => c.ChannelName).ToArray()));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
@ -254,14 +266,14 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
{
|
||||
sb.Clear();
|
||||
|
||||
for (int buc = 0; buc < opts.Channels.Length; buc++)
|
||||
for (int buc = 0; buc < nChannels.Length; buc++)
|
||||
{
|
||||
if ((result.Samples[sample] & ((UInt128)1 << buc)) == 0)
|
||||
if ((result.Samples[sample] & ((UInt128)1 << nChannels[buc])) == 0)
|
||||
sb.Append("0,");
|
||||
else
|
||||
sb.Append("1,");
|
||||
}
|
||||
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
sw.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"profiles": {
|
||||
"CLCapture": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "capture COM3 1000000 1,2,3,4,5,6,7,8 20 20000 TriggerType:Edge,Channel:1,Value:1 ../test.csv"
|
||||
"commandLineArgs": "capture COM9 1000000 1:SDA,2:SDB,3:SDC_A,4:nana,5,6,7,8 20 20000 TriggerType:Edge,Channel:1,Value:0 test.csv"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using LogicAnalyzer.Protocols;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LogicAnalyzer.Classes
|
||||
{
|
||||
public class AnalysisSettings
|
||||
{
|
||||
public ProtocolAnalyzerBase? Analyzer { get; set; }
|
||||
public ProtocolAnalyzerSelectedChannel[]? Channels { get; set; }
|
||||
public ProtocolAnalyzerSettingValue[]? Settings { get; set; }
|
||||
}
|
||||
}
|
|
@ -142,7 +142,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
|
||||
private void LoadSettings(AnalyzerDriverType DriverType)
|
||||
{
|
||||
settingsFile = $"cpSettings{DriverType}.json";
|
||||
settingsFile = WindowExtensions.GetFilePath($"cpSettings{DriverType}.json");
|
||||
|
||||
if (File.Exists(settingsFile))
|
||||
{
|
||||
|
@ -316,7 +316,13 @@ namespace LogicAnalyzer.Dialogs
|
|||
{
|
||||
trigger = (int)nudTriggerBase.Value - 1;
|
||||
|
||||
char[] patternChars = txtPattern.Text.ToArray();
|
||||
if (string.IsNullOrWhiteSpace(txtPattern.Text))
|
||||
{
|
||||
await this.ShowError("Error", "Trigger pattern must be at least one bit long.");
|
||||
return;
|
||||
}
|
||||
|
||||
char[] patternChars = txtPattern.Text.Trim().ToArray();
|
||||
|
||||
if (patternChars.Length == 0)
|
||||
{
|
||||
|
|
|
@ -11,18 +11,32 @@ using System.Threading.Tasks;
|
|||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using static System.Environment;
|
||||
|
||||
namespace LogicAnalyzer.Extensions
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
|
||||
static string BasePath { get { return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; } }
|
||||
|
||||
static JsonSerializerSettings jSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented };
|
||||
|
||||
public static string GetFilePath(string FileName)
|
||||
{
|
||||
string appData = Path.Combine(Environment.GetFolderPath(SpecialFolder.ApplicationData, SpecialFolderOption.DoNotVerify), "LogicAnalyzer");
|
||||
Directory.CreateDirectory(appData);
|
||||
return Path.Combine(appData, FileName);
|
||||
}
|
||||
|
||||
static AppConfig config;
|
||||
static WindowExtensions()
|
||||
{
|
||||
if (File.Exists("AppConfig.json"))
|
||||
config = JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText("AppConfig.json"), jSettings);
|
||||
|
||||
string path = GetFilePath("AppConfig.json");
|
||||
|
||||
if (File.Exists(path))
|
||||
config = JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText(path), jSettings);
|
||||
|
||||
if(config == null)
|
||||
config = new AppConfig();
|
||||
|
@ -132,8 +146,9 @@ namespace LogicAnalyzer.Extensions
|
|||
}
|
||||
private static void PersistSettings()
|
||||
{
|
||||
string path = GetFilePath("AppConfig.json");
|
||||
|
||||
File.WriteAllText("AppConfig.json", JsonConvert.SerializeObject(config, Formatting.Indented, jSettings));
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(config, Formatting.Indented, jSettings));
|
||||
}
|
||||
private static object GetPropertyValue(object Source, string PropertyName)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationIcon>Assets\Ico40.ico</ApplicationIcon>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.5.1.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Windows-Arm64.pubxml</_LastSelectedProfileId>
|
||||
<_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Linux.pubxml</_LastSelectedProfileId>
|
||||
<ActiveDebugProfile>LogicAnalyzer</ActiveDebugProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -3,11 +3,11 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:LogicAnalyzer.Controls"
|
||||
mc:Ignorable="d" d:DesignWidth="1024" d:DesignHeight="800"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
|
||||
x:Class="LogicAnalyzer.MainWindow"
|
||||
Title="LogicAnalyzer - Multiplatform version"
|
||||
Icon="/Assets/Ico40.ico"
|
||||
Background="#383838" MinWidth="1024" MinHeight="800" Width="1024" Height="800" WindowStartupLocation="CenterScreen">
|
||||
Background="#383838" MinWidth="800" MinHeight="600" Width="800" Height="600" WindowStartupLocation="CenterScreen">
|
||||
<DockPanel VerticalAlignment="Stretch">
|
||||
<Menu DockPanel.Dock="Top" Background="#f0202020">
|
||||
<MenuItem Header="_File">
|
||||
|
@ -47,7 +47,7 @@
|
|||
<controls:SampleMarker Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Foreground="White" Background="Transparent" Name="sampleMarker"></controls:SampleMarker>
|
||||
</Grid>
|
||||
|
||||
<ScrollBar VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Orientation="Horizontal" DockPanel.Dock="Bottom" Name="scrSamplePos"></ScrollBar>
|
||||
<ScrollBar VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Orientation="Horizontal" DockPanel.Dock="Bottom" Name="scrSamplePos" AllowAutoHide="False"></ScrollBar>
|
||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ColumnDefinitions="*,240" DockPanel.Dock="Bottom">
|
||||
<ScrollViewer VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Grid ColumnDefinitions="140,*" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
|
|
|
@ -35,6 +35,12 @@ namespace LogicAnalyzer
|
|||
|
||||
UInt128[]? copiedSamples;
|
||||
|
||||
MenuItem? mnuRepeatAnalysis;
|
||||
|
||||
AnalysisSettings? analysisSettings;
|
||||
|
||||
bool preserveSamples = false;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
Instance = this;
|
||||
|
@ -558,7 +564,10 @@ namespace LogicAnalyzer
|
|||
sampleViewer.Samples = e.Samples;
|
||||
sampleViewer.PreSamples = e.PreSamples;
|
||||
sampleViewer.ChannelCount = e.ChannelCount;
|
||||
sampleViewer.SamplesInScreen = Math.Min(100, e.Samples.Length / 10);
|
||||
|
||||
if(!preserveSamples)
|
||||
sampleViewer.SamplesInScreen = Math.Min(100, e.Samples.Length / 10);
|
||||
|
||||
sampleViewer.FirstSample = Math.Max(e.PreSamples - 10, 0);
|
||||
sampleViewer.ClearRegions();
|
||||
sampleViewer.ClearAnalyzedChannels();
|
||||
|
@ -613,14 +622,43 @@ namespace LogicAnalyzer
|
|||
return itm;
|
||||
}).ToArray());
|
||||
|
||||
mnuRepeatAnalysis = new MenuItem { Header = "Repeat last analysis" };
|
||||
mnuRepeatAnalysis.IsEnabled = false;
|
||||
mnuRepeatAnalysis.Click += MnuRepeatAnalysis_Click;
|
||||
finalItems.Add(mnuRepeatAnalysis);
|
||||
|
||||
var clearItem = new MenuItem { Header = "C_lear analysis data" };
|
||||
clearItem.Click += ClearItem_Click;
|
||||
finalItems.Add(clearItem);
|
||||
|
||||
|
||||
|
||||
mnuProtocols.Items = finalItems;
|
||||
}
|
||||
}
|
||||
|
||||
private void MnuRepeatAnalysis_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
if (analysisSettings == null || analysisSettings.Channels == null || analysisSettings.Analyzer == null || analysisSettings.Settings == null)
|
||||
return;
|
||||
|
||||
var channels = analysisSettings.Channels;
|
||||
var samples = sampleViewer.Samples;
|
||||
|
||||
foreach (var channel in channels)
|
||||
ExtractSamples(channel, samples);
|
||||
|
||||
var analysisResult = analysisSettings.Analyzer.Analyze(settings.Frequency, settings.PreTriggerSamples - 1, analysisSettings.Settings, channels);
|
||||
|
||||
if (analysisResult != null)
|
||||
{
|
||||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.AddAnalyzedChannels(analysisResult);
|
||||
sampleViewer.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearItem_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
sampleViewer.BeginUpdate();
|
||||
|
@ -662,6 +700,11 @@ namespace LogicAnalyzer
|
|||
sampleViewer.AddAnalyzedChannels(analysisResult);
|
||||
sampleViewer.EndUpdate();
|
||||
}
|
||||
|
||||
analysisSettings = new AnalysisSettings { Analyzer = analyzer, Channels = channels, Settings = dlg.SelectedSettings };
|
||||
|
||||
if(mnuRepeatAnalysis != null)
|
||||
mnuRepeatAnalysis.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -762,7 +805,7 @@ namespace LogicAnalyzer
|
|||
await this.ShowError("Error", "No capture to repeat");
|
||||
return;
|
||||
}
|
||||
|
||||
preserveSamples = true;
|
||||
BeginCapture();
|
||||
}
|
||||
|
||||
|
@ -775,6 +818,7 @@ namespace LogicAnalyzer
|
|||
return;
|
||||
|
||||
settings = dialog.SelectedSettings;
|
||||
preserveSamples = false;
|
||||
BeginCapture();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"profiles": {
|
||||
"LogicAnalyzer": {
|
||||
"commandName": "Project"
|
||||
},
|
||||
"WSL": {
|
||||
"commandName": "WSL2",
|
||||
"distributionName": ""
|
||||
}
|
||||
}
|
||||
}
|
BIN
Wiki artwork/LogoPage.jpg
Normal file
BIN
Wiki artwork/LogoPage.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 405 KiB |
BIN
Wiki artwork/LogoPage.psd
Normal file
BIN
Wiki artwork/LogoPage.psd
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user