mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-23 12:06:27 +00:00
Updated analyzers
This commit is contained in:
parent
40a9b788da
commit
3765865c50
|
@ -5,12 +5,6 @@ cmake_minimum_required(VERSION 3.13)
|
|||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# set(PICO_BOARD pico_w)
|
||||
|
||||
# Initialise pico_sdk from installed location
|
||||
# (note this can come from environment, CMake cache etc)
|
||||
set(PICO_SDK_PATH "F:/PicoSDK/Pico/pico-sdk")
|
||||
|
||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
|
@ -42,7 +36,7 @@ pico_enable_stdio_usb(LogicAnalyzer 1)
|
|||
# Regular pico: empty
|
||||
# Pico W without WiFi support: pico_cyw43_arch_none
|
||||
# Pico W with WiFi support: pico_cyw43_arch_lwip_poll
|
||||
# set (CYW_LIB pico_cyw43_arch_lwip_poll)
|
||||
set (CYW_LIB pico_cyw43_arch_lwip_poll)
|
||||
# set (CYW_LIB pico_cyw43_arch_none)
|
||||
|
||||
# Add any user requested libraries
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#define FIRMWARE_VERSION "V5_1"
|
||||
|
||||
//Select the board type to build the firmware for
|
||||
#define BUILD_PICO
|
||||
//#define BUILD_PICO
|
||||
//#define BUILD_PICO_W
|
||||
//#define BUILD_PICO_W_WIFI
|
||||
#define BUILD_PICO_W_WIFI
|
||||
//#define BUILD_ZERO
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerialProtocolAnalyzer", "S
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "I2CProtocolAnalyzer", "I2CProtocolAnalyzer\I2CProtocolAnalyzer.csproj", "{74E41F50-E208-4690-84C6-51012C2F26E2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalDescriptionLanguage", "SignalDescriptionLanguage\SignalDescriptionLanguage.csproj", "{BD4731B1-B7CE-49C9-9982-77FA9B95C19F}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SignalDescriptionLanguage", "SignalDescriptionLanguage\SignalDescriptionLanguage.csproj", "{BD4731B1-B7CE-49C9-9982-77FA9B95C19F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelProtocolAnalyzer", "ParallelProtocolAnalyzer\ParallelProtocolAnalyzer.csproj", "{952FD20C-7C12-407B-A264-BA5F429BDD3C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -51,6 +53,10 @@ Global
|
|||
{BD4731B1-B7CE-49C9-9982-77FA9B95C19F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BD4731B1-B7CE-49C9-9982-77FA9B95C19F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BD4731B1-B7CE-49C9-9982-77FA9B95C19F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{952FD20C-7C12-407B-A264-BA5F429BDD3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{952FD20C-7C12-407B-A264-BA5F429BDD3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{952FD20C-7C12-407B-A264-BA5F429BDD3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{952FD20C-7C12-407B-A264-BA5F429BDD3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -6,6 +6,7 @@ using Avalonia.Media;
|
|||
using Avalonia.Threading;
|
||||
using LogicAnalyzer.Classes;
|
||||
using LogicAnalyzer.Dialogs;
|
||||
using LogicAnalyzer.Protocols;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
@ -62,6 +63,7 @@ namespace LogicAnalyzer.Controls
|
|||
|
||||
|
||||
List<SampleRegion> regions = new List<SampleRegion>();
|
||||
List<ProtocolAnalyzedChannel> analysisData = new List<ProtocolAnalyzedChannel>();
|
||||
|
||||
SelectedSamples? selectedSamples = null;
|
||||
SampleRegion? selectedRegion = null;
|
||||
|
@ -69,6 +71,7 @@ namespace LogicAnalyzer.Controls
|
|||
int? userMarker = null;
|
||||
int mnuSample = 0;
|
||||
bool samplesCopied = false;
|
||||
bool updating = false;
|
||||
|
||||
public SampleMarker()
|
||||
{
|
||||
|
@ -163,6 +166,37 @@ namespace LogicAnalyzer.Controls
|
|||
}
|
||||
}
|
||||
|
||||
public void BeginUpdate()
|
||||
{
|
||||
updating = true;
|
||||
}
|
||||
|
||||
public void EndUpdate()
|
||||
{
|
||||
updating = false;
|
||||
InvalidateVisual();
|
||||
}
|
||||
public void AddAnalyzedChannel(ProtocolAnalyzedChannel Data)
|
||||
{
|
||||
analysisData.Add(Data);
|
||||
}
|
||||
public void AddAnalyzedChannels(IEnumerable<ProtocolAnalyzedChannel> Data)
|
||||
{
|
||||
analysisData.AddRange(Data);
|
||||
}
|
||||
public bool RemoveAnalyzedChannel(ProtocolAnalyzedChannel Data)
|
||||
{
|
||||
return analysisData.Remove(Data);
|
||||
}
|
||||
|
||||
public void ClearAnalyzedChannels()
|
||||
{
|
||||
foreach (var data in analysisData)
|
||||
data.Dispose();
|
||||
|
||||
analysisData.Clear();
|
||||
}
|
||||
|
||||
public void AddRegion(SampleRegion Region)
|
||||
{
|
||||
regions.Add(Region);
|
||||
|
@ -202,7 +236,16 @@ namespace LogicAnalyzer.Controls
|
|||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
context.FillRectangle(Background, new Rect(0, 0, Bounds.Width, Bounds.Height));
|
||||
|
||||
var bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
|
||||
|
||||
using (context.PushClip(bounds))
|
||||
{
|
||||
|
||||
if(updating)
|
||||
return;
|
||||
|
||||
context.FillRectangle(Background, bounds);
|
||||
|
||||
if (VisibleSamples == 0)
|
||||
return;
|
||||
|
@ -256,7 +299,7 @@ namespace LogicAnalyzer.Controls
|
|||
|
||||
if (increment == 1)
|
||||
{
|
||||
x = buc * sampleWidth +halfWidth;
|
||||
x = buc * sampleWidth + halfWidth;
|
||||
y1 = halfHeight * 1.75f;
|
||||
|
||||
context.DrawLine(GraphicObjectsCache.GetPen(Foreground, 1), new Point(x, y1), new Point(x, y2));
|
||||
|
@ -265,8 +308,26 @@ namespace LogicAnalyzer.Controls
|
|||
|
||||
}
|
||||
|
||||
if (analysisData.Count > 0)
|
||||
{
|
||||
foreach (var chan in analysisData)
|
||||
{
|
||||
foreach (var evt in chan.Segments)
|
||||
{
|
||||
double x1 = (evt.FirstSample - FirstSample) * sampleWidth;
|
||||
double x2 = (evt.LastSample + 1 - FirstSample) * sampleWidth;
|
||||
double y1 = 0;
|
||||
double y2 = this.Bounds.Height;
|
||||
|
||||
Rect r = new Rect(new Point(x1, y1), new Point(x2, y2));
|
||||
context.FillRectangle(GraphicObjectsCache.GetBrush(chan.BackColor), r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.Render(context);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using Avalonia.Controls;
|
|||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using LogicAnalyzer.Classes;
|
||||
using LogicAnalyzer.Extensions;
|
||||
using LogicAnalyzer.Protocols;
|
||||
using System;
|
||||
|
@ -19,6 +20,9 @@ namespace LogicAnalyzer.Dialogs
|
|||
ProtocolAnalyzerBase analyzer;
|
||||
public ProtocolAnalyzerBase Analyzer { get { return analyzer; } set { analyzer = value; LoadControls(); } }
|
||||
|
||||
AnalysisSettings? initialSettings;
|
||||
public AnalysisSettings? InitialSettings { get { return initialSettings; } set { initialSettings = value; LoadControls(); } }
|
||||
|
||||
Channel[] channels;
|
||||
public Channel[] Channels { get { return channels; } set { channels = value; LoadControls(); } }
|
||||
|
||||
|
@ -60,10 +64,18 @@ namespace LogicAnalyzer.Dialogs
|
|||
{
|
||||
var signal = signals[buc];
|
||||
|
||||
pnlControls.Children.Add(new TextBlock{ IsVisible = true, Name = $"Label_Signal{buc}", Text = $"Channel for signal { signal.SignalName }:" });
|
||||
pnlControls.Children.Add(new TextBlock{ IsVisible = true, Name = $"Label_Signal{buc}", Text = signal.IsBus ? $"First channel of bus {signal.SignalName}" : $"Channel for signal { signal.SignalName }:" });
|
||||
|
||||
var list = new ComboBox { IsVisible = true, Name = $"List_Signal{buc}", Items = channelsSource.ToArray(), HorizontalAlignment=Avalonia.Layout.HorizontalAlignment.Stretch, Margin= new Thickness(0,10,20,0) };
|
||||
|
||||
if (initialSettings != null)
|
||||
{
|
||||
var chan = initialSettings.Channels?.FirstOrDefault(c => c.SignalName == signal.SignalName && c.BusIndex == 0);
|
||||
|
||||
if(chan != null)
|
||||
list.SelectedIndex = chan.ChannelIndex + 1;
|
||||
}
|
||||
|
||||
pnlControls.Children.Add(list);
|
||||
|
||||
list.SelectionChanged += SignalChannel_SelectedIndexChanged;
|
||||
|
@ -87,13 +99,32 @@ namespace LogicAnalyzer.Dialogs
|
|||
case ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Boolean:
|
||||
|
||||
var ck = new CheckBox { IsVisible = true, Name = $"Check_Index{buc}", Content = set.CheckCaption, Margin = new Thickness(0, 10, 20, 0) };
|
||||
|
||||
if (initialSettings != null)
|
||||
{
|
||||
var setV = initialSettings.Settings?.FirstOrDefault(s => s.SettingIndex == buc);
|
||||
|
||||
if(setV != null)
|
||||
ck.IsChecked = (bool)(setV.Value ?? false);
|
||||
}
|
||||
|
||||
pnlControls.Children.Add(ck);
|
||||
|
||||
ck.Checked += BooleanSetting_CheckedChanged;
|
||||
break;
|
||||
|
||||
case ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer:
|
||||
|
||||
var nud = new NumericUpDown { IsVisible = true, Name = $"Numeric_Index{buc}", Minimum = set.IntegerMinimumValue, Maximum = set.IntegerMaximumValue, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, Margin = new Thickness(0, 10, 20, 0) };
|
||||
var nud = new NumericUpDown { IsVisible = true, Name = $"Numeric_Index{buc}", Minimum = set.IntegerMinimumValue, Maximum = set.IntegerMaximumValue, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, Margin = new Thickness(0, 10, 20, 0), Value = set.IntegerMinimumValue };
|
||||
|
||||
if (initialSettings != null)
|
||||
{
|
||||
var setV = initialSettings.Settings?.FirstOrDefault(s => s.SettingIndex == buc);
|
||||
|
||||
if (setV != null)
|
||||
nud.Value = (int)(setV.Value ?? 0);
|
||||
}
|
||||
|
||||
pnlControls.Children.Add(nud);
|
||||
nud.ValueChanged += IntegerSetting_ValueChanged;
|
||||
break;
|
||||
|
@ -101,6 +132,15 @@ namespace LogicAnalyzer.Dialogs
|
|||
case ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List:
|
||||
|
||||
var list = new ComboBox { IsVisible = true, Name = $"List_Index{buc}", Items = set.ListValues, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, Margin = new Thickness(0, 10, 20, 0) };
|
||||
|
||||
if (initialSettings != null)
|
||||
{
|
||||
var setV = initialSettings.Settings?.FirstOrDefault(s => s.SettingIndex == buc);
|
||||
|
||||
if (setV != null)
|
||||
list.SelectedIndex = Array.IndexOf(set.ListValues, setV.Value);
|
||||
}
|
||||
|
||||
pnlControls.Children.Add(list);
|
||||
list.SelectionChanged += ListSetting_SelectedIndexChanged;
|
||||
break;
|
||||
|
@ -112,6 +152,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
}
|
||||
}
|
||||
|
||||
ValidateSettings();
|
||||
}
|
||||
|
||||
private void ListSetting_SelectedIndexChanged(object? sender, RoutedEventArgs e)
|
||||
|
@ -137,9 +178,16 @@ namespace LogicAnalyzer.Dialogs
|
|||
void ValidateSettings()
|
||||
{
|
||||
var st = ComposeSettings();
|
||||
var ch = ComposeChannels();
|
||||
|
||||
if (st == null || ch == null)
|
||||
if (st == null)
|
||||
{
|
||||
btnAccept.IsEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var ch = ComposeChannels(st);
|
||||
|
||||
if (ch == null)
|
||||
{
|
||||
btnAccept.IsEnabled = false;
|
||||
return;
|
||||
|
@ -221,7 +269,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
return settingsValues.ToArray();
|
||||
}
|
||||
|
||||
ProtocolAnalyzerSelectedChannel[]? ComposeChannels()
|
||||
ProtocolAnalyzerSelectedChannel[]? ComposeChannels(ProtocolAnalyzerSettingValue[] values)
|
||||
{
|
||||
if (analyzer == null || channels == null)
|
||||
return null;
|
||||
|
@ -240,12 +288,38 @@ namespace LogicAnalyzer.Dialogs
|
|||
if (list.SelectedIndex == -1)
|
||||
continue;
|
||||
|
||||
var size = signal.IsBus ? analyzer.GetBusWidth(signal, values) : 1;
|
||||
|
||||
if (size == 0)
|
||||
continue;
|
||||
|
||||
int idx = list.SelectedIndex - 1;
|
||||
|
||||
if (idx + size > channels.Length)
|
||||
return null;
|
||||
|
||||
if (size == 1)
|
||||
{
|
||||
|
||||
selectedChannels.Add(new ProtocolAnalyzerSelectedChannel
|
||||
{
|
||||
ChannelIndex = list.SelectedIndex - 1,
|
||||
ChannelIndex = idx,
|
||||
SignalName = signal.SignalName
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int bucS = 0; bucS < size; bucS++)
|
||||
{
|
||||
selectedChannels.Add(new ProtocolAnalyzerSelectedChannel
|
||||
{
|
||||
ChannelIndex = idx + bucS,
|
||||
SignalName = signal.SignalName,
|
||||
BusIndex = bucS
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedChannels.ToArray();
|
||||
}
|
||||
|
@ -258,7 +332,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
private void btnAccept_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectedSettings = ComposeSettings();
|
||||
SelectedChannels = ComposeChannels();
|
||||
SelectedChannels = ComposeChannels(SelectedSettings);
|
||||
this.Close(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -366,6 +366,7 @@ namespace LogicAnalyzer
|
|||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
sampleMarker.ClearAnalyzedChannels();
|
||||
|
||||
scrSamplePos.Maximum = samples.Length - 1;
|
||||
scrSamplePos.Value = sampleViewer.FirstSample;
|
||||
|
@ -592,6 +593,7 @@ namespace LogicAnalyzer
|
|||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
sampleMarker.ClearAnalyzedChannels();
|
||||
|
||||
if (finalRegions.Count > 0)
|
||||
sampleMarker.AddRegions(finalRegions);
|
||||
|
@ -766,6 +768,7 @@ namespace LogicAnalyzer
|
|||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
sampleMarker.ClearAnalyzedChannels();
|
||||
|
||||
btnCapture.IsEnabled = true;
|
||||
btnRepeat.IsEnabled = true;
|
||||
|
@ -852,6 +855,9 @@ namespace LogicAnalyzer
|
|||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.AddAnalyzedChannels(analysisResult);
|
||||
sampleViewer.EndUpdate();
|
||||
sampleMarker.BeginUpdate();
|
||||
sampleMarker.AddAnalyzedChannels(analysisResult);
|
||||
sampleMarker.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -860,6 +866,9 @@ namespace LogicAnalyzer
|
|||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.ClearAnalyzedChannels();
|
||||
sampleViewer.EndUpdate();
|
||||
sampleMarker.BeginUpdate();
|
||||
sampleMarker.ClearAnalyzedChannels();
|
||||
sampleMarker.EndUpdate();
|
||||
}
|
||||
|
||||
private async void ProtocolAnalyzer_Click(object? sender, RoutedEventArgs e)
|
||||
|
@ -873,6 +882,10 @@ namespace LogicAnalyzer
|
|||
|
||||
var dlg = new ProtocolAnalyzerSettingsDialog();
|
||||
{
|
||||
|
||||
if (analysisSettings != null && analysisSettings.Analyzer == analyzer)
|
||||
dlg.InitialSettings = analysisSettings;
|
||||
|
||||
dlg.Analyzer = analyzer;
|
||||
dlg.Channels = channelViewer.Channels.Select(c =>
|
||||
{
|
||||
|
@ -907,6 +920,10 @@ namespace LogicAnalyzer
|
|||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.AddAnalyzedChannels(analysisResult);
|
||||
sampleViewer.EndUpdate();
|
||||
|
||||
sampleMarker.BeginUpdate();
|
||||
sampleMarker.AddAnalyzedChannels(analysisResult);
|
||||
sampleMarker.EndUpdate();
|
||||
}
|
||||
|
||||
analysisSettings = new AnalysisSettings { Analyzer = analyzer, Channels = channels, Settings = dlg.SelectedSettings };
|
||||
|
@ -1296,6 +1313,7 @@ namespace LogicAnalyzer
|
|||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
sampleMarker.ClearAnalyzedChannels();
|
||||
|
||||
if (ex.SelectedRegions != null)
|
||||
sampleMarker.AddRegions(ex.SelectedRegions);
|
||||
|
|
|
@ -73,6 +73,10 @@ namespace LogicAnalyzer.Protocols
|
|||
public string SignalName { get; set; }
|
||||
//If true the signal must be provided, else the signal is optional
|
||||
public bool Required { get; set; }
|
||||
/// <summary>
|
||||
/// If true the signal is a bus and the size will be requested to the protocol analyzer
|
||||
/// </summary>
|
||||
public bool IsBus { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,6 +86,8 @@ namespace LogicAnalyzer.Protocols
|
|||
{
|
||||
//Signal name for which the channel was selected
|
||||
public string SignalName { get; set; }
|
||||
//Index (for buses)
|
||||
public int BusIndex { get; set; }
|
||||
//Channel index in the channel viewer
|
||||
public int ChannelIndex { get; set; }
|
||||
//List of samples
|
||||
|
|
|
@ -35,6 +35,15 @@ namespace LogicAnalyzer.Protocols
|
|||
/// <returns>An array of analyzed channels</returns>
|
||||
public abstract ProtocolAnalyzedChannel[] Analyze(int SamplingRate, int TriggerSample, ProtocolAnalyzerSettingValue[] SelectedSettings, ProtocolAnalyzerSelectedChannel[] SelectedChannels);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Informs the analyzer of the size of a bus. By default returns 0 (bus not used).
|
||||
/// </summary>
|
||||
/// <param name="Signal">The bus to get the size for</param>
|
||||
/// <param name="SelectedSettings">The settings the user selected</param>
|
||||
/// <returns>The size of the bus</returns>
|
||||
public virtual int GetBusWidth(ProtocolAnalyzerSignal Signal, ProtocolAnalyzerSettingValue[] SelectedSettings)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace LogicAnalyzer.Protocols
|
|||
|
||||
public override void RenderSegment(ProtocolAnalyzedChannel Channel, ProtocolAnalyzerDataSegment Segment, DrawingContext G, Rect RenderArea)
|
||||
{
|
||||
FormattedText text = new FormattedText(Segment.Value, segmentFont, 12, TextAlignment.Center, TextWrapping.NoWrap, Size.Infinity);
|
||||
FormattedText text = new FormattedText(Segment.Value, segmentFont, 12, TextAlignment.Left, TextWrapping.NoWrap, Size.Infinity);
|
||||
|
||||
double midY = RenderArea.Y + (RenderArea.Height / 2.0);
|
||||
double rectHeight = text.Bounds.Height + 10;
|
||||
|
@ -26,9 +26,6 @@ namespace LogicAnalyzer.Protocols
|
|||
double bottomY = midY + (rectHeight / 2.0);
|
||||
double minWidth = text.Bounds.Width + 10.0;
|
||||
|
||||
if (RenderArea.Width < minWidth)
|
||||
return;
|
||||
|
||||
PathFigure container = new PathFigure();
|
||||
container.StartPoint = new Point(RenderArea.X, midY);
|
||||
container.Segments.Add(new LineSegment { Point = new Point(RenderArea.X + 5, topY) });
|
||||
|
@ -42,11 +39,11 @@ namespace LogicAnalyzer.Protocols
|
|||
PathGeometry gContainer = new PathGeometry();
|
||||
gContainer.Figures.Add(container);
|
||||
|
||||
//G.FillRectangle(GraphicObjectsCache.GetBrush(Channel.BackColor), RenderArea);
|
||||
//G.DrawRectangle(GraphicObjectsCache.GetPen(Channel.ForeColor, 1), RenderArea);
|
||||
|
||||
G.DrawGeometry(GraphicObjectsCache.GetBrush(Channel.BackColor), GraphicObjectsCache.GetPen(Channel.ForeColor, 1), gContainer);
|
||||
|
||||
if (RenderArea.Width < minWidth)
|
||||
return;
|
||||
|
||||
G.DrawText(GraphicObjectsCache.GetBrush(Channel.ForeColor), new Point(RenderArea.X + (RenderArea.Width / 2 - text.Bounds.Width / 2), RenderArea.Y + (RenderArea.Height / 2 - text.Bounds.Height / 2)), text);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
using Avalonia.Media;
|
||||
using AvaloniaEdit.Document;
|
||||
using LogicAnalyzer.Controls;
|
||||
using LogicAnalyzer.Protocols;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ParallelProtocolAnalyzer
|
||||
{
|
||||
public class ParallelAnalyzer : ProtocolAnalyzerBase
|
||||
{
|
||||
private SimpleSegmentRenderer renderer = new SimpleSegmentRenderer();
|
||||
|
||||
const string CS_SIGNAL_NAME = "CS";
|
||||
const string RD_SIGNAL_NAME = "RD";
|
||||
const string WR_SIGNAL_NAME = "WR";
|
||||
const string DATA_SIGNAL_NAME = "Data";
|
||||
const string ADDR_SIGNAL_NAME = "Address";
|
||||
const string RISING_EDGE = "Rising";
|
||||
const string FALLING_EDGE = "Falling";
|
||||
const string READ_OP = "Read";
|
||||
const string WRITE_OP = "Write";
|
||||
public override string ProtocolName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Parallel";
|
||||
}
|
||||
}
|
||||
|
||||
static ProtocolAnalyzerSetting[] settings = new ProtocolAnalyzerSetting[]
|
||||
{
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||
Caption = "CS edge",
|
||||
ListValues = new string[]{ RISING_EDGE, FALLING_EDGE }
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||
Caption = "RD edge",
|
||||
ListValues = new string[]{ RISING_EDGE, FALLING_EDGE }
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||
Caption = "WR edge",
|
||||
ListValues = new string[]{ RISING_EDGE, FALLING_EDGE }
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer,
|
||||
Caption = "Read offset (in samples)",
|
||||
IntegerMinimumValue = 0,
|
||||
IntegerMaximumValue = 32
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer,
|
||||
Caption = "Write offset (in samples)",
|
||||
IntegerMinimumValue = 0,
|
||||
IntegerMaximumValue = 32
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer,
|
||||
Caption = "Data width",
|
||||
IntegerMinimumValue = 4,
|
||||
IntegerMaximumValue = 32
|
||||
},
|
||||
new ProtocolAnalyzerSetting
|
||||
{
|
||||
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer,
|
||||
Caption = "Address width",
|
||||
IntegerMinimumValue = 0,
|
||||
IntegerMaximumValue = 32
|
||||
}
|
||||
};
|
||||
|
||||
public override ProtocolAnalyzerSetting[] Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolAnalyzerSignal[] signals = new ProtocolAnalyzerSignal[]
|
||||
{
|
||||
new ProtocolAnalyzerSignal
|
||||
{
|
||||
SignalName = CS_SIGNAL_NAME,
|
||||
Required = false
|
||||
},
|
||||
new ProtocolAnalyzerSignal
|
||||
{
|
||||
SignalName = RD_SIGNAL_NAME,
|
||||
Required = false
|
||||
},
|
||||
new ProtocolAnalyzerSignal
|
||||
{
|
||||
SignalName = WR_SIGNAL_NAME,
|
||||
Required = false
|
||||
},
|
||||
new ProtocolAnalyzerSignal
|
||||
{
|
||||
SignalName = DATA_SIGNAL_NAME,
|
||||
Required = true,
|
||||
IsBus = true
|
||||
},
|
||||
new ProtocolAnalyzerSignal
|
||||
{
|
||||
SignalName = ADDR_SIGNAL_NAME,
|
||||
Required = false,
|
||||
IsBus = true
|
||||
},
|
||||
};
|
||||
|
||||
public override ProtocolAnalyzerSignal[] Signals
|
||||
{
|
||||
get
|
||||
{
|
||||
return signals;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetBusWidth(ProtocolAnalyzerSignal Signal, ProtocolAnalyzerSettingValue[] SelectedSettings)
|
||||
{
|
||||
if (Signal.SignalName == DATA_SIGNAL_NAME)
|
||||
return (int)SelectedSettings[5].Value;
|
||||
|
||||
if(Signal.SignalName == ADDR_SIGNAL_NAME)
|
||||
return (int)SelectedSettings[6].Value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override ProtocolAnalyzedChannel[] Analyze(int SamplingRate, int TriggerSample, ProtocolAnalyzerSettingValue[] SelectedSettings, ProtocolAnalyzerSelectedChannel[] SelectedChannels)
|
||||
{
|
||||
|
||||
/*
|
||||
* The protocol analysis can work in two ways:
|
||||
* 1-The CS signal is provided, this is used as the sampling trigger, RD/WR signals will determine
|
||||
* if the OP is read or write, if none of these are provided then the operation is undetermined.
|
||||
*
|
||||
* 2-The CS signal is not provided, then the RD and/or WR signals will be used as trigger
|
||||
*/
|
||||
|
||||
bool csTrigger = false;
|
||||
bool useRD = false;
|
||||
bool useWR = false;
|
||||
|
||||
//Check which trigger signals are used
|
||||
csTrigger = SelectedChannels.Any(c => c.SignalName == CS_SIGNAL_NAME);
|
||||
useRD = SelectedChannels.Any(c => c.SignalName == RD_SIGNAL_NAME);
|
||||
useWR = SelectedChannels.Any(c => c.SignalName == WR_SIGNAL_NAME);
|
||||
|
||||
int csEdge = 0;
|
||||
int rdEdge = 0;
|
||||
int wrEdge = 0;
|
||||
|
||||
//Obtain the edges
|
||||
if (csTrigger && SelectedSettings[0].Value?.ToString() == RISING_EDGE)
|
||||
csEdge = 1;
|
||||
|
||||
if(useRD && SelectedSettings[1].Value?.ToString() == RISING_EDGE)
|
||||
rdEdge = 1;
|
||||
|
||||
if(useWR && SelectedSettings[2].Value?.ToString() == RISING_EDGE)
|
||||
wrEdge = 1;
|
||||
|
||||
//Get the sampling offsets
|
||||
int readOffset = (int)SelectedSettings[3].Value;
|
||||
int writeOffset = (int)SelectedSettings[4].Value;
|
||||
|
||||
//Compose the control channels
|
||||
List<ControlChannel> controls = new List<ControlChannel>();
|
||||
|
||||
if (csTrigger)
|
||||
controls.Add(new ControlChannel { Edge = (byte)csEdge, Samples = SelectedChannels.First(c => c.SignalName == CS_SIGNAL_NAME).Samples, SignalName = CS_SIGNAL_NAME });
|
||||
|
||||
if(useRD)
|
||||
controls.Add(new ControlChannel { Edge = (byte)rdEdge, Samples = SelectedChannels.First(c => c.SignalName == RD_SIGNAL_NAME).Samples, SignalName = RD_SIGNAL_NAME });
|
||||
|
||||
if(useWR)
|
||||
controls.Add(new ControlChannel { Edge = (byte)wrEdge, Samples = SelectedChannels.First(c => c.SignalName == WR_SIGNAL_NAME).Samples, SignalName = WR_SIGNAL_NAME });
|
||||
|
||||
//Compose the data channels
|
||||
byte[][] dataBits = SelectedChannels.Where(c => c.SignalName == DATA_SIGNAL_NAME).OrderBy(c => c.BusIndex).Select(c => c.Samples).ToArray();
|
||||
|
||||
//Compose the address channels
|
||||
byte[][] addressBits = SelectedChannels.Where(c => c.SignalName == ADDR_SIGNAL_NAME).OrderBy(c => c.BusIndex).Select(c => c.Samples).ToArray();
|
||||
|
||||
//Find all ops
|
||||
List<OpData> foundOps = new List<OpData>();
|
||||
int offset = 0;
|
||||
|
||||
OpData? next = FindNextOp(controls, dataBits, addressBits, readOffset, writeOffset, ref offset);
|
||||
|
||||
while (next != null)
|
||||
{
|
||||
foundOps.Add(next);
|
||||
next = FindNextOp(controls, dataBits, addressBits, readOffset, writeOffset, ref offset);
|
||||
}
|
||||
|
||||
//Compose all the data segments
|
||||
var segments = foundOps.Select(o => ComposeSegment(o, addressBits.Length, dataBits.Length));
|
||||
|
||||
List<ProtocolAnalyzedChannel> results = new List<ProtocolAnalyzedChannel>();
|
||||
|
||||
//If we are using a CS trigger...
|
||||
if (csTrigger)
|
||||
{
|
||||
var csChannel = SelectedChannels.First(c => c.SignalName == CS_SIGNAL_NAME);
|
||||
|
||||
//All the operations are shown in the CS channel
|
||||
ProtocolAnalyzedChannel csChannelData = new ProtocolAnalyzedChannel(csChannel.SignalName, csChannel.ChannelIndex, renderer, segments.ToArray(), Colors.White, Color.FromArgb(100, Colors.Blue.R, Colors.Blue.G, Colors.Blue.B));
|
||||
|
||||
results.Add(csChannelData);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (useRD)
|
||||
{
|
||||
var rdChannel = SelectedChannels.First(c => c.SignalName == RD_SIGNAL_NAME);
|
||||
|
||||
//Show read ops in RD channel
|
||||
ProtocolAnalyzedChannel csChannelData = new ProtocolAnalyzedChannel(rdChannel.SignalName, rdChannel.ChannelIndex, renderer, segments.Where(s => s.Value.Contains(READ_OP)).ToArray(), Colors.White, Color.FromArgb(100, Colors.Green.R, Colors.Green.G, Colors.Green.B));
|
||||
|
||||
results.Add(csChannelData);
|
||||
}
|
||||
|
||||
if (useWR)
|
||||
{
|
||||
var wrChannel = SelectedChannels.First(c => c.SignalName == WR_SIGNAL_NAME);
|
||||
|
||||
//Show read ops in RD channel
|
||||
ProtocolAnalyzedChannel csChannelData = new ProtocolAnalyzedChannel(wrChannel.SignalName, wrChannel.ChannelIndex, renderer, segments.Where(s => s.Value.Contains(WRITE_OP)).ToArray(), Colors.White, Color.FromArgb(100, Colors.Red.R, Colors.Red.G, Colors.Red.B));
|
||||
|
||||
results.Add(csChannelData);
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
|
||||
}
|
||||
|
||||
private ProtocolAnalyzerDataSegment ComposeSegment(OpData o, int AddressBits, int DataBits)
|
||||
{
|
||||
int addressNibbles = (AddressBits / 4) + ((AddressBits % 4) == 0 ? 0 : 1);
|
||||
int dataNibbles = (DataBits / 4) + ((DataBits % 4) == 0 ? 0 : 1);
|
||||
|
||||
ProtocolAnalyzerDataSegment segment = new ProtocolAnalyzerDataSegment();
|
||||
segment.FirstSample = o.Start;
|
||||
segment.LastSample = o.End - 1;
|
||||
string value = "";
|
||||
|
||||
if (addressNibbles != 0 && o.Address != null)
|
||||
value += $"A: 0x{o.Address.Value.ToString($"X{addressNibbles}")}\r\n";
|
||||
|
||||
if (o.Operation != null)
|
||||
value += $"{o.Operation}: 0x{o.Value.ToString($"X{dataNibbles}")}";
|
||||
else
|
||||
value += $"V: 0x{o.Value.ToString($"X{dataNibbles}")}";
|
||||
|
||||
segment.Value = value;
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
private OpData? FindNextOp(IEnumerable<ControlChannel> controls, byte[][] dataBits, byte[][] addressBits, int readOffset, int writeOffset, ref int offset)
|
||||
{
|
||||
int max = dataBits[0].Length;
|
||||
|
||||
int start = -1;
|
||||
int end = max;
|
||||
|
||||
//Find the trigger and range
|
||||
if (controls.Any(c => c.SignalName == CS_SIGNAL_NAME))
|
||||
{
|
||||
var cs = controls.First(c => c.SignalName == CS_SIGNAL_NAME);
|
||||
|
||||
for (int buc = offset; buc < max; buc++)
|
||||
{
|
||||
if (cs.Samples[buc] == cs.Edge)
|
||||
{
|
||||
start = buc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (start == -1)
|
||||
return null;
|
||||
|
||||
for (int buc = start; buc < max; buc++)
|
||||
{
|
||||
if (cs.Samples[buc] != cs.Edge)
|
||||
{
|
||||
end = buc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlChannel? trigger = null;
|
||||
|
||||
for (int buc = offset; buc < max; buc++)
|
||||
{
|
||||
foreach(var control in controls)
|
||||
{
|
||||
if (control.Samples[buc] == control.Edge)
|
||||
{
|
||||
trigger = control;
|
||||
start = buc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trigger != null)
|
||||
break;
|
||||
}
|
||||
|
||||
if (trigger == null)
|
||||
return null;
|
||||
|
||||
for (int buc = start; buc < max; buc++)
|
||||
{
|
||||
if (trigger.Samples[buc] != trigger.Edge)
|
||||
{
|
||||
end = buc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpData op = new OpData { Start = start, End = end };
|
||||
|
||||
int samplePos = start;
|
||||
|
||||
op.Operation = GetOp(controls, samplePos);
|
||||
op.Address = GetAddress(addressBits, samplePos);
|
||||
|
||||
if (op.Operation == READ_OP)
|
||||
{
|
||||
if (start + readOffset < end)
|
||||
samplePos = start + readOffset;
|
||||
else
|
||||
samplePos = end - 1;
|
||||
}
|
||||
else if (op.Operation == WRITE_OP)
|
||||
{
|
||||
if (start + writeOffset < end)
|
||||
samplePos = start + writeOffset;
|
||||
else
|
||||
samplePos = end - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int maxOffset = readOffset > writeOffset ? readOffset : writeOffset;
|
||||
|
||||
if (start + maxOffset < end)
|
||||
samplePos = start + maxOffset;
|
||||
else
|
||||
samplePos = end - 1;
|
||||
}
|
||||
|
||||
op.Value = GetData(dataBits, samplePos);
|
||||
|
||||
offset = end;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private string? GetOp(IEnumerable<ControlChannel> controls, int samplePos)
|
||||
{
|
||||
var rdChannel = controls.FirstOrDefault(c => c.SignalName == RD_SIGNAL_NAME);
|
||||
var wrChannel = controls.FirstOrDefault(c => c.SignalName == WR_SIGNAL_NAME);
|
||||
|
||||
if(rdChannel == null && wrChannel == null)
|
||||
return null;
|
||||
|
||||
if (rdChannel != null && rdChannel.Samples[samplePos] == rdChannel.Edge)
|
||||
return READ_OP;
|
||||
|
||||
if (wrChannel != null && wrChannel.Samples[samplePos] == wrChannel.Edge)
|
||||
return WRITE_OP;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private uint? GetAddress(byte[][] addressBits, int samplePos)
|
||||
{
|
||||
if(addressBits == null || addressBits.Length == 0)
|
||||
return null;
|
||||
|
||||
uint address = 0;
|
||||
|
||||
for (int buc = 0; buc < addressBits.Length; buc++)
|
||||
address |= (uint)(addressBits[buc][samplePos] << buc);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
private uint GetData(byte[][] dataBits, int samplePos)
|
||||
{
|
||||
uint value = 0;
|
||||
|
||||
for(int buc = 0; buc < dataBits.Length; buc++)
|
||||
value |= (uint)(dataBits[buc][samplePos] << buc);
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public override bool ValidateSettings(ProtocolAnalyzerSettingValue[] SelectedSettings, ProtocolAnalyzerSelectedChannel[] SelectedChannels)
|
||||
{
|
||||
bool csTrigger = false;
|
||||
bool useRD = false;
|
||||
bool useWR = false;
|
||||
|
||||
//Check which trigger signals are used
|
||||
csTrigger = SelectedChannels.Any(c => c.SignalName == CS_SIGNAL_NAME);
|
||||
useRD = SelectedChannels.Any(c => c.SignalName == RD_SIGNAL_NAME);
|
||||
useWR = SelectedChannels.Any(c => c.SignalName == WR_SIGNAL_NAME);
|
||||
|
||||
//If no control signal selected then configuration is invalid
|
||||
if (!csTrigger && !useRD && !useWR)
|
||||
return false;
|
||||
|
||||
//If CS signal is selected, check for the edge selection
|
||||
if(csTrigger && SelectedSettings[0].Value == null)
|
||||
return false;
|
||||
|
||||
//If RD signal is selected, check for the edge selection
|
||||
if (useRD && SelectedSettings[1].Value == null)
|
||||
return false;
|
||||
|
||||
//If WR signal is selected, check for the edge selection
|
||||
if (useWR && SelectedSettings[2].Value == null)
|
||||
return false;
|
||||
|
||||
int addressSize = 0;
|
||||
|
||||
if (SelectedSettings[5].Value != null)
|
||||
addressSize = (int)SelectedSettings[5].Value;
|
||||
|
||||
//If an address size is provided check for its channels
|
||||
if (addressSize > 0 && !SelectedChannels.Any(c => c.SignalName == ADDR_SIGNAL_NAME))
|
||||
return false;
|
||||
|
||||
//Check for the data channels
|
||||
if (!SelectedChannels.Any(c => c.SignalName == DATA_SIGNAL_NAME))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private class ControlChannel
|
||||
{
|
||||
public string SignalName { get; set; }
|
||||
public byte[] Samples { get; set; }
|
||||
public byte Edge { get; set; }
|
||||
}
|
||||
|
||||
private class OpData
|
||||
{
|
||||
public int Start { get; set; }
|
||||
public int End { get; set; }
|
||||
public uint? Address { get; set; }
|
||||
public uint Value { get; set; }
|
||||
public string? Operation { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LogicAnalyzer\LogicAnalyzer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user